##// END OF EJS Templates
testing: add file storage integration for bad hashes and censoring...
Gregory Szorc -
r40087:cdf61ab1 default
parent child Browse files
Show More
@@ -861,6 +861,110 b' class ifiledatatests(basetestcase):'
861 861 self.assertFalse(f.cmp(node1, fulltext1))
862 862 self.assertTrue(f.cmp(node1, stored0))
863 863
864 def testbadnoderead(self):
865 f = self._makefilefn()
866
867 fulltext0 = b'foo\n' * 30
868 fulltext1 = fulltext0 + b'bar\n'
869
870 with self._maketransactionfn() as tr:
871 node0 = f.add(fulltext0, None, tr, 0, nullid, nullid)
872 node1 = b'\xaa' * 20
873
874 self._addrawrevisionfn(f, tr, node1, node0, nullid, 1,
875 rawtext=fulltext1)
876
877 self.assertEqual(len(f), 2)
878 self.assertEqual(f.parents(node1), (node0, nullid))
879
880 # revision() raises since it performs hash verification.
881 with self.assertRaises(error.StorageError):
882 f.revision(node1)
883
884 # revision(raw=True) still verifies hashes.
885 # TODO this is buggy because of cache interaction.
886 self.assertEqual(f.revision(node1, raw=True), fulltext1)
887
888 # read() behaves like revision().
889 # TODO this is buggy because of cache interaction.
890 f.read(node1)
891
892 # We can't test renamed() here because some backends may not require
893 # reading/validating the fulltext to return rename metadata.
894
895 def testbadnoderevisionraw(self):
896 # Like above except we test revision(raw=True) first to isolate
897 # revision caching behavior.
898 f = self._makefilefn()
899
900 fulltext0 = b'foo\n' * 30
901 fulltext1 = fulltext0 + b'bar\n'
902
903 with self._maketransactionfn() as tr:
904 node0 = f.add(fulltext0, None, tr, 0, nullid, nullid)
905 node1 = b'\xaa' * 20
906
907 self._addrawrevisionfn(f, tr, node1, node0, nullid, 1,
908 rawtext=fulltext1)
909
910 with self.assertRaises(error.StorageError):
911 f.revision(node1, raw=True)
912
913 with self.assertRaises(error.StorageError):
914 f.revision(node1, raw=True)
915
916 def testbadnoderevisionraw(self):
917 # Like above except we test read() first to isolate revision caching
918 # behavior.
919 f = self._makefilefn()
920
921 fulltext0 = b'foo\n' * 30
922 fulltext1 = fulltext0 + b'bar\n'
923
924 with self._maketransactionfn() as tr:
925 node0 = f.add(fulltext0, None, tr, 0, nullid, nullid)
926 node1 = b'\xaa' * 20
927
928 self._addrawrevisionfn(f, tr, node1, node0, nullid, 1,
929 rawtext=fulltext1)
930
931 with self.assertRaises(error.StorageError):
932 f.read(node1)
933
934 # TODO this should raise error.StorageError.
935 f.read(node1)
936
937 def testbadnodedelta(self):
938 f = self._makefilefn()
939
940 fulltext0 = b'foo\n' * 31
941 fulltext1 = fulltext0 + b'bar\n'
942 fulltext2 = fulltext1 + b'baz\n'
943
944 with self._maketransactionfn() as tr:
945 node0 = f.add(fulltext0, None, tr, 0, nullid, nullid)
946 node1 = b'\xaa' * 20
947
948 self._addrawrevisionfn(f, tr, node1, node0, nullid, 1,
949 rawtext=fulltext1)
950
951 with self.assertRaises(error.StorageError):
952 f.read(node1)
953
954 diff = mdiff.textdiff(fulltext1, fulltext2)
955 node2 = storageutil.hashrevisionsha1(fulltext2, node1, nullid)
956 deltas = [(node2, node1, nullid, b'\x01' * 20, node1, diff, 0)]
957
958 # This /might/ fail on some backends.
959 with self._maketransactionfn() as tr:
960 f.addgroup(deltas, lambda x: 0, tr)
961
962 self.assertEqual(len(f), 3)
963
964 # Assuming a delta is stored, we shouldn't need to validate node1 in
965 # order to retrieve node2.
966 self.assertEqual(f.read(node2), fulltext2)
967
864 968 def testcensored(self):
865 969 f = self._makefilefn()
866 970
@@ -868,20 +972,46 b' class ifiledatatests(basetestcase):'
868 972 b'censored': b'tombstone',
869 973 }, b'')
870 974
871 # TODO tests are incomplete because we need the node to be
872 # different due to presence of censor metadata. But we can't
873 # do this with addrevision().
874 975 with self._maketransactionfn() as tr:
875 976 node0 = f.add(b'foo', None, tr, 0, nullid, nullid)
876 f.addrevision(stored1, tr, 1, node0, nullid,
877 flags=repository.REVISION_FLAG_CENSORED)
977
978 # The node value doesn't matter since we can't verify it.
979 node1 = b'\xbb' * 20
980
981 self._addrawrevisionfn(f, tr, node1, node0, nullid, 1, stored1,
982 censored=True)
878 983
879 984 self.assertTrue(f.iscensored(1))
880 985
881 self.assertEqual(f.revision(1), stored1)
986 with self.assertRaises(error.CensoredNodeError):
987 f.revision(1)
988
882 989 self.assertEqual(f.revision(1, raw=True), stored1)
883 990
884 self.assertEqual(f.read(1), b'')
991 with self.assertRaises(error.CensoredNodeError):
992 f.read(1)
993
994 def testcensoredrawrevision(self):
995 # Like above, except we do the revision(raw=True) request first to
996 # isolate revision caching behavior.
997
998 f = self._makefilefn()
999
1000 stored1 = storageutil.packmeta({
1001 b'censored': b'tombstone',
1002 }, b'')
1003
1004 with self._maketransactionfn() as tr:
1005 node0 = f.add(b'foo', None, tr, 0, nullid, nullid)
1006
1007 # The node value doesn't matter since we can't verify it.
1008 node1 = b'\xbb' * 20
1009
1010 self._addrawrevisionfn(f, tr, node1, node0, nullid, 1, stored1,
1011 censored=True)
1012
1013 with self.assertRaises(error.CensoredNodeError):
1014 f.revision(1, raw=True)
885 1015
886 1016 class ifilemutationtests(basetestcase):
887 1017 """Generic tests for the ifilemutation interface.
@@ -1004,6 +1134,55 b' class ifilemutationtests(basetestcase):'
1004 1134 self.assertEqual(f.node(1), nodes[1])
1005 1135 self.assertEqual(f.node(2), nodes[2])
1006 1136
1137 def testdeltaagainstcensored(self):
1138 # Attempt to apply a delta made against a censored revision.
1139 f = self._makefilefn()
1140
1141 stored1 = storageutil.packmeta({
1142 b'censored': b'tombstone',
1143 }, b'')
1144
1145 with self._maketransactionfn() as tr:
1146 node0 = f.add(b'foo\n' * 30, None, tr, 0, nullid, nullid)
1147
1148 # The node value doesn't matter since we can't verify it.
1149 node1 = b'\xbb' * 20
1150
1151 self._addrawrevisionfn(f, tr, node1, node0, nullid, 1, stored1,
1152 censored=True)
1153
1154 delta = mdiff.textdiff(b'bar\n' * 30, (b'bar\n' * 30) + b'baz\n')
1155 deltas = [(b'\xcc' * 20, node1, nullid, b'\x01' * 20, node1, delta, 0)]
1156
1157 with self._maketransactionfn() as tr:
1158 with self.assertRaises(error.CensoredBaseError):
1159 f.addgroup(deltas, lambda x: 0, tr)
1160
1161 def testcensorrevisionbasic(self):
1162 f = self._makefilefn()
1163
1164 with self._maketransactionfn() as tr:
1165 node0 = f.add(b'foo\n' * 30, None, tr, 0, nullid, nullid)
1166 node1 = f.add(b'foo\n' * 31, None, tr, 1, node0, nullid)
1167 node2 = f.add(b'foo\n' * 32, None, tr, 2, node1, nullid)
1168
1169 with self._maketransactionfn() as tr:
1170 f.censorrevision(tr, node1)
1171
1172 self.assertEqual(len(f), 3)
1173 self.assertEqual(list(f.revs()), [0, 1, 2])
1174
1175 self.assertEqual(f.read(node0), b'foo\n' * 30)
1176
1177 # TODO revlog can't resolve revision after censor. Probably due to a
1178 # cache on the revlog instance.
1179 with self.assertRaises(error.StorageError):
1180 self.assertEqual(f.read(node2), b'foo\n' * 32)
1181
1182 # TODO should raise CensoredNodeError, but fallout from above prevents.
1183 with self.assertRaises(error.StorageError):
1184 f.read(node1)
1185
1007 1186 def testgetstrippointnoparents(self):
1008 1187 # N revisions where none have parents.
1009 1188 f = self._makefilefn()
@@ -1121,7 +1300,7 b' class ifilemutationtests(basetestcase):'
1121 1300 with self.assertRaises(error.LookupError):
1122 1301 f.rev(node1)
1123 1302
1124 def makeifileindextests(makefilefn, maketransactionfn):
1303 def makeifileindextests(makefilefn, maketransactionfn, addrawrevisionfn):
1125 1304 """Create a unittest.TestCase class suitable for testing file storage.
1126 1305
1127 1306 ``makefilefn`` is a callable which receives the test case as an
@@ -1130,6 +1309,10 b' def makeifileindextests(makefilefn, make'
1130 1309 ``maketransactionfn`` is a callable which receives the test case as an
1131 1310 argument and returns a transaction object.
1132 1311
1312 ``addrawrevisionfn`` is a callable which receives arguments describing a
1313 low-level revision to add. This callable allows the insertion of
1314 potentially bad data into the store in order to facilitate testing.
1315
1133 1316 Returns a type that is a ``unittest.TestCase`` that can be used for
1134 1317 testing the object implementing the file storage interface. Simply
1135 1318 assign the returned value to a module-level attribute and a test loader
@@ -1138,19 +1321,22 b' def makeifileindextests(makefilefn, make'
1138 1321 d = {
1139 1322 r'_makefilefn': makefilefn,
1140 1323 r'_maketransactionfn': maketransactionfn,
1324 r'_addrawrevisionfn': addrawrevisionfn,
1141 1325 }
1142 1326 return type(r'ifileindextests', (ifileindextests,), d)
1143 1327
1144 def makeifiledatatests(makefilefn, maketransactionfn):
1328 def makeifiledatatests(makefilefn, maketransactionfn, addrawrevisionfn):
1145 1329 d = {
1146 1330 r'_makefilefn': makefilefn,
1147 1331 r'_maketransactionfn': maketransactionfn,
1332 r'_addrawrevisionfn': addrawrevisionfn,
1148 1333 }
1149 1334 return type(r'ifiledatatests', (ifiledatatests,), d)
1150 1335
1151 def makeifilemutationtests(makefilefn, maketransactionfn):
1336 def makeifilemutationtests(makefilefn, maketransactionfn, addrawrevisionfn):
1152 1337 d = {
1153 1338 r'_makefilefn': makefilefn,
1154 1339 r'_maketransactionfn': maketransactionfn,
1340 r'_addrawrevisionfn': addrawrevisionfn,
1155 1341 }
1156 1342 return type(r'ifilemutationtests', (ifilemutationtests,), d)
@@ -5,7 +5,9 b' from __future__ import absolute_import'
5 5 import silenttestrunner
6 6
7 7 from mercurial import (
8 error,
8 9 filelog,
10 revlog,
9 11 transaction,
10 12 ui as uimod,
11 13 vfs as vfsmod,
@@ -33,14 +35,39 b' def maketransaction(self):'
33 35 return transaction.transaction(STATE['ui'].warn, STATE['vfs'], vfsmap,
34 36 b'journal', b'undo')
35 37
38 def addrawrevision(self, fl, tr, node, p1, p2, linkrev, rawtext=None,
39 delta=None, censored=False, ellipsis=False, extstored=False):
40 flags = 0
41
42 if censored:
43 flags |= revlog.REVIDX_ISCENSORED
44 if ellipsis:
45 flags |= revlog.REVIDX_ELLIPSIS
46 if extstored:
47 flags |= revlog.REVIDX_EXTSTORED
48
49 if rawtext is not None:
50 fl._revlog.addrawrevision(rawtext, tr, linkrev, p1, p2, node, flags)
51 elif delta is not None:
52 raise error.Abort('support for storing raw deltas not yet supported')
53 else:
54 raise error.Abort('must supply rawtext or delta arguments')
55
56 # We may insert bad data. Clear caches to prevent e.g. cache hits to
57 # bypass hash verification.
58 fl._revlog.clearcaches()
59
36 60 # Assigning module-level attributes that inherit from unittest.TestCase
37 61 # is all that is needed to register tests.
38 62 filelogindextests = storagetesting.makeifileindextests(makefilefn,
39 maketransaction)
63 maketransaction,
64 addrawrevision)
40 65 filelogdatatests = storagetesting.makeifiledatatests(makefilefn,
41 maketransaction)
66 maketransaction,
67 addrawrevision)
42 68 filelogmutationtests = storagetesting.makeifilemutationtests(makefilefn,
43 maketransaction)
69 maketransaction,
70 addrawrevision)
44 71
45 72 if __name__ == '__main__':
46 73 silenttestrunner.main(__name__)
General Comments 0
You need to be logged in to leave comments. Login now