Skip to content

Commit cf4d2e5

Browse files
committed
fix tests
1 parent e2982c5 commit cf4d2e5

File tree

4 files changed

+217
-41
lines changed

4 files changed

+217
-41
lines changed

services/web/server/src/simcore_service_webserver/products/_web_helpers.py

Lines changed: 45 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -48,45 +48,60 @@ def _themed(dirname: str, template: str) -> Path:
4848
return path
4949

5050

51-
def _safe_get_current_product(request: web.Request) -> Product | None:
51+
def _get_current_product_or_none(request: web.Request) -> Product | None:
5252
try:
5353
product: Product = get_current_product(request)
5454
return product
5555
except KeyError:
5656
return None
5757

5858

59-
async def get_product_template_path(request: web.Request, filename: str) -> Path:
60-
if product := _safe_get_current_product(request):
61-
if template_name := product.get_template_name_for(filename):
62-
template_dir: Path = request.app[APP_PRODUCTS_TEMPLATES_DIR_KEY]
63-
template_path = template_dir / template_name
64-
if not template_path.exists():
65-
# cache
66-
content = await _service.get_template_content(
67-
request.app, template_name=template_name
68-
)
69-
try:
70-
async with aiofiles.open(template_path, "w") as fh:
71-
await fh.write(content)
72-
except Exception:
73-
# fails to write
74-
if template_path.exists():
75-
template_path.unlink()
76-
raise
77-
78-
return template_path
79-
80-
# check static resources under templates/
81-
if (
82-
template_path := _themed(f"templates/{product.name}", filename)
83-
) and template_path.exists():
84-
return template_path
85-
86-
# If no product or template for product defined, we fall back to common templates
59+
async def _get_common_template_path(filename: str) -> Path:
8760
common_template = _themed("templates/common", filename)
8861
if not common_template.exists():
8962
msg = f"{filename} is not part of the templates/common"
9063
raise ValueError(msg)
91-
9264
return common_template
65+
66+
67+
async def _cache_template_content(
68+
request: web.Request, template_path: Path, template_name: str
69+
) -> None:
70+
content = await _service.get_template_content(
71+
request.app, template_name=template_name
72+
)
73+
try:
74+
async with aiofiles.open(template_path, "w") as fh:
75+
await fh.write(content)
76+
except Exception:
77+
if template_path.exists():
78+
template_path.unlink()
79+
raise
80+
81+
82+
async def _get_product_specific_template_path(
83+
request: web.Request, product: Product, filename: str
84+
) -> Path | None:
85+
if template_name := product.get_template_name_for(filename):
86+
template_dir: Path = request.app[APP_PRODUCTS_TEMPLATES_DIR_KEY]
87+
template_path = template_dir / template_name
88+
if not template_path.exists():
89+
await _cache_template_content(request, template_path, template_name)
90+
return template_path
91+
92+
template_path = _themed(f"templates/{product.name}", filename)
93+
if template_path.exists():
94+
return template_path
95+
96+
return None
97+
98+
99+
async def get_product_template_path(request: web.Request, filename: str) -> Path:
100+
if (product := _get_current_product_or_none(request)) and (
101+
template_path := await _get_product_specific_template_path(
102+
request, product, filename
103+
)
104+
):
105+
return template_path
106+
107+
return await _get_common_template_path(filename)

services/web/server/tests/unit/with_dbs/04/products/conftest.py

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,8 +4,15 @@
44

55

66
import pytest
7+
from models_library.products import ProductName
78
from pytest_simcore.helpers.monkeypatch_envs import setenvs_from_dict
89
from pytest_simcore.helpers.typing_env import EnvVarsDict
10+
from simcore_service_webserver.constants import FRONTEND_APP_DEFAULT
11+
12+
13+
@pytest.fixture
14+
def default_product_name() -> ProductName:
15+
return FRONTEND_APP_DEFAULT
916

1017

1118
@pytest.fixture

services/web/server/tests/unit/with_dbs/04/products/test_products_service.py

Lines changed: 5 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -6,26 +6,20 @@
66

77
import pytest
88
from aiohttp import web
9-
from aiohttp.test_utils import TestClient
9+
from aiohttp.test_utils import TestServer
1010
from models_library.products import ProductName
11-
from simcore_service_webserver.constants import FRONTEND_APP_DEFAULT
1211
from simcore_service_webserver.products import products_service
1312
from simcore_service_webserver.products._repository import ProductRepository
1413
from simcore_service_webserver.products.errors import ProductPriceNotDefinedError
1514

1615

1716
@pytest.fixture
1817
def app(
19-
client: TestClient,
18+
web_server: TestServer,
2019
) -> web.Application:
21-
# initialized app
22-
assert client.app
23-
return client.app
24-
25-
26-
@pytest.fixture
27-
def default_product_name() -> ProductName:
28-
return FRONTEND_APP_DEFAULT
20+
# app initialized and server running
21+
assert web_server.app
22+
return web_server.app
2923

3024

3125
async def test_get_product(app: web.Application, default_product_name: ProductName):
Lines changed: 160 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,160 @@
1+
# pylint: disable=redefined-outer-name
2+
# pylint: disable=unused-argument
3+
# pylint: disable=unused-variable
4+
# pylint: disable=too-many-arguments
5+
6+
7+
import pytest
8+
from aiohttp import web
9+
from aiohttp.test_utils import TestClient, make_mocked_request
10+
from common_library.json_serialization import json_dumps
11+
from models_library.products import ProductName
12+
from pytest_mock import MockerFixture, MockType
13+
from servicelib.rest_constants import X_PRODUCT_NAME_HEADER
14+
from simcore_service_webserver._meta import API_VTAG
15+
from simcore_service_webserver.products import products_web
16+
from simcore_service_webserver.products.plugin import setup_products
17+
18+
19+
@pytest.fixture
20+
def setup_products_mocked(mocker: MockerFixture) -> MockType:
21+
def _wrap(app: web.Application):
22+
setup_products(app)
23+
24+
# register test handlers
25+
app.router.add_get(
26+
f"/{API_VTAG}/test-helpers",
27+
_test_helpers_handler,
28+
name=_test_helpers_handler.__name__,
29+
)
30+
app.router.add_get(
31+
f"/{API_VTAG}/test-product-template-helpers",
32+
_test_product_template_handler,
33+
name=_test_product_template_handler.__name__,
34+
)
35+
36+
return True
37+
38+
return mocker.patch(
39+
"simcore_service_webserver.application.setup_products",
40+
autospec=True,
41+
side_effect=_wrap,
42+
)
43+
44+
45+
@pytest.fixture
46+
def client(
47+
setup_products_mocked: MockType, # keep before client fixture!
48+
client: TestClient,
49+
) -> TestClient:
50+
assert setup_products_mocked.called
51+
52+
assert client.app
53+
assert client.app.router
54+
55+
registered_routes = {
56+
route.resource.canonical
57+
for route in client.app.router.routes()
58+
if route.resource
59+
}
60+
assert f"/{API_VTAG}/test-helpers" in registered_routes
61+
62+
return client
63+
64+
65+
async def _test_helpers_handler(request: web.Request):
66+
product_name = products_web.get_product_name(request)
67+
current_product = products_web.get_current_product(request)
68+
69+
assert current_product.name == product_name
70+
71+
credit_price_info = await products_web.get_current_product_credit_price_info(
72+
request
73+
)
74+
assert credit_price_info is None
75+
76+
return web.json_response(
77+
json_dumps(
78+
{
79+
"current_product": current_product,
80+
"get_producproduct_namet_name": product_name,
81+
"credit_price_info": credit_price_info,
82+
}
83+
)
84+
)
85+
86+
87+
async def test_request_helpers(client: TestClient, default_product_name: ProductName):
88+
89+
resp = await client.get(
90+
f"/{API_VTAG}/test-helpers",
91+
headers={X_PRODUCT_NAME_HEADER: default_product_name},
92+
)
93+
94+
assert resp.ok, f"Got {await resp.text()}"
95+
96+
got = await resp.json()
97+
assert got["current_product"] == default_product_name
98+
99+
100+
async def _test_product_template_handler(request: web.Request):
101+
product_name = products_web.get_product_name(request)
102+
103+
# if no product, it should return common
104+
105+
# if no template for product, it should return common
106+
# template/common/close_account.jinja2"
107+
template_path = await products_web.get_product_template_path(
108+
request, filename="close_account.jinja2"
109+
)
110+
assert template_path.exists()
111+
assert template_path.name == "close_account.jinja2"
112+
assert "common/" in f"{template_path.resolve().absolute()}"
113+
114+
# if specific template, it gets and caches in file
115+
# "templates/osparc/registration_email.jinja2"
116+
template_path = await products_web.get_product_template_path(
117+
request, filename="registration_email.jinja2"
118+
)
119+
assert template_path.exists()
120+
assert template_path.name == "registration_email.jinja2"
121+
assert f"{product_name}/" in f"{template_path.resolve().absolute()}"
122+
123+
# get again and should use file
124+
125+
for _ in range(2):
126+
got = await products_web.get_product_template_path(
127+
request, filename="registration_email.jinja2"
128+
)
129+
assert got == template_path
130+
131+
path = await products_web.get_product_template_path(
132+
request, filename="invalid-template-name.jinja"
133+
)
134+
assert path
135+
return web.json_response()
136+
137+
138+
async def test_product_template_helpers(
139+
client: TestClient, default_product_name: ProductName
140+
):
141+
142+
resp = await client.get(
143+
f"/{API_VTAG}/test-product-template-helpers",
144+
headers={X_PRODUCT_NAME_HEADER: default_product_name},
145+
)
146+
147+
assert resp.ok, f"Got {await resp.text()}"
148+
149+
150+
async def test_get_product_template_path_without_product():
151+
fake_request = make_mocked_request("GET", "/fake", app=web.Application())
152+
153+
# if no product, it should return common
154+
template_path = await products_web.get_product_template_path(
155+
fake_request, filename="close_account.jinja2"
156+
)
157+
158+
assert template_path.exists()
159+
assert template_path.name == "close_account.jinja2"
160+
assert "common/" in f"{template_path.resolve().absolute()}"

0 commit comments

Comments
 (0)