Commit d7f9eae9 authored by Jérome Perrin's avatar Jérome Perrin Committed by GitHub

repozo: exit with non-zero code in case of verification failure (#396)

When verification failed, repozo prints a message on standard error,
but the program always exits with a return code indicating a success.
In case of error it's more natural to exit with an error return code.
parent 891a8a6e
...@@ -11,6 +11,9 @@ ...@@ -11,6 +11,9 @@
- Fix sorting issue in ``scripts/space.py``. - Fix sorting issue in ``scripts/space.py``.
- Fix exit code of ``repozo`` script in case of verification error.
For details see `#396 <https://github.com/zopefoundation/ZODB/pull/396>`_.
5.8.1 (2023-07-18) 5.8.1 (2023-07-18)
================== ==================
......
...@@ -780,15 +780,16 @@ def do_verify(options): ...@@ -780,15 +780,16 @@ def do_verify(options):
filename, options.quick) filename, options.quick)
when_uncompressed = '' when_uncompressed = ''
except OSError: except OSError:
error("%s is missing", filename) raise VerificationFail("%s is missing" % filename)
continue
if size != expected_size: if size != expected_size:
error("%s is %d bytes%s, should be %d bytes", filename, raise VerificationFail(
size, when_uncompressed, expected_size) "%s is %d bytes%s, should be %d bytes" % (
filename, size, when_uncompressed, expected_size))
elif not options.quick: elif not options.quick:
if actual_sum != sum: if actual_sum != sum:
error("%s has checksum %s%s instead of %s", filename, raise VerificationFail(
actual_sum, when_uncompressed, sum) "%s has checksum %s%s instead of %s" % (
filename, actual_sum, when_uncompressed, sum))
def get_checksum_and_size_of_gzipped_file(filename, quick): def get_checksum_and_size_of_gzipped_file(filename, quick):
......
...@@ -998,18 +998,8 @@ class Test_do_recover(OptionsTestBase, unittest.TestCase): ...@@ -998,18 +998,8 @@ class Test_do_recover(OptionsTestBase, unittest.TestCase):
class Test_do_verify(OptionsTestBase, unittest.TestCase): class Test_do_verify(OptionsTestBase, unittest.TestCase):
def _callFUT(self, options): def _callFUT(self, options):
from ZODB.scripts import repozo from ZODB.scripts.repozo import do_verify
errors = [] do_verify(options)
orig_error = repozo.error
def _error(msg, *args):
errors.append(msg % args)
repozo.error = _error
try:
repozo.do_verify(options)
return errors
finally:
repozo.error = orig_error
def _makeFile(self, hour, min, sec, ext, text=None): def _makeFile(self, hour, min, sec, ext, text=None):
from ZODB.scripts.repozo import _GzipCloser from ZODB.scripts.repozo import _GzipCloser
...@@ -1040,7 +1030,7 @@ class Test_do_verify(OptionsTestBase, unittest.TestCase): ...@@ -1040,7 +1030,7 @@ class Test_do_verify(OptionsTestBase, unittest.TestCase):
2, 3, 4, '.dat', 2, 3, 4, '.dat',
'/backup/2010-05-14-02-03-04.fs 0 3 e1faffb3e614e6c2fba74296962386b7\n' # noqa: E501 line too long '/backup/2010-05-14-02-03-04.fs 0 3 e1faffb3e614e6c2fba74296962386b7\n' # noqa: E501 line too long
'/backup/2010-05-14-04-05-06.deltafs 3 7 f50881ced34c7d9e6bce100bf33dec60\n') # noqa: E501 line too long '/backup/2010-05-14-04-05-06.deltafs 3 7 f50881ced34c7d9e6bce100bf33dec60\n') # noqa: E501 line too long
self.assertEqual(self._callFUT(options), []) self._callFUT(options)
def test_all_is_fine_gzip(self): def test_all_is_fine_gzip(self):
options = self._makeOptions(quick=False) options = self._makeOptions(quick=False)
...@@ -1050,31 +1040,40 @@ class Test_do_verify(OptionsTestBase, unittest.TestCase): ...@@ -1050,31 +1040,40 @@ class Test_do_verify(OptionsTestBase, unittest.TestCase):
2, 3, 4, '.dat', 2, 3, 4, '.dat',
'/backup/2010-05-14-02-03-04.fsz 0 3 e1faffb3e614e6c2fba74296962386b7\n' # noqa: E501 line too long '/backup/2010-05-14-02-03-04.fsz 0 3 e1faffb3e614e6c2fba74296962386b7\n' # noqa: E501 line too long
'/backup/2010-05-14-04-05-06.deltafsz 3 7 f50881ced34c7d9e6bce100bf33dec60\n') # noqa: E501 line too long '/backup/2010-05-14-04-05-06.deltafsz 3 7 f50881ced34c7d9e6bce100bf33dec60\n') # noqa: E501 line too long
self.assertEqual(self._callFUT(options), []) self._callFUT(options)
def test_missing_file(self): def test_missing_file(self):
from ZODB.scripts.repozo import VerificationFail
options = self._makeOptions(quick=True) options = self._makeOptions(quick=True)
self._makeFile(2, 3, 4, '.fs', 'AAA') self._makeFile(2, 3, 4, '.fs', 'AAA')
self._makeFile( self._makeFile(
2, 3, 4, '.dat', 2, 3, 4, '.dat',
'/backup/2010-05-14-02-03-04.fs 0 3 e1faffb3e614e6c2fba74296962386b7\n' # noqa: E501 line too long '/backup/2010-05-14-02-03-04.fs 0 3 e1faffb3e614e6c2fba74296962386b7\n' # noqa: E501 line too long
'/backup/2010-05-14-04-05-06.deltafs 3 7 f50881ced34c7d9e6bce100bf33dec60\n') # noqa: E501 line too long '/backup/2010-05-14-04-05-06.deltafs 3 7 f50881ced34c7d9e6bce100bf33dec60\n') # noqa: E501 line too long
self.assertEqual(self._callFUT(options), self.assertRaisesRegex(
[options.repository + os.path.sep + VerificationFail,
'2010-05-14-04-05-06.deltafs is missing']) '2010-05-14-04-05-06.deltafs is missing',
self._callFUT,
options,
)
def test_missing_file_gzip(self): def test_missing_file_gzip(self):
from ZODB.scripts.repozo import VerificationFail
options = self._makeOptions(quick=True) options = self._makeOptions(quick=True)
self._makeFile(2, 3, 4, '.fsz', 'AAA') self._makeFile(2, 3, 4, '.fsz', 'AAA')
self._makeFile( self._makeFile(
2, 3, 4, '.dat', 2, 3, 4, '.dat',
'/backup/2010-05-14-02-03-04.fsz 0 3 e1faffb3e614e6c2fba74296962386b7\n' # noqa: E501 line too long '/backup/2010-05-14-02-03-04.fsz 0 3 e1faffb3e614e6c2fba74296962386b7\n' # noqa: E501 line too long
'/backup/2010-05-14-04-05-06.deltafsz 3 7 f50881ced34c7d9e6bce100bf33dec60\n') # noqa: E501 line too long '/backup/2010-05-14-04-05-06.deltafsz 3 7 f50881ced34c7d9e6bce100bf33dec60\n') # noqa: E501 line too long
self.assertEqual(self._callFUT(options), self.assertRaisesRegex(
[options.repository + os.path.sep + VerificationFail,
'2010-05-14-04-05-06.deltafsz is missing']) '2010-05-14-04-05-06.deltafsz is missing',
self._callFUT,
options,
)
def test_bad_size(self): def test_bad_size(self):
from ZODB.scripts.repozo import VerificationFail
options = self._makeOptions(quick=False) options = self._makeOptions(quick=False)
self._makeFile(2, 3, 4, '.fs', 'AAA') self._makeFile(2, 3, 4, '.fs', 'AAA')
self._makeFile(4, 5, 6, '.deltafs', 'BBB') self._makeFile(4, 5, 6, '.deltafs', 'BBB')
...@@ -1082,12 +1081,15 @@ class Test_do_verify(OptionsTestBase, unittest.TestCase): ...@@ -1082,12 +1081,15 @@ class Test_do_verify(OptionsTestBase, unittest.TestCase):
2, 3, 4, '.dat', 2, 3, 4, '.dat',
'/backup/2010-05-14-02-03-04.fs 0 3 e1faffb3e614e6c2fba74296962386b7\n' # noqa: E501 line too long '/backup/2010-05-14-02-03-04.fs 0 3 e1faffb3e614e6c2fba74296962386b7\n' # noqa: E501 line too long
'/backup/2010-05-14-04-05-06.deltafs 3 7 f50881ced34c7d9e6bce100bf33dec60\n') # noqa: E501 line too long '/backup/2010-05-14-04-05-06.deltafs 3 7 f50881ced34c7d9e6bce100bf33dec60\n') # noqa: E501 line too long
self.assertEqual(self._callFUT(options), self.assertRaisesRegex(
[options.repository + os.path.sep + VerificationFail,
'2010-05-14-04-05-06.deltafs is 3 bytes,' '2010-05-14-04-05-06.deltafs is 3 bytes, should be 4 bytes',
' should be 4 bytes']) self._callFUT,
options,
)
def test_bad_size_gzip(self): def test_bad_size_gzip(self):
from ZODB.scripts.repozo import VerificationFail
options = self._makeOptions(quick=False) options = self._makeOptions(quick=False)
self._makeFile(2, 3, 4, '.fsz', 'AAA') self._makeFile(2, 3, 4, '.fsz', 'AAA')
self._makeFile(4, 5, 6, '.deltafsz', 'BBB') self._makeFile(4, 5, 6, '.deltafsz', 'BBB')
...@@ -1095,13 +1097,18 @@ class Test_do_verify(OptionsTestBase, unittest.TestCase): ...@@ -1095,13 +1097,18 @@ class Test_do_verify(OptionsTestBase, unittest.TestCase):
2, 3, 4, '.dat', 2, 3, 4, '.dat',
'/backup/2010-05-14-02-03-04.fsz 0 3 e1faffb3e614e6c2fba74296962386b7\n' # noqa: E501 line too long '/backup/2010-05-14-02-03-04.fsz 0 3 e1faffb3e614e6c2fba74296962386b7\n' # noqa: E501 line too long
'/backup/2010-05-14-04-05-06.deltafsz 3 7 f50881ced34c7d9e6bce100bf33dec60\n') # noqa: E501 line too long '/backup/2010-05-14-04-05-06.deltafsz 3 7 f50881ced34c7d9e6bce100bf33dec60\n') # noqa: E501 line too long
self.assertEqual( self.assertRaisesRegex(
self._callFUT(options), VerificationFail,
[options.repository + os.path.sep + (
'2010-05-14-04-05-06.deltafsz is 3 bytes (when uncompressed),' '2010-05-14-04-05-06.deltafsz is 3 bytes'
' should be 4 bytes']) r' \(when uncompressed\), should be 4 bytes'
),
self._callFUT,
options,
)
def test_bad_checksum(self): def test_bad_checksum(self):
from ZODB.scripts.repozo import VerificationFail
options = self._makeOptions(quick=False) options = self._makeOptions(quick=False)
self._makeFile(2, 3, 4, '.fs', 'AAA') self._makeFile(2, 3, 4, '.fs', 'AAA')
self._makeFile(4, 5, 6, '.deltafs', 'BbBB') self._makeFile(4, 5, 6, '.deltafs', 'BbBB')
...@@ -1109,13 +1116,19 @@ class Test_do_verify(OptionsTestBase, unittest.TestCase): ...@@ -1109,13 +1116,19 @@ class Test_do_verify(OptionsTestBase, unittest.TestCase):
2, 3, 4, '.dat', 2, 3, 4, '.dat',
'/backup/2010-05-14-02-03-04.fs 0 3 e1faffb3e614e6c2fba74296962386b7\n' # noqa: E501 line too long '/backup/2010-05-14-02-03-04.fs 0 3 e1faffb3e614e6c2fba74296962386b7\n' # noqa: E501 line too long
'/backup/2010-05-14-04-05-06.deltafs 3 7 f50881ced34c7d9e6bce100bf33dec60\n') # noqa: E501 line too long '/backup/2010-05-14-04-05-06.deltafs 3 7 f50881ced34c7d9e6bce100bf33dec60\n') # noqa: E501 line too long
self.assertEqual(self._callFUT(options), self.assertRaisesRegex(
[options.repository + os.path.sep + VerificationFail,
'2010-05-14-04-05-06.deltafs has checksum' (
' 36486440db255f0ee6ab109d5d231406 instead of' '2010-05-14-04-05-06.deltafs has checksum'
' f50881ced34c7d9e6bce100bf33dec60']) + ' 36486440db255f0ee6ab109d5d231406 instead of'
+ ' f50881ced34c7d9e6bce100bf33dec60'
),
self._callFUT,
options,
)
def test_bad_checksum_gzip(self): def test_bad_checksum_gzip(self):
from ZODB.scripts.repozo import VerificationFail
options = self._makeOptions(quick=False) options = self._makeOptions(quick=False)
self._makeFile(2, 3, 4, '.fsz', 'AAA') self._makeFile(2, 3, 4, '.fsz', 'AAA')
self._makeFile(4, 5, 6, '.deltafsz', 'BbBB') self._makeFile(4, 5, 6, '.deltafsz', 'BbBB')
...@@ -1123,12 +1136,15 @@ class Test_do_verify(OptionsTestBase, unittest.TestCase): ...@@ -1123,12 +1136,15 @@ class Test_do_verify(OptionsTestBase, unittest.TestCase):
2, 3, 4, '.dat', 2, 3, 4, '.dat',
'/backup/2010-05-14-02-03-04.fsz 0 3 e1faffb3e614e6c2fba74296962386b7\n' # noqa: E501 line too long '/backup/2010-05-14-02-03-04.fsz 0 3 e1faffb3e614e6c2fba74296962386b7\n' # noqa: E501 line too long
'/backup/2010-05-14-04-05-06.deltafsz 3 7 f50881ced34c7d9e6bce100bf33dec60\n') # noqa: E501 line too long '/backup/2010-05-14-04-05-06.deltafsz 3 7 f50881ced34c7d9e6bce100bf33dec60\n') # noqa: E501 line too long
self.assertEqual( self.assertRaisesRegex(
self._callFUT(options), VerificationFail,
[options.repository + os.path.sep + (
'2010-05-14-04-05-06.deltafsz has checksum' '2010-05-14-04-05-06.deltafsz has checksum'
' 36486440db255f0ee6ab109d5d231406 (when uncompressed) instead of' + r' 36486440db255f0ee6ab109d5d231406 \(when uncompressed\)'
' f50881ced34c7d9e6bce100bf33dec60']) + ' instead of f50881ced34c7d9e6bce100bf33dec60'),
self._callFUT,
options,
)
def test_quick_ignores_checksums(self): def test_quick_ignores_checksums(self):
options = self._makeOptions(quick=True) options = self._makeOptions(quick=True)
...@@ -1138,7 +1154,7 @@ class Test_do_verify(OptionsTestBase, unittest.TestCase): ...@@ -1138,7 +1154,7 @@ class Test_do_verify(OptionsTestBase, unittest.TestCase):
2, 3, 4, '.dat', 2, 3, 4, '.dat',
'/backup/2010-05-14-02-03-04.fs 0 3 aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\n' # noqa: E501 line too long '/backup/2010-05-14-02-03-04.fs 0 3 aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\n' # noqa: E501 line too long
'/backup/2010-05-14-04-05-06.deltafs 3 7 bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb\n') # noqa: E501 line too long '/backup/2010-05-14-04-05-06.deltafs 3 7 bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb\n') # noqa: E501 line too long
self.assertEqual(self._callFUT(options), []) self._callFUT(options)
def test_quick_ignores_checksums_gzip(self): def test_quick_ignores_checksums_gzip(self):
options = self._makeOptions(quick=True) options = self._makeOptions(quick=True)
...@@ -1148,7 +1164,7 @@ class Test_do_verify(OptionsTestBase, unittest.TestCase): ...@@ -1148,7 +1164,7 @@ class Test_do_verify(OptionsTestBase, unittest.TestCase):
2, 3, 4, '.dat', 2, 3, 4, '.dat',
'/backup/2010-05-14-02-03-04.fsz 0 3 aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\n' # noqa: E501 line too long '/backup/2010-05-14-02-03-04.fsz 0 3 aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\n' # noqa: E501 line too long
'/backup/2010-05-14-04-05-06.deltafsz 3 7 bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb\n') # noqa: E501 line too long '/backup/2010-05-14-04-05-06.deltafsz 3 7 bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb\n') # noqa: E501 line too long
self.assertEqual(self._callFUT(options), []) self._callFUT(options)
class MonteCarloTests(unittest.TestCase): class MonteCarloTests(unittest.TestCase):
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment