Initial server source import

This commit is contained in:
sashatrask
2026-09-30 20:30:56 +03:00
commit 170dd941b9
498 changed files with 261563 additions and 0 deletions
+773
View File
@@ -0,0 +1,773 @@
import json
import os
import sys
import tempfile
import time
import unittest
from unittest import mock
APP_DIR = os.path.abspath(os.path.join(os.path.dirname(__file__), '..', 'app'))
if APP_DIR not in sys.path:
sys.path.insert(0, APP_DIR)
from worker_contracts import (
AssignmentOutcome,
DiagnosticCategory,
DiagnosticHTTPContext,
DiagnosticKind,
DiagnosticProcessContext,
ScanOutcome,
WorkerPhase,
build_diagnostic_envelope,
make_body_material,
make_log_material,
)
import worker_local_state
from runtime_security import atomic_write_private_json
from worker_local_state import WorkerLocalState, WorkerLocalStateError
UTC = '2026-09-23T12:00:00Z'
class WorkerLocalStateTests(unittest.TestCase):
def test_journal_recovery_ignores_truncated_tail_and_rebuilds_projection(self):
with tempfile.TemporaryDirectory() as root:
state = WorkerLocalState(root)
first = state.emit_phase('instance-1', 0, WorkerPhase.IDLE, timestamp=UTC)
second = state.emit_phase(
'instance-1', 0, WorkerPhase.CLAIMING,
timestamp='2026-09-23T12:00:01Z',
)
self.assertEqual((first['sequence'], second['sequence']), (1, 2))
with open(state.event_path, 'ab') as handle:
handle.write(b'{"incomplete":')
with open(state.status_path, 'wb') as handle:
handle.write(b'not-json')
recovered = WorkerLocalState(root)
self.assertEqual(recovered.next_sequence, 3)
self.assertEqual(recovered.snapshot()['slots'][0]['phase'], 'claiming')
self.assertTrue(open(recovered.event_path, 'rb').read().endswith(b'\n'))
projection = json.load(open(recovered.status_path, encoding='utf-8'))
self.assertEqual(projection['sequence'], 2)
def test_generated_parent_timestamp_never_predates_explicit_runner_event(self):
with tempfile.TemporaryDirectory() as root:
state = WorkerLocalState(root)
runner_timestamp = '2026-09-23T12:00:20Z'
runner_event = state.emit_phase(
'instance-1', 0, WorkerPhase.BUNDLING,
reservation_id=7, timestamp=runner_timestamp,
phase_started_at=runner_timestamp,
)
with mock.patch.object(
worker_local_state, 'utc_now', return_value='2026-09-23T12:00:17Z',
):
uploading = state.emit_phase(
'instance-1', 0, WorkerPhase.UPLOADING, reservation_id=7,
)
awaiting = state.emit_phase(
'instance-1', 0, WorkerPhase.AWAITING_RECEIPT, reservation_id=7,
)
self.assertEqual(runner_event['timestamp'], runner_timestamp)
self.assertEqual(uploading['timestamp'], runner_timestamp)
self.assertEqual(uploading['phase_started_at'], runner_timestamp)
self.assertEqual(awaiting['timestamp'], runner_timestamp)
self.assertEqual(awaiting['phase_started_at'], runner_timestamp)
def test_projection_does_not_modify_authoritative_slot_state(self):
with tempfile.TemporaryDirectory() as root:
state = WorkerLocalState(root)
slot = os.path.join(root, 'slot-0.json')
payload = b'{"assignment":{"reservation":{"reservation_id":7}},"phase":"assigned"}\n'
with open(slot, 'wb') as handle:
handle.write(payload)
state.emit_phase('instance-1', 0, WorkerPhase.IDLE, timestamp=UTC)
state.recover()
self.assertEqual(open(slot, 'rb').read(), payload)
def test_read_only_inspection_never_rewrites_projection_or_journal(self):
with tempfile.TemporaryDirectory() as root:
state = WorkerLocalState(root)
state.emit_phase('instance-1', 0, WorkerPhase.IDLE, timestamp=UTC)
before_projection = open(state.status_path, 'rb').read()
before_journal = open(state.event_path, 'rb').read()
reader = WorkerLocalState(root, read_only=True)
self.assertEqual(reader.snapshot()['sequence'], 1)
self.assertEqual(open(state.status_path, 'rb').read(), before_projection)
self.assertEqual(open(state.event_path, 'rb').read(), before_journal)
with self.assertRaisesRegex(WorkerLocalStateError, 'cannot mutate'):
reader.emit_phase('instance-1', 0, WorkerPhase.CLAIMING)
def test_history_is_append_only_and_idempotent(self):
with tempfile.TemporaryDirectory() as root:
state = WorkerLocalState(root)
record = {
'history_id': 'receipt-1', 'instance_id': 'instance-1',
'slot_id': 0, 'reservation_id': 7, 'source': 'dockerhub',
'outcome': 'bundle_accepted', 'receipt': {'receipt_id': 'receipt-1'},
'started_at': UTC, 'completed_at': UTC, 'duration_seconds': 0.0,
'first_sequence': 1, 'last_sequence': 4, 'diagnostics': [],
'timeline': [], 'phase_durations': {},
}
self.assertTrue(state.append_history(record))
self.assertFalse(state.append_history(record))
self.assertEqual(len(state.history()), 1)
self.assertEqual(state.history(reservation_id=7)[0]['history_id'], 'receipt-1')
with open(state.history_path, 'ab') as handle:
handle.write(b'{"truncated":')
recovered = WorkerLocalState(root)
second = dict(record)
second['history_id'] = 'receipt-2'
self.assertTrue(recovered.append_history(second))
self.assertEqual(
[item['history_id'] for item in recovered.history()],
['receipt-1', 'receipt-2'],
)
def test_history_uses_one_closed_schema_validator_for_append_recovery_and_read(self):
record = {
'history_id': 'receipt-1', 'instance_id': 'instance-1',
'slot_id': 0, 'reservation_id': 7, 'source': 'dockerhub',
'outcome': 'bundle_accepted', 'receipt': {}, 'started_at': UTC,
'completed_at': UTC, 'duration_seconds': 0.0,
'first_sequence': None, 'last_sequence': None, 'diagnostics': [],
'timeline': [], 'phase_durations': {},
}
with tempfile.TemporaryDirectory() as root:
state = WorkerLocalState(root)
with self.assertRaisesRegex(WorkerLocalStateError, 'shape'):
state.append_history({**record, 'unexpected': True})
state.append_history(record)
invalid = {
'schema': 1, **record, 'slot_id': -1, 'history_id': 'receipt-2',
}
with open(state.history_path, 'ab') as handle:
handle.write(json.dumps(
invalid, ensure_ascii=True, sort_keys=True, separators=(',', ':'),
).encode('ascii') + b'\n')
with self.assertRaisesRegex(WorkerLocalStateError, 'slot identity'):
WorkerLocalState(root, read_only=True)
with self.assertRaisesRegex(WorkerLocalStateError, 'slot identity'):
state.history()
def test_legacy_schema_one_history_is_explicitly_normalized_to_schema_two(self):
with tempfile.TemporaryDirectory() as root:
state = WorkerLocalState(root)
legacy = {
'schema': 1,
'history_id': 'legacy-1',
'slot_id': 0,
'reservation_id': 7,
'source': 'gitlab',
'outcome': 'bundle_accepted',
'receipt': {},
'started_at': UTC,
'completed_at': UTC,
'duration_seconds': 0.0,
'first_sequence': 1,
'last_sequence': 1,
'diagnostics': [],
'timeline': [{
'sequence': 1, 'timestamp': UTC, 'phase': 'assigned',
}],
'phase_durations': {'assigned': 0.0},
}
atomic_write_private_json(state.history_path, legacy)
reader = WorkerLocalState(root, read_only=True)
migrated = reader.history()[0]
self.assertEqual(migrated['schema'], 2)
self.assertEqual(migrated['instance_id'], 'legacy-instance-unavailable')
self.assertEqual(migrated['timeline'][0]['progress'], {})
self.assertEqual(
migrated['timeline'][0]['instance_id'],
'legacy-instance-unavailable',
)
second_pass = {
**legacy,
'instance_id': 'second-pass-instance',
'timeline': [{
'sequence': 1,
'timestamp': UTC,
'instance_id': 'second-pass-instance',
'phase': 'assigned',
'progress': {'recovered': True},
}],
}
atomic_write_private_json(state.history_path, second_pass)
migrated = WorkerLocalState(root, read_only=True).history()[0]
self.assertEqual(migrated['schema'], 2)
self.assertEqual(migrated['instance_id'], 'second-pass-instance')
self.assertTrue(migrated['timeline'][0]['progress']['recovered'])
hybrid = {
**second_pass,
'timeline': [{
'sequence': 1, 'timestamp': UTC,
'instance_id': 'second-pass-instance', 'phase': 'assigned',
}],
}
atomic_write_private_json(state.history_path, hybrid)
with self.assertRaisesRegex(WorkerLocalStateError, 'timeline event'):
WorkerLocalState(root, read_only=True)
def test_event_cursor_reads_only_requested_tail_without_writer_lock_scan(self):
with tempfile.TemporaryDirectory() as root:
state = WorkerLocalState(root)
state.emit_phase('instance-1', 0, WorkerPhase.IDLE, timestamp=UTC)
for index in range(2, 102):
state.emit_phase(
'instance-1', 0, WorkerPhase.IDLE,
timestamp=f'2026-09-23T12:00:{min(index, 59):02d}Z',
progress={'sample': index},
)
original = worker_local_state.decode_worker_event
with mock.patch.object(
worker_local_state, 'decode_worker_event', wraps=original,
) as decode:
values = state.events_after(100, 1)
self.assertEqual(values[0]['sequence'], 101)
self.assertLessEqual(decode.call_count, worker_local_state.EVENT_CURSOR_STRIDE)
def test_assignment_timeline_crosses_instance_recovery_boundaries(self):
with tempfile.TemporaryDirectory() as root:
state = WorkerLocalState(root)
state.emit_phase('instance-1', 0, WorkerPhase.IDLE, timestamp=UTC)
state.emit_phase(
'instance-1', 0, WorkerPhase.CLAIMING,
reservation_id=7, source='gitlab',
timestamp='2026-09-23T12:00:01Z',
)
state.emit_phase(
'instance-1', 0, WorkerPhase.ASSIGNED,
reservation_id=7, source='gitlab',
timestamp='2026-09-23T12:00:02Z',
)
state.emit_phase(
'instance-2', 0, WorkerPhase.CLAIMING,
reservation_id=7, source='gitlab',
timestamp='2026-09-23T12:00:03Z', progress={'recovered': True},
)
state.emit_phase(
'instance-2', 0, WorkerPhase.ASSIGNED,
reservation_id=7, source='gitlab',
timestamp='2026-09-23T12:00:04Z', progress={'recovered': True},
)
timeline = state.assignment_timeline(0, 7)
self.assertEqual(
[item['instance_id'] for item in timeline],
['instance-1', 'instance-1', 'instance-2', 'instance-2'],
)
self.assertTrue(timeline[-1]['progress']['recovered'])
def test_diagnostic_archive_preserves_body_stdout_and_stderr_material(self):
envelope = build_diagnostic_envelope(
occurrence_id='occurrence-1', reservation_id=7,
scan_event_id='a' * 32, slot_id=0, source='dockerhub',
phase=WorkerPhase.SCANNING, kind=DiagnosticKind.PROVIDER_HTTP,
category=DiagnosticCategory.AUTHORIZATION,
code='docker.manifest_http_403', summary='request denied',
retryable=False, attempt=1,
assignment_outcome=AssignmentOutcome.ACCEPTED,
scan_outcome=ScanOutcome.ERROR, occurred_at=UTC, captured_at=UTC,
http=DiagnosticHTTPContext(
operation='manifest.get', status_code=403,
content_type='application/json', request_id='request-1',
body=make_body_material(b'{"error":"denied"}'),
),
process=DiagnosticProcessContext(
name='trufflehog', exit_code=1, signal=None, timed_out=False,
stdout=make_log_material(b'stdout\n'),
stderr=make_log_material(b'stderr\n'),
),
)
with tempfile.TemporaryDirectory() as root:
state = WorkerLocalState(root)
archived = state.archive_diagnostic(envelope)
self.assertEqual(state.diagnostic_references(7), [archived])
self.assertEqual(
open(os.path.join(root, *archived['artifacts']['body']['path'].split('/')), 'rb').read(),
b'{"error":"denied"}',
)
self.assertEqual(
open(os.path.join(root, *archived['artifacts']['stdout']['path'].split('/')), 'rb').read(),
b'stdout\n',
)
self.assertTrue(archived['artifacts']['stdout']['path'].endswith('.stdout.log'))
self.assertEqual(
open(os.path.join(root, *archived['artifacts']['stderr']['path'].split('/')), 'rb').read(),
b'stderr\n',
)
self.assertTrue(archived['artifacts']['stderr']['path'].endswith('.stderr.log'))
record = json.load(open(os.path.join(root, *archived['record'].split('/')), encoding='utf-8'))
self.assertFalse(record['artifacts']['body']['truncated'])
state.append_history({
'history_id': 'diagnostic-history', 'instance_id': 'instance-1',
'slot_id': 0, 'reservation_id': 7, 'source': 'dockerhub',
'outcome': 'bundle_accepted', 'receipt': {}, 'started_at': UTC,
'completed_at': UTC, 'duration_seconds': 0.0,
'first_sequence': None, 'last_sequence': None,
'diagnostics': [archived],
'timeline': [], 'phase_durations': {},
})
self.assertTrue(state.history()[0]['diagnostics'][0]['available'])
os.remove(os.path.join(root, *archived['record'].split('/')))
for artifact in archived['artifacts'].values():
if artifact:
os.remove(os.path.join(root, *artifact['path'].split('/')))
retained = state.history()[0]['diagnostics'][0]
self.assertFalse(retained['available'])
self.assertFalse(any(retained['artifact_availability'].values()))
def test_full_artifact_encoding_uses_complete_bytes_not_bounded_excerpt(self):
full_body = (b'a' * (16 * 1024)) + b'\xff'
envelope = build_diagnostic_envelope(
occurrence_id='encoding-1', reservation_id=7,
scan_event_id='a' * 32, slot_id=0, source='dockerhub',
phase=WorkerPhase.RESOLVING, kind=DiagnosticKind.PROVIDER_HTTP,
category=DiagnosticCategory.PROVIDER, code='fixture',
summary='fixture', retryable=False, attempt=1,
assignment_outcome=AssignmentOutcome.ACCEPTED,
scan_outcome=ScanOutcome.ERROR, occurred_at=UTC, captured_at=UTC,
http=DiagnosticHTTPContext(
operation='fixture', status_code=500, content_type=None,
request_id=None, body=make_body_material(full_body),
),
)
self.assertEqual(envelope.http.body.encoding.value, 'text')
self.assertTrue(envelope.http.body.truncated)
with tempfile.TemporaryDirectory() as root:
state = WorkerLocalState(root)
archived = state.archive_diagnostic(envelope, {'body': full_body})
artifact = archived['artifacts']['body']
self.assertEqual(artifact['encoding'], 'base64')
self.assertFalse(artifact['truncated'])
self.assertEqual(
open(os.path.join(root, *artifact['path'].split('/')), 'rb').read(),
full_body,
)
def test_logs_rotate_and_retention_accounts_and_removes_expired_artifacts(self):
with tempfile.TemporaryDirectory() as root:
state = WorkerLocalState(
root, log_bytes=64 * 1024, log_files=2,
retention_days=1, retention_bytes=1024 * 1024,
)
state.log('a' * 40000)
state.log('b' * 40000)
self.assertTrue(os.path.exists(state.log_path + '.1'))
expired = os.path.join(state.diagnostics_dir, 'expired.bin')
with open(expired, 'wb') as handle:
handle.write(b'x' * 100)
os.utime(expired, (time.time() - 172800, time.time() - 172800))
before = state.retention_usage()
cleanup = state.cleanup_retention()
after = state.retention_usage()
self.assertGreaterEqual(before['total_bytes'], after['total_bytes'])
self.assertGreaterEqual(cleanup['removed_files'], 1)
self.assertFalse(os.path.exists(expired))
def test_retention_never_evicts_active_assignment_diagnostics_or_data_roots(self):
envelope = build_diagnostic_envelope(
occurrence_id='active-1', reservation_id=7,
scan_event_id='a' * 32, slot_id=0, source='dockerhub',
phase=WorkerPhase.SCANNING, kind=DiagnosticKind.PROVIDER_HTTP,
category=DiagnosticCategory.AUTHORIZATION, code='fixture',
summary='fixture', retryable=False, attempt=1,
assignment_outcome=AssignmentOutcome.UNFINISHED,
scan_outcome=ScanOutcome.ERROR, occurred_at=UTC, captured_at=UTC,
http=DiagnosticHTTPContext(
operation='fixture', status_code=500, content_type=None,
request_id=None, body=make_body_material(b'active body'),
),
)
with tempfile.TemporaryDirectory() as root:
state = WorkerLocalState(root, retention_days=1, retention_bytes=1024 * 1024)
archived = state.archive_diagnostic(envelope)
slot_path = os.path.join(root, 'slot-0.json')
atomic_write_private_json(slot_path, {
'phase': 'assigned',
'assignment': {'reservation': {'reservation_id': 7}},
})
for path in (
archived['record'],
archived['artifacts']['body']['path'],
):
absolute = os.path.join(root, *path.split('/'))
os.utime(absolute, (time.time() - 172800, time.time() - 172800))
bundle = os.path.join(root, 'bundles')
work = os.path.join(root, 'work')
os.makedirs(bundle)
os.makedirs(work)
open(os.path.join(bundle, 'ready.trb'), 'wb').write(b'bundle')
open(os.path.join(work, 'active.tmp'), 'wb').write(b'work')
usage = state.retention_usage({'bundles': bundle, 'work': work})
self.assertEqual(usage['categories']['bundles']['evictable_bytes'], 0)
self.assertEqual(usage['categories']['work']['evictable_bytes'], 0)
self.assertGreater(usage['categories']['state']['non_evictable_bytes'], 0)
self.assertGreater(usage['categories']['diagnostics']['non_evictable_bytes'], 0)
state.cleanup_retention()
self.assertTrue(os.path.exists(os.path.join(root, *archived['record'].split('/'))))
self.assertTrue(os.path.exists(os.path.join(bundle, 'ready.trb')))
self.assertTrue(os.path.exists(os.path.join(work, 'active.tmp')))
def test_retention_preserves_diagnostics_referenced_by_retained_history(self):
envelope = build_diagnostic_envelope(
occurrence_id='retained-1', reservation_id=7,
scan_event_id='a' * 32, slot_id=0, source='dockerhub',
phase=WorkerPhase.SCANNING, kind=DiagnosticKind.PROVIDER_HTTP,
category=DiagnosticCategory.AUTHORIZATION, code='fixture',
summary='fixture', retryable=False, attempt=1,
assignment_outcome=AssignmentOutcome.ACCEPTED,
scan_outcome=ScanOutcome.ERROR, occurred_at=UTC, captured_at=UTC,
http=DiagnosticHTTPContext(
operation='fixture', status_code=500, content_type=None,
request_id=None, body=make_body_material(b'retained body'),
),
)
with tempfile.TemporaryDirectory() as root:
state = WorkerLocalState(root, retention_days=1)
archived = state.archive_diagnostic(envelope)
state.append_history({
'history_id': 'retained-history', 'instance_id': 'instance-1',
'slot_id': 0, 'reservation_id': 7, 'source': 'dockerhub',
'outcome': 'bundle_accepted', 'receipt': {}, 'started_at': UTC,
'completed_at': UTC, 'duration_seconds': 0.0,
'first_sequence': None, 'last_sequence': None,
'diagnostics': [archived], 'timeline': [], 'phase_durations': {},
})
old = time.time() - 172800
paths = [archived['record']] + [
artifact['path'] for artifact in archived['artifacts'].values()
if artifact is not None
]
for relative in paths:
absolute = os.path.join(root, *relative.split('/'))
os.utime(absolute, (old, old))
state.cleanup_retention()
for relative in paths:
self.assertTrue(os.path.exists(os.path.join(root, *relative.split('/'))))
def test_segment_rotation_restart_cursor_and_retention_preserve_active_files(self):
with tempfile.TemporaryDirectory() as root:
state = WorkerLocalState(
root, event_segment_bytes=1024, history_segment_bytes=1024,
retention_days=1, retention_bytes=1024 * 1024,
)
for index in range(12):
state.emit_phase(
'instance-1', 0, WorkerPhase.IDLE, timestamp=UTC,
progress={'sample': index, 'padding': 'x' * 300},
)
for index in range(3):
state.append_history({
'history_id': f'history-{index}', 'instance_id': 'instance-1',
'slot_id': 0, 'reservation_id': 100 + index,
'source': 'gitlab', 'outcome': 'bundle_accepted',
'receipt': {'padding': 'y' * 700}, 'started_at': UTC,
'completed_at': UTC, 'duration_seconds': 0.0,
'first_sequence': None, 'last_sequence': None,
'diagnostics': [], 'timeline': [], 'phase_durations': {},
})
event_segments = state._closed_event_paths()
history_segments = state._closed_history_paths()
self.assertTrue(event_segments)
self.assertTrue(history_segments)
self.assertEqual(
[item['sequence'] for item in state.events_after(2, 3)],
[3, 4, 5],
)
restarted = WorkerLocalState(
root, event_segment_bytes=1024, history_segment_bytes=1024,
retention_days=1, retention_bytes=1024 * 1024,
)
self.assertEqual(restarted.next_sequence, 13)
self.assertEqual(len(restarted.history()), 3)
old = time.time() - 172800
for _first, _last, path in restarted._closed_event_paths():
os.utime(path, (old, old))
for _index, path in restarted._closed_history_paths():
os.utime(path, (old, old))
atomic_write_private_json(
os.path.join(root, 'control', 'progress-outbox.json'),
{'schema': 1, 'sequence': 12},
)
before = restarted.retention_usage()
self.assertGreater(before['categories']['events']['evictable_bytes'], 0)
self.assertEqual(before['categories']['history']['evictable_bytes'], 0)
restarted.cleanup_retention()
self.assertTrue(os.path.exists(restarted.event_path))
self.assertTrue(os.path.exists(restarted.history_path))
self.assertEqual(len(restarted._closed_history_paths()), len(history_segments))
self.assertEqual(len(restarted.history()), 3)
retained_events = restarted.events_after(0, 100)
self.assertTrue(retained_events)
self.assertGreater(retained_events[0]['sequence'], 1)
after_cleanup = WorkerLocalState(
root, event_segment_bytes=1024, history_segment_bytes=1024,
)
self.assertEqual(after_cleanup.next_sequence, 13)
self.assertEqual(
after_cleanup.events_after(retained_events[0]['sequence'] - 1, 1)[0]['sequence'],
retained_events[0]['sequence'],
)
def test_aggressive_retention_preserves_active_timeline_and_terminal_history(self):
with tempfile.TemporaryDirectory() as root:
state = WorkerLocalState(
root, event_segment_bytes=1024, history_segment_bytes=1024,
retention_days=1, retention_bytes=1024 * 1024,
)
state.emit_phase('instance-1', 0, WorkerPhase.IDLE, timestamp=UTC)
state.emit_phase(
'instance-1', 0, WorkerPhase.CLAIMING,
reservation_id=7, source='gitlab', timestamp=UTC,
progress={'padding': 'x' * 400},
)
for index in range(6):
state.emit_phase(
'instance-1', 0, WorkerPhase.ASSIGNED,
reservation_id=7, source='gitlab', timestamp=UTC,
progress={'sample': index, 'padding': 'x' * 400},
)
atomic_write_private_json(os.path.join(root, 'slot-0.json'), {
'phase': 'assigned',
'assignment': {'reservation': {'reservation_id': 7}},
})
for index in range(3):
state.append_history({
'history_id': f'terminal-{index}', 'instance_id': 'instance-1',
'slot_id': 1, 'reservation_id': 100 + index,
'source': 'gitlab', 'outcome': 'bundle_accepted',
'receipt': {'padding': 'y' * 700}, 'started_at': UTC,
'completed_at': UTC, 'duration_seconds': 0.0,
'first_sequence': None, 'last_sequence': None,
'diagnostics': [], 'timeline': [], 'phase_durations': {},
})
event_segments = [path for _first, _last, path in state._closed_event_paths()]
history_segments = [path for _index, path in state._closed_history_paths()]
self.assertTrue(event_segments)
self.assertTrue(history_segments)
old = time.time() - 172800
for path in event_segments + history_segments:
os.utime(path, (old, old))
usage = state.retention_usage()
self.assertEqual(usage['categories']['events']['evictable_bytes'], 0)
self.assertEqual(usage['categories']['history']['evictable_bytes'], 0)
state.cleanup_retention()
self.assertTrue(all(os.path.exists(path) for path in event_segments))
self.assertTrue(all(os.path.exists(path) for path in history_segments))
self.assertEqual(len(state.history()), 3)
def test_event_retention_usage_stops_at_recent_earlier_segment(self):
with tempfile.TemporaryDirectory() as root:
state = WorkerLocalState(
root, event_segment_bytes=1024,
retention_days=1, retention_bytes=1024 * 1024,
)
for index in range(12):
state.emit_phase(
'instance-1', 0, WorkerPhase.IDLE, timestamp=UTC,
progress={'sample': index, 'padding': 'x' * 300},
)
segments = [path for _first, _last, path in state._closed_event_paths()]
self.assertGreaterEqual(len(segments), 2)
old = time.time() - 172800
for path in segments:
os.utime(path, (old, old))
os.utime(segments[0], None)
usage = state.retention_usage()
self.assertEqual(usage['categories']['events']['evictable_bytes'], 0)
state.cleanup_retention()
self.assertTrue(all(os.path.exists(path) for path in segments))
def test_event_retention_usage_stops_at_in_use_earlier_segment(self):
with tempfile.TemporaryDirectory() as root:
state = WorkerLocalState(
root, event_segment_bytes=1024,
retention_days=1, retention_bytes=1024 * 1024,
)
for index in range(12):
state.emit_phase(
'instance-1', 0, WorkerPhase.IDLE, timestamp=UTC,
progress={'sample': index, 'padding': 'x' * 300},
)
segments = [path for _first, _last, path in state._closed_event_paths()]
old = time.time() - 172800
for path in segments:
os.utime(path, (old, old))
state._retain_segment_paths([segments[0]])
try:
usage = state.retention_usage()
self.assertEqual(usage['categories']['events']['evictable_bytes'], 0)
state.cleanup_retention()
self.assertTrue(all(os.path.exists(path) for path in segments))
finally:
state._release_segment_paths([segments[0]])
def test_event_retention_byte_pressure_overrides_recent_age_until_cap(self):
with tempfile.TemporaryDirectory() as root:
state = WorkerLocalState(
root, event_segment_bytes=1024,
retention_days=30, retention_bytes=1024 * 1024,
)
for index in range(12):
state.emit_phase(
'instance-1', 0, WorkerPhase.IDLE, timestamp=UTC,
progress={'sample': index, 'padding': 'x' * 300},
)
segments = [path for _first, _last, path in state._closed_event_paths()]
work = os.path.join(root, 'work-retention')
os.makedirs(work)
atomic_write_private_json(
os.path.join(root, 'control', 'progress-outbox.json'),
{'schema': 1, 'sequence': 12},
)
initial = state.retention_usage()['total_bytes']
first_size = os.path.getsize(segments[0])
filler_size = state.retention_bytes - initial + max(1, first_size // 2)
with open(os.path.join(work, 'active.bin'), 'wb') as handle:
handle.write(b'w' * filler_size)
usage = state.retention_usage({'work': work})
self.assertEqual(
usage['categories']['events']['evictable_bytes'], first_size,
)
state.cleanup_retention({'work': work})
self.assertFalse(os.path.exists(segments[0]))
self.assertTrue(all(os.path.exists(path) for path in segments[1:]))
self.assertTrue(os.path.exists(os.path.join(work, 'active.bin')))
def test_retention_never_deletes_past_a_protected_event_segment(self):
with tempfile.TemporaryDirectory() as root:
state = WorkerLocalState(
root, event_segment_bytes=1024,
retention_days=1, retention_bytes=1024 * 1024,
)
for index in range(12):
state.emit_phase(
'instance-1', 0, WorkerPhase.IDLE, timestamp=UTC,
progress={'sample': index, 'padding': 'x' * 300},
)
segments = state._closed_event_paths()
self.assertGreaterEqual(len(segments), 2)
protected = os.path.abspath(segments[0][2])
old = time.time() - 172800
for _first, _last, path in segments:
os.utime(path, (old, old))
def evictable(path, *_args):
return os.path.abspath(path) != protected
with mock.patch.object(
state, '_event_segment_is_evictable', side_effect=evictable,
):
usage = state.retention_usage()
self.assertEqual(usage['categories']['events']['evictable_bytes'], 0)
state.cleanup_retention()
self.assertTrue(all(os.path.exists(path) for _first, _last, path in segments))
restarted = WorkerLocalState(root, event_segment_bytes=1024)
self.assertEqual(restarted.next_sequence, 13)
def test_progress_outbox_cursor_protects_newer_segments_in_usage_and_cleanup(self):
with tempfile.TemporaryDirectory() as root:
state = WorkerLocalState(
root, event_segment_bytes=1024,
retention_days=1, retention_bytes=1024 * 1024,
)
for index in range(18):
state.emit_phase(
'instance-1', 0, WorkerPhase.ASSIGNED,
reservation_id=7, source='gitlab', timestamp=UTC,
progress={'sample': index, 'padding': 'x' * 300},
)
segments = state._closed_event_paths()
self.assertGreaterEqual(len(segments), 3)
old = time.time() - 172800
for _first, _last, path in segments:
os.utime(path, (old, old))
cursor = segments[0][1]
atomic_write_private_json(
os.path.join(root, 'control', 'progress-outbox.json'),
{'schema': 1, 'sequence': cursor},
)
with mock.patch.object(
state, '_event_segment_is_evictable', return_value=True,
):
usage = state.retention_usage()
self.assertEqual(
usage['categories']['events']['evictable_files'], 1,
)
self.assertEqual(
usage['progress_outbox']['cursor_sequence'], cursor,
)
state.cleanup_retention()
self.assertFalse(os.path.exists(segments[0][2]))
self.assertTrue(all(
os.path.exists(path) for _first, _last, path in segments[1:]
))
def test_old_root_progress_cursor_migrates_before_retention(self):
with tempfile.TemporaryDirectory() as root:
state = WorkerLocalState(root, event_segment_bytes=1024)
for index in range(12):
state.emit_phase(
'instance-1', 0, WorkerPhase.IDLE, timestamp=UTC,
progress={'sample': index, 'padding': 'x' * 300},
)
old_path = os.path.join(root, 'progress-outbox.json')
atomic_write_private_json(old_path, {'schema': 1, 'sequence': 7})
path, sequence = worker_local_state.prepare_progress_outbox_cursor(root)
self.assertEqual(sequence, 7)
self.assertFalse(os.path.exists(old_path))
self.assertEqual(
json.load(open(path, encoding='utf-8'))['sequence'], 7,
)
self.assertEqual(
state.retention_usage()['progress_outbox']['cursor_sequence'], 7,
)
def test_missing_or_conflicting_progress_cursor_protects_journal(self):
with tempfile.TemporaryDirectory() as root:
state = WorkerLocalState(
root, event_segment_bytes=1024,
retention_days=1, retention_bytes=1024 * 1024,
)
for index in range(12):
state.emit_phase(
'instance-1', 0, WorkerPhase.IDLE, timestamp=UTC,
progress={'sample': index, 'padding': 'x' * 300},
)
old = time.time() - 172800
for _first, _last, path in state._closed_event_paths():
os.utime(path, (old, old))
self.assertEqual(
state.retention_usage()['categories']['events']['evictable_files'],
0,
)
atomic_write_private_json(
os.path.join(root, 'progress-outbox.json'),
{'schema': 1, 'sequence': 3},
)
atomic_write_private_json(
os.path.join(root, 'control', 'progress-outbox.json'),
{'schema': 1, 'sequence': 9},
)
with self.assertRaisesRegex(
WorkerLocalStateError, 'conflicting progress outbox cursors',
):
worker_local_state.prepare_progress_outbox_cursor(root)
self.assertEqual(
state.retention_usage()['progress_outbox']['cursor_sequence'], 0,
)
self.assertEqual(
state.retention_usage()['categories']['events']['evictable_files'],
0,
)
if __name__ == '__main__':
unittest.main()