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