##// END OF EJS Templates
revlog: add an explicit test for `issnapshot`...
Boris Feld -
r41064:15f78383 default
parent child Browse files
Show More
@@ -1,358 +1,431 b''
1 # test revlog interaction about raw data (flagprocessor)
1 # test revlog interaction about raw data (flagprocessor)
2
2
3 from __future__ import absolute_import, print_function
3 from __future__ import absolute_import, print_function
4
4
5 import hashlib
5 import sys
6 import sys
6
7
7 from mercurial import (
8 from mercurial import (
8 encoding,
9 encoding,
9 node,
10 node,
10 revlog,
11 revlog,
11 transaction,
12 transaction,
12 vfs,
13 vfs,
13 )
14 )
14
15
15 from mercurial.revlogutils import (
16 from mercurial.revlogutils import (
16 deltas,
17 deltas,
17 )
18 )
18
19
19 # TESTTMP is optional. This makes it convenient to run without run-tests.py
20 # TESTTMP is optional. This makes it convenient to run without run-tests.py
20 tvfs = vfs.vfs(encoding.environ.get(b'TESTTMP', b'/tmp'))
21 tvfs = vfs.vfs(encoding.environ.get(b'TESTTMP', b'/tmp'))
21
22
22 # Enable generaldelta otherwise revlog won't use delta as expected by the test
23 # Enable generaldelta otherwise revlog won't use delta as expected by the test
23 tvfs.options = {b'generaldelta': True, b'revlogv1': True,
24 tvfs.options = {b'generaldelta': True, b'revlogv1': True,
24 b'sparse-revlog': True}
25 b'sparse-revlog': True}
25
26
26 # The test wants to control whether to use delta explicitly, based on
27 # The test wants to control whether to use delta explicitly, based on
27 # "storedeltachains".
28 # "storedeltachains".
28 revlog.revlog._isgooddeltainfo = lambda self, d, textlen: self._storedeltachains
29 revlog.revlog._isgooddeltainfo = lambda self, d, textlen: self._storedeltachains
29
30
30 def abort(msg):
31 def abort(msg):
31 print('abort: %s' % msg)
32 print('abort: %s' % msg)
32 # Return 0 so run-tests.py could compare the output.
33 # Return 0 so run-tests.py could compare the output.
33 sys.exit()
34 sys.exit()
34
35
35 # Register a revlog processor for flag EXTSTORED.
36 # Register a revlog processor for flag EXTSTORED.
36 #
37 #
37 # It simply prepends a fixed header, and replaces '1' to 'i'. So it has
38 # It simply prepends a fixed header, and replaces '1' to 'i'. So it has
38 # insertion and replacement, and may be interesting to test revlog's line-based
39 # insertion and replacement, and may be interesting to test revlog's line-based
39 # deltas.
40 # deltas.
40 _extheader = b'E\n'
41 _extheader = b'E\n'
41
42
42 def readprocessor(self, rawtext):
43 def readprocessor(self, rawtext):
43 # True: the returned text could be used to verify hash
44 # True: the returned text could be used to verify hash
44 text = rawtext[len(_extheader):].replace(b'i', b'1')
45 text = rawtext[len(_extheader):].replace(b'i', b'1')
45 return text, True
46 return text, True
46
47
47 def writeprocessor(self, text):
48 def writeprocessor(self, text):
48 # False: the returned rawtext shouldn't be used to verify hash
49 # False: the returned rawtext shouldn't be used to verify hash
49 rawtext = _extheader + text.replace(b'1', b'i')
50 rawtext = _extheader + text.replace(b'1', b'i')
50 return rawtext, False
51 return rawtext, False
51
52
52 def rawprocessor(self, rawtext):
53 def rawprocessor(self, rawtext):
53 # False: do not verify hash. Only the content returned by "readprocessor"
54 # False: do not verify hash. Only the content returned by "readprocessor"
54 # can be used to verify hash.
55 # can be used to verify hash.
55 return False
56 return False
56
57
57 revlog.addflagprocessor(revlog.REVIDX_EXTSTORED,
58 revlog.addflagprocessor(revlog.REVIDX_EXTSTORED,
58 (readprocessor, writeprocessor, rawprocessor))
59 (readprocessor, writeprocessor, rawprocessor))
59
60
60 # Utilities about reading and appending revlog
61 # Utilities about reading and appending revlog
61
62
62 def newtransaction():
63 def newtransaction():
63 # A transaction is required to write revlogs
64 # A transaction is required to write revlogs
64 report = lambda msg: None
65 report = lambda msg: None
65 return transaction.transaction(report, tvfs, {'plain': tvfs}, b'journal')
66 return transaction.transaction(report, tvfs, {'plain': tvfs}, b'journal')
66
67
67 def newrevlog(name=b'_testrevlog.i', recreate=False):
68 def newrevlog(name=b'_testrevlog.i', recreate=False):
68 if recreate:
69 if recreate:
69 tvfs.tryunlink(name)
70 tvfs.tryunlink(name)
70 rlog = revlog.revlog(tvfs, name)
71 rlog = revlog.revlog(tvfs, name)
71 return rlog
72 return rlog
72
73
73 def appendrev(rlog, text, tr, isext=False, isdelta=True):
74 def appendrev(rlog, text, tr, isext=False, isdelta=True):
74 '''Append a revision. If isext is True, set the EXTSTORED flag so flag
75 '''Append a revision. If isext is True, set the EXTSTORED flag so flag
75 processor will be used (and rawtext is different from text). If isdelta is
76 processor will be used (and rawtext is different from text). If isdelta is
76 True, force the revision to be a delta, otherwise it's full text.
77 True, force the revision to be a delta, otherwise it's full text.
77 '''
78 '''
78 nextrev = len(rlog)
79 nextrev = len(rlog)
79 p1 = rlog.node(nextrev - 1)
80 p1 = rlog.node(nextrev - 1)
80 p2 = node.nullid
81 p2 = node.nullid
81 if isext:
82 if isext:
82 flags = revlog.REVIDX_EXTSTORED
83 flags = revlog.REVIDX_EXTSTORED
83 else:
84 else:
84 flags = revlog.REVIDX_DEFAULT_FLAGS
85 flags = revlog.REVIDX_DEFAULT_FLAGS
85 # Change storedeltachains temporarily, to override revlog's delta decision
86 # Change storedeltachains temporarily, to override revlog's delta decision
86 rlog._storedeltachains = isdelta
87 rlog._storedeltachains = isdelta
87 try:
88 try:
88 rlog.addrevision(text, tr, nextrev, p1, p2, flags=flags)
89 rlog.addrevision(text, tr, nextrev, p1, p2, flags=flags)
89 return nextrev
90 return nextrev
90 except Exception as ex:
91 except Exception as ex:
91 abort('rev %d: failed to append: %s' % (nextrev, ex))
92 abort('rev %d: failed to append: %s' % (nextrev, ex))
92 finally:
93 finally:
93 # Restore storedeltachains. It is always True, see revlog.__init__
94 # Restore storedeltachains. It is always True, see revlog.__init__
94 rlog._storedeltachains = True
95 rlog._storedeltachains = True
95
96
96 def addgroupcopy(rlog, tr, destname=b'_destrevlog.i', optimaldelta=True):
97 def addgroupcopy(rlog, tr, destname=b'_destrevlog.i', optimaldelta=True):
97 '''Copy revlog to destname using revlog.addgroup. Return the copied revlog.
98 '''Copy revlog to destname using revlog.addgroup. Return the copied revlog.
98
99
99 This emulates push or pull. They use changegroup. Changegroup requires
100 This emulates push or pull. They use changegroup. Changegroup requires
100 repo to work. We don't have a repo, so a dummy changegroup is used.
101 repo to work. We don't have a repo, so a dummy changegroup is used.
101
102
102 If optimaldelta is True, use optimized delta parent, so the destination
103 If optimaldelta is True, use optimized delta parent, so the destination
103 revlog could probably reuse it. Otherwise it builds sub-optimal delta, and
104 revlog could probably reuse it. Otherwise it builds sub-optimal delta, and
104 the destination revlog needs more work to use it.
105 the destination revlog needs more work to use it.
105
106
106 This exercises some revlog.addgroup (and revlog._addrevision(text=None))
107 This exercises some revlog.addgroup (and revlog._addrevision(text=None))
107 code path, which is not covered by "appendrev" alone.
108 code path, which is not covered by "appendrev" alone.
108 '''
109 '''
109 class dummychangegroup(object):
110 class dummychangegroup(object):
110 @staticmethod
111 @staticmethod
111 def deltachunk(pnode):
112 def deltachunk(pnode):
112 pnode = pnode or node.nullid
113 pnode = pnode or node.nullid
113 parentrev = rlog.rev(pnode)
114 parentrev = rlog.rev(pnode)
114 r = parentrev + 1
115 r = parentrev + 1
115 if r >= len(rlog):
116 if r >= len(rlog):
116 return {}
117 return {}
117 if optimaldelta:
118 if optimaldelta:
118 deltaparent = parentrev
119 deltaparent = parentrev
119 else:
120 else:
120 # suboptimal deltaparent
121 # suboptimal deltaparent
121 deltaparent = min(0, parentrev)
122 deltaparent = min(0, parentrev)
122 if not rlog.candelta(deltaparent, r):
123 if not rlog.candelta(deltaparent, r):
123 deltaparent = -1
124 deltaparent = -1
124 return {b'node': rlog.node(r), b'p1': pnode, b'p2': node.nullid,
125 return {b'node': rlog.node(r), b'p1': pnode, b'p2': node.nullid,
125 b'cs': rlog.node(rlog.linkrev(r)), b'flags': rlog.flags(r),
126 b'cs': rlog.node(rlog.linkrev(r)), b'flags': rlog.flags(r),
126 b'deltabase': rlog.node(deltaparent),
127 b'deltabase': rlog.node(deltaparent),
127 b'delta': rlog.revdiff(deltaparent, r)}
128 b'delta': rlog.revdiff(deltaparent, r)}
128
129
129 def deltaiter(self):
130 def deltaiter(self):
130 chain = None
131 chain = None
131 for chunkdata in iter(lambda: self.deltachunk(chain), {}):
132 for chunkdata in iter(lambda: self.deltachunk(chain), {}):
132 node = chunkdata[b'node']
133 node = chunkdata[b'node']
133 p1 = chunkdata[b'p1']
134 p1 = chunkdata[b'p1']
134 p2 = chunkdata[b'p2']
135 p2 = chunkdata[b'p2']
135 cs = chunkdata[b'cs']
136 cs = chunkdata[b'cs']
136 deltabase = chunkdata[b'deltabase']
137 deltabase = chunkdata[b'deltabase']
137 delta = chunkdata[b'delta']
138 delta = chunkdata[b'delta']
138 flags = chunkdata[b'flags']
139 flags = chunkdata[b'flags']
139
140
140 chain = node
141 chain = node
141
142
142 yield (node, p1, p2, cs, deltabase, delta, flags)
143 yield (node, p1, p2, cs, deltabase, delta, flags)
143
144
144 def linkmap(lnode):
145 def linkmap(lnode):
145 return rlog.rev(lnode)
146 return rlog.rev(lnode)
146
147
147 dlog = newrevlog(destname, recreate=True)
148 dlog = newrevlog(destname, recreate=True)
148 dummydeltas = dummychangegroup().deltaiter()
149 dummydeltas = dummychangegroup().deltaiter()
149 dlog.addgroup(dummydeltas, linkmap, tr)
150 dlog.addgroup(dummydeltas, linkmap, tr)
150 return dlog
151 return dlog
151
152
152 def lowlevelcopy(rlog, tr, destname=b'_destrevlog.i'):
153 def lowlevelcopy(rlog, tr, destname=b'_destrevlog.i'):
153 '''Like addgroupcopy, but use the low level revlog._addrevision directly.
154 '''Like addgroupcopy, but use the low level revlog._addrevision directly.
154
155
155 It exercises some code paths that are hard to reach easily otherwise.
156 It exercises some code paths that are hard to reach easily otherwise.
156 '''
157 '''
157 dlog = newrevlog(destname, recreate=True)
158 dlog = newrevlog(destname, recreate=True)
158 for r in rlog:
159 for r in rlog:
159 p1 = rlog.node(r - 1)
160 p1 = rlog.node(r - 1)
160 p2 = node.nullid
161 p2 = node.nullid
161 if r == 0 or (rlog.flags(r) & revlog.REVIDX_EXTSTORED):
162 if r == 0 or (rlog.flags(r) & revlog.REVIDX_EXTSTORED):
162 text = rlog.revision(r, raw=True)
163 text = rlog.revision(r, raw=True)
163 cachedelta = None
164 cachedelta = None
164 else:
165 else:
165 # deltaparent cannot have EXTSTORED flag.
166 # deltaparent cannot have EXTSTORED flag.
166 deltaparent = max([-1] +
167 deltaparent = max([-1] +
167 [p for p in range(r)
168 [p for p in range(r)
168 if rlog.flags(p) & revlog.REVIDX_EXTSTORED == 0])
169 if rlog.flags(p) & revlog.REVIDX_EXTSTORED == 0])
169 text = None
170 text = None
170 cachedelta = (deltaparent, rlog.revdiff(deltaparent, r))
171 cachedelta = (deltaparent, rlog.revdiff(deltaparent, r))
171 flags = rlog.flags(r)
172 flags = rlog.flags(r)
172 ifh = dfh = None
173 ifh = dfh = None
173 try:
174 try:
174 ifh = dlog.opener(dlog.indexfile, b'a+')
175 ifh = dlog.opener(dlog.indexfile, b'a+')
175 if not dlog._inline:
176 if not dlog._inline:
176 dfh = dlog.opener(dlog.datafile, b'a+')
177 dfh = dlog.opener(dlog.datafile, b'a+')
177 dlog._addrevision(rlog.node(r), text, tr, r, p1, p2, flags,
178 dlog._addrevision(rlog.node(r), text, tr, r, p1, p2, flags,
178 cachedelta, ifh, dfh)
179 cachedelta, ifh, dfh)
179 finally:
180 finally:
180 if dfh is not None:
181 if dfh is not None:
181 dfh.close()
182 dfh.close()
182 if ifh is not None:
183 if ifh is not None:
183 ifh.close()
184 ifh.close()
184 return dlog
185 return dlog
185
186
186 # Utilities to generate revisions for testing
187 # Utilities to generate revisions for testing
187
188
188 def genbits(n):
189 def genbits(n):
189 '''Given a number n, generate (2 ** (n * 2) + 1) numbers in range(2 ** n).
190 '''Given a number n, generate (2 ** (n * 2) + 1) numbers in range(2 ** n).
190 i.e. the generated numbers have a width of n bits.
191 i.e. the generated numbers have a width of n bits.
191
192
192 The combination of two adjacent numbers will cover all possible cases.
193 The combination of two adjacent numbers will cover all possible cases.
193 That is to say, given any x, y where both x, and y are in range(2 ** n),
194 That is to say, given any x, y where both x, and y are in range(2 ** n),
194 there is an x followed immediately by y in the generated sequence.
195 there is an x followed immediately by y in the generated sequence.
195 '''
196 '''
196 m = 2 ** n
197 m = 2 ** n
197
198
198 # Gray Code. See https://en.wikipedia.org/wiki/Gray_code
199 # Gray Code. See https://en.wikipedia.org/wiki/Gray_code
199 gray = lambda x: x ^ (x >> 1)
200 gray = lambda x: x ^ (x >> 1)
200 reversegray = dict((gray(i), i) for i in range(m))
201 reversegray = dict((gray(i), i) for i in range(m))
201
202
202 # Generate (n * 2) bit gray code, yield lower n bits as X, and look for
203 # Generate (n * 2) bit gray code, yield lower n bits as X, and look for
203 # the next unused gray code where higher n bits equal to X.
204 # the next unused gray code where higher n bits equal to X.
204
205
205 # For gray codes whose higher bits are X, a[X] of them have been used.
206 # For gray codes whose higher bits are X, a[X] of them have been used.
206 a = [0] * m
207 a = [0] * m
207
208
208 # Iterate from 0.
209 # Iterate from 0.
209 x = 0
210 x = 0
210 yield x
211 yield x
211 for i in range(m * m):
212 for i in range(m * m):
212 x = reversegray[x]
213 x = reversegray[x]
213 y = gray(a[x] + x * m) & (m - 1)
214 y = gray(a[x] + x * m) & (m - 1)
214 assert a[x] < m
215 assert a[x] < m
215 a[x] += 1
216 a[x] += 1
216 x = y
217 x = y
217 yield x
218 yield x
218
219
219 def gentext(rev):
220 def gentext(rev):
220 '''Given a revision number, generate dummy text'''
221 '''Given a revision number, generate dummy text'''
221 return b''.join(b'%d\n' % j for j in range(-1, rev % 5))
222 return b''.join(b'%d\n' % j for j in range(-1, rev % 5))
222
223
223 def writecases(rlog, tr):
224 def writecases(rlog, tr):
224 '''Write some revisions interested to the test.
225 '''Write some revisions interested to the test.
225
226
226 The test is interested in 3 properties of a revision:
227 The test is interested in 3 properties of a revision:
227
228
228 - Is it a delta or a full text? (isdelta)
229 - Is it a delta or a full text? (isdelta)
229 This is to catch some delta application issues.
230 This is to catch some delta application issues.
230 - Does it have a flag of EXTSTORED? (isext)
231 - Does it have a flag of EXTSTORED? (isext)
231 This is to catch some flag processor issues. Especially when
232 This is to catch some flag processor issues. Especially when
232 interacted with revlog deltas.
233 interacted with revlog deltas.
233 - Is its text empty? (isempty)
234 - Is its text empty? (isempty)
234 This is less important. It is intended to try to catch some careless
235 This is less important. It is intended to try to catch some careless
235 checks like "if text" instead of "if text is None". Note: if flag
236 checks like "if text" instead of "if text is None". Note: if flag
236 processor is involved, raw text may be not empty.
237 processor is involved, raw text may be not empty.
237
238
238 Write 65 revisions. So that all combinations of the above flags for
239 Write 65 revisions. So that all combinations of the above flags for
239 adjacent revisions are covered. That is to say,
240 adjacent revisions are covered. That is to say,
240
241
241 len(set(
242 len(set(
242 (r.delta, r.ext, r.empty, (r+1).delta, (r+1).ext, (r+1).empty)
243 (r.delta, r.ext, r.empty, (r+1).delta, (r+1).ext, (r+1).empty)
243 for r in range(len(rlog) - 1)
244 for r in range(len(rlog) - 1)
244 )) is 64.
245 )) is 64.
245
246
246 Where "r.delta", "r.ext", and "r.empty" are booleans matching properties
247 Where "r.delta", "r.ext", and "r.empty" are booleans matching properties
247 mentioned above.
248 mentioned above.
248
249
249 Return expected [(text, rawtext)].
250 Return expected [(text, rawtext)].
250 '''
251 '''
251 result = []
252 result = []
252 for i, x in enumerate(genbits(3)):
253 for i, x in enumerate(genbits(3)):
253 isdelta, isext, isempty = bool(x & 1), bool(x & 2), bool(x & 4)
254 isdelta, isext, isempty = bool(x & 1), bool(x & 2), bool(x & 4)
254 if isempty:
255 if isempty:
255 text = b''
256 text = b''
256 else:
257 else:
257 text = gentext(i)
258 text = gentext(i)
258 rev = appendrev(rlog, text, tr, isext=isext, isdelta=isdelta)
259 rev = appendrev(rlog, text, tr, isext=isext, isdelta=isdelta)
259
260
260 # Verify text, rawtext, and rawsize
261 # Verify text, rawtext, and rawsize
261 if isext:
262 if isext:
262 rawtext = writeprocessor(None, text)[0]
263 rawtext = writeprocessor(None, text)[0]
263 else:
264 else:
264 rawtext = text
265 rawtext = text
265 if rlog.rawsize(rev) != len(rawtext):
266 if rlog.rawsize(rev) != len(rawtext):
266 abort('rev %d: wrong rawsize' % rev)
267 abort('rev %d: wrong rawsize' % rev)
267 if rlog.revision(rev, raw=False) != text:
268 if rlog.revision(rev, raw=False) != text:
268 abort('rev %d: wrong text' % rev)
269 abort('rev %d: wrong text' % rev)
269 if rlog.revision(rev, raw=True) != rawtext:
270 if rlog.revision(rev, raw=True) != rawtext:
270 abort('rev %d: wrong rawtext' % rev)
271 abort('rev %d: wrong rawtext' % rev)
271 result.append((text, rawtext))
272 result.append((text, rawtext))
272
273
273 # Verify flags like isdelta, isext work as expected
274 # Verify flags like isdelta, isext work as expected
274 # isdelta can be overridden to False if this or p1 has isext set
275 # isdelta can be overridden to False if this or p1 has isext set
275 if bool(rlog.deltaparent(rev) > -1) and not isdelta:
276 if bool(rlog.deltaparent(rev) > -1) and not isdelta:
276 abort('rev %d: isdelta is unexpected' % rev)
277 abort('rev %d: isdelta is unexpected' % rev)
277 if bool(rlog.flags(rev)) != isext:
278 if bool(rlog.flags(rev)) != isext:
278 abort('rev %d: isext is ineffective' % rev)
279 abort('rev %d: isext is ineffective' % rev)
279 return result
280 return result
280
281
281 # Main test and checking
282 # Main test and checking
282
283
283 def checkrevlog(rlog, expected):
284 def checkrevlog(rlog, expected):
284 '''Check if revlog has expected contents. expected is [(text, rawtext)]'''
285 '''Check if revlog has expected contents. expected is [(text, rawtext)]'''
285 # Test using different access orders. This could expose some issues
286 # Test using different access orders. This could expose some issues
286 # depending on revlog caching (see revlog._cache).
287 # depending on revlog caching (see revlog._cache).
287 for r0 in range(len(rlog) - 1):
288 for r0 in range(len(rlog) - 1):
288 r1 = r0 + 1
289 r1 = r0 + 1
289 for revorder in [[r0, r1], [r1, r0]]:
290 for revorder in [[r0, r1], [r1, r0]]:
290 for raworder in [[True], [False], [True, False], [False, True]]:
291 for raworder in [[True], [False], [True, False], [False, True]]:
291 nlog = newrevlog()
292 nlog = newrevlog()
292 for rev in revorder:
293 for rev in revorder:
293 for raw in raworder:
294 for raw in raworder:
294 t = nlog.revision(rev, raw=raw)
295 t = nlog.revision(rev, raw=raw)
295 if t != expected[rev][int(raw)]:
296 if t != expected[rev][int(raw)]:
296 abort('rev %d: corrupted %stext'
297 abort('rev %d: corrupted %stext'
297 % (rev, raw and 'raw' or ''))
298 % (rev, raw and 'raw' or ''))
298
299
299 slicingdata = [
300 slicingdata = [
300 ([0, 1, 2, 3, 55, 56, 58, 59, 60],
301 ([0, 1, 2, 3, 55, 56, 58, 59, 60],
301 [[0, 1], [2], [58], [59, 60]],
302 [[0, 1], [2], [58], [59, 60]],
302 10),
303 10),
303 ([0, 1, 2, 3, 55, 56, 58, 59, 60],
304 ([0, 1, 2, 3, 55, 56, 58, 59, 60],
304 [[0, 1], [2], [58], [59, 60]],
305 [[0, 1], [2], [58], [59, 60]],
305 10),
306 10),
306 ([-1, 0, 1, 2, 3, 55, 56, 58, 59, 60],
307 ([-1, 0, 1, 2, 3, 55, 56, 58, 59, 60],
307 [[-1, 0, 1], [2], [58], [59, 60]],
308 [[-1, 0, 1], [2], [58], [59, 60]],
308 10),
309 10),
309 ]
310 ]
310
311
311 def slicingtest(rlog):
312 def slicingtest(rlog):
312 oldmin = rlog._srmingapsize
313 oldmin = rlog._srmingapsize
313 try:
314 try:
314 # the test revlog is small, we remove the floor under which we
315 # the test revlog is small, we remove the floor under which we
315 # slicing is diregarded.
316 # slicing is diregarded.
316 rlog._srmingapsize = 0
317 rlog._srmingapsize = 0
317 for item in slicingdata:
318 for item in slicingdata:
318 chain, expected, target = item
319 chain, expected, target = item
319 result = deltas.slicechunk(rlog, chain, targetsize=target)
320 result = deltas.slicechunk(rlog, chain, targetsize=target)
320 result = list(result)
321 result = list(result)
321 if result != expected:
322 if result != expected:
322 print('slicing differ:')
323 print('slicing differ:')
323 print(' chain: %s' % chain)
324 print(' chain: %s' % chain)
324 print(' target: %s' % target)
325 print(' target: %s' % target)
325 print(' expected: %s' % expected)
326 print(' expected: %s' % expected)
326 print(' result: %s' % result)
327 print(' result: %s' % result)
327 finally:
328 finally:
328 rlog._srmingapsize = oldmin
329 rlog._srmingapsize = oldmin
329
330
331 def md5sum(s):
332 return hashlib.md5(s).digest()
333
334 def _maketext(*coord):
335 """create piece of text according to range of integers
336
337 The test returned use a md5sum of the integer to make it less
338 compressible"""
339 pieces = []
340 for start, size in coord:
341 num = range(start, start + size)
342 p = [md5sum(b'%d' % r) for r in num]
343 pieces.append(b'\n'.join(p))
344 return b'\n'.join(pieces) + b'\n'
345
346 data = [
347 _maketext((0, 120), (456, 60)),
348 _maketext((0, 120), (345, 60)),
349 _maketext((0, 120), (734, 60)),
350 _maketext((0, 120), (734, 60), (923, 45)),
351 _maketext((0, 120), (734, 60), (234, 45)),
352 _maketext((0, 120), (734, 60), (564, 45)),
353 _maketext((0, 120), (734, 60), (361, 45)),
354 _maketext((0, 120), (734, 60), (489, 45)),
355 _maketext((0, 120), (123, 60)),
356 _maketext((0, 120), (145, 60)),
357 _maketext((0, 120), (104, 60)),
358 _maketext((0, 120), (430, 60)),
359 _maketext((0, 120), (430, 60), (923, 45)),
360 _maketext((0, 120), (430, 60), (234, 45)),
361 _maketext((0, 120), (430, 60), (564, 45)),
362 _maketext((0, 120), (430, 60), (361, 45)),
363 _maketext((0, 120), (430, 60), (489, 45)),
364 _maketext((0, 120), (249, 60)),
365 _maketext((0, 120), (832, 60)),
366 _maketext((0, 120), (891, 60)),
367 _maketext((0, 120), (543, 60)),
368 _maketext((0, 120), (120, 60)),
369 _maketext((0, 120), (60, 60), (768, 30)),
370 _maketext((0, 120), (60, 60), (260, 30)),
371 _maketext((0, 120), (60, 60), (450, 30)),
372 _maketext((0, 120), (60, 60), (361, 30)),
373 _maketext((0, 120), (60, 60), (886, 30)),
374 _maketext((0, 120), (60, 60), (116, 30)),
375 _maketext((0, 120), (60, 60), (567, 30), (629, 40)),
376 _maketext((0, 120), (60, 60), (569, 30), (745, 40)),
377 _maketext((0, 120), (60, 60), (777, 30), (700, 40)),
378 _maketext((0, 120), (60, 60), (618, 30), (398, 40), (158, 10)),
379 ]
380
381 def makesnapshot(tr):
382 rl = newrevlog(name=b'_snaprevlog3.i', recreate=True)
383 for i in data:
384 appendrev(rl, i, tr)
385 return rl
386
387 snapshots = [-1, 0, 6, 8, 11, 17, 19, 21, 25, 30]
388 def issnapshottest(rlog):
389 result = []
390 if rlog.issnapshot(-1):
391 result.append(-1)
392 for rev in rlog:
393 if rlog.issnapshot(rev):
394 result.append(rev)
395 if snapshots != result:
396 print('snapshot differ:')
397 print(' expected: %s' % snapshots)
398 print(' got: %s' % result)
399
330 def maintest():
400 def maintest():
331 expected = rl = None
401 expected = rl = None
332 with newtransaction() as tr:
402 with newtransaction() as tr:
333 rl = newrevlog(recreate=True)
403 rl = newrevlog(recreate=True)
334 expected = writecases(rl, tr)
404 expected = writecases(rl, tr)
335 checkrevlog(rl, expected)
405 checkrevlog(rl, expected)
336 print('local test passed')
406 print('local test passed')
337 # Copy via revlog.addgroup
407 # Copy via revlog.addgroup
338 rl1 = addgroupcopy(rl, tr)
408 rl1 = addgroupcopy(rl, tr)
339 checkrevlog(rl1, expected)
409 checkrevlog(rl1, expected)
340 rl2 = addgroupcopy(rl, tr, optimaldelta=False)
410 rl2 = addgroupcopy(rl, tr, optimaldelta=False)
341 checkrevlog(rl2, expected)
411 checkrevlog(rl2, expected)
342 print('addgroupcopy test passed')
412 print('addgroupcopy test passed')
343 # Copy via revlog.clone
413 # Copy via revlog.clone
344 rl3 = newrevlog(name=b'_destrevlog3.i', recreate=True)
414 rl3 = newrevlog(name=b'_destrevlog3.i', recreate=True)
345 rl.clone(tr, rl3)
415 rl.clone(tr, rl3)
346 checkrevlog(rl3, expected)
416 checkrevlog(rl3, expected)
347 print('clone test passed')
417 print('clone test passed')
348 # Copy via low-level revlog._addrevision
418 # Copy via low-level revlog._addrevision
349 rl4 = lowlevelcopy(rl, tr)
419 rl4 = lowlevelcopy(rl, tr)
350 checkrevlog(rl4, expected)
420 checkrevlog(rl4, expected)
351 print('lowlevelcopy test passed')
421 print('lowlevelcopy test passed')
352 slicingtest(rl)
422 slicingtest(rl)
353 print('slicing test passed')
423 print('slicing test passed')
424 rl5 = makesnapshot(tr)
425 issnapshottest(rl5)
426 print('issnapshot test passed')
354
427
355 try:
428 try:
356 maintest()
429 maintest()
357 except Exception as ex:
430 except Exception as ex:
358 abort('crashed: %s' % ex)
431 abort('crashed: %s' % ex)
@@ -1,5 +1,6 b''
1 local test passed
1 local test passed
2 addgroupcopy test passed
2 addgroupcopy test passed
3 clone test passed
3 clone test passed
4 lowlevelcopy test passed
4 lowlevelcopy test passed
5 slicing test passed
5 slicing test passed
6 issnapshot test passed
General Comments 0
You need to be logged in to leave comments. Login now