Files
chimera-gfx-Public/tests/test_phase10am_bounded_copy_model.py
T
Chimera GFX release export a6037502d7
phase0-ci / build-and-audit (push) Successful in 2m14s
Publish Chimera GFX source
2026-09-03 03:27:14 +02:00

104 lines
5.0 KiB
Python

#!/usr/bin/env python3
# SPDX-License-Identifier: GPL-3.0-or-later
"""Failure-injection tests for Phase-1.0AM bounded copy/restore."""
from __future__ import annotations
import argparse
from pathlib import Path
import sys
import unittest
PARSER = argparse.ArgumentParser()
PARSER.add_argument("--root", type=Path, required=True)
ROOT = PARSER.parse_args().root
sys.path.insert(0, str(ROOT / "tools"))
from phase10am_bounded_copy_model import * # noqa: E402,F403
def prefix() -> list[FakeCopyEvent]:
return [FakeCopyEvent(BACKUP_AUTHID, OK), FakeCopyEvent(BACKUP_CAPS, OK),
FakeCopyEvent(SET_PRIV_AUTHID, OK), FakeCopyEvent(SET_PRIV_CAPS, OK)]
class BoundedCopyTests(unittest.TestCase):
def test_exact_multichunk_success_restores_both_fields(self) -> None:
events = prefix() + [FakeCopyEvent(COPY_CHUNK, OK, 4, MORE),
FakeCopyEvent(COPY_CHUNK, OK, 6, COMPLETE),
FakeCopyEvent(RESTORE_CAPS, OK),
FakeCopyEvent(RESTORE_AUTHID, OK)]
result = run_copy(CopyPlan(100, 200, 10), FakeCopyFacade(tuple(events)))
self.assertTrue(result.success)
self.assertEqual(result.copied, 10)
self.assertTrue(result.child_alive)
self.assertFalse(result.target_copy_performed)
self.assertTrue(result.service_available)
def test_partial_error_is_reported_and_child_is_reaped(self) -> None:
events = prefix() + [FakeCopyEvent(COPY_CHUNK, OK, 4, MORE),
FakeCopyEvent(COPY_CHUNK, ERROR, 0, MORE),
FakeCopyEvent(RESTORE_CAPS, OK),
FakeCopyEvent(RESTORE_AUTHID, OK),
FakeCopyEvent(KILL_AND_REAP_CHILD, OK)]
result = run_copy(CopyPlan(0, 32, 10), FakeCopyFacade(tuple(events)))
self.assertEqual(result.classification, "OFFLINE_PARTIAL_COPY_CONTAINED")
self.assertEqual(result.copied, 4)
self.assertFalse(result.child_alive)
def test_zero_and_oversized_progress_never_complete(self) -> None:
for progress in (0, 11):
events = prefix() + [FakeCopyEvent(COPY_CHUNK, OK, progress, MORE),
FakeCopyEvent(RESTORE_CAPS, OK),
FakeCopyEvent(RESTORE_AUTHID, OK)]
with self.subTest(progress=progress):
result = run_copy(CopyPlan(0, 32, 10), FakeCopyFacade(tuple(events)))
self.assertFalse(result.success)
self.assertEqual(result.copied, 0)
def test_both_restores_are_attempted_and_failure_contains_service(self) -> None:
events = prefix() + [FakeCopyEvent(COPY_CHUNK, ERROR, 0, MORE),
FakeCopyEvent(RESTORE_CAPS, ERROR),
FakeCopyEvent(RESTORE_AUTHID, ERROR),
FakeCopyEvent(KILL_AND_REAP_CHILD, OK),
FakeCopyEvent(TERMINATE_SERVICE, OK)]
result = run_copy(CopyPlan(0, 32, 10), FakeCopyFacade(tuple(events)))
self.assertEqual(result.restore_failure_bits, 3)
self.assertFalse(result.child_alive or result.service_available)
def test_caps_set_failure_still_restores_authid(self) -> None:
events = prefix()[:3] + [FakeCopyEvent(SET_PRIV_CAPS, ERROR),
FakeCopyEvent(RESTORE_AUTHID, OK)]
result = run_copy(CopyPlan(0, 32, 10), FakeCopyFacade(tuple(events)))
self.assertEqual(result.classification,
"OFFLINE_COPY_REJECTED_BEFORE_MUTATION")
self.assertTrue(result.child_alive and result.service_available)
def test_restore_or_child_termination_failure_is_hard(self) -> None:
events = prefix() + [FakeCopyEvent(COPY_CHUNK, OK, 1, MORE),
FakeCopyEvent(RESTORE_CAPS, OK),
FakeCopyEvent(RESTORE_AUTHID, OK),
FakeCopyEvent(KILL_AND_REAP_CHILD, ERROR)]
with self.assertRaises(CopyModelError):
run_copy(CopyPlan(0, 32, 10), FakeCopyFacade(tuple(events)))
def test_bounds_deadline_status_and_arithmetic(self) -> None:
for args in ((0, 0, 0), (MAX_U64, 0, 2), (0, MAX_U64, 2)):
with self.subTest(args=args), self.assertRaises(CopyModelError):
CopyPlan(*args)
events = prefix()
events[0] = FakeCopyEvent(BACKUP_AUTHID, OK, ticks=MAX_TICKS)
result = run_copy(CopyPlan(0, 32, 10), FakeCopyFacade(tuple(events[:2])))
self.assertFalse(result.success)
incomplete = prefix() + [FakeCopyEvent(COPY_CHUNK, OK, 9, COMPLETE),
FakeCopyEvent(RESTORE_CAPS, OK),
FakeCopyEvent(RESTORE_AUTHID, OK),
FakeCopyEvent(KILL_AND_REAP_CHILD, OK)]
result = run_copy(CopyPlan(0, 32, 10), FakeCopyFacade(tuple(incomplete)))
self.assertFalse(result.success)
if __name__ == "__main__":
unittest.main(argv=[__file__])