from copy import deepcopy import pytest from railiance_clock import attribution from railiance_clock.client import Clock, FileTrust from railiance_clock.core import ClockError def test_disabled_attribution_does_not_construct_clock(monkeypatch): monkeypatch.delenv('TEST_CLOCK_TRUST', raising=False) def unexpected(_): pytest.fail('unconfigured attribution constructed a clock') monkeypatch.setattr(attribution, '_clock', unexpected) assert attribution.from_environment('TEST_CLOCK_TRUST') == {} def test_recording_evidence_preserves_original_event(setup, monkeypatch): path, _, timer, transport = setup clock = Clock(FileTrust(path), timer=timer, transport=transport) monkeypatch.setenv('TEST_CLOCK_TRUST', str(path)) monkeypatch.setattr(attribution, '_clock', lambda _: clock) event = {'event_id': 'old-event', 'timestamp': '1999-01-01T10:00:00+01:00', 'clock_domain': 'old-boot', 'sequence': 7, 'predecessors': ['earlier']} original = deepcopy(event) evidence = attribution.from_environment('TEST_CLOCK_TRUST') enriched = {**event, **evidence} assert event == original assert all(enriched[k] == v for k, v in original.items()) assert set(evidence) == {'railiance_time'} sample = evidence['railiance_time'] assert sample['kind'] == 'recording_time' and sample['status'] == 'usable' assert sample['lower_ns'] <= sample['upper_ns'] assert sample['sample_id'] and sample['authority_id'] == 'railiance01' assert 'occurrence_time' not in sample # A wall-clock label is retained as provenance, not recalibrated by this API. assert enriched['timestamp'] == original['timestamp'] @pytest.mark.parametrize('error', [OSError('secret-path'), ClockError('private reason'), KeyError('private field'), TypeError('private type')]) def test_unavailable_attribution_is_sanitized(monkeypatch, error): monkeypatch.setenv('TEST_CLOCK_TRUST', '/unused') def unavailable(_): raise error monkeypatch.setattr(attribution, '_clock', unavailable) assert attribution.from_environment('TEST_CLOCK_TRUST') == { 'railiance_time': {'status': 'unavailable', 'kind': 'recording_time'}} def test_expired_cached_clock_never_returns_old_evidence(setup, monkeypatch): path, _, timer, transport = setup clock = Clock(FileTrust(path), timer=timer, transport=transport) monkeypatch.setenv('TEST_CLOCK_TRUST', str(path)) monkeypatch.setattr(attribution, '_clock', lambda _: clock) assert attribution.from_environment('TEST_CLOCK_TRUST')['railiance_time']['status'] == 'usable' timer.n = 61_000_000_000 assert attribution.from_environment('TEST_CLOCK_TRUST') == { 'railiance_time': {'status': 'unavailable', 'kind': 'recording_time'}}