/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):
242
        format = self.get_format()
243
        tree = self.make_branch_and_tree('foo', format=format)
244
        tree.commit('first post')
245
        repo = tree.branch.repository
246
        repo.lock_write()
247
        try:
248
            repo.start_write_group()
249
            try:
250
                inv = inventory.Inventory(revision_id="A")
251
                inv.root.revision = "A"
252
                repo.texts.add_lines((inv.root.file_id, "A"), [], [])
253
                rev = _mod_revision.Revision(timestamp=0, timezone=None,
254
                    committer="Foo Bar <foo@example.com>", message="Message",
255
                    revision_id="A")
256
                rev.parent_ids = ()
257
                repo.add_revision("A", rev, inv=inv)
258
            except:
259
                repo.abort_write_group()
260
                raise
261
            else:
262
                old_names = repo._pack_collection._names.keys()
263
                result = repo.commit_write_group()
264
                cur_names = repo._pack_collection._names.keys()
265
                new_names = list(set(cur_names) - set(old_names))
266
                self.assertEqual(new_names, result)
267
        finally:
268
            repo.unlock()
269
3582.3.1 by Martin Pool
Split pack repository tests into their own file and use scenarios
270
    def test_fail_obsolete_deletion(self):
271
        # failing to delete obsolete packs is not fatal
272
        format = self.get_format()
273
        server = fakenfs.FakeNFSServer()
274
        server.setUp()
275
        self.addCleanup(server.tearDown)
276
        transport = get_transport(server.get_url())
277
        bzrdir = self.get_format().initialize_on_transport(transport)
278
        repo = bzrdir.create_repository()
279
        repo_transport = bzrdir.get_repository_transport(None)
280
        self.assertTrue(repo_transport.has('obsolete_packs'))
281
        # these files are in use by another client and typically can't be deleted
282
        repo_transport.put_bytes('obsolete_packs/.nfsblahblah', 'contents')
283
        repo._pack_collection._clear_obsolete_packs()
284
        self.assertTrue(repo_transport.has('obsolete_packs/.nfsblahblah'))
285
286
    def test_pack_after_two_commits_packs_everything(self):
287
        format = self.get_format()
288
        tree = self.make_branch_and_tree('.', format=format)
289
        trans = tree.branch.repository.bzrdir.get_repository_transport(None)
290
        tree.commit('start')
291
        tree.commit('more work')
292
        tree.branch.repository.pack()
293
        # there should be 1 pack:
3735.1.1 by Robert Collins
Add development2 formats using BTree indices.
294
        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
295
        self.assertEqual(1, len(list(index.iter_all_entries())))
296
        self.assertEqual(2, len(tree.branch.repository.all_revision_ids()))
297
4597.1.6 by John Arbash Meinel
Add a test that inventory texts are preserved during pack.
298
    def test_pack_preserves_all_inventories(self):
299
        # This is related to bug:
300
        #   https://bugs.launchpad.net/bzr/+bug/412198
301
        # Stacked repositories need to keep the inventory for parents, even
302
        # after a pack operation. However, it is harder to test that, then just
303
        # test that all inventory texts are preserved.
304
        format = self.get_format()
305
        builder = self.make_branch_builder('source', format=format)
306
        builder.start_series()
307
        builder.build_snapshot('A-id', None, [
308
            ('add', ('', 'root-id', 'directory', None))])
309
        builder.build_snapshot('B-id', None, [
310
            ('add', ('file', 'file-id', 'file', 'B content\n'))])
311
        builder.build_snapshot('C-id', None, [
312
            ('modify', ('file-id', 'C content\n'))])
313
        builder.finish_series()
314
        b = builder.get_branch()
315
        b.lock_read()
316
        self.addCleanup(b.unlock)
317
        repo = self.make_repository('repo', shared=True, format=format)
318
        repo.lock_write()
319
        self.addCleanup(repo.unlock)
320
        repo.fetch(b.repository, revision_id='B-id')
321
        inv = b.repository.iter_inventories(['C-id']).next()
322
        repo.start_write_group()
323
        repo.add_inventory('C-id', inv, ['B-id'])
324
        repo.commit_write_group()
325
        self.assertEqual([('A-id',), ('B-id',), ('C-id',)],
326
                         sorted(repo.inventories.keys()))
327
        repo.pack()
328
        self.assertEqual([('A-id',), ('B-id',), ('C-id',)],
329
                         sorted(repo.inventories.keys()))
330
        # Content should be preserved as well
331
        self.assertEqual(inv, repo.iter_inventories(['C-id']).next())
332
3582.3.1 by Martin Pool
Split pack repository tests into their own file and use scenarios
333
    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)
334
        # Test that the ordering of revisions in pack repositories is
335
        # tip->ancestor
3582.3.1 by Martin Pool
Split pack repository tests into their own file and use scenarios
336
        format = self.get_format()
337
        tree = self.make_branch_and_tree('.', format=format)
338
        trans = tree.branch.repository.bzrdir.get_repository_transport(None)
339
        tree.commit('start', rev_id='1')
340
        tree.commit('more work', rev_id='2')
341
        tree.branch.repository.pack()
342
        tree.lock_read()
343
        self.addCleanup(tree.unlock)
344
        pack = tree.branch.repository._pack_collection.get_pack_by_name(
345
            tree.branch.repository._pack_collection.names()[0])
3943.8.1 by Marius Kruger
remove all trailing whitespace from bzr source
346
        # 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
347
        # disk is a good idea.
348
        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
349
            if type(format.repository_format) is RepositoryFormat2a:
4350.2.1 by John Arbash Meinel
Update a test to support CHK formats.
350
                # group_start, group_len, internal_start, internal_len
351
                pos = map(int, val.split())
352
            else:
353
                # eol_flag, start, len
354
                pos = int(val[1:].split()[0])
3582.3.1 by Martin Pool
Split pack repository tests into their own file and use scenarios
355
            if key == ('1',):
4350.2.1 by John Arbash Meinel
Update a test to support CHK formats.
356
                pos_1 = pos
3582.3.1 by Martin Pool
Split pack repository tests into their own file and use scenarios
357
            else:
4350.2.1 by John Arbash Meinel
Update a test to support CHK formats.
358
                pos_2 = pos
359
        self.assertTrue(pos_2 < pos_1, 'rev 1 came before rev 2 %s > %s'
360
                                       % (pos_1, pos_2))
3582.3.1 by Martin Pool
Split pack repository tests into their own file and use scenarios
361
362
    def test_pack_repositories_support_multiple_write_locks(self):
363
        format = self.get_format()
364
        self.make_repository('.', shared=True, format=format)
365
        r1 = repository.Repository.open('.')
366
        r2 = repository.Repository.open('.')
367
        r1.lock_write()
368
        self.addCleanup(r1.unlock)
369
        r2.lock_write()
370
        r2.unlock()
371
372
    def _add_text(self, repo, fileid):
373
        """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)
374
        repo.texts.add_lines((fileid, 'samplerev+'+fileid), [],
375
            ['smaplerev+'+fileid])
3582.3.1 by Martin Pool
Split pack repository tests into their own file and use scenarios
376
377
    def test_concurrent_writers_merge_new_packs(self):
378
        format = self.get_format()
379
        self.make_repository('.', shared=True, format=format)
380
        r1 = repository.Repository.open('.')
381
        r2 = repository.Repository.open('.')
382
        r1.lock_write()
383
        try:
384
            # access enough data to load the names list
385
            list(r1.all_revision_ids())
386
            r2.lock_write()
387
            try:
388
                # access enough data to load the names list
389
                list(r2.all_revision_ids())
390
                r1.start_write_group()
391
                try:
392
                    r2.start_write_group()
393
                    try:
394
                        self._add_text(r1, 'fileidr1')
395
                        self._add_text(r2, 'fileidr2')
396
                    except:
397
                        r2.abort_write_group()
398
                        raise
399
                except:
400
                    r1.abort_write_group()
401
                    raise
402
                # both r1 and r2 have open write groups with data in them
403
                # created while the other's write group was open.
404
                # Commit both which requires a merge to the pack-names.
405
                try:
406
                    r1.commit_write_group()
407
                except:
408
                    r1.abort_write_group()
409
                    r2.abort_write_group()
410
                    raise
411
                r2.commit_write_group()
412
                # tell r1 to reload from disk
413
                r1._pack_collection.reset()
414
                # Now both repositories should know about both names
415
                r1._pack_collection.ensure_loaded()
416
                r2._pack_collection.ensure_loaded()
417
                self.assertEqual(r1._pack_collection.names(), r2._pack_collection.names())
418
                self.assertEqual(2, len(r1._pack_collection.names()))
419
            finally:
420
                r2.unlock()
421
        finally:
422
            r1.unlock()
423
424
    def test_concurrent_writer_second_preserves_dropping_a_pack(self):
425
        format = self.get_format()
426
        self.make_repository('.', shared=True, format=format)
427
        r1 = repository.Repository.open('.')
428
        r2 = repository.Repository.open('.')
429
        # add a pack to drop
430
        r1.lock_write()
431
        try:
432
            r1.start_write_group()
433
            try:
434
                self._add_text(r1, 'fileidr1')
435
            except:
436
                r1.abort_write_group()
437
                raise
438
            else:
439
                r1.commit_write_group()
440
            r1._pack_collection.ensure_loaded()
441
            name_to_drop = r1._pack_collection.all_packs()[0].name
442
        finally:
443
            r1.unlock()
444
        r1.lock_write()
445
        try:
446
            # access enough data to load the names list
447
            list(r1.all_revision_ids())
448
            r2.lock_write()
449
            try:
450
                # access enough data to load the names list
451
                list(r2.all_revision_ids())
452
                r1._pack_collection.ensure_loaded()
453
                try:
454
                    r2.start_write_group()
455
                    try:
456
                        # in r1, drop the pack
457
                        r1._pack_collection._remove_pack_from_memory(
458
                            r1._pack_collection.get_pack_by_name(name_to_drop))
459
                        # in r2, add a pack
460
                        self._add_text(r2, 'fileidr2')
461
                    except:
462
                        r2.abort_write_group()
463
                        raise
464
                except:
465
                    r1._pack_collection.reset()
466
                    raise
467
                # r1 has a changed names list, and r2 an open write groups with
468
                # changes.
469
                # save r1, and then commit the r2 write group, which requires a
470
                # merge to the pack-names, which should not reinstate
471
                # name_to_drop
472
                try:
473
                    r1._pack_collection._save_pack_names()
474
                    r1._pack_collection.reset()
475
                except:
476
                    r2.abort_write_group()
477
                    raise
478
                try:
479
                    r2.commit_write_group()
480
                except:
481
                    r2.abort_write_group()
482
                    raise
483
                # Now both repositories should now about just one name.
484
                r1._pack_collection.ensure_loaded()
485
                r2._pack_collection.ensure_loaded()
486
                self.assertEqual(r1._pack_collection.names(), r2._pack_collection.names())
487
                self.assertEqual(1, len(r1._pack_collection.names()))
488
                self.assertFalse(name_to_drop in r1._pack_collection.names())
489
            finally:
490
                r2.unlock()
491
        finally:
492
            r1.unlock()
493
3789.1.1 by John Arbash Meinel
add the failing acceptance test for the first portion.
494
    def test_concurrent_pack_triggers_reload(self):
495
        # create 2 packs, which we will then collapse
496
        tree = self.make_branch_and_tree('tree')
3789.1.2 by John Arbash Meinel
Add RepositoryPackCollection.reload_pack_names()
497
        tree.lock_write()
3789.1.1 by John Arbash Meinel
add the failing acceptance test for the first portion.
498
        try:
3789.1.2 by John Arbash Meinel
Add RepositoryPackCollection.reload_pack_names()
499
            rev1 = tree.commit('one')
500
            rev2 = tree.commit('two')
501
            r2 = repository.Repository.open('tree')
3789.1.1 by John Arbash Meinel
add the failing acceptance test for the first portion.
502
            r2.lock_read()
503
            try:
504
                # Now r2 has read the pack-names file, but will need to reload
505
                # it after r1 has repacked
3789.1.2 by John Arbash Meinel
Add RepositoryPackCollection.reload_pack_names()
506
                tree.branch.repository.pack()
507
                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.
508
            finally:
509
                r2.unlock()
510
        finally:
3789.1.2 by John Arbash Meinel
Add RepositoryPackCollection.reload_pack_names()
511
            tree.unlock()
3789.1.1 by John Arbash Meinel
add the failing acceptance test for the first portion.
512
3789.2.8 by John Arbash Meinel
Add a test that KnitPackRepository.get_record_stream retries when appropriate.
513
    def test_concurrent_pack_during_get_record_reloads(self):
514
        tree = self.make_branch_and_tree('tree')
515
        tree.lock_write()
516
        try:
517
            rev1 = tree.commit('one')
518
            rev2 = tree.commit('two')
3789.2.14 by John Arbash Meinel
Update AggregateIndex to pass the reload_func into _DirectPackAccess
519
            keys = [(rev1,), (rev2,)]
3789.2.8 by John Arbash Meinel
Add a test that KnitPackRepository.get_record_stream retries when appropriate.
520
            r2 = repository.Repository.open('tree')
521
            r2.lock_read()
522
            try:
523
                # At this point, we will start grabbing a record stream, and
524
                # trigger a repack mid-way
525
                packed = False
526
                result = {}
527
                record_stream = r2.revisions.get_record_stream(keys,
528
                                    'unordered', False)
529
                for record in record_stream:
530
                    result[record.key] = record
531
                    if not packed:
532
                        tree.branch.repository.pack()
533
                        packed = True
534
                # The first record will be found in the original location, but
535
                # 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
536
                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.
537
            finally:
538
                r2.unlock()
539
        finally:
540
            tree.unlock()
541
3582.3.1 by Martin Pool
Split pack repository tests into their own file and use scenarios
542
    def test_lock_write_does_not_physically_lock(self):
543
        repo = self.make_repository('.', format=self.get_format())
544
        repo.lock_write()
545
        self.addCleanup(repo.unlock)
546
        self.assertFalse(repo.get_physical_lock_status())
547
548
    def prepare_for_break_lock(self):
549
        # Setup the global ui factory state so that a break-lock method call
550
        # will find usable input in the input stream.
551
        old_factory = ui.ui_factory
552
        def restoreFactory():
553
            ui.ui_factory = old_factory
554
        self.addCleanup(restoreFactory)
4449.3.27 by Martin Pool
More test updates to use CannedInputUIFactory
555
        ui.ui_factory = ui.CannedInputUIFactory([True])
3582.3.1 by Martin Pool
Split pack repository tests into their own file and use scenarios
556
557
    def test_break_lock_breaks_physical_lock(self):
558
        repo = self.make_repository('.', format=self.get_format())
559
        repo._pack_collection.lock_names()
3650.4.1 by Aaron Bentley
Fix test kipple in test_break_lock_breaks_physical_lock
560
        repo.control_files.leave_in_place()
561
        repo.unlock()
3582.3.1 by Martin Pool
Split pack repository tests into their own file and use scenarios
562
        repo2 = repository.Repository.open('.')
563
        self.assertTrue(repo.get_physical_lock_status())
564
        self.prepare_for_break_lock()
565
        repo2.break_lock()
566
        self.assertFalse(repo.get_physical_lock_status())
567
568
    def test_broken_physical_locks_error_on__unlock_names_lock(self):
569
        repo = self.make_repository('.', format=self.get_format())
570
        repo._pack_collection.lock_names()
571
        self.assertTrue(repo.get_physical_lock_status())
572
        repo2 = repository.Repository.open('.')
573
        self.prepare_for_break_lock()
574
        repo2.break_lock()
575
        self.assertRaises(errors.LockBroken, repo._pack_collection._unlock_names)
576
577
    def test_fetch_without_find_ghosts_ignores_ghosts(self):
578
        # we want two repositories at this point:
579
        # one with a revision that is a ghost in the other
580
        # repository.
581
        # 'ghost' is present in has_ghost, 'ghost' is absent in 'missing_ghost'.
582
        # 'references' is present in both repositories, and 'tip' is present
583
        # just in has_ghost.
584
        # has_ghost       missing_ghost
585
        #------------------------------
586
        # 'ghost'             -
587
        # 'references'    'references'
588
        # 'tip'               -
589
        # In this test we fetch 'tip' which should not fetch 'ghost'
590
        has_ghost = self.make_repository('has_ghost', format=self.get_format())
591
        missing_ghost = self.make_repository('missing_ghost',
592
            format=self.get_format())
593
594
        def add_commit(repo, revision_id, parent_ids):
595
            repo.lock_write()
596
            repo.start_write_group()
597
            inv = inventory.Inventory(revision_id=revision_id)
598
            inv.root.revision = revision_id
599
            root_id = inv.root.file_id
600
            sha1 = repo.add_inventory(revision_id, inv, [])
601
            repo.texts.add_lines((root_id, revision_id), [], [])
602
            rev = _mod_revision.Revision(timestamp=0,
603
                                         timezone=None,
604
                                         committer="Foo Bar <foo@example.com>",
605
                                         message="Message",
606
                                         inventory_sha1=sha1,
607
                                         revision_id=revision_id)
608
            rev.parent_ids = parent_ids
609
            repo.add_revision(revision_id, rev)
610
            repo.commit_write_group()
611
            repo.unlock()
612
        add_commit(has_ghost, 'ghost', [])
613
        add_commit(has_ghost, 'references', ['ghost'])
614
        add_commit(missing_ghost, 'references', ['ghost'])
615
        add_commit(has_ghost, 'tip', ['references'])
616
        missing_ghost.fetch(has_ghost, 'tip')
617
        # missing ghost now has tip and not ghost.
618
        rev = missing_ghost.get_revision('tip')
619
        inv = missing_ghost.get_inventory('tip')
620
        self.assertRaises(errors.NoSuchRevision,
621
            missing_ghost.get_revision, 'ghost')
622
        self.assertRaises(errors.NoSuchRevision,
623
            missing_ghost.get_inventory, 'ghost')
624
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.
625
    def make_write_ready_repo(self):
4360.4.6 by John Arbash Meinel
Change how 'missing.*parent_prevents_commit' determines what to skip.
626
        format = self.get_format()
4597.1.10 by John Arbash Meinel
Fix some tests that were failing because we checked against RepositoryFormatCHK1
627
        if isinstance(format.repository_format, RepositoryFormat2a):
4360.4.6 by John Arbash Meinel
Change how 'missing.*parent_prevents_commit' determines what to skip.
628
            raise TestNotApplicable("No missing compression parents")
629
        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.
630
        repo.lock_write()
4360.4.6 by John Arbash Meinel
Change how 'missing.*parent_prevents_commit' determines what to skip.
631
        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.
632
        repo.start_write_group()
4360.4.6 by John Arbash Meinel
Change how 'missing.*parent_prevents_commit' determines what to skip.
633
        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.
634
        return repo
635
636
    def test_missing_inventories_compression_parent_prevents_commit(self):
637
        repo = self.make_write_ready_repo()
638
        key = ('junk',)
639
        repo.inventories._index._missing_compression_parents.add(key)
640
        self.assertRaises(errors.BzrCheckError, repo.commit_write_group)
641
        self.assertRaises(errors.BzrCheckError, repo.commit_write_group)
642
643
    def test_missing_revisions_compression_parent_prevents_commit(self):
644
        repo = self.make_write_ready_repo()
645
        key = ('junk',)
646
        repo.revisions._index._missing_compression_parents.add(key)
647
        self.assertRaises(errors.BzrCheckError, repo.commit_write_group)
648
        self.assertRaises(errors.BzrCheckError, repo.commit_write_group)
649
650
    def test_missing_signatures_compression_parent_prevents_commit(self):
651
        repo = self.make_write_ready_repo()
652
        key = ('junk',)
653
        repo.signatures._index._missing_compression_parents.add(key)
654
        self.assertRaises(errors.BzrCheckError, repo.commit_write_group)
655
        self.assertRaises(errors.BzrCheckError, repo.commit_write_group)
656
657
    def test_missing_text_compression_parent_prevents_commit(self):
658
        repo = self.make_write_ready_repo()
659
        key = ('some', 'junk')
660
        repo.texts._index._missing_compression_parents.add(key)
661
        self.assertRaises(errors.BzrCheckError, repo.commit_write_group)
662
        e = self.assertRaises(errors.BzrCheckError, repo.commit_write_group)
663
3582.3.1 by Martin Pool
Split pack repository tests into their own file and use scenarios
664
    def test_supports_external_lookups(self):
665
        repo = self.make_repository('.', format=self.get_format())
666
        self.assertEqual(self.format_supports_external_lookups,
667
            repo._format.supports_external_lookups)
668
3825.4.1 by Andrew Bennetts
Add suppress_errors to abort_write_group.
669
    def test_abort_write_group_does_not_raise_when_suppressed(self):
670
        """Similar to per_repository.test_write_group's test of the same name.
671
672
        Also requires that the exception is logged.
673
        """
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.
674
        self.vfs_transport_factory = memory.MemoryServer
4343.3.7 by John Arbash Meinel
Update the suspend/resume/commit/abort_write_group tests for CHK1.
675
        repo = self.make_repository('repo', format=self.get_format())
3825.4.1 by Andrew Bennetts
Add suppress_errors to abort_write_group.
676
        token = repo.lock_write()
677
        self.addCleanup(repo.unlock)
678
        repo.start_write_group()
679
        # Damage the repository on the filesystem
680
        self.get_transport('').rename('repo', 'foo')
681
        # abort_write_group will not raise an error
682
        self.assertEqual(None, repo.abort_write_group(suppress_errors=True))
683
        # But it does log an error
684
        log_file = self._get_log(keep_log_file=True)
685
        self.assertContainsRe(log_file, 'abort_write_group failed')
686
        self.assertContainsRe(log_file, r'INFO  bzr: ERROR \(ignored\):')
687
        if token is not None:
688
            repo.leave_lock_in_place()
3943.8.1 by Marius Kruger
remove all trailing whitespace from bzr source
689
3825.4.1 by Andrew Bennetts
Add suppress_errors to abort_write_group.
690
    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.
691
        self.vfs_transport_factory = memory.MemoryServer
4343.3.7 by John Arbash Meinel
Update the suspend/resume/commit/abort_write_group tests for CHK1.
692
        repo = self.make_repository('repo', format=self.get_format())
3825.4.1 by Andrew Bennetts
Add suppress_errors to abort_write_group.
693
        token = repo.lock_write()
694
        self.addCleanup(repo.unlock)
695
        repo.start_write_group()
696
        # Damage the repository on the filesystem
697
        self.get_transport('').rename('repo', 'foo')
698
        # abort_write_group will not raise an error
699
        self.assertRaises(Exception, repo.abort_write_group)
700
        if token is not None:
701
            repo.leave_lock_in_place()
3943.8.1 by Marius Kruger
remove all trailing whitespace from bzr source
702
4002.1.1 by Andrew Bennetts
Implement suspend_write_group/resume_write_group.
703
    def test_suspend_write_group(self):
704
        self.vfs_transport_factory = memory.MemoryServer
4343.3.7 by John Arbash Meinel
Update the suspend/resume/commit/abort_write_group tests for CHK1.
705
        repo = self.make_repository('repo', format=self.get_format())
4002.1.1 by Andrew Bennetts
Implement suspend_write_group/resume_write_group.
706
        token = repo.lock_write()
707
        self.addCleanup(repo.unlock)
708
        repo.start_write_group()
709
        repo.texts.add_lines(('file-id', 'revid'), (), ['lines'])
710
        wg_tokens = repo.suspend_write_group()
711
        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.
712
        expected_names = [wg_tokens[0] + ext for ext in
713
                            ('.rix', '.iix', '.tix', '.six')]
714
        if repo.chk_bytes is not None:
715
            expected_names.append(wg_tokens[0] + '.cix')
716
        expected_names.append(expected_pack_name)
4002.1.1 by Andrew Bennetts
Implement suspend_write_group/resume_write_group.
717
        upload_transport = repo._pack_collection._upload_transport
718
        limbo_files = upload_transport.list_dir('')
4343.3.7 by John Arbash Meinel
Update the suspend/resume/commit/abort_write_group tests for CHK1.
719
        self.assertEqual(sorted(expected_names), sorted(limbo_files))
4002.1.1 by Andrew Bennetts
Implement suspend_write_group/resume_write_group.
720
        md5 = osutils.md5(upload_transport.get_bytes(expected_pack_name))
721
        self.assertEqual(wg_tokens[0], md5.hexdigest())
722
4343.3.8 by John Arbash Meinel
Some cleanup passes.
723
    def test_resume_chk_bytes(self):
724
        self.vfs_transport_factory = memory.MemoryServer
725
        repo = self.make_repository('repo', format=self.get_format())
726
        if repo.chk_bytes is None:
727
            raise TestNotApplicable('no chk_bytes for this repository')
728
        token = repo.lock_write()
729
        self.addCleanup(repo.unlock)
730
        repo.start_write_group()
731
        text = 'a bit of text\n'
732
        key = ('sha1:' + osutils.sha_string(text),)
733
        repo.chk_bytes.add_lines(key, (), [text])
734
        wg_tokens = repo.suspend_write_group()
735
        same_repo = repo.bzrdir.open_repository()
736
        same_repo.lock_write()
737
        self.addCleanup(same_repo.unlock)
738
        same_repo.resume_write_group(wg_tokens)
739
        self.assertEqual([key], list(same_repo.chk_bytes.keys()))
740
        self.assertEqual(
741
            text, same_repo.chk_bytes.get_record_stream([key],
742
                'unordered', True).next().get_bytes_as('fulltext'))
743
        same_repo.abort_write_group()
744
        self.assertEqual([], list(same_repo.chk_bytes.keys()))
745
4002.1.1 by Andrew Bennetts
Implement suspend_write_group/resume_write_group.
746
    def test_resume_write_group_then_abort(self):
747
        # Create a repo, start a write group, insert some data, suspend.
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())
4002.1.1 by Andrew Bennetts
Implement suspend_write_group/resume_write_group.
750
        token = repo.lock_write()
751
        self.addCleanup(repo.unlock)
752
        repo.start_write_group()
753
        text_key = ('file-id', 'revid')
754
        repo.texts.add_lines(text_key, (), ['lines'])
755
        wg_tokens = repo.suspend_write_group()
756
        # Get a fresh repository object for the repo on the filesystem.
757
        same_repo = repo.bzrdir.open_repository()
758
        # Resume
759
        same_repo.lock_write()
760
        self.addCleanup(same_repo.unlock)
761
        same_repo.resume_write_group(wg_tokens)
762
        same_repo.abort_write_group()
763
        self.assertEqual(
764
            [], same_repo._pack_collection._upload_transport.list_dir(''))
765
        self.assertEqual(
766
            [], same_repo._pack_collection._pack_transport.list_dir(''))
767
4343.3.7 by John Arbash Meinel
Update the suspend/resume/commit/abort_write_group tests for CHK1.
768
    def test_commit_resumed_write_group(self):
769
        self.vfs_transport_factory = memory.MemoryServer
770
        repo = self.make_repository('repo', format=self.get_format())
771
        token = repo.lock_write()
772
        self.addCleanup(repo.unlock)
773
        repo.start_write_group()
774
        text_key = ('file-id', 'revid')
775
        repo.texts.add_lines(text_key, (), ['lines'])
776
        wg_tokens = repo.suspend_write_group()
777
        # Get a fresh repository object for the repo on the filesystem.
778
        same_repo = repo.bzrdir.open_repository()
779
        # Resume
780
        same_repo.lock_write()
781
        self.addCleanup(same_repo.unlock)
782
        same_repo.resume_write_group(wg_tokens)
783
        same_repo.commit_write_group()
784
        expected_pack_name = wg_tokens[0] + '.pack'
785
        expected_names = [wg_tokens[0] + ext for ext in
786
                            ('.rix', '.iix', '.tix', '.six')]
787
        if repo.chk_bytes is not None:
788
            expected_names.append(wg_tokens[0] + '.cix')
789
        self.assertEqual(
790
            [], same_repo._pack_collection._upload_transport.list_dir(''))
791
        index_names = repo._pack_collection._index_transport.list_dir('')
792
        self.assertEqual(sorted(expected_names), sorted(index_names))
793
        pack_names = repo._pack_collection._pack_transport.list_dir('')
794
        self.assertEqual([expected_pack_name], pack_names)
795
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.
796
    def test_resume_malformed_token(self):
797
        self.vfs_transport_factory = memory.MemoryServer
798
        # 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.
799
        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.
800
        token = repo.lock_write()
801
        self.addCleanup(repo.unlock)
802
        repo.start_write_group()
803
        text_key = ('file-id', 'revid')
804
        repo.texts.add_lines(text_key, (), ['lines'])
805
        wg_tokens = repo.suspend_write_group()
806
        # Make a new repository
4343.3.7 by John Arbash Meinel
Update the suspend/resume/commit/abort_write_group tests for CHK1.
807
        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.
808
        token = new_repo.lock_write()
809
        self.addCleanup(new_repo.unlock)
810
        hacked_wg_token = (
811
            '../../../../repo/.bzr/repository/upload/' + wg_tokens[0])
812
        self.assertRaises(
4002.1.7 by Andrew Bennetts
Rename UnresumableWriteGroups to UnresumableWriteGroup.
813
            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.
814
            new_repo.resume_write_group, [hacked_wg_token])
815
3582.3.1 by Martin Pool
Split pack repository tests into their own file and use scenarios
816
3582.3.3 by Martin Pool
Reenable tests for stacking pack repositories
817
class TestPackRepositoryStacking(TestCaseWithTransport):
818
819
    """Tests for stacking pack repositories"""
820
821
    def setUp(self):
822
        if not self.format_supports_external_lookups:
3943.8.1 by Marius Kruger
remove all trailing whitespace from bzr source
823
            raise TestNotApplicable("%r doesn't support stacking"
3582.3.3 by Martin Pool
Reenable tests for stacking pack repositories
824
                % (self.format_name,))
825
        super(TestPackRepositoryStacking, self).setUp()
826
827
    def get_format(self):
828
        return bzrdir.format_registry.make_bzrdir(self.format_name)
829
3606.10.5 by John Arbash Meinel
Switch out --1.6-rich-root for --1.6.1-rich-root.
830
    def test_stack_checks_rich_root_compatibility(self):
3582.3.3 by Martin Pool
Reenable tests for stacking pack repositories
831
        # early versions of the packing code relied on pack internals to
832
        # stack, but the current version should be able to stack on any
833
        # format.
834
        #
835
        # TODO: Possibly this should be run per-repository-format and raise
836
        # TestNotApplicable on formats that don't support stacking. -- mbp
837
        # 20080729
838
        repo = self.make_repository('repo', format=self.get_format())
839
        if repo.supports_rich_root():
840
            # can only stack on repositories that have compatible internal
841
            # metadata
3606.10.5 by John Arbash Meinel
Switch out --1.6-rich-root for --1.6.1-rich-root.
842
            if getattr(repo._format, 'supports_tree_reference', False):
4343.3.27 by John Arbash Meinel
Now that dev6 supports external references, the tests for
843
                matching_format_name = 'pack-0.92-subtree'
844
            else:
3735.2.9 by Robert Collins
Get a working chk_map using inventory implementation bootstrapped.
845
                if repo._format.supports_chks:
4597.1.6 by John Arbash Meinel
Add a test that inventory texts are preserved during pack.
846
                    matching_format_name = '2a'
3735.2.9 by Robert Collins
Get a working chk_map using inventory implementation bootstrapped.
847
                else:
4343.3.27 by John Arbash Meinel
Now that dev6 supports external references, the tests for
848
                    matching_format_name = 'rich-root-pack'
3582.3.3 by Martin Pool
Reenable tests for stacking pack repositories
849
            mismatching_format_name = 'pack-0.92'
850
        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)
851
            # 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.
852
            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)
853
                raise AssertionError("no non-rich-root CHK formats known")
3735.2.9 by Robert Collins
Get a working chk_map using inventory implementation bootstrapped.
854
            else:
855
                matching_format_name = 'pack-0.92'
3582.3.3 by Martin Pool
Reenable tests for stacking pack repositories
856
            mismatching_format_name = 'pack-0.92-subtree'
857
        base = self.make_repository('base', format=matching_format_name)
858
        repo.add_fallback_repository(base)
859
        # you can't stack on something with incompatible data
860
        bad_repo = self.make_repository('mismatch',
861
            format=mismatching_format_name)
862
        e = self.assertRaises(errors.IncompatibleRepositories,
863
            repo.add_fallback_repository, bad_repo)
864
        self.assertContainsRe(str(e),
865
            r'(?m)KnitPackRepository.*/mismatch/.*\nis not compatible with\n'
3735.2.9 by Robert Collins
Get a working chk_map using inventory implementation bootstrapped.
866
            r'.*Repository.*/repo/.*\n'
3582.3.3 by Martin Pool
Reenable tests for stacking pack repositories
867
            r'different rich-root support')
868
3606.10.5 by John Arbash Meinel
Switch out --1.6-rich-root for --1.6.1-rich-root.
869
    def test_stack_checks_serializers_compatibility(self):
870
        repo = self.make_repository('repo', format=self.get_format())
871
        if getattr(repo._format, 'supports_tree_reference', False):
872
            # can only stack on repositories that have compatible internal
873
            # metadata
4343.3.27 by John Arbash Meinel
Now that dev6 supports external references, the tests for
874
            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.
875
            mismatching_format_name = 'rich-root-pack'
876
        else:
877
            if repo.supports_rich_root():
4343.3.27 by John Arbash Meinel
Now that dev6 supports external references, the tests for
878
                if repo._format.supports_chks:
4597.1.6 by John Arbash Meinel
Add a test that inventory texts are preserved during pack.
879
                    matching_format_name = '2a'
4343.3.27 by John Arbash Meinel
Now that dev6 supports external references, the tests for
880
                else:
881
                    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.
882
                mismatching_format_name = 'pack-0.92-subtree'
883
            else:
884
                raise TestNotApplicable('No formats use non-v5 serializer'
885
                    ' without having rich-root also set')
886
        base = self.make_repository('base', format=matching_format_name)
887
        repo.add_fallback_repository(base)
888
        # you can't stack on something with incompatible data
889
        bad_repo = self.make_repository('mismatch',
890
            format=mismatching_format_name)
891
        e = self.assertRaises(errors.IncompatibleRepositories,
892
            repo.add_fallback_repository, bad_repo)
893
        self.assertContainsRe(str(e),
894
            r'(?m)KnitPackRepository.*/mismatch/.*\nis not compatible with\n'
3735.2.9 by Robert Collins
Get a working chk_map using inventory implementation bootstrapped.
895
            r'.*Repository.*/repo/.*\n'
3606.10.5 by John Arbash Meinel
Switch out --1.6-rich-root for --1.6.1-rich-root.
896
            r'different serializers')
897
3582.3.3 by Martin Pool
Reenable tests for stacking pack repositories
898
    def test_adding_pack_does_not_record_pack_names_from_other_repositories(self):
899
        base = self.make_branch_and_tree('base', format=self.get_format())
900
        base.commit('foo')
901
        referencing = self.make_branch_and_tree('repo', format=self.get_format())
902
        referencing.branch.repository.add_fallback_repository(base.branch.repository)
4595.4.4 by Robert Collins
Disable committing directly to stacked branches from lightweight checkouts.
903
        local_tree = referencing.branch.create_checkout('local')
904
        local_tree.commit('bar')
3582.3.3 by Martin Pool
Reenable tests for stacking pack repositories
905
        new_instance = referencing.bzrdir.open_repository()
906
        new_instance.lock_read()
907
        self.addCleanup(new_instance.unlock)
908
        new_instance._pack_collection.ensure_loaded()
909
        self.assertEqual(1, len(new_instance._pack_collection.all_packs()))
910
911
    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)
912
        format = self.get_format()
913
        base = self.make_branch_and_tree('base', format=format)
3582.3.3 by Martin Pool
Reenable tests for stacking pack repositories
914
        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)
915
        tree = self.make_branch_and_tree('repo', format=format)
3582.3.3 by Martin Pool
Reenable tests for stacking pack repositories
916
        tree.branch.repository.add_fallback_repository(base.branch.repository)
917
        trans = tree.branch.repository.bzrdir.get_repository_transport(None)
918
        # This test could be a little cheaper by replacing the packs
919
        # attribute on the repository to allow a different pack distribution
920
        # and max packs policy - so we are checking the policy is honoured
921
        # in the test. But for now 11 commits is not a big deal in a single
922
        # test.
4595.4.4 by Robert Collins
Disable committing directly to stacked branches from lightweight checkouts.
923
        local_tree = tree.branch.create_checkout('local')
3582.3.3 by Martin Pool
Reenable tests for stacking pack repositories
924
        for x in range(9):
4595.4.4 by Robert Collins
Disable committing directly to stacked branches from lightweight checkouts.
925
            local_tree.commit('commit %s' % x)
3582.3.3 by Martin Pool
Reenable tests for stacking pack repositories
926
        # there should be 9 packs:
3735.1.1 by Robert Collins
Add development2 formats using BTree indices.
927
        index = self.index_class(trans, 'pack-names', None)
3582.3.3 by Martin Pool
Reenable tests for stacking pack repositories
928
        self.assertEqual(9, len(list(index.iter_all_entries())))
929
        # committing one more should coalesce to 1 of 10.
4595.4.4 by Robert Collins
Disable committing directly to stacked branches from lightweight checkouts.
930
        local_tree.commit('commit triggering pack')
3735.1.1 by Robert Collins
Add development2 formats using BTree indices.
931
        index = self.index_class(trans, 'pack-names', None)
3582.3.3 by Martin Pool
Reenable tests for stacking pack repositories
932
        self.assertEqual(1, len(list(index.iter_all_entries())))
933
        # packing should not damage data
934
        tree = tree.bzrdir.open_workingtree()
935
        check_result = tree.branch.repository.check(
936
            [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)
937
        nb_files = 5 # .pack, .rix, .iix, .tix, .six
938
        if tree.branch.repository._format.supports_chks:
939
            nb_files += 1 # .cix
940
        # 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
941
        obsolete_files = list(trans.list_dir('obsolete_packs'))
942
        self.assertFalse('foo' in obsolete_files)
943
        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)
944
        self.assertEqual(10 * nb_files, len(obsolete_files))
3582.3.3 by Martin Pool
Reenable tests for stacking pack repositories
945
        # XXX: Todo check packs obsoleted correctly - old packs and indices
946
        # in the obsolete_packs directory.
947
        large_pack_name = list(index.iter_all_entries())[0][1][0]
948
        # finally, committing again should not touch the large pack.
4595.4.4 by Robert Collins
Disable committing directly to stacked branches from lightweight checkouts.
949
        local_tree.commit('commit not triggering pack')
3735.1.1 by Robert Collins
Add development2 formats using BTree indices.
950
        index = self.index_class(trans, 'pack-names', None)
3582.3.3 by Martin Pool
Reenable tests for stacking pack repositories
951
        self.assertEqual(2, len(list(index.iter_all_entries())))
952
        pack_names = [node[1][0] for node in index.iter_all_entries()]
953
        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
954
955
4343.3.33 by John Arbash Meinel
Clear KeyDependencies on abort/suspend/commit_write_group.
956
class TestKeyDependencies(TestCaseWithTransport):
957
958
    def get_format(self):
959
        return bzrdir.format_registry.make_bzrdir(self.format_name)
960
961
    def create_source_and_target(self):
962
        builder = self.make_branch_builder('source', format=self.get_format())
963
        builder.start_series()
964
        builder.build_snapshot('A-id', None, [
965
            ('add', ('', 'root-id', 'directory', None))])
966
        builder.build_snapshot('B-id', ['A-id', 'ghost-id'], [])
967
        builder.finish_series()
968
        repo = self.make_repository('target')
969
        b = builder.get_branch()
970
        b.lock_read()
971
        self.addCleanup(b.unlock)
972
        repo.lock_write()
973
        self.addCleanup(repo.unlock)
974
        return b.repository, repo
975
976
    def test_key_dependencies_cleared_on_abort(self):
977
        source_repo, target_repo = self.create_source_and_target()
978
        target_repo.start_write_group()
979
        try:
980
            stream = source_repo.revisions.get_record_stream([('B-id',)],
981
                                                             'unordered', True)
982
            target_repo.revisions.insert_record_stream(stream)
983
            key_refs = target_repo.revisions._index._key_dependencies
984
            self.assertEqual([('B-id',)], sorted(key_refs.get_referrers()))
985
        finally:
986
            target_repo.abort_write_group()
987
        self.assertEqual([], sorted(key_refs.get_referrers()))
988
989
    def test_key_dependencies_cleared_on_suspend(self):
990
        source_repo, target_repo = self.create_source_and_target()
991
        target_repo.start_write_group()
992
        try:
993
            stream = source_repo.revisions.get_record_stream([('B-id',)],
994
                                                             'unordered', True)
995
            target_repo.revisions.insert_record_stream(stream)
996
            key_refs = target_repo.revisions._index._key_dependencies
997
            self.assertEqual([('B-id',)], sorted(key_refs.get_referrers()))
998
        finally:
999
            target_repo.suspend_write_group()
1000
        self.assertEqual([], sorted(key_refs.get_referrers()))
1001
1002
    def test_key_dependencies_cleared_on_commit(self):
1003
        source_repo, target_repo = self.create_source_and_target()
1004
        target_repo.start_write_group()
1005
        try:
1006
            stream = source_repo.revisions.get_record_stream([('B-id',)],
1007
                                                             'unordered', True)
1008
            target_repo.revisions.insert_record_stream(stream)
1009
            key_refs = target_repo.revisions._index._key_dependencies
1010
            self.assertEqual([('B-id',)], sorted(key_refs.get_referrers()))
1011
        finally:
1012
            target_repo.commit_write_group()
1013
        self.assertEqual([], sorted(key_refs.get_referrers()))
1014
1015
3801.1.18 by Andrew Bennetts
Add a test that ensures that the autopack RPC is actually used for all pack formats.
1016
class TestSmartServerAutopack(TestCaseWithTransport):
1017
1018
    def setUp(self):
1019
        super(TestSmartServerAutopack, self).setUp()
1020
        # Create a smart server that publishes whatever the backing VFS server
1021
        # does.
1022
        self.smart_server = server.SmartTCPServer_for_testing()
1023
        self.smart_server.setUp(self.get_server())
1024
        self.addCleanup(self.smart_server.tearDown)
1025
        # Log all HPSS calls into self.hpss_calls.
1026
        client._SmartClient.hooks.install_named_hook(
1027
            'call', self.capture_hpss_call, None)
1028
        self.hpss_calls = []
1029
1030
    def capture_hpss_call(self, params):
1031
        self.hpss_calls.append(params.method)
1032
1033
    def get_format(self):
1034
        return bzrdir.format_registry.make_bzrdir(self.format_name)
1035
4029.2.1 by Robert Collins
Support streaming push to stacked branches.
1036
    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.
1037
        # Make local and remote repos
3735.2.98 by John Arbash Meinel
Merge bzr.dev 4032. Resolve the new streaming fetch.
1038
        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)
1039
        tree = self.make_branch_and_tree('local', format=format)
1040
        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.
1041
        remote_branch_url = self.smart_server.get_url() + 'remote'
1042
        remote_branch = bzrdir.BzrDir.open(remote_branch_url).open_branch()
1043
        # Make 9 local revisions, and push them one at a time to the remote
1044
        # repo to produce 9 pack files.
1045
        for x in range(9):
1046
            tree.commit('commit %s' % x)
1047
            tree.branch.push(remote_branch)
1048
        # Make one more push to trigger an autopack
1049
        self.hpss_calls = []
1050
        tree.commit('commit triggering pack')
1051
        tree.branch.push(remote_branch)
4029.2.1 by Robert Collins
Support streaming push to stacked branches.
1052
        autopack_calls = len([call for call in self.hpss_calls if call ==
1053
            'PackRepository.autopack'])
1054
        streaming_calls = len([call for call in self.hpss_calls if call ==
1055
            'Repository.insert_stream'])
1056
        if autopack_calls:
1057
            # Non streaming server
1058
            self.assertEqual(1, autopack_calls)
1059
            self.assertEqual(0, streaming_calls)
1060
        else:
1061
            # Streaming was used, which autopacks on the remote end.
1062
            self.assertEqual(0, autopack_calls)
1063
            # NB: The 2 calls are because of the sanity check that the server
1064
            # supports the verb (see remote.py:RemoteSink.insert_stream for
1065
            # details).
1066
            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.
1067
1068
4084.5.1 by Robert Collins
Bulk update all test adaptation into a single approach, using multiply_tests rather than test adapters.
1069
def load_tests(basic_tests, module, loader):
3582.3.3 by Martin Pool
Reenable tests for stacking pack repositories
1070
    # these give the bzrdir canned format name, and the repository on-disk
1071
    # format string
3582.3.1 by Martin Pool
Split pack repository tests into their own file and use scenarios
1072
    scenarios_params = [
1073
         dict(format_name='pack-0.92',
1074
              format_string="Bazaar pack repository format 1 (needs bzr 0.92)\n",
3735.1.1 by Robert Collins
Add development2 formats using BTree indices.
1075
              format_supports_external_lookups=False,
1076
              index_class=GraphIndex),
3582.3.1 by Martin Pool
Split pack repository tests into their own file and use scenarios
1077
         dict(format_name='pack-0.92-subtree',
1078
              format_string="Bazaar pack repository format 1 "
1079
              "with subtree support (needs bzr 0.92)\n",
3735.1.1 by Robert Collins
Add development2 formats using BTree indices.
1080
              format_supports_external_lookups=False,
1081
              index_class=GraphIndex),
3582.3.2 by Martin Pool
Add 1.6 formats to pack repository tests
1082
         dict(format_name='1.6',
1083
              format_string="Bazaar RepositoryFormatKnitPack5 (bzr 1.6)\n",
3735.1.1 by Robert Collins
Add development2 formats using BTree indices.
1084
              format_supports_external_lookups=True,
1085
              index_class=GraphIndex),
3606.10.5 by John Arbash Meinel
Switch out --1.6-rich-root for --1.6.1-rich-root.
1086
         dict(format_name='1.6.1-rich-root',
3582.3.2 by Martin Pool
Add 1.6 formats to pack repository tests
1087
              format_string="Bazaar RepositoryFormatKnitPack5RichRoot "
3606.10.5 by John Arbash Meinel
Switch out --1.6-rich-root for --1.6.1-rich-root.
1088
                  "(bzr 1.6.1)\n",
3735.1.1 by Robert Collins
Add development2 formats using BTree indices.
1089
              format_supports_external_lookups=True,
1090
              index_class=GraphIndex),
3805.3.1 by John Arbash Meinel
Add repository 1.9 format, and update the documentation.
1091
         dict(format_name='1.9',
1092
              format_string="Bazaar RepositoryFormatKnitPack6 (bzr 1.9)\n",
1093
              format_supports_external_lookups=True,
1094
              index_class=BTreeGraphIndex),
1095
         dict(format_name='1.9-rich-root',
1096
              format_string="Bazaar RepositoryFormatKnitPack6RichRoot "
1097
                  "(bzr 1.9)\n",
1098
              format_supports_external_lookups=True,
1099
              index_class=BTreeGraphIndex),
4597.1.6 by John Arbash Meinel
Add a test that inventory texts are preserved during pack.
1100
         dict(format_name='2a',
1101
              format_string="Bazaar repository format 2a "
1102
                "(needs bzr 1.16 or later)\n",
4343.3.8 by John Arbash Meinel
Some cleanup passes.
1103
              format_supports_external_lookups=True,
3735.2.40 by Robert Collins
Add development4 which has a parent_id to basename index on CHKInventory objects.
1104
              index_class=BTreeGraphIndex),
3582.3.1 by Martin Pool
Split pack repository tests into their own file and use scenarios
1105
         ]
1106
    # 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.
1107
    scenarios = [(s['format_name'], s) for s in scenarios_params]
1108
    return tests.multiply_tests(basic_tests, scenarios, loader.suiteClass())