# Author: Sandeep Belgavi import tempfile import unittest from pathlib import Path from pattern_07 import Workflow, FakeInspector, demo class WorkflowTests(unittest.TestCase): def setUp(self): self.tmp = tempfile.TemporaryDirectory() self.path = Path(self.tmp.name) / 'state.db' self.flow = Workflow(self.path) self.provider = FakeInspector() self.flow.start('inc') def tearDown(self): self.flow.close() self.tmp.cleanup() def test_restart_checkpoint(self): self.flow.advance('inc', self.provider) self.flow.close() self.flow = Workflow(self.path) self.flow.advance('inc', self.provider) self.assertEqual(self.provider.calls, 1) def test_read_retry_after_crash(self): with self.assertRaises(RuntimeError): self.flow.advance('inc', self.provider, True) self.assertEqual(self.flow.status('inc')['step'], 0) self.flow.advance('inc', self.provider) self.assertEqual(self.provider.calls, 2) def test_atomic_receipt(self): self.flow.advance('inc', self.provider) with self.assertRaises(RuntimeError): self.flow.advance('inc', self.provider, True) self.assertEqual(self.flow.db.execute('SELECT count(*) FROM receipts').fetchone()[0], 0) self.assertEqual(self.flow.status('inc')['step'], 1) def test_completed_noop(self): for _ in range(4): self.flow.advance('inc', self.provider) self.assertEqual(self.flow.db.execute('SELECT count(*) FROM receipts').fetchone()[0], 1) def test_version_guard(self): self.flow.close() self.flow = Workflow(self.path, 'v2') with self.assertRaises(ValueError): self.flow.status('inc') def test_missing_run(self): with self.assertRaises(KeyError): self.flow.advance('missing', self.provider) def test_invalid_provider(self): class Bad: def inspect(self, run_id): return {'summary': 1} with self.assertRaises(ValueError): self.flow.advance('inc', Bad()) self.assertEqual(self.flow.status('inc')['step'], 0) def test_demo(self): self.assertEqual(demo(), {'step': 2, 'provider_calls': 1, 'receipts': 1}) if __name__ == '__main__': unittest.main()