From 808cd691161349213d102f5c7ae6e75d09bf0cf6 Mon Sep 17 00:00:00 2001 From: Iuri de Silvio Date: Thu, 27 Jan 2022 16:02:39 -0300 Subject: [PATCH 1/5] test_get_response --- django_connexion/apis/django_api.py | 15 +- django_connexion/tests/api/__init__.py | 0 .../tests/api/test_get_response.py | 162 ++++++++++++++++++ django_connexion/tests/conftest.py | 11 ++ django_connexion/tests/fakeapi/__init__.py | 0 django_connexion/tests/fakeapi/auth.py | 14 ++ .../tests/fakeapi/django_handlers.py | 106 ++++++++++++ .../tests/fixtures/django/swagger_secure.yaml | 40 +++++ 8 files changed, 346 insertions(+), 2 deletions(-) create mode 100644 django_connexion/tests/api/__init__.py create mode 100644 django_connexion/tests/api/test_get_response.py create mode 100644 django_connexion/tests/conftest.py create mode 100644 django_connexion/tests/fakeapi/__init__.py create mode 100644 django_connexion/tests/fakeapi/auth.py create mode 100644 django_connexion/tests/fakeapi/django_handlers.py create mode 100644 django_connexion/tests/fixtures/django/swagger_secure.yaml diff --git a/django_connexion/apis/django_api.py b/django_connexion/apis/django_api.py index ec07ed4..079dac1 100644 --- a/django_connexion/apis/django_api.py +++ b/django_connexion/apis/django_api.py @@ -67,7 +67,6 @@ def _add_operation_internal(self, method, path, operation): Adds the operation according to the user framework in use. It will be used to register the operation on the user framework router. """ - # print('_add_operation_internal', method, path, operation) operation_id = operation.operation_id logger.debug('... Adding %s -> %s', method.upper(), operation_id, extra=vars(operation)) @@ -153,7 +152,19 @@ def _build_response(cls, data, mimetype, content_type=None, status_code=None, he :return A framework response. :rtype Response """ - breakpoint() + if cls._is_framework_response(data): + return HttpResponse(data, status_code=status_code, headers=headers) + + data, status_code, serialized_mimetype = cls._prepare_body_and_status_code( + data=data, mimetype=mimetype, status_code=status_code, extra_context=extra_context) + print('MIME', mimetype, serialized_mimetype) + kwargs = { + 'content_type': content_type or 'text/plain; charset=utf-8', + 'headers': headers, + 'status': status_code + } + kwargs = {k: v for k, v in kwargs.items() if v is not None} + return HttpResponse(data, **kwargs) @property def urls(self): diff --git a/django_connexion/tests/api/__init__.py b/django_connexion/tests/api/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/django_connexion/tests/api/test_get_response.py b/django_connexion/tests/api/test_get_response.py new file mode 100644 index 0000000..f3a975c --- /dev/null +++ b/django_connexion/tests/api/test_get_response.py @@ -0,0 +1,162 @@ +import json + +import pytest +from django_connexion.apis.django_api import DjangoApi +from connexion.lifecycle import ConnexionResponse + +from django.http import HttpResponse, StreamingHttpResponse + + +@pytest.fixture(scope='module') +def api(django_api_spec_dir): + yield DjangoApi(specification=django_api_spec_dir / 'swagger_secure.yaml') + + +def test_get_response_from_django_response(api): + django_response = HttpResponse( + 'foo', status=201, headers={'X-header': 'value'}, content_type='text/plain; charset=utf-8') + response = api.get_response(django_response) + assert isinstance(response, HttpResponse) + assert response.status_code == 201 + assert response.content == b'foo' + assert dict(response.headers) == { + 'Content-Type': 'text/plain; charset=utf-8', + 'X-header': 'value' + } + + +def test_get_response_from_django_stream_response(api): + response = api.get_response(StreamingHttpResponse(status=201, headers={'X-header': 'value'})) + assert isinstance(response, StreamingHttpResponse) + assert response.status_code == 201 + assert response.headers['Content-Type'] == 'application/octet-stream' + assert dict(response.headers) == {'X-header': 'value'} + + +def test_get_response_from_connexion_response(api): + response = api.get_response(ConnexionResponse(status_code=201, mimetype='text/plain', body='foo', headers={'X-header': 'value'})) + assert isinstance(response, HttpResponse) + assert response.status_code == 201 + assert response.content == b'foo' + assert dict(response.headers) == {'Content-Type': 'text/plain; charset=utf-8', 'X-header': 'value'} + + +def test_get_response_from_string(api): + response = api.get_response('foo') + assert isinstance(response, HttpResponse) + assert response.status_code == 200 + assert response.content == b'foo' + assert dict(response.headers) == {'Content-Type': 'text/plain; charset=utf-8'} + + +def test_get_response_from_string_tuple(api): + response = api.get_response(('foo',)) + assert isinstance(response, HttpResponse) + assert response.status_code == 200 + assert response.content == b'foo' + assert dict(response.headers) == {'Content-Type': 'text/plain; charset=utf-8'} + + +def test_get_response_from_string_status(api): + response = api.get_response(('foo', 201)) + assert isinstance(response, HttpResponse) + assert response.status_code == 201 + assert response.content == b'foo' + assert dict(response.headers) == {'Content-Type': 'text/plain; charset=utf-8'} + + +def test_get_response_from_string_headers(api): + response = api.get_response(('foo', {'X-header': 'value'})) + assert isinstance(response, HttpResponse) + assert response.status_code == 200 + assert response.content == b'foo' + assert dict(response.headers) == {'Content-Type': 'text/plain; charset=utf-8', 'X-header': 'value'} + + +def test_get_response_from_string_status_headers(api): + response = api.get_response(('foo', 201, {'X-header': 'value'})) + assert isinstance(response, HttpResponse) + assert response.status_code == 201 + assert response.content == b'foo' + assert dict(response.headers) == {'Content-Type': 'text/plain; charset=utf-8', 'X-header': 'value'} + + +def test_get_response_from_tuple_error(api): + with pytest.raises(TypeError) as e: + api.get_response((HttpResponse('foo', status=201, headers={'X-header': 'value'}), 200)) + assert str(e.value) == "Cannot return web.StreamResponse in tuple. Only raw data can be returned in tuple." + + +def test_get_response_from_dict(api): + response = api.get_response({'foo': 'bar'}) + assert isinstance(response, HttpResponse) + assert response.status_code == 200 + # odd, yes. but backwards compatible. see test_response_with_non_str_and_non_json_body in tests/aiohttp/test_aiohttp_simple_api.py + # TODO: This should be made into JSON when aiohttp and flask serialization can be harmonized. + assert response.content == b"{'foo': 'bar'}" + assert dict(response.headers) == {'Content-Type': 'text/plain; charset=utf-8'} + + +def test_get_response_from_dict_json(api): + response = api.get_response({'foo': 'bar'}, mimetype='application/json') + assert isinstance(response, HttpResponse) + assert response.status_code == 200 + assert json.loads(response.content.decode()) == {"foo": "bar"} + assert dict(response.headers) == {'Content-Type': 'application/json; charset=utf-8'} + + +def test_get_response_no_data(api): + response = api.get_response(None, mimetype='application/json') + assert isinstance(response, HttpResponse) + assert response.status_code == 204 + assert response.content is None + assert dict(response.headers) == {'Content-Type': 'application/json'} + + +def test_get_response_binary_json(api): + response = api.get_response(b'{"foo":"bar"}', mimetype='application/json') + assert isinstance(response, HttpResponse) + assert response.status_code == 200 + assert json.loads(response.content.decode()) == {"foo": "bar"} + assert dict(response.headers) == {'Content-Type': 'application/json'} + + +def test_get_response_binary_no_mimetype(api): + response = api.get_response(b'{"foo":"bar"}') + assert isinstance(response, HttpResponse) + assert response.status_code == 200 + assert response.content == b'{"foo":"bar"}' + assert response.headers['Content-Type'] == 'application/octet-stream' + assert dict(response.headers) == {} + + +def test_get_connexion_response_from_django_response(api): + response = api.get_connexion_response(HttpResponse('foo', status=201, headers={'X-header': 'value'})) + assert isinstance(response, ConnexionResponse) + assert response.status_code == 201 + assert response.content == b'foo' + assert dict(response.headers) == {'Content-Type': 'text/plain; charset=utf-8', 'X-header': 'value'} + + +def test_get_connexion_response_from_connexion_response(api): + response = api.get_connexion_response(ConnexionResponse(status_code=201, content_type='text/plain', body='foo', headers={'X-header': 'value'})) + assert isinstance(response, ConnexionResponse) + assert response.status_code == 201 + assert response.content == b'foo' + assert dict(response.headers) == {'Content-Type': 'text/plain; charset=utf-8', 'X-header': 'value'} + + +def test_get_connexion_response_from_tuple(api): + response = api.get_connexion_response(('foo', 201, {'X-header': 'value'})) + assert isinstance(response, ConnexionResponse) + assert response.status_code == 201 + assert response.content == b'foo' + assert dict(response.headers) == {'Content-Type': 'text/plain; charset=utf-8', 'X-header': 'value'} + + +def test_get_connexion_response_from_django_stream_response(api): + response = api.get_connexion_response(StreamingHttpResponse(status=201, headers={'X-header': 'value'})) + assert isinstance(response, ConnexionResponse) + assert response.status_code == 201 + assert response.content == None + assert dict(response.headers) == {'X-header': 'value'} diff --git a/django_connexion/tests/conftest.py b/django_connexion/tests/conftest.py new file mode 100644 index 0000000..6640890 --- /dev/null +++ b/django_connexion/tests/conftest.py @@ -0,0 +1,11 @@ +import pathlib + +import pytest + +TEST_FOLDER = pathlib.Path(__file__).parent +FIXTURES_FOLDER = TEST_FOLDER / 'fixtures' + + +@pytest.fixture(scope='session') +def django_api_spec_dir(): + return FIXTURES_FOLDER / 'django' diff --git a/django_connexion/tests/fakeapi/__init__.py b/django_connexion/tests/fakeapi/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/django_connexion/tests/fakeapi/auth.py b/django_connexion/tests/fakeapi/auth.py new file mode 100644 index 0000000..4c91371 --- /dev/null +++ b/django_connexion/tests/fakeapi/auth.py @@ -0,0 +1,14 @@ +import json + + +def fake_basic_auth(username, password, required_scopes=None): + if username == password: + return {'uid': username} + return None + + +def fake_json_auth(token, required_scopes=None): + try: + return json.loads(token) + except ValueError: + return None diff --git a/django_connexion/tests/fakeapi/django_handlers.py b/django_connexion/tests/fakeapi/django_handlers.py new file mode 100644 index 0000000..7bf79de --- /dev/null +++ b/django_connexion/tests/fakeapi/django_handlers.py @@ -0,0 +1,106 @@ +#!/usr/bin/env python3 +import datetime +import uuid + +from connexion.lifecycle import ConnexionResponse + +from django.http import HttpRequest, HttpResponse + + +def get_bye(name): + return HttpResponse(text=f'Goodbye {name}') + + +def django_str_response(): + return 'str response' + + +def django_non_str_non_json_response(): + return 1234 + + +def django_bytes_response(): + return b'bytes response' + + +def django_validate_responses(): + return {"validate": True} + + +def django_post_greeting(name, **kwargs): + data = {'greeting': f'Hello {name}'} + return data + + +def django_echo(**kwargs): + return django.web.json_response(data=kwargs, status=200) + + +def django_access_request_context(request_ctx): + assert request_ctx is not None + assert isinstance(request_ctx, HttpRequest) + return None + + +def django_query_parsing_str(query): + return {'query': query} + + +def django_query_parsing_array(query): + return {'query': query} + + +def django_query_parsing_array_multi(query): + return {'query': query} + + +USERS = [ + {"id": 1, "name": "John Doe"}, + {"id": 2, "name": "Nick Carlson"} +] + + +def django_users_get(*args): + return django.web.json_response(data=USERS, status=200) + + +def django_users_post(user): + if "name" not in user: + return ConnexionResponse(body={"error": "name is undefined"}, + status_code=400, + content_type='application/json') + user['id'] = len(USERS) + 1 + USERS.append(user) + return django.web.json_response(data=USERS[-1], status=201) + + +def django_token_info(token_info): + return django.web.json_response(data=token_info) + + +def django_all_auth(token_info): + return django_token_info(token_info) + + +def django_async_auth(token_info): + return django_token_info(token_info) + + +def django_bearer_auth(token_info): + return django_token_info(token_info) + + +def django_async_bearer_auth(token_info): + return django_token_info(token_info) + + +def get_datetime(): + return ConnexionResponse(body={'value': datetime.datetime(2000, 1, 2, 3, 4, 5, 6)}) + + +def get_date(): + return ConnexionResponse(body={'value': datetime.date(2000, 1, 2)}) + + +def get_uuid(): + return ConnexionResponse(body={'value': uuid.UUID(hex='e7ff66d0-3ec2-4c4e-bed0-6e4723c24c51')}) diff --git a/django_connexion/tests/fixtures/django/swagger_secure.yaml b/django_connexion/tests/fixtures/django/swagger_secure.yaml new file mode 100644 index 0000000..a977d7b --- /dev/null +++ b/django_connexion/tests/fixtures/django/swagger_secure.yaml @@ -0,0 +1,40 @@ +swagger: "2.0" + +info: + title: "{{title}}" + version: "1.0" + +basePath: /v1.0 + +securityDefinitions: + oauth: + type: oauth2 + flow: password + tokenUrl: https://oauth.example/token + x-tokenInfoUrl: https://oauth.example/token_info + scopes: + myscope: can do stuff + basic: + type: basic + x-basicInfoFunc: django_connexion.tests.fakeapi.auth.fake_basic_auth + api_key: + type: apiKey + in: header + name: X-API-Key + x-apikeyInfoFunc: django_connexion.tests.fakeapi.auth.fake_json_auth + +security: + - oauth: + - myscope + - basic: [] + - api_key: [] +paths: + /all_auth: + get: + summary: Test different authentication + operationId: django_connexion.tests.fakeapi.django_handlers.django_token_info + responses: + 200: + description: greeting response + schema: + type: object From 21552ccba8352e07cf0ca50689a95ca42c6bf2e9 Mon Sep 17 00:00:00 2001 From: Iuri de Silvio Date: Fri, 28 Jan 2022 13:51:48 -0300 Subject: [PATCH 2/5] Passa mais uns testes. --- django_connexion/apis/django_api.py | 26 ++++++++++++++++--- .../tests/api/test_get_response.py | 8 +++--- 2 files changed, 28 insertions(+), 6 deletions(-) diff --git a/django_connexion/apis/django_api.py b/django_connexion/apis/django_api.py index 079dac1..a230e97 100644 --- a/django_connexion/apis/django_api.py +++ b/django_connexion/apis/django_api.py @@ -7,7 +7,7 @@ import logging from connexion.apis.abstract import AbstractAPI -from connexion.lifecycle import ConnexionRequest +from connexion.lifecycle import ConnexionRequest, ConnexionResponse from connexion.utils import yamldumper from django.http import HttpResponse, JsonResponse from django.urls import path as django_path @@ -130,6 +130,19 @@ def _is_framework_response(cls, response): @classmethod def _framework_to_connexion_response(cls, response, mimetype): """ Cast framework response class to ConnexionResponse used for schema validation """ + content_type = response.headers['Content-Type'] + try: + mimetype, _ = content_type.split(';', 1) + except ValueError: + mimetype = content_type + + return ConnexionResponse( + status_code=response.status_code, + mimetype=mimetype, + content_type=content_type, + headers=response.headers, + body=response.content, + ) @classmethod def _connexion_to_framework_response(cls, response, mimetype, extra_context=None): @@ -157,9 +170,16 @@ def _build_response(cls, data, mimetype, content_type=None, status_code=None, he data, status_code, serialized_mimetype = cls._prepare_body_and_status_code( data=data, mimetype=mimetype, status_code=status_code, extra_context=extra_context) - print('MIME', mimetype, serialized_mimetype) + + mimetype = mimetype or serialized_mimetype + if content_type is None: + content_type = 'text/plain' + + if ';' not in content_type: + content_type += '; charset=utf-8' + kwargs = { - 'content_type': content_type or 'text/plain; charset=utf-8', + 'content_type': content_type, 'headers': headers, 'status': status_code } diff --git a/django_connexion/tests/api/test_get_response.py b/django_connexion/tests/api/test_get_response.py index f3a975c..3aed736 100644 --- a/django_connexion/tests/api/test_get_response.py +++ b/django_connexion/tests/api/test_get_response.py @@ -34,7 +34,9 @@ def test_get_response_from_django_stream_response(api): def test_get_response_from_connexion_response(api): - response = api.get_response(ConnexionResponse(status_code=201, mimetype='text/plain', body='foo', headers={'X-header': 'value'})) + connexion_response = ConnexionResponse( + status_code=201, mimetype='text/plain', body='foo', headers={'X-header': 'value'}) + response = api.get_response(connexion_response) assert isinstance(response, HttpResponse) assert response.status_code == 201 assert response.content == b'foo' @@ -142,7 +144,7 @@ def test_get_connexion_response_from_connexion_response(api): response = api.get_connexion_response(ConnexionResponse(status_code=201, content_type='text/plain', body='foo', headers={'X-header': 'value'})) assert isinstance(response, ConnexionResponse) assert response.status_code == 201 - assert response.content == b'foo' + assert response.body == b'foo' assert dict(response.headers) == {'Content-Type': 'text/plain; charset=utf-8', 'X-header': 'value'} @@ -150,7 +152,7 @@ def test_get_connexion_response_from_tuple(api): response = api.get_connexion_response(('foo', 201, {'X-header': 'value'})) assert isinstance(response, ConnexionResponse) assert response.status_code == 201 - assert response.content == b'foo' + assert response.body == b'foo' assert dict(response.headers) == {'Content-Type': 'text/plain; charset=utf-8', 'X-header': 'value'} From 5c281bdc4225ef2d12d690009825f50a29b14532 Mon Sep 17 00:00:00 2001 From: Iuri de Silvio Date: Sun, 30 Jan 2022 22:41:51 -0300 Subject: [PATCH 3/5] Passa mais um teste. --- django_connexion/apis/django_api.py | 21 +++++++++++++++---- .../tests/api/test_get_response.py | 4 ++-- 2 files changed, 19 insertions(+), 6 deletions(-) diff --git a/django_connexion/apis/django_api.py b/django_connexion/apis/django_api.py index a230e97..64eeaf3 100644 --- a/django_connexion/apis/django_api.py +++ b/django_connexion/apis/django_api.py @@ -131,10 +131,12 @@ def _is_framework_response(cls, response): def _framework_to_connexion_response(cls, response, mimetype): """ Cast framework response class to ConnexionResponse used for schema validation """ content_type = response.headers['Content-Type'] - try: - mimetype, _ = content_type.split(';', 1) - except ValueError: - mimetype = content_type + + if not mimetype: + try: + mimetype, _ = content_type.split(';', 1) + except ValueError: + mimetype = content_type return ConnexionResponse( status_code=response.status_code, @@ -147,6 +149,17 @@ def _framework_to_connexion_response(cls, response, mimetype): @classmethod def _connexion_to_framework_response(cls, response, mimetype, extra_context=None): """ Cast ConnexionResponse to framework response class """ + content_type = response.content_type + if not content_type: + content_type = f'{mimetype or response.mimetype}; charset=utf-8' + + django_response = HttpResponse( + status=response.status_code, + content_type=content_type, + content=response.body, + headers=response.headers, + ) + return django_response @classmethod def _build_response(cls, data, mimetype, content_type=None, status_code=None, headers=None, diff --git a/django_connexion/tests/api/test_get_response.py b/django_connexion/tests/api/test_get_response.py index 3aed736..363c275 100644 --- a/django_connexion/tests/api/test_get_response.py +++ b/django_connexion/tests/api/test_get_response.py @@ -133,10 +133,10 @@ def test_get_response_binary_no_mimetype(api): def test_get_connexion_response_from_django_response(api): - response = api.get_connexion_response(HttpResponse('foo', status=201, headers={'X-header': 'value'})) + response = api.get_connexion_response(HttpResponse('foo', status=201, content_type='text/plain; charset=utf-8', headers={'X-header': 'value'})) assert isinstance(response, ConnexionResponse) assert response.status_code == 201 - assert response.content == b'foo' + assert response.body == b'foo' assert dict(response.headers) == {'Content-Type': 'text/plain; charset=utf-8', 'X-header': 'value'} From a37274810cd041c1dc6ae934ad18a6615c7929b1 Mon Sep 17 00:00:00 2001 From: Iuri de Silvio Date: Sun, 30 Jan 2022 22:45:36 -0300 Subject: [PATCH 4/5] Passa mais um teste. --- django_connexion/apis/django_api.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/django_connexion/apis/django_api.py b/django_connexion/apis/django_api.py index 64eeaf3..f6ddd63 100644 --- a/django_connexion/apis/django_api.py +++ b/django_connexion/apis/django_api.py @@ -186,7 +186,7 @@ def _build_response(cls, data, mimetype, content_type=None, status_code=None, he mimetype = mimetype or serialized_mimetype if content_type is None: - content_type = 'text/plain' + content_type = mimetype or 'text/plain' if ';' not in content_type: content_type += '; charset=utf-8' From c4855b23ab69aeafb460e21548f7d8aa04de9283 Mon Sep 17 00:00:00 2001 From: Iuri de Silvio Date: Sun, 30 Jan 2022 23:39:46 -0300 Subject: [PATCH 5/5] Passa mais testes. --- django_connexion/apis/django_api.py | 23 +++++-- django_connexion/apis/django_utils.py | 4 +- .../tests/api/test_get_response.py | 69 ++++++++++++------- 3 files changed, 66 insertions(+), 30 deletions(-) diff --git a/django_connexion/apis/django_api.py b/django_connexion/apis/django_api.py index f6ddd63..b1766cb 100644 --- a/django_connexion/apis/django_api.py +++ b/django_connexion/apis/django_api.py @@ -132,6 +132,13 @@ def _framework_to_connexion_response(cls, response, mimetype): """ Cast framework response class to ConnexionResponse used for schema validation """ content_type = response.headers['Content-Type'] + if response.streaming: + body = response.streaming_content + if not content_type: + content_type = 'application/octet-stream' + else: + body = response.content + if not mimetype: try: mimetype, _ = content_type.split(';', 1) @@ -143,7 +150,7 @@ def _framework_to_connexion_response(cls, response, mimetype): mimetype=mimetype, content_type=content_type, headers=response.headers, - body=response.content, + body=body, ) @classmethod @@ -184,11 +191,19 @@ def _build_response(cls, data, mimetype, content_type=None, status_code=None, he data, status_code, serialized_mimetype = cls._prepare_body_and_status_code( data=data, mimetype=mimetype, status_code=status_code, extra_context=extra_context) + if data is None: + data = b'' + mimetype = mimetype or serialized_mimetype if content_type is None: - content_type = mimetype or 'text/plain' - - if ';' not in content_type: + if mimetype: + content_type = mimetype + elif isinstance(data, bytes): + content_type = 'application/octet-stream' + else: + content_type = 'text/plain' + + if isinstance(data, (str, dict)): content_type += '; charset=utf-8' kwargs = { diff --git a/django_connexion/apis/django_utils.py b/django_connexion/apis/django_utils.py index 9261a50..c884ddb 100644 --- a/django_connexion/apis/django_utils.py +++ b/django_connexion/apis/django_utils.py @@ -3,7 +3,7 @@ import re import string -from django.http import HttpResponse +from django.http.response import HttpResponseBase PATH_PARAMETER = re.compile(r'\{([^}]*)\}') @@ -75,4 +75,4 @@ def is_django_response(obj: object) -> bool: >>> is_django_response(flask.Response()) True """ - return isinstance(obj, HttpResponse) + return isinstance(obj, HttpResponseBase) diff --git a/django_connexion/tests/api/test_get_response.py b/django_connexion/tests/api/test_get_response.py index 363c275..8fece78 100644 --- a/django_connexion/tests/api/test_get_response.py +++ b/django_connexion/tests/api/test_get_response.py @@ -26,11 +26,15 @@ def test_get_response_from_django_response(api): def test_get_response_from_django_stream_response(api): - response = api.get_response(StreamingHttpResponse(status=201, headers={'X-header': 'value'})) + django_stream_response = StreamingHttpResponse( + status=201, content_type='application/octet-stream', headers={'X-header': 'value'} + ) + response = api.get_response(django_stream_response) assert isinstance(response, StreamingHttpResponse) assert response.status_code == 201 - assert response.headers['Content-Type'] == 'application/octet-stream' - assert dict(response.headers) == {'X-header': 'value'} + assert dict(response.headers) == { + 'Content-Type': 'application/octet-stream', 'X-header': 'value' + } def test_get_response_from_connexion_response(api): @@ -40,7 +44,9 @@ def test_get_response_from_connexion_response(api): assert isinstance(response, HttpResponse) assert response.status_code == 201 assert response.content == b'foo' - assert dict(response.headers) == {'Content-Type': 'text/plain; charset=utf-8', 'X-header': 'value'} + assert dict(response.headers) == { + 'Content-Type': 'text/plain; charset=utf-8', 'X-header': 'value' + } def test_get_response_from_string(api): @@ -72,7 +78,9 @@ def test_get_response_from_string_headers(api): assert isinstance(response, HttpResponse) assert response.status_code == 200 assert response.content == b'foo' - assert dict(response.headers) == {'Content-Type': 'text/plain; charset=utf-8', 'X-header': 'value'} + assert dict(response.headers) == { + 'Content-Type': 'text/plain; charset=utf-8', 'X-header': 'value' + } def test_get_response_from_string_status_headers(api): @@ -80,20 +88,17 @@ def test_get_response_from_string_status_headers(api): assert isinstance(response, HttpResponse) assert response.status_code == 201 assert response.content == b'foo' - assert dict(response.headers) == {'Content-Type': 'text/plain; charset=utf-8', 'X-header': 'value'} - - -def test_get_response_from_tuple_error(api): - with pytest.raises(TypeError) as e: - api.get_response((HttpResponse('foo', status=201, headers={'X-header': 'value'}), 200)) - assert str(e.value) == "Cannot return web.StreamResponse in tuple. Only raw data can be returned in tuple." + assert dict(response.headers) == { + 'Content-Type': 'text/plain; charset=utf-8', 'X-header': 'value' + } def test_get_response_from_dict(api): response = api.get_response({'foo': 'bar'}) assert isinstance(response, HttpResponse) assert response.status_code == 200 - # odd, yes. but backwards compatible. see test_response_with_non_str_and_non_json_body in tests/aiohttp/test_aiohttp_simple_api.py + # odd, yes. but backwards compatible. see test_response_with_non_str_and_non_json_body in + # tests/aiohttp/test_aiohttp_simple_api.py # TODO: This should be made into JSON when aiohttp and flask serialization can be harmonized. assert response.content == b"{'foo': 'bar'}" assert dict(response.headers) == {'Content-Type': 'text/plain; charset=utf-8'} @@ -111,7 +116,7 @@ def test_get_response_no_data(api): response = api.get_response(None, mimetype='application/json') assert isinstance(response, HttpResponse) assert response.status_code == 204 - assert response.content is None + assert response.content == b'' assert dict(response.headers) == {'Content-Type': 'application/json'} @@ -128,24 +133,33 @@ def test_get_response_binary_no_mimetype(api): assert isinstance(response, HttpResponse) assert response.status_code == 200 assert response.content == b'{"foo":"bar"}' - assert response.headers['Content-Type'] == 'application/octet-stream' - assert dict(response.headers) == {} + assert dict(response.headers) == {'Content-Type': 'application/octet-stream'} def test_get_connexion_response_from_django_response(api): - response = api.get_connexion_response(HttpResponse('foo', status=201, content_type='text/plain; charset=utf-8', headers={'X-header': 'value'})) + django_response = HttpResponse( + 'foo', status=201, content_type='text/plain; charset=utf-8', headers={'X-header': 'value'} + ) + response = api.get_connexion_response(django_response) assert isinstance(response, ConnexionResponse) assert response.status_code == 201 assert response.body == b'foo' - assert dict(response.headers) == {'Content-Type': 'text/plain; charset=utf-8', 'X-header': 'value'} + assert dict(response.headers) == { + 'Content-Type': 'text/plain; charset=utf-8', 'X-header': 'value' + } def test_get_connexion_response_from_connexion_response(api): - response = api.get_connexion_response(ConnexionResponse(status_code=201, content_type='text/plain', body='foo', headers={'X-header': 'value'})) + connexion_response = ConnexionResponse( + status_code=201, content_type='text/plain', body='foo', headers={'X-header': 'value'} + ) + response = api.get_connexion_response(connexion_response) assert isinstance(response, ConnexionResponse) assert response.status_code == 201 assert response.body == b'foo' - assert dict(response.headers) == {'Content-Type': 'text/plain; charset=utf-8', 'X-header': 'value'} + assert dict(response.headers) == { + 'Content-Type': 'text/plain; charset=utf-8', 'X-header': 'value' + } def test_get_connexion_response_from_tuple(api): @@ -153,12 +167,19 @@ def test_get_connexion_response_from_tuple(api): assert isinstance(response, ConnexionResponse) assert response.status_code == 201 assert response.body == b'foo' - assert dict(response.headers) == {'Content-Type': 'text/plain; charset=utf-8', 'X-header': 'value'} + assert dict(response.headers) == { + 'Content-Type': 'text/plain; charset=utf-8', 'X-header': 'value' + } def test_get_connexion_response_from_django_stream_response(api): - response = api.get_connexion_response(StreamingHttpResponse(status=201, headers={'X-header': 'value'})) + django_stream_response = StreamingHttpResponse( + status=201, content_type='application/octet-stream', headers={'X-header': 'value'} + ) + response = api.get_connexion_response(django_stream_response) assert isinstance(response, ConnexionResponse) assert response.status_code == 201 - assert response.content == None - assert dict(response.headers) == {'X-header': 'value'} + assert bytes(response.body) == b'' + assert dict(response.headers) == { + 'Content-Type': 'application/octet-stream', 'X-header': 'value' + }