Skip to content

Commit c7f9f24

Browse files
committed
Merge branch 'init-event-discard'
1 parent 3c6e208 commit c7f9f24

File tree

13 files changed

+73
-65
lines changed

13 files changed

+73
-65
lines changed

tests/conf/apps/event_test_app.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ class TestEventCallback(ADAPI):
1717
listen_kwargs: The keyword arguments to pass to the listen_event method
1818
fire_kwargs: The keyword arguments to pass to the fire_event method
1919
"""
20+
2021
def initialize(self):
2122
self.execute_event = asyncio.Event()
2223
self.listen_event(self.event_callback, self.event, **self.listen_kwargs)

tests/conf/apps/scheduler_test_app.py

Lines changed: 22 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -5,15 +5,18 @@
55

66
class SchedulerTestAppMode(str, Enum):
77
"""Enum for different modes of the SchedulerTestApp."""
8+
89
RUN_EVERY = "run_every"
910

1011

1112
class SchedulerTestApp(ADAPI):
1213
def initialize(self):
13-
self.set_log_level('DEBUG')
14+
self.set_log_level("DEBUG")
1415
self.log("SchedulerTestApp initialized")
1516
self.set_namespace("test")
17+
self.run_in(self.setup_callback, delay=self.register_delay)
1618

19+
def setup_callback(self, **kwargs) -> None:
1720
self.log(f"Running in {self.mode} mode")
1821
match self.mode:
1922
case SchedulerTestAppMode.RUN_EVERY:
@@ -26,30 +29,41 @@ def initialize(self):
2629
def mode(self) -> SchedulerTestAppMode:
2730
return SchedulerTestAppMode(self.args.get("mode", SchedulerTestAppMode.RUN_EVERY))
2831

32+
@property
33+
def register_delay(self) -> float:
34+
return self.args.get("register_delay", 0.5)
35+
2936
def run_every_callback(self, **kwargs) -> None:
3037
"""Callback function for run_every."""
3138
self.log(f"Run every callback executed with kwargs: {kwargs}")
3239

3340

34-
3541
class TestSchedulerRunIn(ADAPI):
3642
"""A test app to verify run_in functionality."""
3743

3844
def initialize(self):
45+
self.set_log_level("DEBUG")
3946
self.set_namespace("test")
40-
41-
assert "delay" in self.args, "Delay argument is required"
42-
delay = self.args["delay"]
43-
self.logger.info(f"Running with a delay of {delay} seconds")
44-
45-
self.run_in(self.run_in_callback, delay=delay, test_id=self.test_id)
47+
self.run_in(self.setup_callback, delay=self.register_delay)
4648
self.logger.info(f"{self.__class__.__name__} initialized")
4749

4850
@property
4951
def test_id(self) -> str:
5052
"""Unique identifier for the test run."""
5153
return self.args.get("test_id", "default_test_id")
5254

55+
@property
56+
def register_delay(self) -> float:
57+
return self.args.get("register_delay", 0.5)
58+
59+
def setup_callback(self, **kwargs) -> None:
60+
assert "delay" in self.args, "Delay argument is required"
61+
delay = self.args["delay"]
62+
self.logger.info(f"Running with a delay of {delay} seconds")
63+
64+
self.run_in(self.run_in_callback, delay=delay, test_id=self.test_id)
65+
# self.log(json.dumps(self.get_scheduler_entries(), default=str, indent=2))
66+
5367
def run_in_callback(self, **kwargs) -> None:
5468
"""Callback function for run_in."""
5569
self.logger.info("Run in callback executed with kwargs: %s", kwargs)

tests/conf/apps/state_test_app.py

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,6 @@ def _generate_next_value_(name, start, count, last_values):
2020
NEW_ATTRIBUTE_FILTER_NEGATIVE = auto()
2121

2222

23-
2423
TEST_ENTITY = "test.some_entity"
2524

2625

@@ -55,7 +54,7 @@ def state_callback(self, entity: str, attribute: str, old: Any, new: Any, **kwar
5554
assert isinstance(entity, str), "Entity should be a string"
5655
assert isinstance(attribute, str), "Attribute should be a string"
5756

58-
self.log(f' {entity}.{attribute} '.center(40, '-'))
57+
self.log(f" {entity}.{attribute} ".center(40, "-"))
5958
self.log(f"{entity}.{attribute} changed from {old} to {new} with kwargs: {kwargs}")
6059

6160
new_state = self.get_state(entity, attribute="all")

tests/conftest.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -141,14 +141,14 @@ def logging_obj() -> Logging:
141141

142142
AsyncTempTest = Callable[..., AbstractAsyncContextManager[tuple[AppDaemon, pytest.LogCaptureFixture]]]
143143

144+
144145
@pytest_asyncio.fixture(scope="function")
145146
async def run_app_for_time(ad: AppDaemon, caplog: pytest.LogCaptureFixture) -> AsyncTempTest:
146147
@asynccontextmanager
147148
async def _run(app_name: str, run_time: float | None = None, **kwargs):
148149
with caplog.at_level(logging.DEBUG, logger=f"AppDaemon.{app_name}"):
149150
async with ad.app_management.app_run_context(app_name, **kwargs):
150151
logger.info(f"===== Running app {app_name} for {format_timedelta(run_time)}")
151-
logger.info(f"Temporarily adding args to app: {kwargs}")
152152
if run_time is not None:
153153
await asyncio.sleep(run_time)
154154
logger.info("=== Done, yielding caplog for inspection")

tests/functional/test_event.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,10 +9,12 @@
99

1010
logger = logging.getLogger("AppDaemon._test")
1111

12+
1213
@pytest.mark.ci
1314
@pytest.mark.functional
1415
class TestEventCallback:
1516
"""Class to group the various tests for event callbacks."""
17+
1618
app_name: str = "test_event_app"
1719

1820
@pytest.mark.asyncio(loop_scope="session")

tests/functional/test_run_every.py

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -25,17 +25,19 @@ async def test_run_every(
2525
run_app_for_time: AsyncTempTest,
2626
interval: str | int | float | timedelta,
2727
start: str,
28-
n: int = 5,
28+
n: int = 2,
2929
) -> None:
3030
interval = parse_timedelta(interval)
3131
run_time = (interval * n) + timedelta(seconds=0.01)
32+
register_delay = 0.1
33+
run_time += timedelta(seconds=register_delay) # Accounts for the delay in registering the callback
3234
if (parts := re.split(r"\s+[\+]\s+", start)) and len(parts) == 2:
3335
_, offset = parts
3436
run_time += parse_timedelta(offset)
3537

3638
app_name = "scheduler_test_app"
3739
test_id = str(uuid.uuid4())
38-
app_args = dict(start=start, interval=interval, msg=test_id)
40+
app_args = dict(start=start, interval=interval, msg=test_id, register_delay=register_delay)
3941
async with run_app_for_time(app_name, run_time=run_time.total_seconds(), **app_args) as (ad, caplog):
4042
check_interval_partial = partial(check_interval, caplog, f"kwargs: {{'msg': '{test_id}',")
4143

tests/functional/test_run_in.py

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -14,12 +14,15 @@
1414
async def test_run_in_delay(run_app_for_time, delay):
1515
run_time = parse_timedelta(delay).total_seconds()
1616
run_time += ERROR_MARGIN * 10
17+
register_delay = 0.1
18+
run_time += register_delay
1719
test_id = str(uuid.uuid4()) # Generate a unique test ID for each run
18-
async with run_app_for_time("test_run_in", run_time=run_time, delay=delay, test_id=test_id) as (ad, caplog):
20+
kwargs = dict(delay=delay, test_id=test_id, register_delay=register_delay)
21+
async with run_app_for_time("test_run_in", run_time=run_time, **kwargs) as (ad, caplog):
1922
assert "TestSchedulerRunIn initialized" in caplog.text
2023
for record in caplog.records:
2124
match record:
22-
case logging.LogRecord(msg="TestSchedulerRunIn initialized", created=created_ts):
25+
case logging.LogRecord(msg=msg, created=created_ts) if msg.startswith("Registering run_in"):
2326
# Nothing really needs to happen here. The created_ts variable is set if the record is matched.
2427
# It's already been asserted that this text is somewhere in the caplog text, so this is guaranteed to
2528
# match one of the records.
@@ -37,3 +40,4 @@ async def test_run_in_delay(run_app_for_time, delay):
3740
else:
3841
# If it reaches here, no matching record was found
3942
assert False, "Run in callback was not executed"
43+
assert False, "Run in callback was not executed"

tests/functional/test_state.py

Lines changed: 9 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -11,15 +11,14 @@
1111
logger = logging.getLogger("AppDaemon._test")
1212

1313

14-
1514
@pytest.mark.ci
1615
@pytest.mark.functional
1716
class TestStateCallback:
1817
"""Class to group the various tests for state callbacks."""
18+
1919
app_name: str = "state_test_app"
2020
timeout: int | float = 0.6
2121

22-
2322
async def _run_callback_test(self, run_app_for_time: AsyncTempTest, app_args: dict, sign: bool) -> None:
2423
"""Helper method to run callback tests with common logic.
2524
@@ -33,15 +32,15 @@ async def _run_callback_test(self, run_app_for_time: AsyncTempTest, app_args: di
3332
wait_coro = asyncio.wait_for(app_obj.execute_event.wait(), timeout=self.timeout)
3433
if sign:
3534
await wait_coro
36-
logger.debug('Callback execute event was set')
35+
logger.debug("Callback execute event was set")
3736
else:
3837
# We expect the timeout because the new state filter doesn't match
3938
with pytest.raises(asyncio.TimeoutError):
4039
await wait_coro
41-
logger.debug('Callback execute event was not set')
40+
logger.debug("Callback execute event was not set")
4241
case _:
4342
raise ValueError("App object not found in app management")
44-
logger.debug(f'Test completed in {perf_counter() - start:.3f} seconds')
43+
logger.debug(f"Test completed in {perf_counter() - start:.3f} seconds")
4544

4645
@pytest.mark.parametrize("sign", [True, False])
4746
@pytest.mark.asyncio(loop_scope="session")
@@ -105,20 +104,19 @@ async def test_old_state_callback(self, run_app_for_time: AsyncTempTest, sign: b
105104
async with run_app_for_time(self.app_name, **app_args) as (ad, caplog):
106105
match ad.app_management.objects.get(self.app_name):
107106
case ManagedObject(object=app_obj):
108-
app_obj.run_in(app_obj.test_change_state, delay=app_obj.delay*2, state="abc")
109-
wait_coro = asyncio.wait_for(app_obj.execute_event.wait(), timeout=self.timeout*2)
107+
app_obj.run_in(app_obj.test_change_state, delay=app_obj.delay * 2, state="abc")
108+
wait_coro = asyncio.wait_for(app_obj.execute_event.wait(), timeout=self.timeout * 2)
110109
if sign:
111110
await wait_coro
112-
logger.debug('Callback execute event was set')
111+
logger.debug("Callback execute event was set")
113112
else:
114113
# We expect the timeout because the new state filter doesn't match
115114
with pytest.raises(asyncio.TimeoutError):
116115
await wait_coro
117-
logger.debug('Callback execute event was not set')
116+
logger.debug("Callback execute event was not set")
118117
case _:
119118
raise ValueError("App object not found in app management")
120119

121-
122120
@pytest.mark.parametrize("sign", [True, False])
123121
@pytest.mark.asyncio(loop_scope="session")
124122
async def test_attribute_callback(self, run_app_for_time: AsyncTempTest, sign: bool) -> None:
@@ -144,8 +142,5 @@ async def test_attribute_callback(self, run_app_for_time: AsyncTempTest, sign: b
144142
"""
145143
new_state = str(uuid.uuid4())
146144
listen_state = new_state if sign else str(uuid.uuid4())
147-
app_args = {
148-
"listen_kwargs": {"attribute": "test_attr", "new": listen_state},
149-
"state_kwargs": {"state": "changed", "test_attr": new_state}
150-
}
145+
app_args = {"listen_kwargs": {"attribute": "test_attr", "new": listen_state}, "state_kwargs": {"state": "changed", "test_attr": new_state}}
151146
await self._run_callback_test(run_app_for_time, app_args, sign)

tests/functional/utils.py

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,6 @@
1010
AsyncTempTest = Callable[..., AbstractAsyncContextManager[tuple[AppDaemon, pytest.LogCaptureFixture]]]
1111

1212

13-
1413
def check_interval(
1514
caplog: pytest.LogCaptureFixture,
1615
search_str: str,
@@ -20,4 +19,4 @@ def check_interval(
2019
) -> None:
2120
logs = list(filter_caplog(caplog, search_str))
2221
assert_timedelta(logs, interval, buffer)
23-
assert len(logs) == n, f"Expected {n} log entries with '{search_str}', found {len(logs)}"
22+
assert len(logs) >= n, f"Expected {n} log entries with '{search_str}', found {len(logs)}"

tests/unit/datetime/test_now_is_between.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
pytest.mark.unit,
1111
]
1212

13+
1314
def test_between_overnight(location: Location, early_now: datetime, default_now: datetime, late_now: datetime) -> None:
1415
sun_check = partial(utils.now_is_between, start_time="sunset", end_time="sunrise", location=location)
1516
assert sun_check(now=early_now), "The early time is not between sunset and sunrise, but should be"

0 commit comments

Comments
 (0)