~bzr-pqm/bzr/bzr.dev

« back to all changes in this revision

Viewing changes to bzrlib/tests/test_repository.py

  • Committer: Patch Queue Manager
  • Date: 2012-03-16 14:15:06 UTC
  • mfrom: (6503.3.1 typo-fix)
  • Revision ID: pqm@pqm.ubuntu.com-20120316141506-30gdc3wkbgmwkdus
(jelmer) Fix a typo: extention -> extension. (Jelmer Vernooij)

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
 
158
181
    def test_register_unregister_format(self):
 
182
        # Test deprecated format registration functions
159
183
        format = SampleRepositoryFormat()
160
184
        # make a control dir
161
185
        dir = bzrdir.BzrDirMetaFormat1().initialize(self.get_url())
162
186
        # make a repo
163
187
        format.initialize(dir)
164
188
        # register a format for it.
165
 
        repository.RepositoryFormat.register_format(format)
 
189
        self.applyDeprecated(symbol_versioning.deprecated_in((2, 4, 0)),
 
190
            repository.RepositoryFormat.register_format, format)
166
191
        # which repository.Open will refuse (not supported)
167
 
        self.assertRaises(UnsupportedFormatError, repository.Repository.open, self.get_url())
 
192
        self.assertRaises(UnsupportedFormatError, repository.Repository.open,
 
193
            self.get_url())
168
194
        # but open(unsupported) will work
169
195
        self.assertEqual(format.open(dir), "opened repository.")
170
196
        # 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)
 
197
        self.applyDeprecated(symbol_versioning.deprecated_in((2, 4, 0)),
 
198
            repository.RepositoryFormat.unregister_format, format)
 
199
 
 
200
 
 
201
class TestRepositoryFormatRegistry(TestCase):
 
202
 
 
203
    def setUp(self):
 
204
        super(TestRepositoryFormatRegistry, self).setUp()
 
205
        self.registry = repository.RepositoryFormatRegistry()
 
206
 
 
207
    def test_register_unregister_format(self):
 
208
        format = SampleRepositoryFormat()
 
209
        self.registry.register(format)
 
210
        self.assertEquals(format, self.registry.get("Sample .bzr repository format."))
 
211
        self.registry.remove(format)
 
212
        self.assertRaises(KeyError, self.registry.get, "Sample .bzr repository format.")
 
213
 
 
214
    def test_get_all(self):
 
215
        format = SampleRepositoryFormat()
 
216
        self.assertEquals([], self.registry._get_all())
 
217
        self.registry.register(format)
 
218
        self.assertEquals([format], self.registry._get_all())
 
219
 
 
220
    def test_register_extra(self):
 
221
        format = SampleExtraRepositoryFormat()
 
222
        self.assertEquals([], self.registry._get_all())
 
223
        self.registry.register_extra(format)
 
224
        self.assertEquals([format], self.registry._get_all())
 
225
 
 
226
    def test_register_extra_lazy(self):
 
227
        self.assertEquals([], self.registry._get_all())
 
228
        self.registry.register_extra_lazy("bzrlib.tests.test_repository",
 
229
            "SampleExtraRepositoryFormat")
 
230
        formats = self.registry._get_all()
 
231
        self.assertEquals(1, len(formats))
 
232
        self.assertIsInstance(formats[0], SampleExtraRepositoryFormat)
360
233
 
361
234
 
362
235
class TestFormatKnit1(TestCaseWithTransport):
364
237
    def test_attribute__fetch_order(self):
365
238
        """Knits need topological data insertion."""
366
239
        repo = self.make_repository('.',
367
 
                format=bzrdir.format_registry.get('knit')())
 
240
                format=controldir.format_registry.get('knit')())
368
241
        self.assertEqual('topological', repo._format._fetch_order)
369
242
 
370
243
    def test_attribute__fetch_uses_deltas(self):
371
244
        """Knits reuse deltas."""
372
245
        repo = self.make_repository('.',
373
 
                format=bzrdir.format_registry.get('knit')())
 
246
                format=controldir.format_registry.get('knit')())
374
247
        self.assertEqual(True, repo._format._fetch_uses_deltas)
375
248
 
376
249
    def test_disk_layout(self):
462
335
        is valid when the api is not being abused.
463
336
        """
464
337
        repo = self.make_repository('.',
465
 
                format=bzrdir.format_registry.get('knit')())
 
338
                format=controldir.format_registry.get('knit')())
466
339
        inv_xml = '<inventory format="5">\n</inventory>\n'
467
340
        inv = repo._deserialise_inventory('test-rev-id', inv_xml)
468
341
        self.assertEqual('test-rev-id', inv.root.revision)
470
343
    def test_deserialise_uses_global_revision_id(self):
471
344
        """If it is set, then we re-use the global revision id"""
472
345
        repo = self.make_repository('.',
473
 
                format=bzrdir.format_registry.get('knit')())
 
346
                format=controldir.format_registry.get('knit')())
474
347
        inv_xml = ('<inventory format="5" revision_id="other-rev-id">\n'
475
348
                   '</inventory>\n')
476
349
        # Arguably, the deserialise_inventory should detect a mismatch, and
483
356
 
484
357
    def test_supports_external_lookups(self):
485
358
        repo = self.make_repository('.',
486
 
                format=bzrdir.format_registry.get('knit')())
 
359
                format=controldir.format_registry.get('knit')())
487
360
        self.assertFalse(repo._format.supports_external_lookups)
488
361
 
489
362
 
530
403
        # classes do not barf inappropriately when a surprising repository type
531
404
        # is handed to them.
532
405
        dummy_a = DummyRepository()
 
406
        dummy_a._format = RepositoryFormat()
 
407
        dummy_a._format.supports_full_versioned_files = True
533
408
        dummy_b = DummyRepository()
 
409
        dummy_b._format = RepositoryFormat()
 
410
        dummy_b._format.supports_full_versioned_files = True
534
411
        self.assertGetsDefaultInterRepository(dummy_a, dummy_b)
535
412
 
536
413
    def assertGetsDefaultInterRepository(self, repo_a, repo_b):
540
417
        no actual sane default in the presence of incompatible data models.
541
418
        """
542
419
        inter_repo = repository.InterRepository.get(repo_a, repo_b)
543
 
        self.assertEqual(repository.InterSameDataRepository,
 
420
        self.assertEqual(vf_repository.InterSameDataRepository,
544
421
                         inter_repo.__class__)
545
422
        self.assertEqual(repo_a, inter_repo.source)
546
423
        self.assertEqual(repo_b, inter_repo.target)
560
437
        dummy_a._serializer = repo._serializer
561
438
        dummy_a._format.supports_tree_reference = repo._format.supports_tree_reference
562
439
        dummy_a._format.rich_root_data = repo._format.rich_root_data
 
440
        dummy_a._format.supports_full_versioned_files = repo._format.supports_full_versioned_files
563
441
        dummy_b._serializer = repo._serializer
564
442
        dummy_b._format.supports_tree_reference = repo._format.supports_tree_reference
565
443
        dummy_b._format.rich_root_data = repo._format.rich_root_data
 
444
        dummy_b._format.supports_full_versioned_files = repo._format.supports_full_versioned_files
566
445
        repository.InterRepository.register_optimiser(InterDummy)
567
446
        try:
568
447
            # we should get the default for something InterDummy returns False
581
460
        self.assertGetsDefaultInterRepository(dummy_a, dummy_b)
582
461
 
583
462
 
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__)
 
463
class TestRepositoryFormat1(knitrepo.RepositoryFormatKnit1):
 
464
 
 
465
    @classmethod
 
466
    def get_format_string(cls):
 
467
        return "Test Format 1"
 
468
 
 
469
 
 
470
class TestRepositoryFormat2(knitrepo.RepositoryFormatKnit1):
 
471
 
 
472
    @classmethod
 
473
    def get_format_string(cls):
 
474
        return "Test Format 2"
613
475
 
614
476
 
615
477
class TestRepositoryConverter(TestCaseWithTransport):
616
478
 
617
479
    def test_convert_empty(self):
618
 
        t = get_transport(self.get_url('.'))
 
480
        source_format = TestRepositoryFormat1()
 
481
        target_format = TestRepositoryFormat2()
 
482
        repository.format_registry.register(source_format)
 
483
        self.addCleanup(repository.format_registry.remove,
 
484
            source_format)
 
485
        repository.format_registry.register(target_format)
 
486
        self.addCleanup(repository.format_registry.remove,
 
487
            target_format)
 
488
        t = self.get_transport()
619
489
        t.mkdir('repository')
620
490
        repo_dir = bzrdir.BzrDirMetaFormat1().initialize('repository')
621
 
        repo = weaverepo.RepositoryFormat7().initialize(repo_dir)
622
 
        target_format = knitrepo.RepositoryFormatKnit1()
 
491
        repo = TestRepositoryFormat1().initialize(repo_dir)
623
492
        converter = repository.CopyConverter(target_format)
624
493
        pb = bzrlib.ui.ui_factory.nested_progress_bar()
625
494
        try:
630
499
        self.assertTrue(isinstance(target_format, repo._format.__class__))
631
500
 
632
501
 
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
502
class TestRepositoryFormatKnit3(TestCaseWithTransport):
641
503
 
642
504
    def test_attribute__fetch_order(self):
663
525
        revision_tree.lock_read()
664
526
        try:
665
527
            self.assertRaises(errors.NoSuchFile, revision_tree.get_file_lines,
666
 
                revision_tree.inventory.root.file_id)
 
528
                revision_tree.get_root_id())
667
529
        finally:
668
530
            revision_tree.unlock()
669
531
        format = bzrdir.BzrDirMetaFormat1()
673
535
        revision_tree = tree.branch.repository.revision_tree('dull')
674
536
        revision_tree.lock_read()
675
537
        try:
676
 
            revision_tree.get_file_lines(revision_tree.inventory.root.file_id)
 
538
            revision_tree.get_file_lines(revision_tree.get_root_id())
677
539
        finally:
678
540
            revision_tree.unlock()
679
541
        tree.commit("Another dull commit", rev_id='dull2')
680
542
        revision_tree = tree.branch.repository.revision_tree('dull2')
681
543
        revision_tree.lock_read()
682
544
        self.addCleanup(revision_tree.unlock)
683
 
        self.assertEqual('dull', revision_tree.inventory.root.revision)
 
545
        self.assertEqual('dull',
 
546
                revision_tree.get_file_revision(revision_tree.get_root_id()))
684
547
 
685
548
    def test_supports_external_lookups(self):
686
549
        format = bzrdir.BzrDirMetaFormat1()
691
554
 
692
555
class Test2a(tests.TestCaseWithMemoryTransport):
693
556
 
 
557
    def test_chk_bytes_uses_custom_btree_parser(self):
 
558
        mt = self.make_branch_and_memory_tree('test', format='2a')
 
559
        mt.lock_write()
 
560
        self.addCleanup(mt.unlock)
 
561
        mt.add([''], ['root-id'])
 
562
        mt.commit('first')
 
563
        index = mt.branch.repository.chk_bytes._index._graph_index._indices[0]
 
564
        self.assertEqual(btree_index._gcchk_factory, index._leaf_factory)
 
565
        # It should also work if we re-open the repo
 
566
        repo = mt.branch.repository.bzrdir.open_repository()
 
567
        repo.lock_read()
 
568
        self.addCleanup(repo.unlock)
 
569
        index = repo.chk_bytes._index._graph_index._indices[0]
 
570
        self.assertEqual(btree_index._gcchk_factory, index._leaf_factory)
 
571
 
694
572
    def test_fetch_combines_groups(self):
695
573
        builder = self.make_branch_builder('source', format='2a')
696
574
        builder.start_series()
822
700
        target = self.make_repository('target', format='rich-root-pack')
823
701
        stream = source._get_source(target._format)
824
702
        # We don't want the child GroupCHKStreamSource
825
 
        self.assertIs(type(stream), repository.StreamSource)
 
703
        self.assertIs(type(stream), vf_repository.StreamSource)
826
704
 
827
705
    def test_get_stream_for_missing_keys_includes_all_chk_refs(self):
828
706
        source_builder = self.make_branch_builder('source',
855
733
 
856
734
        # On a regular pass, getting the inventories and chk pages for rev-2
857
735
        # would only get the newly created chk pages
858
 
        search = graph.SearchResult(set(['rev-2']), set(['rev-1']), 1,
 
736
        search = vf_search.SearchResult(set(['rev-2']), set(['rev-1']), 1,
859
737
                                    set(['rev-2']))
860
738
        simple_chk_records = []
861
739
        for vf_name, substream in source.get_stream(search):
904
782
        source = self.make_repository('source', format='pack-0.92')
905
783
        target = self.make_repository('target', format='pack-0.92')
906
784
        stream_source = source._get_source(target._format)
907
 
        self.assertIsInstance(stream_source, pack_repo.KnitPackStreamSource)
 
785
        self.assertIsInstance(stream_source, knitpack_repo.KnitPackStreamSource)
908
786
 
909
787
    def test_source_to_exact_pack_rich_root_pack(self):
910
788
        source = self.make_repository('source', format='rich-root-pack')
911
789
        target = self.make_repository('target', format='rich-root-pack')
912
790
        stream_source = source._get_source(target._format)
913
 
        self.assertIsInstance(stream_source, pack_repo.KnitPackStreamSource)
 
791
        self.assertIsInstance(stream_source, knitpack_repo.KnitPackStreamSource)
914
792
 
915
793
    def test_source_to_exact_pack_19(self):
916
794
        source = self.make_repository('source', format='1.9')
917
795
        target = self.make_repository('target', format='1.9')
918
796
        stream_source = source._get_source(target._format)
919
 
        self.assertIsInstance(stream_source, pack_repo.KnitPackStreamSource)
 
797
        self.assertIsInstance(stream_source, knitpack_repo.KnitPackStreamSource)
920
798
 
921
799
    def test_source_to_exact_pack_19_rich_root(self):
922
800
        source = self.make_repository('source', format='1.9-rich-root')
923
801
        target = self.make_repository('target', format='1.9-rich-root')
924
802
        stream_source = source._get_source(target._format)
925
 
        self.assertIsInstance(stream_source, pack_repo.KnitPackStreamSource)
 
803
        self.assertIsInstance(stream_source, knitpack_repo.KnitPackStreamSource)
926
804
 
927
805
    def test_source_to_remote_exact_pack_19(self):
928
806
        trans = self.make_smart_server('target')
931
809
        target = self.make_repository('target', format='1.9')
932
810
        target = repository.Repository.open(trans.base)
933
811
        stream_source = source._get_source(target._format)
934
 
        self.assertIsInstance(stream_source, pack_repo.KnitPackStreamSource)
 
812
        self.assertIsInstance(stream_source, knitpack_repo.KnitPackStreamSource)
935
813
 
936
814
    def test_stream_source_to_non_exact(self):
937
815
        source = self.make_repository('source', format='pack-0.92')
938
816
        target = self.make_repository('target', format='1.9')
939
817
        stream = source._get_source(target._format)
940
 
        self.assertIs(type(stream), repository.StreamSource)
 
818
        self.assertIs(type(stream), vf_repository.StreamSource)
941
819
 
942
820
    def test_stream_source_to_non_exact_rich_root(self):
943
821
        source = self.make_repository('source', format='1.9')
944
822
        target = self.make_repository('target', format='1.9-rich-root')
945
823
        stream = source._get_source(target._format)
946
 
        self.assertIs(type(stream), repository.StreamSource)
 
824
        self.assertIs(type(stream), vf_repository.StreamSource)
947
825
 
948
826
    def test_source_to_remote_non_exact_pack_19(self):
949
827
        trans = self.make_smart_server('target')
952
830
        target = self.make_repository('target', format='1.6')
953
831
        target = repository.Repository.open(trans.base)
954
832
        stream_source = source._get_source(target._format)
955
 
        self.assertIs(type(stream_source), repository.StreamSource)
 
833
        self.assertIs(type(stream_source), vf_repository.StreamSource)
956
834
 
957
835
    def test_stream_source_to_knit(self):
958
836
        source = self.make_repository('source', format='pack-0.92')
959
837
        target = self.make_repository('target', format='dirstate')
960
838
        stream = source._get_source(target._format)
961
 
        self.assertIs(type(stream), repository.StreamSource)
 
839
        self.assertIs(type(stream), vf_repository.StreamSource)
962
840
 
963
841
 
964
842
class TestDevelopment6FindParentIdsOfRevisions(TestCaseWithTransport):
966
844
 
967
845
    def setUp(self):
968
846
        super(TestDevelopment6FindParentIdsOfRevisions, self).setUp()
969
 
        self.builder = self.make_branch_builder('source',
970
 
            format='development6-rich-root')
 
847
        self.builder = self.make_branch_builder('source')
971
848
        self.builder.start_series()
972
849
        self.builder.build_snapshot('initial', None,
973
850
            [('add', ('', 'tree-root', 'directory', None))])
1043
920
            revision = _mod_revision.Revision('rev1a',
1044
921
                committer='jrandom@example.com', timestamp=0,
1045
922
                inventory_sha1='', timezone=0, message='foo', parent_ids=[])
1046
 
            repo.add_revision('rev1a',revision, inv)
 
923
            repo.add_revision('rev1a', revision, inv)
1047
924
 
1048
925
            # make rev1b, which has no Revision, but has an Inventory, and
1049
926
            # file1
1084
961
        revision = _mod_revision.Revision(revision_id,
1085
962
            committer='jrandom@example.com', timestamp=0, inventory_sha1='',
1086
963
            timezone=0, message='foo', parent_ids=parent_ids)
1087
 
        repo.add_revision(revision_id,revision, inv)
 
964
        repo.add_revision(revision_id, revision, inv)
1088
965
 
1089
966
    def add_file(self, repo, inv, filename, revision, parents):
1090
967
        file_id = filename + '-id'
1118
995
class TestRepositoryPackCollection(TestCaseWithTransport):
1119
996
 
1120
997
    def get_format(self):
1121
 
        return bzrdir.format_registry.make_bzrdir('pack-0.92')
 
998
        return controldir.format_registry.make_bzrdir('pack-0.92')
1122
999
 
1123
1000
    def get_packs(self):
1124
1001
        format = self.get_format()
1220
1097
            sorted(set([osutils.splitext(n)[0] for n in
1221
1098
                        packs._index_transport.list_dir('.')])))
1222
1099
 
 
1100
    def test__obsolete_packs_missing_directory(self):
 
1101
        tree, r, packs, revs = self.make_packs_and_alt_repo(write_lock=True)
 
1102
        r.control_transport.rmdir('obsolete_packs')
 
1103
        names = packs.names()
 
1104
        pack = packs.get_pack_by_name(names[0])
 
1105
        # Schedule this one for removal
 
1106
        packs._remove_pack_from_memory(pack)
 
1107
        # Now trigger the obsoletion, and ensure that all the remaining files
 
1108
        # are still renamed
 
1109
        packs._obsolete_packs([pack])
 
1110
        self.assertEqual([n + '.pack' for n in names[1:]],
 
1111
                         sorted(packs._pack_transport.list_dir('.')))
 
1112
        # names[0] should not be present in the index anymore
 
1113
        self.assertEqual(names[1:],
 
1114
            sorted(set([osutils.splitext(n)[0] for n in
 
1115
                        packs._index_transport.list_dir('.')])))
 
1116
 
1223
1117
    def test_pack_distribution_zero(self):
1224
1118
        packs = self.get_packs()
1225
1119
        self.assertEqual([0], packs.pack_distribution(0))
1495
1389
        obsolete_names = set([osutils.splitext(n)[0] for n in obsolete_packs])
1496
1390
        self.assertEqual([pack.name], sorted(obsolete_names))
1497
1391
 
 
1392
    def test_pack_no_obsolete_packs_directory(self):
 
1393
        """Bug #314314, don't fail if obsolete_packs directory does
 
1394
        not exist."""
 
1395
        tree, r, packs, revs = self.make_packs_and_alt_repo(write_lock=True)
 
1396
        r.control_transport.rmdir('obsolete_packs')
 
1397
        packs._clear_obsolete_packs()
1498
1398
 
1499
1399
 
1500
1400
class TestPack(TestCaseWithTransport):
1601
1501
        # Because of how they were built, they correspond to
1602
1502
        # ['D', 'C', 'B', 'A']
1603
1503
        packs = b.repository._pack_collection.packs
1604
 
        packer = pack_repo.Packer(b.repository._pack_collection,
 
1504
        packer = knitpack_repo.KnitPacker(b.repository._pack_collection,
1605
1505
                                  packs, 'testing',
1606
1506
                                  revision_ids=['B', 'C'])
1607
1507
        # Now, when we are copying the B & C revisions, their pack files should
1621
1521
        return repo._pack_collection
1622
1522
 
1623
1523
    def test_open_pack_will_optimise(self):
1624
 
        packer = pack_repo.OptimisingPacker(self.get_pack_collection(),
 
1524
        packer = knitpack_repo.OptimisingKnitPacker(self.get_pack_collection(),
1625
1525
                                            [], '.test')
1626
1526
        new_pack = packer.open_pack()
1627
1527
        self.addCleanup(new_pack.abort) # ensure cleanup
1632
1532
        self.assertTrue(new_pack.signature_index._optimize_for_size)
1633
1533
 
1634
1534
 
 
1535
class TestGCCHKPacker(TestCaseWithTransport):
 
1536
 
 
1537
    def make_abc_branch(self):
 
1538
        builder = self.make_branch_builder('source')
 
1539
        builder.start_series()
 
1540
        builder.build_snapshot('A', None, [
 
1541
            ('add', ('', 'root-id', 'directory', None)),
 
1542
            ('add', ('file', 'file-id', 'file', 'content\n')),
 
1543
            ])
 
1544
        builder.build_snapshot('B', ['A'], [
 
1545
            ('add', ('dir', 'dir-id', 'directory', None))])
 
1546
        builder.build_snapshot('C', ['B'], [
 
1547
            ('modify', ('file-id', 'new content\n'))])
 
1548
        builder.finish_series()
 
1549
        return builder.get_branch()
 
1550
 
 
1551
    def make_branch_with_disjoint_inventory_and_revision(self):
 
1552
        """a repo with separate packs for a revisions Revision and Inventory.
 
1553
 
 
1554
        There will be one pack file that holds the Revision content, and one
 
1555
        for the Inventory content.
 
1556
 
 
1557
        :return: (repository,
 
1558
                  pack_name_with_rev_A_Revision,
 
1559
                  pack_name_with_rev_A_Inventory,
 
1560
                  pack_name_with_rev_C_content)
 
1561
        """
 
1562
        b_source = self.make_abc_branch()
 
1563
        b_base = b_source.bzrdir.sprout('base', revision_id='A').open_branch()
 
1564
        b_stacked = b_base.bzrdir.sprout('stacked', stacked=True).open_branch()
 
1565
        b_stacked.lock_write()
 
1566
        self.addCleanup(b_stacked.unlock)
 
1567
        b_stacked.fetch(b_source, 'B')
 
1568
        # Now re-open the stacked repo directly (no fallbacks) so that we can
 
1569
        # fill in the A rev.
 
1570
        repo_not_stacked = b_stacked.bzrdir.open_repository()
 
1571
        repo_not_stacked.lock_write()
 
1572
        self.addCleanup(repo_not_stacked.unlock)
 
1573
        # Now we should have a pack file with A's inventory, but not its
 
1574
        # Revision
 
1575
        self.assertEqual([('A',), ('B',)],
 
1576
                         sorted(repo_not_stacked.inventories.keys()))
 
1577
        self.assertEqual([('B',)],
 
1578
                         sorted(repo_not_stacked.revisions.keys()))
 
1579
        stacked_pack_names = repo_not_stacked._pack_collection.names()
 
1580
        # We have a couple names here, figure out which has A's inventory
 
1581
        for name in stacked_pack_names:
 
1582
            pack = repo_not_stacked._pack_collection.get_pack_by_name(name)
 
1583
            keys = [n[1] for n in pack.inventory_index.iter_all_entries()]
 
1584
            if ('A',) in keys:
 
1585
                inv_a_pack_name = name
 
1586
                break
 
1587
        else:
 
1588
            self.fail('Could not find pack containing A\'s inventory')
 
1589
        repo_not_stacked.fetch(b_source.repository, 'A')
 
1590
        self.assertEqual([('A',), ('B',)],
 
1591
                         sorted(repo_not_stacked.revisions.keys()))
 
1592
        new_pack_names = set(repo_not_stacked._pack_collection.names())
 
1593
        rev_a_pack_names = new_pack_names.difference(stacked_pack_names)
 
1594
        self.assertEqual(1, len(rev_a_pack_names))
 
1595
        rev_a_pack_name = list(rev_a_pack_names)[0]
 
1596
        # Now fetch 'C', so we have a couple pack files to join
 
1597
        repo_not_stacked.fetch(b_source.repository, 'C')
 
1598
        rev_c_pack_names = set(repo_not_stacked._pack_collection.names())
 
1599
        rev_c_pack_names = rev_c_pack_names.difference(new_pack_names)
 
1600
        self.assertEqual(1, len(rev_c_pack_names))
 
1601
        rev_c_pack_name = list(rev_c_pack_names)[0]
 
1602
        return (repo_not_stacked, rev_a_pack_name, inv_a_pack_name,
 
1603
                rev_c_pack_name)
 
1604
 
 
1605
    def test_pack_with_distant_inventories(self):
 
1606
        # See https://bugs.launchpad.net/bzr/+bug/437003
 
1607
        # When repacking, it is possible to have an inventory in a different
 
1608
        # pack file than the associated revision. An autopack can then come
 
1609
        # along, and miss that inventory, and complain.
 
1610
        (repo, rev_a_pack_name, inv_a_pack_name, rev_c_pack_name
 
1611
         ) = self.make_branch_with_disjoint_inventory_and_revision()
 
1612
        a_pack = repo._pack_collection.get_pack_by_name(rev_a_pack_name)
 
1613
        c_pack = repo._pack_collection.get_pack_by_name(rev_c_pack_name)
 
1614
        packer = groupcompress_repo.GCCHKPacker(repo._pack_collection,
 
1615
                    [a_pack, c_pack], '.test-pack')
 
1616
        # This would raise ValueError in bug #437003, but should not raise an
 
1617
        # error once fixed.
 
1618
        packer.pack()
 
1619
 
 
1620
    def test_pack_with_missing_inventory(self):
 
1621
        # Similar to test_pack_with_missing_inventory, but this time, we force
 
1622
        # the A inventory to actually be gone from the repository.
 
1623
        (repo, rev_a_pack_name, inv_a_pack_name, rev_c_pack_name
 
1624
         ) = self.make_branch_with_disjoint_inventory_and_revision()
 
1625
        inv_a_pack = repo._pack_collection.get_pack_by_name(inv_a_pack_name)
 
1626
        repo._pack_collection._remove_pack_from_memory(inv_a_pack)
 
1627
        packer = groupcompress_repo.GCCHKPacker(repo._pack_collection,
 
1628
            repo._pack_collection.all_packs(), '.test-pack')
 
1629
        e = self.assertRaises(ValueError, packer.pack)
 
1630
        packer.new_pack.abort()
 
1631
        self.assertContainsRe(str(e),
 
1632
            r"We are missing inventories for revisions: .*'A'")
 
1633
 
 
1634
 
1635
1635
class TestCrossFormatPacks(TestCaseWithTransport):
1636
1636
 
1637
1637
    def log_pack(self, hint=None):
1652
1652
        self.addCleanup(target.unlock)
1653
1653
        source = source_tree.branch.repository._get_source(target._format)
1654
1654
        self.orig_pack = target.pack
1655
 
        target.pack = self.log_pack
 
1655
        self.overrideAttr(target, "pack", self.log_pack)
1656
1656
        search = target.search_missing_revision_ids(
1657
 
            source_tree.branch.repository, tip)
 
1657
            source_tree.branch.repository, revision_ids=[tip])
1658
1658
        stream = source.get_stream(search)
1659
1659
        from_format = source_tree.branch.repository._format
1660
1660
        sink = target._get_sink()
1676
1676
        self.addCleanup(target.unlock)
1677
1677
        source = source_tree.branch.repository
1678
1678
        self.orig_pack = target.pack
1679
 
        target.pack = self.log_pack
 
1679
        self.overrideAttr(target, "pack", self.log_pack)
1680
1680
        target.fetch(source)
1681
1681
        if expect_pack_called:
1682
1682
            self.assertLength(1, self.calls)
1710
1710
    def test_IDS_format_same_no(self):
1711
1711
        # When the formats are the same, pack is not called.
1712
1712
        self.run_fetch('2a', '2a', False)
 
1713
 
 
1714
 
 
1715
class Test_LazyListJoin(tests.TestCase):
 
1716
 
 
1717
    def test__repr__(self):
 
1718
        lazy = repository._LazyListJoin(['a'], ['b'])
 
1719
        self.assertEqual("bzrlib.repository._LazyListJoin((['a'], ['b']))",
 
1720
                         repr(lazy))
 
1721
 
 
1722
 
 
1723
class TestFeatures(tests.TestCaseWithTransport):
 
1724
 
 
1725
    def test_open_with_present_feature(self):
 
1726
        self.addCleanup(
 
1727
            repository.RepositoryFormatMetaDir.unregister_feature,
 
1728
            "makes-cheese-sandwich")
 
1729
        repository.RepositoryFormatMetaDir.register_feature(
 
1730
            "makes-cheese-sandwich")
 
1731
        repo = self.make_repository('.')
 
1732
        repo.lock_write()
 
1733
        repo._format.features["makes-cheese-sandwich"] = "required"
 
1734
        repo._format.check_support_status(False)
 
1735
        repo.unlock()
 
1736
 
 
1737
    def test_open_with_missing_required_feature(self):
 
1738
        repo = self.make_repository('.')
 
1739
        repo.lock_write()
 
1740
        repo._format.features["makes-cheese-sandwich"] = "required"
 
1741
        self.assertRaises(errors.MissingFeature,
 
1742
            repo._format.check_support_status, False)