|
| 1 | +import json |
| 2 | +import re |
| 3 | +from datetime import datetime |
| 4 | +from unittest.mock import patch |
| 5 | + |
| 6 | +import pytest |
| 7 | + |
| 8 | +from scripts.monitoring.solr_updater_monitor import monitor_solr_updater |
| 9 | + |
| 10 | +DUMMY_OFFSET = "2025-09-20:49255084" |
| 11 | + |
| 12 | + |
| 13 | +def patch_bash_run(commands: dict[str | re.Pattern[str], str]): |
| 14 | + def fake_bash_run(cmd, capture_output=False, sources=None): |
| 15 | + for pattern, response in commands.items(): |
| 16 | + if ( |
| 17 | + isinstance(pattern, re.Pattern) and pattern.match(cmd) |
| 18 | + ) or pattern == cmd: |
| 19 | + return response if capture_output else None |
| 20 | + raise AssertionError(f"Unexpected bash_run call: {cmd}") |
| 21 | + |
| 22 | + return patch('scripts.monitoring.solr_updater_monitor.bash_run', fake_bash_run) |
| 23 | + |
| 24 | + |
| 25 | +def patch_httpx_get(responses: dict[str | re.Pattern[str], str]): |
| 26 | + class FakeResponse: |
| 27 | + def __init__(self, text): |
| 28 | + self._text = text |
| 29 | + |
| 30 | + def raise_for_status(self): |
| 31 | + pass |
| 32 | + |
| 33 | + def json(self): |
| 34 | + return json.loads(self._text) |
| 35 | + |
| 36 | + async def fake_httpx_get(client, url, *args, **kwargs): |
| 37 | + for pattern, response in responses.items(): |
| 38 | + if ( |
| 39 | + isinstance(pattern, re.Pattern) and pattern.match(url) |
| 40 | + ) or pattern == url: |
| 41 | + return FakeResponse(response) |
| 42 | + raise AssertionError(f"Unexpected httpx.get call: {url}") |
| 43 | + |
| 44 | + return patch( |
| 45 | + 'scripts.monitoring.solr_updater_monitor.httpx.AsyncClient.get', fake_httpx_get |
| 46 | + ) |
| 47 | + |
| 48 | + |
| 49 | +@pytest.mark.asyncio |
| 50 | +async def test_container_not_running(capsys): |
| 51 | + fake_bash: dict[str | re.Pattern[str], str] = { |
| 52 | + re.compile(r'^docker ps .*'): "some-other-container\nopenlibrary-web-1", |
| 53 | + } |
| 54 | + with patch_bash_run(fake_bash): |
| 55 | + await monitor_solr_updater(dry_run=True) |
| 56 | + |
| 57 | + out = capsys.readouterr().out |
| 58 | + assert "Container openlibrary-solr-updater-1 not running" in out |
| 59 | + |
| 60 | + |
| 61 | +@pytest.mark.asyncio |
| 62 | +async def test_container_running(capsys): |
| 63 | + fake_bash: dict[str | re.Pattern[str], str] = { |
| 64 | + re.compile(r'^docker ps .*'): "openlibrary-solr-updater-1", |
| 65 | + re.compile(r'^docker exec .*'): DUMMY_OFFSET, |
| 66 | + } |
| 67 | + fake_requests: dict[str | re.Pattern[str], str] = { |
| 68 | + f'http://ol-home.us.archive.org:7000/openlibrary.org/log/{DUMMY_OFFSET}?limit=1': json.dumps( |
| 69 | + { |
| 70 | + "data": [ |
| 71 | + { |
| 72 | + "action": "store.put", |
| 73 | + "site": "openlibrary.org", |
| 74 | + "timestamp": "2025-09-20T14:28:56.908366", |
| 75 | + "data": { |
| 76 | + # ... |
| 77 | + }, |
| 78 | + } |
| 79 | + ], |
| 80 | + "offset": "2025-09-20:94419809", |
| 81 | + } |
| 82 | + ) |
| 83 | + } |
| 84 | + |
| 85 | + with ( |
| 86 | + patch_bash_run(fake_bash), |
| 87 | + patch_httpx_get(fake_requests), |
| 88 | + patch( |
| 89 | + 'scripts.monitoring.solr_updater_monitor.time.time', |
| 90 | + return_value=datetime.fromisoformat( |
| 91 | + "2025-09-20T14:28:56.908366" |
| 92 | + ).timestamp() |
| 93 | + + 64, |
| 94 | + ), |
| 95 | + ): |
| 96 | + await monitor_solr_updater(dry_run=True) |
| 97 | + |
| 98 | + out = capsys.readouterr().out |
| 99 | + assert out == 'stats.ol.solr-updater.seconds_behind 64 1758393000\n' |
0 commit comments