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)