Skip to content

Commit 1dc6cf0

Browse files
committed
Added test for controller routing
1 parent 174e00f commit 1dc6cf0

File tree

11 files changed

+474
-19
lines changed

11 files changed

+474
-19
lines changed

examples/catapp/application/cats/routers.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
from dataclasses import dataclass
33

44
from catapp.application.cats.services import CatService
5-
from ellar.serializer import DataClassSerializer
5+
from ellar.serializer import DataclassSerializer
66
from ellar.core.routing import ModuleRouter
77
from ellar.common import Provide, Req, Render
88
from ellar.core.templating import render_template
@@ -11,7 +11,7 @@
1111

1212

1313
@dataclass
14-
class CatObject(DataClassSerializer):
14+
class CatObject(DataclassSerializer):
1515
name: str
1616

1717

File renamed without changes.

tests/test_controller/sample.py

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
from ellar.common import Controller, Get, WsRoute
2+
from ellar.core.routing import ControllerBase, ModuleRouter
3+
4+
5+
@Controller("/prefix")
6+
class SampleController(ControllerBase):
7+
@Get("/sample")
8+
def sample_example(self):
9+
pass
10+
11+
@WsRoute("/sample")
12+
def sample_example_ws(self):
13+
pass
14+
15+
16+
router = ModuleRouter("/prefix/router", name="mr")
17+
18+
19+
@router.Get("/example")
20+
def example(ctx):
21+
pass

tests/test_controller/test_application_router.py

Whitespace-only changes.
Lines changed: 159 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,159 @@
1+
import pytest
2+
3+
from ellar.common import Get, HttpRoute, WsRoute
4+
from ellar.core import ControllerBase
5+
from ellar.core.routing import ControllerDecorator, ControllerRouter, ControllerType
6+
from ellar.di import has_binding, is_decorated_with_injectable
7+
8+
from .sample import SampleController
9+
10+
11+
class SomeController(ControllerBase):
12+
def __init__(self, a: str):
13+
self.a = a
14+
15+
@Get("/sample")
16+
def some_example(self):
17+
pass
18+
19+
@Get("/sample")
20+
def some_example_3(self):
21+
# some_example_3 overrides `sample_example` OPERATION since its the same 'path' and 'method'
22+
pass
23+
24+
@HttpRoute("/sample", methods=["get"])
25+
def some_example_4(self):
26+
# some_example_4 overrides `sample_example_3` OPERATION since its the same 'path' and 'method'
27+
pass
28+
29+
@HttpRoute("/sample", methods=["get", "post"])
30+
def some_example_5(self):
31+
# `sample_example_4 - Get` overrides `sample_example_5 - Get` RUNTIME CALL in that order
32+
# And '/sample' POST call will be handled here
33+
pass
34+
35+
@WsRoute("/sample")
36+
def some_example_ws(self):
37+
pass
38+
39+
@WsRoute("/sample")
40+
def some_example_ws_2(self):
41+
# `some_example_ws_2` overrides `some_example_ws` OPERATION
42+
pass
43+
44+
45+
def test_get_controller_type():
46+
assert isinstance(SampleController, ControllerDecorator)
47+
assert SampleController.get_controller_type()
48+
assert isinstance(SampleController.get_controller_type(), ControllerType)
49+
50+
with pytest.raises(AssertionError):
51+
ControllerDecorator().get_controller_type()
52+
53+
with pytest.raises(AssertionError):
54+
ControllerDecorator().get_router()
55+
56+
57+
def test_controller_computed_properties():
58+
assert isinstance(SampleController, ControllerDecorator)
59+
controller_type = SampleController.get_controller_type()
60+
61+
assert is_decorated_with_injectable(controller_type)
62+
assert not has_binding(controller_type)
63+
assert SampleController.get_meta() == {
64+
"tag": "sample",
65+
"description": None,
66+
"external_doc_description": None,
67+
"external_doc_url": None,
68+
"path": "/prefix",
69+
"name": "sample",
70+
"version": set(),
71+
"guards": [],
72+
"include_in_schema": True,
73+
}
74+
new_controller = ControllerDecorator(
75+
prefix="/items/{orgID:int}",
76+
tag="Item",
77+
description="Some Controller",
78+
external_doc_url="https://test.com",
79+
external_doc_description="Find out more here",
80+
)(SomeController)
81+
assert new_controller.get_meta() == {
82+
"tag": "Item",
83+
"description": "Some Controller",
84+
"external_doc_description": "Find out more here",
85+
"external_doc_url": "https://test.com",
86+
"path": "/items/{orgID:int}",
87+
"name": "some",
88+
"version": set(),
89+
"guards": [],
90+
"include_in_schema": True,
91+
}
92+
assert is_decorated_with_injectable(new_controller.get_controller_type())
93+
assert has_binding(new_controller.get_controller_type())
94+
95+
96+
@pytest.mark.parametrize(
97+
"controller_decorator, routes_count",
98+
[
99+
(SampleController, 2),
100+
(
101+
ControllerDecorator(
102+
prefix="/items/{orgID:int}",
103+
)(SomeController),
104+
3,
105+
),
106+
],
107+
)
108+
def test_get_mount(controller_decorator, routes_count):
109+
assert isinstance(controller_decorator, ControllerDecorator)
110+
controller_router = controller_decorator.get_router()
111+
assert isinstance(controller_router, ControllerRouter)
112+
assert len(controller_router.routes) == routes_count
113+
114+
115+
def test_tag_configuration_controller_decorator():
116+
new_controller = ControllerDecorator(
117+
prefix="/items/{orgID:int}", name="override_name", tag="new_tag"
118+
)(SomeController)
119+
assert new_controller.get_meta()["tag"] == "new_tag"
120+
assert new_controller.get_meta()["name"] == "override_name"
121+
122+
# defaults to controller name
123+
new_controller = ControllerDecorator(
124+
prefix="/items/{orgID:int}",
125+
)(SomeController)
126+
assert new_controller.get_meta()["tag"] == "some"
127+
assert new_controller.get_meta()["name"] == "some"
128+
129+
new_controller = ControllerDecorator(prefix="/items/{orgID:int}", tag="new_tag")(
130+
SomeController
131+
)
132+
assert new_controller.get_meta()["tag"] == "new_tag"
133+
assert new_controller.get_meta()["name"] == "some"
134+
135+
136+
@pytest.mark.parametrize(
137+
"controller_decorator, tag, prefix, name",
138+
[
139+
(SampleController, "sample", "/prefix", "sample"),
140+
(
141+
ControllerDecorator(
142+
prefix="/items/{orgID:int}", name="override_name", tag="new_tag"
143+
)(SomeController),
144+
"new_tag",
145+
"/items/{orgID:int}",
146+
"override_name",
147+
),
148+
],
149+
)
150+
def test_build_routes(controller_decorator, tag, prefix, name):
151+
controller_decorator.build_routes()
152+
router = controller_decorator.get_router()
153+
154+
for route in router.routes:
155+
assert name in route.name
156+
assert prefix in route.path
157+
if "WS" not in route.methods:
158+
assert tag in route.get_meta().openapi.tags
159+
assert router.controller_type is controller_decorator.get_controller_type()
Lines changed: 97 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,97 @@
1+
import pytest
2+
3+
from ellar.core.routing import ModuleRouter
4+
5+
from .sample import router
6+
7+
another_router = ModuleRouter("/prefix/another", tag="another_router", name="arouter")
8+
9+
10+
@another_router.Get("/sample")
11+
def some_example(self):
12+
pass
13+
14+
15+
@another_router.Get("/sample")
16+
def some_example_3():
17+
# some_example_3 overrides `sample_example` OPERATION since its the same 'path' and 'method'
18+
pass
19+
20+
21+
@another_router.HttpRoute("/sample", methods=["get"])
22+
def some_example_4():
23+
# some_example_4 overrides `sample_example_3` OPERATION since its the same 'path' and 'method'
24+
pass
25+
26+
27+
@another_router.HttpRoute("/sample", methods=["get", "post"])
28+
def some_example_5():
29+
# `sample_example_4 - Get` overrides `sample_example_5 - Get` RUNTIME CALL in that order
30+
# And '/sample' POST call will be handled here
31+
pass
32+
33+
34+
@another_router.WsRoute("/sample")
35+
def some_example_ws():
36+
pass
37+
38+
39+
@another_router.WsRoute("/sample")
40+
def some_example_ws_2():
41+
# `some_example_ws_2` overrides `some_example_ws` OPERATION
42+
pass
43+
44+
45+
@pytest.mark.parametrize(
46+
"router_instance, prefix, tag, name",
47+
[
48+
(router, "/prefix", "mr", "mr"),
49+
(another_router, "/prefix/another", "another_router", "arouter"),
50+
],
51+
)
52+
def test_build_routes(router_instance, prefix, tag, name):
53+
router_instance.build_routes()
54+
55+
for route in router_instance.routes:
56+
assert name in route.name
57+
assert prefix in route.path
58+
if "WS" not in route.methods:
59+
assert tag in route.get_meta().openapi.tags
60+
61+
62+
def test_tag_configuration_module_router():
63+
new_router = ModuleRouter("/items/{orgID:int}", name="override_name", tag="new_tag")
64+
assert new_router.get_meta()["tag"] == "new_tag"
65+
assert new_router.name == "override_name"
66+
67+
new_router = ModuleRouter("/items/{orgID:int}", name="new_name")
68+
assert new_router.get_meta()["tag"] == "new_name"
69+
assert new_router.name == "new_name"
70+
71+
new_controller = ModuleRouter("/items/{orgID:int}", tag="new_tag")
72+
assert new_controller.get_meta()["tag"] == "new_tag"
73+
assert new_controller.name is None
74+
75+
new_router = ModuleRouter("/items/{orgID:int}")
76+
assert new_router.get_meta()["tag"] == "Module Router"
77+
assert new_router.name is None
78+
79+
80+
def test_flatten_name_module_route_build():
81+
new_router = ModuleRouter("/items/{orgID:int}", name="has_name")
82+
83+
@new_router.Get
84+
def some_route():
85+
pass
86+
87+
new_router.build_routes()
88+
assert "has_name" in new_router.routes[0].name
89+
90+
new_router = ModuleRouter("/items/{orgID:int}")
91+
92+
@new_router.Get
93+
def some_route():
94+
pass
95+
96+
new_router.build_routes()
97+
assert "has_name" not in new_router.routes[0].name

0 commit comments

Comments
 (0)