~bzr-pqm/bzr/bzr.dev

« back to all changes in this revision

Viewing changes to bzrlib/tests/test_repository.py

  • Committer: Andrew Bennetts
  • Date: 2010-08-17 06:45:33 UTC
  • mfrom: (5050.17.9 2.2)
  • mto: This revision was merged to the branch mainline in revision 5379.
  • Revision ID: andrew.bennetts@canonical.com-20100817064533-kof2i2f3r6mr4ayb
Merge lp:bzr/2.2 into lp:bzr, including fixes for #192859, #224373, #300062, #585667, #614404, #617503.

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
# Copyright (C) 2006-2011 Canonical Ltd
 
1
# Copyright (C) 2006-2010 Canonical Ltd
2
2
#
3
3
# This program is free software; you can redistribute it and/or modify
4
4
# it under the terms of the GNU General Public License as published by
23
23
"""
24
24
 
25
25
from stat import S_ISDIR
 
26
import sys
26
27
 
27
28
import bzrlib
28
 
from bzrlib.errors import (
29
 
    UnknownFormatError,
30
 
    UnsupportedFormatError,
31
 
    )
 
29
from bzrlib.errors import (NoSuchFile,
 
30
                           UnknownFormatError,
 
31
                           UnsupportedFormatError,
 
32
                           )
32
33
from bzrlib import (
33
 
    btree_index,
34
34
    graph,
35
 
    symbol_versioning,
36
35
    tests,
37
 
    transport,
38
36
    )
39
37
from bzrlib.btree_index import BTreeBuilder, BTreeGraphIndex
40
38
from bzrlib.index import GraphIndex
43
41
    TestCase,
44
42
    TestCaseWithTransport,
45
43
    )
 
44
from bzrlib.transport import (
 
45
    get_transport,
 
46
    )
46
47
from bzrlib import (
47
48
    bzrdir,
48
49
    errors,
52
53
    revision as _mod_revision,
53
54
    upgrade,
54
55
    versionedfile,
55
 
    vf_repository,
56
56
    workingtree,
57
57
    )
58
58
from bzrlib.repofmt import (
59
59
    groupcompress_repo,
60
60
    knitrepo,
61
 
    knitpack_repo,
62
61
    pack_repo,
 
62
    weaverepo,
63
63
    )
64
64
 
65
65
 
68
68
    def test_get_set_default_format(self):
69
69
        old_default = bzrdir.format_registry.get('default')
70
70
        private_default = old_default().repository_format.__class__
71
 
        old_format = repository.format_registry.get_default()
 
71
        old_format = repository.RepositoryFormat.get_default_format()
72
72
        self.assertTrue(isinstance(old_format, private_default))
73
73
        def make_sample_bzrdir():
74
74
            my_bzrdir = bzrdir.BzrDirMetaFormat1()
88
88
            bzrdir.format_registry.remove('default')
89
89
            bzrdir.format_registry.remove('sample')
90
90
            bzrdir.format_registry.register('default', old_default, '')
91
 
        self.assertIsInstance(repository.format_registry.get_default(),
 
91
        self.assertIsInstance(repository.RepositoryFormat.get_default_format(),
92
92
                              old_format.__class__)
93
93
 
94
94
 
116
116
        return "opened repository."
117
117
 
118
118
 
119
 
class SampleExtraRepositoryFormat(repository.RepositoryFormat):
120
 
    """A sample format that can not be used in a metadir
121
 
 
122
 
    """
123
 
 
124
 
    def get_format_string(self):
125
 
        raise NotImplementedError
126
 
 
127
 
 
128
119
class TestRepositoryFormat(TestCaseWithTransport):
129
120
    """Tests for the Repository format detection used by the bzr meta dir facility.BzrBranchFormat facility."""
130
121
 
136
127
        def check_format(format, url):
137
128
            dir = format._matchingbzrdir.initialize(url)
138
129
            format.initialize(dir)
139
 
            t = transport.get_transport(url)
 
130
            t = get_transport(url)
140
131
            found_format = repository.RepositoryFormat.find_format(dir)
141
 
            self.assertIsInstance(found_format, format.__class__)
142
 
        check_format(repository.format_registry.get_default(), "bar")
 
132
            self.failUnless(isinstance(found_format, format.__class__))
 
133
        check_format(weaverepo.RepositoryFormat7(), "bar")
143
134
 
144
135
    def test_find_format_no_repository(self):
145
136
        dir = bzrdir.BzrDirMetaFormat1().initialize(self.get_url())
155
146
                          dir)
156
147
 
157
148
    def test_register_unregister_format(self):
158
 
        # Test deprecated format registration functions
159
149
        format = SampleRepositoryFormat()
160
150
        # make a control dir
161
151
        dir = bzrdir.BzrDirMetaFormat1().initialize(self.get_url())
162
152
        # make a repo
163
153
        format.initialize(dir)
164
154
        # register a format for it.
165
 
        self.applyDeprecated(symbol_versioning.deprecated_in((2, 4, 0)),
166
 
            repository.RepositoryFormat.register_format, format)
 
155
        repository.RepositoryFormat.register_format(format)
167
156
        # which repository.Open will refuse (not supported)
168
 
        self.assertRaises(UnsupportedFormatError, repository.Repository.open,
169
 
            self.get_url())
 
157
        self.assertRaises(UnsupportedFormatError, repository.Repository.open, self.get_url())
170
158
        # but open(unsupported) will work
171
159
        self.assertEqual(format.open(dir), "opened repository.")
172
160
        # unregister the format
173
 
        self.applyDeprecated(symbol_versioning.deprecated_in((2, 4, 0)),
174
 
            repository.RepositoryFormat.unregister_format, format)
175
 
 
176
 
 
177
 
class TestRepositoryFormatRegistry(TestCase):
178
 
 
179
 
    def setUp(self):
180
 
        super(TestRepositoryFormatRegistry, self).setUp()
181
 
        self.registry = repository.RepositoryFormatRegistry()
182
 
 
183
 
    def test_register_unregister_format(self):
184
 
        format = SampleRepositoryFormat()
185
 
        self.registry.register(format)
186
 
        self.assertEquals(format, self.registry.get("Sample .bzr repository format."))
187
 
        self.registry.remove(format)
188
 
        self.assertRaises(KeyError, self.registry.get, "Sample .bzr repository format.")
189
 
 
190
 
    def test_get_all(self):
191
 
        format = SampleRepositoryFormat()
192
 
        self.assertEquals([], self.registry._get_all())
193
 
        self.registry.register(format)
194
 
        self.assertEquals([format], self.registry._get_all())
195
 
 
196
 
    def test_register_extra(self):
197
 
        format = SampleExtraRepositoryFormat()
198
 
        self.assertEquals([], self.registry._get_all())
199
 
        self.registry.register_extra(format)
200
 
        self.assertEquals([format], self.registry._get_all())
201
 
 
202
 
    def test_register_extra_lazy(self):
203
 
        self.assertEquals([], self.registry._get_all())
204
 
        self.registry.register_extra_lazy("bzrlib.tests.test_repository",
205
 
            "SampleExtraRepositoryFormat")
206
 
        formats = self.registry._get_all()
207
 
        self.assertEquals(1, len(formats))
208
 
        self.assertIsInstance(formats[0], SampleExtraRepositoryFormat)
 
161
        repository.RepositoryFormat.unregister_format(format)
 
162
 
 
163
 
 
164
class TestFormat6(TestCaseWithTransport):
 
165
 
 
166
    def test_attribute__fetch_order(self):
 
167
        """Weaves need topological data insertion."""
 
168
        control = bzrdir.BzrDirFormat6().initialize(self.get_url())
 
169
        repo = weaverepo.RepositoryFormat6().initialize(control)
 
170
        self.assertEqual('topological', repo._format._fetch_order)
 
171
 
 
172
    def test_attribute__fetch_uses_deltas(self):
 
173
        """Weaves do not reuse deltas."""
 
174
        control = bzrdir.BzrDirFormat6().initialize(self.get_url())
 
175
        repo = weaverepo.RepositoryFormat6().initialize(control)
 
176
        self.assertEqual(False, repo._format._fetch_uses_deltas)
 
177
 
 
178
    def test_attribute__fetch_reconcile(self):
 
179
        """Weave repositories need a reconcile after fetch."""
 
180
        control = bzrdir.BzrDirFormat6().initialize(self.get_url())
 
181
        repo = weaverepo.RepositoryFormat6().initialize(control)
 
182
        self.assertEqual(True, repo._format._fetch_reconcile)
 
183
 
 
184
    def test_no_ancestry_weave(self):
 
185
        control = bzrdir.BzrDirFormat6().initialize(self.get_url())
 
186
        repo = weaverepo.RepositoryFormat6().initialize(control)
 
187
        # We no longer need to create the ancestry.weave file
 
188
        # since it is *never* used.
 
189
        self.assertRaises(NoSuchFile,
 
190
                          control.transport.get,
 
191
                          'ancestry.weave')
 
192
 
 
193
    def test_supports_external_lookups(self):
 
194
        control = bzrdir.BzrDirFormat6().initialize(self.get_url())
 
195
        repo = weaverepo.RepositoryFormat6().initialize(control)
 
196
        self.assertFalse(repo._format.supports_external_lookups)
 
197
 
 
198
 
 
199
class TestFormat7(TestCaseWithTransport):
 
200
 
 
201
    def test_attribute__fetch_order(self):
 
202
        """Weaves need topological data insertion."""
 
203
        control = bzrdir.BzrDirMetaFormat1().initialize(self.get_url())
 
204
        repo = weaverepo.RepositoryFormat7().initialize(control)
 
205
        self.assertEqual('topological', repo._format._fetch_order)
 
206
 
 
207
    def test_attribute__fetch_uses_deltas(self):
 
208
        """Weaves do not reuse deltas."""
 
209
        control = bzrdir.BzrDirMetaFormat1().initialize(self.get_url())
 
210
        repo = weaverepo.RepositoryFormat7().initialize(control)
 
211
        self.assertEqual(False, repo._format._fetch_uses_deltas)
 
212
 
 
213
    def test_attribute__fetch_reconcile(self):
 
214
        """Weave repositories need a reconcile after fetch."""
 
215
        control = bzrdir.BzrDirMetaFormat1().initialize(self.get_url())
 
216
        repo = weaverepo.RepositoryFormat7().initialize(control)
 
217
        self.assertEqual(True, repo._format._fetch_reconcile)
 
218
 
 
219
    def test_disk_layout(self):
 
220
        control = bzrdir.BzrDirMetaFormat1().initialize(self.get_url())
 
221
        repo = weaverepo.RepositoryFormat7().initialize(control)
 
222
        # in case of side effects of locking.
 
223
        repo.lock_write()
 
224
        repo.unlock()
 
225
        # we want:
 
226
        # format 'Bazaar-NG Repository format 7'
 
227
        # lock ''
 
228
        # inventory.weave == empty_weave
 
229
        # empty revision-store directory
 
230
        # empty weaves directory
 
231
        t = control.get_repository_transport(None)
 
232
        self.assertEqualDiff('Bazaar-NG Repository format 7',
 
233
                             t.get('format').read())
 
234
        self.assertTrue(S_ISDIR(t.stat('revision-store').st_mode))
 
235
        self.assertTrue(S_ISDIR(t.stat('weaves').st_mode))
 
236
        self.assertEqualDiff('# bzr weave file v5\n'
 
237
                             'w\n'
 
238
                             'W\n',
 
239
                             t.get('inventory.weave').read())
 
240
        # Creating a file with id Foo:Bar results in a non-escaped file name on
 
241
        # disk.
 
242
        control.create_branch()
 
243
        tree = control.create_workingtree()
 
244
        tree.add(['foo'], ['Foo:Bar'], ['file'])
 
245
        tree.put_file_bytes_non_atomic('Foo:Bar', 'content\n')
 
246
        try:
 
247
            tree.commit('first post', rev_id='first')
 
248
        except errors.IllegalPath:
 
249
            if sys.platform != 'win32':
 
250
                raise
 
251
            self.knownFailure('Foo:Bar cannot be used as a file-id on windows'
 
252
                              ' in repo format 7')
 
253
            return
 
254
        self.assertEqualDiff(
 
255
            '# bzr weave file v5\n'
 
256
            'i\n'
 
257
            '1 7fe70820e08a1aac0ef224d9c66ab66831cc4ab1\n'
 
258
            'n first\n'
 
259
            '\n'
 
260
            'w\n'
 
261
            '{ 0\n'
 
262
            '. content\n'
 
263
            '}\n'
 
264
            'W\n',
 
265
            t.get('weaves/74/Foo%3ABar.weave').read())
 
266
 
 
267
    def test_shared_disk_layout(self):
 
268
        control = bzrdir.BzrDirMetaFormat1().initialize(self.get_url())
 
269
        repo = weaverepo.RepositoryFormat7().initialize(control, shared=True)
 
270
        # we want:
 
271
        # format 'Bazaar-NG Repository format 7'
 
272
        # inventory.weave == empty_weave
 
273
        # empty revision-store directory
 
274
        # empty weaves directory
 
275
        # a 'shared-storage' marker file.
 
276
        # lock is not present when unlocked
 
277
        t = control.get_repository_transport(None)
 
278
        self.assertEqualDiff('Bazaar-NG Repository format 7',
 
279
                             t.get('format').read())
 
280
        self.assertEqualDiff('', t.get('shared-storage').read())
 
281
        self.assertTrue(S_ISDIR(t.stat('revision-store').st_mode))
 
282
        self.assertTrue(S_ISDIR(t.stat('weaves').st_mode))
 
283
        self.assertEqualDiff('# bzr weave file v5\n'
 
284
                             'w\n'
 
285
                             'W\n',
 
286
                             t.get('inventory.weave').read())
 
287
        self.assertFalse(t.has('branch-lock'))
 
288
 
 
289
    def test_creates_lockdir(self):
 
290
        """Make sure it appears to be controlled by a LockDir existence"""
 
291
        control = bzrdir.BzrDirMetaFormat1().initialize(self.get_url())
 
292
        repo = weaverepo.RepositoryFormat7().initialize(control, shared=True)
 
293
        t = control.get_repository_transport(None)
 
294
        # TODO: Should check there is a 'lock' toplevel directory,
 
295
        # regardless of contents
 
296
        self.assertFalse(t.has('lock/held/info'))
 
297
        repo.lock_write()
 
298
        try:
 
299
            self.assertTrue(t.has('lock/held/info'))
 
300
        finally:
 
301
            # unlock so we don't get a warning about failing to do so
 
302
            repo.unlock()
 
303
 
 
304
    def test_uses_lockdir(self):
 
305
        """repo format 7 actually locks on lockdir"""
 
306
        base_url = self.get_url()
 
307
        control = bzrdir.BzrDirMetaFormat1().initialize(base_url)
 
308
        repo = weaverepo.RepositoryFormat7().initialize(control, shared=True)
 
309
        t = control.get_repository_transport(None)
 
310
        repo.lock_write()
 
311
        repo.unlock()
 
312
        del repo
 
313
        # make sure the same lock is created by opening it
 
314
        repo = repository.Repository.open(base_url)
 
315
        repo.lock_write()
 
316
        self.assertTrue(t.has('lock/held/info'))
 
317
        repo.unlock()
 
318
        self.assertFalse(t.has('lock/held/info'))
 
319
 
 
320
    def test_shared_no_tree_disk_layout(self):
 
321
        control = bzrdir.BzrDirMetaFormat1().initialize(self.get_url())
 
322
        repo = weaverepo.RepositoryFormat7().initialize(control, shared=True)
 
323
        repo.set_make_working_trees(False)
 
324
        # we want:
 
325
        # format 'Bazaar-NG Repository format 7'
 
326
        # lock ''
 
327
        # inventory.weave == empty_weave
 
328
        # empty revision-store directory
 
329
        # empty weaves directory
 
330
        # a 'shared-storage' marker file.
 
331
        t = control.get_repository_transport(None)
 
332
        self.assertEqualDiff('Bazaar-NG Repository format 7',
 
333
                             t.get('format').read())
 
334
        ## self.assertEqualDiff('', t.get('lock').read())
 
335
        self.assertEqualDiff('', t.get('shared-storage').read())
 
336
        self.assertEqualDiff('', t.get('no-working-trees').read())
 
337
        repo.set_make_working_trees(True)
 
338
        self.assertFalse(t.has('no-working-trees'))
 
339
        self.assertTrue(S_ISDIR(t.stat('revision-store').st_mode))
 
340
        self.assertTrue(S_ISDIR(t.stat('weaves').st_mode))
 
341
        self.assertEqualDiff('# bzr weave file v5\n'
 
342
                             'w\n'
 
343
                             'W\n',
 
344
                             t.get('inventory.weave').read())
 
345
 
 
346
    def test_supports_external_lookups(self):
 
347
        control = bzrdir.BzrDirMetaFormat1().initialize(self.get_url())
 
348
        repo = weaverepo.RepositoryFormat7().initialize(control)
 
349
        self.assertFalse(repo._format.supports_external_lookups)
209
350
 
210
351
 
211
352
class TestFormatKnit1(TestCaseWithTransport):
379
520
        # classes do not barf inappropriately when a surprising repository type
380
521
        # is handed to them.
381
522
        dummy_a = DummyRepository()
382
 
        dummy_a._format = RepositoryFormat()
383
 
        dummy_a._format.supports_full_versioned_files = True
384
523
        dummy_b = DummyRepository()
385
 
        dummy_b._format = RepositoryFormat()
386
 
        dummy_b._format.supports_full_versioned_files = True
387
524
        self.assertGetsDefaultInterRepository(dummy_a, dummy_b)
388
525
 
389
526
    def assertGetsDefaultInterRepository(self, repo_a, repo_b):
393
530
        no actual sane default in the presence of incompatible data models.
394
531
        """
395
532
        inter_repo = repository.InterRepository.get(repo_a, repo_b)
396
 
        self.assertEqual(vf_repository.InterSameDataRepository,
 
533
        self.assertEqual(repository.InterSameDataRepository,
397
534
                         inter_repo.__class__)
398
535
        self.assertEqual(repo_a, inter_repo.source)
399
536
        self.assertEqual(repo_b, inter_repo.target)
413
550
        dummy_a._serializer = repo._serializer
414
551
        dummy_a._format.supports_tree_reference = repo._format.supports_tree_reference
415
552
        dummy_a._format.rich_root_data = repo._format.rich_root_data
416
 
        dummy_a._format.supports_full_versioned_files = repo._format.supports_full_versioned_files
417
553
        dummy_b._serializer = repo._serializer
418
554
        dummy_b._format.supports_tree_reference = repo._format.supports_tree_reference
419
555
        dummy_b._format.rich_root_data = repo._format.rich_root_data
420
 
        dummy_b._format.supports_full_versioned_files = repo._format.supports_full_versioned_files
421
556
        repository.InterRepository.register_optimiser(InterDummy)
422
557
        try:
423
558
            # we should get the default for something InterDummy returns False
436
571
        self.assertGetsDefaultInterRepository(dummy_a, dummy_b)
437
572
 
438
573
 
439
 
class TestRepositoryFormat1(knitrepo.RepositoryFormatKnit1):
440
 
 
441
 
    def get_format_string(self):
442
 
        return "Test Format 1"
443
 
 
444
 
 
445
 
class TestRepositoryFormat2(knitrepo.RepositoryFormatKnit1):
446
 
 
447
 
    def get_format_string(self):
448
 
        return "Test Format 2"
 
574
class TestInterWeaveRepo(TestCaseWithTransport):
 
575
 
 
576
    def test_is_compatible_and_registered(self):
 
577
        # InterWeaveRepo is compatible when either side
 
578
        # is a format 5/6/7 branch
 
579
        from bzrlib.repofmt import knitrepo, weaverepo
 
580
        formats = [weaverepo.RepositoryFormat5(),
 
581
                   weaverepo.RepositoryFormat6(),
 
582
                   weaverepo.RepositoryFormat7()]
 
583
        incompatible_formats = [weaverepo.RepositoryFormat4(),
 
584
                                knitrepo.RepositoryFormatKnit1(),
 
585
                                ]
 
586
        repo_a = self.make_repository('a')
 
587
        repo_b = self.make_repository('b')
 
588
        is_compatible = repository.InterWeaveRepo.is_compatible
 
589
        for source in incompatible_formats:
 
590
            # force incompatible left then right
 
591
            repo_a._format = source
 
592
            repo_b._format = formats[0]
 
593
            self.assertFalse(is_compatible(repo_a, repo_b))
 
594
            self.assertFalse(is_compatible(repo_b, repo_a))
 
595
        for source in formats:
 
596
            repo_a._format = source
 
597
            for target in formats:
 
598
                repo_b._format = target
 
599
                self.assertTrue(is_compatible(repo_a, repo_b))
 
600
        self.assertEqual(repository.InterWeaveRepo,
 
601
                         repository.InterRepository.get(repo_a,
 
602
                                                        repo_b).__class__)
449
603
 
450
604
 
451
605
class TestRepositoryConverter(TestCaseWithTransport):
452
606
 
453
607
    def test_convert_empty(self):
454
 
        source_format = TestRepositoryFormat1()
455
 
        target_format = TestRepositoryFormat2()
456
 
        repository.format_registry.register(source_format)
457
 
        self.addCleanup(repository.format_registry.remove,
458
 
            source_format)
459
 
        repository.format_registry.register(target_format)
460
 
        self.addCleanup(repository.format_registry.remove,
461
 
            target_format)
462
 
        t = self.get_transport()
 
608
        t = get_transport(self.get_url('.'))
463
609
        t.mkdir('repository')
464
610
        repo_dir = bzrdir.BzrDirMetaFormat1().initialize('repository')
465
 
        repo = TestRepositoryFormat1().initialize(repo_dir)
 
611
        repo = weaverepo.RepositoryFormat7().initialize(repo_dir)
 
612
        target_format = knitrepo.RepositoryFormatKnit1()
466
613
        converter = repository.CopyConverter(target_format)
467
614
        pb = bzrlib.ui.ui_factory.nested_progress_bar()
468
615
        try:
473
620
        self.assertTrue(isinstance(target_format, repo._format.__class__))
474
621
 
475
622
 
 
623
class TestMisc(TestCase):
 
624
 
 
625
    def test_unescape_xml(self):
 
626
        """We get some kind of error when malformed entities are passed"""
 
627
        self.assertRaises(KeyError, repository._unescape_xml, 'foo&bar;')
 
628
 
 
629
 
476
630
class TestRepositoryFormatKnit3(TestCaseWithTransport):
477
631
 
478
632
    def test_attribute__fetch_order(self):
527
681
 
528
682
class Test2a(tests.TestCaseWithMemoryTransport):
529
683
 
530
 
    def test_chk_bytes_uses_custom_btree_parser(self):
531
 
        mt = self.make_branch_and_memory_tree('test', format='2a')
532
 
        mt.lock_write()
533
 
        self.addCleanup(mt.unlock)
534
 
        mt.add([''], ['root-id'])
535
 
        mt.commit('first')
536
 
        index = mt.branch.repository.chk_bytes._index._graph_index._indices[0]
537
 
        self.assertEqual(btree_index._gcchk_factory, index._leaf_factory)
538
 
        # It should also work if we re-open the repo
539
 
        repo = mt.branch.repository.bzrdir.open_repository()
540
 
        repo.lock_read()
541
 
        self.addCleanup(repo.unlock)
542
 
        index = repo.chk_bytes._index._graph_index._indices[0]
543
 
        self.assertEqual(btree_index._gcchk_factory, index._leaf_factory)
544
 
 
545
684
    def test_fetch_combines_groups(self):
546
685
        builder = self.make_branch_builder('source', format='2a')
547
686
        builder.start_series()
673
812
        target = self.make_repository('target', format='rich-root-pack')
674
813
        stream = source._get_source(target._format)
675
814
        # We don't want the child GroupCHKStreamSource
676
 
        self.assertIs(type(stream), vf_repository.StreamSource)
 
815
        self.assertIs(type(stream), repository.StreamSource)
677
816
 
678
817
    def test_get_stream_for_missing_keys_includes_all_chk_refs(self):
679
818
        source_builder = self.make_branch_builder('source',
755
894
        source = self.make_repository('source', format='pack-0.92')
756
895
        target = self.make_repository('target', format='pack-0.92')
757
896
        stream_source = source._get_source(target._format)
758
 
        self.assertIsInstance(stream_source, knitpack_repo.KnitPackStreamSource)
 
897
        self.assertIsInstance(stream_source, pack_repo.KnitPackStreamSource)
759
898
 
760
899
    def test_source_to_exact_pack_rich_root_pack(self):
761
900
        source = self.make_repository('source', format='rich-root-pack')
762
901
        target = self.make_repository('target', format='rich-root-pack')
763
902
        stream_source = source._get_source(target._format)
764
 
        self.assertIsInstance(stream_source, knitpack_repo.KnitPackStreamSource)
 
903
        self.assertIsInstance(stream_source, pack_repo.KnitPackStreamSource)
765
904
 
766
905
    def test_source_to_exact_pack_19(self):
767
906
        source = self.make_repository('source', format='1.9')
768
907
        target = self.make_repository('target', format='1.9')
769
908
        stream_source = source._get_source(target._format)
770
 
        self.assertIsInstance(stream_source, knitpack_repo.KnitPackStreamSource)
 
909
        self.assertIsInstance(stream_source, pack_repo.KnitPackStreamSource)
771
910
 
772
911
    def test_source_to_exact_pack_19_rich_root(self):
773
912
        source = self.make_repository('source', format='1.9-rich-root')
774
913
        target = self.make_repository('target', format='1.9-rich-root')
775
914
        stream_source = source._get_source(target._format)
776
 
        self.assertIsInstance(stream_source, knitpack_repo.KnitPackStreamSource)
 
915
        self.assertIsInstance(stream_source, pack_repo.KnitPackStreamSource)
777
916
 
778
917
    def test_source_to_remote_exact_pack_19(self):
779
918
        trans = self.make_smart_server('target')
782
921
        target = self.make_repository('target', format='1.9')
783
922
        target = repository.Repository.open(trans.base)
784
923
        stream_source = source._get_source(target._format)
785
 
        self.assertIsInstance(stream_source, knitpack_repo.KnitPackStreamSource)
 
924
        self.assertIsInstance(stream_source, pack_repo.KnitPackStreamSource)
786
925
 
787
926
    def test_stream_source_to_non_exact(self):
788
927
        source = self.make_repository('source', format='pack-0.92')
789
928
        target = self.make_repository('target', format='1.9')
790
929
        stream = source._get_source(target._format)
791
 
        self.assertIs(type(stream), vf_repository.StreamSource)
 
930
        self.assertIs(type(stream), repository.StreamSource)
792
931
 
793
932
    def test_stream_source_to_non_exact_rich_root(self):
794
933
        source = self.make_repository('source', format='1.9')
795
934
        target = self.make_repository('target', format='1.9-rich-root')
796
935
        stream = source._get_source(target._format)
797
 
        self.assertIs(type(stream), vf_repository.StreamSource)
 
936
        self.assertIs(type(stream), repository.StreamSource)
798
937
 
799
938
    def test_source_to_remote_non_exact_pack_19(self):
800
939
        trans = self.make_smart_server('target')
803
942
        target = self.make_repository('target', format='1.6')
804
943
        target = repository.Repository.open(trans.base)
805
944
        stream_source = source._get_source(target._format)
806
 
        self.assertIs(type(stream_source), vf_repository.StreamSource)
 
945
        self.assertIs(type(stream_source), repository.StreamSource)
807
946
 
808
947
    def test_stream_source_to_knit(self):
809
948
        source = self.make_repository('source', format='pack-0.92')
810
949
        target = self.make_repository('target', format='dirstate')
811
950
        stream = source._get_source(target._format)
812
 
        self.assertIs(type(stream), vf_repository.StreamSource)
 
951
        self.assertIs(type(stream), repository.StreamSource)
813
952
 
814
953
 
815
954
class TestDevelopment6FindParentIdsOfRevisions(TestCaseWithTransport):
817
956
 
818
957
    def setUp(self):
819
958
        super(TestDevelopment6FindParentIdsOfRevisions, self).setUp()
820
 
        self.builder = self.make_branch_builder('source')
 
959
        self.builder = self.make_branch_builder('source',
 
960
            format='development6-rich-root')
821
961
        self.builder.start_series()
822
962
        self.builder.build_snapshot('initial', None,
823
963
            [('add', ('', 'tree-root', 'directory', None))])
1451
1591
        # Because of how they were built, they correspond to
1452
1592
        # ['D', 'C', 'B', 'A']
1453
1593
        packs = b.repository._pack_collection.packs
1454
 
        packer = knitpack_repo.KnitPacker(b.repository._pack_collection,
 
1594
        packer = pack_repo.Packer(b.repository._pack_collection,
1455
1595
                                  packs, 'testing',
1456
1596
                                  revision_ids=['B', 'C'])
1457
1597
        # Now, when we are copying the B & C revisions, their pack files should
1471
1611
        return repo._pack_collection
1472
1612
 
1473
1613
    def test_open_pack_will_optimise(self):
1474
 
        packer = knitpack_repo.OptimisingKnitPacker(self.get_pack_collection(),
 
1614
        packer = pack_repo.OptimisingPacker(self.get_pack_collection(),
1475
1615
                                            [], '.test')
1476
1616
        new_pack = packer.open_pack()
1477
1617
        self.addCleanup(new_pack.abort) # ensure cleanup
1482
1622
        self.assertTrue(new_pack.signature_index._optimize_for_size)
1483
1623
 
1484
1624
 
1485
 
class TestGCCHKPacker(TestCaseWithTransport):
1486
 
 
1487
 
    def make_abc_branch(self):
1488
 
        builder = self.make_branch_builder('source')
1489
 
        builder.start_series()
1490
 
        builder.build_snapshot('A', None, [
1491
 
            ('add', ('', 'root-id', 'directory', None)),
1492
 
            ('add', ('file', 'file-id', 'file', 'content\n')),
1493
 
            ])
1494
 
        builder.build_snapshot('B', ['A'], [
1495
 
            ('add', ('dir', 'dir-id', 'directory', None))])
1496
 
        builder.build_snapshot('C', ['B'], [
1497
 
            ('modify', ('file-id', 'new content\n'))])
1498
 
        builder.finish_series()
1499
 
        return builder.get_branch()
1500
 
 
1501
 
    def make_branch_with_disjoint_inventory_and_revision(self):
1502
 
        """a repo with separate packs for a revisions Revision and Inventory.
1503
 
 
1504
 
        There will be one pack file that holds the Revision content, and one
1505
 
        for the Inventory content.
1506
 
 
1507
 
        :return: (repository,
1508
 
                  pack_name_with_rev_A_Revision,
1509
 
                  pack_name_with_rev_A_Inventory,
1510
 
                  pack_name_with_rev_C_content)
1511
 
        """
1512
 
        b_source = self.make_abc_branch()
1513
 
        b_base = b_source.bzrdir.sprout('base', revision_id='A').open_branch()
1514
 
        b_stacked = b_base.bzrdir.sprout('stacked', stacked=True).open_branch()
1515
 
        b_stacked.lock_write()
1516
 
        self.addCleanup(b_stacked.unlock)
1517
 
        b_stacked.fetch(b_source, 'B')
1518
 
        # Now re-open the stacked repo directly (no fallbacks) so that we can
1519
 
        # fill in the A rev.
1520
 
        repo_not_stacked = b_stacked.bzrdir.open_repository()
1521
 
        repo_not_stacked.lock_write()
1522
 
        self.addCleanup(repo_not_stacked.unlock)
1523
 
        # Now we should have a pack file with A's inventory, but not its
1524
 
        # Revision
1525
 
        self.assertEqual([('A',), ('B',)],
1526
 
                         sorted(repo_not_stacked.inventories.keys()))
1527
 
        self.assertEqual([('B',)],
1528
 
                         sorted(repo_not_stacked.revisions.keys()))
1529
 
        stacked_pack_names = repo_not_stacked._pack_collection.names()
1530
 
        # We have a couple names here, figure out which has A's inventory
1531
 
        for name in stacked_pack_names:
1532
 
            pack = repo_not_stacked._pack_collection.get_pack_by_name(name)
1533
 
            keys = [n[1] for n in pack.inventory_index.iter_all_entries()]
1534
 
            if ('A',) in keys:
1535
 
                inv_a_pack_name = name
1536
 
                break
1537
 
        else:
1538
 
            self.fail('Could not find pack containing A\'s inventory')
1539
 
        repo_not_stacked.fetch(b_source.repository, 'A')
1540
 
        self.assertEqual([('A',), ('B',)],
1541
 
                         sorted(repo_not_stacked.revisions.keys()))
1542
 
        new_pack_names = set(repo_not_stacked._pack_collection.names())
1543
 
        rev_a_pack_names = new_pack_names.difference(stacked_pack_names)
1544
 
        self.assertEqual(1, len(rev_a_pack_names))
1545
 
        rev_a_pack_name = list(rev_a_pack_names)[0]
1546
 
        # Now fetch 'C', so we have a couple pack files to join
1547
 
        repo_not_stacked.fetch(b_source.repository, 'C')
1548
 
        rev_c_pack_names = set(repo_not_stacked._pack_collection.names())
1549
 
        rev_c_pack_names = rev_c_pack_names.difference(new_pack_names)
1550
 
        self.assertEqual(1, len(rev_c_pack_names))
1551
 
        rev_c_pack_name = list(rev_c_pack_names)[0]
1552
 
        return (repo_not_stacked, rev_a_pack_name, inv_a_pack_name,
1553
 
                rev_c_pack_name)
1554
 
 
1555
 
    def test_pack_with_distant_inventories(self):
1556
 
        # See https://bugs.launchpad.net/bzr/+bug/437003
1557
 
        # When repacking, it is possible to have an inventory in a different
1558
 
        # pack file than the associated revision. An autopack can then come
1559
 
        # along, and miss that inventory, and complain.
1560
 
        (repo, rev_a_pack_name, inv_a_pack_name, rev_c_pack_name
1561
 
         ) = self.make_branch_with_disjoint_inventory_and_revision()
1562
 
        a_pack = repo._pack_collection.get_pack_by_name(rev_a_pack_name)
1563
 
        c_pack = repo._pack_collection.get_pack_by_name(rev_c_pack_name)
1564
 
        packer = groupcompress_repo.GCCHKPacker(repo._pack_collection,
1565
 
                    [a_pack, c_pack], '.test-pack')
1566
 
        # This would raise ValueError in bug #437003, but should not raise an
1567
 
        # error once fixed.
1568
 
        packer.pack()
1569
 
 
1570
 
    def test_pack_with_missing_inventory(self):
1571
 
        # Similar to test_pack_with_missing_inventory, but this time, we force
1572
 
        # the A inventory to actually be gone from the repository.
1573
 
        (repo, rev_a_pack_name, inv_a_pack_name, rev_c_pack_name
1574
 
         ) = self.make_branch_with_disjoint_inventory_and_revision()
1575
 
        inv_a_pack = repo._pack_collection.get_pack_by_name(inv_a_pack_name)
1576
 
        repo._pack_collection._remove_pack_from_memory(inv_a_pack)
1577
 
        packer = groupcompress_repo.GCCHKPacker(repo._pack_collection,
1578
 
            repo._pack_collection.all_packs(), '.test-pack')
1579
 
        e = self.assertRaises(ValueError, packer.pack)
1580
 
        packer.new_pack.abort()
1581
 
        self.assertContainsRe(str(e),
1582
 
            r"We are missing inventories for revisions: .*'A'")
1583
 
 
1584
 
 
1585
1625
class TestCrossFormatPacks(TestCaseWithTransport):
1586
1626
 
1587
1627
    def log_pack(self, hint=None):
1602
1642
        self.addCleanup(target.unlock)
1603
1643
        source = source_tree.branch.repository._get_source(target._format)
1604
1644
        self.orig_pack = target.pack
1605
 
        self.overrideAttr(target, "pack", self.log_pack)
 
1645
        target.pack = self.log_pack
1606
1646
        search = target.search_missing_revision_ids(
1607
 
            source_tree.branch.repository, revision_ids=[tip])
 
1647
            source_tree.branch.repository, tip)
1608
1648
        stream = source.get_stream(search)
1609
1649
        from_format = source_tree.branch.repository._format
1610
1650
        sink = target._get_sink()
1626
1666
        self.addCleanup(target.unlock)
1627
1667
        source = source_tree.branch.repository
1628
1668
        self.orig_pack = target.pack
1629
 
        self.overrideAttr(target, "pack", self.log_pack)
 
1669
        target.pack = self.log_pack
1630
1670
        target.fetch(source)
1631
1671
        if expect_pack_called:
1632
1672
            self.assertLength(1, self.calls)