test updates

This commit is contained in:
John Lancaster
2024-09-04 23:50:57 -05:00
parent b673bda1f2
commit 7a8e6f383a
6 changed files with 89 additions and 29 deletions

View File

@@ -20,6 +20,9 @@ build-backend = "hatchling.build"
managed = true
dev-dependencies = []
[tool.ruff.format]
quote-style = "single"
[tool.hatch.metadata]
allow-direct-references = true

View File

@@ -1,2 +1,2 @@
def hello() -> str:
return "Hello from ad-test!"
return 'Hello from ad-test!'

View File

@@ -38,7 +38,7 @@ def base_config() -> AppDaemonConfig:
time_zone='America/Chicago',
config_dir=CONFIG_DIR,
config_file='appdaemon.yaml',
module_debug={'_app_management': 'DEBUG'}
module_debug={'_app_management': 'DEBUG'},
)
@@ -48,6 +48,10 @@ def ad(base_config: AppDaemonConfig):
ad = AppDaemon(Logging(), loop, base_config)
import sys
sys.path.insert(0, (CONFIG_DIR / 'apps/food-repo/src').as_posix())
for cfg in ad.logging.config.values():
logger = logging.getLogger(cfg['name'])
logger.propagate = True

View File

@@ -3,16 +3,14 @@ import logging
import re
from pathlib import Path
import food.menu
import pytest
from appdaemon.appdaemon import AppDaemon
from git import Repo
from . import utils
from .utils import (
count_error_lines,
get_app_orders,
get_load_order,
get_loaded_apps,
reset_file,
)
@@ -20,6 +18,8 @@ INDENT = ' ' * 4
def test_file(ad: AppDaemon, caplog: pytest.LogCaptureFixture, config_repo: Repo):
import food.menu
module_file = Path(food.menu.__file__)
file_content = module_file.read_text()
@@ -40,7 +40,11 @@ def test_file(ad: AppDaemon, caplog: pytest.LogCaptureFixture, config_repo: Repo
reset_file(config_repo, module_file)
def test_file_with_error(ad: AppDaemon, caplog: pytest.LogCaptureFixture, config_repo: Repo):
def test_file_with_error(
ad: AppDaemon, caplog: pytest.LogCaptureFixture, config_repo: Repo
):
import food.menu
module_file = Path(food.menu.__file__)
file_content = module_file.read_text().splitlines()
@@ -61,23 +65,38 @@ def test_file_with_error(ad: AppDaemon, caplog: pytest.LogCaptureFixture, config
reset_file(config_repo, module_file)
def test_modification_child(ad: AppDaemon, caplog: pytest.LogCaptureFixture, config_repo: Repo):
def test_modification_child(
ad: AppDaemon, caplog: pytest.LogCaptureFixture, config_repo: Repo
):
assert isinstance(ad, AppDaemon)
ad.loop.run_until_complete(asyncio.sleep(2.5))
module_file = Path(__file__).parents[2] / 'conf/apps/family/child.py'
file_content = module_file.read_text()
file_content += (INDENT * 2) + "self.log(f'Modified {self.__class__.__name__}')\n"
module_file.write_text(file_content)
utils.inject_into_file(module_file, 2, 'raise ImportError')
try:
with caplog.at_level(logging.DEBUG):
ad.loop.run_until_complete(asyncio.sleep(1.0))
assert count_error_lines(caplog) == 0
assert get_loaded_apps(caplog) == {'child'}
assert get_app_orders(caplog, 'stop') == ['child', 'parent', 'grand-parent']
assert get_app_orders(caplog, 'start') == ['child', 'parent', 'grand-parent']
assert "Error importing 'child'" in caplog.text
load_order = utils.get_load_order(caplog)
assert load_order == ['child', 'sibling'] # sibling is a variant of child
stopping = get_app_orders(caplog, 'stop', ordered=False)
assert stopping is not None, 'Failed to get app stop order'
assert stopping == {'child_app', 'sibling_app'}
# start_order = get_app_orders(caplog, 'start')
# assert start_order is None
# assert start_order == ['child', 'parent', 'grand-parent'], f'Wrong app start order: {start_order}'
finally:
reset_file(config_repo, module_file)
ad.loop.run_until_complete(asyncio.sleep(1.0))
start_order = get_app_orders(caplog, 'start', ordered=False)
assert start_order == {
'child_app',
'sibling_app',
}, f'Wrong app start order: {start_order}'

View File

@@ -5,7 +5,7 @@ from typing import List
import pytest
from appdaemon.appdaemon import AppDaemon
from .utils import get_load_order, count_error_lines
from .utils import count_error_lines, get_load_order
def validate_app_dependencies(ad: AppDaemon):

View File

@@ -1,7 +1,7 @@
import asyncio
import re
from pathlib import Path
from typing import List
from typing import Generator, List, Literal
import pytest
from appdaemon.appdaemon import AppDaemon
@@ -13,23 +13,47 @@ async def delayed_stop(ad: AppDaemon, delay: float):
ad.stop()
def get_load_order(caplog: pytest.LogCaptureFixture) -> List[str]:
for record in caplog.records:
if record.name == 'AppDaemon._app_management':
if 'Determined module load order' in record.msg:
return record.args[0]
def get_load_order(
caplog: pytest.LogCaptureFixture, ordered: bool = True
) -> Generator[str, None, None]:
records = (
record.args[0]
for record in get_logger_records(caplog, 'AppDaemon._app_management')
if 'Determined module load order' in record.msg
)
try:
result = list(records)[-1]
if not ordered:
result = set(result)
return result
except Exception:
return
def get_logger_records(caplog: pytest.LogCaptureFixture, name: str):
def get_logger_records(caplog: pytest.LogCaptureFixture, logger_name: str):
for record in caplog.records:
if record.name == name:
if record.name == logger_name:
yield record
def get_app_orders(caplog: pytest.LogCaptureFixture, phase: str) -> List[str]:
for record in get_logger_records(caplog, 'AppDaemon._app_management'):
if re.search(f'App {phase} order', record.msg):
return record.args[0]
def get_app_orders(
caplog: pytest.LogCaptureFixture,
phase: Literal['start', 'stop'],
ordered: bool = True,
) -> list[str]:
"""Extracts the app start/stop order from the captured log lines"""
records = (
record.args[0]
for record in get_logger_records(caplog, 'AppDaemon._app_management')
if re.search(f'App {phase} order', record.msg)
)
try:
result = list(records)[-1]
if not ordered:
result = set(result)
return result
except Exception:
return
def get_loaded_apps(caplog: pytest.LogCaptureFixture):
@@ -39,7 +63,9 @@ def get_loaded_apps(caplog: pytest.LogCaptureFixture):
def count_error_lines(caplog: pytest.LogCaptureFixture) -> int:
error_log_lines = [msg for name, lvl, msg in caplog.record_tuples if name.startswith('Error')]
error_log_lines = [
msg for name, lvl, msg in caplog.record_tuples if name.startswith('Error')
]
return len(error_log_lines)
@@ -47,3 +73,11 @@ def reset_file(repo: Repo, changed: Path):
if not changed.is_absolute():
changed = Path(repo.working_tree_dir) / changed
repo.git.checkout('HEAD', '--', changed)
def inject_into_file(file: Path, pos: int, line: str):
content = file.read_text()
lines = content.splitlines()
lines.insert(pos, line)
new_content = '\n'.join(lines)
file.write_text(new_content)