Skip to content

fix(perforce): Isolate P4 trust/ticket files per client to prevent lock contention#109652

Merged
mujacica merged 3 commits intomasterfrom
fix/perforce_p4trust
Mar 3, 2026
Merged

fix(perforce): Isolate P4 trust/ticket files per client to prevent lock contention#109652
mujacica merged 3 commits intomasterfrom
fix/perforce_p4trust

Conversation

@mujacica
Copy link
Contributor

@mujacica mujacica commented Mar 2, 2026

Perforce SSL connections were failing with "Unrecoverable lock error '/home/sentry/.p4trust.lck'" because all tenants shared the same global trust and ticket files (~/.p4trust, ~/.p4tickets, ~/.p4enviro).

Changes:

  • Create a per-PerforceClient temp directory for .p4trust and .p4tickets, isolating each tenant's SSL trust and session ticket state.
  • Use p4.set_env("P4TRUST", ...) instead of the non-existent p4.trust_file property (which raises "No string attribute with name trust_file").
  • Redirect P4ENVIRO to /dev/null at module level to prevent set_env() from writing to the shared ~/.p4enviro file on disk. The per-instance in-memory value (which P4 operations actually use) is still set even when the disk write fails.
  • Bind temp directory lifetime to the PerforceClient instance so trust/ticket state is cached across multiple _connect() calls within the same client.
  • Add tests verifying per-instance isolation, P4ENVIRO redirect behavior, in-memory value survival on disk write failure, and concurrent safety.

…ck contention

Perforce SSL connections were failing with "Unrecoverable lock error
'/home/sentry/.p4trust.lck'" because all tenants shared the same global
trust and ticket files (~/.p4trust, ~/.p4tickets, ~/.p4enviro).

Changes:
- Create a per-PerforceClient temp directory for .p4trust and .p4tickets,
  isolating each tenant's SSL trust and session ticket state.
- Use p4.set_env("P4TRUST", ...) instead of the non-existent p4.trust_file
  property (which raises "No string attribute with name trust_file").
- Redirect P4ENVIRO to /dev/null at module level to prevent set_env() from
  writing to the shared ~/.p4enviro file on disk. The per-instance in-memory
  value (which P4 operations actually use) is still set even when the disk
  write fails.
- Bind temp directory lifetime to the PerforceClient instance so trust/ticket
  state is cached across multiple _connect() calls within the same client.
- Add tests verifying per-instance isolation, P4ENVIRO redirect behavior,
  in-memory value survival on disk write failure, and concurrent safety.
@github-actions github-actions bot added the Scope: Backend Automatically applied to PRs that change backend components label Mar 2, 2026
@github-actions
Copy link
Contributor

github-actions bot commented Mar 2, 2026

Backend Test Failures

Failures on ef283c8 in this run:

tests/sentry/integrations/perforce/test_client.py::PerforceClientTest::test_set_env_p4trust_is_per_p4_instancelog
tests/sentry/integrations/perforce/test_client.py:691: in test_set_env_p4trust_is_per_p4_instance
    p4a.set_env("P4TRUST", "/tmp/customer_a/.p4trust")
E   P4.P4Exception: Can't set registry on UNIX.
tests/sentry/integrations/perforce/test_code_mapping.py::PerforceEndToEndCodeMappingTest::test_full_flow_with_web_viewerlog
.venv/lib/python3.13/site-packages/_pytest/runner.py:340: in from_call
    result: Optional[TResult] = func()
.venv/lib/python3.13/site-packages/_pytest/runner.py:240: in <lambda>
    lambda: runtest_hook(item=item, **kwds), when=when, reraise=reraise
.venv/lib/python3.13/site-packages/pluggy/_hooks.py:513: in __call__
    return self._hookexec(self.name, self._hookimpls.copy(), kwargs, firstresult)
.venv/lib/python3.13/site-packages/pluggy/_manager.py:120: in _hookexec
    return self._inner_hookexec(hook_name, methods, kwargs, firstresult)
.venv/lib/python3.13/site-packages/_pytest/threadexception.py:87: in pytest_runtest_call
    yield from thread_exception_runtest_hook()
.venv/lib/python3.13/site-packages/_pytest/threadexception.py:63: in thread_exception_runtest_hook
    yield
.venv/lib/python3.13/site-packages/_pytest/unraisableexception.py:90: in pytest_runtest_call
    yield from unraisable_exception_runtest_hook()
.venv/lib/python3.13/site-packages/_pytest/unraisableexception.py:80: in unraisable_exception_runtest_hook
    warnings.warn(pytest.PytestUnraisableExceptionWarning(msg))
E   pytest.PytestUnraisableExceptionWarning: Exception ignored in: <finalize object at 0x7f0464dabc40; dead>
E   
E   Traceback (most recent call last):
E     File "/opt/hostedtoolcache/Python/3.13.1/x64/lib/python3.13/weakref.py", line 590, in __call__
E       return info.func(*info.args, **(info.kwargs or {}))
E              ~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
E     File "/opt/hostedtoolcache/Python/3.13.1/x64/lib/python3.13/tempfile.py", line 936, in _cleanup
E       _warnings.warn(warn_message, ResourceWarning)
E       ~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
E   ResourceWarning: Implicitly cleaning up <TemporaryDirectory '/tmp/sentry-p4-4r1amxij'>
tests/sentry/integrations/perforce/test_integration.py::PerforceIntegrationTest::test_format_source_url_swarm_viewerlog
.venv/lib/python3.13/site-packages/_pytest/runner.py:340: in from_call
    result: Optional[TResult] = func()
.venv/lib/python3.13/site-packages/_pytest/runner.py:240: in <lambda>
    lambda: runtest_hook(item=item, **kwds), when=when, reraise=reraise
.venv/lib/python3.13/site-packages/pluggy/_hooks.py:513: in __call__
    return self._hookexec(self.name, self._hookimpls.copy(), kwargs, firstresult)
.venv/lib/python3.13/site-packages/pluggy/_manager.py:120: in _hookexec
    return self._inner_hookexec(hook_name, methods, kwargs, firstresult)
.venv/lib/python3.13/site-packages/_pytest/threadexception.py:87: in pytest_runtest_call
    yield from thread_exception_runtest_hook()
.venv/lib/python3.13/site-packages/_pytest/threadexception.py:63: in thread_exception_runtest_hook
    yield
.venv/lib/python3.13/site-packages/_pytest/unraisableexception.py:90: in pytest_runtest_call
    yield from unraisable_exception_runtest_hook()
.venv/lib/python3.13/site-packages/_pytest/unraisableexception.py:80: in unraisable_exception_runtest_hook
    warnings.warn(pytest.PytestUnraisableExceptionWarning(msg))
E   pytest.PytestUnraisableExceptionWarning: Exception ignored in: <finalize object at 0x7fcc69eb0ba0; dead>
E   
E   Traceback (most recent call last):
E     File "/opt/hostedtoolcache/Python/3.13.1/x64/lib/python3.13/weakref.py", line 590, in __call__
E       return info.func(*info.args, **(info.kwargs or {}))
E              ~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
E     File "/opt/hostedtoolcache/Python/3.13.1/x64/lib/python3.13/tempfile.py", line 936, in _cleanup
E       _warnings.warn(warn_message, ResourceWarning)
E       ~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
E   ResourceWarning: Implicitly cleaning up <TemporaryDirectory '/tmp/sentry-p4-4y9mhhvj'>
tests/sentry/integrations/perforce/test_stacktrace_link.py::PerforceStacktraceLinkTest::test_get_stacktrace_config_multiple_code_mappingslog
.venv/lib/python3.13/site-packages/_pytest/runner.py:340: in from_call
    result: Optional[TResult] = func()
.venv/lib/python3.13/site-packages/_pytest/runner.py:240: in <lambda>
    lambda: runtest_hook(item=item, **kwds), when=when, reraise=reraise
.venv/lib/python3.13/site-packages/pluggy/_hooks.py:513: in __call__
    return self._hookexec(self.name, self._hookimpls.copy(), kwargs, firstresult)
.venv/lib/python3.13/site-packages/pluggy/_manager.py:120: in _hookexec
    return self._inner_hookexec(hook_name, methods, kwargs, firstresult)
.venv/lib/python3.13/site-packages/_pytest/threadexception.py:87: in pytest_runtest_call
    yield from thread_exception_runtest_hook()
.venv/lib/python3.13/site-packages/_pytest/threadexception.py:63: in thread_exception_runtest_hook
    yield
.venv/lib/python3.13/site-packages/_pytest/unraisableexception.py:90: in pytest_runtest_call
    yield from unraisable_exception_runtest_hook()
.venv/lib/python3.13/site-packages/_pytest/unraisableexception.py:80: in unraisable_exception_runtest_hook
    warnings.warn(pytest.PytestUnraisableExceptionWarning(msg))
E   pytest.PytestUnraisableExceptionWarning: Exception ignored in: <finalize object at 0x7f5e3429b400; dead>
E   
E   Traceback (most recent call last):
E     File "/opt/hostedtoolcache/Python/3.13.1/x64/lib/python3.13/weakref.py", line 590, in __call__
E       return info.func(*info.args, **(info.kwargs or {}))
E              ~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
E     File "/opt/hostedtoolcache/Python/3.13.1/x64/lib/python3.13/tempfile.py", line 936, in _cleanup
E       _warnings.warn(warn_message, ResourceWarning)
E       ~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
E   ResourceWarning: Implicitly cleaning up <TemporaryDirectory '/tmp/sentry-p4-evl8fobv'>
tests/sentry/integrations/perforce/test_stacktrace_link.py::PerforceStacktraceLinkEdgeCasesTest::test_stacktrace_link_with_special_characters_in_pathlog
.venv/lib/python3.13/site-packages/_pytest/runner.py:340: in from_call
    result: Optional[TResult] = func()
.venv/lib/python3.13/site-packages/_pytest/runner.py:240: in <lambda>
    lambda: runtest_hook(item=item, **kwds), when=when, reraise=reraise
.venv/lib/python3.13/site-packages/pluggy/_hooks.py:513: in __call__
    return self._hookexec(self.name, self._hookimpls.copy(), kwargs, firstresult)
.venv/lib/python3.13/site-packages/pluggy/_manager.py:120: in _hookexec
    return self._inner_hookexec(hook_name, methods, kwargs, firstresult)
.venv/lib/python3.13/site-packages/_pytest/threadexception.py:87: in pytest_runtest_call
    yield from thread_exception_runtest_hook()
.venv/lib/python3.13/site-packages/_pytest/threadexception.py:63: in thread_exception_runtest_hook
    yield
.venv/lib/python3.13/site-packages/_pytest/unraisableexception.py:90: in pytest_runtest_call
    yield from unraisable_exception_runtest_hook()
.venv/lib/python3.13/site-packages/_pytest/unraisableexception.py:80: in unraisable_exception_runtest_hook
    warnings.warn(pytest.PytestUnraisableExceptionWarning(msg))
E   pytest.PytestUnraisableExceptionWarning: Exception ignored in: <finalize object at 0x7f5e342739c0; dead>
E   
E   Traceback (most recent call last):
E     File "/opt/hostedtoolcache/Python/3.13.1/x64/lib/python3.13/weakref.py", line 590, in __call__
E       return info.func(*info.args, **(info.kwargs or {}))
E              ~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
E     File "/opt/hostedtoolcache/Python/3.13.1/x64/lib/python3.13/tempfile.py", line 936, in _cleanup
E       _warnings.warn(warn_message, ResourceWarning)
E       ~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
E   ResourceWarning: Implicitly cleaning up <TemporaryDirectory '/tmp/sentry-p4-o6oav_hd'>
tests/sentry/integrations/perforce/test_client.py::PerforceClientTest::test_set_env_p4trust_does_not_affect_os_environlog
tests/sentry/integrations/perforce/test_client.py:704: in test_set_env_p4trust_does_not_affect_os_environ
    p4.set_env("P4TRUST", "/tmp/should_not_leak/.p4trust")
E   P4.P4Exception: Can't set registry on UNIX.
tests/sentry/integrations/perforce/test_stacktrace_link.py::PerforceStacktraceLinkTest::test_get_stacktrace_config_abs_path_fallbacklog
.venv/lib/python3.13/site-packages/_pytest/runner.py:340: in from_call
    result: Optional[TResult] = func()
.venv/lib/python3.13/site-packages/_pytest/runner.py:240: in <lambda>
    lambda: runtest_hook(item=item, **kwds), when=when, reraise=reraise
.venv/lib/python3.13/site-packages/pluggy/_hooks.py:513: in __call__
    return self._hookexec(self.name, self._hookimpls.copy(), kwargs, firstresult)
.venv/lib/python3.13/site-packages/pluggy/_manager.py:120: in _hookexec
    return self._inner_hookexec(hook_name, methods, kwargs, firstresult)
.venv/lib/python3.13/site-packages/_pytest/threadexception.py:87: in pytest_runtest_call
    yield from thread_exception_runtest_hook()
.venv/lib/python3.13/site-packages/_pytest/threadexception.py:63: in thread_exception_runtest_hook
    yield
.venv/lib/python3.13/site-packages/_pytest/unraisableexception.py:90: in pytest_runtest_call
    yield from unraisable_exception_runtest_hook()
.venv/lib/python3.13/site-packages/_pytest/unraisableexception.py:80: in unraisable_exception_runtest_hook
    warnings.warn(pytest.PytestUnraisableExceptionWarning(msg))
E   pytest.PytestUnraisableExceptionWarning: Exception ignored in: <finalize object at 0x7fb8a6dca0a0; dead>
E   
E   Traceback (most recent call last):
E     File "/opt/hostedtoolcache/Python/3.13.1/x64/lib/python3.13/weakref.py", line 590, in __call__
E       return info.func(*info.args, **(info.kwargs or {}))
E              ~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
E     File "/opt/hostedtoolcache/Python/3.13.1/x64/lib/python3.13/tempfile.py", line 936, in _cleanup
E       _warnings.warn(warn_message, ResourceWarning)
E       ~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
E   ResourceWarning: Implicitly cleaning up <TemporaryDirectory '/tmp/sentry-p4-feytttu8'>
tests/sentry/integrations/perforce/test_integration.py::PerforceIntegrationTest::test_format_source_url_swarm_viewer_no_revisionlog
.venv/lib/python3.13/site-packages/_pytest/runner.py:340: in from_call
    result: Optional[TResult] = func()
.venv/lib/python3.13/site-packages/_pytest/runner.py:240: in <lambda>
    lambda: runtest_hook(item=item, **kwds), when=when, reraise=reraise
.venv/lib/python3.13/site-packages/pluggy/_hooks.py:513: in __call__
    return self._hookexec(self.name, self._hookimpls.copy(), kwargs, firstresult)
.venv/lib/python3.13/site-packages/pluggy/_manager.py:120: in _hookexec
    return self._inner_hookexec(hook_name, methods, kwargs, firstresult)
.venv/lib/python3.13/site-packages/_pytest/threadexception.py:87: in pytest_runtest_call
    yield from thread_exception_runtest_hook()
.venv/lib/python3.13/site-packages/_pytest/threadexception.py:63: in thread_exception_runtest_hook
    yield
.venv/lib/python3.13/site-packages/_pytest/unraisableexception.py:90: in pytest_runtest_call
    yield from unraisable_exception_runtest_hook()
.venv/lib/python3.13/site-packages/_pytest/unraisableexception.py:80: in unraisable_exception_runtest_hook
    warnings.warn(pytest.PytestUnraisableExceptionWarning(msg))
E   pytest.PytestUnraisableExceptionWarning: Exception ignored in: <finalize object at 0x7fc6c701c040; dead>
E   
E   Traceback (most recent call last):
E     File "/opt/hostedtoolcache/Python/3.13.1/x64/lib/python3.13/weakref.py", line 590, in __call__
E       return info.func(*info.args, **(info.kwargs or {}))
E              ~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
E     File "/opt/hostedtoolcache/Python/3.13.1/x64/lib/python3.13/tempfile.py", line 936, in _cleanup
E       _warnings.warn(warn_message, ResourceWarning)
E       ~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
E   ResourceWarning: Implicitly cleaning up <TemporaryDirectory '/tmp/sentry-p4-nxs4perx'>
tests/sentry/integrations/perforce/test_integration.py::PerforceIntegrationWebViewersTest::test_swarm_extracts_revision_from_filenamelog
.venv/lib/python3.13/site-packages/_pytest/runner.py:340: in from_call
    result: Optional[TResult] = func()
.venv/lib/python3.13/site-packages/_pytest/runner.py:240: in <lambda>
    lambda: runtest_hook(item=item, **kwds), when=when, reraise=reraise
.venv/lib/python3.13/site-packages/pluggy/_hooks.py:513: in __call__
    return self._hookexec(self.name, self._hookimpls.copy(), kwargs, firstresult)
.venv/lib/python3.13/site-packages/pluggy/_manager.py:120: in _hookexec
    return self._inner_hookexec(hook_name, methods, kwargs, firstresult)
.venv/lib/python3.13/site-packages/_pytest/threadexception.py:87: in pytest_runtest_call
    yield from thread_exception_runtest_hook()
.venv/lib/python3.13/site-packages/_pytest/threadexception.py:63: in thread_exception_runtest_hook
    yield
.venv/lib/python3.13/site-packages/_pytest/unraisableexception.py:90: in pytest_runtest_call
    yield from unraisable_exception_runtest_hook()
.venv/lib/python3.13/site-packages/_pytest/unraisableexception.py:80: in unraisable_exception_runtest_hook
    warnings.warn(pytest.PytestUnraisableExceptionWarning(msg))
E   pytest.PytestUnraisableExceptionWarning: Exception ignored in: <finalize object at 0x7fcf761528c0; dead>
E   
E   Traceback (most recent call last):
E     File "/opt/hostedtoolcache/Python/3.13.1/x64/lib/python3.13/weakref.py", line 590, in __call__
E       return info.func(*info.args, **(info.kwargs or {}))
E              ~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
E     File "/opt/hostedtoolcache/Python/3.13.1/x64/lib/python3.13/tempfile.py", line 936, in _cleanup
E       _warnings.warn(warn_message, ResourceWarning)
E       ~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
E   ResourceWarning: Implicitly cleaning up <TemporaryDirectory '/tmp/sentry-p4-php1p_et'>
tests/sentry/integrations/perforce/test_stacktrace_link.py::PerforceStacktraceLinkEdgeCasesTest::test_stacktrace_link_empty_stack_rootlog
.venv/lib/python3.13/site-packages/_pytest/runner.py:340: in from_call
    result: Optional[TResult] = func()
.venv/lib/python3.13/site-packages/_pytest/runner.py:240: in <lambda>
    lambda: runtest_hook(item=item, **kwds), when=when, reraise=reraise
.venv/lib/python3.13/site-packages/pluggy/_hooks.py:513: in __call__
    return self._hookexec(self.name, self._hookimpls.copy(), kwargs, firstresult)
.venv/lib/python3.13/site-packages/pluggy/_manager.py:120: in _hookexec
    return self._inner_hookexec(hook_name, methods, kwargs, firstresult)
.venv/lib/python3.13/site-packages/_pytest/threadexception.py:87: in pytest_runtest_call
    yield from thread_exception_runtest_hook()
.venv/lib/python3.13/site-packages/_pytest/threadexception.py:63: in thread_exception_runtest_hook
    yield
.venv/lib/python3.13/site-packages/_pytest/unraisableexception.py:90: in pytest_runtest_call
    yield from unraisable_exception_runtest_hook()
.venv/lib/python3.13/site-packages/_pytest/unraisableexception.py:80: in unraisable_exception_runtest_hook
    warnings.warn(pytest.PytestUnraisableExceptionWarning(msg))
E   pytest.PytestUnraisableExceptionWarning: Exception ignored in: <finalize object at 0x7fc1ed39dc80; dead>
E   
E   Traceback (most recent call last):
E     File "/opt/hostedtoolcache/Python/3.13.1/x64/lib/python3.13/weakref.py", line 590, in __call__
E       return info.func(*info.args, **(info.kwargs or {}))
E              ~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
E     File "/opt/hostedtoolcache/Python/3.13.1/x64/lib/python3.13/tempfile.py", line 936, in _cleanup
E       _warnings.warn(warn_message, ResourceWarning)
E       ~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
E   ResourceWarning: Implicitly cleaning up <TemporaryDirectory '/tmp/sentry-p4-nm3wdrn0'>
tests/sentry/integrations/perforce/test_stacktrace_link.py::PerforceStacktraceLinkTest::test_get_stacktrace_config_stops_on_first_matchlog
.venv/lib/python3.13/site-packages/_pytest/runner.py:340: in from_call
    result: Optional[TResult] = func()
.venv/lib/python3.13/site-packages/_pytest/runner.py:240: in <lambda>
    lambda: runtest_hook(item=item, **kwds), when=when, reraise=reraise
.venv/lib/python3.13/site-packages/pluggy/_hooks.py:513: in __call__
    return self._hookexec(self.name, self._hookimpls.copy(), kwargs, firstresult)
.venv/lib/python3.13/site-packages/pluggy/_manager.py:120: in _hookexec
    return self._inner_hookexec(hook_name, methods, kwargs, firstresult)
.venv/lib/python3.13/site-packages/_pytest/threadexception.py:87: in pytest_runtest_call
    yield from thread_exception_runtest_hook()
.venv/lib/python3.13/site-packages/_pytest/threadexception.py:63: in thread_exception_runtest_hook
    yield
.venv/lib/python3.13/site-packages/_pytest/unraisableexception.py:90: in pytest_runtest_call
    yield from unraisable_exception_runtest_hook()
.venv/lib/python3.13/site-packages/_pytest/unraisableexception.py:80: in unraisable_exception_runtest_hook
    warnings.warn(pytest.PytestUnraisableExceptionWarning(msg))
E   pytest.PytestUnraisableExceptionWarning: Exception ignored in: <finalize object at 0x7fd53c31e6c0; dead>
E   
E   Traceback (most recent call last):
E     File "/opt/hostedtoolcache/Python/3.13.1/x64/lib/python3.13/weakref.py", line 590, in __call__
E       return info.func(*info.args, **(info.kwargs or {}))
E              ~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
E     File "/opt/hostedtoolcache/Python/3.13.1/x64/lib/python3.13/tempfile.py", line 936, in _cleanup
E       _warnings.warn(warn_message, ResourceWarning)
E       ~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
E   ResourceWarning: Implicitly cleaning up <TemporaryDirectory '/tmp/sentry-p4-94v6viyx'>
tests/sentry/integrations/perforce/test_integration.py::PerforceIntegrationTest::test_format_source_url_swarm_viewer_absolute_pathlog
.venv/lib/python3.13/site-packages/_pytest/runner.py:340: in from_call
    result: Optional[TResult] = func()
.venv/lib/python3.13/site-packages/_pytest/runner.py:240: in <lambda>
    lambda: runtest_hook(item=item, **kwds), when=when, reraise=reraise
.venv/lib/python3.13/site-packages/pluggy/_hooks.py:513: in __call__
    return self._hookexec(self.name, self._hookimpls.copy(), kwargs, firstresult)
.venv/lib/python3.13/site-packages/pluggy/_manager.py:120: in _hookexec
    return self._inner_hookexec(hook_name, methods, kwargs, firstresult)
.venv/lib/python3.13/site-packages/_pytest/threadexception.py:87: in pytest_runtest_call
    yield from thread_exception_runtest_hook()
.venv/lib/python3.13/site-packages/_pytest/threadexception.py:63: in thread_exception_runtest_hook
    yield
.venv/lib/python3.13/site-packages/_pytest/unraisableexception.py:90: in pytest_runtest_call
    yield from unraisable_exception_runtest_hook()
.venv/lib/python3.13/site-packages/_pytest/unraisableexception.py:80: in unraisable_exception_runtest_hook
    warnings.warn(pytest.PytestUnraisableExceptionWarning(msg))
E   pytest.PytestUnraisableExceptionWarning: Exception ignored in: <finalize object at 0x7f7c78415f00; dead>
E   
E   Traceback (most recent call last):
E     File "/opt/hostedtoolcache/Python/3.13.1/x64/lib/python3.13/weakref.py", line 590, in __call__
E       return info.func(*info.args, **(info.kwargs or {}))
E              ~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
E     File "/opt/hostedtoolcache/Python/3.13.1/x64/lib/python3.13/tempfile.py", line 936, in _cleanup
E       _warnings.warn(warn_message, ResourceWarning)
E       ~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
E   ResourceWarning: Implicitly cleaning up <TemporaryDirectory '/tmp/sentry-p4-ampnnm1h'>
tests/sentry/integrations/perforce/test_stacktrace_link.py::PerforceStacktraceLinkTest::test_get_stacktrace_config_cpp_path_with_revisionlog
.venv/lib/python3.13/site-packages/_pytest/runner.py:340: in from_call
    result: Optional[TResult] = func()
.venv/lib/python3.13/site-packages/_pytest/runner.py:240: in <lambda>
    lambda: runtest_hook(item=item, **kwds), when=when, reraise=reraise
.venv/lib/python3.13/site-packages/pluggy/_hooks.py:513: in __call__
    return self._hookexec(self.name, self._hookimpls.copy(), kwargs, firstresult)
.venv/lib/python3.13/site-packages/pluggy/_manager.py:120: in _hookexec
    return self._inner_hookexec(hook_name, methods, kwargs, firstresult)
.venv/lib/python3.13/site-packages/_pytest/threadexception.py:87: in pytest_runtest_call
    yield from thread_exception_runtest_hook()
.venv/lib/python3.13/site-packages/_pytest/threadexception.py:63: in thread_exception_runtest_hook
    yield
.venv/lib/python3.13/site-packages/_pytest/unraisableexception.py:90: in pytest_runtest_call
    yield from unraisable_exception_runtest_hook()
.venv/lib/python3.13/site-packages/_pytest/unraisableexception.py:80: in unraisable_exception_runtest_hook
    warnings.warn(pytest.PytestUnraisableExceptionWarning(msg))
E   pytest.PytestUnraisableExceptionWarning: Exception ignored in: <finalize object at 0x7f2b2dc02c20; dead>
E   
E   Traceback (most recent call last):
E     File "/opt/hostedtoolcache/Python/3.13.1/x64/lib/python3.13/weakref.py", line 590, in __call__
E       return info.func(*info.args, **(info.kwargs or {}))
E              ~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
E     File "/opt/hostedtoolcache/Python/3.13.1/x64/lib/python3.13/tempfile.py", line 936, in _cleanup
E       _warnings.warn(warn_message, ResourceWarning)
E       ~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
E   ResourceWarning: Implicitly cleaning up <TemporaryDirectory '/tmp/sentry-p4-j0cxfdp0'>
tests/sentry/integrations/perforce/test_stacktrace_link.py::PerforceStacktraceLinkEdgeCasesTest::test_stacktrace_link_deeply_nested_pathlog
.venv/lib/python3.13/site-packages/_pytest/runner.py:340: in from_call
    result: Optional[TResult] = func()
.venv/lib/python3.13/site-packages/_pytest/runner.py:240: in <lambda>
    lambda: runtest_hook(item=item, **kwds), when=when, reraise=reraise
.venv/lib/python3.13/site-packages/pluggy/_hooks.py:513: in __call__
    return self._hookexec(self.name, self._hookimpls.copy(), kwargs, firstresult)
.venv/lib/python3.13/site-packages/pluggy/_manager.py:120: in _hookexec
    return self._inner_hookexec(hook_name, methods, kwargs, firstresult)
.venv/lib/python3.13/site-packages/_pytest/threadexception.py:87: in pytest_runtest_call
    yield from thread_exception_runtest_hook()
.venv/lib/python3.13/site-packages/_pytest/threadexception.py:63: in thread_exception_runtest_hook
    yield
.venv/lib/python3.13/site-packages/_pytest/unraisableexception.py:90: in pytest_runtest_call
    yield from unraisable_exception_runtest_hook()
.venv/lib/python3.13/site-packages/_pytest/unraisableexception.py:80: in unraisable_exception_runtest_hook
    warnings.warn(pytest.PytestUnraisableExceptionWarning(msg))
E   pytest.PytestUnraisableExceptionWarning: Exception ignored in: <finalize object at 0x7f2b2de22020; dead>
E   
E   Traceback (most recent call last):
E     File "/opt/hostedtoolcache/Python/3.13.1/x64/lib/python3.13/weakref.py", line 590, in __call__
E       return info.func(*info.args, **(info.kwargs or {}))
E              ~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
E     File "/opt/hostedtoolcache/Python/3.13.1/x64/lib/python3.13/tempfile.py", line 936, in _cleanup
E       _warnings.warn(warn_message, ResourceWarning)
E       ~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
E   ResourceWarning: Implicitly cleaning up <TemporaryDirectory '/tmp/sentry-p4-tkfr0noi'>
tests/sentry/integrations/perforce/test_client.py::PerforceClientTest::test_connect_does_not_set_trust_file_propertylog
tests/sentry/integrations/perforce/test_client.py:678: in test_connect_does_not_set_trust_file_property
    assert mock_p4.trust_file != mock.Mock.trust_file
E   AttributeError: type object 'Mock' has no attribute 'trust_file'
tests/sentry/integrations/perforce/test_stacktrace_link.py::PerforceStacktraceLinkTest::test_get_stacktrace_config_iteration_countlog
.venv/lib/python3.13/site-packages/_pytest/runner.py:340: in from_call
    result: Optional[TResult] = func()
.venv/lib/python3.13/site-packages/_pytest/runner.py:240: in <lambda>
    lambda: runtest_hook(item=item, **kwds), when=when, reraise=reraise
.venv/lib/python3.13/site-packages/pluggy/_hooks.py:513: in __call__
    return self._hookexec(self.name, self._hookimpls.copy(), kwargs, firstresult)
.venv/lib/python3.13/site-packages/pluggy/_manager.py:120: in _hookexec
    return self._inner_hookexec(hook_name, methods, kwargs, firstresult)
.venv/lib/python3.13/site-packages/_pytest/threadexception.py:87: in pytest_runtest_call
    yield from thread_exception_runtest_hook()
.venv/lib/python3.13/site-packages/_pytest/threadexception.py:63: in thread_exception_runtest_hook
    yield
.venv/lib/python3.13/site-packages/_pytest/unraisableexception.py:90: in pytest_runtest_call
    yield from unraisable_exception_runtest_hook()
.venv/lib/python3.13/site-packages/_pytest/unraisableexception.py:80: in unraisable_exception_runtest_hook
    warnings.warn(pytest.PytestUnraisableExceptionWarning(msg))
E   pytest.PytestUnraisableExceptionWarning: Exception ignored in: <finalize object at 0x7fad34c7f280; dead>
E   
E   Traceback (most recent call last):
E     File "/opt/hostedtoolcache/Python/3.13.1/x64/lib/python3.13/weakref.py", line 590, in __call__
E       return info.func(*info.args, **(info.kwargs or {}))
E              ~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
E     File "/opt/hostedtoolcache/Python/3.13.1/x64/lib/python3.13/tempfile.py", line 936, in _cleanup
E       _warnings.warn(warn_message, ResourceWarning)
E       ~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
E   ResourceWarning: Implicitly cleaning up <TemporaryDirectory '/tmp/sentry-p4-mrjx5hv4'>
tests/sentry/integrations/perforce/test_integration.py::PerforceIntegrationTest::test_format_source_url_swarm_viewer_depot_name_pathlog
.venv/lib/python3.13/site-packages/_pytest/runner.py:340: in from_call
    result: Optional[TResult] = func()
.venv/lib/python3.13/site-packages/_pytest/runner.py:240: in <lambda>
    lambda: runtest_hook(item=item, **kwds), when=when, reraise=reraise
.venv/lib/python3.13/site-packages/pluggy/_hooks.py:513: in __call__
    return self._hookexec(self.name, self._hookimpls.copy(), kwargs, firstresult)
.venv/lib/python3.13/site-packages/pluggy/_manager.py:120: in _hookexec
    return self._inner_hookexec(hook_name, methods, kwargs, firstresult)
.venv/lib/python3.13/site-packages/_pytest/threadexception.py:87: in pytest_runtest_call
    yield from thread_exception_runtest_hook()
.venv/lib/python3.13/site-packages/_pytest/threadexception.py:63: in thread_exception_runtest_hook
    yield
.venv/lib/python3.13/site-packages/_pytest/unraisableexception.py:90: in pytest_runtest_call
    yield from unraisable_exception_runtest_hook()
.venv/lib/python3.13/site-packages/_pytest/unraisableexception.py:80: in unraisable_exception_runtest_hook
    warnings.warn(pytest.PytestUnraisableExceptionWarning(msg))
E   pytest.PytestUnraisableExceptionWarning: Exception ignored in: <finalize object at 0x7f2e64750f60; dead>
E   
E   Traceback (most recent call last):
E     File "/opt/hostedtoolcache/Python/3.13.1/x64/lib/python3.13/weakref.py", line 590, in __call__
E       return info.func(*info.args, **(info.kwargs or {}))
E              ~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
E     File "/opt/hostedtoolcache/Python/3.13.1/x64/lib/python3.13/tempfile.py", line 936, in _cleanup
E       _warnings.warn(warn_message, ResourceWarning)
E       ~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
E   ResourceWarning: Implicitly cleaning up <TemporaryDirectory '/tmp/sentry-p4-ua1btnw9'>
tests/sentry/integrations/perforce/test_stacktrace_link.py::PerforceStacktraceLinkTest::test_get_stacktrace_config_python_pathlog
.venv/lib/python3.13/site-packages/_pytest/runner.py:340: in from_call
    result: Optional[TResult] = func()
.venv/lib/python3.13/site-packages/_pytest/runner.py:240: in <lambda>
    lambda: runtest_hook(item=item, **kwds), when=when, reraise=reraise
.venv/lib/python3.13/site-packages/pluggy/_hooks.py:513: in __call__
    return self._hookexec(self.name, self._hookimpls.copy(), kwargs, firstresult)
.venv/lib/python3.13/site-packages/pluggy/_manager.py:120: in _hookexec
    return self._inner_hookexec(hook_name, methods, kwargs, firstresult)
.venv/lib/python3.13/site-packages/_pytest/threadexception.py:87: in pytest_runtest_call
    yield from thread_exception_runtest_hook()
.venv/lib/python3.13/site-packages/_pytest/threadexception.py:63: in thread_exception_runtest_hook
    yield
.venv/lib/python3.13/site-packages/_pytest/unraisableexception.py:90: in pytest_runtest_call
    yield from unraisable_exception_runtest_hook()
.venv/lib/python3.13/site-packages/_pytest/unraisableexception.py:80: in unraisable_exception_runtest_hook
    warnings.warn(pytest.PytestUnraisableExceptionWarning(msg))
E   pytest.PytestUnraisableExceptionWarning: Exception ignored in: <finalize object at 0x7f2e64586500; dead>
E   
E   Traceback (most recent call last):
E     File "/opt/hostedtoolcache/Python/3.13.1/x64/lib/python3.13/weakref.py", line 590, in __call__
E       return info.func(*info.args, **(info.kwargs or {}))
E              ~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
E     File "/opt/hostedtoolcache/Python/3.13.1/x64/lib/python3.13/tempfile.py", line 936, in _cleanup
E       _warnings.warn(warn_message, ResourceWarning)
E       ~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
E   ResourceWarning: Implicitly cleaning up <TemporaryDirectory '/tmp/sentry-p4-hl0bdqgb'>
tests/sentry/integrations/perforce/test_stacktrace_link.py::PerforceStacktraceLinkTest::test_get_stacktrace_config_with_web_viewerlog
.venv/lib/python3.13/site-packages/_pytest/runner.py:340: in from_call
    result: Optional[TResult] = func()
.venv/lib/python3.13/site-packages/_pytest/runner.py:240: in <lambda>
    lambda: runtest_hook(item=item, **kwds), when=when, reraise=reraise
.venv/lib/python3.13/site-packages/pluggy/_hooks.py:513: in __call__
    return self._hookexec(self.name, self._hookimpls.copy(), kwargs, firstresult)
.venv/lib/python3.13/site-packages/pluggy/_manager.py:120: in _hookexec
    return self._inner_hookexec(hook_name, methods, kwargs, firstresult)
.venv/lib/python3.13/site-packages/_pytest/threadexception.py:87: in pytest_runtest_call
    yield from thread_exception_runtest_hook()
.venv/lib/python3.13/site-packages/_pytest/threadexception.py:63: in thread_exception_runtest_hook
    yield
.venv/lib/python3.13/site-packages/_pytest/unraisableexception.py:90: in pytest_runtest_call
    yield from unraisable_exception_runtest_hook()
.venv/lib/python3.13/site-packages/_pytest/unraisableexception.py:80: in unraisable_exception_runtest_hook
    warnings.warn(pytest.PytestUnraisableExceptionWarning(msg))
E   pytest.PytestUnraisableExceptionWarning: Exception ignored in: <finalize object at 0x7f2e76552540; dead>
E   
E   Traceback (most recent call last):
E     File "/opt/hostedtoolcache/Python/3.13.1/x64/lib/python3.13/weakref.py", line 590, in __call__
E       return info.func(*info.args, **(info.kwargs or {}))
E              ~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
E     File "/opt/hostedtoolcache/Python/3.13.1/x64/lib/python3.13/tempfile.py", line 936, in _cleanup
E       _warnings.warn(warn_message, ResourceWarning)
E       ~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
E   ResourceWarning: Implicitly cleaning up <TemporaryDirectory '/tmp/sentry-p4-0bu3c3y4'>

…rceWarning

Python 3.13 raises ResourceWarning when TemporaryDirectory is cleaned
up implicitly by the garbage collector rather than via explicit context
manager exit. Since PerforceClient stores the temp dir as an instance
attribute (not in a with block), GC cleanup triggers this warning and
fails CI.

Switch to mkdtemp + atexit.register(shutil.rmtree) for explicit
cleanup without relying on GC finalizers.

Co-Authored-By: Claude <noreply@anthropic.com>
@github-actions
Copy link
Contributor

github-actions bot commented Mar 2, 2026

Backend Test Failures

Failures on 11ae572 in this run:

tests/sentry/integrations/perforce/test_client.py::PerforceClientTest::test_set_env_p4trust_is_per_p4_instancelog
tests/sentry/integrations/perforce/test_client.py:694: in test_set_env_p4trust_is_per_p4_instance
    p4a.set_env("P4TRUST", "/tmp/customer_a/.p4trust")
E   P4.P4Exception: Can't set registry on UNIX.
tests/sentry/integrations/perforce/test_client.py::PerforceClientTest::test_set_env_p4trust_does_not_affect_os_environlog
tests/sentry/integrations/perforce/test_client.py:707: in test_set_env_p4trust_does_not_affect_os_environ
    p4.set_env("P4TRUST", "/tmp/should_not_leak/.p4trust")
E   P4.P4Exception: Can't set registry on UNIX.
tests/sentry/integrations/perforce/test_client.py::PerforceClientTest::test_connect_does_not_set_trust_file_propertylog
tests/sentry/integrations/perforce/test_client.py:681: in test_connect_does_not_set_trust_file_property
    assert mock_p4.trust_file != mock.Mock.trust_file
E   AttributeError: type object 'Mock' has no attribute 'trust_file'

…emp+atexit

Replace mkdtemp+atexit with TemporaryDirectory inside _connect() to
properly scope temp directory lifetime. The atexit approach only ran
cleanup at process shutdown, causing temp dirs to accumulate in long-
running workers. The context manager cleans up immediately when the
connection context exits.

Also fix three test failures:
- Remove broken test_connect_does_not_set_trust_file_property (Mock
  attribute assertion was incorrect, and the behavior is already
  verified by test_connect_sets_isolated_trust_and_ticket_paths)
- Add try/except around set_env calls in tests that use real P4
  instances (set_env raises when P4ENVIRO is /dev/null)
- Remove tests that relied on __init__ tmpdir (no longer exists)

Co-Authored-By: Claude <noreply@anthropic.com>
@mujacica mujacica marked this pull request as ready for review March 2, 2026 11:47
@mujacica mujacica requested review from a team as code owners March 2, 2026 11:47
@mujacica mujacica merged commit 5faeeb5 into master Mar 3, 2026
75 checks passed
@mujacica mujacica deleted the fix/perforce_p4trust branch March 3, 2026 09:41
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Scope: Backend Automatically applied to PRs that change backend components

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants