mercurial/testing/storage.py
changeset 40051 cdf61ab1f54c
parent 40050 8e136940c0e6
child 40054 801ccd8e67c0
equal deleted inserted replaced
40050:8e136940c0e6 40051:cdf61ab1f54c
   859         self.assertTrue(f.cmp(node0, stored0))
   859         self.assertTrue(f.cmp(node0, stored0))
   860 
   860 
   861         self.assertFalse(f.cmp(node1, fulltext1))
   861         self.assertFalse(f.cmp(node1, fulltext1))
   862         self.assertTrue(f.cmp(node1, stored0))
   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     def testcensored(self):
   968     def testcensored(self):
   865         f = self._makefilefn()
   969         f = self._makefilefn()
   866 
   970 
   867         stored1 = storageutil.packmeta({
   971         stored1 = storageutil.packmeta({
   868             b'censored': b'tombstone',
   972             b'censored': b'tombstone',
   869         }, b'')
   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         with self._maketransactionfn() as tr:
   975         with self._maketransactionfn() as tr:
   875             node0 = f.add(b'foo', None, tr, 0, nullid, nullid)
   976             node0 = f.add(b'foo', None, tr, 0, nullid, nullid)
   876             f.addrevision(stored1, tr, 1, node0, nullid,
   977 
   877                           flags=repository.REVISION_FLAG_CENSORED)
   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         self.assertTrue(f.iscensored(1))
   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         self.assertEqual(f.revision(1, raw=True), stored1)
   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 class ifilemutationtests(basetestcase):
  1016 class ifilemutationtests(basetestcase):
   887     """Generic tests for the ifilemutation interface.
  1017     """Generic tests for the ifilemutation interface.
   888 
  1018 
   889     All file storage backends that support writing should conform to this
  1019     All file storage backends that support writing should conform to this
  1001         self.assertEqual(f.rev(nodes[1]), 1)
  1131         self.assertEqual(f.rev(nodes[1]), 1)
  1002         self.assertEqual(f.rev(nodes[2]), 2)
  1132         self.assertEqual(f.rev(nodes[2]), 2)
  1003         self.assertEqual(f.node(0), nodes[0])
  1133         self.assertEqual(f.node(0), nodes[0])
  1004         self.assertEqual(f.node(1), nodes[1])
  1134         self.assertEqual(f.node(1), nodes[1])
  1005         self.assertEqual(f.node(2), nodes[2])
  1135         self.assertEqual(f.node(2), nodes[2])
       
  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)
  1006 
  1185 
  1007     def testgetstrippointnoparents(self):
  1186     def testgetstrippointnoparents(self):
  1008         # N revisions where none have parents.
  1187         # N revisions where none have parents.
  1009         f = self._makefilefn()
  1188         f = self._makefilefn()
  1010 
  1189 
  1119         self.assertEqual(len(f), 1)
  1298         self.assertEqual(len(f), 1)
  1120 
  1299 
  1121         with self.assertRaises(error.LookupError):
  1300         with self.assertRaises(error.LookupError):
  1122             f.rev(node1)
  1301             f.rev(node1)
  1123 
  1302 
  1124 def makeifileindextests(makefilefn, maketransactionfn):
  1303 def makeifileindextests(makefilefn, maketransactionfn, addrawrevisionfn):
  1125     """Create a unittest.TestCase class suitable for testing file storage.
  1304     """Create a unittest.TestCase class suitable for testing file storage.
  1126 
  1305 
  1127     ``makefilefn`` is a callable which receives the test case as an
  1306     ``makefilefn`` is a callable which receives the test case as an
  1128     argument and returns an object implementing the ``ifilestorage`` interface.
  1307     argument and returns an object implementing the ``ifilestorage`` interface.
  1129 
  1308 
  1130     ``maketransactionfn`` is a callable which receives the test case as an
  1309     ``maketransactionfn`` is a callable which receives the test case as an
  1131     argument and returns a transaction object.
  1310     argument and returns a transaction object.
       
  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.
  1132 
  1315 
  1133     Returns a type that is a ``unittest.TestCase`` that can be used for
  1316     Returns a type that is a ``unittest.TestCase`` that can be used for
  1134     testing the object implementing the file storage interface. Simply
  1317     testing the object implementing the file storage interface. Simply
  1135     assign the returned value to a module-level attribute and a test loader
  1318     assign the returned value to a module-level attribute and a test loader
  1136     should find and run it automatically.
  1319     should find and run it automatically.
  1137     """
  1320     """
  1138     d = {
  1321     d = {
  1139         r'_makefilefn': makefilefn,
  1322         r'_makefilefn': makefilefn,
  1140         r'_maketransactionfn': maketransactionfn,
  1323         r'_maketransactionfn': maketransactionfn,
       
  1324         r'_addrawrevisionfn': addrawrevisionfn,
  1141     }
  1325     }
  1142     return type(r'ifileindextests', (ifileindextests,), d)
  1326     return type(r'ifileindextests', (ifileindextests,), d)
  1143 
  1327 
  1144 def makeifiledatatests(makefilefn, maketransactionfn):
  1328 def makeifiledatatests(makefilefn, maketransactionfn, addrawrevisionfn):
  1145     d = {
  1329     d = {
  1146         r'_makefilefn': makefilefn,
  1330         r'_makefilefn': makefilefn,
  1147         r'_maketransactionfn': maketransactionfn,
  1331         r'_maketransactionfn': maketransactionfn,
       
  1332         r'_addrawrevisionfn': addrawrevisionfn,
  1148     }
  1333     }
  1149     return type(r'ifiledatatests', (ifiledatatests,), d)
  1334     return type(r'ifiledatatests', (ifiledatatests,), d)
  1150 
  1335 
  1151 def makeifilemutationtests(makefilefn, maketransactionfn):
  1336 def makeifilemutationtests(makefilefn, maketransactionfn, addrawrevisionfn):
  1152     d = {
  1337     d = {
  1153         r'_makefilefn': makefilefn,
  1338         r'_makefilefn': makefilefn,
  1154         r'_maketransactionfn': maketransactionfn,
  1339         r'_maketransactionfn': maketransactionfn,
       
  1340         r'_addrawrevisionfn': addrawrevisionfn,
  1155     }
  1341     }
  1156     return type(r'ifilemutationtests', (ifilemutationtests,), d)
  1342     return type(r'ifilemutationtests', (ifilemutationtests,), d)