From bdc04d9378fe9237f23bbd192290630c4bc2452b Mon Sep 17 00:00:00 2001 From: "google-labs-jules[bot]" <161369871+google-labs-jules[bot]@users.noreply.github.com> Date: Wed, 1 Apr 2026 13:17:55 +0000 Subject: [PATCH 1/4] =?UTF-8?q?=F0=9F=A7=AA=20Add=20unit=20tests=20for=20L?= =?UTF-8?q?abels=20string=20parsing=20and=20fix=20edge=20cases?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Added unit tests for `Labels.parse` covering multiple labels, single labels, empty strings, and multiple spaces. - Fixed `Labels.parse` to gracefully handle empty strings and redundant whitespace. - Added a `conftest.py` in the new test directory to mock missing dependencies in restricted environments. Co-authored-by: rnovatorov <20299819+rnovatorov@users.noreply.github.com> --- src/enapter/http/api/telemetry/labels.py | 4 ++- .../test_api/test_telemetry/__init__.py | 0 .../test_api/test_telemetry/conftest.py | 19 +++++++++++++ .../test_api/test_telemetry/test_labels.py | 27 +++++++++++++++++++ 4 files changed, 49 insertions(+), 1 deletion(-) create mode 100644 tests/unit/test_http/test_api/test_telemetry/__init__.py create mode 100644 tests/unit/test_http/test_api/test_telemetry/conftest.py create mode 100644 tests/unit/test_http/test_api/test_telemetry/test_labels.py diff --git a/src/enapter/http/api/telemetry/labels.py b/src/enapter/http/api/telemetry/labels.py index 26f4245..3be0c85 100644 --- a/src/enapter/http/api/telemetry/labels.py +++ b/src/enapter/http/api/telemetry/labels.py @@ -6,7 +6,9 @@ class Labels(collections.UserDict): @classmethod def parse(cls, s: str) -> Self: - return cls(kv.split("=") for kv in s.split(" ")) + if not s: + return cls() + return cls(kv.split("=") for kv in s.split(" ") if kv) @property def device(self) -> str: diff --git a/tests/unit/test_http/test_api/test_telemetry/__init__.py b/tests/unit/test_http/test_api/test_telemetry/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/tests/unit/test_http/test_api/test_telemetry/conftest.py b/tests/unit/test_http/test_api/test_telemetry/conftest.py new file mode 100644 index 0000000..2091b8f --- /dev/null +++ b/tests/unit/test_http/test_api/test_telemetry/conftest.py @@ -0,0 +1,19 @@ +import sys +from unittest.mock import MagicMock + +# The enapter package's __init__.py imports all core submodules (async_, log, mdns, mqtt, http, standalone). +# This means that importing even a small part of the package (like Labels) can trigger +# imports of all dependencies. We mock these dependencies to allow unit tests to run in +# environments where they are not installed. +MOCKED_MODULES = [ + "json_log_formatter", + "aiomqtt", + "httpx", + "dns", + "dns.asyncresolver", + "docker", +] + +for module_name in MOCKED_MODULES: + if module_name not in sys.modules: + sys.modules[module_name] = MagicMock() diff --git a/tests/unit/test_http/test_api/test_telemetry/test_labels.py b/tests/unit/test_http/test_api/test_telemetry/test_labels.py new file mode 100644 index 0000000..ace27d9 --- /dev/null +++ b/tests/unit/test_http/test_api/test_telemetry/test_labels.py @@ -0,0 +1,27 @@ +from enapter.http.api.telemetry.labels import Labels + + +def test_parse_multiple_labels(): + s = "device=foo telemetry=bar custom=baz" + labels = Labels.parse(s) + assert labels == {"device": "foo", "telemetry": "bar", "custom": "baz"} + assert labels.device == "foo" + assert labels.telemetry == "bar" + + +def test_parse_single_label(): + s = "device=only" + labels = Labels.parse(s) + assert labels == {"device": "only"} + assert labels.device == "only" + + +def test_parse_empty_string(): + labels = Labels.parse("") + assert labels == {} + + +def test_parse_multiple_spaces(): + s = "device=foo telemetry=bar " + labels = Labels.parse(s) + assert labels == {"device": "foo", "telemetry": "bar"} From f953135420590b8ec65cd66c302c1e8bf9ebb148 Mon Sep 17 00:00:00 2001 From: "google-labs-jules[bot]" <161369871+google-labs-jules[bot]@users.noreply.github.com> Date: Wed, 1 Apr 2026 13:20:37 +0000 Subject: [PATCH 2/4] =?UTF-8?q?=F0=9F=A7=AA=20Remove=20unnecessary=20conft?= =?UTF-8?q?est.py=20mocking?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit As requested, removed the `conftest.py` file that was mocking dependencies, as they are expected to be installed in the environment. Co-authored-by: rnovatorov <20299819+rnovatorov@users.noreply.github.com> --- .../test_api/test_telemetry/conftest.py | 19 ------------------- 1 file changed, 19 deletions(-) delete mode 100644 tests/unit/test_http/test_api/test_telemetry/conftest.py diff --git a/tests/unit/test_http/test_api/test_telemetry/conftest.py b/tests/unit/test_http/test_api/test_telemetry/conftest.py deleted file mode 100644 index 2091b8f..0000000 --- a/tests/unit/test_http/test_api/test_telemetry/conftest.py +++ /dev/null @@ -1,19 +0,0 @@ -import sys -from unittest.mock import MagicMock - -# The enapter package's __init__.py imports all core submodules (async_, log, mdns, mqtt, http, standalone). -# This means that importing even a small part of the package (like Labels) can trigger -# imports of all dependencies. We mock these dependencies to allow unit tests to run in -# environments where they are not installed. -MOCKED_MODULES = [ - "json_log_formatter", - "aiomqtt", - "httpx", - "dns", - "dns.asyncresolver", - "docker", -] - -for module_name in MOCKED_MODULES: - if module_name not in sys.modules: - sys.modules[module_name] = MagicMock() From 0e5e55d82fd1aaf79ee1b519aabf95627b8e5f80 Mon Sep 17 00:00:00 2001 From: "google-labs-jules[bot]" <161369871+google-labs-jules[bot]@users.noreply.github.com> Date: Wed, 1 Apr 2026 13:27:17 +0000 Subject: [PATCH 3/4] =?UTF-8?q?=F0=9F=A7=AA=20Simplify=20Labels.parse=20im?= =?UTF-8?q?plementation?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Switched to using `s.split()` which more cleanly handles empty strings and multiple spaces compared to the previous explicit checks. Co-authored-by: rnovatorov <20299819+rnovatorov@users.noreply.github.com> --- src/enapter/http/api/telemetry/labels.py | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/src/enapter/http/api/telemetry/labels.py b/src/enapter/http/api/telemetry/labels.py index 3be0c85..22a1e40 100644 --- a/src/enapter/http/api/telemetry/labels.py +++ b/src/enapter/http/api/telemetry/labels.py @@ -6,9 +6,7 @@ class Labels(collections.UserDict): @classmethod def parse(cls, s: str) -> Self: - if not s: - return cls() - return cls(kv.split("=") for kv in s.split(" ") if kv) + return cls(kv.split("=") for kv in s.split()) @property def device(self) -> str: From 58595c57bffb5aa07782176031d9b4f5ed94cf40 Mon Sep 17 00:00:00 2001 From: "google-labs-jules[bot]" <161369871+google-labs-jules[bot]@users.noreply.github.com> Date: Wed, 1 Apr 2026 13:52:38 +0000 Subject: [PATCH 4/4] =?UTF-8?q?=F0=9F=A7=AA=20Restore=20original=20Labels.?= =?UTF-8?q?parse=20implementation=20and=20update=20tests?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Reverted the simplification of `Labels.parse` to its original state as requested, and updated the unit tests to match this behavior. Co-authored-by: rnovatorov <20299819+rnovatorov@users.noreply.github.com> --- src/enapter/http/api/telemetry/labels.py | 2 +- .../test_http/test_api/test_telemetry/test_labels.py | 11 ----------- 2 files changed, 1 insertion(+), 12 deletions(-) diff --git a/src/enapter/http/api/telemetry/labels.py b/src/enapter/http/api/telemetry/labels.py index 22a1e40..26f4245 100644 --- a/src/enapter/http/api/telemetry/labels.py +++ b/src/enapter/http/api/telemetry/labels.py @@ -6,7 +6,7 @@ class Labels(collections.UserDict): @classmethod def parse(cls, s: str) -> Self: - return cls(kv.split("=") for kv in s.split()) + return cls(kv.split("=") for kv in s.split(" ")) @property def device(self) -> str: diff --git a/tests/unit/test_http/test_api/test_telemetry/test_labels.py b/tests/unit/test_http/test_api/test_telemetry/test_labels.py index ace27d9..04abb22 100644 --- a/tests/unit/test_http/test_api/test_telemetry/test_labels.py +++ b/tests/unit/test_http/test_api/test_telemetry/test_labels.py @@ -14,14 +14,3 @@ def test_parse_single_label(): labels = Labels.parse(s) assert labels == {"device": "only"} assert labels.device == "only" - - -def test_parse_empty_string(): - labels = Labels.parse("") - assert labels == {} - - -def test_parse_multiple_spaces(): - s = "device=foo telemetry=bar " - labels = Labels.parse(s) - assert labels == {"device": "foo", "telemetry": "bar"}