import copy from pathlib import Path import sys import unittest ROOT = Path(__file__).resolve().parents[1] APP_DIR = ROOT / 'app' sys.path.insert(0, str(APP_DIR)) import docker_depth_experiment as depth from tests.test_docker_depth_experiment import valid_config class DockerDepthResolverRefundTests(unittest.TestCase): def setUp(self): validated = depth.validate_docker_depth_config( valid_config(enabled=True), managed_postgres=True, final_cutover=True, ) self.experiment = validated.experiment self.policy_sha256 = 'a' * 64 self.authority = depth._docker_depth_authority( self.experiment, self.policy_sha256, ) def _entry(self, *, work_state='pending', attempts=2, last_error=None): target = 'owner/repository' last_error = last_error or depth.DOCKER_DEPTH_RESOLVER_REFUND_OLD_ERROR row = { 'id': 21, 'effective_repository_queue_id': 31, 'query_ordinal': 2, 'repository_rank': 1, 'work_state': work_state, 'resolver_attempts': attempts, 'last_error_code': last_error, 'normalized_target': target, } line = ( f'Unable to fetch Docker Hub tags for {target}: ' f'{depth.DOCKER_DEPTH_RESOLVER_REFUND_OLD_ERROR}' ) return depth._docker_depth_resolver_refund_entry(row, [line, line]) def _manifest(self, entries): manifest = { 'schema': 1, 'type': depth.DOCKER_DEPTH_RESOLVER_REFUND_MANIFEST_TYPE, 'version': 1, 'experiment_id': 1, 'experiment_key': self.authority['experiment_key'], 'source': self.authority['source'], 'config_sha256': self.authority['config_sha256'], 'ordered_queries_sha256': self.authority['ordered_queries_sha256'], 'selector_sha256': self.authority['selector_sha256'], 'provenance_policy_sha256': self.authority['provenance_policy_sha256'], 'plan_sha256': 'b' * 64, 'hold_reason_code': 'resolver_attempt_limit', 'recovery_kind': depth.DOCKER_DEPTH_RESOLVER_REFUND_KIND, 'refund_attempts': 2, 'evidence_log_name': 'dockerhub.log', 'evidence_log_sha256': 'c' * 64, 'entry_count': len(entries), 'held_entry_count': sum( item['prior_work_state'] == 'held' for item in entries ), 'selection_sha256': depth._canonical_sha256(entries), 'entries': entries, } return manifest def test_entry_requires_exactly_two_target_bound_old_bug_events(self): entry = self._entry() self.assertEqual(entry['refund_attempts'], 2) self.assertEqual(entry['next_resolver_attempts'], 0) self.assertNotIn('target', entry) self.assertNotIn('last_error_code', entry) target = 'owner/repository' row = { 'id': 21, 'effective_repository_queue_id': 31, 'query_ordinal': 2, 'repository_rank': 1, 'work_state': 'pending', 'resolver_attempts': 2, 'last_error_code': depth.DOCKER_DEPTH_RESOLVER_REFUND_OLD_ERROR, 'normalized_target': target, } unrelated = ( 'Unable to fetch Docker Hub tags for another/repository: ' + depth.DOCKER_DEPTH_RESOLVER_REFUND_OLD_ERROR ) self.assertIsNone(depth._docker_depth_resolver_refund_entry( row, [unrelated, unrelated], )) def test_manifest_accepts_one_held_entry_and_rejects_refund_drift(self): held = self._entry( work_state='held', attempts=3, last_error='resolver_attempt_limit', ) manifest = self._manifest([held]) normalized, digest = depth.validate_docker_depth_resolver_refund_manifest( manifest, self.experiment, self.policy_sha256, ) self.assertEqual(normalized, manifest) self.assertRegex(digest, r'^[a-f0-9]{64}$') changed = copy.deepcopy(manifest) changed['refund_attempts'] = 3 with self.assertRaisesRegex(ValueError, 'evidence conflicts'): depth.validate_docker_depth_resolver_refund_manifest( changed, self.experiment, self.policy_sha256, ) if __name__ == '__main__': unittest.main()