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