test_integration.py python
110 lines 4.4 KB
Raw
sha256:91e875d4a97bb1e35f37992f803988d5713931f1782d870c371c50054574af22 Add fixture provenance retention deletion Human minor ⚠ breaking 43 days ago
1 """Integration tier tests for Scooling Lab API and BOM generation."""
2
3 from __future__ import annotations
4
5 from datetime import UTC, datetime, timedelta
6 import unittest
7
8 from scooling_lab_helpers import PROJECT_ROOT, valid_payload
9
10 from scooling_lab.bom import collect_entries, render_markdown
11 from scooling_lab.errors import ApiError
12 from scooling_lab.provenance import validate_provenance_record
13 from scooling_lab.service import TrainingApiService
14 from scooling_lab.store import TrainingJobStore
15
16
17 class ScoolingLabIntegrationTests(unittest.TestCase):
18 """Integration tests spanning service, fake worker, store, and BOM."""
19
20 def test_integration_api_to_fake_worker_lifecycle(self) -> None:
21 """createTrainingJob completes through the fake worker and lists metadata."""
22
23 service = TrainingApiService(TrainingJobStore())
24 created = service.create_training_job(valid_payload("integration"))
25 self.assertEqual(created["status"], "succeeded")
26 job_id = str(created["id"])
27
28 fetched = service.get_training_job(job_id)
29 self.assertEqual(fetched["id"], job_id)
30 self.assertEqual(fetched["status"], "succeeded")
31
32 artifacts = service.list_artifacts(job_id)
33 self.assertEqual(len(artifacts["artifacts"]), 1)
34 artifact = artifacts["artifacts"][0]
35 self.assertEqual(artifact["jobId"], job_id)
36 self.assertTrue(str(artifact["datasetHash"]))
37 self.assertTrue(str(artifact["artifactHash"]))
38 self.assertTrue(str(artifact["provenanceRecordId"]))
39
40 def test_integration_fake_worker_emits_valid_provenance(self) -> None:
41 """Worker completion writes a schema-valid provenance record."""
42
43 service = TrainingApiService(TrainingJobStore())
44 created = service.create_training_job(valid_payload("provenance-integration"))
45 job_id = str(created["id"])
46
47 provenance = service.get_provenance(job_id)
48
49 validate_provenance_record(provenance)
50 self.assertEqual(provenance["jobId"], job_id)
51 self.assertEqual(provenance["baseModelId"], "fixture-tiny-llm")
52
53 def test_integration_deletion_cascades_store_and_provenance(self) -> None:
54 """deleteArtifact removes artifact metadata and provenance together."""
55
56 service = TrainingApiService(TrainingJobStore())
57 created = service.create_training_job(valid_payload("delete-integration"))
58 job_id = str(created["id"])
59 artifact = service.list_artifacts(job_id)["artifacts"][0]
60 artifact_id = str(artifact["id"])
61 deleted_hashes = (
62 str(artifact["datasetHash"]),
63 str(artifact["artifactHash"]),
64 str(service.get_provenance(job_id)["trainingConfigHash"]),
65 )
66
67 receipt = service.delete_artifact(job_id, artifact_id)
68
69 self.assertTrue(receipt["deleted"])
70 self.assertTrue(service.verify_deleted_artifact_absence(deleted_hashes))
71 self.assertEqual(service.list_artifacts(job_id)["artifacts"], [])
72 with self.assertRaises(ApiError):
73 service.get_provenance(job_id)
74
75 def test_integration_sweep_over_mixed_policy_fixtures(self) -> None:
76 """Explicit sweep deletes expired artifacts and keeps unexpired artifacts."""
77
78 service = TrainingApiService(TrainingJobStore())
79 expired = service.create_training_job(
80 valid_payload(
81 "sweep-expired",
82 {"policyClass": "ephemeral", "ttlSeconds": 60},
83 )
84 )
85 retained = service.create_training_job(
86 valid_payload(
87 "sweep-retained",
88 {"policyClass": "extended", "ttlSeconds": 86_400},
89 )
90 )
91 sweep_at = datetime.now(UTC) + timedelta(seconds=120)
92
93 summary = service.sweep_expired_artifacts(sweep_at)
94
95 self.assertEqual(summary["deletedCount"], 1)
96 self.assertEqual(service.get_training_job(str(expired["id"]))["status"], "deleted")
97 self.assertEqual(service.get_training_job(str(retained["id"]))["status"], "succeeded")
98
99 def test_integration_bom_generation_over_real_project_files(self) -> None:
100 """The real project pyproject and lockfile generate an allowlisted BOM."""
101
102 entries = collect_entries(PROJECT_ROOT)
103 markdown = render_markdown(entries)
104 self.assertIn("scooling-lab", markdown)
105 self.assertIn("Apache-2.0", markdown)
106 self.assertNotIn("AGPL-3.0 |", markdown)
107
108
109 if __name__ == "__main__":
110 unittest.main()
File History 1 commit
sha256:91e875d4a97bb1e35f37992f803988d5713931f1782d870c371c50054574af22 Add fixture provenance retention deletion Human minor 43 days ago