From 0701b248891e7edb03033247a8a120fcbeae2838 Mon Sep 17 00:00:00 2001 From: Carter Tinney Date: Thu, 3 Sep 2026 08:57:53 -0700 Subject: [PATCH 1/2] e2e: add DPS leak checks Run strict SDK and Paho leak tracking after every DPS registration test. Share tracker construction with the IoT Hub suite while preserving its existing false-positive filter. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- dev_utils/dev_utils/sdk_leak_tracker.py | 15 ++++++++++++++ tests/e2e/iothub_e2e/conftest.py | 14 +++---------- tests/e2e/provisioning_e2e/conftest.py | 27 +++++++++++++++++++++++++ 3 files changed, 45 insertions(+), 11 deletions(-) create mode 100644 dev_utils/dev_utils/sdk_leak_tracker.py create mode 100644 tests/e2e/provisioning_e2e/conftest.py diff --git a/dev_utils/dev_utils/sdk_leak_tracker.py b/dev_utils/dev_utils/sdk_leak_tracker.py new file mode 100644 index 000000000..55d3f9e30 --- /dev/null +++ b/dev_utils/dev_utils/sdk_leak_tracker.py @@ -0,0 +1,15 @@ +# Copyright (c) Microsoft. All rights reserved. +# Licensed under the MIT license. See LICENSE file in the project root for +# full license information. + +from .leak_tracker import LeakTracker + +TRACKED_MODULES = ("azure.iot.device", "paho") + + +def create_tracker(filter_callback=None): + tracker = LeakTracker() + for module_name in TRACKED_MODULES: + tracker.track_module(module_name) + tracker.filter_callback = filter_callback + return tracker diff --git a/tests/e2e/iothub_e2e/conftest.py b/tests/e2e/iothub_e2e/conftest.py index c52ed10e1..c888de164 100644 --- a/tests/e2e/iothub_e2e/conftest.py +++ b/tests/e2e/iothub_e2e/conftest.py @@ -8,8 +8,7 @@ import test_config import device_identity_helper import const -import dev_utils.leak_tracker as leak_tracker_module -from dev_utils import test_env, get_random_message, get_random_dict, iptables +from dev_utils import test_env, get_random_message, get_random_dict, iptables, sdk_leak_tracker from utils import is_windows from drop_fixtures import dropper # noqa: F401 @@ -122,11 +121,7 @@ def leak_tracker_filter(leaks): @pytest.fixture(scope="function") def leak_tracker(): """Opt the requesting test into a leak check before fixture teardown.""" - tracker = leak_tracker_module.LeakTracker() - tracker.track_module("azure.iot.device") - tracker.track_module("paho") - tracker.filter_callback = leak_tracker_filter - return tracker + return sdk_leak_tracker.create_tracker(filter_callback=leak_tracker_filter) @pytest.fixture(scope="session") @@ -232,10 +227,7 @@ def pytest_runtest_setup(item): # # Of these 2, the `leak_tracker` fixture is more useful. # - item.outer_leak_tracker = leak_tracker_module.LeakTracker() - item.outer_leak_tracker.track_module("azure.iot.device") - item.outer_leak_tracker.track_module("paho") - item.outer_leak_tracker.filter_callback = leak_tracker_filter + item.outer_leak_tracker = sdk_leak_tracker.create_tracker(filter_callback=leak_tracker_filter) item.outer_leak_tracker.set_initial_object_list() diff --git a/tests/e2e/provisioning_e2e/conftest.py b/tests/e2e/provisioning_e2e/conftest.py new file mode 100644 index 000000000..fcdf26d1d --- /dev/null +++ b/tests/e2e/provisioning_e2e/conftest.py @@ -0,0 +1,27 @@ +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for +# license information. + +import pytest + +from dev_utils import sdk_leak_tracker + + +@pytest.hookimpl(wrapper=True) +def pytest_runtest_call(): + """ + Check that DPS client objects are released after each registration test. + + Successful registration shuts down the provisioning pipeline before returning. The leak check + runs after the test frame is released so test-local clients and results do not cause false + positives. + """ + # DPS clients are created after this baseline, so allowing a "replacement" object would hide + # a real leak rather than suppress a false positive. + tracker = sdk_leak_tracker.create_tracker() + tracker.set_initial_object_list() + + result = yield + + tracker.check_for_leaks() + return result From 5f0b8db9e270ae55f5942728c6e2555fa96ef465 Mon Sep 17 00:00:00 2001 From: Carter Tinney Date: Thu, 3 Sep 2026 09:00:41 -0700 Subject: [PATCH 2/2] e2e: keep DPS leak setup local Remove the shared tracker factory and leave the existing IoT Hub setup untouched. The DPS conftest now configures its LeakTracker directly. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- dev_utils/dev_utils/sdk_leak_tracker.py | 15 --------------- tests/e2e/iothub_e2e/conftest.py | 14 +++++++++++--- tests/e2e/provisioning_e2e/conftest.py | 6 ++++-- 3 files changed, 15 insertions(+), 20 deletions(-) delete mode 100644 dev_utils/dev_utils/sdk_leak_tracker.py diff --git a/dev_utils/dev_utils/sdk_leak_tracker.py b/dev_utils/dev_utils/sdk_leak_tracker.py deleted file mode 100644 index 55d3f9e30..000000000 --- a/dev_utils/dev_utils/sdk_leak_tracker.py +++ /dev/null @@ -1,15 +0,0 @@ -# Copyright (c) Microsoft. All rights reserved. -# Licensed under the MIT license. See LICENSE file in the project root for -# full license information. - -from .leak_tracker import LeakTracker - -TRACKED_MODULES = ("azure.iot.device", "paho") - - -def create_tracker(filter_callback=None): - tracker = LeakTracker() - for module_name in TRACKED_MODULES: - tracker.track_module(module_name) - tracker.filter_callback = filter_callback - return tracker diff --git a/tests/e2e/iothub_e2e/conftest.py b/tests/e2e/iothub_e2e/conftest.py index c888de164..c52ed10e1 100644 --- a/tests/e2e/iothub_e2e/conftest.py +++ b/tests/e2e/iothub_e2e/conftest.py @@ -8,7 +8,8 @@ import test_config import device_identity_helper import const -from dev_utils import test_env, get_random_message, get_random_dict, iptables, sdk_leak_tracker +import dev_utils.leak_tracker as leak_tracker_module +from dev_utils import test_env, get_random_message, get_random_dict, iptables from utils import is_windows from drop_fixtures import dropper # noqa: F401 @@ -121,7 +122,11 @@ def leak_tracker_filter(leaks): @pytest.fixture(scope="function") def leak_tracker(): """Opt the requesting test into a leak check before fixture teardown.""" - return sdk_leak_tracker.create_tracker(filter_callback=leak_tracker_filter) + tracker = leak_tracker_module.LeakTracker() + tracker.track_module("azure.iot.device") + tracker.track_module("paho") + tracker.filter_callback = leak_tracker_filter + return tracker @pytest.fixture(scope="session") @@ -227,7 +232,10 @@ def pytest_runtest_setup(item): # # Of these 2, the `leak_tracker` fixture is more useful. # - item.outer_leak_tracker = sdk_leak_tracker.create_tracker(filter_callback=leak_tracker_filter) + item.outer_leak_tracker = leak_tracker_module.LeakTracker() + item.outer_leak_tracker.track_module("azure.iot.device") + item.outer_leak_tracker.track_module("paho") + item.outer_leak_tracker.filter_callback = leak_tracker_filter item.outer_leak_tracker.set_initial_object_list() diff --git a/tests/e2e/provisioning_e2e/conftest.py b/tests/e2e/provisioning_e2e/conftest.py index fcdf26d1d..e9fb836d2 100644 --- a/tests/e2e/provisioning_e2e/conftest.py +++ b/tests/e2e/provisioning_e2e/conftest.py @@ -4,7 +4,7 @@ import pytest -from dev_utils import sdk_leak_tracker +import dev_utils.leak_tracker as leak_tracker_module @pytest.hookimpl(wrapper=True) @@ -18,7 +18,9 @@ def pytest_runtest_call(): """ # DPS clients are created after this baseline, so allowing a "replacement" object would hide # a real leak rather than suppress a false positive. - tracker = sdk_leak_tracker.create_tracker() + tracker = leak_tracker_module.LeakTracker() + tracker.track_module("azure.iot.device") + tracker.track_module("paho") tracker.set_initial_object_list() result = yield