Add basic test

This commit is contained in:
phil 2024-12-14 17:34:48 +01:00
parent f2b924e9e9
commit c2a4aaac51
4 changed files with 128 additions and 22 deletions

View file

@ -60,4 +60,6 @@ dev-dependencies = [
"asyncpg-stubs>=0.29.1",
"types-python-jose>=3.3.4.20240106",
"types-passlib>=1.7.7.20240311",
"pytest>=8.3.4",
"httpx>=0.28.1",
]

View file

@ -9,15 +9,18 @@ from gisaf.baskets import Basket, standard_baskets
from gisaf.redis_tools import store
from gisaf.registry import registry
logger = logging.getLogger('Gisaf admin manager')
logger = logging.getLogger("Gisaf admin manager")
class AdminManager:
"""
Application wide manager of the admin (baskets).
One instance only, handled by Gisaf's process.
"""
store: Store
baskets: dict[str, Basket]
async def setup_admin(self):
"""
Create the default baskets, scan and create baskets
@ -28,12 +31,9 @@ class AdminManager:
# self.store = app['store']
## Standard baskets
self.baskets = {
basket.name: basket
for basket in standard_baskets
}
self.baskets = {basket.name: basket for basket in standard_baskets}
for entry_point in entry_points().select(group='gisaf_extras.baskets'):
for entry_point in entry_points().select(group="gisaf_extras.baskets"):
try:
basket_class = entry_point.load()
except ModuleNotFoundError as err:
@ -46,24 +46,32 @@ class AdminManager:
else:
name = basket_class.name
if name in self.baskets:
logger.warn(f'Skip basket {name} in {entry_point.module}: name already defined')
logger.warning(
f"Skip basket {name} in {entry_point.module}: name already defined"
)
continue
## Instanciate
basket = basket_class()
basket._custom_module = entry_point.name # type: ignore
basket._custom_module = entry_point.name # type: ignore
## Check base_dir, eventually create it
if not basket.base_dir.exists():
try:
basket.base_dir.mkdir()
except Exception as err:
logger.warn(f'Skip basket {name} in {entry_point.module}: '
f'cannot create directory for basket {name} at {basket.base_dir}')
logger.warning(
f"Skip basket {name} in {entry_point.module}: "
f"cannot create directory for basket {name} at {basket.base_dir}"
)
continue
else:
logger.info(f'Created directory for basket {name} at {basket.base_dir}')
logger.info(
f"Created directory for basket {name} at {basket.base_dir}"
)
## Add to register
self.baskets[name] = basket
logger.info(f'Added Basket {entry_point.name} from {entry_point.module}')
logger.info(
f"Added Basket {entry_point.name} from {entry_point.module}"
)
## Give a reference to the application to the baskets
# for basket in self.baskets.values():
@ -72,16 +80,17 @@ class AdminManager:
## Subscribe to admin redis channels
self.pub_categories = store.redis.pubsub()
self.pub_scheduler = store.redis.pubsub()
await self.pub_categories.psubscribe('admin:categories:update')
await self.pub_categories.psubscribe("admin:categories:update")
task1 = create_task(self._listen_to_redis_categories())
await self.pub_scheduler.psubscribe('admin:scheduler:json')
await self.pub_scheduler.psubscribe("admin:scheduler:json")
task2 = create_task(self._listen_to_redis_scheduler())
# app['admin'] = self
async def baskets_for_role(self, user: User) -> dict[str, Basket]:
return {
name: basket for name, basket in self.baskets.items()
name: basket
for name, basket in self.baskets.items()
if await basket.allowed_for(user)
}
@ -90,9 +99,9 @@ class AdminManager:
Subscribe the redis sub channel for category updates ("admin:categories:update")
"""
async for msg in self.pub_categories.listen():
if msg['type'] == 'pmessage':
if msg["type"] == "pmessage":
## XXX: Why the name isn't retrieved?
#client = await self.app['store'].pub.client_getname()
# client = await self.app['store'].pub.client_getname()
client = store.uuid
## !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
@ -100,8 +109,8 @@ class AdminManager:
## !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
## Skip for the process which sent this message actually updated its registry
#breakpoint()
if client != msg['data'].decode():
# breakpoint()
if client != msg["data"].decode():
await registry.make_registry()
async def _listen_to_redis_scheduler(self):
@ -109,8 +118,11 @@ class AdminManager:
Subscribe the redis sub channel for scheduler jobs ("admin:scheduler:json")
"""
async for msg in self.pub_scheduler.listen():
if msg['type'] == 'pmessage':
await live_server._send_to_ws_clients(msg['channel'].decode(), msg['data'].decode())
if msg["type"] == "pmessage":
await live_server._send_to_ws_clients(
msg["channel"].decode(), msg["data"].decode()
)
manager = AdminManager()

27
tests/basic.py Normal file
View file

@ -0,0 +1,27 @@
from fastapi.testclient import TestClient
from gisaf.application import app
client = TestClient(app)
def test_bootstrap():
with TestClient(app) as client:
response = client.get("/api/bootstrap")
assert response.status_code == 200
json = response.json()
assert "version" in json
assert "title" in json
assert "windowTitle" in json
assert "map" in json
assert "geo" in json
assert "measures" in json
assert json["user"] is None
assert "bearing" in json["map"]
assert "lat" in json["map"]
assert "lng" in json["map"]
assert "pitch" in json["map"]
assert "zoom" in json["map"]
assert "style" in json["map"]
assert "status" in json["map"]
assert isinstance(json["map"]["status"], list)

65
uv.lock generated
View file

@ -652,9 +652,11 @@ mqtt = [
[package.dev-dependencies]
dev = [
{ name = "asyncpg-stubs" },
{ name = "httpx" },
{ name = "ipdb" },
{ name = "pandas-stubs" },
{ name = "pretty-errors" },
{ name = "pytest" },
{ name = "types-passlib" },
{ name = "types-psycopg2" },
{ name = "types-python-jose" },
@ -699,9 +701,11 @@ requires-dist = [
[package.metadata.requires-dev]
dev = [
{ name = "asyncpg-stubs", specifier = ">=0.29.1" },
{ name = "httpx", specifier = ">=0.28.1" },
{ name = "ipdb", specifier = ">=0.13.13" },
{ name = "pandas-stubs", specifier = ">=2.1.4.231218" },
{ name = "pretty-errors", specifier = ">=1.2.25" },
{ name = "pytest", specifier = ">=8.3.4" },
{ name = "types-passlib", specifier = ">=1.7.7.20240311" },
{ name = "types-psycopg2", specifier = ">=2.9.21.20" },
{ name = "types-python-jose", specifier = ">=3.3.4.20240106" },
@ -759,6 +763,34 @@ wheels = [
{ url = "https://files.pythonhosted.org/packages/95/04/ff642e65ad6b90db43e668d70ffb6736436c7ce41fcc549f4e9472234127/h11-0.14.0-py3-none-any.whl", hash = "sha256:e3fe4ac4b851c468cc8363d500db52c2ead036020723024a109d37346efaa761", size = 58259 },
]
[[package]]
name = "httpcore"
version = "1.0.7"
source = { registry = "https://pypi.org/simple" }
dependencies = [
{ name = "certifi" },
{ name = "h11" },
]
sdist = { url = "https://files.pythonhosted.org/packages/6a/41/d7d0a89eb493922c37d343b607bc1b5da7f5be7e383740b4753ad8943e90/httpcore-1.0.7.tar.gz", hash = "sha256:8551cb62a169ec7162ac7be8d4817d561f60e08eaa485234898414bb5a8a0b4c", size = 85196 }
wheels = [
{ url = "https://files.pythonhosted.org/packages/87/f5/72347bc88306acb359581ac4d52f23c0ef445b57157adedb9aee0cd689d2/httpcore-1.0.7-py3-none-any.whl", hash = "sha256:a3fff8f43dc260d5bd363d9f9cf1830fa3a458b332856f34282de498ed420edd", size = 78551 },
]
[[package]]
name = "httpx"
version = "0.28.1"
source = { registry = "https://pypi.org/simple" }
dependencies = [
{ name = "anyio" },
{ name = "certifi" },
{ name = "httpcore" },
{ name = "idna" },
]
sdist = { url = "https://files.pythonhosted.org/packages/b1/df/48c586a5fe32a0f01324ee087459e112ebb7224f646c0b5023f5e79e9956/httpx-0.28.1.tar.gz", hash = "sha256:75e98c5f16b0f35b567856f597f06ff2270a374470a5c2392242528e3e3e42fc", size = 141406 }
wheels = [
{ url = "https://files.pythonhosted.org/packages/2a/39/e50c7c3a983047577ee07d2a9e53faf5a69493943ec3f6a384bdc792deb2/httpx-0.28.1-py3-none-any.whl", hash = "sha256:d909fcccc110f8c7faf814ca82a9a4d816bc5a6dbfea25d6591d6985b8ba59ad", size = 73517 },
]
[[package]]
name = "idna"
version = "3.10"
@ -768,6 +800,15 @@ wheels = [
{ url = "https://files.pythonhosted.org/packages/76/c6/c88e154df9c4e1a2a66ccf0005a88dfb2650c1dffb6f5ce603dfbd452ce3/idna-3.10-py3-none-any.whl", hash = "sha256:946d195a0d259cbba61165e88e65941f16e9b36ea6ddb97f00452bae8b1287d3", size = 70442 },
]
[[package]]
name = "iniconfig"
version = "2.0.0"
source = { registry = "https://pypi.org/simple" }
sdist = { url = "https://files.pythonhosted.org/packages/d7/4b/cbd8e699e64a6f16ca3a8220661b5f83792b3017d0f79807cb8708d33913/iniconfig-2.0.0.tar.gz", hash = "sha256:2d91e135bf72d31a410b17c16da610a82cb55f6b0477d1a902134b24a455b8b3", size = 4646 }
wheels = [
{ url = "https://files.pythonhosted.org/packages/ef/a6/62565a6e1cf69e10f5727360368e451d4b7f58beeac6173dc9db836a5b46/iniconfig-2.0.0-py3-none-any.whl", hash = "sha256:b6a85871a79d2e3b22d2d1b94ac2824226a63c6b741c88f7ae975f18b6778374", size = 5892 },
]
[[package]]
name = "ipdb"
version = "0.13.13"
@ -1215,6 +1256,15 @@ wheels = [
{ url = "https://files.pythonhosted.org/packages/e5/ae/580600f441f6fc05218bd6c9d5794f4aef072a7d9093b291f1c50a9db8bc/plotly-5.24.1-py3-none-any.whl", hash = "sha256:f67073a1e637eb0dc3e46324d9d51e2fe76e9727c892dde64ddf1e1b51f29089", size = 19054220 },
]
[[package]]
name = "pluggy"
version = "1.5.0"
source = { registry = "https://pypi.org/simple" }
sdist = { url = "https://files.pythonhosted.org/packages/96/2d/02d4312c973c6050a18b314a5ad0b3210edb65a906f868e31c111dede4a6/pluggy-1.5.0.tar.gz", hash = "sha256:2cffa88e94fdc978c4c574f15f9e59b7f4201d439195c3715ca9e2486f1d0cf1", size = 67955 }
wheels = [
{ url = "https://files.pythonhosted.org/packages/88/5f/e351af9a41f866ac3f1fac4ca0613908d9a41741cfcf2228f4ad853b697d/pluggy-1.5.0-py3-none-any.whl", hash = "sha256:44e1ad92c8ca002de6377e165f3e0f1be63266ab4d554740532335b9d75ea669", size = 20556 },
]
[[package]]
name = "pretty-errors"
version = "1.2.25"
@ -1517,6 +1567,21 @@ wheels = [
{ url = "https://files.pythonhosted.org/packages/98/2f/68116db5b36b895c0450e3072b8cb6c2fac0359279b182ea97014d3c8ac0/pyshp-2.3.1-py2.py3-none-any.whl", hash = "sha256:67024c0ccdc352ba5db777c4e968483782dfa78f8e200672a90d2d30fd8b7b49", size = 46537 },
]
[[package]]
name = "pytest"
version = "8.3.4"
source = { registry = "https://pypi.org/simple" }
dependencies = [
{ name = "colorama", marker = "sys_platform == 'win32'" },
{ name = "iniconfig" },
{ name = "packaging" },
{ name = "pluggy" },
]
sdist = { url = "https://files.pythonhosted.org/packages/05/35/30e0d83068951d90a01852cb1cef56e5d8a09d20c7f511634cc2f7e0372a/pytest-8.3.4.tar.gz", hash = "sha256:965370d062bce11e73868e0335abac31b4d3de0e82f4007408d242b4f8610761", size = 1445919 }
wheels = [
{ url = "https://files.pythonhosted.org/packages/11/92/76a1c94d3afee238333bc0a42b82935dd8f9cf8ce9e336ff87ee14d9e1cf/pytest-8.3.4-py3-none-any.whl", hash = "sha256:50e16d954148559c9a74109af1eaf0c945ba2d8f30f0a3d3335edde19788b6f6", size = 343083 },
]
[[package]]
name = "python-dateutil"
version = "2.9.0.post0"