|
3 | 3 | Sequential HEADs on a recursive list stack into a client-timeout-tripping stall. |
4 | 4 | This proves: HEADs run concurrently, output order matches input order, internal |
5 | 5 | keys are skipped, and a failing HEAD falls back to the listed size/etag. |
6 | | -
|
7 | | -The repo's package __init__ chain currently pulls in modules with pre-existing |
8 | | -Py2 `except A, B:` syntax (utils.py, dashboard/*) that won't import under Py3, |
9 | | -so we load buckets.py directly with stubbed siblings to exercise the real code. |
10 | 6 | """ |
11 | 7 |
|
12 | 8 | import asyncio |
13 | 9 | import datetime as dt |
14 | | -import importlib.util |
15 | | -import sys |
16 | | -import types |
17 | | -from pathlib import Path |
18 | | - |
19 | | -REPO = Path(__file__).resolve().parents[2] |
20 | | - |
21 | | - |
22 | | -def _load_buckets(): |
23 | | - def stub(name, **attrs): |
24 | | - m = types.ModuleType(name) |
25 | | - for k, v in attrs.items(): |
26 | | - setattr(m, k, v) |
27 | | - sys.modules[name] = m |
28 | | - return m |
29 | | - |
30 | | - stub("s3proxy") |
31 | | - stub("s3proxy.handlers") |
32 | | - stub("s3proxy.xml_responses") |
33 | | - stub("s3proxy.client", S3Credentials=object) |
34 | | - stub("s3proxy.errors", S3Error=type("S3Error", (Exception,), {})) |
35 | | - stub( |
36 | | - "s3proxy.state", |
37 | | - INTERNAL_PREFIX="s3proxy-internal/", |
38 | | - META_SUFFIX_LEGACY=".s3proxy-meta", |
39 | | - delete_multipart_metadata=lambda *a, **k: None, |
40 | | - ) |
41 | | - stub("s3proxy.xml_utils", find_element=lambda *a, **k: None, find_elements=lambda *a, **k: []) |
42 | | - stub("s3proxy.handlers.base", BaseHandler=object) |
43 | | - |
44 | | - spec = importlib.util.spec_from_file_location( |
45 | | - "s3proxy.handlers.buckets", REPO / "s3proxy" / "handlers" / "buckets.py" |
46 | | - ) |
47 | | - mod = importlib.util.module_from_spec(spec) |
48 | | - sys.modules["s3proxy.handlers.buckets"] = mod |
49 | | - spec.loader.exec_module(mod) |
50 | | - return mod |
51 | | - |
52 | | - |
53 | | -buckets = _load_buckets() |
| 10 | + |
| 11 | +from s3proxy.handlers.buckets import LIST_HEAD_CONCURRENCY, BucketHandlerMixin |
| 12 | + |
54 | 13 | INTERNAL_PREFIX = "s3proxy-internal/" |
55 | 14 |
|
56 | 15 |
|
57 | 16 | class FakeHandler: |
58 | | - _process_list_objects = buckets.BucketHandlerMixin._process_list_objects |
| 17 | + _process_list_objects = BucketHandlerMixin._process_list_objects |
59 | 18 |
|
60 | 19 | def __init__(self): |
61 | 20 | self.inflight = 0 |
@@ -120,7 +79,7 @@ def test_parallel_order_and_fallback(): |
120 | 79 | assert result[1]["etag"] == "raw-etag" |
121 | 80 | # HEADs actually ran concurrently (would be 1 if sequential), and stayed bounded. |
122 | 81 | assert handler.max_inflight > 1 |
123 | | - assert handler.max_inflight <= buckets.LIST_HEAD_CONCURRENCY |
| 82 | + assert handler.max_inflight <= LIST_HEAD_CONCURRENCY |
124 | 83 |
|
125 | 84 |
|
126 | 85 | if __name__ == "__main__": |
|
0 commit comments