Mercurial > hg
comparison tests/test-revlog-raw.py @ 43076:2372284d9457
formatting: blacken the codebase
This is using my patch to black
(https://github.com/psf/black/pull/826) so we don't un-wrap collection
literals.
Done with:
hg files 'set:**.py - mercurial/thirdparty/** - "contrib/python-zstandard/**"' | xargs black -S
# skip-blame mass-reformatting only
# no-check-commit reformats foo_bar functions
Differential Revision: https://phab.mercurial-scm.org/D6971
author | Augie Fackler <augie@google.com> |
---|---|
date | Sun, 06 Oct 2019 09:45:02 -0400 |
parents | f4caf910669e |
children | 9d2b2df2c2ba |
comparison
equal
deleted
inserted
replaced
43075:57875cf423c9 | 43076:2372284d9457 |
---|---|
21 | 21 |
22 # TESTTMP is optional. This makes it convenient to run without run-tests.py | 22 # TESTTMP is optional. This makes it convenient to run without run-tests.py |
23 tvfs = vfs.vfs(encoding.environ.get(b'TESTTMP', b'/tmp')) | 23 tvfs = vfs.vfs(encoding.environ.get(b'TESTTMP', b'/tmp')) |
24 | 24 |
25 # Enable generaldelta otherwise revlog won't use delta as expected by the test | 25 # Enable generaldelta otherwise revlog won't use delta as expected by the test |
26 tvfs.options = {b'generaldelta': True, b'revlogv1': True, | 26 tvfs.options = { |
27 b'sparse-revlog': True} | 27 b'generaldelta': True, |
28 b'revlogv1': True, | |
29 b'sparse-revlog': True, | |
30 } | |
28 | 31 |
29 # The test wants to control whether to use delta explicitly, based on | 32 # The test wants to control whether to use delta explicitly, based on |
30 # "storedeltachains". | 33 # "storedeltachains". |
31 revlog.revlog._isgooddeltainfo = lambda self, d, textlen: self._storedeltachains | 34 revlog.revlog._isgooddeltainfo = lambda self, d, textlen: self._storedeltachains |
35 | |
32 | 36 |
33 def abort(msg): | 37 def abort(msg): |
34 print('abort: %s' % msg) | 38 print('abort: %s' % msg) |
35 # Return 0 so run-tests.py could compare the output. | 39 # Return 0 so run-tests.py could compare the output. |
36 sys.exit() | 40 sys.exit() |
41 | |
37 | 42 |
38 # Register a revlog processor for flag EXTSTORED. | 43 # Register a revlog processor for flag EXTSTORED. |
39 # | 44 # |
40 # It simply prepends a fixed header, and replaces '1' to 'i'. So it has | 45 # It simply prepends a fixed header, and replaces '1' to 'i'. So it has |
41 # insertion and replacement, and may be interesting to test revlog's line-based | 46 # insertion and replacement, and may be interesting to test revlog's line-based |
42 # deltas. | 47 # deltas. |
43 _extheader = b'E\n' | 48 _extheader = b'E\n' |
44 | 49 |
50 | |
45 def readprocessor(self, rawtext): | 51 def readprocessor(self, rawtext): |
46 # True: the returned text could be used to verify hash | 52 # True: the returned text could be used to verify hash |
47 text = rawtext[len(_extheader):].replace(b'i', b'1') | 53 text = rawtext[len(_extheader) :].replace(b'i', b'1') |
48 return text, True, {} | 54 return text, True, {} |
55 | |
49 | 56 |
50 def writeprocessor(self, text, sidedata): | 57 def writeprocessor(self, text, sidedata): |
51 # False: the returned rawtext shouldn't be used to verify hash | 58 # False: the returned rawtext shouldn't be used to verify hash |
52 rawtext = _extheader + text.replace(b'1', b'i') | 59 rawtext = _extheader + text.replace(b'1', b'i') |
53 return rawtext, False | 60 return rawtext, False |
54 | 61 |
62 | |
55 def rawprocessor(self, rawtext): | 63 def rawprocessor(self, rawtext): |
56 # False: do not verify hash. Only the content returned by "readprocessor" | 64 # False: do not verify hash. Only the content returned by "readprocessor" |
57 # can be used to verify hash. | 65 # can be used to verify hash. |
58 return False | 66 return False |
59 | 67 |
60 flagutil.addflagprocessor(revlog.REVIDX_EXTSTORED, | 68 |
61 (readprocessor, writeprocessor, rawprocessor)) | 69 flagutil.addflagprocessor( |
70 revlog.REVIDX_EXTSTORED, (readprocessor, writeprocessor, rawprocessor) | |
71 ) | |
62 | 72 |
63 # Utilities about reading and appending revlog | 73 # Utilities about reading and appending revlog |
74 | |
64 | 75 |
65 def newtransaction(): | 76 def newtransaction(): |
66 # A transaction is required to write revlogs | 77 # A transaction is required to write revlogs |
67 report = lambda msg: None | 78 report = lambda msg: None |
68 return transaction.transaction(report, tvfs, {'plain': tvfs}, b'journal') | 79 return transaction.transaction(report, tvfs, {'plain': tvfs}, b'journal') |
80 | |
69 | 81 |
70 def newrevlog(name=b'_testrevlog.i', recreate=False): | 82 def newrevlog(name=b'_testrevlog.i', recreate=False): |
71 if recreate: | 83 if recreate: |
72 tvfs.tryunlink(name) | 84 tvfs.tryunlink(name) |
73 rlog = revlog.revlog(tvfs, name) | 85 rlog = revlog.revlog(tvfs, name) |
74 return rlog | 86 return rlog |
87 | |
75 | 88 |
76 def appendrev(rlog, text, tr, isext=False, isdelta=True): | 89 def appendrev(rlog, text, tr, isext=False, isdelta=True): |
77 '''Append a revision. If isext is True, set the EXTSTORED flag so flag | 90 '''Append a revision. If isext is True, set the EXTSTORED flag so flag |
78 processor will be used (and rawtext is different from text). If isdelta is | 91 processor will be used (and rawtext is different from text). If isdelta is |
79 True, force the revision to be a delta, otherwise it's full text. | 92 True, force the revision to be a delta, otherwise it's full text. |
94 abort('rev %d: failed to append: %s' % (nextrev, ex)) | 107 abort('rev %d: failed to append: %s' % (nextrev, ex)) |
95 finally: | 108 finally: |
96 # Restore storedeltachains. It is always True, see revlog.__init__ | 109 # Restore storedeltachains. It is always True, see revlog.__init__ |
97 rlog._storedeltachains = True | 110 rlog._storedeltachains = True |
98 | 111 |
112 | |
99 def addgroupcopy(rlog, tr, destname=b'_destrevlog.i', optimaldelta=True): | 113 def addgroupcopy(rlog, tr, destname=b'_destrevlog.i', optimaldelta=True): |
100 '''Copy revlog to destname using revlog.addgroup. Return the copied revlog. | 114 '''Copy revlog to destname using revlog.addgroup. Return the copied revlog. |
101 | 115 |
102 This emulates push or pull. They use changegroup. Changegroup requires | 116 This emulates push or pull. They use changegroup. Changegroup requires |
103 repo to work. We don't have a repo, so a dummy changegroup is used. | 117 repo to work. We don't have a repo, so a dummy changegroup is used. |
107 the destination revlog needs more work to use it. | 121 the destination revlog needs more work to use it. |
108 | 122 |
109 This exercises some revlog.addgroup (and revlog._addrevision(text=None)) | 123 This exercises some revlog.addgroup (and revlog._addrevision(text=None)) |
110 code path, which is not covered by "appendrev" alone. | 124 code path, which is not covered by "appendrev" alone. |
111 ''' | 125 ''' |
126 | |
112 class dummychangegroup(object): | 127 class dummychangegroup(object): |
113 @staticmethod | 128 @staticmethod |
114 def deltachunk(pnode): | 129 def deltachunk(pnode): |
115 pnode = pnode or node.nullid | 130 pnode = pnode or node.nullid |
116 parentrev = rlog.rev(pnode) | 131 parentrev = rlog.rev(pnode) |
122 else: | 137 else: |
123 # suboptimal deltaparent | 138 # suboptimal deltaparent |
124 deltaparent = min(0, parentrev) | 139 deltaparent = min(0, parentrev) |
125 if not rlog.candelta(deltaparent, r): | 140 if not rlog.candelta(deltaparent, r): |
126 deltaparent = -1 | 141 deltaparent = -1 |
127 return {b'node': rlog.node(r), b'p1': pnode, b'p2': node.nullid, | 142 return { |
128 b'cs': rlog.node(rlog.linkrev(r)), b'flags': rlog.flags(r), | 143 b'node': rlog.node(r), |
129 b'deltabase': rlog.node(deltaparent), | 144 b'p1': pnode, |
130 b'delta': rlog.revdiff(deltaparent, r)} | 145 b'p2': node.nullid, |
146 b'cs': rlog.node(rlog.linkrev(r)), | |
147 b'flags': rlog.flags(r), | |
148 b'deltabase': rlog.node(deltaparent), | |
149 b'delta': rlog.revdiff(deltaparent, r), | |
150 } | |
131 | 151 |
132 def deltaiter(self): | 152 def deltaiter(self): |
133 chain = None | 153 chain = None |
134 for chunkdata in iter(lambda: self.deltachunk(chain), {}): | 154 for chunkdata in iter(lambda: self.deltachunk(chain), {}): |
135 node = chunkdata[b'node'] | 155 node = chunkdata[b'node'] |
149 | 169 |
150 dlog = newrevlog(destname, recreate=True) | 170 dlog = newrevlog(destname, recreate=True) |
151 dummydeltas = dummychangegroup().deltaiter() | 171 dummydeltas = dummychangegroup().deltaiter() |
152 dlog.addgroup(dummydeltas, linkmap, tr) | 172 dlog.addgroup(dummydeltas, linkmap, tr) |
153 return dlog | 173 return dlog |
174 | |
154 | 175 |
155 def lowlevelcopy(rlog, tr, destname=b'_destrevlog.i'): | 176 def lowlevelcopy(rlog, tr, destname=b'_destrevlog.i'): |
156 '''Like addgroupcopy, but use the low level revlog._addrevision directly. | 177 '''Like addgroupcopy, but use the low level revlog._addrevision directly. |
157 | 178 |
158 It exercises some code paths that are hard to reach easily otherwise. | 179 It exercises some code paths that are hard to reach easily otherwise. |
164 if r == 0 or (rlog.flags(r) & revlog.REVIDX_EXTSTORED): | 185 if r == 0 or (rlog.flags(r) & revlog.REVIDX_EXTSTORED): |
165 text = rlog.rawdata(r) | 186 text = rlog.rawdata(r) |
166 cachedelta = None | 187 cachedelta = None |
167 else: | 188 else: |
168 # deltaparent cannot have EXTSTORED flag. | 189 # deltaparent cannot have EXTSTORED flag. |
169 deltaparent = max([-1] + | 190 deltaparent = max( |
170 [p for p in range(r) | 191 [-1] |
171 if rlog.flags(p) & revlog.REVIDX_EXTSTORED == 0]) | 192 + [ |
193 p | |
194 for p in range(r) | |
195 if rlog.flags(p) & revlog.REVIDX_EXTSTORED == 0 | |
196 ] | |
197 ) | |
172 text = None | 198 text = None |
173 cachedelta = (deltaparent, rlog.revdiff(deltaparent, r)) | 199 cachedelta = (deltaparent, rlog.revdiff(deltaparent, r)) |
174 flags = rlog.flags(r) | 200 flags = rlog.flags(r) |
175 ifh = dfh = None | 201 ifh = dfh = None |
176 try: | 202 try: |
177 ifh = dlog.opener(dlog.indexfile, b'a+') | 203 ifh = dlog.opener(dlog.indexfile, b'a+') |
178 if not dlog._inline: | 204 if not dlog._inline: |
179 dfh = dlog.opener(dlog.datafile, b'a+') | 205 dfh = dlog.opener(dlog.datafile, b'a+') |
180 dlog._addrevision(rlog.node(r), text, tr, r, p1, p2, flags, | 206 dlog._addrevision( |
181 cachedelta, ifh, dfh) | 207 rlog.node(r), text, tr, r, p1, p2, flags, cachedelta, ifh, dfh |
208 ) | |
182 finally: | 209 finally: |
183 if dfh is not None: | 210 if dfh is not None: |
184 dfh.close() | 211 dfh.close() |
185 if ifh is not None: | 212 if ifh is not None: |
186 ifh.close() | 213 ifh.close() |
187 return dlog | 214 return dlog |
188 | 215 |
216 | |
189 # Utilities to generate revisions for testing | 217 # Utilities to generate revisions for testing |
218 | |
190 | 219 |
191 def genbits(n): | 220 def genbits(n): |
192 '''Given a number n, generate (2 ** (n * 2) + 1) numbers in range(2 ** n). | 221 '''Given a number n, generate (2 ** (n * 2) + 1) numbers in range(2 ** n). |
193 i.e. the generated numbers have a width of n bits. | 222 i.e. the generated numbers have a width of n bits. |
194 | 223 |
217 assert a[x] < m | 246 assert a[x] < m |
218 a[x] += 1 | 247 a[x] += 1 |
219 x = y | 248 x = y |
220 yield x | 249 yield x |
221 | 250 |
251 | |
222 def gentext(rev): | 252 def gentext(rev): |
223 '''Given a revision number, generate dummy text''' | 253 '''Given a revision number, generate dummy text''' |
224 return b''.join(b'%d\n' % j for j in range(-1, rev % 5)) | 254 return b''.join(b'%d\n' % j for j in range(-1, rev % 5)) |
255 | |
225 | 256 |
226 def writecases(rlog, tr): | 257 def writecases(rlog, tr): |
227 '''Write some revisions interested to the test. | 258 '''Write some revisions interested to the test. |
228 | 259 |
229 The test is interested in 3 properties of a revision: | 260 The test is interested in 3 properties of a revision: |
279 abort('rev %d: isdelta is unexpected' % rev) | 310 abort('rev %d: isdelta is unexpected' % rev) |
280 if bool(rlog.flags(rev)) != isext: | 311 if bool(rlog.flags(rev)) != isext: |
281 abort('rev %d: isext is ineffective' % rev) | 312 abort('rev %d: isext is ineffective' % rev) |
282 return result | 313 return result |
283 | 314 |
315 | |
284 # Main test and checking | 316 # Main test and checking |
317 | |
285 | 318 |
286 def checkrevlog(rlog, expected): | 319 def checkrevlog(rlog, expected): |
287 '''Check if revlog has expected contents. expected is [(text, rawtext)]''' | 320 '''Check if revlog has expected contents. expected is [(text, rawtext)]''' |
288 # Test using different access orders. This could expose some issues | 321 # Test using different access orders. This could expose some issues |
289 # depending on revlog caching (see revlog._cache). | 322 # depending on revlog caching (see revlog._cache). |
297 if raw: | 330 if raw: |
298 t = nlog.rawdata(rev) | 331 t = nlog.rawdata(rev) |
299 else: | 332 else: |
300 t = nlog.revision(rev) | 333 t = nlog.revision(rev) |
301 if t != expected[rev][int(raw)]: | 334 if t != expected[rev][int(raw)]: |
302 abort('rev %d: corrupted %stext' | 335 abort( |
303 % (rev, raw and 'raw' or '')) | 336 'rev %d: corrupted %stext' |
337 % (rev, raw and 'raw' or '') | |
338 ) | |
339 | |
304 | 340 |
305 slicingdata = [ | 341 slicingdata = [ |
306 ([0, 1, 2, 3, 55, 56, 58, 59, 60], | 342 ([0, 1, 2, 3, 55, 56, 58, 59, 60], [[0, 1], [2], [58], [59, 60]], 10), |
307 [[0, 1], [2], [58], [59, 60]], | 343 ([0, 1, 2, 3, 55, 56, 58, 59, 60], [[0, 1], [2], [58], [59, 60]], 10), |
308 10), | 344 ( |
309 ([0, 1, 2, 3, 55, 56, 58, 59, 60], | 345 [-1, 0, 1, 2, 3, 55, 56, 58, 59, 60], |
310 [[0, 1], [2], [58], [59, 60]], | 346 [[-1, 0, 1], [2], [58], [59, 60]], |
311 10), | 347 10, |
312 ([-1, 0, 1, 2, 3, 55, 56, 58, 59, 60], | 348 ), |
313 [[-1, 0, 1], [2], [58], [59, 60]], | |
314 10), | |
315 ] | 349 ] |
350 | |
316 | 351 |
317 def slicingtest(rlog): | 352 def slicingtest(rlog): |
318 oldmin = rlog._srmingapsize | 353 oldmin = rlog._srmingapsize |
319 try: | 354 try: |
320 # the test revlog is small, we remove the floor under which we | 355 # the test revlog is small, we remove the floor under which we |
331 print(' expected: %s' % expected) | 366 print(' expected: %s' % expected) |
332 print(' result: %s' % result) | 367 print(' result: %s' % result) |
333 finally: | 368 finally: |
334 rlog._srmingapsize = oldmin | 369 rlog._srmingapsize = oldmin |
335 | 370 |
371 | |
336 def md5sum(s): | 372 def md5sum(s): |
337 return hashlib.md5(s).digest() | 373 return hashlib.md5(s).digest() |
374 | |
338 | 375 |
339 def _maketext(*coord): | 376 def _maketext(*coord): |
340 """create piece of text according to range of integers | 377 """create piece of text according to range of integers |
341 | 378 |
342 The test returned use a md5sum of the integer to make it less | 379 The test returned use a md5sum of the integer to make it less |
345 for start, size in coord: | 382 for start, size in coord: |
346 num = range(start, start + size) | 383 num = range(start, start + size) |
347 p = [md5sum(b'%d' % r) for r in num] | 384 p = [md5sum(b'%d' % r) for r in num] |
348 pieces.append(b'\n'.join(p)) | 385 pieces.append(b'\n'.join(p)) |
349 return b'\n'.join(pieces) + b'\n' | 386 return b'\n'.join(pieces) + b'\n' |
387 | |
350 | 388 |
351 data = [ | 389 data = [ |
352 _maketext((0, 120), (456, 60)), | 390 _maketext((0, 120), (456, 60)), |
353 _maketext((0, 120), (345, 60)), | 391 _maketext((0, 120), (345, 60)), |
354 _maketext((0, 120), (734, 60)), | 392 _maketext((0, 120), (734, 60)), |
381 _maketext((0, 120), (60, 60), (569, 30), (745, 40)), | 419 _maketext((0, 120), (60, 60), (569, 30), (745, 40)), |
382 _maketext((0, 120), (60, 60), (777, 30), (700, 40)), | 420 _maketext((0, 120), (60, 60), (777, 30), (700, 40)), |
383 _maketext((0, 120), (60, 60), (618, 30), (398, 40), (158, 10)), | 421 _maketext((0, 120), (60, 60), (618, 30), (398, 40), (158, 10)), |
384 ] | 422 ] |
385 | 423 |
424 | |
386 def makesnapshot(tr): | 425 def makesnapshot(tr): |
387 rl = newrevlog(name=b'_snaprevlog3.i', recreate=True) | 426 rl = newrevlog(name=b'_snaprevlog3.i', recreate=True) |
388 for i in data: | 427 for i in data: |
389 appendrev(rl, i, tr) | 428 appendrev(rl, i, tr) |
390 return rl | 429 return rl |
391 | 430 |
431 | |
392 snapshots = [-1, 0, 6, 8, 11, 17, 19, 21, 25, 30] | 432 snapshots = [-1, 0, 6, 8, 11, 17, 19, 21, 25, 30] |
433 | |
434 | |
393 def issnapshottest(rlog): | 435 def issnapshottest(rlog): |
394 result = [] | 436 result = [] |
395 if rlog.issnapshot(-1): | 437 if rlog.issnapshot(-1): |
396 result.append(-1) | 438 result.append(-1) |
397 for rev in rlog: | 439 for rev in rlog: |
400 if snapshots != result: | 442 if snapshots != result: |
401 print('snapshot differ:') | 443 print('snapshot differ:') |
402 print(' expected: %s' % snapshots) | 444 print(' expected: %s' % snapshots) |
403 print(' got: %s' % result) | 445 print(' got: %s' % result) |
404 | 446 |
447 | |
405 snapshotmapall = {0: [6, 8, 11, 17, 19, 25], 8: [21], -1: [0, 30]} | 448 snapshotmapall = {0: [6, 8, 11, 17, 19, 25], 8: [21], -1: [0, 30]} |
406 snapshotmap15 = {0: [17, 19, 25], 8: [21], -1: [30]} | 449 snapshotmap15 = {0: [17, 19, 25], 8: [21], -1: [30]} |
450 | |
451 | |
407 def findsnapshottest(rlog): | 452 def findsnapshottest(rlog): |
408 resultall = collections.defaultdict(list) | 453 resultall = collections.defaultdict(list) |
409 deltas._findsnapshots(rlog, resultall, 0) | 454 deltas._findsnapshots(rlog, resultall, 0) |
410 resultall = dict(resultall.items()) | 455 resultall = dict(resultall.items()) |
411 if resultall != snapshotmapall: | 456 if resultall != snapshotmapall: |
417 result15 = dict(result15.items()) | 462 result15 = dict(result15.items()) |
418 if result15 != snapshotmap15: | 463 if result15 != snapshotmap15: |
419 print('snapshot map differ:') | 464 print('snapshot map differ:') |
420 print(' expected: %s' % snapshotmap15) | 465 print(' expected: %s' % snapshotmap15) |
421 print(' got: %s' % result15) | 466 print(' got: %s' % result15) |
467 | |
422 | 468 |
423 def maintest(): | 469 def maintest(): |
424 with newtransaction() as tr: | 470 with newtransaction() as tr: |
425 rl = newrevlog(recreate=True) | 471 rl = newrevlog(recreate=True) |
426 expected = writecases(rl, tr) | 472 expected = writecases(rl, tr) |
447 issnapshottest(rl5) | 493 issnapshottest(rl5) |
448 print('issnapshot test passed') | 494 print('issnapshot test passed') |
449 findsnapshottest(rl5) | 495 findsnapshottest(rl5) |
450 print('findsnapshot test passed') | 496 print('findsnapshot test passed') |
451 | 497 |
498 | |
452 try: | 499 try: |
453 maintest() | 500 maintest() |
454 except Exception as ex: | 501 except Exception as ex: |
455 abort('crashed: %s' % ex) | 502 abort('crashed: %s' % ex) |