Skip to content

Commit bb278dc

Browse files
committed
test: stop Flagsmith background threads via an autouse fixture
Flagsmith(...) can start polling, streaming and event-processor background threads. Track every instance created during a test and stop its threads on teardown so they don't leak across the suite — previously a leaked polling thread could call a class-level-patched update_environment in a later test. Replaces the scattered per-test try/finally cleanup.
1 parent 4559226 commit bb278dc

2 files changed

Lines changed: 33 additions & 15 deletions

File tree

tests/conftest.py

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,32 @@
2323
DATA_DIR = os.path.join(os.path.dirname(__file__), "data")
2424

2525

26+
@pytest.fixture(autouse=True)
27+
def stop_flagsmith_background_threads(
28+
monkeypatch: pytest.MonkeyPatch,
29+
) -> Generator[None, None, None]:
30+
# Flagsmith starts polling, streaming and event-processor background
31+
# threads. Track every instance created during a test and stop its threads
32+
# on teardown so they don't leak across the suite (mirroring __del__, but
33+
# deterministically rather than at GC).
34+
instances: typing.List[Flagsmith] = []
35+
original_init = Flagsmith.__init__
36+
37+
def tracking_init(self: Flagsmith, *args: typing.Any, **kwargs: typing.Any) -> None:
38+
instances.append(self)
39+
original_init(self, *args, **kwargs)
40+
41+
monkeypatch.setattr(Flagsmith, "__init__", tracking_init)
42+
yield
43+
for flagsmith in instances:
44+
if getattr(flagsmith, "environment_data_polling_manager_thread", None):
45+
flagsmith.environment_data_polling_manager_thread.stop()
46+
if getattr(flagsmith, "event_stream_thread", None):
47+
flagsmith.event_stream_thread.stop()
48+
if flagsmith._event_processor:
49+
flagsmith._event_processor.stop()
50+
51+
2652
@pytest.fixture()
2753
def analytics_processor() -> AnalyticsProcessor:
2854
return AnalyticsProcessor(

tests/test_flagsmith.py

Lines changed: 7 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -959,12 +959,8 @@ def test_track_event_raises_without_config(api_key: str) -> None:
959959

960960
def test_track_event_rejects_reserved_prefix(api_key: str) -> None:
961961
flagsmith = Flagsmith(environment_key=api_key, enable_events=True)
962-
try:
963-
with pytest.raises(ValueError, match='reserved "\\$" prefix'):
964-
flagsmith.track_event("$made_up")
965-
finally:
966-
if flagsmith._event_processor:
967-
flagsmith._event_processor.stop()
962+
with pytest.raises(ValueError, match='reserved "\\$" prefix'):
963+
flagsmith.track_event("$made_up")
968964

969965

970966
def test_event_processor_config_without_enable_events_raises(api_key: str) -> None:
@@ -978,15 +974,11 @@ def test_event_processor_config_without_enable_events_raises(api_key: str) -> No
978974

979975
def test_enable_events_without_config_uses_default(api_key: str) -> None:
980976
flagsmith = Flagsmith(environment_key=api_key, enable_events=True)
981-
try:
982-
assert flagsmith._event_processor is not None
983-
assert (
984-
flagsmith._event_processor._batch_endpoint
985-
== "https://events.api.flagsmith.com/v1/events"
986-
)
987-
finally:
988-
if flagsmith._event_processor:
989-
flagsmith._event_processor.stop()
977+
assert flagsmith._event_processor is not None
978+
assert (
979+
flagsmith._event_processor._batch_endpoint
980+
== "https://events.api.flagsmith.com/v1/events"
981+
)
990982

991983

992984
def test_track_event_delegates_to_event_processor(

0 commit comments

Comments
 (0)