provide-foundation 0.0.0.dev2__py3-none-any.whl → 0.0.0.dev3__py3-none-any.whl
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/foundation/__init__.py +20 -20
- provide/foundation/archive/__init__.py +1 -1
- provide/foundation/archive/base.py +15 -14
- provide/foundation/archive/bzip2.py +40 -40
- provide/foundation/archive/gzip.py +42 -42
- provide/foundation/archive/operations.py +90 -91
- provide/foundation/archive/tar.py +33 -31
- provide/foundation/archive/zip.py +52 -50
- provide/foundation/asynctools/__init__.py +20 -0
- provide/foundation/asynctools/core.py +126 -0
- provide/foundation/cli/__init__.py +2 -2
- provide/foundation/cli/commands/deps.py +4 -4
- provide/foundation/cli/commands/logs/__init__.py +2 -2
- provide/foundation/cli/commands/logs/generate.py +2 -2
- provide/foundation/cli/commands/logs/query.py +3 -3
- provide/foundation/cli/commands/logs/send.py +2 -2
- provide/foundation/cli/commands/logs/tail.py +2 -2
- provide/foundation/cli/decorators.py +0 -1
- provide/foundation/cli/testing.py +0 -5
- provide/foundation/cli/utils.py +1 -2
- provide/foundation/config/__init__.py +19 -19
- provide/foundation/config/base.py +2 -2
- provide/foundation/config/converters.py +81 -83
- provide/foundation/config/defaults.py +1 -1
- provide/foundation/config/env.py +2 -1
- provide/foundation/config/loader.py +1 -1
- provide/foundation/config/sync.py +8 -6
- provide/foundation/config/types.py +5 -5
- provide/foundation/config/validators.py +4 -4
- provide/foundation/console/output.py +7 -7
- provide/foundation/context/core.py +19 -17
- provide/foundation/crypto/certificates/__init__.py +9 -5
- provide/foundation/crypto/certificates/base.py +2 -2
- provide/foundation/crypto/certificates/certificate.py +48 -19
- provide/foundation/crypto/certificates/factory.py +26 -18
- provide/foundation/crypto/certificates/generator.py +24 -23
- provide/foundation/crypto/certificates/loader.py +24 -16
- provide/foundation/crypto/certificates/operations.py +17 -10
- provide/foundation/crypto/certificates/trust.py +21 -21
- provide/foundation/env/__init__.py +28 -0
- provide/foundation/env/core.py +218 -0
- provide/foundation/errors/__init__.py +3 -2
- provide/foundation/errors/decorators.py +0 -3
- provide/foundation/errors/types.py +0 -1
- provide/foundation/eventsets/display.py +13 -14
- provide/foundation/eventsets/registry.py +61 -31
- provide/foundation/eventsets/resolver.py +50 -46
- provide/foundation/eventsets/sets/das.py +8 -8
- provide/foundation/eventsets/sets/database.py +14 -14
- provide/foundation/eventsets/sets/http.py +21 -21
- provide/foundation/eventsets/sets/llm.py +16 -16
- provide/foundation/eventsets/sets/task_queue.py +13 -13
- provide/foundation/eventsets/types.py +7 -7
- provide/foundation/file/directory.py +1 -1
- provide/foundation/file/lock.py +2 -3
- provide/foundation/hub/components.py +19 -21
- provide/foundation/hub/config.py +25 -19
- provide/foundation/hub/discovery.py +5 -4
- provide/foundation/hub/handlers.py +13 -5
- provide/foundation/hub/lifecycle.py +10 -9
- provide/foundation/hub/manager.py +3 -0
- provide/foundation/hub/processors.py +8 -3
- provide/foundation/integrations/__init__.py +1 -1
- provide/foundation/integrations/openobserve/client.py +2 -2
- provide/foundation/integrations/openobserve/commands.py +9 -9
- provide/foundation/integrations/openobserve/config.py +2 -2
- provide/foundation/integrations/openobserve/otlp.py +2 -2
- provide/foundation/integrations/openobserve/search.py +1 -2
- provide/foundation/integrations/openobserve/streaming.py +1 -1
- provide/foundation/logger/__init__.py +0 -1
- provide/foundation/logger/config/base.py +1 -1
- provide/foundation/logger/config/logging.py +19 -19
- provide/foundation/logger/config/telemetry.py +11 -13
- provide/foundation/logger/factories.py +2 -2
- provide/foundation/logger/processors/main.py +12 -10
- provide/foundation/logger/ratelimit/limiters.py +4 -4
- provide/foundation/logger/ratelimit/processor.py +1 -1
- provide/foundation/logger/setup/coordinator.py +38 -24
- provide/foundation/logger/setup/processors.py +3 -3
- provide/foundation/logger/setup/testing.py +14 -0
- provide/foundation/logger/trace.py +5 -5
- provide/foundation/metrics/__init__.py +1 -1
- provide/foundation/metrics/otel.py +3 -1
- provide/foundation/observability/__init__.py +1 -1
- provide/foundation/process/__init__.py +1 -1
- provide/foundation/process/exit.py +6 -5
- provide/foundation/process/lifecycle.py +41 -18
- provide/foundation/resilience/__init__.py +6 -5
- provide/foundation/resilience/circuit.py +32 -30
- provide/foundation/resilience/decorators.py +58 -42
- provide/foundation/resilience/fallback.py +55 -40
- provide/foundation/resilience/retry.py +67 -65
- provide/foundation/serialization/__init__.py +16 -0
- provide/foundation/serialization/core.py +70 -0
- provide/foundation/streams/config.py +8 -9
- provide/foundation/streams/console.py +3 -3
- provide/foundation/streams/core.py +2 -2
- provide/foundation/streams/file.py +1 -1
- provide/foundation/testing/__init__.py +22 -7
- provide/foundation/testing/archive/__init__.py +7 -7
- provide/foundation/testing/archive/fixtures.py +58 -54
- provide/foundation/testing/cli.py +3 -6
- provide/foundation/testing/common/__init__.py +13 -13
- provide/foundation/testing/common/fixtures.py +27 -30
- provide/foundation/testing/file/__init__.py +15 -15
- provide/foundation/testing/file/content_fixtures.py +65 -92
- provide/foundation/testing/file/directory_fixtures.py +19 -19
- provide/foundation/testing/file/fixtures.py +14 -17
- provide/foundation/testing/file/special_fixtures.py +34 -42
- provide/foundation/testing/logger.py +28 -23
- provide/foundation/testing/mocking/__init__.py +21 -21
- provide/foundation/testing/mocking/fixtures.py +80 -67
- provide/foundation/testing/process/__init__.py +23 -23
- provide/foundation/testing/process/async_fixtures.py +89 -80
- provide/foundation/testing/process/fixtures.py +11 -13
- provide/foundation/testing/process/subprocess_fixtures.py +41 -40
- provide/foundation/testing/threading/__init__.py +17 -17
- provide/foundation/testing/threading/basic_fixtures.py +21 -17
- provide/foundation/testing/threading/data_fixtures.py +18 -16
- provide/foundation/testing/threading/execution_fixtures.py +67 -52
- provide/foundation/testing/threading/fixtures.py +10 -14
- provide/foundation/testing/threading/sync_fixtures.py +21 -18
- provide/foundation/testing/time/__init__.py +11 -11
- provide/foundation/testing/time/fixtures.py +91 -79
- provide/foundation/testing/transport/__init__.py +9 -9
- provide/foundation/testing/transport/fixtures.py +54 -54
- provide/foundation/time/__init__.py +18 -0
- provide/foundation/time/core.py +63 -0
- provide/foundation/tools/__init__.py +2 -2
- provide/foundation/tools/base.py +68 -67
- provide/foundation/tools/cache.py +62 -69
- provide/foundation/tools/downloader.py +51 -56
- provide/foundation/tools/installer.py +51 -57
- provide/foundation/tools/registry.py +38 -45
- provide/foundation/tools/resolver.py +70 -68
- provide/foundation/tools/verifier.py +39 -50
- provide/foundation/tracer/spans.py +1 -13
- provide/foundation/transport/__init__.py +26 -33
- provide/foundation/transport/base.py +32 -30
- provide/foundation/transport/client.py +44 -49
- provide/foundation/transport/config.py +11 -13
- provide/foundation/transport/errors.py +13 -27
- provide/foundation/transport/http.py +69 -55
- provide/foundation/transport/middleware.py +86 -81
- provide/foundation/transport/registry.py +29 -27
- provide/foundation/transport/types.py +6 -6
- provide/foundation/utils/deps.py +3 -2
- provide/foundation/utils/parsing.py +7 -7
- {provide_foundation-0.0.0.dev2.dist-info → provide_foundation-0.0.0.dev3.dist-info}/METADATA +2 -2
- provide_foundation-0.0.0.dev3.dist-info/RECORD +233 -0
- provide_foundation-0.0.0.dev2.dist-info/RECORD +0 -225
- {provide_foundation-0.0.0.dev2.dist-info → provide_foundation-0.0.0.dev3.dist-info}/WHEEL +0 -0
- {provide_foundation-0.0.0.dev2.dist-info → provide_foundation-0.0.0.dev3.dist-info}/entry_points.txt +0 -0
- {provide_foundation-0.0.0.dev2.dist-info → provide_foundation-0.0.0.dev3.dist-info}/licenses/LICENSE +0 -0
- {provide_foundation-0.0.0.dev2.dist-info → provide_foundation-0.0.0.dev3.dist-info}/top_level.txt +0 -0
@@ -5,8 +5,8 @@ Fixtures specific to testing archive operations like tar, zip, gzip, bzip2.
|
|
5
5
|
Builds on top of file fixtures for archive-specific test scenarios.
|
6
6
|
"""
|
7
7
|
|
8
|
-
from pathlib import Path
|
9
8
|
from collections.abc import Generator
|
9
|
+
from pathlib import Path
|
10
10
|
|
11
11
|
import pytest
|
12
12
|
|
@@ -17,10 +17,10 @@ from provide.foundation.testing.file.fixtures import temp_directory
|
|
17
17
|
def archive_test_content() -> Generator[tuple[Path, dict[str, str]], None, None]:
|
18
18
|
"""
|
19
19
|
Create a standard set of files for archive testing.
|
20
|
-
|
20
|
+
|
21
21
|
Creates multiple files with different types of content to ensure
|
22
22
|
proper compression and extraction testing.
|
23
|
-
|
23
|
+
|
24
24
|
Yields:
|
25
25
|
Tuple of (source_dir, content_map) where content_map maps
|
26
26
|
relative paths to their expected content.
|
@@ -28,26 +28,28 @@ def archive_test_content() -> Generator[tuple[Path, dict[str, str]], None, None]
|
|
28
28
|
with temp_directory() as temp_dir:
|
29
29
|
source = temp_dir / "archive_source"
|
30
30
|
source.mkdir()
|
31
|
-
|
31
|
+
|
32
32
|
content_map = {
|
33
33
|
"text_file.txt": "This is a text file for archive testing.\n" * 10,
|
34
34
|
"data.json": '{"test": "data", "array": [1, 2, 3]}',
|
35
35
|
"script.py": "#!/usr/bin/env python\nprint('Hello from archive')\n",
|
36
36
|
"nested/dir/file.md": "# Nested File\nContent in nested directory",
|
37
|
-
"binary.dat": "Binary\x00\x01\x02\x03\
|
37
|
+
"binary.dat": "Binary\x00\x01\x02\x03\xff\xfe data",
|
38
38
|
"empty.txt": "",
|
39
39
|
}
|
40
|
-
|
40
|
+
|
41
41
|
# Create all files
|
42
42
|
for rel_path, content in content_map.items():
|
43
43
|
file_path = source / rel_path
|
44
44
|
file_path.parent.mkdir(parents=True, exist_ok=True)
|
45
|
-
|
45
|
+
|
46
46
|
if isinstance(content, str):
|
47
47
|
file_path.write_text(content)
|
48
48
|
else:
|
49
|
-
file_path.write_bytes(
|
50
|
-
|
49
|
+
file_path.write_bytes(
|
50
|
+
content.encode() if isinstance(content, str) else content
|
51
|
+
)
|
52
|
+
|
51
53
|
yield source, content_map
|
52
54
|
|
53
55
|
|
@@ -55,19 +57,19 @@ def archive_test_content() -> Generator[tuple[Path, dict[str, str]], None, None]
|
|
55
57
|
def large_file_for_compression() -> Generator[Path, None, None]:
|
56
58
|
"""
|
57
59
|
Create a large file suitable for compression testing.
|
58
|
-
|
60
|
+
|
59
61
|
The file contains repetitive content that compresses well.
|
60
|
-
|
62
|
+
|
61
63
|
Yields:
|
62
64
|
Path to a large file with compressible content.
|
63
65
|
"""
|
64
66
|
with temp_directory() as temp_dir:
|
65
67
|
large_file = temp_dir / "large_compressible.txt"
|
66
|
-
|
68
|
+
|
67
69
|
# Create 10MB of highly compressible content
|
68
70
|
content = "This is a line of text that will be repeated many times.\n" * 100
|
69
71
|
large_content = content * 1000 # ~6MB of repetitive text
|
70
|
-
|
72
|
+
|
71
73
|
large_file.write_text(large_content)
|
72
74
|
yield large_file
|
73
75
|
|
@@ -76,46 +78,48 @@ def large_file_for_compression() -> Generator[Path, None, None]:
|
|
76
78
|
def multi_format_archives() -> Generator[dict[str, Path], None, None]:
|
77
79
|
"""
|
78
80
|
Create sample archives in different formats for format detection testing.
|
79
|
-
|
81
|
+
|
80
82
|
Yields:
|
81
83
|
Dict mapping format names to paths of sample archives.
|
82
84
|
"""
|
83
85
|
with temp_directory() as temp_dir:
|
84
86
|
archives = {}
|
85
|
-
|
87
|
+
|
86
88
|
# Create minimal valid archives in different formats
|
87
89
|
# Note: These are minimal headers, not full valid archives
|
88
|
-
|
90
|
+
|
89
91
|
# GZIP file (magic: 1f 8b)
|
90
92
|
gzip_file = temp_dir / "sample.gz"
|
91
|
-
gzip_file.write_bytes(
|
93
|
+
gzip_file.write_bytes(
|
94
|
+
b"\x1f\x8b\x08\x00\x00\x00\x00\x00\x00\x03" + b"compressed data"
|
95
|
+
)
|
92
96
|
archives["gzip"] = gzip_file
|
93
|
-
|
97
|
+
|
94
98
|
# BZIP2 file (magic: BZh)
|
95
99
|
bzip2_file = temp_dir / "sample.bz2"
|
96
|
-
bzip2_file.write_bytes(b
|
100
|
+
bzip2_file.write_bytes(b"BZh91AY&SY" + b"compressed data")
|
97
101
|
archives["bzip2"] = bzip2_file
|
98
|
-
|
102
|
+
|
99
103
|
# ZIP file (magic: PK\x03\x04)
|
100
104
|
zip_file = temp_dir / "sample.zip"
|
101
|
-
zip_file.write_bytes(b
|
105
|
+
zip_file.write_bytes(b"PK\x03\x04" + b"\x00" * 16 + b"zipfile")
|
102
106
|
archives["zip"] = zip_file
|
103
|
-
|
107
|
+
|
104
108
|
# TAR file (has specific header structure)
|
105
109
|
tar_file = temp_dir / "sample.tar"
|
106
110
|
# Minimal tar header (512 bytes)
|
107
|
-
tar_header = b
|
108
|
-
tar_header += b
|
109
|
-
tar_header += b
|
110
|
-
tar_header += b
|
111
|
-
tar_header += b
|
112
|
-
tar_header += b
|
113
|
-
tar_header += b
|
114
|
-
tar_header += b
|
115
|
-
tar_header += b
|
111
|
+
tar_header = b"testfile.txt" + b"\x00" * 88 # name
|
112
|
+
tar_header += b"0000644\x00" # mode
|
113
|
+
tar_header += b"0000000\x00" # uid
|
114
|
+
tar_header += b"0000000\x00" # gid
|
115
|
+
tar_header += b"00000000000\x00" # size
|
116
|
+
tar_header += b"00000000000\x00" # mtime
|
117
|
+
tar_header += b" " # checksum placeholder
|
118
|
+
tar_header += b"0" # typeflag
|
119
|
+
tar_header += b"\x00" * 355 # padding to 512 bytes
|
116
120
|
tar_file.write_bytes(tar_header[:512])
|
117
121
|
archives["tar"] = tar_file
|
118
|
-
|
122
|
+
|
119
123
|
yield archives
|
120
124
|
|
121
125
|
|
@@ -123,34 +127,34 @@ def multi_format_archives() -> Generator[dict[str, Path], None, None]:
|
|
123
127
|
def archive_with_permissions() -> Generator[Path, None, None]:
|
124
128
|
"""
|
125
129
|
Create files with specific permissions for archive permission testing.
|
126
|
-
|
130
|
+
|
127
131
|
Yields:
|
128
132
|
Path to directory containing files with various permission modes.
|
129
133
|
"""
|
130
134
|
with temp_directory() as temp_dir:
|
131
135
|
source = temp_dir / "permissions_test"
|
132
136
|
source.mkdir()
|
133
|
-
|
137
|
+
|
134
138
|
# Regular file
|
135
139
|
regular = source / "regular.txt"
|
136
140
|
regular.write_text("Regular file")
|
137
141
|
regular.chmod(0o644)
|
138
|
-
|
142
|
+
|
139
143
|
# Executable file
|
140
144
|
executable = source / "script.sh"
|
141
145
|
executable.write_text("#!/bin/bash\necho 'Hello'")
|
142
146
|
executable.chmod(0o755)
|
143
|
-
|
147
|
+
|
144
148
|
# Read-only file
|
145
149
|
readonly = source / "readonly.txt"
|
146
150
|
readonly.write_text("Read only content")
|
147
151
|
readonly.chmod(0o444)
|
148
|
-
|
152
|
+
|
149
153
|
# Directory with specific permissions
|
150
154
|
special_dir = source / "special"
|
151
155
|
special_dir.mkdir()
|
152
156
|
special_dir.chmod(0o700)
|
153
|
-
|
157
|
+
|
154
158
|
yield source
|
155
159
|
|
156
160
|
|
@@ -158,33 +162,33 @@ def archive_with_permissions() -> Generator[Path, None, None]:
|
|
158
162
|
def corrupted_archives() -> Generator[dict[str, Path], None, None]:
|
159
163
|
"""
|
160
164
|
Create corrupted archive files for error handling testing.
|
161
|
-
|
165
|
+
|
162
166
|
Yields:
|
163
167
|
Dict mapping format names to paths of corrupted archives.
|
164
168
|
"""
|
165
169
|
with temp_directory() as temp_dir:
|
166
170
|
corrupted = {}
|
167
|
-
|
171
|
+
|
168
172
|
# Corrupted GZIP (invalid header)
|
169
173
|
bad_gzip = temp_dir / "corrupted.gz"
|
170
|
-
bad_gzip.write_bytes(b
|
174
|
+
bad_gzip.write_bytes(b"\x1f\x8c" + b"not really gzip data")
|
171
175
|
corrupted["gzip"] = bad_gzip
|
172
|
-
|
176
|
+
|
173
177
|
# Corrupted ZIP (incomplete header)
|
174
178
|
bad_zip = temp_dir / "corrupted.zip"
|
175
|
-
bad_zip.write_bytes(b
|
179
|
+
bad_zip.write_bytes(b"PK\x03") # Incomplete magic
|
176
180
|
corrupted["zip"] = bad_zip
|
177
|
-
|
181
|
+
|
178
182
|
# Corrupted BZIP2 (wrong magic)
|
179
183
|
bad_bzip2 = temp_dir / "corrupted.bz2"
|
180
|
-
bad_bzip2.write_bytes(b
|
184
|
+
bad_bzip2.write_bytes(b"BZX" + b"not bzip2")
|
181
185
|
corrupted["bzip2"] = bad_bzip2
|
182
|
-
|
186
|
+
|
183
187
|
# Empty file claiming to be archive
|
184
188
|
empty_archive = temp_dir / "empty.tar.gz"
|
185
|
-
empty_archive.write_bytes(b
|
189
|
+
empty_archive.write_bytes(b"")
|
186
190
|
corrupted["empty"] = empty_archive
|
187
|
-
|
191
|
+
|
188
192
|
yield corrupted
|
189
193
|
|
190
194
|
|
@@ -192,26 +196,26 @@ def corrupted_archives() -> Generator[dict[str, Path], None, None]:
|
|
192
196
|
def archive_stress_test_files() -> Generator[Path, None, None]:
|
193
197
|
"""
|
194
198
|
Create a large number of files for stress testing archive operations.
|
195
|
-
|
199
|
+
|
196
200
|
Yields:
|
197
201
|
Path to directory with many files for stress testing.
|
198
202
|
"""
|
199
203
|
with temp_directory() as temp_dir:
|
200
204
|
stress_dir = temp_dir / "stress_test"
|
201
205
|
stress_dir.mkdir()
|
202
|
-
|
206
|
+
|
203
207
|
# Create 100 files in various subdirectories
|
204
208
|
for i in range(10):
|
205
209
|
subdir = stress_dir / f"subdir_{i}"
|
206
210
|
subdir.mkdir()
|
207
|
-
|
211
|
+
|
208
212
|
for j in range(10):
|
209
213
|
file_path = subdir / f"file_{j}.txt"
|
210
214
|
file_path.write_text(f"Content of file {i}_{j}\n" * 10)
|
211
|
-
|
215
|
+
|
212
216
|
# Add some binary files
|
213
217
|
for i in range(5):
|
214
218
|
bin_file = stress_dir / f"binary_{i}.dat"
|
215
219
|
bin_file.write_bytes(bytes(range(256)) * 10)
|
216
|
-
|
217
|
-
yield stress_dir
|
220
|
+
|
221
|
+
yield stress_dir
|
@@ -11,7 +11,6 @@ import os
|
|
11
11
|
from pathlib import Path
|
12
12
|
import tempfile
|
13
13
|
from typing import Any
|
14
|
-
from unittest.mock import MagicMock
|
15
14
|
|
16
15
|
import click
|
17
16
|
from click.testing import CliRunner
|
@@ -167,8 +166,6 @@ def create_test_cli(
|
|
167
166
|
return cli
|
168
167
|
|
169
168
|
|
170
|
-
|
171
|
-
|
172
169
|
class CliTestCase:
|
173
170
|
"""Base class for CLI test cases with common utilities."""
|
174
171
|
|
@@ -218,11 +215,11 @@ class CliTestCase:
|
|
218
215
|
def click_testing_mode():
|
219
216
|
"""
|
220
217
|
Pytest fixture to enable Click testing mode.
|
221
|
-
|
218
|
+
|
222
219
|
Sets CLICK_TESTING=1 environment variable for the duration of the test,
|
223
220
|
then restores the original value. This fixture makes it easy to enable
|
224
221
|
Click testing mode without manual environment variable management.
|
225
|
-
|
222
|
+
|
226
223
|
Usage:
|
227
224
|
def test_my_cli(click_testing_mode):
|
228
225
|
# Test CLI code here - CLICK_TESTING is automatically set
|
@@ -230,7 +227,7 @@ def click_testing_mode():
|
|
230
227
|
"""
|
231
228
|
original_value = os.environ.get("CLICK_TESTING")
|
232
229
|
os.environ["CLICK_TESTING"] = "1"
|
233
|
-
|
230
|
+
|
234
231
|
try:
|
235
232
|
yield
|
236
233
|
finally:
|
@@ -6,27 +6,27 @@ in any project that depends on provide.foundation.
|
|
6
6
|
"""
|
7
7
|
|
8
8
|
from provide.foundation.testing.common.fixtures import (
|
9
|
-
mock_http_config,
|
10
|
-
mock_telemetry_config,
|
11
|
-
mock_config_source,
|
12
|
-
mock_event_emitter,
|
13
|
-
mock_transport,
|
14
|
-
mock_metrics_collector,
|
15
9
|
mock_cache,
|
10
|
+
mock_config_source,
|
16
11
|
mock_database,
|
12
|
+
mock_event_emitter,
|
17
13
|
mock_file_system,
|
14
|
+
mock_http_config,
|
15
|
+
mock_metrics_collector,
|
18
16
|
mock_subprocess,
|
17
|
+
mock_telemetry_config,
|
18
|
+
mock_transport,
|
19
19
|
)
|
20
20
|
|
21
21
|
__all__ = [
|
22
|
-
"mock_http_config",
|
23
|
-
"mock_telemetry_config",
|
24
|
-
"mock_config_source",
|
25
|
-
"mock_event_emitter",
|
26
|
-
"mock_transport",
|
27
|
-
"mock_metrics_collector",
|
28
22
|
"mock_cache",
|
23
|
+
"mock_config_source",
|
29
24
|
"mock_database",
|
25
|
+
"mock_event_emitter",
|
30
26
|
"mock_file_system",
|
27
|
+
"mock_http_config",
|
28
|
+
"mock_metrics_collector",
|
31
29
|
"mock_subprocess",
|
32
|
-
|
30
|
+
"mock_telemetry_config",
|
31
|
+
"mock_transport",
|
32
|
+
]
|
@@ -5,8 +5,7 @@ Reusable mock objects for configuration, logging, and other common
|
|
5
5
|
testing scenarios across the provide-io ecosystem.
|
6
6
|
"""
|
7
7
|
|
8
|
-
from unittest.mock import Mock,
|
9
|
-
from typing import Any
|
8
|
+
from unittest.mock import Mock, PropertyMock
|
10
9
|
|
11
10
|
import pytest
|
12
11
|
|
@@ -18,12 +17,12 @@ from provide.foundation.logger.config.logging import LoggingConfig
|
|
18
17
|
def mock_http_config():
|
19
18
|
"""
|
20
19
|
Standard HTTP configuration for testing.
|
21
|
-
|
20
|
+
|
22
21
|
Returns:
|
23
22
|
HTTPConfig with common test settings.
|
24
23
|
"""
|
25
24
|
from provide.foundation.transport.config import HTTPConfig
|
26
|
-
|
25
|
+
|
27
26
|
return HTTPConfig(
|
28
27
|
timeout=30.0,
|
29
28
|
max_retries=3,
|
@@ -37,13 +36,11 @@ def mock_http_config():
|
|
37
36
|
)
|
38
37
|
|
39
38
|
|
40
|
-
|
41
|
-
|
42
39
|
@pytest.fixture
|
43
40
|
def mock_telemetry_config():
|
44
41
|
"""
|
45
42
|
Standard telemetry configuration for testing.
|
46
|
-
|
43
|
+
|
47
44
|
Returns:
|
48
45
|
TelemetryConfig with debug logging enabled.
|
49
46
|
"""
|
@@ -59,7 +56,7 @@ def mock_telemetry_config():
|
|
59
56
|
def mock_config_source():
|
60
57
|
"""
|
61
58
|
Mock configuration source for testing config loading.
|
62
|
-
|
59
|
+
|
63
60
|
Returns:
|
64
61
|
Mock that simulates a configuration source.
|
65
62
|
"""
|
@@ -70,7 +67,7 @@ def mock_config_source():
|
|
70
67
|
source.watch = Mock()
|
71
68
|
source.priority = 100
|
72
69
|
source.name = "mock_source"
|
73
|
-
|
70
|
+
|
74
71
|
return source
|
75
72
|
|
76
73
|
|
@@ -78,7 +75,7 @@ def mock_config_source():
|
|
78
75
|
def mock_event_emitter():
|
79
76
|
"""
|
80
77
|
Mock event emitter for testing event-driven components.
|
81
|
-
|
78
|
+
|
82
79
|
Returns:
|
83
80
|
Mock with emit, on, off methods.
|
84
81
|
"""
|
@@ -89,7 +86,7 @@ def mock_event_emitter():
|
|
89
86
|
emitter.once = Mock()
|
90
87
|
emitter.listeners = Mock(return_value=[])
|
91
88
|
emitter.remove_all_listeners = Mock()
|
92
|
-
|
89
|
+
|
93
90
|
return emitter
|
94
91
|
|
95
92
|
|
@@ -97,7 +94,7 @@ def mock_event_emitter():
|
|
97
94
|
def mock_transport():
|
98
95
|
"""
|
99
96
|
Mock transport for testing network operations.
|
100
|
-
|
97
|
+
|
101
98
|
Returns:
|
102
99
|
Mock transport with request/response methods.
|
103
100
|
"""
|
@@ -108,7 +105,7 @@ def mock_transport():
|
|
108
105
|
transport.put = Mock(return_value={"status": 200, "data": {}})
|
109
106
|
transport.delete = Mock(return_value={"status": 204})
|
110
107
|
transport.close = Mock()
|
111
|
-
|
108
|
+
|
112
109
|
return transport
|
113
110
|
|
114
111
|
|
@@ -116,7 +113,7 @@ def mock_transport():
|
|
116
113
|
def mock_metrics_collector():
|
117
114
|
"""
|
118
115
|
Mock metrics collector for testing instrumentation.
|
119
|
-
|
116
|
+
|
120
117
|
Returns:
|
121
118
|
Mock with common metrics methods.
|
122
119
|
"""
|
@@ -127,13 +124,13 @@ def mock_metrics_collector():
|
|
127
124
|
collector.histogram = Mock()
|
128
125
|
collector.timer = Mock()
|
129
126
|
collector.flush = Mock()
|
130
|
-
|
127
|
+
|
131
128
|
# Add context manager support for timing
|
132
129
|
timer_cm = Mock()
|
133
130
|
timer_cm.__enter__ = Mock(return_value=timer_cm)
|
134
131
|
timer_cm.__exit__ = Mock(return_value=None)
|
135
132
|
collector.timer.return_value = timer_cm
|
136
|
-
|
133
|
+
|
137
134
|
return collector
|
138
135
|
|
139
136
|
|
@@ -141,12 +138,12 @@ def mock_metrics_collector():
|
|
141
138
|
def mock_cache():
|
142
139
|
"""
|
143
140
|
Mock cache for testing caching behavior.
|
144
|
-
|
141
|
+
|
145
142
|
Returns:
|
146
143
|
Mock with get, set, delete, clear methods.
|
147
144
|
"""
|
148
145
|
cache_data = {}
|
149
|
-
|
146
|
+
|
150
147
|
cache = Mock()
|
151
148
|
cache.get = Mock(side_effect=lambda k, default=None: cache_data.get(k, default))
|
152
149
|
cache.set = Mock(side_effect=lambda k, v, ttl=None: cache_data.update({k: v}))
|
@@ -154,10 +151,10 @@ def mock_cache():
|
|
154
151
|
cache.clear = Mock(side_effect=cache_data.clear)
|
155
152
|
cache.exists = Mock(side_effect=lambda k: k in cache_data)
|
156
153
|
cache.keys = Mock(return_value=list(cache_data.keys()))
|
157
|
-
|
154
|
+
|
158
155
|
# Store reference to data for test assertions
|
159
156
|
cache._data = cache_data
|
160
|
-
|
157
|
+
|
161
158
|
return cache
|
162
159
|
|
163
160
|
|
@@ -165,7 +162,7 @@ def mock_cache():
|
|
165
162
|
def mock_database():
|
166
163
|
"""
|
167
164
|
Mock database connection for testing.
|
168
|
-
|
165
|
+
|
169
166
|
Returns:
|
170
167
|
Mock with execute, fetch, commit, rollback methods.
|
171
168
|
"""
|
@@ -178,11 +175,11 @@ def mock_database():
|
|
178
175
|
db.rollback = Mock()
|
179
176
|
db.close = Mock()
|
180
177
|
db.is_connected = PropertyMock(return_value=True)
|
181
|
-
|
178
|
+
|
182
179
|
# Add context manager support
|
183
180
|
db.__enter__ = Mock(return_value=db)
|
184
181
|
db.__exit__ = Mock(return_value=None)
|
185
|
-
|
182
|
+
|
186
183
|
return db
|
187
184
|
|
188
185
|
|
@@ -190,7 +187,7 @@ def mock_database():
|
|
190
187
|
def mock_file_system():
|
191
188
|
"""
|
192
189
|
Mock file system operations.
|
193
|
-
|
190
|
+
|
194
191
|
Returns:
|
195
192
|
Mock with read, write, exists, delete methods.
|
196
193
|
"""
|
@@ -203,7 +200,7 @@ def mock_file_system():
|
|
203
200
|
fs.rmdir = Mock()
|
204
201
|
fs.list = Mock(return_value=[])
|
205
202
|
fs.stat = Mock(return_value=Mock(st_size=1024, st_mtime=0))
|
206
|
-
|
203
|
+
|
207
204
|
return fs
|
208
205
|
|
209
206
|
|
@@ -211,19 +208,19 @@ def mock_file_system():
|
|
211
208
|
def mock_subprocess():
|
212
209
|
"""
|
213
210
|
Mock subprocess for testing command execution.
|
214
|
-
|
211
|
+
|
215
212
|
Returns:
|
216
213
|
Mock with run, Popen methods.
|
217
214
|
"""
|
218
215
|
subprocess = Mock()
|
219
|
-
|
216
|
+
|
220
217
|
# Mock run method
|
221
218
|
result = Mock()
|
222
219
|
result.returncode = 0
|
223
220
|
result.stdout = "output"
|
224
221
|
result.stderr = ""
|
225
222
|
subprocess.run = Mock(return_value=result)
|
226
|
-
|
223
|
+
|
227
224
|
# Mock Popen
|
228
225
|
process = Mock()
|
229
226
|
process.communicate = Mock(return_value=("output", ""))
|
@@ -232,5 +229,5 @@ def mock_subprocess():
|
|
232
229
|
process.poll = Mock(return_value=0)
|
233
230
|
process.wait = Mock(return_value=0)
|
234
231
|
subprocess.Popen = Mock(return_value=process)
|
235
|
-
|
236
|
-
return subprocess
|
232
|
+
|
233
|
+
return subprocess
|
@@ -6,35 +6,35 @@ across any project that depends on provide.foundation.
|
|
6
6
|
"""
|
7
7
|
|
8
8
|
from provide.foundation.testing.file.fixtures import (
|
9
|
-
temp_directory,
|
10
|
-
test_files_structure,
|
11
|
-
temp_file,
|
12
9
|
binary_file,
|
13
|
-
nested_directory_structure,
|
14
10
|
empty_directory,
|
11
|
+
nested_directory_structure,
|
15
12
|
readonly_file,
|
16
|
-
temp_named_file,
|
17
|
-
temp_file_with_content,
|
18
13
|
temp_binary_file,
|
19
14
|
temp_csv_file,
|
15
|
+
temp_directory,
|
16
|
+
temp_executable_file,
|
17
|
+
temp_file,
|
18
|
+
temp_file_with_content,
|
20
19
|
temp_json_file,
|
20
|
+
temp_named_file,
|
21
21
|
temp_symlink,
|
22
|
-
|
22
|
+
test_files_structure,
|
23
23
|
)
|
24
24
|
|
25
25
|
__all__ = [
|
26
|
-
"temp_directory",
|
27
|
-
"test_files_structure",
|
28
|
-
"temp_file",
|
29
26
|
"binary_file",
|
30
|
-
"nested_directory_structure",
|
31
27
|
"empty_directory",
|
28
|
+
"nested_directory_structure",
|
32
29
|
"readonly_file",
|
33
|
-
"temp_named_file",
|
34
|
-
"temp_file_with_content",
|
35
30
|
"temp_binary_file",
|
36
31
|
"temp_csv_file",
|
32
|
+
"temp_directory",
|
33
|
+
"temp_executable_file",
|
34
|
+
"temp_file",
|
35
|
+
"temp_file_with_content",
|
37
36
|
"temp_json_file",
|
37
|
+
"temp_named_file",
|
38
38
|
"temp_symlink",
|
39
|
-
"
|
40
|
-
]
|
39
|
+
"test_files_structure",
|
40
|
+
]
|