多线程并发提交 —— 计数器自洽验证。
| 131 | # --------------------------------------------------------------------------- |
| 132 | |
| 133 | class TestConcurrentSubmitCounting: |
| 134 | """多线程并发提交 —— 计数器自洽验证。""" |
| 135 | |
| 136 | def test_no_exceptions_raised(self, isolated_engine): |
| 137 | """并发提交不得抛出异常。""" |
| 138 | _, errors = _concurrent_submit(isolated_engine, n_threads=5, per_thread=10) |
| 139 | assert errors == [], f"并发提交出现异常: {errors}" |
| 140 | |
| 141 | def test_total_requests_equals_total_submitted(self, isolated_engine): |
| 142 | """并发提交 N*M 次后,total_requests 增量应恰好为 N*M。""" |
| 143 | n_threads, per_thread = 5, 20 |
| 144 | before = isolated_engine.stats["total_requests"] |
| 145 | _, errors = _concurrent_submit(isolated_engine, n_threads, per_thread) |
| 146 | assert errors == [], f"并发出现异常: {errors}" |
| 147 | assert isolated_engine.stats["total_requests"] == before + n_threads * per_thread |
| 148 | |
| 149 | def test_all_results_returned(self, isolated_engine): |
| 150 | """每次 submit_request 都应返回结果(不会静默丢失)。""" |
| 151 | n_threads, per_thread = 4, 10 |
| 152 | results, errors = _concurrent_submit(isolated_engine, n_threads, per_thread) |
| 153 | assert errors == [] |
| 154 | assert len(results) == n_threads * per_thread |
| 155 | |
| 156 | def test_results_are_dicts(self, isolated_engine): |
| 157 | """每个返回值都应是字典。""" |
| 158 | results, errors = _concurrent_submit(isolated_engine, n_threads=3, per_thread=5) |
| 159 | assert errors == [] |
| 160 | for r in results: |
| 161 | assert isinstance(r, dict), f"返回值应为 dict,实际为 {type(r)}" |
| 162 | |
| 163 | def test_results_have_id_field(self, isolated_engine): |
| 164 | """每个结果字典应包含 id 字段。""" |
| 165 | results, errors = _concurrent_submit(isolated_engine, n_threads=3, per_thread=5) |
| 166 | assert errors == [] |
| 167 | for r in results: |
| 168 | assert "id" in r or r.get("status") == "error", ( |
| 169 | f"结果缺少 id 字段: {r}" |
| 170 | ) |
| 171 | |
| 172 | def test_results_have_status_field(self, isolated_engine): |
| 173 | """每个结果字典应包含 status 字段。""" |
| 174 | results, errors = _concurrent_submit(isolated_engine, n_threads=3, per_thread=5) |
| 175 | assert errors == [] |
| 176 | for r in results: |
| 177 | assert "status" in r, f"结果缺少 status 字段: {r}" |
| 178 | |
| 179 | def test_no_duplicate_ids(self, isolated_engine): |
| 180 | """并发提交产生的请求 ID 应唯一(若结果含 id)。""" |
| 181 | results, errors = _concurrent_submit(isolated_engine, n_threads=4, per_thread=10) |
| 182 | assert errors == [] |
| 183 | ids = [r.get("id") for r in results if r.get("id") is not None] |
| 184 | assert len(ids) == len(set(ids)), "出现重复 id" |
| 185 | |
| 186 | def test_request_list_consistent_with_counter(self, isolated_engine): |
| 187 | """transmission_requests + request_history 长度等于 total_requests 增量。""" |
| 188 | n_threads, per_thread = 4, 15 |
| 189 | before_total = isolated_engine.stats["total_requests"] |
| 190 | before_lists = ( |
nothing calls this directly
no outgoing calls
no test coverage detected