Skip to content

Commit 91d7328

Browse files
Add tests for ConfigManagingActor
1 parent febfe4b commit 91d7328

File tree

1 file changed

+89
-0
lines changed

1 file changed

+89
-0
lines changed

tests/config/test_config_manager.py

Lines changed: 89 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,18 +2,21 @@
22
# Copyright © 2022 Frequenz Energy-as-a-Service GmbH
33

44
"""Test for ConfigManager."""
5+
import asyncio
56
import os
67
import pathlib
78
from collections import defaultdict
89
from collections.abc import Mapping, MutableMapping
910
from dataclasses import dataclass
1011
from typing import Any
12+
from pytest_mock import MockerFixture
1113

1214
import pytest
1315
from frequenz.channels import Broadcast
1416

1517
from frequenz.sdk.config import ConfigManagingActor
1618
from frequenz.sdk.config._config_managing import _recursive_update
19+
from frequenz.channels.file_watcher import Event, EventType
1720

1821

1922
class Item:
@@ -265,6 +268,92 @@ async def test_update_multiple_files(self, config_file: pathlib.Path) -> None:
265268
"dict_str_int": {"a": 1, "b": 2, "c": 4},
266269
}
267270

271+
async def test_actor_works_if_not_all_config_files_exist(
272+
self, config_file: pathlib.Path
273+
) -> None:
274+
"""Test ConfigManagingActor works if not all config files exist."""
275+
config_channel: Broadcast[Mapping[str, Any]] = Broadcast(
276+
name="Config Channel", resend_latest=True
277+
)
278+
config_receiver = config_channel.new_receiver()
279+
config_file2 = config_file.parent / "config2.toml"
280+
281+
async with ConfigManagingActor(
282+
[config_file, config_file2],
283+
config_channel.new_sender(),
284+
force_polling=False,
285+
):
286+
config = await config_receiver.receive()
287+
assert config is not None
288+
assert config.get("var2") is None
289+
290+
number = 5
291+
config_file.write_text(create_content(number=number))
292+
293+
config = await config_receiver.receive()
294+
assert config is not None
295+
assert config.get("var2") == str(number)
296+
297+
# Create second config file that overrides the value from the first one
298+
number = 42
299+
config_file2.write_text(create_content(number=number))
300+
301+
config = await config_receiver.receive()
302+
assert config is not None
303+
assert config.get("var2") == str(number)
304+
305+
async def test_actor_does_not_crash_if_file_is_deleted(
306+
self, config_file: pathlib.Path, mocker: MockerFixture
307+
) -> None:
308+
"""Test ConfigManagingActor does not crash if a file is deleted."""
309+
config_channel: Broadcast[Mapping[str, Any]] = Broadcast(
310+
name="Config Channel", resend_latest=True
311+
)
312+
config_receiver = config_channel.new_receiver()
313+
314+
number = 5
315+
config_file2 = config_file.parent / "config2.toml"
316+
config_file2.write_text(create_content(number=number))
317+
318+
# Not config file but existing in the same directory
319+
any_file = config_file.parent / "any_file.txt"
320+
any_file.write_text("content")
321+
322+
async with ConfigManagingActor(
323+
[config_file, config_file2],
324+
config_channel.new_sender(),
325+
force_polling=False,
326+
) as actor:
327+
send_config_spy = mocker.spy(actor, "send_config")
328+
329+
config = await config_receiver.receive()
330+
assert config is not None
331+
assert config.get("var2") == str(number)
332+
send_config_spy.assert_called_once()
333+
send_config_spy.reset_mock()
334+
335+
# Remove file and send DELETE events
336+
any_file.unlink()
337+
config_file2.unlink()
338+
number = 101
339+
config_file.write_text(create_content(number=number))
340+
mocker.patch.object(
341+
actor._file_watcher,
342+
"__anext__",
343+
side_effect=[
344+
Event(EventType.DELETE, any_file),
345+
Event(EventType.DELETE, config_file2),
346+
Event(EventType.MODIFY, config_file),
347+
],
348+
)
349+
350+
config = await config_receiver.receive()
351+
assert config is not None
352+
assert config.get("var2") == str(number)
353+
# Config should be updated only once on MODIFY event
354+
# DELETE events are ignored
355+
send_config_spy.assert_called_once()
356+
268357

269358
@dataclass(frozen=True, kw_only=True)
270359
class RecursiveUpdateTestCase:

0 commit comments

Comments
 (0)