Skip to content

Commit 8fa2eb3

Browse files
committed
Added more tests
1 parent f0801e4 commit 8fa2eb3

File tree

8 files changed

+292
-19
lines changed

8 files changed

+292
-19
lines changed

tests/test_application/test_application_functions.py

Lines changed: 19 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -162,7 +162,23 @@ async def lifespan(app):
162162
assert startup_complete
163163
assert cleanup_complete
164164

165-
def test_app_debug(self):
165+
def test_app_debug_return_html(self):
166+
@get("/")
167+
async def homepage(request: Request):
168+
raise RuntimeError()
169+
170+
app = AppFactory.create_app()
171+
app.router.append(homepage)
172+
app.debug = True
173+
174+
client = TestClient(app, raise_server_exceptions=False)
175+
response = client.get("/", headers={"accept": "text/html"})
176+
assert response.status_code == 500
177+
assert "<head>" in response.text
178+
assert ".traceback-container" in response.text
179+
assert app.debug
180+
181+
def test_app_debug_plain_text(self):
166182
@get("/")
167183
async def homepage(request: Request):
168184
raise RuntimeError()
@@ -174,10 +190,8 @@ async def homepage(request: Request):
174190
client = TestClient(app, raise_server_exceptions=False)
175191
response = client.get("/")
176192
assert response.status_code == 500
177-
assert response.json() == {
178-
"detail": "Internal server error",
179-
"status_code": 500,
180-
}
193+
assert "test_application_functions.py" in response.text
194+
assert "line 184" in response.text
181195
assert app.debug
182196

183197

tests/test_exceptions/test_custom_exceptions.py

Lines changed: 4 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -133,8 +133,7 @@ def homepage():
133133

134134
tm = TestClientFactory.create_test_module()
135135
tm.app.router.append(homepage)
136-
tm.app.config.EXCEPTION_HANDLERS += [NewExceptionHandler()]
137-
tm.app.rebuild_middleware_stack()
136+
tm.app.add_exception_handler(NewExceptionHandler())
138137

139138
client = tm.get_client()
140139
res = client.get("/")
@@ -149,8 +148,7 @@ def homepage():
149148

150149
tm = TestClientFactory.create_test_module()
151150
tm.app.router.append(homepage)
152-
tm.app.config.EXCEPTION_HANDLERS += [OverrideAPIExceptionHandler()]
153-
tm.app.rebuild_middleware_stack()
151+
tm.app.add_exception_handler(OverrideAPIExceptionHandler())
154152

155153
client = tm.get_client()
156154
res = client.get("/")
@@ -174,8 +172,7 @@ def homepage():
174172

175173
tm = TestClientFactory.create_test_module()
176174
tm.app.router.append(homepage)
177-
tm.app.config.EXCEPTION_HANDLERS += [exception_handler]
178-
tm.app.rebuild_middleware_stack()
175+
tm.app.add_exception_handler(exception_handler)
179176

180177
client = tm.get_client(raise_server_exceptions=False)
181178
res = client.get("/")
@@ -220,7 +217,7 @@ async def app(scope, receive, send):
220217
app = ExceptionMiddleware(
221218
app,
222219
debug=True,
223-
exception_middleware_service=ExceptionMiddlewareService(config=Config()),
220+
exception_middleware_service=ExceptionMiddlewareService(),
224221
)
225222
client = test_client_factory(app)
226223
with pytest.raises(RuntimeError):

tests/test_routing/sample.py

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
from datetime import datetime
22
from enum import IntEnum
3-
from typing import Optional
3+
from typing import List, Optional
44

55
from pydantic import Field
66

@@ -36,3 +36,16 @@ class Filter(Schema):
3636
class Data(Schema):
3737
an_int: int = Field(alias="int", default=0)
3838
a_float: float = Field(alias="float", default=1.5)
39+
40+
41+
class NonPrimitiveSchema(Schema):
42+
# The schema can only work for Body
43+
# And will fail for Path, Cookie, Query, Header, Form
44+
filter: Filter
45+
46+
47+
class ListOfPrimitiveSchema(Schema):
48+
# The schema can only work for Body, Query, Header and Form
49+
# And will fail for Path, Cookie
50+
an_int: List[int] = Field(alias="int")
51+
a_float: List[float] = Field(alias="float")

tests/test_routing/test_cookie_schema.py

Lines changed: 32 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,14 @@
1-
from ellar.common import Cookie
1+
import pytest
2+
3+
from ellar.common import Cookie, get
24
from ellar.core import TestClientFactory
35
from ellar.core.connection import Request
6+
from ellar.core.exceptions import ImproperConfiguration
47
from ellar.core.routing import ModuleRouter
58
from ellar.openapi import OpenAPIDocumentBuilder
69
from ellar.serializer import serialize_object
710

8-
from .sample import Data, Filter
11+
from .sample import Data, Filter, ListOfPrimitiveSchema, NonPrimitiveSchema
912

1013
router = ModuleRouter("")
1114

@@ -105,3 +108,30 @@ def test_cookie_schema():
105108
"in": "cookie",
106109
},
107110
]
111+
112+
113+
def test_invalid_schema_cookie():
114+
with pytest.raises(ImproperConfiguration) as ex:
115+
116+
@get("/test")
117+
def invalid_path_parameter(cookie: NonPrimitiveSchema = Cookie()):
118+
pass
119+
120+
assert (
121+
str(ex.value)
122+
== "field: 'filter' with annotation:'<class 'tests.test_routing.sample.Filter'>' in "
123+
"'<class 'tests.test_routing.sample.NonPrimitiveSchema'>'can't be processed. "
124+
"Field type is not a primitive type"
125+
)
126+
127+
with pytest.raises(ImproperConfiguration) as ex:
128+
129+
@get("/test")
130+
def invalid_path_parameter(cookie: ListOfPrimitiveSchema = Cookie()):
131+
pass
132+
133+
assert (
134+
str(ex.value) == "field: 'an_int' with annotation:'typing.List[int]' in "
135+
"'<class 'tests.test_routing.sample.ListOfPrimitiveSchema'>'can't be processed. "
136+
"Field type is not a primitive type"
137+
)
Lines changed: 81 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,81 @@
1+
import pytest
2+
3+
from ellar.common import Form, post
4+
from ellar.core import TestClientFactory
5+
from ellar.core.connection import Request
6+
from ellar.core.exceptions import ImproperConfiguration
7+
from ellar.core.routing import ModuleRouter
8+
from ellar.openapi import OpenAPIDocumentBuilder
9+
from ellar.serializer import serialize_object
10+
11+
from .sample import Filter, NonPrimitiveSchema
12+
13+
mr = ModuleRouter("")
14+
15+
16+
@mr.post("/form-schema")
17+
def form_params_schema(
18+
request: Request,
19+
filters: Filter = Form(..., alias="will_not_work_for_schema_with_many_field"),
20+
):
21+
return filters.dict()
22+
23+
24+
test_module = TestClientFactory.create_test_module(routers=(mr,))
25+
26+
27+
def test_request():
28+
client = test_module.get_client()
29+
response = client.post("/form-schema", data={"from": "1", "to": "2", "range": "20"})
30+
assert response.json() == {
31+
"to_datetime": "1970-01-01T00:00:02+00:00",
32+
"from_datetime": "1970-01-01T00:00:01+00:00",
33+
"range": 20,
34+
}
35+
36+
response = client.post(
37+
"/form-schema", data={"from": "1", "to": "2", "range": "100"}
38+
)
39+
assert response.status_code == 422
40+
json = response.json()
41+
assert json == {
42+
"detail": [
43+
{
44+
"loc": ["body", "range"],
45+
"msg": "value is not a valid enumeration member; permitted: 20, 50, 200",
46+
"type": "type_error.enum",
47+
"ctx": {"enum_values": [20, 50, 200]},
48+
}
49+
]
50+
}
51+
52+
53+
def test_schema():
54+
document = serialize_object(
55+
OpenAPIDocumentBuilder().build_document(test_module.app)
56+
)
57+
params = document["paths"]["/form-schema"]["post"]["requestBody"]
58+
assert params == {
59+
"content": {
60+
"application/x-www-form-urlencoded": {
61+
"schema": {"$ref": "#/components/schemas/Filter"}
62+
}
63+
},
64+
"required": True,
65+
}
66+
67+
68+
def test_for_invalid_schema():
69+
with pytest.raises(ImproperConfiguration) as ex:
70+
71+
@post("/test")
72+
def invalid_path_parameter(path: NonPrimitiveSchema = Form()):
73+
pass
74+
75+
assert (
76+
str(ex.value)
77+
== "field: 'filter' with annotation:'<class 'tests.test_routing.sample.Filter'>' in "
78+
"'<class 'tests.test_routing.sample.NonPrimitiveSchema'>'can't be processed. "
79+
"Field type should belong to (<class 'list'>, <class 'set'>, <class 'tuple'>) "
80+
"or any primitive type"
81+
)

tests/test_routing/test_header_schema.py

Lines changed: 21 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,14 @@
1-
from ellar.common import Header
1+
import pytest
2+
3+
from ellar.common import Header, get
24
from ellar.core import TestClientFactory
35
from ellar.core.connection import Request
6+
from ellar.core.exceptions import ImproperConfiguration
47
from ellar.core.routing import ModuleRouter
58
from ellar.openapi import OpenAPIDocumentBuilder
69
from ellar.serializer import serialize_object
710

8-
from .sample import Data, Filter
11+
from .sample import Data, Filter, NonPrimitiveSchema
912

1013
mr = ModuleRouter("")
1114

@@ -105,3 +108,19 @@ def test_header_schema():
105108
"in": "header",
106109
},
107110
]
111+
112+
113+
def test_invalid_schema_header():
114+
with pytest.raises(ImproperConfiguration) as ex:
115+
116+
@get("/test")
117+
def invalid_path_parameter(cookie: NonPrimitiveSchema = Header()):
118+
pass
119+
120+
assert (
121+
str(ex.value)
122+
== "field: 'filter' with annotation:'<class 'tests.test_routing.sample.Filter'>' in "
123+
"'<class 'tests.test_routing.sample.NonPrimitiveSchema'>'can't be processed. "
124+
"Field type should belong to (<class 'list'>, <class 'set'>, <class 'tuple'>) "
125+
"or any primitive type"
126+
)
Lines changed: 100 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,100 @@
1+
import pytest
2+
3+
from ellar.common import Path, get
4+
from ellar.core import TestClientFactory
5+
from ellar.core.connection import Request
6+
from ellar.core.exceptions import ImproperConfiguration
7+
from ellar.core.routing import ModuleRouter
8+
from ellar.openapi import OpenAPIDocumentBuilder
9+
from ellar.serializer import serialize_object
10+
11+
from .sample import Filter, ListOfPrimitiveSchema, NonPrimitiveSchema
12+
13+
mr = ModuleRouter("")
14+
15+
16+
@mr.get("/path-with-schema/{from}/{to}/{range}")
17+
def path_params_schema(
18+
request: Request,
19+
filters: Filter = Path(..., alias="will_not_work_for_schema_with_many_field"),
20+
):
21+
return filters.dict()
22+
23+
24+
test_module = TestClientFactory.create_test_module(routers=(mr,))
25+
26+
27+
def test_request():
28+
client = test_module.get_client()
29+
response = client.get("/path-with-schema/1/2/20")
30+
assert response.json() == {
31+
"to_datetime": "1970-01-01T00:00:02+00:00",
32+
"from_datetime": "1970-01-01T00:00:01+00:00",
33+
"range": 20,
34+
}
35+
36+
response = client.get("/path-with-schema/1/2/100")
37+
assert response.status_code == 422
38+
assert response.json() == {
39+
"detail": [
40+
{
41+
"loc": ["path", "range"],
42+
"msg": "value is not a valid enumeration member; permitted: 20, 50, 200",
43+
"type": "type_error.enum",
44+
"ctx": {"enum_values": [20, 50, 200]},
45+
}
46+
]
47+
}
48+
49+
50+
def test_schema():
51+
document = serialize_object(
52+
OpenAPIDocumentBuilder().build_document(test_module.app)
53+
)
54+
params = document["paths"]["/path-with-schema/{from}/{to}/{range}"]["get"][
55+
"parameters"
56+
]
57+
assert params == [
58+
{
59+
"required": True,
60+
"schema": {"title": "To", "type": "string", "format": "date-time"},
61+
"name": "to",
62+
"in": "path",
63+
},
64+
{
65+
"required": True,
66+
"schema": {"title": "From", "type": "string", "format": "date-time"},
67+
"name": "from",
68+
"in": "path",
69+
},
70+
{
71+
"required": True,
72+
"schema": {"$ref": "#/components/schemas/Range"},
73+
"name": "range",
74+
"in": "path",
75+
},
76+
]
77+
78+
79+
def test_for_invalid_schema():
80+
with pytest.raises(ImproperConfiguration) as ex:
81+
82+
@get("/{filter}")
83+
def invalid_path_parameter(path: NonPrimitiveSchema = Path()):
84+
pass
85+
86+
assert (
87+
str(ex.value)
88+
== "Path params must be of one of the supported types. Only primitive types"
89+
)
90+
91+
with pytest.raises(ImproperConfiguration) as ex:
92+
93+
@get("/{int}/{float}")
94+
def invalid_path_parameter(path: ListOfPrimitiveSchema = Path()):
95+
pass
96+
97+
assert (
98+
str(ex.value)
99+
== "Path params must be of one of the supported types. Only primitive types"
100+
)

0 commit comments

Comments
 (0)