From 1ee69cb39b8be8e97b1498218b4ff3a4b9b1c3ee Mon Sep 17 00:00:00 2001 From: zermelo-wisen Date: Sat, 8 Jun 2024 00:15:32 +0300 Subject: [PATCH] fix: request recording in unittest setUp method --- _appmap/test/data/django/test/test_unittest_setup.py | 11 +++++++++++ _appmap/test/test_django.py | 10 ++++++---- _appmap/unittest.py | 12 ++++++++++++ 3 files changed, 29 insertions(+), 4 deletions(-) create mode 100644 _appmap/test/data/django/test/test_unittest_setup.py diff --git a/_appmap/test/data/django/test/test_unittest_setup.py b/_appmap/test/data/django/test/test_unittest_setup.py new file mode 100644 index 00000000..e535d528 --- /dev/null +++ b/_appmap/test/data/django/test/test_unittest_setup.py @@ -0,0 +1,11 @@ + +from unittest import TestCase + +from django.test import Client + +class DisabledRequestsRecordingTest(TestCase): + def setUp(self) -> None: + Client().get("/") + + def test_request_in_setup(self): + pass diff --git a/_appmap/test/test_django.py b/_appmap/test/test_django.py index 1e9ee1dc..730c7f36 100644 --- a/_appmap/test/test_django.py +++ b/_appmap/test/test_django.py @@ -201,11 +201,13 @@ def test_enabled(self, pytester): # To really check middleware reset, the tests must run in order, # so disable randomly. result = pytester.runpytest("-svv", "-p", "no:randomly") - result.assert_outcomes(passed=4, failed=0, errors=0) + result.assert_outcomes(passed=5, failed=0, errors=0) # Look for the http_server_request event in test_app's appmap. If # middleware reset is broken, it won't be there. appmap_file = pytester.path / "tmp" / "appmap" / "pytest" / "test_request.appmap.json" - assert not os.path.exists(pytester.path / "tmp" / "appmap" / "requests") + assert not os.path.exists( + pytester.path / "tmp" / "appmap" / "requests" + ), "django tests generated request recordings" events = json.loads(appmap_file.read_text())["events"] assert "http_server_request" in events[0] @@ -213,7 +215,7 @@ def test_enabled(self, pytester): def test_disabled(self, pytester, monkeypatch): monkeypatch.setenv("_APPMAP", "false") result = pytester.runpytest("-svv", "-p", "no:randomly", "-k", "test_request") - result.assert_outcomes(passed=1, failed=0, errors=0) + result.assert_outcomes(passed=2, failed=0, errors=0) assert not (pytester.path / "tmp").exists() def test_disabled_for_process(self, pytester, monkeypatch): @@ -223,7 +225,7 @@ def test_disabled_for_process(self, pytester, monkeypatch): # There are two tests for remote recording. They should both fail, # because process recording should disable remote recording. - result.assert_outcomes(passed=2, failed=2, errors=0) + result.assert_outcomes(passed=3, failed=2, errors=0) assert (pytester.path / "tmp" / "appmap" / "process").exists() assert not (pytester.path / "tmp" / "appmap" / "requests").exists() diff --git a/_appmap/unittest.py b/_appmap/unittest.py index 7641a86b..d2a2bd7f 100644 --- a/_appmap/unittest.py +++ b/_appmap/unittest.py @@ -3,6 +3,7 @@ from contextlib import contextmanager from _appmap import noappmap, testing_framework, wrapt +from _appmap.env import Env from _appmap.utils import get_function_location _session = testing_framework.session("unittest", "tests") @@ -52,6 +53,17 @@ def _args(test_case, *_, isTest=False, **__): yield else: + # We need to disable request recording in TestCase._callSetUp too + # in order to prevent creation of a request recording besides test + # recording when requests are made inside setUp method. + # This edge case can be observed in this test in django project: + # $ APPMAP=TRUE ./runtests.py auth_tests.test_views.ChangelistTests.test_user_change_email + #  (ChangelistTests.setUp makes a request) + @wrapt.patch_function_wrapper("unittest.case", "TestCase._callSetUp") + def callSetUp(wrapped, test_case, args, kwargs): # pylint: disable=unused-argument + with Env.current.disabled("requests"): + wrapped(*args, **kwargs) + # As of 3.8, unittest.case.TestCase now calls the test's method indirectly, through # TestCase._callTestMethod. Hook that to manage a recording session. @wrapt.patch_function_wrapper("unittest.case", "TestCase._callTestMethod")