diff options
-rw-r--r-- | gemato/verify.py | 44 | ||||
-rw-r--r-- | tests/test_verify.py | 99 |
2 files changed, 143 insertions, 0 deletions
diff --git a/gemato/verify.py b/gemato/verify.py index 14052eb..a34264e 100644 --- a/gemato/verify.py +++ b/gemato/verify.py @@ -125,6 +125,50 @@ def verify_path(path, e): return (True, []) +def verify_entry_compatibility(e1, e2): + """ + Verify that the two entries @e1 and @e2 are compatible. + + If the entries are compatible, returns (True, diff). Otherwise, + returns (False, diff). Here diff is a list of differences between + @e1 and @e2. Each list element is a tuple of (name, e1, e2). + + In case of successful comparison, the diff may contain additional + hashes that are present only in one of the entries. + """ + + assert e1.path == e2.path + assert isinstance(e1, gemato.manifest.ManifestPathEntry) + assert isinstance(e2, gemato.manifest.ManifestPathEntry) + + # 1. compare types + t1 = e1.tag + t2 = e2.tag + if t1 != t2: + # all those tags have compatible semantics + COMPATIBLE_TAGS = ('MANIFEST', 'DATA', 'EBUILD', 'AUX') + if t1 not in COMPATIBLE_TAGS or t2 not in COMPATIBLE_TAGS: + return (False, [('__type__', t1, t2)]) + + # 2. compare sizes + if e1.size != e2.size: + return (False, [('__size__', e1.size, e2.size)]) + + # 3. compare checksums + hashes = frozenset(e1.checksums) | frozenset(e2.checksums) + ret = True + diff = [] + for h in sorted(hashes): + h1 = e1.checksums.get(h) + h2 = e2.checksums.get(h) + if h1 != h2: + diff.append((h, h1, h2)) + if h1 is not None and h2 is not None: + ret = False + + return (ret, diff) + + class ManifestMismatch(Exception): """ An exception raised for verification failure. diff --git a/tests/test_verify.py b/tests/test_verify.py index 5f3e492..837fa16 100644 --- a/tests/test_verify.py +++ b/tests/test_verify.py @@ -435,3 +435,102 @@ class ExceptionVerificationTest(object): def testNone(self): self.assertRaises(gemato.verify.ManifestMismatch, gemato.verify.gemato.verify.assert_path_verifies, self.path, None) + + +class EntryCompatibilityVerificationTest(unittest.TestCase): + def test_matching_entry(self): + e1 = gemato.manifest.ManifestEntryDATA.from_list( + ('DATA', 'test', '0', 'MD5', 'd41d8cd98f00b204e9800998ecf8427e')) + e2 = gemato.manifest.ManifestEntryDATA.from_list( + ('DATA', 'test', '0', 'MD5', 'd41d8cd98f00b204e9800998ecf8427e')) + self.assertEqual(gemato.verify.verify_entry_compatibility(e1, e2), + (True, [])) + + def test_compatible_types(self): + e1 = gemato.manifest.ManifestEntryDATA.from_list( + ('DATA', 'test', '0', 'MD5', 'd41d8cd98f00b204e9800998ecf8427e')) + e2 = gemato.manifest.ManifestEntryEBUILD.from_list( + ('EBUILD', 'test', '0', 'MD5', 'd41d8cd98f00b204e9800998ecf8427e')) + self.assertEqual(gemato.verify.verify_entry_compatibility(e1, e2), + (True, [])) + + def test_compatible_types_AUX(self): + e1 = gemato.manifest.ManifestEntryDATA.from_list( + ('DATA', 'files/test.patch', '0', 'MD5', 'd41d8cd98f00b204e9800998ecf8427e')) + e2 = gemato.manifest.ManifestEntryAUX.from_list( + ('AUX', 'test.patch', '0', 'MD5', 'd41d8cd98f00b204e9800998ecf8427e')) + self.assertEqual(gemato.verify.verify_entry_compatibility(e1, e2), + (True, [])) + + def test_compatible_types_MANIFEST(self): + e1 = gemato.manifest.ManifestEntryDATA.from_list( + ('DATA', 'test', '0', 'MD5', 'd41d8cd98f00b204e9800998ecf8427e')) + e2 = gemato.manifest.ManifestEntryMANIFEST.from_list( + ('MANIFEST', 'test', '0', 'MD5', 'd41d8cd98f00b204e9800998ecf8427e')) + self.assertEqual(gemato.verify.verify_entry_compatibility(e1, e2), + (True, [])) + + def test_incompatible_types_DATA_MISC(self): + e1 = gemato.manifest.ManifestEntryDATA.from_list( + ('DATA', 'test', '0', 'MD5', 'd41d8cd98f00b204e9800998ecf8427e')) + e2 = gemato.manifest.ManifestEntryMISC.from_list( + ('MISC', 'test', '0', 'MD5', 'd41d8cd98f00b204e9800998ecf8427e')) + self.assertEqual(gemato.verify.verify_entry_compatibility(e1, e2), + (False, [('__type__', 'DATA', 'MISC')])) + + def test_incompatible_types_DATA_OPTIONAL(self): + e1 = gemato.manifest.ManifestEntryDATA.from_list( + ('DATA', 'test', '0', 'MD5', 'd41d8cd98f00b204e9800998ecf8427e')) + e2 = gemato.manifest.ManifestEntryOPTIONAL.from_list( + ('OPTIONAL', 'test')) + self.assertEqual(gemato.verify.verify_entry_compatibility(e1, e2), + (False, [('__type__', 'DATA', 'OPTIONAL')])) + + def test_incompatible_types_MISC_OPTIONAL(self): + e1 = gemato.manifest.ManifestEntryMISC.from_list( + ('MISC', 'test', '0', 'MD5', 'd41d8cd98f00b204e9800998ecf8427e')) + e2 = gemato.manifest.ManifestEntryOPTIONAL.from_list( + ('OPTIONAL', 'test')) + self.assertEqual(gemato.verify.verify_entry_compatibility(e1, e2), + (False, [('__type__', 'MISC', 'OPTIONAL')])) + + def test_incompatible_types_DATA_IGNORE(self): + e1 = gemato.manifest.ManifestEntryDATA.from_list( + ('DATA', 'test', '0', 'MD5', 'd41d8cd98f00b204e9800998ecf8427e')) + e2 = gemato.manifest.ManifestEntryIGNORE.from_list( + ('IGNORE', 'test')) + self.assertEqual(gemato.verify.verify_entry_compatibility(e1, e2), + (False, [('__type__', 'DATA', 'IGNORE')])) + + def test_incompatible_types_DATA_DIST(self): + e1 = gemato.manifest.ManifestEntryDATA.from_list( + ('DATA', 'test', '0', 'MD5', 'd41d8cd98f00b204e9800998ecf8427e')) + e2 = gemato.manifest.ManifestEntryDIST.from_list( + ('DIST', 'test', '0', 'MD5', 'd41d8cd98f00b204e9800998ecf8427e')) + self.assertEqual(gemato.verify.verify_entry_compatibility(e1, e2), + (False, [('__type__', 'DATA', 'DIST')])) + + def test_mismatched_size(self): + e1 = gemato.manifest.ManifestEntryDATA.from_list( + ('DATA', 'test', '0', 'MD5', 'd41d8cd98f00b204e9800998ecf8427e')) + e2 = gemato.manifest.ManifestEntryDATA.from_list( + ('DATA', 'test', '32', 'MD5', 'd41d8cd98f00b204e9800998ecf8427e')) + self.assertEqual(gemato.verify.verify_entry_compatibility(e1, e2), + (False, [('__size__', 0, 32)])) + + def test_mismatched_md5(self): + e1 = gemato.manifest.ManifestEntryDATA.from_list( + ('DATA', 'test', '0', 'MD5', 'd41d8cd98f00b204e9800998ecf8427e')) + e2 = gemato.manifest.ManifestEntryDATA.from_list( + ('DATA', 'test', '0', 'MD5', '9e107d9d372bb6826bd81d3542a419d6')) + self.assertEqual(gemato.verify.verify_entry_compatibility(e1, e2), + (False, [('MD5', 'd41d8cd98f00b204e9800998ecf8427e', '9e107d9d372bb6826bd81d3542a419d6')])) + + def test_different_hashsets(self): + e1 = gemato.manifest.ManifestEntryDATA.from_list( + ('DATA', 'test', '0', 'MD5', 'd41d8cd98f00b204e9800998ecf8427e')) + e2 = gemato.manifest.ManifestEntryDATA.from_list( + ('DATA', 'test', '0', 'SHA1', 'da39a3ee5e6b4b0d3255bfef95601890afd80709')) + self.assertEqual(gemato.verify.verify_entry_compatibility(e1, e2), + (True, [('MD5', 'd41d8cd98f00b204e9800998ecf8427e', None), + ('SHA1', None, 'da39a3ee5e6b4b0d3255bfef95601890afd80709')])) |