/brz/remove-bazaar

To get this branch, use:
bzr branch http://gegoxaren.bato24.eu/bzr/brz/remove-bazaar
5557.1.15 by John Arbash Meinel
Merge bzr.dev 5597 to resolve NEWS, aka bzr-2.3.txt
1
# Copyright (C) 2008-2011 Canonical Ltd
3582.3.1 by Martin Pool
Split pack repository tests into their own file and use scenarios
2
#
3
# This program is free software; you can redistribute it and/or modify
4
# it under the terms of the GNU General Public License as published by
5
# the Free Software Foundation; either version 2 of the License, or
6
# (at your option) any later version.
7
#
8
# This program is distributed in the hope that it will be useful,
9
# but WITHOUT ANY WARRANTY; without even the implied warranty of
10
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
11
# GNU General Public License for more details.
12
#
13
# You should have received a copy of the GNU General Public License
14
# along with this program; if not, write to the Free Software
4183.7.1 by Sabin Iacob
update FSF mailing address
15
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
3582.3.1 by Martin Pool
Split pack repository tests into their own file and use scenarios
16
17
"""Tests for pack repositories.
18
19
These tests are repeated for all pack-based repository formats.
20
"""
21
22
from stat import S_ISDIR
23
6670.4.1 by Jelmer Vernooij
Update imports.
24
from ..bzr.btree_index import BTreeGraphIndex
25
from ..bzr.index import GraphIndex
6624 by Jelmer Vernooij
Merge Python3 porting work ('py3 pokes')
26
from .. import (
6472.2.1 by Jelmer Vernooij
Use bzrdir.controldir for generic access to control directories.
27
    controldir,
3582.3.1 by Martin Pool
Split pack repository tests into their own file and use scenarios
28
    errors,
4002.1.1 by Andrew Bennetts
Implement suspend_write_group/resume_write_group.
29
    osutils,
3582.3.1 by Martin Pool
Split pack repository tests into their own file and use scenarios
30
    repository,
31
    revision as _mod_revision,
32
    tests,
5609.9.1 by Martin
Blindly change all users of get_transport to address the function via the transport module
33
    transport,
3582.3.1 by Martin Pool
Split pack repository tests into their own file and use scenarios
34
    ui,
4360.4.6 by John Arbash Meinel
Change how 'missing.*parent_prevents_commit' determines what to skip.
35
    )
6670.4.1 by Jelmer Vernooij
Update imports.
36
from ..bzr import (
37
    inventory,
38
    )
6670.4.5 by Jelmer Vernooij
Move breezy.repofmt contents to breezy.bzr.
39
from ..bzr.groupcompress_repo import RepositoryFormat2a
6670.4.16 by Jelmer Vernooij
Move smart to breezy.bzr.
40
from ..bzr.smart import (
3801.1.18 by Andrew Bennetts
Add a test that ensures that the autopack RPC is actually used for all pack formats.
41
    client,
42
    )
6624 by Jelmer Vernooij
Merge Python3 porting work ('py3 pokes')
43
from . import (
3582.3.1 by Martin Pool
Split pack repository tests into their own file and use scenarios
44
    TestCaseWithTransport,
3582.3.3 by Martin Pool
Reenable tests for stacking pack repositories
45
    TestNotApplicable,
3582.3.1 by Martin Pool
Split pack repository tests into their own file and use scenarios
46
    )
6624 by Jelmer Vernooij
Merge Python3 porting work ('py3 pokes')
47
from ..transport import (
5017.3.45 by Vincent Ladeuil
Move MemoryServer back into bzrlib.transport.memory as it's needed as soon as a MemoryTransport is used. Add a NEWS entry.
48
    memory,
3582.3.1 by Martin Pool
Split pack repository tests into their own file and use scenarios
49
    )
6624 by Jelmer Vernooij
Merge Python3 porting work ('py3 pokes')
50
from . import test_server
3582.3.1 by Martin Pool
Split pack repository tests into their own file and use scenarios
51
52
53
class TestPackRepository(TestCaseWithTransport):
54
    """Tests to be repeated across all pack-based formats.
55
56
    The following are populated from the test scenario:
57
58
    :ivar format_name: Registered name fo the format to test.
59
    :ivar format_string: On-disk format marker.
60
    :ivar format_supports_external_lookups: Boolean.
61
    """
62
63
    def get_format(self):
6653.6.5 by Jelmer Vernooij
Rename make_bzrdir to make_controldir.
64
        return controldir.format_registry.make_controldir(self.format_name)
3582.3.1 by Martin Pool
Split pack repository tests into their own file and use scenarios
65
66
    def test_attribute__fetch_order(self):
3606.7.3 by John Arbash Meinel
We don't have to fetch in topological order, as long as we fix all of the delta logic pieces.
67
        """Packs do not need ordered data retrieval."""
3582.3.1 by Martin Pool
Split pack repository tests into their own file and use scenarios
68
        format = self.get_format()
69
        repo = self.make_repository('.', format=format)
4053.1.4 by Robert Collins
Move the fetch control attributes from Repository to RepositoryFormat.
70
        self.assertEqual('unordered', repo._format._fetch_order)
3582.3.1 by Martin Pool
Split pack repository tests into their own file and use scenarios
71
72
    def test_attribute__fetch_uses_deltas(self):
73
        """Packs reuse deltas."""
74
        format = self.get_format()
75
        repo = self.make_repository('.', format=format)
4597.1.10 by John Arbash Meinel
Fix some tests that were failing because we checked against RepositoryFormatCHK1
76
        if isinstance(format.repository_format, RepositoryFormat2a):
4265.1.4 by John Arbash Meinel
Special case the CHK1 format to allow it to not fetch using deltas.
77
            # TODO: This is currently a workaround. CHK format repositories
78
            #       ignore the 'deltas' flag, but during conversions, we can't
79
            #       do unordered delta fetches. Remove this clause once we
80
            #       improve the inter-format fetching.
81
            self.assertEqual(False, repo._format._fetch_uses_deltas)
82
        else:
83
            self.assertEqual(True, repo._format._fetch_uses_deltas)
3582.3.1 by Martin Pool
Split pack repository tests into their own file and use scenarios
84
85
    def test_disk_layout(self):
86
        format = self.get_format()
87
        repo = self.make_repository('.', format=format)
88
        # in case of side effects of locking.
89
        repo.lock_write()
90
        repo.unlock()
6653.6.1 by Jelmer Vernooij
Rename a number of attributes from bzrdir to controldir.
91
        t = repo.controldir.get_repository_transport(None)
3582.3.1 by Martin Pool
Split pack repository tests into their own file and use scenarios
92
        self.check_format(t)
93
        # XXX: no locks left when unlocked at the moment
94
        # self.assertEqualDiff('', t.get('lock').read())
95
        self.check_databases(t)
96
97
    def check_format(self, t):
98
        self.assertEqualDiff(
99
            self.format_string, # from scenario
100
            t.get('format').read())
101
102
    def assertHasNoKndx(self, t, knit_name):
103
        """Assert that knit_name has no index on t."""
104
        self.assertFalse(t.has(knit_name + '.kndx'))
105
106
    def assertHasNoKnit(self, t, knit_name):
107
        """Assert that knit_name exists on t."""
108
        # no default content
109
        self.assertFalse(t.has(knit_name + '.knit'))
110
111
    def check_databases(self, t):
112
        """check knit content for a repository."""
113
        # check conversion worked
114
        self.assertHasNoKndx(t, 'inventory')
115
        self.assertHasNoKnit(t, 'inventory')
116
        self.assertHasNoKndx(t, 'revisions')
117
        self.assertHasNoKnit(t, 'revisions')
118
        self.assertHasNoKndx(t, 'signatures')
119
        self.assertHasNoKnit(t, 'signatures')
120
        self.assertFalse(t.has('knits'))
121
        # revision-indexes file-container directory
122
        self.assertEqual([],
3735.1.1 by Robert Collins
Add development2 formats using BTree indices.
123
            list(self.index_class(t, 'pack-names', None).iter_all_entries()))
3582.3.1 by Martin Pool
Split pack repository tests into their own file and use scenarios
124
        self.assertTrue(S_ISDIR(t.stat('packs').st_mode))
125
        self.assertTrue(S_ISDIR(t.stat('upload').st_mode))
126
        self.assertTrue(S_ISDIR(t.stat('indices').st_mode))
127
        self.assertTrue(S_ISDIR(t.stat('obsolete_packs').st_mode))
128
129
    def test_shared_disk_layout(self):
130
        format = self.get_format()
131
        repo = self.make_repository('.', shared=True, format=format)
132
        # we want:
6653.6.1 by Jelmer Vernooij
Rename a number of attributes from bzrdir to controldir.
133
        t = repo.controldir.get_repository_transport(None)
3582.3.1 by Martin Pool
Split pack repository tests into their own file and use scenarios
134
        self.check_format(t)
135
        # XXX: no locks left when unlocked at the moment
136
        # self.assertEqualDiff('', t.get('lock').read())
137
        # We should have a 'shared-storage' marker file.
138
        self.assertEqualDiff('', t.get('shared-storage').read())
139
        self.check_databases(t)
140
141
    def test_shared_no_tree_disk_layout(self):
142
        format = self.get_format()
143
        repo = self.make_repository('.', shared=True, format=format)
144
        repo.set_make_working_trees(False)
145
        # we want:
6653.6.1 by Jelmer Vernooij
Rename a number of attributes from bzrdir to controldir.
146
        t = repo.controldir.get_repository_transport(None)
3582.3.1 by Martin Pool
Split pack repository tests into their own file and use scenarios
147
        self.check_format(t)
148
        # XXX: no locks left when unlocked at the moment
149
        # self.assertEqualDiff('', t.get('lock').read())
150
        # We should have a 'shared-storage' marker file.
151
        self.assertEqualDiff('', t.get('shared-storage').read())
152
        # We should have a marker for the no-working-trees flag.
153
        self.assertEqualDiff('', t.get('no-working-trees').read())
154
        # The marker should go when we toggle the setting.
155
        repo.set_make_working_trees(True)
156
        self.assertFalse(t.has('no-working-trees'))
157
        self.check_databases(t)
158
159
    def test_adding_revision_creates_pack_indices(self):
160
        format = self.get_format()
161
        tree = self.make_branch_and_tree('.', format=format)
6653.6.1 by Jelmer Vernooij
Rename a number of attributes from bzrdir to controldir.
162
        trans = tree.branch.repository.controldir.get_repository_transport(None)
3582.3.1 by Martin Pool
Split pack repository tests into their own file and use scenarios
163
        self.assertEqual([],
3735.1.1 by Robert Collins
Add development2 formats using BTree indices.
164
            list(self.index_class(trans, 'pack-names', None).iter_all_entries()))
3582.3.1 by Martin Pool
Split pack repository tests into their own file and use scenarios
165
        tree.commit('foobarbaz')
3735.1.1 by Robert Collins
Add development2 formats using BTree indices.
166
        index = self.index_class(trans, 'pack-names', None)
3582.3.1 by Martin Pool
Split pack repository tests into their own file and use scenarios
167
        index_nodes = list(index.iter_all_entries())
168
        self.assertEqual(1, len(index_nodes))
169
        node = index_nodes[0]
170
        name = node[1][0]
171
        # the pack sizes should be listed in the index
172
        pack_value = node[2]
173
        sizes = [int(digits) for digits in pack_value.split(' ')]
174
        for size, suffix in zip(sizes, ['.rix', '.iix', '.tix', '.six']):
175
            stat = trans.stat('indices/%s%s' % (name, suffix))
176
            self.assertEqual(size, stat.st_size)
177
178
    def test_pulling_nothing_leads_to_no_new_names(self):
179
        format = self.get_format()
180
        tree1 = self.make_branch_and_tree('1', format=format)
181
        tree2 = self.make_branch_and_tree('2', format=format)
182
        tree1.branch.repository.fetch(tree2.branch.repository)
6653.6.1 by Jelmer Vernooij
Rename a number of attributes from bzrdir to controldir.
183
        trans = tree1.branch.repository.controldir.get_repository_transport(None)
3582.3.1 by Martin Pool
Split pack repository tests into their own file and use scenarios
184
        self.assertEqual([],
3735.1.1 by Robert Collins
Add development2 formats using BTree indices.
185
            list(self.index_class(trans, 'pack-names', None).iter_all_entries()))
3582.3.1 by Martin Pool
Split pack repository tests into their own file and use scenarios
186
187
    def test_commit_across_pack_shape_boundary_autopacks(self):
188
        format = self.get_format()
189
        tree = self.make_branch_and_tree('.', format=format)
6653.6.1 by Jelmer Vernooij
Rename a number of attributes from bzrdir to controldir.
190
        trans = tree.branch.repository.controldir.get_repository_transport(None)
3582.3.1 by Martin Pool
Split pack repository tests into their own file and use scenarios
191
        # This test could be a little cheaper by replacing the packs
192
        # attribute on the repository to allow a different pack distribution
193
        # and max packs policy - so we are checking the policy is honoured
194
        # in the test. But for now 11 commits is not a big deal in a single
195
        # test.
196
        for x in range(9):
197
            tree.commit('commit %s' % x)
198
        # there should be 9 packs:
3735.1.1 by Robert Collins
Add development2 formats using BTree indices.
199
        index = self.index_class(trans, 'pack-names', None)
3582.3.1 by Martin Pool
Split pack repository tests into their own file and use scenarios
200
        self.assertEqual(9, len(list(index.iter_all_entries())))
201
        # insert some files in obsolete_packs which should be removed by pack.
202
        trans.put_bytes('obsolete_packs/foo', '123')
203
        trans.put_bytes('obsolete_packs/bar', '321')
204
        # committing one more should coalesce to 1 of 10.
205
        tree.commit('commit triggering pack')
3735.1.1 by Robert Collins
Add development2 formats using BTree indices.
206
        index = self.index_class(trans, 'pack-names', None)
3582.3.1 by Martin Pool
Split pack repository tests into their own file and use scenarios
207
        self.assertEqual(1, len(list(index.iter_all_entries())))
208
        # packing should not damage data
6653.6.1 by Jelmer Vernooij
Rename a number of attributes from bzrdir to controldir.
209
        tree = tree.controldir.open_workingtree()
3582.3.1 by Martin Pool
Split pack repository tests into their own file and use scenarios
210
        check_result = tree.branch.repository.check(
211
            [tree.branch.last_revision()])
4241.6.8 by Robert Collins, John Arbash Meinel, Ian Clatworthy, Vincent Ladeuil
Add --development6-rich-root, disabling the legacy and unneeded development2 format, and activating the tests for CHK features disabled pending this format. (Robert Collins, John Arbash Meinel, Ian Clatworthy, Vincent Ladeuil)
212
        nb_files = 5 # .pack, .rix, .iix, .tix, .six
213
        if tree.branch.repository._format.supports_chks:
214
            nb_files += 1 # .cix
215
        # We should have 10 x nb_files files in the obsolete_packs directory.
3582.3.1 by Martin Pool
Split pack repository tests into their own file and use scenarios
216
        obsolete_files = list(trans.list_dir('obsolete_packs'))
217
        self.assertFalse('foo' in obsolete_files)
218
        self.assertFalse('bar' in obsolete_files)
4241.6.8 by Robert Collins, John Arbash Meinel, Ian Clatworthy, Vincent Ladeuil
Add --development6-rich-root, disabling the legacy and unneeded development2 format, and activating the tests for CHK features disabled pending this format. (Robert Collins, John Arbash Meinel, Ian Clatworthy, Vincent Ladeuil)
219
        self.assertEqual(10 * nb_files, len(obsolete_files))
3582.3.1 by Martin Pool
Split pack repository tests into their own file and use scenarios
220
        # XXX: Todo check packs obsoleted correctly - old packs and indices
221
        # in the obsolete_packs directory.
222
        large_pack_name = list(index.iter_all_entries())[0][1][0]
223
        # finally, committing again should not touch the large pack.
224
        tree.commit('commit not triggering pack')
3735.1.1 by Robert Collins
Add development2 formats using BTree indices.
225
        index = self.index_class(trans, 'pack-names', None)
3582.3.1 by Martin Pool
Split pack repository tests into their own file and use scenarios
226
        self.assertEqual(2, len(list(index.iter_all_entries())))
227
        pack_names = [node[1][0] for node in index.iter_all_entries()]
228
        self.assertTrue(large_pack_name in pack_names)
229
4431.3.7 by Jonathan Lange
Cherrypick bzr.dev 4470, resolving conflicts.
230
    def test_commit_write_group_returns_new_pack_names(self):
4634.30.1 by Robert Collins
Properly pack 2a repositories during conversion operations. (Robert Collins. #423818)
231
        # This test doesn't need real disk.
5017.3.45 by Vincent Ladeuil
Move MemoryServer back into bzrlib.transport.memory as it's needed as soon as a MemoryTransport is used. Add a NEWS entry.
232
        self.vfs_transport_factory = memory.MemoryServer
4431.3.7 by Jonathan Lange
Cherrypick bzr.dev 4470, resolving conflicts.
233
        format = self.get_format()
4634.30.1 by Robert Collins
Properly pack 2a repositories during conversion operations. (Robert Collins. #423818)
234
        repo = self.make_repository('foo', format=format)
4431.3.7 by Jonathan Lange
Cherrypick bzr.dev 4470, resolving conflicts.
235
        repo.lock_write()
236
        try:
4634.30.1 by Robert Collins
Properly pack 2a repositories during conversion operations. (Robert Collins. #423818)
237
            # All current pack repository styles autopack at 10 revisions; and
238
            # autopack as well as regular commit write group needs to return
239
            # the new pack name. Looping is a little ugly, but we don't have a
240
            # clean way to test both the autopack logic and the normal code
241
            # path without doing this loop.
242
            for pos in range(10):
243
                revid = str(pos)
244
                repo.start_write_group()
245
                try:
246
                    inv = inventory.Inventory(revision_id=revid)
247
                    inv.root.revision = revid
248
                    repo.texts.add_lines((inv.root.file_id, revid), [], [])
249
                    rev = _mod_revision.Revision(timestamp=0, timezone=None,
250
                        committer="Foo Bar <foo@example.com>", message="Message",
251
                        revision_id=revid)
252
                    rev.parent_ids = ()
253
                    repo.add_revision(revid, rev, inv=inv)
254
                except:
255
                    repo.abort_write_group()
256
                    raise
257
                else:
6656.1.1 by Martin
Apply 2to3 dict fixer and clean up resulting mess using view helpers
258
                    old_names = set(repo._pack_collection._names)
4634.30.1 by Robert Collins
Properly pack 2a repositories during conversion operations. (Robert Collins. #423818)
259
                    result = repo.commit_write_group()
6656.1.1 by Martin
Apply 2to3 dict fixer and clean up resulting mess using view helpers
260
                    cur_names = set(repo._pack_collection._names)
261
                    # In this test, len(result) is always 1, so unordered is ok
262
                    new_names = list(cur_names - old_names)
4634.30.1 by Robert Collins
Properly pack 2a repositories during conversion operations. (Robert Collins. #423818)
263
                    self.assertEqual(new_names, result)
4431.3.7 by Jonathan Lange
Cherrypick bzr.dev 4470, resolving conflicts.
264
        finally:
265
            repo.unlock()
266
3582.3.1 by Martin Pool
Split pack repository tests into their own file and use scenarios
267
    def test_fail_obsolete_deletion(self):
268
        # failing to delete obsolete packs is not fatal
269
        format = self.get_format()
5017.3.44 by Vincent Ladeuil
-s bt.per_pack_repos passing
270
        server = test_server.FakeNFSServer()
4659.1.2 by Robert Collins
Refactor creation and shutdown of test servers to use a common helper,
271
        self.start_server(server)
6083.1.1 by Jelmer Vernooij
Use get_transport_from_{url,path} in more places.
272
        t = transport.get_transport_from_url(server.get_url())
5609.9.1 by Martin
Blindly change all users of get_transport to address the function via the transport module
273
        bzrdir = self.get_format().initialize_on_transport(t)
3582.3.1 by Martin Pool
Split pack repository tests into their own file and use scenarios
274
        repo = bzrdir.create_repository()
275
        repo_transport = bzrdir.get_repository_transport(None)
276
        self.assertTrue(repo_transport.has('obsolete_packs'))
277
        # these files are in use by another client and typically can't be deleted
278
        repo_transport.put_bytes('obsolete_packs/.nfsblahblah', 'contents')
279
        repo._pack_collection._clear_obsolete_packs()
280
        self.assertTrue(repo_transport.has('obsolete_packs/.nfsblahblah'))
281
5086.7.8 by Andrew Bennetts
Test that pack collection uses set_sibling_indices.
282
    def test_pack_collection_sets_sibling_indices(self):
283
        """The CombinedGraphIndex objects in the pack collection are all
284
        siblings of each other, so that search-order reorderings will be copied
285
        to each other.
286
        """
287
        repo = self.make_repository('repo')
288
        pack_coll = repo._pack_collection
6619.3.12 by Jelmer Vernooij
Use 2to3 set_literal fixer.
289
        indices = {pack_coll.revision_index, pack_coll.inventory_index,
290
                pack_coll.text_index, pack_coll.signature_index}
5086.7.8 by Andrew Bennetts
Test that pack collection uses set_sibling_indices.
291
        if pack_coll.chk_index is not None:
292
            indices.add(pack_coll.chk_index)
293
        combined_indices = set(idx.combined_index for idx in indices)
294
        for combined_index in combined_indices:
295
            self.assertEqual(
296
                combined_indices.difference([combined_index]),
297
                combined_index._sibling_indices)
298
3582.3.1 by Martin Pool
Split pack repository tests into their own file and use scenarios
299
    def test_pack_after_two_commits_packs_everything(self):
300
        format = self.get_format()
301
        tree = self.make_branch_and_tree('.', format=format)
6653.6.1 by Jelmer Vernooij
Rename a number of attributes from bzrdir to controldir.
302
        trans = tree.branch.repository.controldir.get_repository_transport(None)
3582.3.1 by Martin Pool
Split pack repository tests into their own file and use scenarios
303
        tree.commit('start')
304
        tree.commit('more work')
305
        tree.branch.repository.pack()
306
        # there should be 1 pack:
3735.1.1 by Robert Collins
Add development2 formats using BTree indices.
307
        index = self.index_class(trans, 'pack-names', None)
3582.3.1 by Martin Pool
Split pack repository tests into their own file and use scenarios
308
        self.assertEqual(1, len(list(index.iter_all_entries())))
309
        self.assertEqual(2, len(tree.branch.repository.all_revision_ids()))
310
4597.1.6 by John Arbash Meinel
Add a test that inventory texts are preserved during pack.
311
    def test_pack_preserves_all_inventories(self):
312
        # This is related to bug:
313
        #   https://bugs.launchpad.net/bzr/+bug/412198
314
        # Stacked repositories need to keep the inventory for parents, even
315
        # after a pack operation. However, it is harder to test that, then just
316
        # test that all inventory texts are preserved.
317
        format = self.get_format()
318
        builder = self.make_branch_builder('source', format=format)
319
        builder.start_series()
6816.2.1 by Jelmer Vernooij
Migrate some build_snapshot code over to having revision_id as keyword argument.
320
        builder.build_snapshot(None, [
321
            ('add', ('', 'root-id', 'directory', None))],
322
            revision_id='A-id')
323
        builder.build_snapshot(None, [
324
            ('add', ('file', 'file-id', 'file', 'B content\n'))],
325
            revision_id='B-id')
326
        builder.build_snapshot(None, [
327
            ('modify', ('file-id', 'C content\n'))],
328
            revision_id='C-id')
4597.1.6 by John Arbash Meinel
Add a test that inventory texts are preserved during pack.
329
        builder.finish_series()
330
        b = builder.get_branch()
331
        b.lock_read()
332
        self.addCleanup(b.unlock)
333
        repo = self.make_repository('repo', shared=True, format=format)
334
        repo.lock_write()
335
        self.addCleanup(repo.unlock)
336
        repo.fetch(b.repository, revision_id='B-id')
6634.2.1 by Martin
Apply 2to3 next fixer and make compatible
337
        inv = next(b.repository.iter_inventories(['C-id']))
4597.1.6 by John Arbash Meinel
Add a test that inventory texts are preserved during pack.
338
        repo.start_write_group()
339
        repo.add_inventory('C-id', inv, ['B-id'])
340
        repo.commit_write_group()
341
        self.assertEqual([('A-id',), ('B-id',), ('C-id',)],
342
                         sorted(repo.inventories.keys()))
343
        repo.pack()
344
        self.assertEqual([('A-id',), ('B-id',), ('C-id',)],
345
                         sorted(repo.inventories.keys()))
346
        # Content should be preserved as well
6634.2.1 by Martin
Apply 2to3 next fixer and make compatible
347
        self.assertEqual(inv, next(repo.iter_inventories(['C-id'])))
4597.1.6 by John Arbash Meinel
Add a test that inventory texts are preserved during pack.
348
3582.3.1 by Martin Pool
Split pack repository tests into their own file and use scenarios
349
    def test_pack_layout(self):
4241.6.8 by Robert Collins, John Arbash Meinel, Ian Clatworthy, Vincent Ladeuil
Add --development6-rich-root, disabling the legacy and unneeded development2 format, and activating the tests for CHK features disabled pending this format. (Robert Collins, John Arbash Meinel, Ian Clatworthy, Vincent Ladeuil)
350
        # Test that the ordering of revisions in pack repositories is
351
        # tip->ancestor
3582.3.1 by Martin Pool
Split pack repository tests into their own file and use scenarios
352
        format = self.get_format()
353
        tree = self.make_branch_and_tree('.', format=format)
6653.6.1 by Jelmer Vernooij
Rename a number of attributes from bzrdir to controldir.
354
        trans = tree.branch.repository.controldir.get_repository_transport(None)
3582.3.1 by Martin Pool
Split pack repository tests into their own file and use scenarios
355
        tree.commit('start', rev_id='1')
356
        tree.commit('more work', rev_id='2')
357
        tree.branch.repository.pack()
358
        tree.lock_read()
359
        self.addCleanup(tree.unlock)
360
        pack = tree.branch.repository._pack_collection.get_pack_by_name(
361
            tree.branch.repository._pack_collection.names()[0])
3943.8.1 by Marius Kruger
remove all trailing whitespace from bzr source
362
        # revision access tends to be tip->ancestor, so ordering that way on
3582.3.1 by Martin Pool
Split pack repository tests into their own file and use scenarios
363
        # disk is a good idea.
364
        for _1, key, val, refs in pack.revision_index.iter_all_entries():
6619.3.18 by Jelmer Vernooij
Run 2to3 idioms fixer.
365
            if isinstance(format.repository_format, RepositoryFormat2a):
4350.2.1 by John Arbash Meinel
Update a test to support CHK formats.
366
                # group_start, group_len, internal_start, internal_len
6631.3.1 by Martin
Run 2to3 map fixer and refactor after
367
                pos = list(map(int, val.split()))
4350.2.1 by John Arbash Meinel
Update a test to support CHK formats.
368
            else:
369
                # eol_flag, start, len
370
                pos = int(val[1:].split()[0])
3582.3.1 by Martin Pool
Split pack repository tests into their own file and use scenarios
371
            if key == ('1',):
4350.2.1 by John Arbash Meinel
Update a test to support CHK formats.
372
                pos_1 = pos
3582.3.1 by Martin Pool
Split pack repository tests into their own file and use scenarios
373
            else:
4350.2.1 by John Arbash Meinel
Update a test to support CHK formats.
374
                pos_2 = pos
375
        self.assertTrue(pos_2 < pos_1, 'rev 1 came before rev 2 %s > %s'
376
                                       % (pos_1, pos_2))
3582.3.1 by Martin Pool
Split pack repository tests into their own file and use scenarios
377
378
    def test_pack_repositories_support_multiple_write_locks(self):
379
        format = self.get_format()
380
        self.make_repository('.', shared=True, format=format)
381
        r1 = repository.Repository.open('.')
382
        r2 = repository.Repository.open('.')
383
        r1.lock_write()
384
        self.addCleanup(r1.unlock)
385
        r2.lock_write()
386
        r2.unlock()
387
388
    def _add_text(self, repo, fileid):
389
        """Add a text to the repository within a write group."""
4241.6.8 by Robert Collins, John Arbash Meinel, Ian Clatworthy, Vincent Ladeuil
Add --development6-rich-root, disabling the legacy and unneeded development2 format, and activating the tests for CHK features disabled pending this format. (Robert Collins, John Arbash Meinel, Ian Clatworthy, Vincent Ladeuil)
390
        repo.texts.add_lines((fileid, 'samplerev+'+fileid), [],
391
            ['smaplerev+'+fileid])
3582.3.1 by Martin Pool
Split pack repository tests into their own file and use scenarios
392
393
    def test_concurrent_writers_merge_new_packs(self):
394
        format = self.get_format()
395
        self.make_repository('.', shared=True, format=format)
396
        r1 = repository.Repository.open('.')
397
        r2 = repository.Repository.open('.')
398
        r1.lock_write()
399
        try:
400
            # access enough data to load the names list
401
            list(r1.all_revision_ids())
402
            r2.lock_write()
403
            try:
404
                # access enough data to load the names list
405
                list(r2.all_revision_ids())
406
                r1.start_write_group()
407
                try:
408
                    r2.start_write_group()
409
                    try:
410
                        self._add_text(r1, 'fileidr1')
411
                        self._add_text(r2, 'fileidr2')
412
                    except:
413
                        r2.abort_write_group()
414
                        raise
415
                except:
416
                    r1.abort_write_group()
417
                    raise
418
                # both r1 and r2 have open write groups with data in them
419
                # created while the other's write group was open.
420
                # Commit both which requires a merge to the pack-names.
421
                try:
422
                    r1.commit_write_group()
423
                except:
424
                    r1.abort_write_group()
425
                    r2.abort_write_group()
426
                    raise
427
                r2.commit_write_group()
428
                # tell r1 to reload from disk
429
                r1._pack_collection.reset()
430
                # Now both repositories should know about both names
431
                r1._pack_collection.ensure_loaded()
432
                r2._pack_collection.ensure_loaded()
433
                self.assertEqual(r1._pack_collection.names(), r2._pack_collection.names())
434
                self.assertEqual(2, len(r1._pack_collection.names()))
435
            finally:
436
                r2.unlock()
437
        finally:
438
            r1.unlock()
439
440
    def test_concurrent_writer_second_preserves_dropping_a_pack(self):
441
        format = self.get_format()
442
        self.make_repository('.', shared=True, format=format)
443
        r1 = repository.Repository.open('.')
444
        r2 = repository.Repository.open('.')
445
        # add a pack to drop
446
        r1.lock_write()
447
        try:
448
            r1.start_write_group()
449
            try:
450
                self._add_text(r1, 'fileidr1')
451
            except:
452
                r1.abort_write_group()
453
                raise
454
            else:
455
                r1.commit_write_group()
456
            r1._pack_collection.ensure_loaded()
457
            name_to_drop = r1._pack_collection.all_packs()[0].name
458
        finally:
459
            r1.unlock()
460
        r1.lock_write()
461
        try:
462
            # access enough data to load the names list
463
            list(r1.all_revision_ids())
464
            r2.lock_write()
465
            try:
466
                # access enough data to load the names list
467
                list(r2.all_revision_ids())
468
                r1._pack_collection.ensure_loaded()
469
                try:
470
                    r2.start_write_group()
471
                    try:
472
                        # in r1, drop the pack
473
                        r1._pack_collection._remove_pack_from_memory(
474
                            r1._pack_collection.get_pack_by_name(name_to_drop))
475
                        # in r2, add a pack
476
                        self._add_text(r2, 'fileidr2')
477
                    except:
478
                        r2.abort_write_group()
479
                        raise
480
                except:
481
                    r1._pack_collection.reset()
482
                    raise
483
                # r1 has a changed names list, and r2 an open write groups with
484
                # changes.
485
                # save r1, and then commit the r2 write group, which requires a
486
                # merge to the pack-names, which should not reinstate
487
                # name_to_drop
488
                try:
489
                    r1._pack_collection._save_pack_names()
490
                    r1._pack_collection.reset()
491
                except:
492
                    r2.abort_write_group()
493
                    raise
494
                try:
495
                    r2.commit_write_group()
496
                except:
497
                    r2.abort_write_group()
498
                    raise
499
                # Now both repositories should now about just one name.
500
                r1._pack_collection.ensure_loaded()
501
                r2._pack_collection.ensure_loaded()
502
                self.assertEqual(r1._pack_collection.names(), r2._pack_collection.names())
503
                self.assertEqual(1, len(r1._pack_collection.names()))
504
                self.assertFalse(name_to_drop in r1._pack_collection.names())
505
            finally:
506
                r2.unlock()
507
        finally:
508
            r1.unlock()
509
3789.1.1 by John Arbash Meinel
add the failing acceptance test for the first portion.
510
    def test_concurrent_pack_triggers_reload(self):
511
        # create 2 packs, which we will then collapse
512
        tree = self.make_branch_and_tree('tree')
3789.1.2 by John Arbash Meinel
Add RepositoryPackCollection.reload_pack_names()
513
        tree.lock_write()
3789.1.1 by John Arbash Meinel
add the failing acceptance test for the first portion.
514
        try:
3789.1.2 by John Arbash Meinel
Add RepositoryPackCollection.reload_pack_names()
515
            rev1 = tree.commit('one')
516
            rev2 = tree.commit('two')
517
            r2 = repository.Repository.open('tree')
3789.1.1 by John Arbash Meinel
add the failing acceptance test for the first portion.
518
            r2.lock_read()
519
            try:
520
                # Now r2 has read the pack-names file, but will need to reload
521
                # it after r1 has repacked
3789.1.2 by John Arbash Meinel
Add RepositoryPackCollection.reload_pack_names()
522
                tree.branch.repository.pack()
523
                self.assertEqual({rev2:(rev1,)}, r2.get_parent_map([rev2]))
3789.1.1 by John Arbash Meinel
add the failing acceptance test for the first portion.
524
            finally:
525
                r2.unlock()
526
        finally:
3789.1.2 by John Arbash Meinel
Add RepositoryPackCollection.reload_pack_names()
527
            tree.unlock()
3789.1.1 by John Arbash Meinel
add the failing acceptance test for the first portion.
528
3789.2.8 by John Arbash Meinel
Add a test that KnitPackRepository.get_record_stream retries when appropriate.
529
    def test_concurrent_pack_during_get_record_reloads(self):
530
        tree = self.make_branch_and_tree('tree')
531
        tree.lock_write()
532
        try:
533
            rev1 = tree.commit('one')
534
            rev2 = tree.commit('two')
3789.2.14 by John Arbash Meinel
Update AggregateIndex to pass the reload_func into _DirectPackAccess
535
            keys = [(rev1,), (rev2,)]
3789.2.8 by John Arbash Meinel
Add a test that KnitPackRepository.get_record_stream retries when appropriate.
536
            r2 = repository.Repository.open('tree')
537
            r2.lock_read()
538
            try:
539
                # At this point, we will start grabbing a record stream, and
540
                # trigger a repack mid-way
541
                packed = False
542
                result = {}
543
                record_stream = r2.revisions.get_record_stream(keys,
544
                                    'unordered', False)
545
                for record in record_stream:
546
                    result[record.key] = record
547
                    if not packed:
548
                        tree.branch.repository.pack()
549
                        packed = True
550
                # The first record will be found in the original location, but
551
                # after the pack, we have to reload to find the next record
3789.2.14 by John Arbash Meinel
Update AggregateIndex to pass the reload_func into _DirectPackAccess
552
                self.assertEqual(sorted(keys), sorted(result.keys()))
3789.2.8 by John Arbash Meinel
Add a test that KnitPackRepository.get_record_stream retries when appropriate.
553
            finally:
554
                r2.unlock()
555
        finally:
556
            tree.unlock()
557
4634.113.2 by John Arbash Meinel
Add a test which triggers the behavior.
558
    def test_concurrent_pack_during_autopack(self):
559
        tree = self.make_branch_and_tree('tree')
560
        tree.lock_write()
561
        try:
6651.2.2 by Martin
Apply 2to3 xrange fix and fix up with sixish range
562
            for i in range(9):
4634.113.2 by John Arbash Meinel
Add a test which triggers the behavior.
563
                tree.commit('rev %d' % (i,))
564
            r2 = repository.Repository.open('tree')
565
            r2.lock_write()
566
            try:
567
                # Monkey patch so that pack occurs while the other repo is
568
                # autopacking. This is slightly bad, but all current pack
569
                # repository implementations have a _pack_collection, and we
570
                # test that it gets triggered. So if a future format changes
571
                # things, the test will fail rather than succeed accidentally.
572
                autopack_count = [0]
573
                r1 = tree.branch.repository
574
                orig = r1._pack_collection.pack_distribution
575
                def trigger_during_auto(*args, **kwargs):
576
                    ret = orig(*args, **kwargs)
577
                    if not autopack_count[0]:
578
                        r2.pack()
579
                    autopack_count[0] += 1
580
                    return ret
581
                r1._pack_collection.pack_distribution = trigger_during_auto
582
                tree.commit('autopack-rev')
583
                # This triggers 2 autopacks. The first one causes r2.pack() to
584
                # fire, but r2 doesn't see the new pack file yet. The
585
                # autopack restarts and sees there are 2 files and there
586
                # should be only 1 for 10 commits. So it goes ahead and
587
                # finishes autopacking.
588
                self.assertEqual([2], autopack_count)
589
            finally:
590
                r2.unlock()
591
        finally:
592
            tree.unlock()
593
3582.3.1 by Martin Pool
Split pack repository tests into their own file and use scenarios
594
    def test_lock_write_does_not_physically_lock(self):
595
        repo = self.make_repository('.', format=self.get_format())
596
        repo.lock_write()
597
        self.addCleanup(repo.unlock)
598
        self.assertFalse(repo.get_physical_lock_status())
599
600
    def prepare_for_break_lock(self):
601
        # Setup the global ui factory state so that a break-lock method call
602
        # will find usable input in the input stream.
4449.3.27 by Martin Pool
More test updates to use CannedInputUIFactory
603
        ui.ui_factory = ui.CannedInputUIFactory([True])
3582.3.1 by Martin Pool
Split pack repository tests into their own file and use scenarios
604
605
    def test_break_lock_breaks_physical_lock(self):
606
        repo = self.make_repository('.', format=self.get_format())
607
        repo._pack_collection.lock_names()
3650.4.1 by Aaron Bentley
Fix test kipple in test_break_lock_breaks_physical_lock
608
        repo.control_files.leave_in_place()
609
        repo.unlock()
3582.3.1 by Martin Pool
Split pack repository tests into their own file and use scenarios
610
        repo2 = repository.Repository.open('.')
611
        self.assertTrue(repo.get_physical_lock_status())
612
        self.prepare_for_break_lock()
613
        repo2.break_lock()
614
        self.assertFalse(repo.get_physical_lock_status())
615
616
    def test_broken_physical_locks_error_on__unlock_names_lock(self):
617
        repo = self.make_repository('.', format=self.get_format())
618
        repo._pack_collection.lock_names()
619
        self.assertTrue(repo.get_physical_lock_status())
620
        repo2 = repository.Repository.open('.')
621
        self.prepare_for_break_lock()
622
        repo2.break_lock()
623
        self.assertRaises(errors.LockBroken, repo._pack_collection._unlock_names)
624
625
    def test_fetch_without_find_ghosts_ignores_ghosts(self):
626
        # we want two repositories at this point:
627
        # one with a revision that is a ghost in the other
628
        # repository.
629
        # 'ghost' is present in has_ghost, 'ghost' is absent in 'missing_ghost'.
630
        # 'references' is present in both repositories, and 'tip' is present
631
        # just in has_ghost.
632
        # has_ghost       missing_ghost
633
        #------------------------------
634
        # 'ghost'             -
635
        # 'references'    'references'
636
        # 'tip'               -
637
        # In this test we fetch 'tip' which should not fetch 'ghost'
638
        has_ghost = self.make_repository('has_ghost', format=self.get_format())
639
        missing_ghost = self.make_repository('missing_ghost',
640
            format=self.get_format())
641
642
        def add_commit(repo, revision_id, parent_ids):
643
            repo.lock_write()
644
            repo.start_write_group()
645
            inv = inventory.Inventory(revision_id=revision_id)
646
            inv.root.revision = revision_id
647
            root_id = inv.root.file_id
648
            sha1 = repo.add_inventory(revision_id, inv, [])
649
            repo.texts.add_lines((root_id, revision_id), [], [])
650
            rev = _mod_revision.Revision(timestamp=0,
651
                                         timezone=None,
652
                                         committer="Foo Bar <foo@example.com>",
653
                                         message="Message",
654
                                         inventory_sha1=sha1,
655
                                         revision_id=revision_id)
656
            rev.parent_ids = parent_ids
657
            repo.add_revision(revision_id, rev)
658
            repo.commit_write_group()
659
            repo.unlock()
660
        add_commit(has_ghost, 'ghost', [])
661
        add_commit(has_ghost, 'references', ['ghost'])
662
        add_commit(missing_ghost, 'references', ['ghost'])
663
        add_commit(has_ghost, 'tip', ['references'])
664
        missing_ghost.fetch(has_ghost, 'tip')
665
        # missing ghost now has tip and not ghost.
666
        rev = missing_ghost.get_revision('tip')
667
        inv = missing_ghost.get_inventory('tip')
668
        self.assertRaises(errors.NoSuchRevision,
669
            missing_ghost.get_revision, 'ghost')
670
        self.assertRaises(errors.NoSuchRevision,
671
            missing_ghost.get_inventory, 'ghost')
672
4011.5.6 by Andrew Bennetts
Make sure it's not possible to commit a pack write group when any versioned file has missing compression parents.
673
    def make_write_ready_repo(self):
4360.4.6 by John Arbash Meinel
Change how 'missing.*parent_prevents_commit' determines what to skip.
674
        format = self.get_format()
4597.1.10 by John Arbash Meinel
Fix some tests that were failing because we checked against RepositoryFormatCHK1
675
        if isinstance(format.repository_format, RepositoryFormat2a):
4360.4.6 by John Arbash Meinel
Change how 'missing.*parent_prevents_commit' determines what to skip.
676
            raise TestNotApplicable("No missing compression parents")
677
        repo = self.make_repository('.', format=format)
4011.5.6 by Andrew Bennetts
Make sure it's not possible to commit a pack write group when any versioned file has missing compression parents.
678
        repo.lock_write()
4360.4.6 by John Arbash Meinel
Change how 'missing.*parent_prevents_commit' determines what to skip.
679
        self.addCleanup(repo.unlock)
4011.5.6 by Andrew Bennetts
Make sure it's not possible to commit a pack write group when any versioned file has missing compression parents.
680
        repo.start_write_group()
4360.4.6 by John Arbash Meinel
Change how 'missing.*parent_prevents_commit' determines what to skip.
681
        self.addCleanup(repo.abort_write_group)
4011.5.6 by Andrew Bennetts
Make sure it's not possible to commit a pack write group when any versioned file has missing compression parents.
682
        return repo
683
684
    def test_missing_inventories_compression_parent_prevents_commit(self):
685
        repo = self.make_write_ready_repo()
686
        key = ('junk',)
687
        repo.inventories._index._missing_compression_parents.add(key)
688
        self.assertRaises(errors.BzrCheckError, repo.commit_write_group)
689
        self.assertRaises(errors.BzrCheckError, repo.commit_write_group)
690
691
    def test_missing_revisions_compression_parent_prevents_commit(self):
692
        repo = self.make_write_ready_repo()
693
        key = ('junk',)
694
        repo.revisions._index._missing_compression_parents.add(key)
695
        self.assertRaises(errors.BzrCheckError, repo.commit_write_group)
696
        self.assertRaises(errors.BzrCheckError, repo.commit_write_group)
697
698
    def test_missing_signatures_compression_parent_prevents_commit(self):
699
        repo = self.make_write_ready_repo()
700
        key = ('junk',)
701
        repo.signatures._index._missing_compression_parents.add(key)
702
        self.assertRaises(errors.BzrCheckError, repo.commit_write_group)
703
        self.assertRaises(errors.BzrCheckError, repo.commit_write_group)
704
705
    def test_missing_text_compression_parent_prevents_commit(self):
706
        repo = self.make_write_ready_repo()
707
        key = ('some', 'junk')
708
        repo.texts._index._missing_compression_parents.add(key)
709
        self.assertRaises(errors.BzrCheckError, repo.commit_write_group)
710
        e = self.assertRaises(errors.BzrCheckError, repo.commit_write_group)
711
3582.3.1 by Martin Pool
Split pack repository tests into their own file and use scenarios
712
    def test_supports_external_lookups(self):
713
        repo = self.make_repository('.', format=self.get_format())
714
        self.assertEqual(self.format_supports_external_lookups,
715
            repo._format.supports_external_lookups)
716
5200.3.3 by Robert Collins
Lock methods on ``Tree``, ``Branch`` and ``Repository`` are now
717
    def _lock_write(self, write_lockable):
718
        """Lock write_lockable, add a cleanup and return the result.
719
        
720
        :param write_lockable: An object with a lock_write method.
721
        :return: The result of write_lockable.lock_write().
722
        """
723
        result = write_lockable.lock_write()
724
        self.addCleanup(result.unlock)
725
        return result
726
3825.4.1 by Andrew Bennetts
Add suppress_errors to abort_write_group.
727
    def test_abort_write_group_does_not_raise_when_suppressed(self):
728
        """Similar to per_repository.test_write_group's test of the same name.
729
730
        Also requires that the exception is logged.
731
        """
5017.3.45 by Vincent Ladeuil
Move MemoryServer back into bzrlib.transport.memory as it's needed as soon as a MemoryTransport is used. Add a NEWS entry.
732
        self.vfs_transport_factory = memory.MemoryServer
4343.3.7 by John Arbash Meinel
Update the suspend/resume/commit/abort_write_group tests for CHK1.
733
        repo = self.make_repository('repo', format=self.get_format())
5200.3.3 by Robert Collins
Lock methods on ``Tree``, ``Branch`` and ``Repository`` are now
734
        token = self._lock_write(repo).repository_token
3825.4.1 by Andrew Bennetts
Add suppress_errors to abort_write_group.
735
        repo.start_write_group()
736
        # Damage the repository on the filesystem
737
        self.get_transport('').rename('repo', 'foo')
738
        # abort_write_group will not raise an error
739
        self.assertEqual(None, repo.abort_write_group(suppress_errors=True))
740
        # But it does log an error
4794.1.15 by Robert Collins
Review feedback.
741
        log = self.get_log()
4794.1.8 by Robert Collins
Move the passing of test logs to the result to be via the getDetails API and remove all public use of TestCase._get_log.
742
        self.assertContainsRe(log, 'abort_write_group failed')
6681.2.10 by Jelmer Vernooij
Fix failures.
743
        self.assertContainsRe(log, r'INFO  brz: ERROR \(ignored\):')
3825.4.1 by Andrew Bennetts
Add suppress_errors to abort_write_group.
744
        if token is not None:
745
            repo.leave_lock_in_place()
3943.8.1 by Marius Kruger
remove all trailing whitespace from bzr source
746
3825.4.1 by Andrew Bennetts
Add suppress_errors to abort_write_group.
747
    def test_abort_write_group_does_raise_when_not_suppressed(self):
5017.3.45 by Vincent Ladeuil
Move MemoryServer back into bzrlib.transport.memory as it's needed as soon as a MemoryTransport is used. Add a NEWS entry.
748
        self.vfs_transport_factory = memory.MemoryServer
4343.3.7 by John Arbash Meinel
Update the suspend/resume/commit/abort_write_group tests for CHK1.
749
        repo = self.make_repository('repo', format=self.get_format())
5200.3.3 by Robert Collins
Lock methods on ``Tree``, ``Branch`` and ``Repository`` are now
750
        token = self._lock_write(repo).repository_token
3825.4.1 by Andrew Bennetts
Add suppress_errors to abort_write_group.
751
        repo.start_write_group()
752
        # Damage the repository on the filesystem
753
        self.get_transport('').rename('repo', 'foo')
754
        # abort_write_group will not raise an error
755
        self.assertRaises(Exception, repo.abort_write_group)
756
        if token is not None:
757
            repo.leave_lock_in_place()
3943.8.1 by Marius Kruger
remove all trailing whitespace from bzr source
758
4002.1.1 by Andrew Bennetts
Implement suspend_write_group/resume_write_group.
759
    def test_suspend_write_group(self):
5017.3.45 by Vincent Ladeuil
Move MemoryServer back into bzrlib.transport.memory as it's needed as soon as a MemoryTransport is used. Add a NEWS entry.
760
        self.vfs_transport_factory = memory.MemoryServer
4343.3.7 by John Arbash Meinel
Update the suspend/resume/commit/abort_write_group tests for CHK1.
761
        repo = self.make_repository('repo', format=self.get_format())
5200.3.3 by Robert Collins
Lock methods on ``Tree``, ``Branch`` and ``Repository`` are now
762
        token = self._lock_write(repo).repository_token
4002.1.1 by Andrew Bennetts
Implement suspend_write_group/resume_write_group.
763
        repo.start_write_group()
764
        repo.texts.add_lines(('file-id', 'revid'), (), ['lines'])
765
        wg_tokens = repo.suspend_write_group()
766
        expected_pack_name = wg_tokens[0] + '.pack'
4343.3.7 by John Arbash Meinel
Update the suspend/resume/commit/abort_write_group tests for CHK1.
767
        expected_names = [wg_tokens[0] + ext for ext in
768
                            ('.rix', '.iix', '.tix', '.six')]
769
        if repo.chk_bytes is not None:
770
            expected_names.append(wg_tokens[0] + '.cix')
771
        expected_names.append(expected_pack_name)
4002.1.1 by Andrew Bennetts
Implement suspend_write_group/resume_write_group.
772
        upload_transport = repo._pack_collection._upload_transport
773
        limbo_files = upload_transport.list_dir('')
4343.3.7 by John Arbash Meinel
Update the suspend/resume/commit/abort_write_group tests for CHK1.
774
        self.assertEqual(sorted(expected_names), sorted(limbo_files))
4002.1.1 by Andrew Bennetts
Implement suspend_write_group/resume_write_group.
775
        md5 = osutils.md5(upload_transport.get_bytes(expected_pack_name))
776
        self.assertEqual(wg_tokens[0], md5.hexdigest())
777
4343.3.8 by John Arbash Meinel
Some cleanup passes.
778
    def test_resume_chk_bytes(self):
5017.3.45 by Vincent Ladeuil
Move MemoryServer back into bzrlib.transport.memory as it's needed as soon as a MemoryTransport is used. Add a NEWS entry.
779
        self.vfs_transport_factory = memory.MemoryServer
4343.3.8 by John Arbash Meinel
Some cleanup passes.
780
        repo = self.make_repository('repo', format=self.get_format())
781
        if repo.chk_bytes is None:
782
            raise TestNotApplicable('no chk_bytes for this repository')
5200.3.3 by Robert Collins
Lock methods on ``Tree``, ``Branch`` and ``Repository`` are now
783
        token = self._lock_write(repo).repository_token
4343.3.8 by John Arbash Meinel
Some cleanup passes.
784
        repo.start_write_group()
785
        text = 'a bit of text\n'
786
        key = ('sha1:' + osutils.sha_string(text),)
787
        repo.chk_bytes.add_lines(key, (), [text])
788
        wg_tokens = repo.suspend_write_group()
6653.6.1 by Jelmer Vernooij
Rename a number of attributes from bzrdir to controldir.
789
        same_repo = repo.controldir.open_repository()
4343.3.8 by John Arbash Meinel
Some cleanup passes.
790
        same_repo.lock_write()
791
        self.addCleanup(same_repo.unlock)
792
        same_repo.resume_write_group(wg_tokens)
793
        self.assertEqual([key], list(same_repo.chk_bytes.keys()))
794
        self.assertEqual(
795
            text, same_repo.chk_bytes.get_record_stream([key],
796
                'unordered', True).next().get_bytes_as('fulltext'))
797
        same_repo.abort_write_group()
798
        self.assertEqual([], list(same_repo.chk_bytes.keys()))
799
4002.1.1 by Andrew Bennetts
Implement suspend_write_group/resume_write_group.
800
    def test_resume_write_group_then_abort(self):
801
        # Create a repo, start a write group, insert some data, suspend.
5017.3.45 by Vincent Ladeuil
Move MemoryServer back into bzrlib.transport.memory as it's needed as soon as a MemoryTransport is used. Add a NEWS entry.
802
        self.vfs_transport_factory = memory.MemoryServer
4343.3.7 by John Arbash Meinel
Update the suspend/resume/commit/abort_write_group tests for CHK1.
803
        repo = self.make_repository('repo', format=self.get_format())
5200.3.3 by Robert Collins
Lock methods on ``Tree``, ``Branch`` and ``Repository`` are now
804
        token = self._lock_write(repo).repository_token
4002.1.1 by Andrew Bennetts
Implement suspend_write_group/resume_write_group.
805
        repo.start_write_group()
806
        text_key = ('file-id', 'revid')
807
        repo.texts.add_lines(text_key, (), ['lines'])
808
        wg_tokens = repo.suspend_write_group()
809
        # Get a fresh repository object for the repo on the filesystem.
6653.6.1 by Jelmer Vernooij
Rename a number of attributes from bzrdir to controldir.
810
        same_repo = repo.controldir.open_repository()
4002.1.1 by Andrew Bennetts
Implement suspend_write_group/resume_write_group.
811
        # Resume
812
        same_repo.lock_write()
813
        self.addCleanup(same_repo.unlock)
814
        same_repo.resume_write_group(wg_tokens)
815
        same_repo.abort_write_group()
816
        self.assertEqual(
817
            [], same_repo._pack_collection._upload_transport.list_dir(''))
818
        self.assertEqual(
819
            [], same_repo._pack_collection._pack_transport.list_dir(''))
820
4343.3.7 by John Arbash Meinel
Update the suspend/resume/commit/abort_write_group tests for CHK1.
821
    def test_commit_resumed_write_group(self):
5017.3.45 by Vincent Ladeuil
Move MemoryServer back into bzrlib.transport.memory as it's needed as soon as a MemoryTransport is used. Add a NEWS entry.
822
        self.vfs_transport_factory = memory.MemoryServer
4343.3.7 by John Arbash Meinel
Update the suspend/resume/commit/abort_write_group tests for CHK1.
823
        repo = self.make_repository('repo', format=self.get_format())
5200.3.3 by Robert Collins
Lock methods on ``Tree``, ``Branch`` and ``Repository`` are now
824
        token = self._lock_write(repo).repository_token
4343.3.7 by John Arbash Meinel
Update the suspend/resume/commit/abort_write_group tests for CHK1.
825
        repo.start_write_group()
826
        text_key = ('file-id', 'revid')
827
        repo.texts.add_lines(text_key, (), ['lines'])
828
        wg_tokens = repo.suspend_write_group()
829
        # Get a fresh repository object for the repo on the filesystem.
6653.6.1 by Jelmer Vernooij
Rename a number of attributes from bzrdir to controldir.
830
        same_repo = repo.controldir.open_repository()
4343.3.7 by John Arbash Meinel
Update the suspend/resume/commit/abort_write_group tests for CHK1.
831
        # Resume
832
        same_repo.lock_write()
833
        self.addCleanup(same_repo.unlock)
834
        same_repo.resume_write_group(wg_tokens)
835
        same_repo.commit_write_group()
836
        expected_pack_name = wg_tokens[0] + '.pack'
837
        expected_names = [wg_tokens[0] + ext for ext in
838
                            ('.rix', '.iix', '.tix', '.six')]
839
        if repo.chk_bytes is not None:
840
            expected_names.append(wg_tokens[0] + '.cix')
841
        self.assertEqual(
842
            [], same_repo._pack_collection._upload_transport.list_dir(''))
843
        index_names = repo._pack_collection._index_transport.list_dir('')
844
        self.assertEqual(sorted(expected_names), sorted(index_names))
845
        pack_names = repo._pack_collection._pack_transport.list_dir('')
846
        self.assertEqual([expected_pack_name], pack_names)
847
4002.1.5 by Andrew Bennetts
Fix possible security issue with resuming write groups: make sure the token is well-formed so that it's not possible to steal a write group from another repo.
848
    def test_resume_malformed_token(self):
5017.3.45 by Vincent Ladeuil
Move MemoryServer back into bzrlib.transport.memory as it's needed as soon as a MemoryTransport is used. Add a NEWS entry.
849
        self.vfs_transport_factory = memory.MemoryServer
4002.1.5 by Andrew Bennetts
Fix possible security issue with resuming write groups: make sure the token is well-formed so that it's not possible to steal a write group from another repo.
850
        # Make a repository with a suspended write group
4343.3.7 by John Arbash Meinel
Update the suspend/resume/commit/abort_write_group tests for CHK1.
851
        repo = self.make_repository('repo', format=self.get_format())
5200.3.3 by Robert Collins
Lock methods on ``Tree``, ``Branch`` and ``Repository`` are now
852
        token = self._lock_write(repo).repository_token
4002.1.5 by Andrew Bennetts
Fix possible security issue with resuming write groups: make sure the token is well-formed so that it's not possible to steal a write group from another repo.
853
        repo.start_write_group()
854
        text_key = ('file-id', 'revid')
855
        repo.texts.add_lines(text_key, (), ['lines'])
856
        wg_tokens = repo.suspend_write_group()
857
        # Make a new repository
4343.3.7 by John Arbash Meinel
Update the suspend/resume/commit/abort_write_group tests for CHK1.
858
        new_repo = self.make_repository('new_repo', format=self.get_format())
5200.3.3 by Robert Collins
Lock methods on ``Tree``, ``Branch`` and ``Repository`` are now
859
        token = self._lock_write(new_repo).repository_token
4002.1.5 by Andrew Bennetts
Fix possible security issue with resuming write groups: make sure the token is well-formed so that it's not possible to steal a write group from another repo.
860
        hacked_wg_token = (
861
            '../../../../repo/.bzr/repository/upload/' + wg_tokens[0])
862
        self.assertRaises(
4002.1.7 by Andrew Bennetts
Rename UnresumableWriteGroups to UnresumableWriteGroup.
863
            errors.UnresumableWriteGroup,
4002.1.5 by Andrew Bennetts
Fix possible security issue with resuming write groups: make sure the token is well-formed so that it's not possible to steal a write group from another repo.
864
            new_repo.resume_write_group, [hacked_wg_token])
865
3582.3.1 by Martin Pool
Split pack repository tests into their own file and use scenarios
866
3582.3.3 by Martin Pool
Reenable tests for stacking pack repositories
867
class TestPackRepositoryStacking(TestCaseWithTransport):
868
869
    """Tests for stacking pack repositories"""
870
871
    def setUp(self):
872
        if not self.format_supports_external_lookups:
3943.8.1 by Marius Kruger
remove all trailing whitespace from bzr source
873
            raise TestNotApplicable("%r doesn't support stacking"
3582.3.3 by Martin Pool
Reenable tests for stacking pack repositories
874
                % (self.format_name,))
875
        super(TestPackRepositoryStacking, self).setUp()
876
877
    def get_format(self):
6653.6.5 by Jelmer Vernooij
Rename make_bzrdir to make_controldir.
878
        return controldir.format_registry.make_controldir(self.format_name)
3582.3.3 by Martin Pool
Reenable tests for stacking pack repositories
879
3606.10.5 by John Arbash Meinel
Switch out --1.6-rich-root for --1.6.1-rich-root.
880
    def test_stack_checks_rich_root_compatibility(self):
3582.3.3 by Martin Pool
Reenable tests for stacking pack repositories
881
        # early versions of the packing code relied on pack internals to
882
        # stack, but the current version should be able to stack on any
883
        # format.
884
        #
885
        # TODO: Possibly this should be run per-repository-format and raise
886
        # TestNotApplicable on formats that don't support stacking. -- mbp
887
        # 20080729
888
        repo = self.make_repository('repo', format=self.get_format())
889
        if repo.supports_rich_root():
890
            # can only stack on repositories that have compatible internal
891
            # metadata
3606.10.5 by John Arbash Meinel
Switch out --1.6-rich-root for --1.6.1-rich-root.
892
            if getattr(repo._format, 'supports_tree_reference', False):
4343.3.27 by John Arbash Meinel
Now that dev6 supports external references, the tests for
893
                matching_format_name = 'pack-0.92-subtree'
894
            else:
3735.2.9 by Robert Collins
Get a working chk_map using inventory implementation bootstrapped.
895
                if repo._format.supports_chks:
4597.1.6 by John Arbash Meinel
Add a test that inventory texts are preserved during pack.
896
                    matching_format_name = '2a'
3735.2.9 by Robert Collins
Get a working chk_map using inventory implementation bootstrapped.
897
                else:
4343.3.27 by John Arbash Meinel
Now that dev6 supports external references, the tests for
898
                    matching_format_name = 'rich-root-pack'
3582.3.3 by Martin Pool
Reenable tests for stacking pack repositories
899
            mismatching_format_name = 'pack-0.92'
900
        else:
4241.6.8 by Robert Collins, John Arbash Meinel, Ian Clatworthy, Vincent Ladeuil
Add --development6-rich-root, disabling the legacy and unneeded development2 format, and activating the tests for CHK features disabled pending this format. (Robert Collins, John Arbash Meinel, Ian Clatworthy, Vincent Ladeuil)
901
            # We don't have a non-rich-root CHK format.
3735.2.9 by Robert Collins
Get a working chk_map using inventory implementation bootstrapped.
902
            if repo._format.supports_chks:
4241.6.8 by Robert Collins, John Arbash Meinel, Ian Clatworthy, Vincent Ladeuil
Add --development6-rich-root, disabling the legacy and unneeded development2 format, and activating the tests for CHK features disabled pending this format. (Robert Collins, John Arbash Meinel, Ian Clatworthy, Vincent Ladeuil)
903
                raise AssertionError("no non-rich-root CHK formats known")
3735.2.9 by Robert Collins
Get a working chk_map using inventory implementation bootstrapped.
904
            else:
905
                matching_format_name = 'pack-0.92'
3582.3.3 by Martin Pool
Reenable tests for stacking pack repositories
906
            mismatching_format_name = 'pack-0.92-subtree'
907
        base = self.make_repository('base', format=matching_format_name)
908
        repo.add_fallback_repository(base)
909
        # you can't stack on something with incompatible data
910
        bad_repo = self.make_repository('mismatch',
911
            format=mismatching_format_name)
912
        e = self.assertRaises(errors.IncompatibleRepositories,
913
            repo.add_fallback_repository, bad_repo)
914
        self.assertContainsRe(str(e),
915
            r'(?m)KnitPackRepository.*/mismatch/.*\nis not compatible with\n'
3735.2.9 by Robert Collins
Get a working chk_map using inventory implementation bootstrapped.
916
            r'.*Repository.*/repo/.*\n'
3582.3.3 by Martin Pool
Reenable tests for stacking pack repositories
917
            r'different rich-root support')
918
3606.10.5 by John Arbash Meinel
Switch out --1.6-rich-root for --1.6.1-rich-root.
919
    def test_stack_checks_serializers_compatibility(self):
920
        repo = self.make_repository('repo', format=self.get_format())
921
        if getattr(repo._format, 'supports_tree_reference', False):
922
            # can only stack on repositories that have compatible internal
923
            # metadata
4343.3.27 by John Arbash Meinel
Now that dev6 supports external references, the tests for
924
            matching_format_name = 'pack-0.92-subtree'
3606.10.5 by John Arbash Meinel
Switch out --1.6-rich-root for --1.6.1-rich-root.
925
            mismatching_format_name = 'rich-root-pack'
926
        else:
927
            if repo.supports_rich_root():
4343.3.27 by John Arbash Meinel
Now that dev6 supports external references, the tests for
928
                if repo._format.supports_chks:
4597.1.6 by John Arbash Meinel
Add a test that inventory texts are preserved during pack.
929
                    matching_format_name = '2a'
4343.3.27 by John Arbash Meinel
Now that dev6 supports external references, the tests for
930
                else:
931
                    matching_format_name = 'rich-root-pack'
3606.10.5 by John Arbash Meinel
Switch out --1.6-rich-root for --1.6.1-rich-root.
932
                mismatching_format_name = 'pack-0.92-subtree'
933
            else:
934
                raise TestNotApplicable('No formats use non-v5 serializer'
935
                    ' without having rich-root also set')
936
        base = self.make_repository('base', format=matching_format_name)
937
        repo.add_fallback_repository(base)
938
        # you can't stack on something with incompatible data
939
        bad_repo = self.make_repository('mismatch',
940
            format=mismatching_format_name)
941
        e = self.assertRaises(errors.IncompatibleRepositories,
942
            repo.add_fallback_repository, bad_repo)
943
        self.assertContainsRe(str(e),
944
            r'(?m)KnitPackRepository.*/mismatch/.*\nis not compatible with\n'
3735.2.9 by Robert Collins
Get a working chk_map using inventory implementation bootstrapped.
945
            r'.*Repository.*/repo/.*\n'
3606.10.5 by John Arbash Meinel
Switch out --1.6-rich-root for --1.6.1-rich-root.
946
            r'different serializers')
947
3582.3.3 by Martin Pool
Reenable tests for stacking pack repositories
948
    def test_adding_pack_does_not_record_pack_names_from_other_repositories(self):
949
        base = self.make_branch_and_tree('base', format=self.get_format())
950
        base.commit('foo')
951
        referencing = self.make_branch_and_tree('repo', format=self.get_format())
952
        referencing.branch.repository.add_fallback_repository(base.branch.repository)
4595.4.4 by Robert Collins
Disable committing directly to stacked branches from lightweight checkouts.
953
        local_tree = referencing.branch.create_checkout('local')
954
        local_tree.commit('bar')
6653.6.1 by Jelmer Vernooij
Rename a number of attributes from bzrdir to controldir.
955
        new_instance = referencing.controldir.open_repository()
3582.3.3 by Martin Pool
Reenable tests for stacking pack repositories
956
        new_instance.lock_read()
957
        self.addCleanup(new_instance.unlock)
958
        new_instance._pack_collection.ensure_loaded()
959
        self.assertEqual(1, len(new_instance._pack_collection.all_packs()))
960
961
    def test_autopack_only_considers_main_repo_packs(self):
4241.6.8 by Robert Collins, John Arbash Meinel, Ian Clatworthy, Vincent Ladeuil
Add --development6-rich-root, disabling the legacy and unneeded development2 format, and activating the tests for CHK features disabled pending this format. (Robert Collins, John Arbash Meinel, Ian Clatworthy, Vincent Ladeuil)
962
        format = self.get_format()
963
        base = self.make_branch_and_tree('base', format=format)
3582.3.3 by Martin Pool
Reenable tests for stacking pack repositories
964
        base.commit('foo')
4241.6.8 by Robert Collins, John Arbash Meinel, Ian Clatworthy, Vincent Ladeuil
Add --development6-rich-root, disabling the legacy and unneeded development2 format, and activating the tests for CHK features disabled pending this format. (Robert Collins, John Arbash Meinel, Ian Clatworthy, Vincent Ladeuil)
965
        tree = self.make_branch_and_tree('repo', format=format)
3582.3.3 by Martin Pool
Reenable tests for stacking pack repositories
966
        tree.branch.repository.add_fallback_repository(base.branch.repository)
6653.6.1 by Jelmer Vernooij
Rename a number of attributes from bzrdir to controldir.
967
        trans = tree.branch.repository.controldir.get_repository_transport(None)
3582.3.3 by Martin Pool
Reenable tests for stacking pack repositories
968
        # This test could be a little cheaper by replacing the packs
969
        # attribute on the repository to allow a different pack distribution
970
        # and max packs policy - so we are checking the policy is honoured
971
        # in the test. But for now 11 commits is not a big deal in a single
972
        # test.
4595.4.4 by Robert Collins
Disable committing directly to stacked branches from lightweight checkouts.
973
        local_tree = tree.branch.create_checkout('local')
3582.3.3 by Martin Pool
Reenable tests for stacking pack repositories
974
        for x in range(9):
4595.4.4 by Robert Collins
Disable committing directly to stacked branches from lightweight checkouts.
975
            local_tree.commit('commit %s' % x)
3582.3.3 by Martin Pool
Reenable tests for stacking pack repositories
976
        # there should be 9 packs:
3735.1.1 by Robert Collins
Add development2 formats using BTree indices.
977
        index = self.index_class(trans, 'pack-names', None)
3582.3.3 by Martin Pool
Reenable tests for stacking pack repositories
978
        self.assertEqual(9, len(list(index.iter_all_entries())))
979
        # committing one more should coalesce to 1 of 10.
4595.4.4 by Robert Collins
Disable committing directly to stacked branches from lightweight checkouts.
980
        local_tree.commit('commit triggering pack')
3735.1.1 by Robert Collins
Add development2 formats using BTree indices.
981
        index = self.index_class(trans, 'pack-names', None)
3582.3.3 by Martin Pool
Reenable tests for stacking pack repositories
982
        self.assertEqual(1, len(list(index.iter_all_entries())))
983
        # packing should not damage data
6653.6.1 by Jelmer Vernooij
Rename a number of attributes from bzrdir to controldir.
984
        tree = tree.controldir.open_workingtree()
3582.3.3 by Martin Pool
Reenable tests for stacking pack repositories
985
        check_result = tree.branch.repository.check(
986
            [tree.branch.last_revision()])
4241.6.8 by Robert Collins, John Arbash Meinel, Ian Clatworthy, Vincent Ladeuil
Add --development6-rich-root, disabling the legacy and unneeded development2 format, and activating the tests for CHK features disabled pending this format. (Robert Collins, John Arbash Meinel, Ian Clatworthy, Vincent Ladeuil)
987
        nb_files = 5 # .pack, .rix, .iix, .tix, .six
988
        if tree.branch.repository._format.supports_chks:
989
            nb_files += 1 # .cix
990
        # We should have 10 x nb_files files in the obsolete_packs directory.
3582.3.3 by Martin Pool
Reenable tests for stacking pack repositories
991
        obsolete_files = list(trans.list_dir('obsolete_packs'))
992
        self.assertFalse('foo' in obsolete_files)
993
        self.assertFalse('bar' in obsolete_files)
4241.6.8 by Robert Collins, John Arbash Meinel, Ian Clatworthy, Vincent Ladeuil
Add --development6-rich-root, disabling the legacy and unneeded development2 format, and activating the tests for CHK features disabled pending this format. (Robert Collins, John Arbash Meinel, Ian Clatworthy, Vincent Ladeuil)
994
        self.assertEqual(10 * nb_files, len(obsolete_files))
3582.3.3 by Martin Pool
Reenable tests for stacking pack repositories
995
        # XXX: Todo check packs obsoleted correctly - old packs and indices
996
        # in the obsolete_packs directory.
997
        large_pack_name = list(index.iter_all_entries())[0][1][0]
998
        # finally, committing again should not touch the large pack.
4595.4.4 by Robert Collins
Disable committing directly to stacked branches from lightweight checkouts.
999
        local_tree.commit('commit not triggering pack')
3735.1.1 by Robert Collins
Add development2 formats using BTree indices.
1000
        index = self.index_class(trans, 'pack-names', None)
3582.3.3 by Martin Pool
Reenable tests for stacking pack repositories
1001
        self.assertEqual(2, len(list(index.iter_all_entries())))
1002
        pack_names = [node[1][0] for node in index.iter_all_entries()]
1003
        self.assertTrue(large_pack_name in pack_names)
3582.3.1 by Martin Pool
Split pack repository tests into their own file and use scenarios
1004
1005
4343.3.33 by John Arbash Meinel
Clear KeyDependencies on abort/suspend/commit_write_group.
1006
class TestKeyDependencies(TestCaseWithTransport):
1007
1008
    def get_format(self):
6653.6.5 by Jelmer Vernooij
Rename make_bzrdir to make_controldir.
1009
        return controldir.format_registry.make_controldir(self.format_name)
4343.3.33 by John Arbash Meinel
Clear KeyDependencies on abort/suspend/commit_write_group.
1010
1011
    def create_source_and_target(self):
1012
        builder = self.make_branch_builder('source', format=self.get_format())
1013
        builder.start_series()
6816.2.1 by Jelmer Vernooij
Migrate some build_snapshot code over to having revision_id as keyword argument.
1014
        builder.build_snapshot(None, [
1015
            ('add', ('', 'root-id', 'directory', None))],
1016
            revision_id='A-id')
1017
        builder.build_snapshot(
1018
                ['A-id', 'ghost-id'], [],
1019
                revision_id='B-id', )
4343.3.33 by John Arbash Meinel
Clear KeyDependencies on abort/suspend/commit_write_group.
1020
        builder.finish_series()
4634.29.16 by Andrew Bennetts
Fix buggy TestKeyDependencies test, tweak error string and comment.
1021
        repo = self.make_repository('target', format=self.get_format())
4343.3.33 by John Arbash Meinel
Clear KeyDependencies on abort/suspend/commit_write_group.
1022
        b = builder.get_branch()
1023
        b.lock_read()
1024
        self.addCleanup(b.unlock)
1025
        repo.lock_write()
1026
        self.addCleanup(repo.unlock)
1027
        return b.repository, repo
1028
1029
    def test_key_dependencies_cleared_on_abort(self):
1030
        source_repo, target_repo = self.create_source_and_target()
1031
        target_repo.start_write_group()
1032
        try:
1033
            stream = source_repo.revisions.get_record_stream([('B-id',)],
1034
                                                             'unordered', True)
1035
            target_repo.revisions.insert_record_stream(stream)
1036
            key_refs = target_repo.revisions._index._key_dependencies
1037
            self.assertEqual([('B-id',)], sorted(key_refs.get_referrers()))
1038
        finally:
1039
            target_repo.abort_write_group()
1040
        self.assertEqual([], sorted(key_refs.get_referrers()))
1041
1042
    def test_key_dependencies_cleared_on_suspend(self):
1043
        source_repo, target_repo = self.create_source_and_target()
1044
        target_repo.start_write_group()
1045
        try:
1046
            stream = source_repo.revisions.get_record_stream([('B-id',)],
1047
                                                             'unordered', True)
1048
            target_repo.revisions.insert_record_stream(stream)
1049
            key_refs = target_repo.revisions._index._key_dependencies
1050
            self.assertEqual([('B-id',)], sorted(key_refs.get_referrers()))
1051
        finally:
1052
            target_repo.suspend_write_group()
1053
        self.assertEqual([], sorted(key_refs.get_referrers()))
1054
1055
    def test_key_dependencies_cleared_on_commit(self):
1056
        source_repo, target_repo = self.create_source_and_target()
1057
        target_repo.start_write_group()
1058
        try:
4634.29.16 by Andrew Bennetts
Fix buggy TestKeyDependencies test, tweak error string and comment.
1059
            # Copy all texts, inventories, and chks so that nothing is missing
1060
            # for revision B-id.
1061
            for vf_name in ['texts', 'chk_bytes', 'inventories']:
1062
                source_vf = getattr(source_repo, vf_name, None)
1063
                if source_vf is None:
1064
                    continue
1065
                target_vf = getattr(target_repo, vf_name)
1066
                stream = source_vf.get_record_stream(
1067
                    source_vf.keys(), 'unordered', True)
1068
                target_vf.insert_record_stream(stream)
1069
            # Copy just revision B-id
1070
            stream = source_repo.revisions.get_record_stream(
1071
                [('B-id',)], 'unordered', True)
4343.3.33 by John Arbash Meinel
Clear KeyDependencies on abort/suspend/commit_write_group.
1072
            target_repo.revisions.insert_record_stream(stream)
1073
            key_refs = target_repo.revisions._index._key_dependencies
1074
            self.assertEqual([('B-id',)], sorted(key_refs.get_referrers()))
1075
        finally:
1076
            target_repo.commit_write_group()
1077
        self.assertEqual([], sorted(key_refs.get_referrers()))
1078
1079
3801.1.18 by Andrew Bennetts
Add a test that ensures that the autopack RPC is actually used for all pack formats.
1080
class TestSmartServerAutopack(TestCaseWithTransport):
1081
1082
    def setUp(self):
1083
        super(TestSmartServerAutopack, self).setUp()
1084
        # Create a smart server that publishes whatever the backing VFS server
1085
        # does.
5017.3.44 by Vincent Ladeuil
-s bt.per_pack_repos passing
1086
        self.smart_server = test_server.SmartTCPServer_for_testing()
4659.1.2 by Robert Collins
Refactor creation and shutdown of test servers to use a common helper,
1087
        self.start_server(self.smart_server, self.get_server())
3801.1.18 by Andrew Bennetts
Add a test that ensures that the autopack RPC is actually used for all pack formats.
1088
        # Log all HPSS calls into self.hpss_calls.
1089
        client._SmartClient.hooks.install_named_hook(
1090
            'call', self.capture_hpss_call, None)
1091
        self.hpss_calls = []
1092
1093
    def capture_hpss_call(self, params):
1094
        self.hpss_calls.append(params.method)
1095
1096
    def get_format(self):
6653.6.5 by Jelmer Vernooij
Rename make_bzrdir to make_controldir.
1097
        return controldir.format_registry.make_controldir(self.format_name)
3801.1.18 by Andrew Bennetts
Add a test that ensures that the autopack RPC is actually used for all pack formats.
1098
4029.2.1 by Robert Collins
Support streaming push to stacked branches.
1099
    def test_autopack_or_streaming_rpc_is_used_when_using_hpss(self):
3801.1.18 by Andrew Bennetts
Add a test that ensures that the autopack RPC is actually used for all pack formats.
1100
        # Make local and remote repos
3735.2.98 by John Arbash Meinel
Merge bzr.dev 4032. Resolve the new streaming fetch.
1101
        format = self.get_format()
4241.6.8 by Robert Collins, John Arbash Meinel, Ian Clatworthy, Vincent Ladeuil
Add --development6-rich-root, disabling the legacy and unneeded development2 format, and activating the tests for CHK features disabled pending this format. (Robert Collins, John Arbash Meinel, Ian Clatworthy, Vincent Ladeuil)
1102
        tree = self.make_branch_and_tree('local', format=format)
1103
        self.make_branch_and_tree('remote', format=format)
3801.1.18 by Andrew Bennetts
Add a test that ensures that the autopack RPC is actually used for all pack formats.
1104
        remote_branch_url = self.smart_server.get_url() + 'remote'
6472.2.1 by Jelmer Vernooij
Use bzrdir.controldir for generic access to control directories.
1105
        remote_branch = controldir.ControlDir.open(remote_branch_url).open_branch()
3801.1.18 by Andrew Bennetts
Add a test that ensures that the autopack RPC is actually used for all pack formats.
1106
        # Make 9 local revisions, and push them one at a time to the remote
1107
        # repo to produce 9 pack files.
1108
        for x in range(9):
1109
            tree.commit('commit %s' % x)
1110
            tree.branch.push(remote_branch)
1111
        # Make one more push to trigger an autopack
1112
        self.hpss_calls = []
1113
        tree.commit('commit triggering pack')
1114
        tree.branch.push(remote_branch)
4029.2.1 by Robert Collins
Support streaming push to stacked branches.
1115
        autopack_calls = len([call for call in self.hpss_calls if call ==
1116
            'PackRepository.autopack'])
4476.3.66 by Andrew Bennetts
Fix trivial test failure by making the test recognise the new insert_stream_1.18 verb.
1117
        streaming_calls = len([call for call in self.hpss_calls if call in
4476.3.82 by Andrew Bennetts
Mention another bug fix in NEWS, and update verb name, comments, and NEWS additions for landing on 1.19 rather than 1.18.
1118
            ('Repository.insert_stream', 'Repository.insert_stream_1.19')])
4029.2.1 by Robert Collins
Support streaming push to stacked branches.
1119
        if autopack_calls:
1120
            # Non streaming server
1121
            self.assertEqual(1, autopack_calls)
1122
            self.assertEqual(0, streaming_calls)
1123
        else:
1124
            # Streaming was used, which autopacks on the remote end.
1125
            self.assertEqual(0, autopack_calls)
1126
            # NB: The 2 calls are because of the sanity check that the server
1127
            # supports the verb (see remote.py:RemoteSink.insert_stream for
1128
            # details).
1129
            self.assertEqual(2, streaming_calls)
3801.1.18 by Andrew Bennetts
Add a test that ensures that the autopack RPC is actually used for all pack formats.
1130
1131
6625.1.5 by Martin
Drop custom load_tests implementation and use unittest signature
1132
def load_tests(loader, basic_tests, pattern):
3582.3.3 by Martin Pool
Reenable tests for stacking pack repositories
1133
    # these give the bzrdir canned format name, and the repository on-disk
1134
    # format string
3582.3.1 by Martin Pool
Split pack repository tests into their own file and use scenarios
1135
    scenarios_params = [
1136
         dict(format_name='pack-0.92',
1137
              format_string="Bazaar pack repository format 1 (needs bzr 0.92)\n",
3735.1.1 by Robert Collins
Add development2 formats using BTree indices.
1138
              format_supports_external_lookups=False,
1139
              index_class=GraphIndex),
3582.3.1 by Martin Pool
Split pack repository tests into their own file and use scenarios
1140
         dict(format_name='pack-0.92-subtree',
1141
              format_string="Bazaar pack repository format 1 "
1142
              "with subtree support (needs bzr 0.92)\n",
3735.1.1 by Robert Collins
Add development2 formats using BTree indices.
1143
              format_supports_external_lookups=False,
1144
              index_class=GraphIndex),
3582.3.2 by Martin Pool
Add 1.6 formats to pack repository tests
1145
         dict(format_name='1.6',
1146
              format_string="Bazaar RepositoryFormatKnitPack5 (bzr 1.6)\n",
3735.1.1 by Robert Collins
Add development2 formats using BTree indices.
1147
              format_supports_external_lookups=True,
1148
              index_class=GraphIndex),
3606.10.5 by John Arbash Meinel
Switch out --1.6-rich-root for --1.6.1-rich-root.
1149
         dict(format_name='1.6.1-rich-root',
3582.3.2 by Martin Pool
Add 1.6 formats to pack repository tests
1150
              format_string="Bazaar RepositoryFormatKnitPack5RichRoot "
3606.10.5 by John Arbash Meinel
Switch out --1.6-rich-root for --1.6.1-rich-root.
1151
                  "(bzr 1.6.1)\n",
3735.1.1 by Robert Collins
Add development2 formats using BTree indices.
1152
              format_supports_external_lookups=True,
1153
              index_class=GraphIndex),
3805.3.1 by John Arbash Meinel
Add repository 1.9 format, and update the documentation.
1154
         dict(format_name='1.9',
1155
              format_string="Bazaar RepositoryFormatKnitPack6 (bzr 1.9)\n",
1156
              format_supports_external_lookups=True,
1157
              index_class=BTreeGraphIndex),
1158
         dict(format_name='1.9-rich-root',
1159
              format_string="Bazaar RepositoryFormatKnitPack6RichRoot "
1160
                  "(bzr 1.9)\n",
1161
              format_supports_external_lookups=True,
1162
              index_class=BTreeGraphIndex),
4597.1.6 by John Arbash Meinel
Add a test that inventory texts are preserved during pack.
1163
         dict(format_name='2a',
1164
              format_string="Bazaar repository format 2a "
1165
                "(needs bzr 1.16 or later)\n",
4343.3.8 by John Arbash Meinel
Some cleanup passes.
1166
              format_supports_external_lookups=True,
3735.2.40 by Robert Collins
Add development4 which has a parent_id to basename index on CHKInventory objects.
1167
              index_class=BTreeGraphIndex),
3582.3.1 by Martin Pool
Split pack repository tests into their own file and use scenarios
1168
         ]
1169
    # name of the scenario is the format name
4084.5.1 by Robert Collins
Bulk update all test adaptation into a single approach, using multiply_tests rather than test adapters.
1170
    scenarios = [(s['format_name'], s) for s in scenarios_params]
1171
    return tests.multiply_tests(basic_tests, scenarios, loader.suiteClass())