Merge lp:~spiv/bzr/gc-batching into lp:~bzr/bzr/trunk-old

Proposed by Andrew Bennetts
Status: Merged
Merged at revision: not available
Proposed branch: lp:~spiv/bzr/gc-batching
Merge into: lp:~bzr/bzr/trunk-old
Diff against target: 115 lines
To merge this branch: bzr merge lp:~spiv/bzr/gc-batching
Reviewer Review Type Date Requested Status
Vincent Ladeuil Approve
Review via email: mp+10831@code.launchpad.net
To post a comment you must log in.
Revision history for this message
Andrew Bennetts (spiv) wrote :

This adds some unit tests for _BatchingBlockFetcher. These tests are a bit weak, but they at least cover a few interesting cases and also manage to exercise every line except for the assertion). But it's a start, and will hopefully help the next person that touches this code (to understand and change the code with confidence, and also as a starting point for more adding more thorough tests).

Revision history for this message
Vincent Ladeuil (vila) wrote :

Amen

review: Approve

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'bzrlib/tests/test_groupcompress.py'
2--- bzrlib/tests/test_groupcompress.py 2009-06-29 14:51:13 +0000
3+++ bzrlib/tests/test_groupcompress.py 2009-08-28 06:35:10 +0000
4@@ -702,6 +702,111 @@
5 " 0 8', \(\(\('a',\),\),\)\)")
6
7
8+class StubGCVF(object):
9+ def __init__(self, canned_get_blocks=None):
10+ self._group_cache = {}
11+ self._canned_get_blocks = canned_get_blocks or []
12+ def _get_blocks(self, read_memos):
13+ return iter(self._canned_get_blocks)
14+
15+
16+class Test_BatchingBlockFetcher(TestCaseWithGroupCompressVersionedFiles):
17+ """Simple whitebox unit tests for _BatchingBlockFetcher."""
18+
19+ def test_add_key_new_read_memo(self):
20+ """Adding a key with an uncached read_memo new to this batch adds that
21+ read_memo to the list of memos to fetch.
22+ """
23+ # locations are: index_memo, ignored, parents, ignored
24+ # where index_memo is: (idx, offset, len, factory_start, factory_end)
25+ # and (idx, offset, size) is known as the 'read_memo', identifying the
26+ # raw bytes needed.
27+ read_memo = ('fake index', 100, 50)
28+ locations = {
29+ ('key',): (read_memo + (None, None), None, None, None)}
30+ batcher = groupcompress._BatchingBlockFetcher(StubGCVF(), locations)
31+ total_size = batcher.add_key(('key',))
32+ self.assertEqual(50, total_size)
33+ self.assertEqual([('key',)], batcher.keys)
34+ self.assertEqual([read_memo], batcher.memos_to_get)
35+
36+ def test_add_key_duplicate_read_memo(self):
37+ """read_memos that occur multiple times in a batch will only be fetched
38+ once.
39+ """
40+ read_memo = ('fake index', 100, 50)
41+ # Two keys, both sharing the same read memo (but different overall
42+ # index_memos).
43+ locations = {
44+ ('key1',): (read_memo + (0, 1), None, None, None),
45+ ('key2',): (read_memo + (1, 2), None, None, None)}
46+ batcher = groupcompress._BatchingBlockFetcher(StubGCVF(), locations)
47+ total_size = batcher.add_key(('key1',))
48+ total_size = batcher.add_key(('key2',))
49+ self.assertEqual(50, total_size)
50+ self.assertEqual([('key1',), ('key2',)], batcher.keys)
51+ self.assertEqual([read_memo], batcher.memos_to_get)
52+
53+ def test_add_key_cached_read_memo(self):
54+ """Adding a key with a cached read_memo will not cause that read_memo
55+ to be added to the list to fetch.
56+ """
57+ read_memo = ('fake index', 100, 50)
58+ gcvf = StubGCVF()
59+ gcvf._group_cache[read_memo] = 'fake block'
60+ locations = {
61+ ('key',): (read_memo + (None, None), None, None, None)}
62+ batcher = groupcompress._BatchingBlockFetcher(gcvf, locations)
63+ total_size = batcher.add_key(('key',))
64+ self.assertEqual(0, total_size)
65+ self.assertEqual([('key',)], batcher.keys)
66+ self.assertEqual([], batcher.memos_to_get)
67+
68+ def test_yield_factories_empty(self):
69+ """An empty batch yields no factories."""
70+ batcher = groupcompress._BatchingBlockFetcher(StubGCVF(), {})
71+ self.assertEqual([], list(batcher.yield_factories()))
72+
73+ def test_yield_factories_calls_get_blocks(self):
74+ """Uncached memos are retrieved via get_blocks."""
75+ read_memo1 = ('fake index', 100, 50)
76+ read_memo2 = ('fake index', 150, 40)
77+ gcvf = StubGCVF(
78+ canned_get_blocks=[
79+ (read_memo1, groupcompress.GroupCompressBlock()),
80+ (read_memo2, groupcompress.GroupCompressBlock())])
81+ locations = {
82+ ('key1',): (read_memo1 + (None, None), None, None, None),
83+ ('key2',): (read_memo2 + (None, None), None, None, None)}
84+ batcher = groupcompress._BatchingBlockFetcher(gcvf, locations)
85+ batcher.add_key(('key1',))
86+ batcher.add_key(('key2',))
87+ factories = list(batcher.yield_factories(full_flush=True))
88+ self.assertLength(2, factories)
89+ keys = [f.key for f in factories]
90+ kinds = [f.storage_kind for f in factories]
91+ self.assertEqual([('key1',), ('key2',)], keys)
92+ self.assertEqual(['groupcompress-block', 'groupcompress-block'], kinds)
93+
94+ def test_yield_factories_flushing(self):
95+ """yield_factories holds back on yielding results from the final block
96+ unless passed full_flush=True.
97+ """
98+ fake_block = groupcompress.GroupCompressBlock()
99+ read_memo = ('fake index', 100, 50)
100+ gcvf = StubGCVF()
101+ gcvf._group_cache[read_memo] = fake_block
102+ locations = {
103+ ('key',): (read_memo + (None, None), None, None, None)}
104+ batcher = groupcompress._BatchingBlockFetcher(gcvf, locations)
105+ batcher.add_key(('key',))
106+ self.assertEqual([], list(batcher.yield_factories()))
107+ factories = list(batcher.yield_factories(full_flush=True))
108+ self.assertLength(1, factories)
109+ self.assertEqual(('key',), factories[0].key)
110+ self.assertEqual('groupcompress-block', factories[0].storage_kind)
111+
112+
113 class TestLazyGroupCompress(tests.TestCaseWithTransport):
114
115 _texts = {