~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-11-22 03:35:24 UTC
  • mto: This revision was merged to the branch mainline in revision 5547.
  • Revision ID: andrew.bennetts@canonical.com-20101122033524-ouxj0onm3gtkimx3
Remove RepositoryFormatCHK1 and RepositoryFormatCHK2.

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
34
    btree_index,
34
35
    graph,
35
 
    symbol_versioning,
36
36
    tests,
37
 
    transport,
38
37
    )
39
38
from bzrlib.btree_index import BTreeBuilder, BTreeGraphIndex
40
39
from bzrlib.index import GraphIndex
43
42
    TestCase,
44
43
    TestCaseWithTransport,
45
44
    )
 
45
from bzrlib.transport import (
 
46
    get_transport,
 
47
    )
46
48
from bzrlib import (
47
49
    bzrdir,
48
50
    errors,
52
54
    revision as _mod_revision,
53
55
    upgrade,
54
56
    versionedfile,
55
 
    vf_repository,
56
57
    workingtree,
57
58
    )
58
59
from bzrlib.repofmt import (
59
60
    groupcompress_repo,
60
61
    knitrepo,
61
 
    knitpack_repo,
62
62
    pack_repo,
 
63
    weaverepo,
63
64
    )
64
65
 
65
66
 
68
69
    def test_get_set_default_format(self):
69
70
        old_default = bzrdir.format_registry.get('default')
70
71
        private_default = old_default().repository_format.__class__
71
 
        old_format = repository.format_registry.get_default()
 
72
        old_format = repository.RepositoryFormat.get_default_format()
72
73
        self.assertTrue(isinstance(old_format, private_default))
73
74
        def make_sample_bzrdir():
74
75
            my_bzrdir = bzrdir.BzrDirMetaFormat1()
88
89
            bzrdir.format_registry.remove('default')
89
90
            bzrdir.format_registry.remove('sample')
90
91
            bzrdir.format_registry.register('default', old_default, '')
91
 
        self.assertIsInstance(repository.format_registry.get_default(),
 
92
        self.assertIsInstance(repository.RepositoryFormat.get_default_format(),
92
93
                              old_format.__class__)
93
94
 
94
95
 
116
117
        return "opened repository."
117
118
 
118
119
 
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
120
class TestRepositoryFormat(TestCaseWithTransport):
129
121
    """Tests for the Repository format detection used by the bzr meta dir facility.BzrBranchFormat facility."""
130
122
 
136
128
        def check_format(format, url):
137
129
            dir = format._matchingbzrdir.initialize(url)
138
130
            format.initialize(dir)
139
 
            t = transport.get_transport_from_path(url)
 
131
            t = get_transport(url)
140
132
            found_format = repository.RepositoryFormat.find_format(dir)
141
 
            self.assertIsInstance(found_format, format.__class__)
142
 
        check_format(repository.format_registry.get_default(), "bar")
 
133
            self.failUnless(isinstance(found_format, format.__class__))
 
134
        check_format(weaverepo.RepositoryFormat7(), "bar")
143
135
 
144
136
    def test_find_format_no_repository(self):
145
137
        dir = bzrdir.BzrDirMetaFormat1().initialize(self.get_url())
155
147
                          dir)
156
148
 
157
149
    def test_register_unregister_format(self):
158
 
        # Test deprecated format registration functions
159
150
        format = SampleRepositoryFormat()
160
151
        # make a control dir
161
152
        dir = bzrdir.BzrDirMetaFormat1().initialize(self.get_url())
162
153
        # make a repo
163
154
        format.initialize(dir)
164
155
        # register a format for it.
165
 
        self.applyDeprecated(symbol_versioning.deprecated_in((2, 4, 0)),
166
 
            repository.RepositoryFormat.register_format, format)
 
156
        repository.RepositoryFormat.register_format(format)
167
157
        # which repository.Open will refuse (not supported)
168
 
        self.assertRaises(UnsupportedFormatError, repository.Repository.open,
169
 
            self.get_url())
 
158
        self.assertRaises(UnsupportedFormatError, repository.Repository.open, self.get_url())
170
159
        # but open(unsupported) will work
171
160
        self.assertEqual(format.open(dir), "opened repository.")
172
161
        # 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)
 
162
        repository.RepositoryFormat.unregister_format(format)
 
163
 
 
164
 
 
165
class TestFormat6(TestCaseWithTransport):
 
166
 
 
167
    def test_attribute__fetch_order(self):
 
168
        """Weaves need topological data insertion."""
 
169
        control = bzrdir.BzrDirFormat6().initialize(self.get_url())
 
170
        repo = weaverepo.RepositoryFormat6().initialize(control)
 
171
        self.assertEqual('topological', repo._format._fetch_order)
 
172
 
 
173
    def test_attribute__fetch_uses_deltas(self):
 
174
        """Weaves do not reuse deltas."""
 
175
        control = bzrdir.BzrDirFormat6().initialize(self.get_url())
 
176
        repo = weaverepo.RepositoryFormat6().initialize(control)
 
177
        self.assertEqual(False, repo._format._fetch_uses_deltas)
 
178
 
 
179
    def test_attribute__fetch_reconcile(self):
 
180
        """Weave repositories need a reconcile after fetch."""
 
181
        control = bzrdir.BzrDirFormat6().initialize(self.get_url())
 
182
        repo = weaverepo.RepositoryFormat6().initialize(control)
 
183
        self.assertEqual(True, repo._format._fetch_reconcile)
 
184
 
 
185
    def test_no_ancestry_weave(self):
 
186
        control = bzrdir.BzrDirFormat6().initialize(self.get_url())
 
187
        repo = weaverepo.RepositoryFormat6().initialize(control)
 
188
        # We no longer need to create the ancestry.weave file
 
189
        # since it is *never* used.
 
190
        self.assertRaises(NoSuchFile,
 
191
                          control.transport.get,
 
192
                          'ancestry.weave')
 
193
 
 
194
    def test_supports_external_lookups(self):
 
195
        control = bzrdir.BzrDirFormat6().initialize(self.get_url())
 
196
        repo = weaverepo.RepositoryFormat6().initialize(control)
 
197
        self.assertFalse(repo._format.supports_external_lookups)
 
198
 
 
199
 
 
200
class TestFormat7(TestCaseWithTransport):
 
201
 
 
202
    def test_attribute__fetch_order(self):
 
203
        """Weaves need topological data insertion."""
 
204
        control = bzrdir.BzrDirMetaFormat1().initialize(self.get_url())
 
205
        repo = weaverepo.RepositoryFormat7().initialize(control)
 
206
        self.assertEqual('topological', repo._format._fetch_order)
 
207
 
 
208
    def test_attribute__fetch_uses_deltas(self):
 
209
        """Weaves do not reuse deltas."""
 
210
        control = bzrdir.BzrDirMetaFormat1().initialize(self.get_url())
 
211
        repo = weaverepo.RepositoryFormat7().initialize(control)
 
212
        self.assertEqual(False, repo._format._fetch_uses_deltas)
 
213
 
 
214
    def test_attribute__fetch_reconcile(self):
 
215
        """Weave repositories need a reconcile after fetch."""
 
216
        control = bzrdir.BzrDirMetaFormat1().initialize(self.get_url())
 
217
        repo = weaverepo.RepositoryFormat7().initialize(control)
 
218
        self.assertEqual(True, repo._format._fetch_reconcile)
 
219
 
 
220
    def test_disk_layout(self):
 
221
        control = bzrdir.BzrDirMetaFormat1().initialize(self.get_url())
 
222
        repo = weaverepo.RepositoryFormat7().initialize(control)
 
223
        # in case of side effects of locking.
 
224
        repo.lock_write()
 
225
        repo.unlock()
 
226
        # we want:
 
227
        # format 'Bazaar-NG Repository format 7'
 
228
        # lock ''
 
229
        # inventory.weave == empty_weave
 
230
        # empty revision-store directory
 
231
        # empty weaves directory
 
232
        t = control.get_repository_transport(None)
 
233
        self.assertEqualDiff('Bazaar-NG Repository format 7',
 
234
                             t.get('format').read())
 
235
        self.assertTrue(S_ISDIR(t.stat('revision-store').st_mode))
 
236
        self.assertTrue(S_ISDIR(t.stat('weaves').st_mode))
 
237
        self.assertEqualDiff('# bzr weave file v5\n'
 
238
                             'w\n'
 
239
                             'W\n',
 
240
                             t.get('inventory.weave').read())
 
241
        # Creating a file with id Foo:Bar results in a non-escaped file name on
 
242
        # disk.
 
243
        control.create_branch()
 
244
        tree = control.create_workingtree()
 
245
        tree.add(['foo'], ['Foo:Bar'], ['file'])
 
246
        tree.put_file_bytes_non_atomic('Foo:Bar', 'content\n')
 
247
        try:
 
248
            tree.commit('first post', rev_id='first')
 
249
        except errors.IllegalPath:
 
250
            if sys.platform != 'win32':
 
251
                raise
 
252
            self.knownFailure('Foo:Bar cannot be used as a file-id on windows'
 
253
                              ' in repo format 7')
 
254
            return
 
255
        self.assertEqualDiff(
 
256
            '# bzr weave file v5\n'
 
257
            'i\n'
 
258
            '1 7fe70820e08a1aac0ef224d9c66ab66831cc4ab1\n'
 
259
            'n first\n'
 
260
            '\n'
 
261
            'w\n'
 
262
            '{ 0\n'
 
263
            '. content\n'
 
264
            '}\n'
 
265
            'W\n',
 
266
            t.get('weaves/74/Foo%3ABar.weave').read())
 
267
 
 
268
    def test_shared_disk_layout(self):
 
269
        control = bzrdir.BzrDirMetaFormat1().initialize(self.get_url())
 
270
        repo = weaverepo.RepositoryFormat7().initialize(control, shared=True)
 
271
        # we want:
 
272
        # format 'Bazaar-NG Repository format 7'
 
273
        # inventory.weave == empty_weave
 
274
        # empty revision-store directory
 
275
        # empty weaves directory
 
276
        # a 'shared-storage' marker file.
 
277
        # lock is not present when unlocked
 
278
        t = control.get_repository_transport(None)
 
279
        self.assertEqualDiff('Bazaar-NG Repository format 7',
 
280
                             t.get('format').read())
 
281
        self.assertEqualDiff('', t.get('shared-storage').read())
 
282
        self.assertTrue(S_ISDIR(t.stat('revision-store').st_mode))
 
283
        self.assertTrue(S_ISDIR(t.stat('weaves').st_mode))
 
284
        self.assertEqualDiff('# bzr weave file v5\n'
 
285
                             'w\n'
 
286
                             'W\n',
 
287
                             t.get('inventory.weave').read())
 
288
        self.assertFalse(t.has('branch-lock'))
 
289
 
 
290
    def test_creates_lockdir(self):
 
291
        """Make sure it appears to be controlled by a LockDir existence"""
 
292
        control = bzrdir.BzrDirMetaFormat1().initialize(self.get_url())
 
293
        repo = weaverepo.RepositoryFormat7().initialize(control, shared=True)
 
294
        t = control.get_repository_transport(None)
 
295
        # TODO: Should check there is a 'lock' toplevel directory,
 
296
        # regardless of contents
 
297
        self.assertFalse(t.has('lock/held/info'))
 
298
        repo.lock_write()
 
299
        try:
 
300
            self.assertTrue(t.has('lock/held/info'))
 
301
        finally:
 
302
            # unlock so we don't get a warning about failing to do so
 
303
            repo.unlock()
 
304
 
 
305
    def test_uses_lockdir(self):
 
306
        """repo format 7 actually locks on lockdir"""
 
307
        base_url = self.get_url()
 
308
        control = bzrdir.BzrDirMetaFormat1().initialize(base_url)
 
309
        repo = weaverepo.RepositoryFormat7().initialize(control, shared=True)
 
310
        t = control.get_repository_transport(None)
 
311
        repo.lock_write()
 
312
        repo.unlock()
 
313
        del repo
 
314
        # make sure the same lock is created by opening it
 
315
        repo = repository.Repository.open(base_url)
 
316
        repo.lock_write()
 
317
        self.assertTrue(t.has('lock/held/info'))
 
318
        repo.unlock()
 
319
        self.assertFalse(t.has('lock/held/info'))
 
320
 
 
321
    def test_shared_no_tree_disk_layout(self):
 
322
        control = bzrdir.BzrDirMetaFormat1().initialize(self.get_url())
 
323
        repo = weaverepo.RepositoryFormat7().initialize(control, shared=True)
 
324
        repo.set_make_working_trees(False)
 
325
        # we want:
 
326
        # format 'Bazaar-NG Repository format 7'
 
327
        # lock ''
 
328
        # inventory.weave == empty_weave
 
329
        # empty revision-store directory
 
330
        # empty weaves directory
 
331
        # a 'shared-storage' marker file.
 
332
        t = control.get_repository_transport(None)
 
333
        self.assertEqualDiff('Bazaar-NG Repository format 7',
 
334
                             t.get('format').read())
 
335
        ## self.assertEqualDiff('', t.get('lock').read())
 
336
        self.assertEqualDiff('', t.get('shared-storage').read())
 
337
        self.assertEqualDiff('', t.get('no-working-trees').read())
 
338
        repo.set_make_working_trees(True)
 
339
        self.assertFalse(t.has('no-working-trees'))
 
340
        self.assertTrue(S_ISDIR(t.stat('revision-store').st_mode))
 
341
        self.assertTrue(S_ISDIR(t.stat('weaves').st_mode))
 
342
        self.assertEqualDiff('# bzr weave file v5\n'
 
343
                             'w\n'
 
344
                             'W\n',
 
345
                             t.get('inventory.weave').read())
 
346
 
 
347
    def test_supports_external_lookups(self):
 
348
        control = bzrdir.BzrDirMetaFormat1().initialize(self.get_url())
 
349
        repo = weaverepo.RepositoryFormat7().initialize(control)
 
350
        self.assertFalse(repo._format.supports_external_lookups)
209
351
 
210
352
 
211
353
class TestFormatKnit1(TestCaseWithTransport):
379
521
        # classes do not barf inappropriately when a surprising repository type
380
522
        # is handed to them.
381
523
        dummy_a = DummyRepository()
382
 
        dummy_a._format = RepositoryFormat()
383
 
        dummy_a._format.supports_full_versioned_files = True
384
524
        dummy_b = DummyRepository()
385
 
        dummy_b._format = RepositoryFormat()
386
 
        dummy_b._format.supports_full_versioned_files = True
387
525
        self.assertGetsDefaultInterRepository(dummy_a, dummy_b)
388
526
 
389
527
    def assertGetsDefaultInterRepository(self, repo_a, repo_b):
393
531
        no actual sane default in the presence of incompatible data models.
394
532
        """
395
533
        inter_repo = repository.InterRepository.get(repo_a, repo_b)
396
 
        self.assertEqual(vf_repository.InterSameDataRepository,
 
534
        self.assertEqual(repository.InterSameDataRepository,
397
535
                         inter_repo.__class__)
398
536
        self.assertEqual(repo_a, inter_repo.source)
399
537
        self.assertEqual(repo_b, inter_repo.target)
413
551
        dummy_a._serializer = repo._serializer
414
552
        dummy_a._format.supports_tree_reference = repo._format.supports_tree_reference
415
553
        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
554
        dummy_b._serializer = repo._serializer
418
555
        dummy_b._format.supports_tree_reference = repo._format.supports_tree_reference
419
556
        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
557
        repository.InterRepository.register_optimiser(InterDummy)
422
558
        try:
423
559
            # we should get the default for something InterDummy returns False
436
572
        self.assertGetsDefaultInterRepository(dummy_a, dummy_b)
437
573
 
438
574
 
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"
 
575
class TestInterWeaveRepo(TestCaseWithTransport):
 
576
 
 
577
    def test_is_compatible_and_registered(self):
 
578
        # InterWeaveRepo is compatible when either side
 
579
        # is a format 5/6/7 branch
 
580
        from bzrlib.repofmt import knitrepo, weaverepo
 
581
        formats = [weaverepo.RepositoryFormat5(),
 
582
                   weaverepo.RepositoryFormat6(),
 
583
                   weaverepo.RepositoryFormat7()]
 
584
        incompatible_formats = [weaverepo.RepositoryFormat4(),
 
585
                                knitrepo.RepositoryFormatKnit1(),
 
586
                                ]
 
587
        repo_a = self.make_repository('a')
 
588
        repo_b = self.make_repository('b')
 
589
        is_compatible = repository.InterWeaveRepo.is_compatible
 
590
        for source in incompatible_formats:
 
591
            # force incompatible left then right
 
592
            repo_a._format = source
 
593
            repo_b._format = formats[0]
 
594
            self.assertFalse(is_compatible(repo_a, repo_b))
 
595
            self.assertFalse(is_compatible(repo_b, repo_a))
 
596
        for source in formats:
 
597
            repo_a._format = source
 
598
            for target in formats:
 
599
                repo_b._format = target
 
600
                self.assertTrue(is_compatible(repo_a, repo_b))
 
601
        self.assertEqual(repository.InterWeaveRepo,
 
602
                         repository.InterRepository.get(repo_a,
 
603
                                                        repo_b).__class__)
449
604
 
450
605
 
451
606
class TestRepositoryConverter(TestCaseWithTransport):
452
607
 
453
608
    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()
 
609
        t = get_transport(self.get_url('.'))
463
610
        t.mkdir('repository')
464
611
        repo_dir = bzrdir.BzrDirMetaFormat1().initialize('repository')
465
 
        repo = TestRepositoryFormat1().initialize(repo_dir)
 
612
        repo = weaverepo.RepositoryFormat7().initialize(repo_dir)
 
613
        target_format = knitrepo.RepositoryFormatKnit1()
466
614
        converter = repository.CopyConverter(target_format)
467
615
        pb = bzrlib.ui.ui_factory.nested_progress_bar()
468
616
        try:
473
621
        self.assertTrue(isinstance(target_format, repo._format.__class__))
474
622
 
475
623
 
 
624
class TestMisc(TestCase):
 
625
 
 
626
    def test_unescape_xml(self):
 
627
        """We get some kind of error when malformed entities are passed"""
 
628
        self.assertRaises(KeyError, repository._unescape_xml, 'foo&bar;')
 
629
 
 
630
 
476
631
class TestRepositoryFormatKnit3(TestCaseWithTransport):
477
632
 
478
633
    def test_attribute__fetch_order(self):
673
828
        target = self.make_repository('target', format='rich-root-pack')
674
829
        stream = source._get_source(target._format)
675
830
        # We don't want the child GroupCHKStreamSource
676
 
        self.assertIs(type(stream), vf_repository.StreamSource)
 
831
        self.assertIs(type(stream), repository.StreamSource)
677
832
 
678
833
    def test_get_stream_for_missing_keys_includes_all_chk_refs(self):
679
834
        source_builder = self.make_branch_builder('source',
755
910
        source = self.make_repository('source', format='pack-0.92')
756
911
        target = self.make_repository('target', format='pack-0.92')
757
912
        stream_source = source._get_source(target._format)
758
 
        self.assertIsInstance(stream_source, knitpack_repo.KnitPackStreamSource)
 
913
        self.assertIsInstance(stream_source, pack_repo.KnitPackStreamSource)
759
914
 
760
915
    def test_source_to_exact_pack_rich_root_pack(self):
761
916
        source = self.make_repository('source', format='rich-root-pack')
762
917
        target = self.make_repository('target', format='rich-root-pack')
763
918
        stream_source = source._get_source(target._format)
764
 
        self.assertIsInstance(stream_source, knitpack_repo.KnitPackStreamSource)
 
919
        self.assertIsInstance(stream_source, pack_repo.KnitPackStreamSource)
765
920
 
766
921
    def test_source_to_exact_pack_19(self):
767
922
        source = self.make_repository('source', format='1.9')
768
923
        target = self.make_repository('target', format='1.9')
769
924
        stream_source = source._get_source(target._format)
770
 
        self.assertIsInstance(stream_source, knitpack_repo.KnitPackStreamSource)
 
925
        self.assertIsInstance(stream_source, pack_repo.KnitPackStreamSource)
771
926
 
772
927
    def test_source_to_exact_pack_19_rich_root(self):
773
928
        source = self.make_repository('source', format='1.9-rich-root')
774
929
        target = self.make_repository('target', format='1.9-rich-root')
775
930
        stream_source = source._get_source(target._format)
776
 
        self.assertIsInstance(stream_source, knitpack_repo.KnitPackStreamSource)
 
931
        self.assertIsInstance(stream_source, pack_repo.KnitPackStreamSource)
777
932
 
778
933
    def test_source_to_remote_exact_pack_19(self):
779
934
        trans = self.make_smart_server('target')
782
937
        target = self.make_repository('target', format='1.9')
783
938
        target = repository.Repository.open(trans.base)
784
939
        stream_source = source._get_source(target._format)
785
 
        self.assertIsInstance(stream_source, knitpack_repo.KnitPackStreamSource)
 
940
        self.assertIsInstance(stream_source, pack_repo.KnitPackStreamSource)
786
941
 
787
942
    def test_stream_source_to_non_exact(self):
788
943
        source = self.make_repository('source', format='pack-0.92')
789
944
        target = self.make_repository('target', format='1.9')
790
945
        stream = source._get_source(target._format)
791
 
        self.assertIs(type(stream), vf_repository.StreamSource)
 
946
        self.assertIs(type(stream), repository.StreamSource)
792
947
 
793
948
    def test_stream_source_to_non_exact_rich_root(self):
794
949
        source = self.make_repository('source', format='1.9')
795
950
        target = self.make_repository('target', format='1.9-rich-root')
796
951
        stream = source._get_source(target._format)
797
 
        self.assertIs(type(stream), vf_repository.StreamSource)
 
952
        self.assertIs(type(stream), repository.StreamSource)
798
953
 
799
954
    def test_source_to_remote_non_exact_pack_19(self):
800
955
        trans = self.make_smart_server('target')
803
958
        target = self.make_repository('target', format='1.6')
804
959
        target = repository.Repository.open(trans.base)
805
960
        stream_source = source._get_source(target._format)
806
 
        self.assertIs(type(stream_source), vf_repository.StreamSource)
 
961
        self.assertIs(type(stream_source), repository.StreamSource)
807
962
 
808
963
    def test_stream_source_to_knit(self):
809
964
        source = self.make_repository('source', format='pack-0.92')
810
965
        target = self.make_repository('target', format='dirstate')
811
966
        stream = source._get_source(target._format)
812
 
        self.assertIs(type(stream), vf_repository.StreamSource)
 
967
        self.assertIs(type(stream), repository.StreamSource)
813
968
 
814
969
 
815
970
class TestDevelopment6FindParentIdsOfRevisions(TestCaseWithTransport):
1451
1606
        # Because of how they were built, they correspond to
1452
1607
        # ['D', 'C', 'B', 'A']
1453
1608
        packs = b.repository._pack_collection.packs
1454
 
        packer = knitpack_repo.KnitPacker(b.repository._pack_collection,
 
1609
        packer = pack_repo.Packer(b.repository._pack_collection,
1455
1610
                                  packs, 'testing',
1456
1611
                                  revision_ids=['B', 'C'])
1457
1612
        # Now, when we are copying the B & C revisions, their pack files should
1471
1626
        return repo._pack_collection
1472
1627
 
1473
1628
    def test_open_pack_will_optimise(self):
1474
 
        packer = knitpack_repo.OptimisingKnitPacker(self.get_pack_collection(),
 
1629
        packer = pack_repo.OptimisingPacker(self.get_pack_collection(),
1475
1630
                                            [], '.test')
1476
1631
        new_pack = packer.open_pack()
1477
1632
        self.addCleanup(new_pack.abort) # ensure cleanup
1482
1637
        self.assertTrue(new_pack.signature_index._optimize_for_size)
1483
1638
 
1484
1639
 
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
1640
class TestCrossFormatPacks(TestCaseWithTransport):
1586
1641
 
1587
1642
    def log_pack(self, hint=None):
1602
1657
        self.addCleanup(target.unlock)
1603
1658
        source = source_tree.branch.repository._get_source(target._format)
1604
1659
        self.orig_pack = target.pack
1605
 
        self.overrideAttr(target, "pack", self.log_pack)
 
1660
        target.pack = self.log_pack
1606
1661
        search = target.search_missing_revision_ids(
1607
 
            source_tree.branch.repository, revision_ids=[tip])
 
1662
            source_tree.branch.repository, tip)
1608
1663
        stream = source.get_stream(search)
1609
1664
        from_format = source_tree.branch.repository._format
1610
1665
        sink = target._get_sink()
1626
1681
        self.addCleanup(target.unlock)
1627
1682
        source = source_tree.branch.repository
1628
1683
        self.orig_pack = target.pack
1629
 
        self.overrideAttr(target, "pack", self.log_pack)
 
1684
        target.pack = self.log_pack
1630
1685
        target.fetch(source)
1631
1686
        if expect_pack_called:
1632
1687
            self.assertLength(1, self.calls)
1660
1715
    def test_IDS_format_same_no(self):
1661
1716
        # When the formats are the same, pack is not called.
1662
1717
        self.run_fetch('2a', '2a', False)
1663
 
 
1664
 
 
1665
 
class Test_LazyListJoin(tests.TestCase):
1666
 
 
1667
 
    def test__repr__(self):
1668
 
        lazy = repository._LazyListJoin(['a'], ['b'])
1669
 
        self.assertEqual("bzrlib.repository._LazyListJoin((['a'], ['b']))",
1670
 
                         repr(lazy))