25 basepack, |
25 basepack, |
26 constants, |
26 constants, |
27 datapack, |
27 datapack, |
28 ) |
28 ) |
29 |
29 |
|
30 |
30 class datapacktestsbase(object): |
31 class datapacktestsbase(object): |
31 def __init__(self, datapackreader, paramsavailable): |
32 def __init__(self, datapackreader, paramsavailable): |
32 self.datapackreader = datapackreader |
33 self.datapackreader = datapackreader |
33 self.paramsavailable = paramsavailable |
34 self.paramsavailable = paramsavailable |
34 |
35 |
46 |
47 |
47 def getHash(self, content): |
48 def getHash(self, content): |
48 return hashlib.sha1(content).digest() |
49 return hashlib.sha1(content).digest() |
49 |
50 |
50 def getFakeHash(self): |
51 def getFakeHash(self): |
51 return b''.join(pycompat.bytechr(random.randint(0, 255)) |
52 return b''.join( |
52 for _ in range(20)) |
53 pycompat.bytechr(random.randint(0, 255)) for _ in range(20) |
|
54 ) |
53 |
55 |
54 def createPack(self, revisions=None, packdir=None): |
56 def createPack(self, revisions=None, packdir=None): |
55 if revisions is None: |
57 if revisions is None: |
56 revisions = [(b"filename", self.getFakeHash(), nullid, b"content")] |
58 revisions = [(b"filename", self.getFakeHash(), nullid, b"content")] |
57 |
59 |
78 node = self.getHash(content) |
80 node = self.getHash(content) |
79 |
81 |
80 revisions = [(filename, node, nullid, content)] |
82 revisions = [(filename, node, nullid, content)] |
81 pack = self.createPack(revisions) |
83 pack = self.createPack(revisions) |
82 if self.paramsavailable: |
84 if self.paramsavailable: |
83 self.assertEqual(pack.params.fanoutprefix, |
85 self.assertEqual( |
84 basepack.SMALLFANOUTPREFIX) |
86 pack.params.fanoutprefix, basepack.SMALLFANOUTPREFIX |
|
87 ) |
85 |
88 |
86 chain = pack.getdeltachain(filename, node) |
89 chain = pack.getdeltachain(filename, node) |
87 self.assertEqual(content, chain[0][4]) |
90 self.assertEqual(content, chain[0][4]) |
88 |
91 |
89 def testAddSingle(self): |
92 def testAddSingle(self): |
169 revisions = [] |
172 revisions = [] |
170 for i in range(100): |
173 for i in range(100): |
171 filename = b'%d.txt' % i |
174 filename = b'%d.txt' % i |
172 content = b'put-something-here \n' * i |
175 content = b'put-something-here \n' * i |
173 node = self.getHash(content) |
176 node = self.getHash(content) |
174 meta = {constants.METAKEYFLAG: i ** 4, |
177 meta = { |
175 constants.METAKEYSIZE: len(content), |
178 constants.METAKEYFLAG: i ** 4, |
176 b'Z': b'random_string', |
179 constants.METAKEYSIZE: len(content), |
177 b'_': b'\0' * i} |
180 b'Z': b'random_string', |
|
181 b'_': b'\0' * i, |
|
182 } |
178 revisions.append((filename, node, nullid, content, meta)) |
183 revisions.append((filename, node, nullid, content, meta)) |
179 pack = self.createPack(revisions) |
184 pack = self.createPack(revisions) |
180 for name, node, x, content, origmeta in revisions: |
185 for name, node, x, content, origmeta in revisions: |
181 parsedmeta = pack.getmeta(name, node) |
186 parsedmeta = pack.getmeta(name, node) |
182 # flag == 0 should be optimized out |
187 # flag == 0 should be optimized out |
199 pack = self.createPack(revisions) |
204 pack = self.createPack(revisions) |
200 |
205 |
201 missing = pack.getmissing([(b"foo", revisions[0][1])]) |
206 missing = pack.getmissing([(b"foo", revisions[0][1])]) |
202 self.assertFalse(missing) |
207 self.assertFalse(missing) |
203 |
208 |
204 missing = pack.getmissing([(b"foo", revisions[0][1]), |
209 missing = pack.getmissing( |
205 (b"foo", revisions[1][1])]) |
210 [(b"foo", revisions[0][1]), (b"foo", revisions[1][1])] |
|
211 ) |
206 self.assertFalse(missing) |
212 self.assertFalse(missing) |
207 |
213 |
208 fakenode = self.getFakeHash() |
214 fakenode = self.getFakeHash() |
209 missing = pack.getmissing([(b"foo", revisions[0][1]), |
215 missing = pack.getmissing( |
210 (b"foo", fakenode)]) |
216 [(b"foo", revisions[0][1]), (b"foo", fakenode)] |
|
217 ) |
211 self.assertEqual(missing, [(b"foo", fakenode)]) |
218 self.assertEqual(missing, [(b"foo", fakenode)]) |
212 |
219 |
213 def testAddThrows(self): |
220 def testAddThrows(self): |
214 pack = self.createPack() |
221 pack = self.createPack() |
215 |
222 |
255 blobs[(filename, node)] = content |
262 blobs[(filename, node)] = content |
256 revisions.append((filename, node, nullid, content)) |
263 revisions.append((filename, node, nullid, content)) |
257 |
264 |
258 pack = self.createPack(revisions) |
265 pack = self.createPack(revisions) |
259 if self.paramsavailable: |
266 if self.paramsavailable: |
260 self.assertEqual(pack.params.fanoutprefix, |
267 self.assertEqual( |
261 basepack.LARGEFANOUTPREFIX) |
268 pack.params.fanoutprefix, basepack.LARGEFANOUTPREFIX |
|
269 ) |
262 |
270 |
263 for (filename, node), content in blobs.items(): |
271 for (filename, node), content in blobs.items(): |
264 actualcontent = pack.getdeltachain(filename, node)[0][4] |
272 actualcontent = pack.getdeltachain(filename, node)[0][4] |
265 self.assertEqual(actualcontent, content) |
273 self.assertEqual(actualcontent, content) |
266 |
274 |
301 revision = random.choice(randomchain) |
309 revision = random.choice(randomchain) |
302 chain = store.getdeltachain(revision[0], revision[1]) |
310 chain = store.getdeltachain(revision[0], revision[1]) |
303 |
311 |
304 mostrecentpack = next(iter(store.packs), None) |
312 mostrecentpack = next(iter(store.packs), None) |
305 self.assertEqual( |
313 self.assertEqual( |
306 mostrecentpack.getdeltachain(revision[0], revision[1]), |
314 mostrecentpack.getdeltachain(revision[0], revision[1]), chain |
307 chain |
|
308 ) |
315 ) |
309 |
316 |
310 self.assertEqual(randomchain.index(revision) + 1, len(chain)) |
317 self.assertEqual(randomchain.index(revision) + 1, len(chain)) |
311 |
318 |
312 # perf test off by default since it's slow |
319 # perf test off by default since it's slow |
339 |
346 |
340 path = self.createPack(revisions).path |
347 path = self.createPack(revisions).path |
341 |
348 |
342 # Perf of large multi-get |
349 # Perf of large multi-get |
343 import gc |
350 import gc |
|
351 |
344 gc.disable() |
352 gc.disable() |
345 pack = self.datapackreader(path) |
353 pack = self.datapackreader(path) |
346 for lookupsize in lookupsizes: |
354 for lookupsize in lookupsizes: |
347 if lookupsize > packsize: |
355 if lookupsize > packsize: |
348 continue |
356 continue |
350 findnodes = [(rev[0], rev[1]) for rev in revisions] |
358 findnodes = [(rev[0], rev[1]) for rev in revisions] |
351 |
359 |
352 start = time.time() |
360 start = time.time() |
353 pack.getmissing(findnodes[:lookupsize]) |
361 pack.getmissing(findnodes[:lookupsize]) |
354 elapsed = time.time() - start |
362 elapsed = time.time() - start |
355 print ("%s pack %d lookups = %0.04f" % |
363 print( |
356 (('%d' % packsize).rjust(7), |
364 "%s pack %d lookups = %0.04f" |
|
365 % ( |
|
366 ('%d' % packsize).rjust(7), |
357 ('%d' % lookupsize).rjust(7), |
367 ('%d' % lookupsize).rjust(7), |
358 elapsed)) |
368 elapsed, |
|
369 ) |
|
370 ) |
359 |
371 |
360 print("") |
372 print("") |
361 gc.enable() |
373 gc.enable() |
362 |
374 |
363 # The perf test is meant to produce output, so we always fail the test |
375 # The perf test is meant to produce output, so we always fail the test |
364 # so the user sees the output. |
376 # so the user sees the output. |
365 raise RuntimeError("perf test always fails") |
377 raise RuntimeError("perf test always fails") |
|
378 |
366 |
379 |
367 class datapacktests(datapacktestsbase, unittest.TestCase): |
380 class datapacktests(datapacktestsbase, unittest.TestCase): |
368 def __init__(self, *args, **kwargs): |
381 def __init__(self, *args, **kwargs): |
369 datapacktestsbase.__init__(self, datapack.datapack, True) |
382 datapacktestsbase.__init__(self, datapack.datapack, True) |
370 unittest.TestCase.__init__(self, *args, **kwargs) |
383 unittest.TestCase.__init__(self, *args, **kwargs) |
371 |
384 |
|
385 |
372 # TODO: |
386 # TODO: |
373 # datapack store: |
387 # datapack store: |
374 # - getmissing |
388 # - getmissing |
375 # - GC two packs into one |
389 # - GC two packs into one |
376 |
390 |
377 if __name__ == '__main__': |
391 if __name__ == '__main__': |
378 if pycompat.iswindows: |
392 if pycompat.iswindows: |
379 sys.exit(80) # Skip on Windows |
393 sys.exit(80) # Skip on Windows |
380 silenttestrunner.main(__name__) |
394 silenttestrunner.main(__name__) |