~bzr-pqm/bzr/bzr.dev

« back to all changes in this revision

Viewing changes to bzrlib/tests/test_repository.py

  • Committer: Vincent Ladeuil
  • Date: 2016-01-21 09:52:36 UTC
  • mto: This revision was merged to the branch mainline in revision 6611.
  • Revision ID: v.ladeuil+lp@free.fr-20160121095236-iandk0fic0phu9ey
Fix the failing gpg test on wily.

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
# Copyright (C) 2006-2010 Canonical Ltd
 
1
# Copyright (C) 2006-2011 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
 
from StringIO import StringIO
27
 
import sys
28
26
 
29
27
import bzrlib
30
 
from bzrlib.errors import (NotBranchError,
31
 
                           NoSuchFile,
32
 
                           UnknownFormatError,
33
 
                           UnsupportedFormatError,
34
 
                           )
 
28
from bzrlib.errors import (
 
29
    UnknownFormatError,
 
30
    UnsupportedFormatError,
 
31
    )
35
32
from bzrlib import (
36
 
    graph,
 
33
    btree_index,
 
34
    symbol_versioning,
37
35
    tests,
 
36
    transport,
 
37
    vf_search,
38
38
    )
39
 
from bzrlib.branchbuilder import BranchBuilder
40
39
from bzrlib.btree_index import BTreeBuilder, BTreeGraphIndex
41
 
from bzrlib.index import GraphIndex, InMemoryGraphIndex
 
40
from bzrlib.index import GraphIndex
42
41
from bzrlib.repository import RepositoryFormat
43
 
from bzrlib.smart import server
44
42
from bzrlib.tests import (
45
43
    TestCase,
46
44
    TestCaseWithTransport,
47
 
    TestSkipped,
48
 
    test_knit,
49
 
    )
50
 
from bzrlib.transport import (
51
 
    fakenfs,
52
 
    get_transport,
53
45
    )
54
46
from bzrlib import (
55
 
    bencode,
56
47
    bzrdir,
 
48
    controldir,
57
49
    errors,
58
50
    inventory,
59
51
    osutils,
60
 
    progress,
61
52
    repository,
62
53
    revision as _mod_revision,
63
 
    symbol_versioning,
64
54
    upgrade,
65
55
    versionedfile,
 
56
    vf_repository,
66
57
    workingtree,
67
58
    )
68
59
from bzrlib.repofmt import (
69
60
    groupcompress_repo,
70
61
    knitrepo,
 
62
    knitpack_repo,
71
63
    pack_repo,
72
 
    weaverepo,
73
64
    )
74
65
 
75
66
 
76
67
class TestDefaultFormat(TestCase):
77
68
 
78
69
    def test_get_set_default_format(self):
79
 
        old_default = bzrdir.format_registry.get('default')
 
70
        old_default = controldir.format_registry.get('default')
80
71
        private_default = old_default().repository_format.__class__
81
 
        old_format = repository.RepositoryFormat.get_default_format()
 
72
        old_format = repository.format_registry.get_default()
82
73
        self.assertTrue(isinstance(old_format, private_default))
83
74
        def make_sample_bzrdir():
84
75
            my_bzrdir = bzrdir.BzrDirMetaFormat1()
85
76
            my_bzrdir.repository_format = SampleRepositoryFormat()
86
77
            return my_bzrdir
87
 
        bzrdir.format_registry.remove('default')
88
 
        bzrdir.format_registry.register('sample', make_sample_bzrdir, '')
89
 
        bzrdir.format_registry.set_default('sample')
 
78
        controldir.format_registry.remove('default')
 
79
        controldir.format_registry.register('sample', make_sample_bzrdir, '')
 
80
        controldir.format_registry.set_default('sample')
90
81
        # creating a repository should now create an instrumented dir.
91
82
        try:
92
83
            # the default branch format is used by the meta dir format
95
86
            result = dir.create_repository()
96
87
            self.assertEqual(result, 'A bzr repository dir')
97
88
        finally:
98
 
            bzrdir.format_registry.remove('default')
99
 
            bzrdir.format_registry.remove('sample')
100
 
            bzrdir.format_registry.register('default', old_default, '')
101
 
        self.assertIsInstance(repository.RepositoryFormat.get_default_format(),
 
89
            controldir.format_registry.remove('default')
 
90
            controldir.format_registry.remove('sample')
 
91
            controldir.format_registry.register('default', old_default, '')
 
92
        self.assertIsInstance(repository.format_registry.get_default(),
102
93
                              old_format.__class__)
103
94
 
104
95
 
105
 
class SampleRepositoryFormat(repository.RepositoryFormat):
 
96
class SampleRepositoryFormat(repository.RepositoryFormatMetaDir):
106
97
    """A sample format
107
98
 
108
99
    this format is initializable, unsupported to aid in testing the
109
100
    open and open(unsupported=True) routines.
110
101
    """
111
102
 
112
 
    def get_format_string(self):
 
103
    @classmethod
 
104
    def get_format_string(cls):
113
105
        """See RepositoryFormat.get_format_string()."""
114
106
        return "Sample .bzr repository format."
115
107
 
126
118
        return "opened repository."
127
119
 
128
120
 
 
121
class SampleExtraRepositoryFormat(repository.RepositoryFormat):
 
122
    """A sample format that can not be used in a metadir
 
123
 
 
124
    """
 
125
 
 
126
    def get_format_string(self):
 
127
        raise NotImplementedError
 
128
 
 
129
 
129
130
class TestRepositoryFormat(TestCaseWithTransport):
130
131
    """Tests for the Repository format detection used by the bzr meta dir facility.BzrBranchFormat facility."""
131
132
 
137
138
        def check_format(format, url):
138
139
            dir = format._matchingbzrdir.initialize(url)
139
140
            format.initialize(dir)
140
 
            t = get_transport(url)
141
 
            found_format = repository.RepositoryFormat.find_format(dir)
142
 
            self.failUnless(isinstance(found_format, format.__class__))
143
 
        check_format(weaverepo.RepositoryFormat7(), "bar")
 
141
            t = transport.get_transport_from_path(url)
 
142
            found_format = repository.RepositoryFormatMetaDir.find_format(dir)
 
143
            self.assertIsInstance(found_format, format.__class__)
 
144
        check_format(repository.format_registry.get_default(), "bar")
144
145
 
145
146
    def test_find_format_no_repository(self):
146
147
        dir = bzrdir.BzrDirMetaFormat1().initialize(self.get_url())
147
148
        self.assertRaises(errors.NoRepositoryPresent,
148
 
                          repository.RepositoryFormat.find_format,
 
149
                          repository.RepositoryFormatMetaDir.find_format,
149
150
                          dir)
150
151
 
 
152
    def test_from_string(self):
 
153
        self.assertIsInstance(
 
154
            SampleRepositoryFormat.from_string(
 
155
                "Sample .bzr repository format."),
 
156
            SampleRepositoryFormat)
 
157
        self.assertRaises(AssertionError,
 
158
            SampleRepositoryFormat.from_string,
 
159
                "Different .bzr repository format.")
 
160
 
151
161
    def test_find_format_unknown_format(self):
152
162
        dir = bzrdir.BzrDirMetaFormat1().initialize(self.get_url())
153
163
        SampleRepositoryFormat().initialize(dir)
154
164
        self.assertRaises(UnknownFormatError,
155
 
                          repository.RepositoryFormat.find_format,
 
165
                          repository.RepositoryFormatMetaDir.find_format,
156
166
                          dir)
157
167
 
 
168
    def test_find_format_with_features(self):
 
169
        tree = self.make_branch_and_tree('.', format='2a')
 
170
        tree.branch.repository.update_feature_flags({"name": "necessity"})
 
171
        found_format = repository.RepositoryFormatMetaDir.find_format(tree.bzrdir)
 
172
        self.assertIsInstance(found_format, repository.RepositoryFormatMetaDir)
 
173
        self.assertEquals(found_format.features.get("name"), "necessity")
 
174
        self.assertRaises(errors.MissingFeature, found_format.check_support_status,
 
175
            True)
 
176
        self.addCleanup(repository.RepositoryFormatMetaDir.unregister_feature,
 
177
            "name")
 
178
        repository.RepositoryFormatMetaDir.register_feature("name")
 
179
        found_format.check_support_status(True)
 
180
 
 
181
 
 
182
class TestRepositoryFormatRegistry(TestCase):
 
183
 
 
184
    def setUp(self):
 
185
        super(TestRepositoryFormatRegistry, self).setUp()
 
186
        self.registry = repository.RepositoryFormatRegistry()
 
187
 
158
188
    def test_register_unregister_format(self):
159
189
        format = SampleRepositoryFormat()
160
 
        # make a control dir
161
 
        dir = bzrdir.BzrDirMetaFormat1().initialize(self.get_url())
162
 
        # make a repo
163
 
        format.initialize(dir)
164
 
        # register a format for it.
165
 
        repository.RepositoryFormat.register_format(format)
166
 
        # which repository.Open will refuse (not supported)
167
 
        self.assertRaises(UnsupportedFormatError, repository.Repository.open, self.get_url())
168
 
        # but open(unsupported) will work
169
 
        self.assertEqual(format.open(dir), "opened repository.")
170
 
        # unregister the format
171
 
        repository.RepositoryFormat.unregister_format(format)
172
 
 
173
 
 
174
 
class TestFormat6(TestCaseWithTransport):
175
 
 
176
 
    def test_attribute__fetch_order(self):
177
 
        """Weaves need topological data insertion."""
178
 
        control = bzrdir.BzrDirFormat6().initialize(self.get_url())
179
 
        repo = weaverepo.RepositoryFormat6().initialize(control)
180
 
        self.assertEqual('topological', repo._format._fetch_order)
181
 
 
182
 
    def test_attribute__fetch_uses_deltas(self):
183
 
        """Weaves do not reuse deltas."""
184
 
        control = bzrdir.BzrDirFormat6().initialize(self.get_url())
185
 
        repo = weaverepo.RepositoryFormat6().initialize(control)
186
 
        self.assertEqual(False, repo._format._fetch_uses_deltas)
187
 
 
188
 
    def test_attribute__fetch_reconcile(self):
189
 
        """Weave repositories need a reconcile after fetch."""
190
 
        control = bzrdir.BzrDirFormat6().initialize(self.get_url())
191
 
        repo = weaverepo.RepositoryFormat6().initialize(control)
192
 
        self.assertEqual(True, repo._format._fetch_reconcile)
193
 
 
194
 
    def test_no_ancestry_weave(self):
195
 
        control = bzrdir.BzrDirFormat6().initialize(self.get_url())
196
 
        repo = weaverepo.RepositoryFormat6().initialize(control)
197
 
        # We no longer need to create the ancestry.weave file
198
 
        # since it is *never* used.
199
 
        self.assertRaises(NoSuchFile,
200
 
                          control.transport.get,
201
 
                          'ancestry.weave')
202
 
 
203
 
    def test_supports_external_lookups(self):
204
 
        control = bzrdir.BzrDirFormat6().initialize(self.get_url())
205
 
        repo = weaverepo.RepositoryFormat6().initialize(control)
206
 
        self.assertFalse(repo._format.supports_external_lookups)
207
 
 
208
 
 
209
 
class TestFormat7(TestCaseWithTransport):
210
 
 
211
 
    def test_attribute__fetch_order(self):
212
 
        """Weaves need topological data insertion."""
213
 
        control = bzrdir.BzrDirMetaFormat1().initialize(self.get_url())
214
 
        repo = weaverepo.RepositoryFormat7().initialize(control)
215
 
        self.assertEqual('topological', repo._format._fetch_order)
216
 
 
217
 
    def test_attribute__fetch_uses_deltas(self):
218
 
        """Weaves do not reuse deltas."""
219
 
        control = bzrdir.BzrDirMetaFormat1().initialize(self.get_url())
220
 
        repo = weaverepo.RepositoryFormat7().initialize(control)
221
 
        self.assertEqual(False, repo._format._fetch_uses_deltas)
222
 
 
223
 
    def test_attribute__fetch_reconcile(self):
224
 
        """Weave repositories need a reconcile after fetch."""
225
 
        control = bzrdir.BzrDirMetaFormat1().initialize(self.get_url())
226
 
        repo = weaverepo.RepositoryFormat7().initialize(control)
227
 
        self.assertEqual(True, repo._format._fetch_reconcile)
228
 
 
229
 
    def test_disk_layout(self):
230
 
        control = bzrdir.BzrDirMetaFormat1().initialize(self.get_url())
231
 
        repo = weaverepo.RepositoryFormat7().initialize(control)
232
 
        # in case of side effects of locking.
233
 
        repo.lock_write()
234
 
        repo.unlock()
235
 
        # we want:
236
 
        # format 'Bazaar-NG Repository format 7'
237
 
        # lock ''
238
 
        # inventory.weave == empty_weave
239
 
        # empty revision-store directory
240
 
        # empty weaves directory
241
 
        t = control.get_repository_transport(None)
242
 
        self.assertEqualDiff('Bazaar-NG Repository format 7',
243
 
                             t.get('format').read())
244
 
        self.assertTrue(S_ISDIR(t.stat('revision-store').st_mode))
245
 
        self.assertTrue(S_ISDIR(t.stat('weaves').st_mode))
246
 
        self.assertEqualDiff('# bzr weave file v5\n'
247
 
                             'w\n'
248
 
                             'W\n',
249
 
                             t.get('inventory.weave').read())
250
 
        # Creating a file with id Foo:Bar results in a non-escaped file name on
251
 
        # disk.
252
 
        control.create_branch()
253
 
        tree = control.create_workingtree()
254
 
        tree.add(['foo'], ['Foo:Bar'], ['file'])
255
 
        tree.put_file_bytes_non_atomic('Foo:Bar', 'content\n')
256
 
        try:
257
 
            tree.commit('first post', rev_id='first')
258
 
        except errors.IllegalPath:
259
 
            if sys.platform != 'win32':
260
 
                raise
261
 
            self.knownFailure('Foo:Bar cannot be used as a file-id on windows'
262
 
                              ' in repo format 7')
263
 
            return
264
 
        self.assertEqualDiff(
265
 
            '# bzr weave file v5\n'
266
 
            'i\n'
267
 
            '1 7fe70820e08a1aac0ef224d9c66ab66831cc4ab1\n'
268
 
            'n first\n'
269
 
            '\n'
270
 
            'w\n'
271
 
            '{ 0\n'
272
 
            '. content\n'
273
 
            '}\n'
274
 
            'W\n',
275
 
            t.get('weaves/74/Foo%3ABar.weave').read())
276
 
 
277
 
    def test_shared_disk_layout(self):
278
 
        control = bzrdir.BzrDirMetaFormat1().initialize(self.get_url())
279
 
        repo = weaverepo.RepositoryFormat7().initialize(control, shared=True)
280
 
        # we want:
281
 
        # format 'Bazaar-NG Repository format 7'
282
 
        # inventory.weave == empty_weave
283
 
        # empty revision-store directory
284
 
        # empty weaves directory
285
 
        # a 'shared-storage' marker file.
286
 
        # lock is not present when unlocked
287
 
        t = control.get_repository_transport(None)
288
 
        self.assertEqualDiff('Bazaar-NG Repository format 7',
289
 
                             t.get('format').read())
290
 
        self.assertEqualDiff('', t.get('shared-storage').read())
291
 
        self.assertTrue(S_ISDIR(t.stat('revision-store').st_mode))
292
 
        self.assertTrue(S_ISDIR(t.stat('weaves').st_mode))
293
 
        self.assertEqualDiff('# bzr weave file v5\n'
294
 
                             'w\n'
295
 
                             'W\n',
296
 
                             t.get('inventory.weave').read())
297
 
        self.assertFalse(t.has('branch-lock'))
298
 
 
299
 
    def test_creates_lockdir(self):
300
 
        """Make sure it appears to be controlled by a LockDir existence"""
301
 
        control = bzrdir.BzrDirMetaFormat1().initialize(self.get_url())
302
 
        repo = weaverepo.RepositoryFormat7().initialize(control, shared=True)
303
 
        t = control.get_repository_transport(None)
304
 
        # TODO: Should check there is a 'lock' toplevel directory,
305
 
        # regardless of contents
306
 
        self.assertFalse(t.has('lock/held/info'))
307
 
        repo.lock_write()
308
 
        try:
309
 
            self.assertTrue(t.has('lock/held/info'))
310
 
        finally:
311
 
            # unlock so we don't get a warning about failing to do so
312
 
            repo.unlock()
313
 
 
314
 
    def test_uses_lockdir(self):
315
 
        """repo format 7 actually locks on lockdir"""
316
 
        base_url = self.get_url()
317
 
        control = bzrdir.BzrDirMetaFormat1().initialize(base_url)
318
 
        repo = weaverepo.RepositoryFormat7().initialize(control, shared=True)
319
 
        t = control.get_repository_transport(None)
320
 
        repo.lock_write()
321
 
        repo.unlock()
322
 
        del repo
323
 
        # make sure the same lock is created by opening it
324
 
        repo = repository.Repository.open(base_url)
325
 
        repo.lock_write()
326
 
        self.assertTrue(t.has('lock/held/info'))
327
 
        repo.unlock()
328
 
        self.assertFalse(t.has('lock/held/info'))
329
 
 
330
 
    def test_shared_no_tree_disk_layout(self):
331
 
        control = bzrdir.BzrDirMetaFormat1().initialize(self.get_url())
332
 
        repo = weaverepo.RepositoryFormat7().initialize(control, shared=True)
333
 
        repo.set_make_working_trees(False)
334
 
        # we want:
335
 
        # format 'Bazaar-NG Repository format 7'
336
 
        # lock ''
337
 
        # inventory.weave == empty_weave
338
 
        # empty revision-store directory
339
 
        # empty weaves directory
340
 
        # a 'shared-storage' marker file.
341
 
        t = control.get_repository_transport(None)
342
 
        self.assertEqualDiff('Bazaar-NG Repository format 7',
343
 
                             t.get('format').read())
344
 
        ## self.assertEqualDiff('', t.get('lock').read())
345
 
        self.assertEqualDiff('', t.get('shared-storage').read())
346
 
        self.assertEqualDiff('', t.get('no-working-trees').read())
347
 
        repo.set_make_working_trees(True)
348
 
        self.assertFalse(t.has('no-working-trees'))
349
 
        self.assertTrue(S_ISDIR(t.stat('revision-store').st_mode))
350
 
        self.assertTrue(S_ISDIR(t.stat('weaves').st_mode))
351
 
        self.assertEqualDiff('# bzr weave file v5\n'
352
 
                             'w\n'
353
 
                             'W\n',
354
 
                             t.get('inventory.weave').read())
355
 
 
356
 
    def test_supports_external_lookups(self):
357
 
        control = bzrdir.BzrDirMetaFormat1().initialize(self.get_url())
358
 
        repo = weaverepo.RepositoryFormat7().initialize(control)
359
 
        self.assertFalse(repo._format.supports_external_lookups)
 
190
        self.registry.register(format)
 
191
        self.assertEquals(format, self.registry.get("Sample .bzr repository format."))
 
192
        self.registry.remove(format)
 
193
        self.assertRaises(KeyError, self.registry.get, "Sample .bzr repository format.")
 
194
 
 
195
    def test_get_all(self):
 
196
        format = SampleRepositoryFormat()
 
197
        self.assertEquals([], self.registry._get_all())
 
198
        self.registry.register(format)
 
199
        self.assertEquals([format], self.registry._get_all())
 
200
 
 
201
    def test_register_extra(self):
 
202
        format = SampleExtraRepositoryFormat()
 
203
        self.assertEquals([], self.registry._get_all())
 
204
        self.registry.register_extra(format)
 
205
        self.assertEquals([format], self.registry._get_all())
 
206
 
 
207
    def test_register_extra_lazy(self):
 
208
        self.assertEquals([], self.registry._get_all())
 
209
        self.registry.register_extra_lazy("bzrlib.tests.test_repository",
 
210
            "SampleExtraRepositoryFormat")
 
211
        formats = self.registry._get_all()
 
212
        self.assertEquals(1, len(formats))
 
213
        self.assertIsInstance(formats[0], SampleExtraRepositoryFormat)
360
214
 
361
215
 
362
216
class TestFormatKnit1(TestCaseWithTransport):
364
218
    def test_attribute__fetch_order(self):
365
219
        """Knits need topological data insertion."""
366
220
        repo = self.make_repository('.',
367
 
                format=bzrdir.format_registry.get('knit')())
 
221
                format=controldir.format_registry.get('knit')())
368
222
        self.assertEqual('topological', repo._format._fetch_order)
369
223
 
370
224
    def test_attribute__fetch_uses_deltas(self):
371
225
        """Knits reuse deltas."""
372
226
        repo = self.make_repository('.',
373
 
                format=bzrdir.format_registry.get('knit')())
 
227
                format=controldir.format_registry.get('knit')())
374
228
        self.assertEqual(True, repo._format._fetch_uses_deltas)
375
229
 
376
230
    def test_disk_layout(self):
462
316
        is valid when the api is not being abused.
463
317
        """
464
318
        repo = self.make_repository('.',
465
 
                format=bzrdir.format_registry.get('knit')())
 
319
                format=controldir.format_registry.get('knit')())
466
320
        inv_xml = '<inventory format="5">\n</inventory>\n'
467
321
        inv = repo._deserialise_inventory('test-rev-id', inv_xml)
468
322
        self.assertEqual('test-rev-id', inv.root.revision)
470
324
    def test_deserialise_uses_global_revision_id(self):
471
325
        """If it is set, then we re-use the global revision id"""
472
326
        repo = self.make_repository('.',
473
 
                format=bzrdir.format_registry.get('knit')())
 
327
                format=controldir.format_registry.get('knit')())
474
328
        inv_xml = ('<inventory format="5" revision_id="other-rev-id">\n'
475
329
                   '</inventory>\n')
476
330
        # Arguably, the deserialise_inventory should detect a mismatch, and
483
337
 
484
338
    def test_supports_external_lookups(self):
485
339
        repo = self.make_repository('.',
486
 
                format=bzrdir.format_registry.get('knit')())
 
340
                format=controldir.format_registry.get('knit')())
487
341
        self.assertFalse(repo._format.supports_external_lookups)
488
342
 
489
343
 
530
384
        # classes do not barf inappropriately when a surprising repository type
531
385
        # is handed to them.
532
386
        dummy_a = DummyRepository()
 
387
        dummy_a._format = RepositoryFormat()
 
388
        dummy_a._format.supports_full_versioned_files = True
533
389
        dummy_b = DummyRepository()
 
390
        dummy_b._format = RepositoryFormat()
 
391
        dummy_b._format.supports_full_versioned_files = True
534
392
        self.assertGetsDefaultInterRepository(dummy_a, dummy_b)
535
393
 
536
394
    def assertGetsDefaultInterRepository(self, repo_a, repo_b):
540
398
        no actual sane default in the presence of incompatible data models.
541
399
        """
542
400
        inter_repo = repository.InterRepository.get(repo_a, repo_b)
543
 
        self.assertEqual(repository.InterSameDataRepository,
 
401
        self.assertEqual(vf_repository.InterSameDataRepository,
544
402
                         inter_repo.__class__)
545
403
        self.assertEqual(repo_a, inter_repo.source)
546
404
        self.assertEqual(repo_b, inter_repo.target)
560
418
        dummy_a._serializer = repo._serializer
561
419
        dummy_a._format.supports_tree_reference = repo._format.supports_tree_reference
562
420
        dummy_a._format.rich_root_data = repo._format.rich_root_data
 
421
        dummy_a._format.supports_full_versioned_files = repo._format.supports_full_versioned_files
563
422
        dummy_b._serializer = repo._serializer
564
423
        dummy_b._format.supports_tree_reference = repo._format.supports_tree_reference
565
424
        dummy_b._format.rich_root_data = repo._format.rich_root_data
 
425
        dummy_b._format.supports_full_versioned_files = repo._format.supports_full_versioned_files
566
426
        repository.InterRepository.register_optimiser(InterDummy)
567
427
        try:
568
428
            # we should get the default for something InterDummy returns False
581
441
        self.assertGetsDefaultInterRepository(dummy_a, dummy_b)
582
442
 
583
443
 
584
 
class TestInterWeaveRepo(TestCaseWithTransport):
585
 
 
586
 
    def test_is_compatible_and_registered(self):
587
 
        # InterWeaveRepo is compatible when either side
588
 
        # is a format 5/6/7 branch
589
 
        from bzrlib.repofmt import knitrepo, weaverepo
590
 
        formats = [weaverepo.RepositoryFormat5(),
591
 
                   weaverepo.RepositoryFormat6(),
592
 
                   weaverepo.RepositoryFormat7()]
593
 
        incompatible_formats = [weaverepo.RepositoryFormat4(),
594
 
                                knitrepo.RepositoryFormatKnit1(),
595
 
                                ]
596
 
        repo_a = self.make_repository('a')
597
 
        repo_b = self.make_repository('b')
598
 
        is_compatible = repository.InterWeaveRepo.is_compatible
599
 
        for source in incompatible_formats:
600
 
            # force incompatible left then right
601
 
            repo_a._format = source
602
 
            repo_b._format = formats[0]
603
 
            self.assertFalse(is_compatible(repo_a, repo_b))
604
 
            self.assertFalse(is_compatible(repo_b, repo_a))
605
 
        for source in formats:
606
 
            repo_a._format = source
607
 
            for target in formats:
608
 
                repo_b._format = target
609
 
                self.assertTrue(is_compatible(repo_a, repo_b))
610
 
        self.assertEqual(repository.InterWeaveRepo,
611
 
                         repository.InterRepository.get(repo_a,
612
 
                                                        repo_b).__class__)
 
444
class TestRepositoryFormat1(knitrepo.RepositoryFormatKnit1):
 
445
 
 
446
    @classmethod
 
447
    def get_format_string(cls):
 
448
        return "Test Format 1"
 
449
 
 
450
 
 
451
class TestRepositoryFormat2(knitrepo.RepositoryFormatKnit1):
 
452
 
 
453
    @classmethod
 
454
    def get_format_string(cls):
 
455
        return "Test Format 2"
613
456
 
614
457
 
615
458
class TestRepositoryConverter(TestCaseWithTransport):
616
459
 
617
460
    def test_convert_empty(self):
618
 
        t = get_transport(self.get_url('.'))
 
461
        source_format = TestRepositoryFormat1()
 
462
        target_format = TestRepositoryFormat2()
 
463
        repository.format_registry.register(source_format)
 
464
        self.addCleanup(repository.format_registry.remove,
 
465
            source_format)
 
466
        repository.format_registry.register(target_format)
 
467
        self.addCleanup(repository.format_registry.remove,
 
468
            target_format)
 
469
        t = self.get_transport()
619
470
        t.mkdir('repository')
620
471
        repo_dir = bzrdir.BzrDirMetaFormat1().initialize('repository')
621
 
        repo = weaverepo.RepositoryFormat7().initialize(repo_dir)
622
 
        target_format = knitrepo.RepositoryFormatKnit1()
 
472
        repo = TestRepositoryFormat1().initialize(repo_dir)
623
473
        converter = repository.CopyConverter(target_format)
624
474
        pb = bzrlib.ui.ui_factory.nested_progress_bar()
625
475
        try:
630
480
        self.assertTrue(isinstance(target_format, repo._format.__class__))
631
481
 
632
482
 
633
 
class TestMisc(TestCase):
634
 
 
635
 
    def test_unescape_xml(self):
636
 
        """We get some kind of error when malformed entities are passed"""
637
 
        self.assertRaises(KeyError, repository._unescape_xml, 'foo&bar;')
638
 
 
639
 
 
640
483
class TestRepositoryFormatKnit3(TestCaseWithTransport):
641
484
 
642
485
    def test_attribute__fetch_order(self):
663
506
        revision_tree.lock_read()
664
507
        try:
665
508
            self.assertRaises(errors.NoSuchFile, revision_tree.get_file_lines,
666
 
                revision_tree.inventory.root.file_id)
 
509
                revision_tree.get_root_id())
667
510
        finally:
668
511
            revision_tree.unlock()
669
512
        format = bzrdir.BzrDirMetaFormat1()
673
516
        revision_tree = tree.branch.repository.revision_tree('dull')
674
517
        revision_tree.lock_read()
675
518
        try:
676
 
            revision_tree.get_file_lines(revision_tree.inventory.root.file_id)
 
519
            revision_tree.get_file_lines(revision_tree.get_root_id())
677
520
        finally:
678
521
            revision_tree.unlock()
679
522
        tree.commit("Another dull commit", rev_id='dull2')
680
523
        revision_tree = tree.branch.repository.revision_tree('dull2')
681
524
        revision_tree.lock_read()
682
525
        self.addCleanup(revision_tree.unlock)
683
 
        self.assertEqual('dull', revision_tree.inventory.root.revision)
 
526
        self.assertEqual('dull',
 
527
                revision_tree.get_file_revision(revision_tree.get_root_id()))
684
528
 
685
529
    def test_supports_external_lookups(self):
686
530
        format = bzrdir.BzrDirMetaFormat1()
691
535
 
692
536
class Test2a(tests.TestCaseWithMemoryTransport):
693
537
 
 
538
    def test_chk_bytes_uses_custom_btree_parser(self):
 
539
        mt = self.make_branch_and_memory_tree('test', format='2a')
 
540
        mt.lock_write()
 
541
        self.addCleanup(mt.unlock)
 
542
        mt.add([''], ['root-id'])
 
543
        mt.commit('first')
 
544
        index = mt.branch.repository.chk_bytes._index._graph_index._indices[0]
 
545
        self.assertEqual(btree_index._gcchk_factory, index._leaf_factory)
 
546
        # It should also work if we re-open the repo
 
547
        repo = mt.branch.repository.bzrdir.open_repository()
 
548
        repo.lock_read()
 
549
        self.addCleanup(repo.unlock)
 
550
        index = repo.chk_bytes._index._graph_index._indices[0]
 
551
        self.assertEqual(btree_index._gcchk_factory, index._leaf_factory)
 
552
 
694
553
    def test_fetch_combines_groups(self):
695
554
        builder = self.make_branch_builder('source', format='2a')
696
555
        builder.start_series()
822
681
        target = self.make_repository('target', format='rich-root-pack')
823
682
        stream = source._get_source(target._format)
824
683
        # We don't want the child GroupCHKStreamSource
825
 
        self.assertIs(type(stream), repository.StreamSource)
 
684
        self.assertIs(type(stream), vf_repository.StreamSource)
826
685
 
827
686
    def test_get_stream_for_missing_keys_includes_all_chk_refs(self):
828
687
        source_builder = self.make_branch_builder('source',
855
714
 
856
715
        # On a regular pass, getting the inventories and chk pages for rev-2
857
716
        # would only get the newly created chk pages
858
 
        search = graph.SearchResult(set(['rev-2']), set(['rev-1']), 1,
 
717
        search = vf_search.SearchResult(set(['rev-2']), set(['rev-1']), 1,
859
718
                                    set(['rev-2']))
860
719
        simple_chk_records = []
861
720
        for vf_name, substream in source.get_stream(search):
904
763
        source = self.make_repository('source', format='pack-0.92')
905
764
        target = self.make_repository('target', format='pack-0.92')
906
765
        stream_source = source._get_source(target._format)
907
 
        self.assertIsInstance(stream_source, pack_repo.KnitPackStreamSource)
 
766
        self.assertIsInstance(stream_source, knitpack_repo.KnitPackStreamSource)
908
767
 
909
768
    def test_source_to_exact_pack_rich_root_pack(self):
910
769
        source = self.make_repository('source', format='rich-root-pack')
911
770
        target = self.make_repository('target', format='rich-root-pack')
912
771
        stream_source = source._get_source(target._format)
913
 
        self.assertIsInstance(stream_source, pack_repo.KnitPackStreamSource)
 
772
        self.assertIsInstance(stream_source, knitpack_repo.KnitPackStreamSource)
914
773
 
915
774
    def test_source_to_exact_pack_19(self):
916
775
        source = self.make_repository('source', format='1.9')
917
776
        target = self.make_repository('target', format='1.9')
918
777
        stream_source = source._get_source(target._format)
919
 
        self.assertIsInstance(stream_source, pack_repo.KnitPackStreamSource)
 
778
        self.assertIsInstance(stream_source, knitpack_repo.KnitPackStreamSource)
920
779
 
921
780
    def test_source_to_exact_pack_19_rich_root(self):
922
781
        source = self.make_repository('source', format='1.9-rich-root')
923
782
        target = self.make_repository('target', format='1.9-rich-root')
924
783
        stream_source = source._get_source(target._format)
925
 
        self.assertIsInstance(stream_source, pack_repo.KnitPackStreamSource)
 
784
        self.assertIsInstance(stream_source, knitpack_repo.KnitPackStreamSource)
926
785
 
927
786
    def test_source_to_remote_exact_pack_19(self):
928
787
        trans = self.make_smart_server('target')
931
790
        target = self.make_repository('target', format='1.9')
932
791
        target = repository.Repository.open(trans.base)
933
792
        stream_source = source._get_source(target._format)
934
 
        self.assertIsInstance(stream_source, pack_repo.KnitPackStreamSource)
 
793
        self.assertIsInstance(stream_source, knitpack_repo.KnitPackStreamSource)
935
794
 
936
795
    def test_stream_source_to_non_exact(self):
937
796
        source = self.make_repository('source', format='pack-0.92')
938
797
        target = self.make_repository('target', format='1.9')
939
798
        stream = source._get_source(target._format)
940
 
        self.assertIs(type(stream), repository.StreamSource)
 
799
        self.assertIs(type(stream), vf_repository.StreamSource)
941
800
 
942
801
    def test_stream_source_to_non_exact_rich_root(self):
943
802
        source = self.make_repository('source', format='1.9')
944
803
        target = self.make_repository('target', format='1.9-rich-root')
945
804
        stream = source._get_source(target._format)
946
 
        self.assertIs(type(stream), repository.StreamSource)
 
805
        self.assertIs(type(stream), vf_repository.StreamSource)
947
806
 
948
807
    def test_source_to_remote_non_exact_pack_19(self):
949
808
        trans = self.make_smart_server('target')
952
811
        target = self.make_repository('target', format='1.6')
953
812
        target = repository.Repository.open(trans.base)
954
813
        stream_source = source._get_source(target._format)
955
 
        self.assertIs(type(stream_source), repository.StreamSource)
 
814
        self.assertIs(type(stream_source), vf_repository.StreamSource)
956
815
 
957
816
    def test_stream_source_to_knit(self):
958
817
        source = self.make_repository('source', format='pack-0.92')
959
818
        target = self.make_repository('target', format='dirstate')
960
819
        stream = source._get_source(target._format)
961
 
        self.assertIs(type(stream), repository.StreamSource)
 
820
        self.assertIs(type(stream), vf_repository.StreamSource)
962
821
 
963
822
 
964
823
class TestDevelopment6FindParentIdsOfRevisions(TestCaseWithTransport):
966
825
 
967
826
    def setUp(self):
968
827
        super(TestDevelopment6FindParentIdsOfRevisions, self).setUp()
969
 
        self.builder = self.make_branch_builder('source',
970
 
            format='development6-rich-root')
 
828
        self.builder = self.make_branch_builder('source')
971
829
        self.builder.start_series()
972
830
        self.builder.build_snapshot('initial', None,
973
831
            [('add', ('', 'tree-root', 'directory', None))])
1043
901
            revision = _mod_revision.Revision('rev1a',
1044
902
                committer='jrandom@example.com', timestamp=0,
1045
903
                inventory_sha1='', timezone=0, message='foo', parent_ids=[])
1046
 
            repo.add_revision('rev1a',revision, inv)
 
904
            repo.add_revision('rev1a', revision, inv)
1047
905
 
1048
906
            # make rev1b, which has no Revision, but has an Inventory, and
1049
907
            # file1
1084
942
        revision = _mod_revision.Revision(revision_id,
1085
943
            committer='jrandom@example.com', timestamp=0, inventory_sha1='',
1086
944
            timezone=0, message='foo', parent_ids=parent_ids)
1087
 
        repo.add_revision(revision_id,revision, inv)
 
945
        repo.add_revision(revision_id, revision, inv)
1088
946
 
1089
947
    def add_file(self, repo, inv, filename, revision, parents):
1090
948
        file_id = filename + '-id'
1118
976
class TestRepositoryPackCollection(TestCaseWithTransport):
1119
977
 
1120
978
    def get_format(self):
1121
 
        return bzrdir.format_registry.make_bzrdir('pack-0.92')
 
979
        return controldir.format_registry.make_bzrdir('pack-0.92')
1122
980
 
1123
981
    def get_packs(self):
1124
982
        format = self.get_format()
1220
1078
            sorted(set([osutils.splitext(n)[0] for n in
1221
1079
                        packs._index_transport.list_dir('.')])))
1222
1080
 
 
1081
    def test__obsolete_packs_missing_directory(self):
 
1082
        tree, r, packs, revs = self.make_packs_and_alt_repo(write_lock=True)
 
1083
        r.control_transport.rmdir('obsolete_packs')
 
1084
        names = packs.names()
 
1085
        pack = packs.get_pack_by_name(names[0])
 
1086
        # Schedule this one for removal
 
1087
        packs._remove_pack_from_memory(pack)
 
1088
        # Now trigger the obsoletion, and ensure that all the remaining files
 
1089
        # are still renamed
 
1090
        packs._obsolete_packs([pack])
 
1091
        self.assertEqual([n + '.pack' for n in names[1:]],
 
1092
                         sorted(packs._pack_transport.list_dir('.')))
 
1093
        # names[0] should not be present in the index anymore
 
1094
        self.assertEqual(names[1:],
 
1095
            sorted(set([osutils.splitext(n)[0] for n in
 
1096
                        packs._index_transport.list_dir('.')])))
 
1097
 
1223
1098
    def test_pack_distribution_zero(self):
1224
1099
        packs = self.get_packs()
1225
1100
        self.assertEqual([0], packs.pack_distribution(0))
1495
1370
        obsolete_names = set([osutils.splitext(n)[0] for n in obsolete_packs])
1496
1371
        self.assertEqual([pack.name], sorted(obsolete_names))
1497
1372
 
 
1373
    def test_pack_no_obsolete_packs_directory(self):
 
1374
        """Bug #314314, don't fail if obsolete_packs directory does
 
1375
        not exist."""
 
1376
        tree, r, packs, revs = self.make_packs_and_alt_repo(write_lock=True)
 
1377
        r.control_transport.rmdir('obsolete_packs')
 
1378
        packs._clear_obsolete_packs()
1498
1379
 
1499
1380
 
1500
1381
class TestPack(TestCaseWithTransport):
1601
1482
        # Because of how they were built, they correspond to
1602
1483
        # ['D', 'C', 'B', 'A']
1603
1484
        packs = b.repository._pack_collection.packs
1604
 
        packer = pack_repo.Packer(b.repository._pack_collection,
 
1485
        packer = knitpack_repo.KnitPacker(b.repository._pack_collection,
1605
1486
                                  packs, 'testing',
1606
1487
                                  revision_ids=['B', 'C'])
1607
1488
        # Now, when we are copying the B & C revisions, their pack files should
1621
1502
        return repo._pack_collection
1622
1503
 
1623
1504
    def test_open_pack_will_optimise(self):
1624
 
        packer = pack_repo.OptimisingPacker(self.get_pack_collection(),
 
1505
        packer = knitpack_repo.OptimisingKnitPacker(self.get_pack_collection(),
1625
1506
                                            [], '.test')
1626
1507
        new_pack = packer.open_pack()
1627
1508
        self.addCleanup(new_pack.abort) # ensure cleanup
1632
1513
        self.assertTrue(new_pack.signature_index._optimize_for_size)
1633
1514
 
1634
1515
 
 
1516
class TestGCCHKPacker(TestCaseWithTransport):
 
1517
 
 
1518
    def make_abc_branch(self):
 
1519
        builder = self.make_branch_builder('source')
 
1520
        builder.start_series()
 
1521
        builder.build_snapshot('A', None, [
 
1522
            ('add', ('', 'root-id', 'directory', None)),
 
1523
            ('add', ('file', 'file-id', 'file', 'content\n')),
 
1524
            ])
 
1525
        builder.build_snapshot('B', ['A'], [
 
1526
            ('add', ('dir', 'dir-id', 'directory', None))])
 
1527
        builder.build_snapshot('C', ['B'], [
 
1528
            ('modify', ('file-id', 'new content\n'))])
 
1529
        builder.finish_series()
 
1530
        return builder.get_branch()
 
1531
 
 
1532
    def make_branch_with_disjoint_inventory_and_revision(self):
 
1533
        """a repo with separate packs for a revisions Revision and Inventory.
 
1534
 
 
1535
        There will be one pack file that holds the Revision content, and one
 
1536
        for the Inventory content.
 
1537
 
 
1538
        :return: (repository,
 
1539
                  pack_name_with_rev_A_Revision,
 
1540
                  pack_name_with_rev_A_Inventory,
 
1541
                  pack_name_with_rev_C_content)
 
1542
        """
 
1543
        b_source = self.make_abc_branch()
 
1544
        b_base = b_source.bzrdir.sprout('base', revision_id='A').open_branch()
 
1545
        b_stacked = b_base.bzrdir.sprout('stacked', stacked=True).open_branch()
 
1546
        b_stacked.lock_write()
 
1547
        self.addCleanup(b_stacked.unlock)
 
1548
        b_stacked.fetch(b_source, 'B')
 
1549
        # Now re-open the stacked repo directly (no fallbacks) so that we can
 
1550
        # fill in the A rev.
 
1551
        repo_not_stacked = b_stacked.bzrdir.open_repository()
 
1552
        repo_not_stacked.lock_write()
 
1553
        self.addCleanup(repo_not_stacked.unlock)
 
1554
        # Now we should have a pack file with A's inventory, but not its
 
1555
        # Revision
 
1556
        self.assertEqual([('A',), ('B',)],
 
1557
                         sorted(repo_not_stacked.inventories.keys()))
 
1558
        self.assertEqual([('B',)],
 
1559
                         sorted(repo_not_stacked.revisions.keys()))
 
1560
        stacked_pack_names = repo_not_stacked._pack_collection.names()
 
1561
        # We have a couple names here, figure out which has A's inventory
 
1562
        for name in stacked_pack_names:
 
1563
            pack = repo_not_stacked._pack_collection.get_pack_by_name(name)
 
1564
            keys = [n[1] for n in pack.inventory_index.iter_all_entries()]
 
1565
            if ('A',) in keys:
 
1566
                inv_a_pack_name = name
 
1567
                break
 
1568
        else:
 
1569
            self.fail('Could not find pack containing A\'s inventory')
 
1570
        repo_not_stacked.fetch(b_source.repository, 'A')
 
1571
        self.assertEqual([('A',), ('B',)],
 
1572
                         sorted(repo_not_stacked.revisions.keys()))
 
1573
        new_pack_names = set(repo_not_stacked._pack_collection.names())
 
1574
        rev_a_pack_names = new_pack_names.difference(stacked_pack_names)
 
1575
        self.assertEqual(1, len(rev_a_pack_names))
 
1576
        rev_a_pack_name = list(rev_a_pack_names)[0]
 
1577
        # Now fetch 'C', so we have a couple pack files to join
 
1578
        repo_not_stacked.fetch(b_source.repository, 'C')
 
1579
        rev_c_pack_names = set(repo_not_stacked._pack_collection.names())
 
1580
        rev_c_pack_names = rev_c_pack_names.difference(new_pack_names)
 
1581
        self.assertEqual(1, len(rev_c_pack_names))
 
1582
        rev_c_pack_name = list(rev_c_pack_names)[0]
 
1583
        return (repo_not_stacked, rev_a_pack_name, inv_a_pack_name,
 
1584
                rev_c_pack_name)
 
1585
 
 
1586
    def test_pack_with_distant_inventories(self):
 
1587
        # See https://bugs.launchpad.net/bzr/+bug/437003
 
1588
        # When repacking, it is possible to have an inventory in a different
 
1589
        # pack file than the associated revision. An autopack can then come
 
1590
        # along, and miss that inventory, and complain.
 
1591
        (repo, rev_a_pack_name, inv_a_pack_name, rev_c_pack_name
 
1592
         ) = self.make_branch_with_disjoint_inventory_and_revision()
 
1593
        a_pack = repo._pack_collection.get_pack_by_name(rev_a_pack_name)
 
1594
        c_pack = repo._pack_collection.get_pack_by_name(rev_c_pack_name)
 
1595
        packer = groupcompress_repo.GCCHKPacker(repo._pack_collection,
 
1596
                    [a_pack, c_pack], '.test-pack')
 
1597
        # This would raise ValueError in bug #437003, but should not raise an
 
1598
        # error once fixed.
 
1599
        packer.pack()
 
1600
 
 
1601
    def test_pack_with_missing_inventory(self):
 
1602
        # Similar to test_pack_with_missing_inventory, but this time, we force
 
1603
        # the A inventory to actually be gone from the repository.
 
1604
        (repo, rev_a_pack_name, inv_a_pack_name, rev_c_pack_name
 
1605
         ) = self.make_branch_with_disjoint_inventory_and_revision()
 
1606
        inv_a_pack = repo._pack_collection.get_pack_by_name(inv_a_pack_name)
 
1607
        repo._pack_collection._remove_pack_from_memory(inv_a_pack)
 
1608
        packer = groupcompress_repo.GCCHKPacker(repo._pack_collection,
 
1609
            repo._pack_collection.all_packs(), '.test-pack')
 
1610
        e = self.assertRaises(ValueError, packer.pack)
 
1611
        packer.new_pack.abort()
 
1612
        self.assertContainsRe(str(e),
 
1613
            r"We are missing inventories for revisions: .*'A'")
 
1614
 
 
1615
 
1635
1616
class TestCrossFormatPacks(TestCaseWithTransport):
1636
1617
 
1637
1618
    def log_pack(self, hint=None):
1652
1633
        self.addCleanup(target.unlock)
1653
1634
        source = source_tree.branch.repository._get_source(target._format)
1654
1635
        self.orig_pack = target.pack
1655
 
        target.pack = self.log_pack
 
1636
        self.overrideAttr(target, "pack", self.log_pack)
1656
1637
        search = target.search_missing_revision_ids(
1657
 
            source_tree.branch.repository, tip)
 
1638
            source_tree.branch.repository, revision_ids=[tip])
1658
1639
        stream = source.get_stream(search)
1659
1640
        from_format = source_tree.branch.repository._format
1660
1641
        sink = target._get_sink()
1676
1657
        self.addCleanup(target.unlock)
1677
1658
        source = source_tree.branch.repository
1678
1659
        self.orig_pack = target.pack
1679
 
        target.pack = self.log_pack
 
1660
        self.overrideAttr(target, "pack", self.log_pack)
1680
1661
        target.fetch(source)
1681
1662
        if expect_pack_called:
1682
1663
            self.assertLength(1, self.calls)
1710
1691
    def test_IDS_format_same_no(self):
1711
1692
        # When the formats are the same, pack is not called.
1712
1693
        self.run_fetch('2a', '2a', False)
 
1694
 
 
1695
 
 
1696
class Test_LazyListJoin(tests.TestCase):
 
1697
 
 
1698
    def test__repr__(self):
 
1699
        lazy = repository._LazyListJoin(['a'], ['b'])
 
1700
        self.assertEqual("bzrlib.repository._LazyListJoin((['a'], ['b']))",
 
1701
                         repr(lazy))
 
1702
 
 
1703
 
 
1704
class TestFeatures(tests.TestCaseWithTransport):
 
1705
 
 
1706
    def test_open_with_present_feature(self):
 
1707
        self.addCleanup(
 
1708
            repository.RepositoryFormatMetaDir.unregister_feature,
 
1709
            "makes-cheese-sandwich")
 
1710
        repository.RepositoryFormatMetaDir.register_feature(
 
1711
            "makes-cheese-sandwich")
 
1712
        repo = self.make_repository('.')
 
1713
        repo.lock_write()
 
1714
        repo._format.features["makes-cheese-sandwich"] = "required"
 
1715
        repo._format.check_support_status(False)
 
1716
        repo.unlock()
 
1717
 
 
1718
    def test_open_with_missing_required_feature(self):
 
1719
        repo = self.make_repository('.')
 
1720
        repo.lock_write()
 
1721
        repo._format.features["makes-cheese-sandwich"] = "required"
 
1722
        self.assertRaises(errors.MissingFeature,
 
1723
            repo._format.check_support_status, False)