/brz/remove-bazaar

To get this branch, use:
bzr branch http://gegoxaren.bato24.eu/bzr/brz/remove-bazaar
3582.3.1 by Martin Pool
Split pack repository tests into their own file and use scenarios
1
# Copyright (C) 2008 Canonical Ltd
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
    )
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)
41
from bzrlib.repofmt.groupcompress_repo import RepositoryFormatCHK1
3801.1.18 by Andrew Bennetts
Add a test that ensures that the autopack RPC is actually used for all pack formats.
42
from bzrlib.smart import (
43
    client,
44
    server,
45
    )
3582.3.1 by Martin Pool
Split pack repository tests into their own file and use scenarios
46
from bzrlib.tests import (
47
    TestCase,
48
    TestCaseWithTransport,
3582.3.3 by Martin Pool
Reenable tests for stacking pack repositories
49
    TestNotApplicable,
3582.3.1 by Martin Pool
Split pack repository tests into their own file and use scenarios
50
    TestSkipped,
51
    )
52
from bzrlib.transport import (
53
    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.
54
    memory,
3582.3.1 by Martin Pool
Split pack repository tests into their own file and use scenarios
55
    get_transport,
56
    )
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.
57
from bzrlib.tests.per_repository import TestCaseWithRepository
3582.3.1 by Martin Pool
Split pack repository tests into their own file and use scenarios
58
59
60
class TestPackRepository(TestCaseWithTransport):
61
    """Tests to be repeated across all pack-based formats.
62
63
    The following are populated from the test scenario:
64
65
    :ivar format_name: Registered name fo the format to test.
66
    :ivar format_string: On-disk format marker.
67
    :ivar format_supports_external_lookups: Boolean.
68
    """
69
70
    def get_format(self):
71
        return bzrdir.format_registry.make_bzrdir(self.format_name)
72
73
    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.
74
        """Packs do not need ordered data retrieval."""
3582.3.1 by Martin Pool
Split pack repository tests into their own file and use scenarios
75
        format = self.get_format()
76
        repo = self.make_repository('.', format=format)
4053.1.4 by Robert Collins
Move the fetch control attributes from Repository to RepositoryFormat.
77
        self.assertEqual('unordered', repo._format._fetch_order)
3582.3.1 by Martin Pool
Split pack repository tests into their own file and use scenarios
78
79
    def test_attribute__fetch_uses_deltas(self):
80
        """Packs reuse deltas."""
81
        format = self.get_format()
82
        repo = self.make_repository('.', format=format)
4265.1.4 by John Arbash Meinel
Special case the CHK1 format to allow it to not fetch using deltas.
83
        if isinstance(format.repository_format, RepositoryFormatCHK1):
84
            # TODO: This is currently a workaround. CHK format repositories
85
            #       ignore the 'deltas' flag, but during conversions, we can't
86
            #       do unordered delta fetches. Remove this clause once we
87
            #       improve the inter-format fetching.
88
            self.assertEqual(False, repo._format._fetch_uses_deltas)
89
        else:
90
            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
91
92
    def test_disk_layout(self):
93
        format = self.get_format()
94
        repo = self.make_repository('.', format=format)
95
        # in case of side effects of locking.
96
        repo.lock_write()
97
        repo.unlock()
98
        t = repo.bzrdir.get_repository_transport(None)
99
        self.check_format(t)
100
        # XXX: no locks left when unlocked at the moment
101
        # self.assertEqualDiff('', t.get('lock').read())
102
        self.check_databases(t)
103
104
    def check_format(self, t):
105
        self.assertEqualDiff(
106
            self.format_string, # from scenario
107
            t.get('format').read())
108
109
    def assertHasNoKndx(self, t, knit_name):
110
        """Assert that knit_name has no index on t."""
111
        self.assertFalse(t.has(knit_name + '.kndx'))
112
113
    def assertHasNoKnit(self, t, knit_name):
114
        """Assert that knit_name exists on t."""
115
        # no default content
116
        self.assertFalse(t.has(knit_name + '.knit'))
117
118
    def check_databases(self, t):
119
        """check knit content for a repository."""
120
        # check conversion worked
121
        self.assertHasNoKndx(t, 'inventory')
122
        self.assertHasNoKnit(t, 'inventory')
123
        self.assertHasNoKndx(t, 'revisions')
124
        self.assertHasNoKnit(t, 'revisions')
125
        self.assertHasNoKndx(t, 'signatures')
126
        self.assertHasNoKnit(t, 'signatures')
127
        self.assertFalse(t.has('knits'))
128
        # revision-indexes file-container directory
129
        self.assertEqual([],
3735.1.1 by Robert Collins
Add development2 formats using BTree indices.
130
            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
131
        self.assertTrue(S_ISDIR(t.stat('packs').st_mode))
132
        self.assertTrue(S_ISDIR(t.stat('upload').st_mode))
133
        self.assertTrue(S_ISDIR(t.stat('indices').st_mode))
134
        self.assertTrue(S_ISDIR(t.stat('obsolete_packs').st_mode))
135
136
    def test_shared_disk_layout(self):
137
        format = self.get_format()
138
        repo = self.make_repository('.', shared=True, format=format)
139
        # we want:
140
        t = repo.bzrdir.get_repository_transport(None)
141
        self.check_format(t)
142
        # XXX: no locks left when unlocked at the moment
143
        # self.assertEqualDiff('', t.get('lock').read())
144
        # We should have a 'shared-storage' marker file.
145
        self.assertEqualDiff('', t.get('shared-storage').read())
146
        self.check_databases(t)
147
148
    def test_shared_no_tree_disk_layout(self):
149
        format = self.get_format()
150
        repo = self.make_repository('.', shared=True, format=format)
151
        repo.set_make_working_trees(False)
152
        # we want:
153
        t = repo.bzrdir.get_repository_transport(None)
154
        self.check_format(t)
155
        # XXX: no locks left when unlocked at the moment
156
        # self.assertEqualDiff('', t.get('lock').read())
157
        # We should have a 'shared-storage' marker file.
158
        self.assertEqualDiff('', t.get('shared-storage').read())
159
        # We should have a marker for the no-working-trees flag.
160
        self.assertEqualDiff('', t.get('no-working-trees').read())
161
        # The marker should go when we toggle the setting.
162
        repo.set_make_working_trees(True)
163
        self.assertFalse(t.has('no-working-trees'))
164
        self.check_databases(t)
165
166
    def test_adding_revision_creates_pack_indices(self):
167
        format = self.get_format()
168
        tree = self.make_branch_and_tree('.', format=format)
169
        trans = tree.branch.repository.bzrdir.get_repository_transport(None)
170
        self.assertEqual([],
3735.1.1 by Robert Collins
Add development2 formats using BTree indices.
171
            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
172
        tree.commit('foobarbaz')
3735.1.1 by Robert Collins
Add development2 formats using BTree indices.
173
        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
174
        index_nodes = list(index.iter_all_entries())
175
        self.assertEqual(1, len(index_nodes))
176
        node = index_nodes[0]
177
        name = node[1][0]
178
        # the pack sizes should be listed in the index
179
        pack_value = node[2]
180
        sizes = [int(digits) for digits in pack_value.split(' ')]
181
        for size, suffix in zip(sizes, ['.rix', '.iix', '.tix', '.six']):
182
            stat = trans.stat('indices/%s%s' % (name, suffix))
183
            self.assertEqual(size, stat.st_size)
184
185
    def test_pulling_nothing_leads_to_no_new_names(self):
186
        format = self.get_format()
187
        tree1 = self.make_branch_and_tree('1', format=format)
188
        tree2 = self.make_branch_and_tree('2', format=format)
189
        tree1.branch.repository.fetch(tree2.branch.repository)
190
        trans = tree1.branch.repository.bzrdir.get_repository_transport(None)
191
        self.assertEqual([],
3735.1.1 by Robert Collins
Add development2 formats using BTree indices.
192
            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
193
194
    def test_commit_across_pack_shape_boundary_autopacks(self):
195
        format = self.get_format()
196
        tree = self.make_branch_and_tree('.', format=format)
197
        trans = tree.branch.repository.bzrdir.get_repository_transport(None)
198
        # This test could be a little cheaper by replacing the packs
199
        # attribute on the repository to allow a different pack distribution
200
        # and max packs policy - so we are checking the policy is honoured
201
        # in the test. But for now 11 commits is not a big deal in a single
202
        # test.
203
        for x in range(9):
204
            tree.commit('commit %s' % x)
205
        # there should be 9 packs:
3735.1.1 by Robert Collins
Add development2 formats using BTree indices.
206
        index = self.index_class(trans, 'pack-names', None)
3582.3.1 by Martin Pool
Split pack repository tests into their own file and use scenarios
207
        self.assertEqual(9, len(list(index.iter_all_entries())))
208
        # insert some files in obsolete_packs which should be removed by pack.
209
        trans.put_bytes('obsolete_packs/foo', '123')
210
        trans.put_bytes('obsolete_packs/bar', '321')
211
        # committing one more should coalesce to 1 of 10.
212
        tree.commit('commit triggering pack')
3735.1.1 by Robert Collins
Add development2 formats using BTree indices.
213
        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
214
        self.assertEqual(1, len(list(index.iter_all_entries())))
215
        # packing should not damage data
216
        tree = tree.bzrdir.open_workingtree()
217
        check_result = tree.branch.repository.check(
218
            [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)
219
        nb_files = 5 # .pack, .rix, .iix, .tix, .six
220
        if tree.branch.repository._format.supports_chks:
221
            nb_files += 1 # .cix
222
        # 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
223
        obsolete_files = list(trans.list_dir('obsolete_packs'))
224
        self.assertFalse('foo' in obsolete_files)
225
        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)
226
        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
227
        # XXX: Todo check packs obsoleted correctly - old packs and indices
228
        # in the obsolete_packs directory.
229
        large_pack_name = list(index.iter_all_entries())[0][1][0]
230
        # finally, committing again should not touch the large pack.
231
        tree.commit('commit not triggering pack')
3735.1.1 by Robert Collins
Add development2 formats using BTree indices.
232
        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
233
        self.assertEqual(2, len(list(index.iter_all_entries())))
234
        pack_names = [node[1][0] for node in index.iter_all_entries()]
235
        self.assertTrue(large_pack_name in pack_names)
236
237
    def test_fail_obsolete_deletion(self):
238
        # failing to delete obsolete packs is not fatal
239
        format = self.get_format()
240
        server = fakenfs.FakeNFSServer()
241
        server.setUp()
242
        self.addCleanup(server.tearDown)
243
        transport = get_transport(server.get_url())
244
        bzrdir = self.get_format().initialize_on_transport(transport)
245
        repo = bzrdir.create_repository()
246
        repo_transport = bzrdir.get_repository_transport(None)
247
        self.assertTrue(repo_transport.has('obsolete_packs'))
248
        # these files are in use by another client and typically can't be deleted
249
        repo_transport.put_bytes('obsolete_packs/.nfsblahblah', 'contents')
250
        repo._pack_collection._clear_obsolete_packs()
251
        self.assertTrue(repo_transport.has('obsolete_packs/.nfsblahblah'))
252
253
    def test_pack_after_two_commits_packs_everything(self):
254
        format = self.get_format()
255
        tree = self.make_branch_and_tree('.', format=format)
256
        trans = tree.branch.repository.bzrdir.get_repository_transport(None)
257
        tree.commit('start')
258
        tree.commit('more work')
259
        tree.branch.repository.pack()
260
        # there should be 1 pack:
3735.1.1 by Robert Collins
Add development2 formats using BTree indices.
261
        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
262
        self.assertEqual(1, len(list(index.iter_all_entries())))
263
        self.assertEqual(2, len(tree.branch.repository.all_revision_ids()))
264
265
    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)
266
        # Test that the ordering of revisions in pack repositories is
267
        # tip->ancestor
3582.3.1 by Martin Pool
Split pack repository tests into their own file and use scenarios
268
        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)
269
        if type(format.repository_format) is RepositoryFormatCHK1:
270
            raise TestSkipped("Not updated for GroupCompress internals")
3582.3.1 by Martin Pool
Split pack repository tests into their own file and use scenarios
271
        tree = self.make_branch_and_tree('.', format=format)
272
        trans = tree.branch.repository.bzrdir.get_repository_transport(None)
273
        tree.commit('start', rev_id='1')
274
        tree.commit('more work', rev_id='2')
275
        tree.branch.repository.pack()
276
        tree.lock_read()
277
        self.addCleanup(tree.unlock)
278
        pack = tree.branch.repository._pack_collection.get_pack_by_name(
279
            tree.branch.repository._pack_collection.names()[0])
3943.8.1 by Marius Kruger
remove all trailing whitespace from bzr source
280
        # 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
281
        # disk is a good idea.
282
        for _1, key, val, refs in pack.revision_index.iter_all_entries():
283
            if key == ('1',):
284
                pos_1 = int(val[1:].split()[0])
285
            else:
286
                pos_2 = int(val[1:].split()[0])
287
        self.assertTrue(pos_2 < pos_1)
288
289
    def test_pack_repositories_support_multiple_write_locks(self):
290
        format = self.get_format()
291
        self.make_repository('.', shared=True, format=format)
292
        r1 = repository.Repository.open('.')
293
        r2 = repository.Repository.open('.')
294
        r1.lock_write()
295
        self.addCleanup(r1.unlock)
296
        r2.lock_write()
297
        r2.unlock()
298
299
    def _add_text(self, repo, fileid):
300
        """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)
301
        repo.texts.add_lines((fileid, 'samplerev+'+fileid), [],
302
            ['smaplerev+'+fileid])
3582.3.1 by Martin Pool
Split pack repository tests into their own file and use scenarios
303
304
    def test_concurrent_writers_merge_new_packs(self):
305
        format = self.get_format()
306
        self.make_repository('.', shared=True, format=format)
307
        r1 = repository.Repository.open('.')
308
        r2 = repository.Repository.open('.')
309
        r1.lock_write()
310
        try:
311
            # access enough data to load the names list
312
            list(r1.all_revision_ids())
313
            r2.lock_write()
314
            try:
315
                # access enough data to load the names list
316
                list(r2.all_revision_ids())
317
                r1.start_write_group()
318
                try:
319
                    r2.start_write_group()
320
                    try:
321
                        self._add_text(r1, 'fileidr1')
322
                        self._add_text(r2, 'fileidr2')
323
                    except:
324
                        r2.abort_write_group()
325
                        raise
326
                except:
327
                    r1.abort_write_group()
328
                    raise
329
                # both r1 and r2 have open write groups with data in them
330
                # created while the other's write group was open.
331
                # Commit both which requires a merge to the pack-names.
332
                try:
333
                    r1.commit_write_group()
334
                except:
335
                    r1.abort_write_group()
336
                    r2.abort_write_group()
337
                    raise
338
                r2.commit_write_group()
339
                # tell r1 to reload from disk
340
                r1._pack_collection.reset()
341
                # Now both repositories should know about both names
342
                r1._pack_collection.ensure_loaded()
343
                r2._pack_collection.ensure_loaded()
344
                self.assertEqual(r1._pack_collection.names(), r2._pack_collection.names())
345
                self.assertEqual(2, len(r1._pack_collection.names()))
346
            finally:
347
                r2.unlock()
348
        finally:
349
            r1.unlock()
350
351
    def test_concurrent_writer_second_preserves_dropping_a_pack(self):
352
        format = self.get_format()
353
        self.make_repository('.', shared=True, format=format)
354
        r1 = repository.Repository.open('.')
355
        r2 = repository.Repository.open('.')
356
        # add a pack to drop
357
        r1.lock_write()
358
        try:
359
            r1.start_write_group()
360
            try:
361
                self._add_text(r1, 'fileidr1')
362
            except:
363
                r1.abort_write_group()
364
                raise
365
            else:
366
                r1.commit_write_group()
367
            r1._pack_collection.ensure_loaded()
368
            name_to_drop = r1._pack_collection.all_packs()[0].name
369
        finally:
370
            r1.unlock()
371
        r1.lock_write()
372
        try:
373
            # access enough data to load the names list
374
            list(r1.all_revision_ids())
375
            r2.lock_write()
376
            try:
377
                # access enough data to load the names list
378
                list(r2.all_revision_ids())
379
                r1._pack_collection.ensure_loaded()
380
                try:
381
                    r2.start_write_group()
382
                    try:
383
                        # in r1, drop the pack
384
                        r1._pack_collection._remove_pack_from_memory(
385
                            r1._pack_collection.get_pack_by_name(name_to_drop))
386
                        # in r2, add a pack
387
                        self._add_text(r2, 'fileidr2')
388
                    except:
389
                        r2.abort_write_group()
390
                        raise
391
                except:
392
                    r1._pack_collection.reset()
393
                    raise
394
                # r1 has a changed names list, and r2 an open write groups with
395
                # changes.
396
                # save r1, and then commit the r2 write group, which requires a
397
                # merge to the pack-names, which should not reinstate
398
                # name_to_drop
399
                try:
400
                    r1._pack_collection._save_pack_names()
401
                    r1._pack_collection.reset()
402
                except:
403
                    r2.abort_write_group()
404
                    raise
405
                try:
406
                    r2.commit_write_group()
407
                except:
408
                    r2.abort_write_group()
409
                    raise
410
                # Now both repositories should now about just one name.
411
                r1._pack_collection.ensure_loaded()
412
                r2._pack_collection.ensure_loaded()
413
                self.assertEqual(r1._pack_collection.names(), r2._pack_collection.names())
414
                self.assertEqual(1, len(r1._pack_collection.names()))
415
                self.assertFalse(name_to_drop in r1._pack_collection.names())
416
            finally:
417
                r2.unlock()
418
        finally:
419
            r1.unlock()
420
3789.1.1 by John Arbash Meinel
add the failing acceptance test for the first portion.
421
    def test_concurrent_pack_triggers_reload(self):
422
        # create 2 packs, which we will then collapse
423
        tree = self.make_branch_and_tree('tree')
3789.1.2 by John Arbash Meinel
Add RepositoryPackCollection.reload_pack_names()
424
        tree.lock_write()
3789.1.1 by John Arbash Meinel
add the failing acceptance test for the first portion.
425
        try:
3789.1.2 by John Arbash Meinel
Add RepositoryPackCollection.reload_pack_names()
426
            rev1 = tree.commit('one')
427
            rev2 = tree.commit('two')
428
            r2 = repository.Repository.open('tree')
3789.1.1 by John Arbash Meinel
add the failing acceptance test for the first portion.
429
            r2.lock_read()
430
            try:
431
                # Now r2 has read the pack-names file, but will need to reload
432
                # it after r1 has repacked
3789.1.2 by John Arbash Meinel
Add RepositoryPackCollection.reload_pack_names()
433
                tree.branch.repository.pack()
434
                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.
435
            finally:
436
                r2.unlock()
437
        finally:
3789.1.2 by John Arbash Meinel
Add RepositoryPackCollection.reload_pack_names()
438
            tree.unlock()
3789.1.1 by John Arbash Meinel
add the failing acceptance test for the first portion.
439
3789.2.8 by John Arbash Meinel
Add a test that KnitPackRepository.get_record_stream retries when appropriate.
440
    def test_concurrent_pack_during_get_record_reloads(self):
441
        tree = self.make_branch_and_tree('tree')
442
        tree.lock_write()
443
        try:
444
            rev1 = tree.commit('one')
445
            rev2 = tree.commit('two')
3789.2.14 by John Arbash Meinel
Update AggregateIndex to pass the reload_func into _DirectPackAccess
446
            keys = [(rev1,), (rev2,)]
3789.2.8 by John Arbash Meinel
Add a test that KnitPackRepository.get_record_stream retries when appropriate.
447
            r2 = repository.Repository.open('tree')
448
            r2.lock_read()
449
            try:
450
                # At this point, we will start grabbing a record stream, and
451
                # trigger a repack mid-way
452
                packed = False
453
                result = {}
454
                record_stream = r2.revisions.get_record_stream(keys,
455
                                    'unordered', False)
456
                for record in record_stream:
457
                    result[record.key] = record
458
                    if not packed:
459
                        tree.branch.repository.pack()
460
                        packed = True
461
                # The first record will be found in the original location, but
462
                # 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
463
                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.
464
            finally:
465
                r2.unlock()
466
        finally:
467
            tree.unlock()
468
3582.3.1 by Martin Pool
Split pack repository tests into their own file and use scenarios
469
    def test_lock_write_does_not_physically_lock(self):
470
        repo = self.make_repository('.', format=self.get_format())
471
        repo.lock_write()
472
        self.addCleanup(repo.unlock)
473
        self.assertFalse(repo.get_physical_lock_status())
474
475
    def prepare_for_break_lock(self):
476
        # Setup the global ui factory state so that a break-lock method call
477
        # will find usable input in the input stream.
478
        old_factory = ui.ui_factory
479
        def restoreFactory():
480
            ui.ui_factory = old_factory
481
        self.addCleanup(restoreFactory)
482
        ui.ui_factory = ui.SilentUIFactory()
483
        ui.ui_factory.stdin = StringIO("y\n")
484
485
    def test_break_lock_breaks_physical_lock(self):
486
        repo = self.make_repository('.', format=self.get_format())
487
        repo._pack_collection.lock_names()
3650.4.1 by Aaron Bentley
Fix test kipple in test_break_lock_breaks_physical_lock
488
        repo.control_files.leave_in_place()
489
        repo.unlock()
3582.3.1 by Martin Pool
Split pack repository tests into their own file and use scenarios
490
        repo2 = repository.Repository.open('.')
491
        self.assertTrue(repo.get_physical_lock_status())
492
        self.prepare_for_break_lock()
493
        repo2.break_lock()
494
        self.assertFalse(repo.get_physical_lock_status())
495
496
    def test_broken_physical_locks_error_on__unlock_names_lock(self):
497
        repo = self.make_repository('.', format=self.get_format())
498
        repo._pack_collection.lock_names()
499
        self.assertTrue(repo.get_physical_lock_status())
500
        repo2 = repository.Repository.open('.')
501
        self.prepare_for_break_lock()
502
        repo2.break_lock()
503
        self.assertRaises(errors.LockBroken, repo._pack_collection._unlock_names)
504
505
    def test_fetch_without_find_ghosts_ignores_ghosts(self):
506
        # we want two repositories at this point:
507
        # one with a revision that is a ghost in the other
508
        # repository.
509
        # 'ghost' is present in has_ghost, 'ghost' is absent in 'missing_ghost'.
510
        # 'references' is present in both repositories, and 'tip' is present
511
        # just in has_ghost.
512
        # has_ghost       missing_ghost
513
        #------------------------------
514
        # 'ghost'             -
515
        # 'references'    'references'
516
        # 'tip'               -
517
        # In this test we fetch 'tip' which should not fetch 'ghost'
518
        has_ghost = self.make_repository('has_ghost', format=self.get_format())
519
        missing_ghost = self.make_repository('missing_ghost',
520
            format=self.get_format())
521
522
        def add_commit(repo, revision_id, parent_ids):
523
            repo.lock_write()
524
            repo.start_write_group()
525
            inv = inventory.Inventory(revision_id=revision_id)
526
            inv.root.revision = revision_id
527
            root_id = inv.root.file_id
528
            sha1 = repo.add_inventory(revision_id, inv, [])
529
            repo.texts.add_lines((root_id, revision_id), [], [])
530
            rev = _mod_revision.Revision(timestamp=0,
531
                                         timezone=None,
532
                                         committer="Foo Bar <foo@example.com>",
533
                                         message="Message",
534
                                         inventory_sha1=sha1,
535
                                         revision_id=revision_id)
536
            rev.parent_ids = parent_ids
537
            repo.add_revision(revision_id, rev)
538
            repo.commit_write_group()
539
            repo.unlock()
540
        add_commit(has_ghost, 'ghost', [])
541
        add_commit(has_ghost, 'references', ['ghost'])
542
        add_commit(missing_ghost, 'references', ['ghost'])
543
        add_commit(has_ghost, 'tip', ['references'])
544
        missing_ghost.fetch(has_ghost, 'tip')
545
        # missing ghost now has tip and not ghost.
546
        rev = missing_ghost.get_revision('tip')
547
        inv = missing_ghost.get_inventory('tip')
548
        self.assertRaises(errors.NoSuchRevision,
549
            missing_ghost.get_revision, 'ghost')
550
        self.assertRaises(errors.NoSuchRevision,
551
            missing_ghost.get_inventory, 'ghost')
552
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.
553
    def make_write_ready_repo(self):
554
        repo = self.make_repository('.', format=self.get_format())
555
        repo.lock_write()
556
        repo.start_write_group()
557
        return repo
558
559
    def test_missing_inventories_compression_parent_prevents_commit(self):
560
        repo = self.make_write_ready_repo()
561
        key = ('junk',)
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)
562
        if not getattr(repo.inventories._index, '_missing_compression_parents',
563
            None):
564
            raise TestSkipped("No missing compression parents")
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.
565
        repo.inventories._index._missing_compression_parents.add(key)
566
        self.assertRaises(errors.BzrCheckError, repo.commit_write_group)
567
        self.assertRaises(errors.BzrCheckError, repo.commit_write_group)
568
        repo.abort_write_group()
569
        repo.unlock()
570
571
    def test_missing_revisions_compression_parent_prevents_commit(self):
572
        repo = self.make_write_ready_repo()
573
        key = ('junk',)
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)
574
        if not getattr(repo.inventories._index, '_missing_compression_parents',
575
            None):
576
            raise TestSkipped("No missing compression parents")
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.
577
        repo.revisions._index._missing_compression_parents.add(key)
578
        self.assertRaises(errors.BzrCheckError, repo.commit_write_group)
579
        self.assertRaises(errors.BzrCheckError, repo.commit_write_group)
580
        repo.abort_write_group()
581
        repo.unlock()
582
583
    def test_missing_signatures_compression_parent_prevents_commit(self):
584
        repo = self.make_write_ready_repo()
585
        key = ('junk',)
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)
586
        if not getattr(repo.inventories._index, '_missing_compression_parents',
587
            None):
588
            raise TestSkipped("No missing compression parents")
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.
589
        repo.signatures._index._missing_compression_parents.add(key)
590
        self.assertRaises(errors.BzrCheckError, repo.commit_write_group)
591
        self.assertRaises(errors.BzrCheckError, repo.commit_write_group)
592
        repo.abort_write_group()
593
        repo.unlock()
594
595
    def test_missing_text_compression_parent_prevents_commit(self):
596
        repo = self.make_write_ready_repo()
597
        key = ('some', 'junk')
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)
598
        if not getattr(repo.inventories._index, '_missing_compression_parents',
599
            None):
600
            raise TestSkipped("No missing compression parents")
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.
601
        repo.texts._index._missing_compression_parents.add(key)
602
        self.assertRaises(errors.BzrCheckError, repo.commit_write_group)
603
        e = self.assertRaises(errors.BzrCheckError, repo.commit_write_group)
604
        repo.abort_write_group()
605
        repo.unlock()
606
3582.3.1 by Martin Pool
Split pack repository tests into their own file and use scenarios
607
    def test_supports_external_lookups(self):
608
        repo = self.make_repository('.', format=self.get_format())
609
        self.assertEqual(self.format_supports_external_lookups,
610
            repo._format.supports_external_lookups)
611
3825.4.1 by Andrew Bennetts
Add suppress_errors to abort_write_group.
612
    def test_abort_write_group_does_not_raise_when_suppressed(self):
613
        """Similar to per_repository.test_write_group's test of the same name.
614
615
        Also requires that the exception is logged.
616
        """
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.
617
        self.vfs_transport_factory = memory.MemoryServer
3825.4.1 by Andrew Bennetts
Add suppress_errors to abort_write_group.
618
        repo = self.make_repository('repo')
619
        token = repo.lock_write()
620
        self.addCleanup(repo.unlock)
621
        repo.start_write_group()
622
        # Damage the repository on the filesystem
623
        self.get_transport('').rename('repo', 'foo')
624
        # abort_write_group will not raise an error
625
        self.assertEqual(None, repo.abort_write_group(suppress_errors=True))
626
        # But it does log an error
627
        log_file = self._get_log(keep_log_file=True)
628
        self.assertContainsRe(log_file, 'abort_write_group failed')
629
        self.assertContainsRe(log_file, r'INFO  bzr: ERROR \(ignored\):')
630
        if token is not None:
631
            repo.leave_lock_in_place()
3943.8.1 by Marius Kruger
remove all trailing whitespace from bzr source
632
3825.4.1 by Andrew Bennetts
Add suppress_errors to abort_write_group.
633
    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.
634
        self.vfs_transport_factory = memory.MemoryServer
3825.4.1 by Andrew Bennetts
Add suppress_errors to abort_write_group.
635
        repo = self.make_repository('repo')
636
        token = repo.lock_write()
637
        self.addCleanup(repo.unlock)
638
        repo.start_write_group()
639
        # Damage the repository on the filesystem
640
        self.get_transport('').rename('repo', 'foo')
641
        # abort_write_group will not raise an error
642
        self.assertRaises(Exception, repo.abort_write_group)
643
        if token is not None:
644
            repo.leave_lock_in_place()
3943.8.1 by Marius Kruger
remove all trailing whitespace from bzr source
645
4002.1.1 by Andrew Bennetts
Implement suspend_write_group/resume_write_group.
646
    def test_suspend_write_group(self):
647
        self.vfs_transport_factory = memory.MemoryServer
648
        repo = self.make_repository('repo')
649
        token = repo.lock_write()
650
        self.addCleanup(repo.unlock)
651
        repo.start_write_group()
652
        repo.texts.add_lines(('file-id', 'revid'), (), ['lines'])
653
        wg_tokens = repo.suspend_write_group()
654
        expected_pack_name = wg_tokens[0] + '.pack'
655
        upload_transport = repo._pack_collection._upload_transport
656
        limbo_files = upload_transport.list_dir('')
657
        self.assertTrue(expected_pack_name in limbo_files, limbo_files)
658
        md5 = osutils.md5(upload_transport.get_bytes(expected_pack_name))
659
        self.assertEqual(wg_tokens[0], md5.hexdigest())
660
661
    def test_resume_write_group_then_abort(self):
662
        # Create a repo, start a write group, insert some data, suspend.
663
        self.vfs_transport_factory = memory.MemoryServer
664
        repo = self.make_repository('repo')
665
        token = repo.lock_write()
666
        self.addCleanup(repo.unlock)
667
        repo.start_write_group()
668
        text_key = ('file-id', 'revid')
669
        repo.texts.add_lines(text_key, (), ['lines'])
670
        wg_tokens = repo.suspend_write_group()
671
        # Get a fresh repository object for the repo on the filesystem.
672
        same_repo = repo.bzrdir.open_repository()
673
        # Resume
674
        same_repo.lock_write()
675
        self.addCleanup(same_repo.unlock)
676
        same_repo.resume_write_group(wg_tokens)
677
        same_repo.abort_write_group()
678
        self.assertEqual(
679
            [], same_repo._pack_collection._upload_transport.list_dir(''))
680
        self.assertEqual(
681
            [], same_repo._pack_collection._pack_transport.list_dir(''))
682
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.
683
    def test_resume_malformed_token(self):
684
        self.vfs_transport_factory = memory.MemoryServer
685
        # Make a repository with a suspended write group
686
        repo = self.make_repository('repo')
687
        token = repo.lock_write()
688
        self.addCleanup(repo.unlock)
689
        repo.start_write_group()
690
        text_key = ('file-id', 'revid')
691
        repo.texts.add_lines(text_key, (), ['lines'])
692
        wg_tokens = repo.suspend_write_group()
693
        # Make a new repository
694
        new_repo = self.make_repository('new_repo')
695
        token = new_repo.lock_write()
696
        self.addCleanup(new_repo.unlock)
697
        hacked_wg_token = (
698
            '../../../../repo/.bzr/repository/upload/' + wg_tokens[0])
699
        self.assertRaises(
4002.1.7 by Andrew Bennetts
Rename UnresumableWriteGroups to UnresumableWriteGroup.
700
            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.
701
            new_repo.resume_write_group, [hacked_wg_token])
702
3582.3.1 by Martin Pool
Split pack repository tests into their own file and use scenarios
703
3582.3.3 by Martin Pool
Reenable tests for stacking pack repositories
704
class TestPackRepositoryStacking(TestCaseWithTransport):
705
706
    """Tests for stacking pack repositories"""
707
708
    def setUp(self):
709
        if not self.format_supports_external_lookups:
3943.8.1 by Marius Kruger
remove all trailing whitespace from bzr source
710
            raise TestNotApplicable("%r doesn't support stacking"
3582.3.3 by Martin Pool
Reenable tests for stacking pack repositories
711
                % (self.format_name,))
712
        super(TestPackRepositoryStacking, self).setUp()
713
714
    def get_format(self):
715
        return bzrdir.format_registry.make_bzrdir(self.format_name)
716
3606.10.5 by John Arbash Meinel
Switch out --1.6-rich-root for --1.6.1-rich-root.
717
    def test_stack_checks_rich_root_compatibility(self):
3582.3.3 by Martin Pool
Reenable tests for stacking pack repositories
718
        # early versions of the packing code relied on pack internals to
719
        # stack, but the current version should be able to stack on any
720
        # format.
721
        #
722
        # TODO: Possibly this should be run per-repository-format and raise
723
        # TestNotApplicable on formats that don't support stacking. -- mbp
724
        # 20080729
725
        repo = self.make_repository('repo', format=self.get_format())
726
        if repo.supports_rich_root():
727
            # can only stack on repositories that have compatible internal
728
            # metadata
3606.10.5 by John Arbash Meinel
Switch out --1.6-rich-root for --1.6.1-rich-root.
729
            if getattr(repo._format, 'supports_tree_reference', False):
3735.2.9 by Robert Collins
Get a working chk_map using inventory implementation bootstrapped.
730
                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)
731
                    matching_format_name = 'development6-rich-root'
3735.2.9 by Robert Collins
Get a working chk_map using inventory implementation bootstrapped.
732
                else:
733
                    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.
734
            else:
735
                matching_format_name = 'rich-root-pack'
3582.3.3 by Martin Pool
Reenable tests for stacking pack repositories
736
            mismatching_format_name = 'pack-0.92'
737
        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)
738
            # 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.
739
            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)
740
                raise AssertionError("no non-rich-root CHK formats known")
3735.2.9 by Robert Collins
Get a working chk_map using inventory implementation bootstrapped.
741
            else:
742
                matching_format_name = 'pack-0.92'
3582.3.3 by Martin Pool
Reenable tests for stacking pack repositories
743
            mismatching_format_name = 'pack-0.92-subtree'
744
        base = self.make_repository('base', format=matching_format_name)
745
        repo.add_fallback_repository(base)
746
        # you can't stack on something with incompatible data
747
        bad_repo = self.make_repository('mismatch',
748
            format=mismatching_format_name)
749
        e = self.assertRaises(errors.IncompatibleRepositories,
750
            repo.add_fallback_repository, bad_repo)
751
        self.assertContainsRe(str(e),
752
            r'(?m)KnitPackRepository.*/mismatch/.*\nis not compatible with\n'
3735.2.9 by Robert Collins
Get a working chk_map using inventory implementation bootstrapped.
753
            r'.*Repository.*/repo/.*\n'
3582.3.3 by Martin Pool
Reenable tests for stacking pack repositories
754
            r'different rich-root support')
755
3606.10.5 by John Arbash Meinel
Switch out --1.6-rich-root for --1.6.1-rich-root.
756
    def test_stack_checks_serializers_compatibility(self):
757
        repo = self.make_repository('repo', format=self.get_format())
758
        if getattr(repo._format, 'supports_tree_reference', False):
759
            # can only stack on repositories that have compatible internal
760
            # metadata
3735.2.9 by Robert Collins
Get a working chk_map using inventory implementation bootstrapped.
761
            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)
762
                # No CHK subtree formats in bzr.dev, so this doesn't execute.
763
                matching_format_name = 'development6-subtree'
3735.2.9 by Robert Collins
Get a working chk_map using inventory implementation bootstrapped.
764
            else:
765
                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.
766
            mismatching_format_name = 'rich-root-pack'
767
        else:
768
            if repo.supports_rich_root():
769
                matching_format_name = 'rich-root-pack'
770
                mismatching_format_name = 'pack-0.92-subtree'
771
            else:
772
                raise TestNotApplicable('No formats use non-v5 serializer'
773
                    ' without having rich-root also set')
774
        base = self.make_repository('base', format=matching_format_name)
775
        repo.add_fallback_repository(base)
776
        # you can't stack on something with incompatible data
777
        bad_repo = self.make_repository('mismatch',
778
            format=mismatching_format_name)
779
        e = self.assertRaises(errors.IncompatibleRepositories,
780
            repo.add_fallback_repository, bad_repo)
781
        self.assertContainsRe(str(e),
782
            r'(?m)KnitPackRepository.*/mismatch/.*\nis not compatible with\n'
3735.2.9 by Robert Collins
Get a working chk_map using inventory implementation bootstrapped.
783
            r'.*Repository.*/repo/.*\n'
3606.10.5 by John Arbash Meinel
Switch out --1.6-rich-root for --1.6.1-rich-root.
784
            r'different serializers')
785
3582.3.3 by Martin Pool
Reenable tests for stacking pack repositories
786
    def test_adding_pack_does_not_record_pack_names_from_other_repositories(self):
787
        base = self.make_branch_and_tree('base', format=self.get_format())
788
        base.commit('foo')
789
        referencing = self.make_branch_and_tree('repo', format=self.get_format())
790
        referencing.branch.repository.add_fallback_repository(base.branch.repository)
791
        referencing.commit('bar')
792
        new_instance = referencing.bzrdir.open_repository()
793
        new_instance.lock_read()
794
        self.addCleanup(new_instance.unlock)
795
        new_instance._pack_collection.ensure_loaded()
796
        self.assertEqual(1, len(new_instance._pack_collection.all_packs()))
797
798
    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)
799
        format = self.get_format()
800
        base = self.make_branch_and_tree('base', format=format)
3582.3.3 by Martin Pool
Reenable tests for stacking pack repositories
801
        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)
802
        tree = self.make_branch_and_tree('repo', format=format)
3582.3.3 by Martin Pool
Reenable tests for stacking pack repositories
803
        tree.branch.repository.add_fallback_repository(base.branch.repository)
804
        trans = tree.branch.repository.bzrdir.get_repository_transport(None)
805
        # This test could be a little cheaper by replacing the packs
806
        # attribute on the repository to allow a different pack distribution
807
        # and max packs policy - so we are checking the policy is honoured
808
        # in the test. But for now 11 commits is not a big deal in a single
809
        # test.
810
        for x in range(9):
811
            tree.commit('commit %s' % x)
812
        # there should be 9 packs:
3735.1.1 by Robert Collins
Add development2 formats using BTree indices.
813
        index = self.index_class(trans, 'pack-names', None)
3582.3.3 by Martin Pool
Reenable tests for stacking pack repositories
814
        self.assertEqual(9, len(list(index.iter_all_entries())))
815
        # committing one more should coalesce to 1 of 10.
816
        tree.commit('commit triggering pack')
3735.1.1 by Robert Collins
Add development2 formats using BTree indices.
817
        index = self.index_class(trans, 'pack-names', None)
3582.3.3 by Martin Pool
Reenable tests for stacking pack repositories
818
        self.assertEqual(1, len(list(index.iter_all_entries())))
819
        # packing should not damage data
820
        tree = tree.bzrdir.open_workingtree()
821
        check_result = tree.branch.repository.check(
822
            [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)
823
        nb_files = 5 # .pack, .rix, .iix, .tix, .six
824
        if tree.branch.repository._format.supports_chks:
825
            nb_files += 1 # .cix
826
        # 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
827
        obsolete_files = list(trans.list_dir('obsolete_packs'))
828
        self.assertFalse('foo' in obsolete_files)
829
        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)
830
        self.assertEqual(10 * nb_files, len(obsolete_files))
3582.3.3 by Martin Pool
Reenable tests for stacking pack repositories
831
        # XXX: Todo check packs obsoleted correctly - old packs and indices
832
        # in the obsolete_packs directory.
833
        large_pack_name = list(index.iter_all_entries())[0][1][0]
834
        # finally, committing again should not touch the large pack.
835
        tree.commit('commit not triggering pack')
3735.1.1 by Robert Collins
Add development2 formats using BTree indices.
836
        index = self.index_class(trans, 'pack-names', None)
3582.3.3 by Martin Pool
Reenable tests for stacking pack repositories
837
        self.assertEqual(2, len(list(index.iter_all_entries())))
838
        pack_names = [node[1][0] for node in index.iter_all_entries()]
839
        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
840
841
3801.1.18 by Andrew Bennetts
Add a test that ensures that the autopack RPC is actually used for all pack formats.
842
class TestSmartServerAutopack(TestCaseWithTransport):
843
844
    def setUp(self):
845
        super(TestSmartServerAutopack, self).setUp()
846
        # Create a smart server that publishes whatever the backing VFS server
847
        # does.
848
        self.smart_server = server.SmartTCPServer_for_testing()
849
        self.smart_server.setUp(self.get_server())
850
        self.addCleanup(self.smart_server.tearDown)
851
        # Log all HPSS calls into self.hpss_calls.
852
        client._SmartClient.hooks.install_named_hook(
853
            'call', self.capture_hpss_call, None)
854
        self.hpss_calls = []
855
856
    def capture_hpss_call(self, params):
857
        self.hpss_calls.append(params.method)
858
859
    def get_format(self):
860
        return bzrdir.format_registry.make_bzrdir(self.format_name)
861
4029.2.1 by Robert Collins
Support streaming push to stacked branches.
862
    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.
863
        # Make local and remote repos
3735.2.98 by John Arbash Meinel
Merge bzr.dev 4032. Resolve the new streaming fetch.
864
        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)
865
        tree = self.make_branch_and_tree('local', format=format)
866
        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.
867
        remote_branch_url = self.smart_server.get_url() + 'remote'
868
        remote_branch = bzrdir.BzrDir.open(remote_branch_url).open_branch()
869
        # Make 9 local revisions, and push them one at a time to the remote
870
        # repo to produce 9 pack files.
871
        for x in range(9):
872
            tree.commit('commit %s' % x)
873
            tree.branch.push(remote_branch)
874
        # Make one more push to trigger an autopack
875
        self.hpss_calls = []
876
        tree.commit('commit triggering pack')
877
        tree.branch.push(remote_branch)
4029.2.1 by Robert Collins
Support streaming push to stacked branches.
878
        autopack_calls = len([call for call in self.hpss_calls if call ==
879
            'PackRepository.autopack'])
880
        streaming_calls = len([call for call in self.hpss_calls if call ==
881
            'Repository.insert_stream'])
882
        if autopack_calls:
883
            # Non streaming server
884
            self.assertEqual(1, autopack_calls)
885
            self.assertEqual(0, streaming_calls)
886
        else:
887
            # Streaming was used, which autopacks on the remote end.
888
            self.assertEqual(0, autopack_calls)
889
            # NB: The 2 calls are because of the sanity check that the server
890
            # supports the verb (see remote.py:RemoteSink.insert_stream for
891
            # details).
892
            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.
893
894
4084.5.1 by Robert Collins
Bulk update all test adaptation into a single approach, using multiply_tests rather than test adapters.
895
def load_tests(basic_tests, module, loader):
3582.3.3 by Martin Pool
Reenable tests for stacking pack repositories
896
    # these give the bzrdir canned format name, and the repository on-disk
897
    # format string
3582.3.1 by Martin Pool
Split pack repository tests into their own file and use scenarios
898
    scenarios_params = [
899
         dict(format_name='pack-0.92',
900
              format_string="Bazaar pack repository format 1 (needs bzr 0.92)\n",
3735.1.1 by Robert Collins
Add development2 formats using BTree indices.
901
              format_supports_external_lookups=False,
902
              index_class=GraphIndex),
3582.3.1 by Martin Pool
Split pack repository tests into their own file and use scenarios
903
         dict(format_name='pack-0.92-subtree',
904
              format_string="Bazaar pack repository format 1 "
905
              "with subtree support (needs bzr 0.92)\n",
3735.1.1 by Robert Collins
Add development2 formats using BTree indices.
906
              format_supports_external_lookups=False,
907
              index_class=GraphIndex),
3582.3.2 by Martin Pool
Add 1.6 formats to pack repository tests
908
         dict(format_name='1.6',
909
              format_string="Bazaar RepositoryFormatKnitPack5 (bzr 1.6)\n",
3735.1.1 by Robert Collins
Add development2 formats using BTree indices.
910
              format_supports_external_lookups=True,
911
              index_class=GraphIndex),
3606.10.5 by John Arbash Meinel
Switch out --1.6-rich-root for --1.6.1-rich-root.
912
         dict(format_name='1.6.1-rich-root',
3582.3.2 by Martin Pool
Add 1.6 formats to pack repository tests
913
              format_string="Bazaar RepositoryFormatKnitPack5RichRoot "
3606.10.5 by John Arbash Meinel
Switch out --1.6-rich-root for --1.6.1-rich-root.
914
                  "(bzr 1.6.1)\n",
3735.1.1 by Robert Collins
Add development2 formats using BTree indices.
915
              format_supports_external_lookups=True,
916
              index_class=GraphIndex),
3805.3.1 by John Arbash Meinel
Add repository 1.9 format, and update the documentation.
917
         dict(format_name='1.9',
918
              format_string="Bazaar RepositoryFormatKnitPack6 (bzr 1.9)\n",
919
              format_supports_external_lookups=True,
920
              index_class=BTreeGraphIndex),
921
         dict(format_name='1.9-rich-root',
922
              format_string="Bazaar RepositoryFormatKnitPack6RichRoot "
923
                  "(bzr 1.9)\n",
924
              format_supports_external_lookups=True,
925
              index_class=BTreeGraphIndex),
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)
926
         dict(format_name='development6-rich-root',
927
              format_string='Bazaar development format - group compression '
928
                  'and chk inventory (needs bzr.dev from 1.14)\n',
929
              format_supports_external_lookups=False,
3735.2.40 by Robert Collins
Add development4 which has a parent_id to basename index on CHKInventory objects.
930
              index_class=BTreeGraphIndex),
3582.3.1 by Martin Pool
Split pack repository tests into their own file and use scenarios
931
         ]
932
    # 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.
933
    scenarios = [(s['format_name'], s) for s in scenarios_params]
934
    return tests.multiply_tests(basic_tests, scenarios, loader.suiteClass())