-
Notifications
You must be signed in to change notification settings - Fork 31
fix(processors): add missing getint to ConfigAdapter (#145 regression) #148
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
Merged
Changes from all commits
Commits
Show all changes
5 commits
Select commit
Hold shift + click to select a range
fd01902
fix(processors): add missing getint to ConfigAdapter
anderslindho db79a89
test(processors): add unit tests for ConfigAdapter and CFConfig.loads
anderslindho e05b241
test(server): smoke-test container startup against real image
anderslindho 6f79211
refactor(tests): split test_config into test_processors and test_cfstore
anderslindho 04d2e64
chore(ci): add sonar-project.properties to fix Python version warning
anderslindho File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1 @@ | ||
| sonar.python.version=3.9 |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,52 @@ | ||
| from configparser import ConfigParser | ||
|
|
||
| from recceiver.cfstore import CFConfig | ||
| from recceiver.processors import ConfigAdapter | ||
|
|
||
|
|
||
| def make_adapter(section: str = "cf", values: dict = None, env: dict = None) -> ConfigAdapter: | ||
| parser = ConfigParser() | ||
| parser.add_section(section) | ||
| for key, value in (values or {}).items(): | ||
| parser.set(section, key, str(value)) | ||
| adapter = ConfigAdapter(parser, section) | ||
| if env: | ||
| adapter.env_vars = env | ||
| return adapter | ||
|
|
||
|
|
||
| class TestCFConfigLoads: | ||
| def test_loads_defaults_without_error(self): | ||
| adapter = make_adapter() | ||
| config = CFConfig.loads(adapter) | ||
| assert isinstance(config, CFConfig) | ||
|
|
||
| def test_default_push_max_retries(self): | ||
| adapter = make_adapter() | ||
| config = CFConfig.loads(adapter) | ||
| assert config.push_max_retries == 10 | ||
|
|
||
| def test_push_max_retries_from_config(self): | ||
| adapter = make_adapter(values={"pushmaxretries": "3"}) | ||
| config = CFConfig.loads(adapter) | ||
| assert config.push_max_retries == 3 | ||
|
|
||
| def test_push_max_retries_from_env(self): | ||
| adapter = make_adapter(env={"pushmaxretries": "7"}) | ||
| config = CFConfig.loads(adapter) | ||
| assert config.push_max_retries == 7 | ||
|
|
||
| def test_default_push_always_retry(self): | ||
| adapter = make_adapter() | ||
| config = CFConfig.loads(adapter) | ||
| assert config.push_always_retry is True | ||
|
|
||
| def test_alias_disabled_by_default(self): | ||
| adapter = make_adapter() | ||
| config = CFConfig.loads(adapter) | ||
| assert config.alias_enabled is False | ||
|
|
||
| def test_alias_enabled_from_config(self): | ||
| adapter = make_adapter(values={"alias": "true"}) | ||
| config = CFConfig.loads(adapter) | ||
| assert config.alias_enabled is True |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,46 @@ | ||
| import time | ||
| from pathlib import Path | ||
|
|
||
| import pytest | ||
|
|
||
| from docker import DockerClient | ||
|
|
||
| SERVER_DIR = Path(__file__).parent.parent | ||
|
|
||
|
|
||
| @pytest.fixture(scope="session") | ||
| def recceiver_image(): | ||
| client = DockerClient() | ||
| image, _ = client.images.build(path=str(SERVER_DIR), tag="recceiver-test:smoke", rm=True) | ||
| yield image.id | ||
| client.images.remove(image.id, force=True) | ||
|
|
||
|
|
||
| class TestContainerSmoke: | ||
| def test_container_starts_and_parses_config(self, recceiver_image): | ||
| """Verify the container reaches the CF connection attempt rather than crashing during config parsing. | ||
|
|
||
| A config parsing error (e.g. AttributeError on a missing ConfigAdapter method) causes the | ||
| container to exit before CF_START is logged. A healthy startup logs CF_START first and only | ||
| then fails to connect to CF. | ||
| """ | ||
| client = DockerClient() | ||
| container = client.containers.run( | ||
| recceiver_image, | ||
| environment={ | ||
| "RECCEIVER_RECCEIVER_PROCS": "cf", | ||
| "RECCEIVER_RECCEIVER_LOGLEVEL": "INFO", | ||
| "RECCEIVER_CF_BASEURL": "https://nonexistent-cf:8080/ChannelFinder", | ||
| "RECCEIVER_CF_CFUSERNAME": "admin", | ||
| "RECCEIVER_CF_CFPASSWORD": "password", | ||
| }, | ||
| detach=True, | ||
| ) | ||
| try: | ||
| time.sleep(10) | ||
| logs = container.logs().decode() | ||
| assert "AttributeError" not in logs, f"Container crashed with AttributeError:\n{logs}" | ||
| assert "CF_START" in logs, f"CF_START not found in logs — service may not have started:\n{logs}" | ||
| finally: | ||
| container.stop(timeout=5) | ||
| container.remove() |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,99 @@ | ||
| import textwrap | ||
| from configparser import ConfigParser | ||
| from pathlib import Path | ||
|
|
||
| from recceiver.cfstore import CFProcessor | ||
| from recceiver.processors import ConfigAdapter, ProcessorController | ||
|
|
||
|
|
||
| def make_adapter(section: str = "cf", values: dict = None, env: dict = None) -> ConfigAdapter: | ||
| parser = ConfigParser() | ||
| parser.add_section(section) | ||
| for key, value in (values or {}).items(): | ||
| parser.set(section, key, str(value)) | ||
| adapter = ConfigAdapter(parser, section) | ||
| if env: | ||
| adapter.env_vars = env | ||
| return adapter | ||
|
|
||
|
|
||
| class TestConfigAdapterGet: | ||
| def test_returns_value(self): | ||
| adapter = make_adapter(values={"baseurl": "https://cf:8080"}) | ||
| assert adapter.get("baseurl") == "https://cf:8080" | ||
|
|
||
| def test_returns_default_when_missing(self): | ||
| adapter = make_adapter() | ||
| assert adapter.get("baseurl", "fallback") == "fallback" | ||
|
|
||
| def test_returns_none_when_missing_and_no_default(self): | ||
| adapter = make_adapter() | ||
| assert adapter.get("baseurl") is None | ||
|
|
||
| def test_env_var_overrides_config(self): | ||
| adapter = make_adapter(values={"baseurl": "https://original"}, env={"baseurl": "https://override"}) | ||
| assert adapter.get("baseurl") == "https://override" | ||
|
|
||
| def test_env_var_provides_value_not_in_config(self): | ||
| adapter = make_adapter(env={"baseurl": "https://from-env"}) | ||
| assert adapter.get("baseurl") == "https://from-env" | ||
|
|
||
|
|
||
| class TestConfigAdapterGetBoolean: | ||
| def test_returns_true(self): | ||
| adapter = make_adapter(values={"alias": "true"}) | ||
| assert adapter.getboolean("alias") is True | ||
|
|
||
| def test_returns_false(self): | ||
| adapter = make_adapter(values={"alias": "false"}) | ||
| assert adapter.getboolean("alias") is False | ||
|
|
||
| def test_returns_default_when_missing(self): | ||
| adapter = make_adapter() | ||
| assert adapter.getboolean("alias", False) is False | ||
|
|
||
| def test_returns_default_on_invalid_value(self): | ||
| adapter = make_adapter(values={"alias": "notabool"}) | ||
| assert adapter.getboolean("alias", True) is True | ||
|
|
||
|
|
||
| class TestConfigAdapterGetInt: | ||
| def test_returns_int(self): | ||
| adapter = make_adapter(values={"pushmaxretries": "5"}) | ||
| assert adapter.getint("pushmaxretries") == 5 | ||
|
|
||
| def test_returns_default_when_missing(self): | ||
| adapter = make_adapter() | ||
| assert adapter.getint("pushmaxretries", 10) == 10 | ||
|
|
||
| def test_returns_none_when_missing_and_no_default(self): | ||
| adapter = make_adapter() | ||
| assert adapter.getint("pushmaxretries") is None | ||
|
|
||
| def test_returns_default_on_invalid_value(self): | ||
| adapter = make_adapter(values={"pushmaxretries": "notanint"}) | ||
| assert adapter.getint("pushmaxretries", 10) == 10 | ||
|
|
||
| def test_env_var_overrides_config(self): | ||
| adapter = make_adapter(values={"pushmaxretries": "5"}, env={"pushmaxretries": "99"}) | ||
| assert adapter.getint("pushmaxretries", 10) == 99 | ||
|
|
||
|
|
||
| class TestProcessorControllerFromConfig: | ||
| def test_cf_processor_initialized_from_config_file(self, tmp_path: Path): | ||
| config_file = tmp_path / "recceiver.conf" | ||
| config_file.write_text( | ||
| textwrap.dedent( | ||
| """\ | ||
| [recceiver] | ||
| procs = cf | ||
|
|
||
| [cf] | ||
| pushMaxRetries = 5 | ||
| """ | ||
| ) | ||
|
anderslindho marked this conversation as resolved.
|
||
| ) | ||
| ctrl = ProcessorController(cfile=str(config_file)) | ||
| assert len(ctrl.procs) == 1 | ||
| assert isinstance(ctrl.procs[0], CFProcessor) | ||
| assert ctrl.procs[0].cf_config.push_max_retries == 5 | ||
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.