provide-testkit 0.0.0.dev6__tar.gz → 0.0.31__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {provide_testkit-0.0.0.dev6 → provide_testkit-0.0.31}/PKG-INFO +3 -1
- provide_testkit-0.0.31/VERSION +1 -0
- {provide_testkit-0.0.0.dev6 → provide_testkit-0.0.31}/pyproject.toml +2 -0
- {provide_testkit-0.0.0.dev6 → provide_testkit-0.0.31}/src/provide/testkit/__init__.py +104 -65
- provide_testkit-0.0.31/src/provide/testkit/base/__init__.py +0 -0
- provide_testkit-0.0.31/src/provide/testkit/base/foundation.py +90 -0
- provide_testkit-0.0.31/src/provide/testkit/base/minimal.py +122 -0
- provide_testkit-0.0.31/src/provide/testkit/chaos/__init__.py +103 -0
- provide_testkit-0.0.31/src/provide/testkit/chaos/concurrency_strategies.py +396 -0
- provide_testkit-0.0.31/src/provide/testkit/chaos/fixtures.py +265 -0
- provide_testkit-0.0.31/src/provide/testkit/chaos/io_strategies.py +374 -0
- provide_testkit-0.0.31/src/provide/testkit/chaos/strategies.py +340 -0
- provide_testkit-0.0.31/src/provide/testkit/chaos/time_strategies.py +299 -0
- provide_testkit-0.0.31/src/provide/testkit/cli/__init__.py +0 -0
- provide_testkit-0.0.31/src/provide/testkit/cli/runner.py +215 -0
- provide_testkit-0.0.0.dev6/src/provide/testkit/cli.py → provide_testkit-0.0.31/src/provide/testkit/cli/testing.py +28 -28
- provide_testkit-0.0.31/src/provide/testkit/common/fixtures.py +164 -0
- provide_testkit-0.0.31/src/provide/testkit/crypto/__init__.py +37 -0
- provide_testkit-0.0.31/src/provide/testkit/file/temp.py +292 -0
- provide_testkit-0.0.31/src/provide/testkit/hub/__init__.py +0 -0
- provide_testkit-0.0.31/src/provide/testkit/logger/mocks.py +92 -0
- provide_testkit-0.0.31/src/provide/testkit/logger/reset.py +47 -0
- {provide_testkit-0.0.0.dev6 → provide_testkit-0.0.31}/src/provide/testkit/mocking/__init__.py +2 -0
- {provide_testkit-0.0.0.dev6 → provide_testkit-0.0.31}/src/provide/testkit/mocking/fixtures.py +7 -6
- provide_testkit-0.0.31/src/provide/testkit/mocking/time.py +183 -0
- {provide_testkit-0.0.0.dev6 → provide_testkit-0.0.31}/src/provide/testkit/process/__init__.py +0 -2
- {provide_testkit-0.0.0.dev6 → provide_testkit-0.0.31}/src/provide/testkit/process/async_fixtures.py +1 -21
- {provide_testkit-0.0.0.dev6 → provide_testkit-0.0.31}/src/provide/testkit/process/fixtures.py +0 -2
- provide_testkit-0.0.31/src/provide/testkit/streams/__init__.py +19 -0
- provide_testkit-0.0.31/src/provide/testkit/streams/testing.py +96 -0
- {provide_testkit-0.0.0.dev6 → provide_testkit-0.0.31}/src/provide/testkit/time/__init__.py +17 -2
- provide_testkit-0.0.31/src/provide/testkit/time/classes.py +320 -0
- provide_testkit-0.0.31/src/provide/testkit/time/controlled.py +81 -0
- provide_testkit-0.0.31/src/provide/testkit/time/fixtures.py +76 -0
- provide_testkit-0.0.31/src/provide/testkit/time/freezing.py +103 -0
- provide_testkit-0.0.31/src/provide/testkit/time/measurement.py +48 -0
- provide_testkit-0.0.31/src/provide/testkit/time/mocking.py +132 -0
- provide_testkit-0.0.31/src/provide/testkit/time/rate_limiting.py +33 -0
- provide_testkit-0.0.31/src/provide/testkit/utils/__init__.py +0 -0
- provide_testkit-0.0.31/src/provide/testkit/utils/temp_env.py +186 -0
- {provide_testkit-0.0.0.dev6 → provide_testkit-0.0.31}/src/provide_testkit.egg-info/PKG-INFO +3 -1
- {provide_testkit-0.0.0.dev6 → provide_testkit-0.0.31}/src/provide_testkit.egg-info/SOURCES.txt +31 -7
- {provide_testkit-0.0.0.dev6 → provide_testkit-0.0.31}/src/provide_testkit.egg-info/requires.txt +2 -0
- provide_testkit-0.0.0.dev6/VERSION +0 -1
- provide_testkit-0.0.0.dev6/src/provide/testkit/common/fixtures.py +0 -234
- provide_testkit-0.0.0.dev6/src/provide/testkit/fixtures.py +0 -52
- provide_testkit-0.0.0.dev6/src/provide/testkit/logger/reset.py +0 -230
- provide_testkit-0.0.0.dev6/src/provide/testkit/streams.py +0 -54
- provide_testkit-0.0.0.dev6/src/provide/testkit/time/fixtures.py +0 -416
- {provide_testkit-0.0.0.dev6 → provide_testkit-0.0.31}/README.md +0 -0
- {provide_testkit-0.0.0.dev6 → provide_testkit-0.0.31}/setup.cfg +0 -0
- {provide_testkit-0.0.0.dev6 → provide_testkit-0.0.31}/src/provide/__init__.py +0 -0
- {provide_testkit-0.0.0.dev6 → provide_testkit-0.0.31}/src/provide/testkit/archive/__init__.py +0 -0
- {provide_testkit-0.0.0.dev6 → provide_testkit-0.0.31}/src/provide/testkit/archive/fixtures.py +0 -0
- {provide_testkit-0.0.0.dev6/src/provide/testkit → provide_testkit-0.0.31/src/provide/testkit/base}/harness.py +0 -0
- {provide_testkit-0.0.0.dev6 → provide_testkit-0.0.31}/src/provide/testkit/common/__init__.py +0 -0
- /provide_testkit-0.0.0.dev6/src/provide/testkit/crypto.py → /provide_testkit-0.0.31/src/provide/testkit/crypto/fixtures.py +0 -0
- {provide_testkit-0.0.0.dev6 → provide_testkit-0.0.31}/src/provide/testkit/file/__init__.py +0 -0
- {provide_testkit-0.0.0.dev6 → provide_testkit-0.0.31}/src/provide/testkit/file/content_fixtures.py +0 -0
- {provide_testkit-0.0.0.dev6 → provide_testkit-0.0.31}/src/provide/testkit/file/directory_fixtures.py +0 -0
- {provide_testkit-0.0.0.dev6 → provide_testkit-0.0.31}/src/provide/testkit/file/fixtures.py +0 -0
- {provide_testkit-0.0.0.dev6 → provide_testkit-0.0.31}/src/provide/testkit/file/special_fixtures.py +0 -0
- /provide_testkit-0.0.0.dev6/src/provide/testkit/hub.py → /provide_testkit-0.0.31/src/provide/testkit/hub/fixtures.py +0 -0
- {provide_testkit-0.0.0.dev6 → provide_testkit-0.0.31}/src/provide/testkit/logger/__init__.py +0 -0
- {provide_testkit-0.0.0.dev6 → provide_testkit-0.0.31}/src/provide/testkit/logger/hooks.py +0 -0
- {provide_testkit-0.0.0.dev6 → provide_testkit-0.0.31}/src/provide/testkit/main.py +0 -0
- {provide_testkit-0.0.0.dev6 → provide_testkit-0.0.31}/src/provide/testkit/process/subprocess_fixtures.py +0 -0
- {provide_testkit-0.0.0.dev6 → provide_testkit-0.0.31}/src/provide/testkit/quality/__init__.py +0 -0
- {provide_testkit-0.0.0.dev6 → provide_testkit-0.0.31}/src/provide/testkit/quality/artifacts.py +0 -0
- {provide_testkit-0.0.0.dev6 → provide_testkit-0.0.31}/src/provide/testkit/quality/base.py +0 -0
- {provide_testkit-0.0.0.dev6 → provide_testkit-0.0.31}/src/provide/testkit/quality/cli.py +0 -0
- {provide_testkit-0.0.0.dev6 → provide_testkit-0.0.31}/src/provide/testkit/quality/complexity/__init__.py +0 -0
- {provide_testkit-0.0.0.dev6 → provide_testkit-0.0.31}/src/provide/testkit/quality/complexity/analyzer.py +0 -0
- {provide_testkit-0.0.0.dev6 → provide_testkit-0.0.31}/src/provide/testkit/quality/complexity/fixture.py +0 -0
- {provide_testkit-0.0.0.dev6 → provide_testkit-0.0.31}/src/provide/testkit/quality/coverage/__init__.py +0 -0
- {provide_testkit-0.0.0.dev6 → provide_testkit-0.0.31}/src/provide/testkit/quality/coverage/fixture.py +0 -0
- {provide_testkit-0.0.0.dev6 → provide_testkit-0.0.31}/src/provide/testkit/quality/coverage/reporter.py +0 -0
- {provide_testkit-0.0.0.dev6 → provide_testkit-0.0.31}/src/provide/testkit/quality/coverage/tracker.py +0 -0
- {provide_testkit-0.0.0.dev6 → provide_testkit-0.0.31}/src/provide/testkit/quality/decorators.py +0 -0
- {provide_testkit-0.0.0.dev6 → provide_testkit-0.0.31}/src/provide/testkit/quality/documentation/__init__.py +0 -0
- {provide_testkit-0.0.0.dev6 → provide_testkit-0.0.31}/src/provide/testkit/quality/documentation/checker.py +0 -0
- {provide_testkit-0.0.0.dev6 → provide_testkit-0.0.31}/src/provide/testkit/quality/documentation/fixture.py +0 -0
- {provide_testkit-0.0.0.dev6 → provide_testkit-0.0.31}/src/provide/testkit/quality/profiling/__init__.py +0 -0
- {provide_testkit-0.0.0.dev6 → provide_testkit-0.0.31}/src/provide/testkit/quality/profiling/fixture.py +0 -0
- {provide_testkit-0.0.0.dev6 → provide_testkit-0.0.31}/src/provide/testkit/quality/profiling/profiler.py +0 -0
- {provide_testkit-0.0.0.dev6 → provide_testkit-0.0.31}/src/provide/testkit/quality/report.py +0 -0
- {provide_testkit-0.0.0.dev6 → provide_testkit-0.0.31}/src/provide/testkit/quality/runner.py +0 -0
- {provide_testkit-0.0.0.dev6 → provide_testkit-0.0.31}/src/provide/testkit/quality/security/__init__.py +0 -0
- {provide_testkit-0.0.0.dev6 → provide_testkit-0.0.31}/src/provide/testkit/quality/security/fixture.py +0 -0
- {provide_testkit-0.0.0.dev6 → provide_testkit-0.0.31}/src/provide/testkit/quality/security/scanner.py +0 -0
- {provide_testkit-0.0.0.dev6 → provide_testkit-0.0.31}/src/provide/testkit/threading/__init__.py +0 -0
- {provide_testkit-0.0.0.dev6 → provide_testkit-0.0.31}/src/provide/testkit/threading/basic_fixtures.py +0 -0
- {provide_testkit-0.0.0.dev6 → provide_testkit-0.0.31}/src/provide/testkit/threading/data_fixtures.py +0 -0
- {provide_testkit-0.0.0.dev6 → provide_testkit-0.0.31}/src/provide/testkit/threading/execution_fixtures.py +0 -0
- {provide_testkit-0.0.0.dev6 → provide_testkit-0.0.31}/src/provide/testkit/threading/fixtures.py +0 -0
- {provide_testkit-0.0.0.dev6 → provide_testkit-0.0.31}/src/provide/testkit/threading/sync_fixtures.py +0 -0
- {provide_testkit-0.0.0.dev6 → provide_testkit-0.0.31}/src/provide/testkit/transport/__init__.py +0 -0
- {provide_testkit-0.0.0.dev6 → provide_testkit-0.0.31}/src/provide/testkit/transport/fixtures.py +0 -0
- {provide_testkit-0.0.0.dev6/src/provide/testkit → provide_testkit-0.0.31/src/provide/testkit/utils}/environment.py +0 -0
- {provide_testkit-0.0.0.dev6 → provide_testkit-0.0.31}/src/provide_testkit.egg-info/dependency_links.txt +0 -0
- {provide_testkit-0.0.0.dev6 → provide_testkit-0.0.31}/src/provide_testkit.egg-info/entry_points.txt +0 -0
- {provide_testkit-0.0.0.dev6 → provide_testkit-0.0.31}/src/provide_testkit.egg-info/top_level.txt +0 -0
- {provide_testkit-0.0.0.dev6 → provide_testkit-0.0.31}/tests/test_placeholder.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: provide-testkit
|
|
3
|
-
Version: 0.0.
|
|
3
|
+
Version: 0.0.31
|
|
4
4
|
Summary: Testing utilities and fixtures for the provide ecosystem.
|
|
5
5
|
Author-email: Tim Perkins <code@tim.life>
|
|
6
6
|
Maintainer-email: "provide.io" <code@provide.io>
|
|
@@ -50,6 +50,8 @@ Requires-Dist: types-grpcio>=1.0.0.20250603; extra == "typecheck"
|
|
|
50
50
|
Requires-Dist: types-toml>=0.10.8.20240310; extra == "typecheck"
|
|
51
51
|
Requires-Dist: types-protobuf>=6.30.2.20250516; extra == "typecheck"
|
|
52
52
|
Requires-Dist: types-click>=7.1.8; extra == "typecheck"
|
|
53
|
+
Requires-Dist: types-pyyaml>=6.0.12.20250915; extra == "typecheck"
|
|
54
|
+
Requires-Dist: types-psutil>=7.0.0.20250822; extra == "typecheck"
|
|
53
55
|
Provides-Extra: advanced-testing
|
|
54
56
|
Requires-Dist: hypothesis>=6.131.28; extra == "advanced-testing"
|
|
55
57
|
Requires-Dist: freezegun>=1.5.1; extra == "advanced-testing"
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
0.0.31
|
|
@@ -12,10 +12,10 @@ Note: Testing information is displayed via pytest hooks in conftest.py
|
|
|
12
12
|
|
|
13
13
|
from typing import Any
|
|
14
14
|
|
|
15
|
-
# Mapping of attribute names to their modules
|
|
15
|
+
# Mapping of attribute names to their modules for lazy loading.
|
|
16
16
|
_LAZY_IMPORTS = {
|
|
17
17
|
# CLI testing utilities
|
|
18
|
-
"cli": [
|
|
18
|
+
"cli.testing": [
|
|
19
19
|
"MockContext",
|
|
20
20
|
"isolated_cli_runner",
|
|
21
21
|
"temp_config_file",
|
|
@@ -23,6 +23,12 @@ _LAZY_IMPORTS = {
|
|
|
23
23
|
"CliTestCase",
|
|
24
24
|
"click_testing_mode",
|
|
25
25
|
],
|
|
26
|
+
# CLI runner utilities
|
|
27
|
+
"cli.runner": [
|
|
28
|
+
"CliTestRunner",
|
|
29
|
+
"assert_cli_success",
|
|
30
|
+
"assert_cli_error",
|
|
31
|
+
],
|
|
26
32
|
# Logger testing utilities
|
|
27
33
|
"logger": [
|
|
28
34
|
"reset_foundation_setup_for_testing",
|
|
@@ -36,11 +42,21 @@ _LAZY_IMPORTS = {
|
|
|
36
42
|
"suppress_loggers",
|
|
37
43
|
],
|
|
38
44
|
# Stream testing utilities
|
|
39
|
-
"streams": ["set_log_stream_for_testing"],
|
|
40
|
-
#
|
|
41
|
-
"fixtures": [
|
|
45
|
+
"streams.testing": ["set_log_stream_for_testing", "enable_file_logging_for_testing"],
|
|
46
|
+
# Common fixture utilities
|
|
47
|
+
"common.fixtures": [
|
|
42
48
|
"captured_stderr_for_foundation",
|
|
43
49
|
"setup_foundation_telemetry_for_test",
|
|
50
|
+
"mock_http_config",
|
|
51
|
+
"mock_telemetry_config",
|
|
52
|
+
"mock_config_source",
|
|
53
|
+
"mock_event_emitter",
|
|
54
|
+
"mock_transport",
|
|
55
|
+
"mock_metrics_collector",
|
|
56
|
+
"mock_cache",
|
|
57
|
+
"mock_database",
|
|
58
|
+
"mock_file_system",
|
|
59
|
+
"mock_subprocess",
|
|
44
60
|
],
|
|
45
61
|
# File testing utilities
|
|
46
62
|
"file.fixtures": [
|
|
@@ -63,20 +79,6 @@ _LAZY_IMPORTS = {
|
|
|
63
79
|
"async_iterator",
|
|
64
80
|
"async_queue",
|
|
65
81
|
"async_lock",
|
|
66
|
-
"mock_async_sleep",
|
|
67
|
-
],
|
|
68
|
-
# Common mock utilities
|
|
69
|
-
"common.fixtures": [
|
|
70
|
-
"mock_http_config",
|
|
71
|
-
"mock_telemetry_config",
|
|
72
|
-
"mock_config_source",
|
|
73
|
-
"mock_event_emitter",
|
|
74
|
-
"mock_transport",
|
|
75
|
-
"mock_metrics_collector",
|
|
76
|
-
"mock_cache",
|
|
77
|
-
"mock_database",
|
|
78
|
-
"mock_file_system",
|
|
79
|
-
"mock_subprocess",
|
|
80
82
|
],
|
|
81
83
|
# Transport/network testing utilities
|
|
82
84
|
"transport.fixtures": [
|
|
@@ -100,7 +102,7 @@ _LAZY_IMPORTS = {
|
|
|
100
102
|
"archive_stress_test_files",
|
|
101
103
|
],
|
|
102
104
|
# Crypto fixtures
|
|
103
|
-
"crypto": [
|
|
105
|
+
"crypto.fixtures": [
|
|
104
106
|
"client_cert",
|
|
105
107
|
"server_cert",
|
|
106
108
|
"ca_cert",
|
|
@@ -118,26 +120,95 @@ _LAZY_IMPORTS = {
|
|
|
118
120
|
"external_ca_pem",
|
|
119
121
|
],
|
|
120
122
|
# Hub fixtures
|
|
121
|
-
"hub": ["default_container_directory"],
|
|
123
|
+
"hub.fixtures": ["default_container_directory"],
|
|
122
124
|
# Environment utilities
|
|
123
|
-
"environment": [
|
|
125
|
+
"utils.environment": [
|
|
124
126
|
"TestEnvironment",
|
|
125
127
|
"get_example_dir",
|
|
126
128
|
"add_src_to_path",
|
|
127
129
|
"reset_test_environment",
|
|
128
130
|
],
|
|
131
|
+
# Temp environment utilities
|
|
132
|
+
"utils.temp_env": [
|
|
133
|
+
"temp_env",
|
|
134
|
+
"temp_env_from_dict",
|
|
135
|
+
"isolated_env",
|
|
136
|
+
"EnvContext",
|
|
137
|
+
],
|
|
138
|
+
# Base test classes
|
|
139
|
+
"base.foundation": [
|
|
140
|
+
"FoundationTestCase",
|
|
141
|
+
],
|
|
142
|
+
"base.minimal": [
|
|
143
|
+
"MinimalTestCase",
|
|
144
|
+
],
|
|
145
|
+
# Base harness utilities
|
|
146
|
+
"base.harness": [
|
|
147
|
+
"HarnessRunner",
|
|
148
|
+
],
|
|
149
|
+
# Mocking utilities
|
|
150
|
+
"mocking.fixtures": [
|
|
151
|
+
"ANY",
|
|
152
|
+
"AsyncMock",
|
|
153
|
+
"MagicMock",
|
|
154
|
+
"Mock",
|
|
155
|
+
"PropertyMock",
|
|
156
|
+
"assert_mock_calls",
|
|
157
|
+
"async_mock_factory",
|
|
158
|
+
"auto_patch",
|
|
159
|
+
"call",
|
|
160
|
+
"magic_mock_factory",
|
|
161
|
+
"mock_factory",
|
|
162
|
+
"mock_open_fixture",
|
|
163
|
+
"patch",
|
|
164
|
+
"patch_fixture",
|
|
165
|
+
"patch_multiple_fixture",
|
|
166
|
+
"property_mock_factory",
|
|
167
|
+
"spy_fixture",
|
|
168
|
+
],
|
|
169
|
+
# Time mocking utilities
|
|
170
|
+
"mocking.time": [
|
|
171
|
+
"SleepTracker",
|
|
172
|
+
"mock_sleep",
|
|
173
|
+
"mock_time_sleep",
|
|
174
|
+
"mock_asyncio_sleep",
|
|
175
|
+
"create_sleep_mock",
|
|
176
|
+
],
|
|
177
|
+
# Time fixture utilities
|
|
178
|
+
"time.fixtures": [
|
|
179
|
+
"time_machine",
|
|
180
|
+
"freeze_time",
|
|
181
|
+
"mock_datetime",
|
|
182
|
+
"timer",
|
|
183
|
+
"time_travel",
|
|
184
|
+
"rate_limiter_mock",
|
|
185
|
+
"benchmark_timer",
|
|
186
|
+
"advance_time",
|
|
187
|
+
],
|
|
188
|
+
# File temp utilities
|
|
189
|
+
"file.temp": [
|
|
190
|
+
"TempFileManager",
|
|
191
|
+
"create_temp_file",
|
|
192
|
+
"create_temp_dir",
|
|
193
|
+
],
|
|
129
194
|
}
|
|
130
195
|
|
|
131
196
|
# Submodules that can be imported directly
|
|
132
197
|
_DIRECT_SUBMODULES = [
|
|
133
198
|
"archive",
|
|
199
|
+
"base",
|
|
200
|
+
"cli",
|
|
134
201
|
"common",
|
|
202
|
+
"crypto",
|
|
135
203
|
"file",
|
|
136
|
-
"
|
|
137
|
-
"transport",
|
|
204
|
+
"hub",
|
|
138
205
|
"mocking",
|
|
139
|
-
"
|
|
206
|
+
"process",
|
|
207
|
+
"streams",
|
|
140
208
|
"threading",
|
|
209
|
+
"time",
|
|
210
|
+
"transport",
|
|
211
|
+
"utils",
|
|
141
212
|
]
|
|
142
213
|
|
|
143
214
|
|
|
@@ -174,43 +245,11 @@ def __getattr__(name: str) -> Any:
|
|
|
174
245
|
raise AttributeError(f"module '{__name__}' has no attribute '{name}'")
|
|
175
246
|
|
|
176
247
|
|
|
177
|
-
# Public API
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
"ca_cert",
|
|
186
|
-
"captured_stderr_for_foundation",
|
|
187
|
-
"cert_with_extra_whitespace",
|
|
188
|
-
"cert_with_utf8_bom",
|
|
189
|
-
"cert_with_windows_line_endings",
|
|
190
|
-
"client_cert",
|
|
191
|
-
"create_test_cli",
|
|
192
|
-
"default_container_directory",
|
|
193
|
-
"empty_cert",
|
|
194
|
-
"external_ca_pem",
|
|
195
|
-
"get_example_dir",
|
|
196
|
-
"get_log_level_for_noisy_loggers",
|
|
197
|
-
"get_noisy_loggers",
|
|
198
|
-
"invalid_cert_pem",
|
|
199
|
-
"invalid_key_pem",
|
|
200
|
-
"isolated_cli_runner",
|
|
201
|
-
"malformed_cert_pem",
|
|
202
|
-
"mock_logger",
|
|
203
|
-
"pytest_runtest_setup",
|
|
204
|
-
"reset_foundation_setup_for_testing",
|
|
205
|
-
"reset_foundation_state",
|
|
206
|
-
"reset_test_environment",
|
|
207
|
-
"server_cert",
|
|
208
|
-
"set_log_stream_for_testing",
|
|
209
|
-
"setup_foundation_telemetry_for_test",
|
|
210
|
-
"suppress_loggers",
|
|
211
|
-
"temp_config_file",
|
|
212
|
-
"temporary_cert_file",
|
|
213
|
-
"temporary_key_file",
|
|
214
|
-
"valid_cert_pem",
|
|
215
|
-
"valid_key_pem",
|
|
216
|
-
]
|
|
248
|
+
# --- Public API ---
|
|
249
|
+
# This list is dynamically generated to be comprehensive and stay in sync
|
|
250
|
+
# with the lazy loader, ensuring a complete and correct public API.
|
|
251
|
+
_all_lazy_attributes: list[str] = []
|
|
252
|
+
for _attributes in _LAZY_IMPORTS.values():
|
|
253
|
+
_all_lazy_attributes.extend(_attributes)
|
|
254
|
+
|
|
255
|
+
__all__ = sorted(list(set(_all_lazy_attributes)))
|
|
File without changes
|
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
"""
|
|
2
|
+
FoundationTestCase Base Class.
|
|
3
|
+
|
|
4
|
+
Provides a common base class for all Foundation-based tests with
|
|
5
|
+
standard utilities, automatic setup/cleanup, and common assertions.
|
|
6
|
+
"""
|
|
7
|
+
|
|
8
|
+
from __future__ import annotations
|
|
9
|
+
|
|
10
|
+
from provide.testkit.base.minimal import MinimalTestCase
|
|
11
|
+
from provide.testkit.logger import reset_foundation_setup_for_testing
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
class FoundationTestCase(MinimalTestCase):
|
|
15
|
+
"""Base test case for Foundation-based tests.
|
|
16
|
+
|
|
17
|
+
Provides common utilities for testing Foundation applications:
|
|
18
|
+
- Automatic Foundation reset between tests
|
|
19
|
+
- Temporary file/directory tracking and cleanup
|
|
20
|
+
- Mock tracking utilities
|
|
21
|
+
- Common assertion methods
|
|
22
|
+
- Output capture helpers
|
|
23
|
+
"""
|
|
24
|
+
|
|
25
|
+
def setup_method(self) -> None:
|
|
26
|
+
"""Set up test case with Foundation reset."""
|
|
27
|
+
# Check if this test/class is marked as timing_sensitive
|
|
28
|
+
if self._needs_full_reset():
|
|
29
|
+
reset_foundation_setup_for_testing()
|
|
30
|
+
else:
|
|
31
|
+
# For timing-sensitive tests, do minimal reset to prevent test interference
|
|
32
|
+
# but avoid full setup that could affect timing
|
|
33
|
+
self._minimal_state_reset()
|
|
34
|
+
|
|
35
|
+
# Always call parent setup for basic utilities
|
|
36
|
+
super().setup_method()
|
|
37
|
+
|
|
38
|
+
def _needs_full_reset(self) -> bool:
|
|
39
|
+
"""Check if this test needs full Foundation reset.
|
|
40
|
+
|
|
41
|
+
Returns False if test/class is marked with timing_sensitive marker.
|
|
42
|
+
"""
|
|
43
|
+
# Get the current test item from pytest's request fixture
|
|
44
|
+
# We need to be careful here as this runs during setup
|
|
45
|
+
try:
|
|
46
|
+
import inspect
|
|
47
|
+
|
|
48
|
+
# Get the test method
|
|
49
|
+
frame = inspect.currentframe()
|
|
50
|
+
while frame:
|
|
51
|
+
if frame.f_code.co_name.startswith("test_"):
|
|
52
|
+
test_method = getattr(self, frame.f_code.co_name, None)
|
|
53
|
+
if test_method and hasattr(test_method, "pytestmark"):
|
|
54
|
+
marks = getattr(test_method, "pytestmark", [])
|
|
55
|
+
for mark in marks:
|
|
56
|
+
if mark.name == "timing_sensitive":
|
|
57
|
+
return False
|
|
58
|
+
break
|
|
59
|
+
frame = frame.f_back
|
|
60
|
+
|
|
61
|
+
# Check class-level markers
|
|
62
|
+
if hasattr(self.__class__, "pytestmark"):
|
|
63
|
+
marks = getattr(self.__class__, "pytestmark", [])
|
|
64
|
+
for mark in marks:
|
|
65
|
+
if mark.name == "timing_sensitive":
|
|
66
|
+
return False
|
|
67
|
+
except Exception:
|
|
68
|
+
# If we can't determine, default to full reset for safety
|
|
69
|
+
pass
|
|
70
|
+
|
|
71
|
+
return True
|
|
72
|
+
|
|
73
|
+
def _minimal_state_reset(self) -> None:
|
|
74
|
+
"""Perform minimal state reset for timing-sensitive tests.
|
|
75
|
+
|
|
76
|
+
This resets only the most critical global state that can cause
|
|
77
|
+
test interference, while avoiding expensive operations that could
|
|
78
|
+
affect timing.
|
|
79
|
+
"""
|
|
80
|
+
try:
|
|
81
|
+
# Reset Hub state which includes component registry
|
|
82
|
+
from provide.foundation.testmode.internal import reset_hub_state
|
|
83
|
+
|
|
84
|
+
reset_hub_state()
|
|
85
|
+
except ImportError:
|
|
86
|
+
# Testmode module not available, skip
|
|
87
|
+
pass
|
|
88
|
+
|
|
89
|
+
|
|
90
|
+
__all__ = ["FoundationTestCase"]
|
|
@@ -0,0 +1,122 @@
|
|
|
1
|
+
"""
|
|
2
|
+
MinimalTestCase Base Class.
|
|
3
|
+
|
|
4
|
+
Provides a lightweight base class for tests that need common utilities
|
|
5
|
+
but don't require Foundation state reset. Ideal for timing-sensitive
|
|
6
|
+
tests or tests that don't use Foundation components.
|
|
7
|
+
"""
|
|
8
|
+
|
|
9
|
+
from __future__ import annotations
|
|
10
|
+
|
|
11
|
+
import json
|
|
12
|
+
from pathlib import Path
|
|
13
|
+
from typing import Any
|
|
14
|
+
from unittest.mock import Mock
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
class MinimalTestCase:
|
|
18
|
+
"""Minimal test case base class without Foundation reset overhead.
|
|
19
|
+
|
|
20
|
+
Provides common test utilities without the heavyweight Foundation reset:
|
|
21
|
+
- Temporary file/directory tracking and cleanup
|
|
22
|
+
- Mock tracking utilities
|
|
23
|
+
- Common assertion methods
|
|
24
|
+
- Output capture helpers
|
|
25
|
+
|
|
26
|
+
Use this for timing-sensitive tests or tests that don't need
|
|
27
|
+
Foundation state isolation.
|
|
28
|
+
"""
|
|
29
|
+
|
|
30
|
+
def setup_method(self) -> None:
|
|
31
|
+
"""Set up test case with minimal overhead."""
|
|
32
|
+
self._temp_files: list[Path] = []
|
|
33
|
+
self._mocks: list[Mock] = []
|
|
34
|
+
|
|
35
|
+
def teardown_method(self) -> None:
|
|
36
|
+
"""Clean up test case."""
|
|
37
|
+
# Clean up temporary files
|
|
38
|
+
for path in self._temp_files:
|
|
39
|
+
if path.exists():
|
|
40
|
+
if path.is_file():
|
|
41
|
+
path.unlink()
|
|
42
|
+
elif path.is_dir():
|
|
43
|
+
import shutil
|
|
44
|
+
|
|
45
|
+
shutil.rmtree(path)
|
|
46
|
+
|
|
47
|
+
# Reset mocks
|
|
48
|
+
for mock in self._mocks:
|
|
49
|
+
mock.reset_mock()
|
|
50
|
+
|
|
51
|
+
def create_temp_file(self, content: str = "", suffix: str = "") -> Path:
|
|
52
|
+
"""Create a temporary file that will be cleaned up."""
|
|
53
|
+
from provide.foundation.file import temp_file
|
|
54
|
+
|
|
55
|
+
with temp_file(suffix=suffix, text=True, cleanup=False) as path:
|
|
56
|
+
if content:
|
|
57
|
+
path.write_text(content)
|
|
58
|
+
self._temp_files.append(path)
|
|
59
|
+
return path
|
|
60
|
+
|
|
61
|
+
def create_temp_dir(self) -> Path:
|
|
62
|
+
"""Create a temporary directory that will be cleaned up."""
|
|
63
|
+
import tempfile
|
|
64
|
+
|
|
65
|
+
temp_dir = Path(tempfile.mkdtemp())
|
|
66
|
+
self._temp_files.append(temp_dir)
|
|
67
|
+
return temp_dir
|
|
68
|
+
|
|
69
|
+
def track_mock(self, mock: Mock) -> Mock:
|
|
70
|
+
"""Track a mock for automatic reset during teardown."""
|
|
71
|
+
self._mocks.append(mock)
|
|
72
|
+
return mock
|
|
73
|
+
|
|
74
|
+
def assert_json_output(self, output: str, expected: dict[str, Any]) -> None:
|
|
75
|
+
"""Assert that output is valid JSON matching expected values."""
|
|
76
|
+
try:
|
|
77
|
+
actual = json.loads(output)
|
|
78
|
+
except json.JSONDecodeError as e:
|
|
79
|
+
raise AssertionError(f"Output is not valid JSON: {e}\n{output}") from e
|
|
80
|
+
|
|
81
|
+
for key, value in expected.items():
|
|
82
|
+
assert key in actual, f"Key '{key}' not in output"
|
|
83
|
+
assert actual[key] == value, f"Value mismatch for '{key}': {actual[key]} != {value}"
|
|
84
|
+
|
|
85
|
+
def assert_contains_error(
|
|
86
|
+
self, output: str, error_type: type[Exception], message: str | None = None
|
|
87
|
+
) -> None:
|
|
88
|
+
"""Assert that output contains an error of the specified type."""
|
|
89
|
+
error_name = error_type.__name__
|
|
90
|
+
assert error_name in output, f"Error type '{error_name}' not found in output: {output}"
|
|
91
|
+
|
|
92
|
+
if message:
|
|
93
|
+
assert message in output, f"Error message '{message}' not found in output: {output}"
|
|
94
|
+
|
|
95
|
+
def assert_log_contains(self, captured_logs: str, level: str, message: str) -> None:
|
|
96
|
+
"""Assert that captured logs contain a message at the specified level."""
|
|
97
|
+
log_line = f"[{level.lower()}]"
|
|
98
|
+
assert log_line in captured_logs, f"Log level '{level}' not found in logs"
|
|
99
|
+
assert message in captured_logs, f"Log message '{message}' not found in logs"
|
|
100
|
+
|
|
101
|
+
def assert_file_exists(self, path: str | Path) -> None:
|
|
102
|
+
"""Assert that a file exists."""
|
|
103
|
+
file_path = Path(path)
|
|
104
|
+
assert file_path.exists(), f"File does not exist: {file_path}"
|
|
105
|
+
assert file_path.is_file(), f"Path exists but is not a file: {file_path}"
|
|
106
|
+
|
|
107
|
+
def assert_dir_exists(self, path: str | Path) -> None:
|
|
108
|
+
"""Assert that a directory exists."""
|
|
109
|
+
dir_path = Path(path)
|
|
110
|
+
assert dir_path.exists(), f"Directory does not exist: {dir_path}"
|
|
111
|
+
assert dir_path.is_dir(), f"Path exists but is not a directory: {dir_path}"
|
|
112
|
+
|
|
113
|
+
def assert_output_contains(self, output: str, expected: str) -> None:
|
|
114
|
+
"""Assert that output contains expected string."""
|
|
115
|
+
assert expected in output, f"Expected '{expected}' not found in output: {output}"
|
|
116
|
+
|
|
117
|
+
def assert_output_not_contains(self, output: str, unexpected: str) -> None:
|
|
118
|
+
"""Assert that output does not contain unexpected string."""
|
|
119
|
+
assert unexpected not in output, f"Unexpected '{unexpected}' found in output: {output}"
|
|
120
|
+
|
|
121
|
+
|
|
122
|
+
__all__ = ["MinimalTestCase"]
|
|
@@ -0,0 +1,103 @@
|
|
|
1
|
+
"""Chaos testing utilities for property-based testing with Hypothesis.
|
|
2
|
+
|
|
3
|
+
This module provides reusable Hypothesis strategies and fixtures for chaos engineering
|
|
4
|
+
in tests. It enables systematic exploration of edge cases, race conditions, and failure
|
|
5
|
+
scenarios that are difficult to test with traditional methods.
|
|
6
|
+
|
|
7
|
+
Key Features:
|
|
8
|
+
- Property-based testing strategies for common chaos patterns
|
|
9
|
+
- Time manipulation and clock skew simulation
|
|
10
|
+
- Concurrency and race condition triggers
|
|
11
|
+
- I/O failure injection patterns
|
|
12
|
+
- Reusable pytest fixtures for chaos testing
|
|
13
|
+
|
|
14
|
+
Example:
|
|
15
|
+
```python
|
|
16
|
+
from hypothesis import given
|
|
17
|
+
from provide.testkit.chaos import chaos_timings, failure_patterns
|
|
18
|
+
|
|
19
|
+
@given(
|
|
20
|
+
timing=chaos_timings(),
|
|
21
|
+
failures=failure_patterns()
|
|
22
|
+
)
|
|
23
|
+
async def test_with_chaos(timing, failures):
|
|
24
|
+
# Your chaos test here
|
|
25
|
+
pass
|
|
26
|
+
```
|
|
27
|
+
"""
|
|
28
|
+
|
|
29
|
+
from __future__ import annotations
|
|
30
|
+
|
|
31
|
+
from provide.testkit.chaos.concurrency_strategies import (
|
|
32
|
+
async_event_patterns,
|
|
33
|
+
deadlock_scenarios,
|
|
34
|
+
lock_contention_patterns,
|
|
35
|
+
pid_recycling_scenarios,
|
|
36
|
+
process_pool_patterns,
|
|
37
|
+
race_condition_triggers,
|
|
38
|
+
task_cancellation_patterns,
|
|
39
|
+
thread_counts,
|
|
40
|
+
)
|
|
41
|
+
from provide.testkit.chaos.io_strategies import (
|
|
42
|
+
buffer_overflow_patterns,
|
|
43
|
+
disk_full_scenarios,
|
|
44
|
+
file_corruption_patterns,
|
|
45
|
+
file_sizes,
|
|
46
|
+
lock_file_scenarios,
|
|
47
|
+
network_error_patterns,
|
|
48
|
+
path_traversal_patterns,
|
|
49
|
+
permission_patterns,
|
|
50
|
+
)
|
|
51
|
+
from provide.testkit.chaos.strategies import (
|
|
52
|
+
chaos_timings,
|
|
53
|
+
edge_values,
|
|
54
|
+
failure_patterns,
|
|
55
|
+
malformed_inputs,
|
|
56
|
+
resource_limits,
|
|
57
|
+
unicode_chaos,
|
|
58
|
+
)
|
|
59
|
+
from provide.testkit.chaos.time_strategies import (
|
|
60
|
+
clock_skew,
|
|
61
|
+
deadline_scenarios,
|
|
62
|
+
jitter_patterns,
|
|
63
|
+
rate_burst_patterns,
|
|
64
|
+
retry_backoff_patterns,
|
|
65
|
+
time_advances,
|
|
66
|
+
timeout_patterns,
|
|
67
|
+
)
|
|
68
|
+
|
|
69
|
+
__all__ = [
|
|
70
|
+
# Concurrency strategies
|
|
71
|
+
"async_event_patterns",
|
|
72
|
+
# I/O strategies
|
|
73
|
+
"buffer_overflow_patterns",
|
|
74
|
+
# Core strategies
|
|
75
|
+
"chaos_timings",
|
|
76
|
+
# Time strategies
|
|
77
|
+
"clock_skew",
|
|
78
|
+
"deadline_scenarios",
|
|
79
|
+
"deadlock_scenarios",
|
|
80
|
+
"disk_full_scenarios",
|
|
81
|
+
"edge_values",
|
|
82
|
+
"failure_patterns",
|
|
83
|
+
"file_corruption_patterns",
|
|
84
|
+
"file_sizes",
|
|
85
|
+
"jitter_patterns",
|
|
86
|
+
"lock_contention_patterns",
|
|
87
|
+
"lock_file_scenarios",
|
|
88
|
+
"malformed_inputs",
|
|
89
|
+
"network_error_patterns",
|
|
90
|
+
"path_traversal_patterns",
|
|
91
|
+
"permission_patterns",
|
|
92
|
+
"pid_recycling_scenarios",
|
|
93
|
+
"process_pool_patterns",
|
|
94
|
+
"race_condition_triggers",
|
|
95
|
+
"rate_burst_patterns",
|
|
96
|
+
"resource_limits",
|
|
97
|
+
"retry_backoff_patterns",
|
|
98
|
+
"task_cancellation_patterns",
|
|
99
|
+
"thread_counts",
|
|
100
|
+
"time_advances",
|
|
101
|
+
"timeout_patterns",
|
|
102
|
+
"unicode_chaos",
|
|
103
|
+
]
|