# HG changeset patch # User Dan Villiom Podlaski Christiansen # Date 1323817678 -3600 # Node ID 3bfb7e985c4739d7335b9ebbe744056fa28bedbf # Parent 7a98fbadcae985374d481c4beb2ecc3eb6d42d2a svn verify: add a test for corrupt repositories. This case contains a couple of unlikely (but not impossible) failure cases that the code previously did not handle. The verifier is updated to address these, and the output made a bit more consistent. diff --git a/hgsubversion/svncommands.py b/hgsubversion/svncommands.py --- a/hgsubversion/svncommands.py +++ b/hgsubversion/svncommands.py @@ -66,24 +66,21 @@ def verify(ui, repo, args=None, **opts): except error.LookupError: result = 1 continue - dmatch = fctx.data() == data - mmatch = fctx.flags() == mode - if not (dmatch and mmatch): - ui.write('difference in file %s\n' % fn) + if not fctx.data() == data: + ui.write('difference in: %s\n' % fn) + result = 1 + if not fctx.flags() == mode: + ui.write('wrong flags for: %s\n' % fn) result = 1 hgfiles = set(ctx) - util.ignoredfiles if hgfiles != svnfiles: unexpected = hgfiles - svnfiles - if unexpected: - ui.write('unexpected files:\n') - for f in sorted(unexpected): - ui.write(' %s\n' % f) + for f in sorted(unexpected): + ui.write('unexpected file: %s\n' % f) missing = svnfiles - hgfiles - if missing: - ui.write('missing files:\n') - for f in sorted(missing): - ui.write(' %s\n' % f) + for f in sorted(missing): + ui.write('missing file: %s\n' % f) result = 1 util.progress(ui, 'verify', None) diff --git a/tests/comprehensive/test_stupid_pull.py b/tests/comprehensive/test_stupid_pull.py --- a/tests/comprehensive/test_stupid_pull.py +++ b/tests/comprehensive/test_stupid_pull.py @@ -45,6 +45,8 @@ def buildmethod(case, name, layout): attrs = {'_do_case': _do_case, } for case in (f for f in os.listdir(test_util.FIXTURES) if f.endswith('.svndump')): + if case == 'corrupt.svndump': + continue name = 'test_' + case[:-len('.svndump')] # Automatic layout branchtag collision exposes a minor defect # here, but since it isn't a regression we suppress the test case. diff --git a/tests/comprehensive/test_verify_and_startrev.py b/tests/comprehensive/test_verify_and_startrev.py --- a/tests/comprehensive/test_verify_and_startrev.py +++ b/tests/comprehensive/test_verify_and_startrev.py @@ -21,6 +21,8 @@ from hgsubversion import svncommands 'binaryfiles.svndump', 'binaryfiles-broken.svndump', 'emptyrepo.svndump', + 'correct.svndump', + 'corrupt.svndump', ]) _skipall = set([ @@ -29,6 +31,8 @@ from hgsubversion import svncommands _skipstandard = set([ 'subdir_is_file_prefix.svndump', + 'correct.svndump', + 'corrupt.svndump', ]) def _do_case(self, name, stupid, layout): diff --git a/tests/fixtures/correct.svndump b/tests/fixtures/correct.svndump new file mode 100644 --- /dev/null +++ b/tests/fixtures/correct.svndump @@ -0,0 +1,103 @@ +SVN-fs-dump-format-version: 2 + +UUID: 00000000-0000-0000-0000-000000000000 + +Revision-number: 0 +Prop-content-length: 56 +Content-length: 56 + +K 8 +svn:date +V 27 +2010-11-30T15:10:25.898546Z +PROPS-END + +Revision-number: 1 +Prop-content-length: 100 +Content-length: 100 + +K 7 +svn:log +V 0 + +K 10 +svn:author +V 6 +danchr +K 8 +svn:date +V 27 +2010-11-30T15:16:01.077550Z +PROPS-END + +Node-path: empty-file +Node-kind: file +Node-action: add +Prop-content-length: 10 +Text-content-length: 0 +Text-content-md5: d41d8cd98f00b204e9800998ecf8427e +Text-content-sha1: da39a3ee5e6b4b0d3255bfef95601890afd80709 +Content-length: 10 + +PROPS-END + + +Node-path: executable-file +Node-kind: file +Node-action: add +Prop-content-length: 36 +Text-content-length: 11 +Text-content-md5: 01839ba8c81c3b2c7486607e0c683e62 +Text-content-sha1: 5e70f8a25fe8ad4ad971bfd3388c258b019268d4 +Content-length: 47 + +K 14 +svn:executable +V 1 +* +PROPS-END +Executable + + +Node-path: regular-file +Node-kind: file +Node-action: add +Prop-content-length: 10 +Text-content-length: 10 +Text-content-md5: 2e01b7f4ab0c18c05a3059eb2e2420d9 +Text-content-sha1: 6e530e985be313a43dc9734251656be8f0c94ab8 +Content-length: 20 + +PROPS-END +Contents. + + +Node-path: another-regular-file +Node-kind: file +Node-action: add +Prop-content-length: 10 +Text-content-length: 10 +Text-content-md5: 2e01b7f4ab0c18c05a3059eb2e2420d9 +Text-content-sha1: 6e530e985be313a43dc9734251656be8f0c94ab8 +Content-length: 20 + +PROPS-END +Contents. + + +Node-path: symlink +Node-kind: file +Node-action: add +Prop-content-length: 33 +Text-content-length: 6 +Text-content-md5: 654580f41818cd6f51408c7cbd313728 +Text-content-sha1: 130b8faaf3e1acc1b95f77ac835e9c8b6eee5c96 +Content-length: 39 + +K 11 +svn:special +V 1 +* +PROPS-END +link A + diff --git a/tests/fixtures/corrupt.svndump b/tests/fixtures/corrupt.svndump new file mode 100644 --- /dev/null +++ b/tests/fixtures/corrupt.svndump @@ -0,0 +1,97 @@ +SVN-fs-dump-format-version: 2 + +UUID: 00000000-0000-0000-0000-000000000000 + +Revision-number: 0 +Prop-content-length: 56 +Content-length: 56 + +K 8 +svn:date +V 27 +2010-11-30T15:10:25.898546Z +PROPS-END + +Revision-number: 1 +Prop-content-length: 100 +Content-length: 100 + +K 10 +svn:author +V 6 +danchr +K 8 +svn:date +V 27 +2010-11-30T15:16:01.077550Z +K 7 +svn:log +V 0 + +PROPS-END + +Node-path: another-regular-file +Node-kind: file +Node-action: add +Prop-content-length: 10 +Text-content-length: 0 +Text-content-md5: d41d8cd98f00b204e9800998ecf8427e +Text-content-sha1: da39a3ee5e6b4b0d3255bfef95601890afd80709 +Content-length: 10 + +PROPS-END + + +Node-path: executable-file +Node-kind: file +Node-action: add +Prop-content-length: 10 +Text-content-length: 11 +Text-content-md5: 01839ba8c81c3b2c7486607e0c683e62 +Text-content-sha1: 5e70f8a25fe8ad4ad971bfd3388c258b019268d4 +Content-length: 21 + +PROPS-END +Executable + + +Node-path: missing-file +Node-kind: file +Node-action: add +Prop-content-length: 10 +Text-content-length: 0 +Text-content-md5: d41d8cd98f00b204e9800998ecf8427e +Text-content-sha1: da39a3ee5e6b4b0d3255bfef95601890afd80709 +Content-length: 10 + +PROPS-END + + +Node-path: regular-file +Node-kind: file +Node-action: add +Prop-content-length: 33 +Text-content-length: 18 +Text-content-md5: adf66a0cec83e25644c63f3c3007ae7c +Text-content-sha1: 047e6e482d0c9cb812f89d18a9f07a43caab76bb +Content-length: 51 + +K 11 +svn:special +V 1 +* +PROPS-END +link Bad contents. + +Node-path: symlink +Node-kind: file +Node-action: add +Prop-content-length: 10 +Text-content-length: 1 +Text-content-md5: 7fc56270e7a70fa81a5935b72eacbe29 +Text-content-sha1: 6dcd4ce23d88e2ee9568ba546c007c63d9131c1b +Content-length: 11 + +PROPS-END +A + diff --git a/tests/test_rebuildmeta.py b/tests/test_rebuildmeta.py --- a/tests/test_rebuildmeta.py +++ b/tests/test_rebuildmeta.py @@ -101,11 +101,16 @@ def buildmethod(case, name, stupid, sing return m +skip = set([ + 'project_root_not_repo_root.svndump', + 'corrupt.svndump', +]) + attrs = {'_do_case': _do_case, } for case in [f for f in os.listdir(test_util.FIXTURES) if f.endswith('.svndump')]: # this fixture results in an empty repository, don't use it - if case == 'project_root_not_repo_root.svndump': + if case in skip: continue bname = 'test_' + case[:-len('.svndump')] attrs[bname] = buildmethod(case, bname, False, False) diff --git a/tests/test_utility_commands.py b/tests/test_utility_commands.py --- a/tests/test_utility_commands.py +++ b/tests/test_utility_commands.py @@ -260,13 +260,46 @@ class UtilityTests(test_util.TestBase): output = re.sub(r'file://\S+', 'file://', output) self.assertMultiLineEqual("""\ verifying d51f46a715a1 against file:// -difference in file binary2 -unexpected files: - binary1 -missing files: - binary3 +difference in: binary2 +unexpected file: binary1 +missing file: binary3 """, output) + def test_svnverify_corruption(self): + SUCCESS = 0 + FAILURE = 1 + + repo, repo_path = self.load_and_fetch('correct.svndump', layout='single', + subdir='') + + ui = self.ui() + + self.assertEqual(SUCCESS, svncommands.verify(ui, self.repo, rev='tip')) + + corrupt_source = test_util.fileurl(self.load_svndump('corrupt.svndump')) + + repo.ui.setconfig('paths', 'default', corrupt_source) + + ui.pushbuffer() + code = svncommands.verify(ui, repo, rev='tip') + actual = ui.popbuffer() + + actual = actual.replace(corrupt_source, '$REPO') + actual = set(actual.splitlines()) + + expected = set([ + 'verifying 78e965230a13 against $REPO@1', + 'missing file: missing-file', + 'wrong flags for: executable-file', + 'wrong flags for: symlink', + 'wrong flags for: regular-file', + 'difference in: another-regular-file', + 'difference in: regular-file', + 'unexpected file: empty-file', + ]) + + self.assertEqual((FAILURE, expected), (code, actual)) + def suite(): all_tests = [unittest.TestLoader().loadTestsFromTestCase(UtilityTests), ]