示例#1
0
async def test_asgi_to_jackie():
    @asgi_to_jackie
    async def view(scope, receive, send):
        query = urllib.parse.parse_qs(scope['query_string'].decode())
        try:
            name = query['name'][-1]
        except KeyError:
            name = 'World'
        body = f'Hello, {name}!'.encode()
        await send({
            'type':
            'http.response.start',
            'status':
            200,
            'headers': [
                (b'content-type', b'text/plain; charset=UTF-8'),
            ]
        })
        await send({'type': 'http.response.body', 'body': body})

    response = await view(Request())
    assert response.status == 200
    assert list(response.headers.allitems()) == [
        ('content-type', 'text/plain; charset=UTF-8'),
    ]
    assert await response.body() == b'Hello, World!'

    response = await view(Request(query={'name': 'Jack'}))
    assert response.status == 200
    assert list(response.headers.allitems()) == [
        ('content-type', 'text/plain; charset=UTF-8'),
    ]
    assert await response.body() == b'Hello, Jack!'
示例#2
0
async def test_asgi_to_jackie_send_file():
    with tempfile.NamedTemporaryFile(suffix='.txt') as f:
        f.write(b'foobar')
        f.flush()

        @asgi_to_jackie
        async def view(scope, receive, send):
            await send({
                'type': 'http.response.start',
                'status': 200,
                'headers': [],
            })
            query = urllib.parse.parse_qs(scope['query_string'].decode())
            message = {
                'type': 'http.response.zerocopysend',
                'file': open(f.name, 'rb'),
            }
            if 'offset' in query:
                message['offset'] = int(query['offset'][-1])
            if 'size' in query:
                message['count'] = int(query['size'][-1])
            await send(message)

        response = await view(Request())
        assert await response.body() == b'foobar'

        response = await view(Request(query={'offset': 3}))
        assert await response.body() == b'bar'

        response = await view(Request(query={'size': 3}))
        assert await response.body() == b'foo'
示例#3
0
async def test_post():
    response = await view(Request(method='GET', path='/post/'))
    assert response.status == 200
    assert await response.text() == 'post list'

    response = await view(Request(method='POST', path='/post/'))
    assert response.status == 200
    assert await response.text() == 'post create'

    response = await view(Request(method='PUT', path='/post/'))
    assert response.status == 405
    assert response.headers['Allow'] == 'GET, POST'
    assert await response.text() == 'Method Not Allowed'

    response = await view(Request(method='GET', path='/post/123/'))
    assert response.status == 200
    assert await response.text() == 'post detail 123'

    response = await view(Request(method='PUT', path='/post/123/'))
    assert response.status == 200
    assert await response.text() == 'post update 123'

    response = await view(Request(method='PATCH', path='/post/123/'))
    assert response.status == 200
    assert await response.text() == 'post update 123'

    response = await view(Request(method='DELETE', path='/post/123/'))
    assert response.status == 200
    assert await response.text() == 'post delete 123'

    response = await view(Request(method='POST', path='/post/123/'))
    assert response.status == 405
    assert response.headers['Allow'] == 'DELETE, GET, PATCH, PUT'
    assert await response.text() == 'Method Not Allowed'
示例#4
0
async def test_asgi_to_jackie_disconnect():
    @asgi_to_jackie
    async def view(scope, receive, send):
        assert scope['type'] == 'http'
        assert await receive() == {
            'type': 'http.request',
            'body': b'foo',
            'more_body': True,
        }
        assert await receive() == {
            'type': 'http.disconnect',
        }
        await send({
            'type': 'http.response.start',
            'status': 200,
        })
        await send({
            'type': 'http.response.body',
            'body': b'foo',
        })

    async def get_request_body():
        yield b'foo'
        raise Disconnect

    await view(Request(body=get_request_body()))
示例#5
0
async def test_form_request():
    request = Request(form={
        'foo': '123',
        'bar': 'multi\nline\nstring',
        'baz': File('baz.png', 'image/png', b'pngcontent'),
    })
    assert request.content_type == 'multipart/form-data'
    boundary = request.boundary.encode()
    assert await request.body() == (
        b'--' + boundary + b'\n'
        b'Content-Disposition: form-data; name=foo\n'
        b'\n'
        b'123\n'
        b'--' + boundary + b'\n'
        b'Content-Disposition: form-data; name=bar\n'
        b'\n'
        b'multi\n'
        b'line\n'
        b'string\n'
        b'--' + boundary + b'\n'
        b'Content-Disposition: form-data; name=baz; filename=baz.png\n'
        b'Content-Type: image/png\n'
        b'\n'
        b'pngcontent\n'
        b'--' + boundary + b'--\n'
    )
    data = await request.form()
    assert set(data) == {'foo', 'bar', 'baz'}
    assert data['foo'] == '123'
    assert data['bar'] == 'multi\nline\nstring'
    assert data['baz'].content_type == 'image/png'
    assert data['baz'].content == b'pngcontent'
示例#6
0
async def test_asgi_to_jackie_unexpected_message():
    @asgi_to_jackie
    async def view(scope, receive, send):
        assert scope['type'] == 'http'
        await send({'type': 'invalid'})

    with pytest.raises(ValueError):
        await view(Request())

    @asgi_to_jackie
    async def view(scope, receive, send):
        assert scope['type'] == 'http'
        await send({'type': 'http.response.start', 'status': 200})
        await send({'type': 'invalid'})

    response = await view(Request())
    with pytest.raises(ValueError):
        await response.body()
示例#7
0
async def test_file_request():
    with tempfile.NamedTemporaryFile(suffix='.txt') as f:
        f.write(b'foobar')
        f.flush()

        request = Request(file=f.name)
        assert request.content_type == 'text/plain'
        assert await request.body() == b'foobar'
        assert await request.text() == 'foobar'
示例#8
0
async def test_asgi_to_jackie_forward_exception():
    @asgi_to_jackie
    async def view(scope, receive, send):
        raise ValueError('test exception')

    with pytest.raises(ValueError) as exc_info:
        await view(Request(body=[]))

    assert str(exc_info.value) == 'test exception'
示例#9
0
async def test_middleware():
    router = Router()

    @router.get('/foo/')
    async def foo(request):
        return Response(text='foo')

    @router.get('/foo/<param>/')
    async def bar(request, param):
        return Response(text=param)

    @router.middleware
    def prefix_content(get_response):
        async def view(request):
            response = await get_response(request)
            try:
                prefix = request.query['prefix']
            except KeyError:
                pass
            else:
                response = Response(text=prefix + await response.text())
            return response

        return view

    view = asgi_to_jackie(router)

    response = await view(Request('/foo/'))
    assert response.status == 200
    assert await response.text() == 'foo'

    response = await view(Request('/foo/', query={'prefix': 'prefixed '}))
    assert response.status == 200
    assert await response.text() == 'prefixed foo'

    response = await view(Request('/foo/bar/'))
    assert response.status == 200
    assert await response.text() == 'bar'

    response = await view(Request('/foo/bar/', query={'prefix': 'prefixed '}))
    assert response.status == 200
    assert await response.text() == 'prefixed bar'
示例#10
0
async def test_asgi_to_jackie_no_more_messages():
    @asgi_to_jackie
    async def view(scope, receive, send):
        assert await receive() == {
            'type': 'http.request',
            'body': b'',
            'more_body': False,
        }
        with pytest.raises(ValueError):
            await receive()

    with pytest.raises(ValueError):
        await view(Request(body=[]))
示例#11
0
async def test_user():
    response = await view(Request(method='GET', path='/user/'))
    assert response.status == 200
    assert await response.text() == 'user list'

    response = await view(Request(method='POST', path='/user/'))
    assert response.status == 200
    assert await response.text() == 'user create'

    response = await view(Request(method='PUT', path='/user/'))
    assert response.status == 405
    assert response.headers['Allow'] == 'GET, POST'
    assert await response.text() == 'Method Not Allowed'

    response = await view(Request(method='GET', path='/user/123/'))
    assert response.status == 200
    assert await response.text() == 'user detail 123'

    response = await view(Request(method='PUT', path='/user/123/'))
    assert response.status == 200
    assert await response.text() == 'user update 123'

    response = await view(Request(method='PATCH', path='/user/123/'))
    assert response.status == 200
    assert await response.text() == 'user update 123'

    response = await view(Request(method='DELETE', path='/user/123/'))
    assert response.status == 200
    assert await response.text() == 'user delete 123'

    response = await view(Request(method='POST', path='/user/123/'))
    assert response.status == 405
    assert response.headers['Allow'] == 'DELETE, GET, PATCH, PUT'
    assert await response.text() == 'Method Not Allowed'

    response = await view(Request(method='POST', path='/user/foo/'))
    assert response.status == 404
    assert await response.text() == 'Not Found'
示例#12
0
def test_cookies():
    request = Request(Cookie='foo=bar; bar="baz\\"qux"')
    assert request.cookies == {
        'foo': 'bar',
        'bar': 'baz"qux',
    }
示例#13
0
async def test_multipart_file_request():
    request = Request(file=File('foo.txt', 'text/plain', b'foobar'))
    assert request.content_type == 'text/plain'
    assert await request.body() == b'foobar'
    assert await request.text() == 'foobar'
示例#14
0
async def test_text_request():
    request = Request(text='foobar')
    assert request.content_type == 'text/plain'
    assert request.charset == 'UTF-8'
    assert await request.body() == b'foobar'
    assert await request.text() == 'foobar'
示例#15
0
async def test_json_request():
    request = Request(json={'foo': 'bar'})
    assert request.content_type == 'application/json'
    assert request.charset == 'UTF-8'
    assert await request.body() == b'{"foo": "bar"}'
    assert await request.json() == {'foo': 'bar'}
示例#16
0
async def test_all_methods():
    app = Router()

    @app.get('/')
    async def get_view(request):
        return Response(text='get')

    @app.head('/')
    async def head_view(request):
        return Response(text='head')

    @app.post('/')
    async def post_view(request):
        return Response(text='post')

    @app.put('/')
    async def put_view(request):
        return Response(text='put')

    @app.delete('/')
    async def delete_view(request):
        return Response(text='delete')

    @app.connect('/')
    async def connect_view(request):
        return Response(text='connect')

    @app.options('/')
    async def options_view(request):
        return Response(text='options')

    @app.trace('/')
    async def trace_view(request):
        return Response(text='trace')

    @app.patch('/')
    async def patch_view(request):
        return Response(text='patch')

    view = asgi_to_jackie(app)

    response = await view(Request(method='GET', path='/'))
    assert response.status == 200
    assert await response.text() == 'get'

    response = await view(Request(method='HEAD', path='/'))
    assert response.status == 200
    assert await response.text() == 'head'

    response = await view(Request(method='POST', path='/'))
    assert response.status == 200
    assert await response.text() == 'post'

    response = await view(Request(method='PUT', path='/'))
    assert response.status == 200
    assert await response.text() == 'put'

    response = await view(Request(method='DELETE', path='/'))
    assert response.status == 200
    assert await response.text() == 'delete'

    response = await view(Request(method='CONNECT', path='/'))
    assert response.status == 200
    assert await response.text() == 'connect'

    response = await view(Request(method='OPTIONS', path='/'))
    assert response.status == 200
    assert await response.text() == 'options'

    response = await view(Request(method='TRACE', path='/'))
    assert response.status == 200
    assert await response.text() == 'trace'

    response = await view(Request(method='PATCH', path='/'))
    assert response.status == 200
    assert await response.text() == 'patch'
示例#17
0
async def test_custom_error_pages():
    router = Router()

    @router.get('/api/')
    async def foo(request):
        return Response(json={'foo': 'bar'})

    @router.not_found
    async def not_found(request):
        return Response(
            status=404,
            json={
                'code': 'not_found',
                'message': 'Not Found',
            },
        )

    @router.method_not_allowed
    async def method_not_allowed(request, methods):
        return Response(status=405,
                        json={
                            'code': 'method_not_allowed',
                            'message': 'Method Not Allowed',
                        },
                        allow=', '.join(sorted(methods)))

    @router.websocket_not_found
    async def websocket_not_found(socket):
        await socket.close(1337)

    view = asgi_to_jackie(router)

    response = await view(Request(method='GET', path='/api/'))
    assert response.status == 200
    assert await response.json() == {'foo': 'bar'}

    response = await view(Request(method='GET', path='/other/'))
    assert response.status == 404
    assert await response.json() == {
        'code': 'not_found',
        'message': 'Not Found',
    }

    response = await view(Request(method='POST', path='/api/'))
    assert response.status == 405
    assert await response.json() == {
        'code': 'method_not_allowed',
        'message': 'Method Not Allowed',
    }

    input_queue = asyncio.Queue()
    output_queue = asyncio.Queue()

    scope = {
        'type': 'websocket',
        'path': '/api/',
        'query_string': b'',
        'headers': [],
    }
    task = asyncio.ensure_future(
        router(scope, input_queue.get, output_queue.put))

    await input_queue.put({'type': 'websocket.connect'})
    assert await output_queue.get() == {
        'type': 'websocket.close',
        'code': 1337,
    }
    await task

    input_queue = asyncio.Queue()
    output_queue = asyncio.Queue()

    scope = {
        'type': 'websocket',
        'path': '/other/',
        'query_string': b'',
        'headers': [],
    }
    task = asyncio.ensure_future(
        router(scope, input_queue.get, output_queue.put))

    await input_queue.put({'type': 'websocket.connect'})
    assert await output_queue.get() == {
        'type': 'websocket.close',
        'code': 1337,
    }
    await task