/brz/remove-bazaar

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