Implement missing agent system support via tests.data.SystemSupportAction
Marco Ricci

Marco Ricci commited on 2026-07-04 21:10:03
Zeige 3 geänderte Dateien mit 42 Einfügungen und 113 Löschungen.


Implement the "missing system support for the SSH agent communication
channel" setup code via the now centralized
`tests.data.SystemSupportAction` enum, instead of duplicating the setup
steps everywhere.  This means adding the correct `SystemSupportAction`
value to the `MISSING_AGENT_SUPPORT` parametrization set.

In particular, since this parametrization set is already used in two
different test modules, put it into
`tests.machinery.pytest.Parametrize`.
... ...
@@ -36,7 +36,11 @@ from typing_extensions import assert_never, overload
36 36
 import tests.data
37 37
 import tests.machinery
38 38
 from derivepassphrase import _types, ssh_agent
39
-from derivepassphrase._internals import cli_helpers, cli_machinery
39
+from derivepassphrase._internals import (
40
+    cli_helpers,
41
+    cli_machinery,
42
+    cli_messages,
43
+)
40 44
 from derivepassphrase.ssh_agent import socketprovider
41 45
 
42 46
 __all__ = ()
... ...
@@ -216,6 +220,33 @@ class Parametrize(types.SimpleNamespace):
216 220
             ),
217 221
         ],
218 222
     )
223
+    MISSING_AGENT_SUPPORT = pytest.mark.parametrize(
224
+        ["provider", "sys_action", "exception", "message"],
225
+        [
226
+            pytest.param(
227
+                _types.BuiltinSSHAgentSocketProvider.SSH_AUTH_SOCK_ON_POSIX,
228
+                tests.data.SystemSupportAction.UNSET_AF_UNIX_AND_ENSURE_USE,
229
+                socketprovider.UnixDomainSocketsNotAvailableError,
230
+                str(
231
+                    cli_messages.TranslatedString(
232
+                        cli_messages.WarnMsgTemplate.NO_UNIX_DOMAIN_SOCKETS
233
+                    )
234
+                ),
235
+                id="unix_domain_sockets",
236
+            ),
237
+            pytest.param(
238
+                _types.BuiltinSSHAgentSocketProvider.WINDOWS_NAMED_PIPE,
239
+                tests.data.SystemSupportAction.UNSET_WINDLL_AND_ENSURE_USE,
240
+                socketprovider.WindowsNamedPipesNotAvailableError,
241
+                str(
242
+                    cli_messages.TranslatedString(
243
+                        cli_messages.WarnMsgTemplate.NO_WINDOWS_NAMED_PIPES
244
+                    )
245
+                ),
246
+                id="windows_named_pipes",
247
+            ),
248
+        ],
249
+    )
219 250
 
220 251
 
221 252
 # Monkeypatchings
... ...
@@ -13,18 +13,14 @@ subsystems.)
13 13
 from __future__ import annotations
14 14
 
15 15
 import contextlib
16
-import ctypes
17 16
 import json
18
-import socket
19 17
 import textwrap
20
-import types
21 18
 from typing import TYPE_CHECKING, ClassVar
22 19
 
23 20
 import pytest
24 21
 
25
-from derivepassphrase import _types, cli, ssh_agent
26
-from derivepassphrase._internals import cli_helpers, cli_messages
27
-from derivepassphrase.ssh_agent import socketprovider
22
+from derivepassphrase import _types, cli
23
+from derivepassphrase._internals import cli_helpers
28 24
 from tests import data, machinery
29 25
 from tests.machinery import pytest as pytest_machinery
30 26
 
... ...
@@ -36,7 +32,7 @@ DUMMY_PASSPHRASE = data.DUMMY_PASSPHRASE
36 32
 DUMMY_CONFIG_SETTINGS = data.DUMMY_CONFIG_SETTINGS
37 33
 
38 34
 
39
-class Parametrize(types.SimpleNamespace):
35
+class Parametrize(pytest_machinery.Parametrize):
40 36
     """Common test parametrizations."""
41 37
 
42 38
     UNICODE_NORMALIZATION_ERROR_INPUTS = pytest.mark.parametrize(
... ...
@@ -218,31 +214,6 @@ class Parametrize(types.SimpleNamespace):
218 214
             ),
219 215
         ],
220 216
     )
221
-    MISSING_AGENT_SUPPORT = pytest.mark.parametrize(
222
-        ["provider", "exception", "message"],
223
-        [
224
-            pytest.param(
225
-                _types.BuiltinSSHAgentSocketProvider.SSH_AUTH_SOCK_ON_POSIX,
226
-                socketprovider.UnixDomainSocketsNotAvailableError,
227
-                str(
228
-                    cli_messages.TranslatedString(
229
-                        cli_messages.WarnMsgTemplate.NO_UNIX_DOMAIN_SOCKETS
230
-                    )
231
-                ),
232
-                id="unix_domain_sockets",
233
-            ),
234
-            pytest.param(
235
-                _types.BuiltinSSHAgentSocketProvider.WINDOWS_NAMED_PIPE,
236
-                socketprovider.WindowsNamedPipesNotAvailableError,
237
-                str(
238
-                    cli_messages.TranslatedString(
239
-                        cli_messages.WarnMsgTemplate.NO_WINDOWS_NAMED_PIPES
240
-                    )
241
-                ),
242
-                id="windows_named_pipes",
243
-            ),
244
-        ],
245
-    )
246 217
 
247 218
 
248 219
 class TestPassphraseUnicodeNormalization:
... ...
@@ -389,39 +360,17 @@ class TestUserConfigurationFileOther:
389 360
 class TestSSHAgentAvailability:
390 361
     """Tests concerning the availability of the SSH agent."""
391 362
 
392
-    # TODO(the-13th-letter): Decouple tests from exact knowledge of how
393
-    # to unsupport a certain socket provider.  Coordinate with
394
-    # tests.test_derivepassphrase_ssh_agent.test_000_basic.TestConstructorFailures.
395
-    def _unsupport_provider_and_force_use(
396
-        self,
397
-        provider: _types.BuiltinSSHAgentSocketProvider,
398
-        monkeypatch: pytest.MonkeyPatch,
399
-    ) -> None:
400
-        """Remove support for the named socket provider."""
401
-        if (
402
-            provider
403
-            == _types.BuiltinSSHAgentSocketProvider.SSH_AUTH_SOCK_ON_POSIX
404
-        ):
405
-            monkeypatch.delattr(socket, "AF_UNIX", raising=False)
406
-        elif (
407
-            provider == _types.BuiltinSSHAgentSocketProvider.WINDOWS_NAMED_PIPE
408
-        ):
409
-            monkeypatch.delattr(ctypes, "WinDLL", raising=False)
410
-        else:
411
-            pytest.fail(f"Don't know how to remove support for {provider!r}.")
412
-        monkeypatch.setattr(
413
-            ssh_agent.SSHAgentClient, "SOCKET_PROVIDERS", [provider]
414
-        )
415
-
416 363
     @Parametrize.MISSING_AGENT_SUPPORT
417 364
     def test_missing_agent_support(
418 365
         self,
419 366
         caplog: pytest.LogCaptureFixture,
420 367
         provider: _types.BuiltinSSHAgentSocketProvider,
368
+        sys_action: data.SystemSupportAction,
421 369
         exception: type[NotImplementedError],
422 370
         message: str,
423 371
     ) -> None:
424 372
         """Querying the SSH agent without support fails."""
373
+        del provider
425 374
         del exception
426 375
         runner = machinery.CliRunner(mix_stderr=False)
427 376
         # TODO(the-13th-letter): Rewrite using parenthesized
... ...
@@ -439,7 +388,7 @@ class TestSSHAgentAvailability:
439 388
             monkeypatch.setenv(
440 389
                 "SSH_AUTH_SOCK", "the value doesn't even matter"
441 390
             )
442
-            self._unsupport_provider_and_force_use(provider, monkeypatch)
391
+            sys_action(monkeypatch)
443 392
             result = runner.invoke(
444 393
                 cli.derivepassphrase_vault,
445 394
                 ["--key", "--config"],
... ...
@@ -8,12 +8,9 @@ from __future__ import annotations
8 8
 
9 9
 import base64
10 10
 import contextlib
11
-import ctypes
12 11
 import importlib.metadata
13 12
 import re
14
-import socket
15 13
 import sys
16
-import types
17 14
 from typing import TYPE_CHECKING, Final, cast
18 15
 
19 16
 import click
... ...
@@ -23,7 +20,7 @@ from hypothesis import strategies
23 20
 from typing_extensions import TypeAlias
24 21
 
25 22
 from derivepassphrase import _types, ssh_agent, vault
26
-from derivepassphrase._internals import cli_helpers, cli_messages
23
+from derivepassphrase._internals import cli_helpers
27 24
 from derivepassphrase.ssh_agent import socketprovider
28 25
 from tests import data, machinery
29 26
 from tests.data import callables
... ...
@@ -57,7 +54,7 @@ def use_stub_agent() -> Generator[None, None, None]:
57 54
         yield
58 55
 
59 56
 
60
-class Parametrize(types.SimpleNamespace):
57
+class Parametrize(pytest_machinery.Parametrize):
61 58
     BAD_ENTRY_POINTS = pytest.mark.parametrize(
62 59
         "additional_entry_points",
63 60
         [
... ...
@@ -338,31 +335,6 @@ class Parametrize(types.SimpleNamespace):
338 335
             ),
339 336
         ],
340 337
     )
341
-    MISSING_AGENT_SUPPORT = pytest.mark.parametrize(
342
-        ["provider", "exception", "message"],
343
-        [
344
-            pytest.param(
345
-                _types.BuiltinSSHAgentSocketProvider.SSH_AUTH_SOCK_ON_POSIX,
346
-                socketprovider.UnixDomainSocketsNotAvailableError,
347
-                str(
348
-                    cli_messages.TranslatedString(
349
-                        cli_messages.WarnMsgTemplate.NO_UNIX_DOMAIN_SOCKETS
350
-                    )
351
-                ),
352
-                id="unix_domain_sockets",
353
-            ),
354
-            pytest.param(
355
-                _types.BuiltinSSHAgentSocketProvider.WINDOWS_NAMED_PIPE,
356
-                socketprovider.WindowsNamedPipesNotAvailableError,
357
-                str(
358
-                    cli_messages.TranslatedString(
359
-                        cli_messages.WarnMsgTemplate.NO_WINDOWS_NAMED_PIPES
360
-                    )
361
-                ),
362
-                id="windows_named_pipes",
363
-            ),
364
-        ],
365
-    )
366 338
     PUBLIC_KEY_DATA = pytest.mark.parametrize(
367 339
         "public_key_struct",
368 340
         list(data.SUPPORTED_KEYS.values()),
... ...
@@ -1156,30 +1128,6 @@ class TestSuitableKeys:
1156 1128
 class TestConstructorFailures:
1157 1129
     """Test actually talking to the SSH agent: constructor failures."""
1158 1130
 
1159
-    # TODO(the-13th-letter): Decouple tests from exact knowledge of how
1160
-    # to unsupport a certain socket provider.  Coordinate with
1161
-    # tests.test_derivepassphrase_cli.test_000_basic.TestSSHAgentAvailability.
1162
-    def _unsupport_provider_and_force_use(
1163
-        self,
1164
-        provider: _types.BuiltinSSHAgentSocketProvider,
1165
-        monkeypatch: pytest.MonkeyPatch,
1166
-    ) -> None:
1167
-        """Remove support for the named socket provider."""
1168
-        if (
1169
-            provider
1170
-            == _types.BuiltinSSHAgentSocketProvider.SSH_AUTH_SOCK_ON_POSIX
1171
-        ):
1172
-            monkeypatch.delattr(socket, "AF_UNIX", raising=False)
1173
-        elif (
1174
-            provider == _types.BuiltinSSHAgentSocketProvider.WINDOWS_NAMED_PIPE
1175
-        ):
1176
-            monkeypatch.delattr(ctypes, "WinDLL", raising=False)
1177
-        else:
1178
-            pytest.fail(f"Don't know how to remove support for {provider!r}.")
1179
-        monkeypatch.setattr(
1180
-            ssh_agent.SSHAgentClient, "SOCKET_PROVIDERS", [provider]
1181
-        )
1182
-
1183 1131
     def test_constructor_bad_running_agent(
1184 1132
         self,
1185 1133
         running_ssh_agent: data.RunningSSHAgentInfo,
... ...
@@ -1199,6 +1147,7 @@ class TestConstructorFailures:
1199 1147
     def test_constructor_no_support(
1200 1148
         self,
1201 1149
         provider: _types.BuiltinSSHAgentSocketProvider,
1150
+        sys_action: data.SystemSupportAction,
1202 1151
         exception: type[NotImplementedError],
1203 1152
         message: str,
1204 1153
     ) -> None:
... ...
@@ -1209,7 +1158,7 @@ class TestConstructorFailures:
1209 1158
             monkeypatch.setenv(
1210 1159
                 "SSH_AUTH_SOCK", "the value doesn't even matter"
1211 1160
             )
1212
-            self._unsupport_provider_and_force_use(provider, monkeypatch)
1161
+            sys_action(monkeypatch)
1213 1162
             with pytest.raises(exception):
1214 1163
                 ssh_agent.SSHAgentClient(socket=provider)
1215 1164
 
1216 1165