|
22 | 22 | _select_process_from_sysmon, |
23 | 23 | _select_process_output_keys, |
24 | 24 | _serialize_process, |
| 25 | + _should_skip_first_snapshot, |
25 | 26 | _validate_process_keys, |
26 | 27 | _write_json, |
27 | 28 | _write_process, |
28 | | - iter_initialized_processes, |
| 29 | + iter_processes, |
| 30 | + sysmon_process_monitor_threshold_task, |
29 | 31 | ) |
30 | 32 |
|
31 | 33 |
|
| 34 | +class _FakeSysmontap: |
| 35 | + def __init__(self, snapshots): |
| 36 | + self._snapshots = snapshots |
| 37 | + |
| 38 | + async def __aenter__(self): |
| 39 | + return self |
| 40 | + |
| 41 | + async def __aexit__(self, exc_type, exc, tb): |
| 42 | + return None |
| 43 | + |
| 44 | + async def iter_processes(self): |
| 45 | + for snapshot in self._snapshots: |
| 46 | + yield snapshot |
| 47 | + |
| 48 | + |
| 49 | +class _FakeDvtProvider: |
| 50 | + def __init__(self, service_provider): |
| 51 | + self.service_provider = service_provider |
| 52 | + |
| 53 | + async def __aenter__(self): |
| 54 | + return object() |
| 55 | + |
| 56 | + async def __aexit__(self, exc_type, exc, tb): |
| 57 | + return None |
| 58 | + |
| 59 | + |
32 | 60 | def test_parse_process_filters_groups_values_by_key(): |
33 | 61 | assert _parse_process_filters(["name=abc", "name=def", "pid=7"]) == { |
34 | 62 | "name": ["abc", "def"], |
@@ -180,46 +208,75 @@ def test_duration_elapsed(monkeypatch, start_time, duration_ms, current_time, ex |
180 | 208 | assert _duration_elapsed(start_time, duration_ms) is expected |
181 | 209 |
|
182 | 210 |
|
183 | | -class _FakeSysmontap: |
184 | | - def __init__(self, snapshots): |
185 | | - self._snapshots = snapshots |
186 | | - |
187 | | - async def __aenter__(self): |
188 | | - return self |
189 | | - |
190 | | - async def __aexit__(self, exc_type, exc, tb): |
191 | | - return None |
192 | | - |
193 | | - async def iter_processes(self): |
194 | | - for snapshot in self._snapshots: |
195 | | - yield snapshot |
| 211 | +@pytest.mark.parametrize( |
| 212 | + ("keys", "expected"), |
| 213 | + [ |
| 214 | + (None, True), |
| 215 | + (["pid"], False), |
| 216 | + (["pid", "cpuUsage"], True), |
| 217 | + ], |
| 218 | +) |
| 219 | +def test_should_skip_first_snapshot(keys, expected): |
| 220 | + assert _should_skip_first_snapshot(keys) is expected |
196 | 221 |
|
197 | 222 |
|
198 | 223 | @pytest.mark.asyncio |
199 | | -async def test_iter_initialized_processes_skips_first_snapshot(): |
200 | | - sysmon = _FakeSysmontap([ |
| 224 | +async def test_iter_processes_skips_first_snapshot_when_requested(): |
| 225 | + snapshots = [ |
201 | 226 | [{"pid": 10, "ppid": 1, "name": "first-snapshot"}], |
202 | 227 | [{"pid": 20, "ppid": 2, "name": "second-snapshot"}], |
203 | 228 | [{"pid": 30, "ppid": 3, "name": "third-snapshot"}], |
204 | | - ]) |
| 229 | + ] |
| 230 | + sysmon = _FakeSysmontap(snapshots) |
205 | 231 |
|
206 | | - snapshots = [snapshot async for snapshot in iter_initialized_processes(sysmon)] |
| 232 | + iterated_snapshots = [snapshot async for snapshot in iter_processes(sysmon, skip_first_snapshot=True)] |
207 | 233 |
|
208 | | - assert snapshots == [ |
209 | | - [{"pid": 20, "ppid": 2, "name": "second-snapshot"}], |
210 | | - [{"pid": 30, "ppid": 3, "name": "third-snapshot"}], |
211 | | - ] |
| 234 | + assert iterated_snapshots == snapshots[1:] |
212 | 235 |
|
213 | 236 |
|
214 | 237 | @pytest.mark.asyncio |
215 | | -async def test_iter_initialized_processes_empty_when_only_warmup_snapshot_exists(): |
| 238 | +async def test_iter_processes_empty_when_only_warmup_snapshot_exists(): |
216 | 239 | sysmon = _FakeSysmontap([[{"pid": 10, "ppid": 1, "name": "first-snapshot"}]]) |
217 | 240 |
|
218 | | - snapshots = [snapshot async for snapshot in iter_initialized_processes(sysmon)] |
| 241 | + snapshots = [snapshot async for snapshot in iter_processes(sysmon, skip_first_snapshot=True)] |
219 | 242 |
|
220 | 243 | assert snapshots == [] |
221 | 244 |
|
222 | 245 |
|
| 246 | +@pytest.mark.asyncio |
| 247 | +async def test_iter_processes_keeps_first_snapshot_when_cpu_usage_not_required(): |
| 248 | + snapshots = [ |
| 249 | + [{"pid": 10, "ppid": 1, "name": "first-snapshot"}], |
| 250 | + [{"pid": 20, "ppid": 2, "name": "second-snapshot"}], |
| 251 | + ] |
| 252 | + |
| 253 | + sysmon = _FakeSysmontap(snapshots) |
| 254 | + |
| 255 | + iterated_snapshots = [snapshot async for snapshot in iter_processes(sysmon, skip_first_snapshot=False)] |
| 256 | + |
| 257 | + assert iterated_snapshots == snapshots |
| 258 | + |
| 259 | + |
| 260 | +@pytest.mark.asyncio |
| 261 | +async def test_sysmon_process_monitor_threshold_task_skips_first_snapshot(monkeypatch): |
| 262 | + async def fake_create(_dvt): |
| 263 | + return _FakeSysmontap([ |
| 264 | + [{"pid": 10, "cpuUsage": 99.0}], |
| 265 | + [{"pid": 20, "cpuUsage": 1.5}], |
| 266 | + ]) |
| 267 | + |
| 268 | + monkeypatch.setattr(process_module, "DvtProvider", _FakeDvtProvider) |
| 269 | + monkeypatch.setattr(process_module.Sysmontap, "create", fake_create) |
| 270 | + |
| 271 | + out = StringIO() |
| 272 | + |
| 273 | + await sysmon_process_monitor_threshold_task(object(), threshold=0.0, keys=["pid"], out=out, duration=1) |
| 274 | + |
| 275 | + lines = [json.loads(line) for line in out.getvalue().splitlines() if line.strip()] |
| 276 | + assert len(lines) == 1 |
| 277 | + assert lines[0]["pid"] == 20 |
| 278 | + |
| 279 | + |
223 | 280 | def test_process_sort_key_normalizes_missing_values(): |
224 | 281 | assert _process_sort_key({"name": "abc"}) == (-1, -1, "abc") |
225 | 282 |
|
@@ -337,6 +394,23 @@ async def fake_create(_dvt): |
337 | 394 | assert selected == {"pid": 20, "ppid": 2, "name": "second-snapshot"} |
338 | 395 |
|
339 | 396 |
|
| 397 | +@pytest.mark.asyncio |
| 398 | +async def test_select_process_from_sysmon_doesnt_skip_first_snapshot_when_cpu_usage_not_requested(monkeypatch): |
| 399 | + async def fake_create(_dvt): |
| 400 | + return _FakeSysmontap([ |
| 401 | + [{"pid": 10, "ppid": 1, "name": "first-snapshot"}], |
| 402 | + [{"pid": 20, "ppid": 2, "name": "second-snapshot"}], |
| 403 | + ]) |
| 404 | + |
| 405 | + monkeypatch.setattr(process_module.Sysmontap, "create", fake_create) |
| 406 | + |
| 407 | + selected = await _select_process_from_sysmon( |
| 408 | + object(), {"name": ["first-snapshot"]}, ["pid", "name"], ProcessSelectionMode.FIRST |
| 409 | + ) |
| 410 | + |
| 411 | + assert selected == {"pid": 10, "ppid": 1, "name": "first-snapshot"} |
| 412 | + |
| 413 | + |
340 | 414 | @pytest.mark.asyncio |
341 | 415 | async def test_select_process_from_sysmon_raises_when_no_usable_snapshot(monkeypatch): |
342 | 416 | async def fake_create(_dvt): |
|
0 commit comments