/brz/remove-bazaar

To get this branch, use:
bzr branch http://gegoxaren.bato24.eu/bzr/brz/remove-bazaar
4634.126.1 by John Arbash Meinel
(jam) Fix bug #507566, concurrent autopacking correctness.
1
# Copyright (C) 2006-2010 Canonical Ltd
1685.1.63 by Martin Pool
Small Transport fixups
2
#
1534.4.40 by Robert Collins
Add RepositoryFormats and allow bzrdir.open or create _repository to be used.
3
# This program is free software; you can redistribute it and/or modify
4
# it under the terms of the GNU General Public License as published by
5
# the Free Software Foundation; either version 2 of the License, or
6
# (at your option) any later version.
1685.1.63 by Martin Pool
Small Transport fixups
7
#
1534.4.40 by Robert Collins
Add RepositoryFormats and allow bzrdir.open or create _repository to be used.
8
# This program is distributed in the hope that it will be useful,
9
# but WITHOUT ANY WARRANTY; without even the implied warranty of
10
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
11
# GNU General Public License for more details.
1685.1.63 by Martin Pool
Small Transport fixups
12
#
1534.4.40 by Robert Collins
Add RepositoryFormats and allow bzrdir.open or create _repository to be used.
13
# You should have received a copy of the GNU General Public License
14
# along with this program; if not, write to the Free Software
4183.7.1 by Sabin Iacob
update FSF mailing address
15
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
1534.4.40 by Robert Collins
Add RepositoryFormats and allow bzrdir.open or create _repository to be used.
16
17
"""Tests for the Repository facility that are not interface tests.
18
3689.1.4 by John Arbash Meinel
Doc strings that reference repository_implementations
19
For interface tests see tests/per_repository/*.py.
1534.4.40 by Robert Collins
Add RepositoryFormats and allow bzrdir.open or create _repository to be used.
20
21
For concrete class tests see this file, and for storage formats tests
22
also see this file.
23
"""
24
1773.4.1 by Martin Pool
Add pyflakes makefile target; fix many warnings
25
from stat import S_ISDIR
4789.25.4 by John Arbash Meinel
Turn a repository format 7 failure into a KnownFailure.
26
import sys
1534.4.40 by Robert Collins
Add RepositoryFormats and allow bzrdir.open or create _repository to be used.
27
1556.1.4 by Robert Collins
Add a new format for what will become knit, and the surrounding logic to upgrade repositories within metadirs, and tests for the same.
28
import bzrlib
5121.2.2 by Jelmer Vernooij
Remove more unused imports in the tests.
29
from bzrlib.errors import (NoSuchFile,
1534.4.40 by Robert Collins
Add RepositoryFormats and allow bzrdir.open or create _repository to be used.
30
                           UnknownFormatError,
31
                           UnsupportedFormatError,
32
                           )
4360.4.3 by John Arbash Meinel
Introduce a KnitPackStreamSource which is used when
33
from bzrlib import (
5365.5.20 by John Arbash Meinel
Add some tests that check the leaf factory is correct.
34
    btree_index,
4360.4.3 by John Arbash Meinel
Introduce a KnitPackStreamSource which is used when
35
    graph,
36
    tests,
5609.9.1 by Martin
Blindly change all users of get_transport to address the function via the transport module
37
    transport,
4360.4.3 by John Arbash Meinel
Introduce a KnitPackStreamSource which is used when
38
    )
3735.1.1 by Robert Collins
Add development2 formats using BTree indices.
39
from bzrlib.btree_index import BTreeBuilder, BTreeGraphIndex
5121.2.2 by Jelmer Vernooij
Remove more unused imports in the tests.
40
from bzrlib.index import GraphIndex
2241.1.1 by Martin Pool
Change RepositoryFormat to use a Registry rather than ad-hoc dictionary
41
from bzrlib.repository import RepositoryFormat
2670.3.5 by Andrew Bennetts
Remove get_stream_as_bytes from KnitVersionedFile's API, make it a function in knitrepo.py instead.
42
from bzrlib.tests import (
43
    TestCase,
44
    TestCaseWithTransport,
45
    )
2241.1.1 by Martin Pool
Change RepositoryFormat to use a Registry rather than ad-hoc dictionary
46
from bzrlib import (
2535.3.41 by Andrew Bennetts
Add tests for InterRemoteToOther.is_compatible.
47
    bzrdir,
48
    errors,
2535.3.57 by Andrew Bennetts
Perform some sanity checking of data streams rather than blindly inserting them into our repository.
49
    inventory,
2929.3.5 by Vincent Ladeuil
New files, same warnings, same fixes.
50
    osutils,
2241.1.1 by Martin Pool
Change RepositoryFormat to use a Registry rather than ad-hoc dictionary
51
    repository,
2535.3.57 by Andrew Bennetts
Perform some sanity checking of data streams rather than blindly inserting them into our repository.
52
    revision as _mod_revision,
2241.1.1 by Martin Pool
Change RepositoryFormat to use a Registry rather than ad-hoc dictionary
53
    upgrade,
4634.126.1 by John Arbash Meinel
(jam) Fix bug #507566, concurrent autopacking correctness.
54
    versionedfile,
2241.1.1 by Martin Pool
Change RepositoryFormat to use a Registry rather than ad-hoc dictionary
55
    workingtree,
56
    )
3735.42.5 by John Arbash Meinel
Change the tests so we now just use a direct test that _get_source is
57
from bzrlib.repofmt import (
58
    groupcompress_repo,
59
    knitrepo,
60
    pack_repo,
61
    weaverepo,
62
    )
1534.4.40 by Robert Collins
Add RepositoryFormats and allow bzrdir.open or create _repository to be used.
63
64
65
class TestDefaultFormat(TestCase):
66
1534.4.41 by Robert Collins
Branch now uses BzrDir reasonably sanely.
67
    def test_get_set_default_format(self):
2204.5.3 by Aaron Bentley
zap old repository default handling
68
        old_default = bzrdir.format_registry.get('default')
69
        private_default = old_default().repository_format.__class__
1534.4.40 by Robert Collins
Add RepositoryFormats and allow bzrdir.open or create _repository to be used.
70
        old_format = repository.RepositoryFormat.get_default_format()
1910.2.33 by Aaron Bentley
Fix default format test
71
        self.assertTrue(isinstance(old_format, private_default))
2204.5.3 by Aaron Bentley
zap old repository default handling
72
        def make_sample_bzrdir():
73
            my_bzrdir = bzrdir.BzrDirMetaFormat1()
74
            my_bzrdir.repository_format = SampleRepositoryFormat()
75
            return my_bzrdir
76
        bzrdir.format_registry.remove('default')
77
        bzrdir.format_registry.register('sample', make_sample_bzrdir, '')
78
        bzrdir.format_registry.set_default('sample')
1534.4.40 by Robert Collins
Add RepositoryFormats and allow bzrdir.open or create _repository to be used.
79
        # creating a repository should now create an instrumented dir.
80
        try:
1534.4.47 by Robert Collins
Split out repository into .bzr/repository
81
            # the default branch format is used by the meta dir format
82
            # which is not the default bzrdir format at this point
1685.1.63 by Martin Pool
Small Transport fixups
83
            dir = bzrdir.BzrDirMetaFormat1().initialize('memory:///')
1534.4.47 by Robert Collins
Split out repository into .bzr/repository
84
            result = dir.create_repository()
1534.4.40 by Robert Collins
Add RepositoryFormats and allow bzrdir.open or create _repository to be used.
85
            self.assertEqual(result, 'A bzr repository dir')
2241.1.1 by Martin Pool
Change RepositoryFormat to use a Registry rather than ad-hoc dictionary
86
        finally:
2204.5.3 by Aaron Bentley
zap old repository default handling
87
            bzrdir.format_registry.remove('default')
2363.5.14 by Aaron Bentley
Prevent repository.get_set_default_format from corrupting inventory
88
            bzrdir.format_registry.remove('sample')
2204.5.3 by Aaron Bentley
zap old repository default handling
89
            bzrdir.format_registry.register('default', old_default, '')
90
        self.assertIsInstance(repository.RepositoryFormat.get_default_format(),
91
                              old_format.__class__)
1534.4.40 by Robert Collins
Add RepositoryFormats and allow bzrdir.open or create _repository to be used.
92
93
94
class SampleRepositoryFormat(repository.RepositoryFormat):
95
    """A sample format
96
3943.8.1 by Marius Kruger
remove all trailing whitespace from bzr source
97
    this format is initializable, unsupported to aid in testing the
1534.4.47 by Robert Collins
Split out repository into .bzr/repository
98
    open and open(unsupported=True) routines.
1534.4.40 by Robert Collins
Add RepositoryFormats and allow bzrdir.open or create _repository to be used.
99
    """
100
101
    def get_format_string(self):
102
        """See RepositoryFormat.get_format_string()."""
103
        return "Sample .bzr repository format."
104
1534.6.1 by Robert Collins
allow API creation of shared repositories
105
    def initialize(self, a_bzrdir, shared=False):
1534.4.40 by Robert Collins
Add RepositoryFormats and allow bzrdir.open or create _repository to be used.
106
        """Initialize a repository in a BzrDir"""
1534.4.47 by Robert Collins
Split out repository into .bzr/repository
107
        t = a_bzrdir.get_repository_transport(self)
1955.3.13 by John Arbash Meinel
Run the full test suite, and fix up any deprecation warnings.
108
        t.put_bytes('format', self.get_format_string())
1534.4.40 by Robert Collins
Add RepositoryFormats and allow bzrdir.open or create _repository to be used.
109
        return 'A bzr repository dir'
110
111
    def is_supported(self):
112
        return False
113
1534.4.47 by Robert Collins
Split out repository into .bzr/repository
114
    def open(self, a_bzrdir, _found=False):
1534.4.40 by Robert Collins
Add RepositoryFormats and allow bzrdir.open or create _repository to be used.
115
        return "opened repository."
1534.4.41 by Robert Collins
Branch now uses BzrDir reasonably sanely.
116
117
1534.4.47 by Robert Collins
Split out repository into .bzr/repository
118
class TestRepositoryFormat(TestCaseWithTransport):
119
    """Tests for the Repository format detection used by the bzr meta dir facility.BzrBranchFormat facility."""
120
121
    def test_find_format(self):
122
        # is the right format object found for a repository?
123
        # create a branch with a few known format objects.
3943.8.1 by Marius Kruger
remove all trailing whitespace from bzr source
124
        # this is not quite the same as
1534.4.47 by Robert Collins
Split out repository into .bzr/repository
125
        self.build_tree(["foo/", "bar/"])
126
        def check_format(format, url):
127
            dir = format._matchingbzrdir.initialize(url)
128
            format.initialize(dir)
5609.9.1 by Martin
Blindly change all users of get_transport to address the function via the transport module
129
            t = transport.get_transport(url)
1534.4.47 by Robert Collins
Split out repository into .bzr/repository
130
            found_format = repository.RepositoryFormat.find_format(dir)
131
            self.failUnless(isinstance(found_format, format.__class__))
2241.1.4 by Martin Pool
Moved old weave-based repository formats into bzrlib.repofmt.weaverepo.
132
        check_format(weaverepo.RepositoryFormat7(), "bar")
3943.8.1 by Marius Kruger
remove all trailing whitespace from bzr source
133
1534.4.47 by Robert Collins
Split out repository into .bzr/repository
134
    def test_find_format_no_repository(self):
135
        dir = bzrdir.BzrDirMetaFormat1().initialize(self.get_url())
136
        self.assertRaises(errors.NoRepositoryPresent,
137
                          repository.RepositoryFormat.find_format,
138
                          dir)
139
140
    def test_find_format_unknown_format(self):
141
        dir = bzrdir.BzrDirMetaFormat1().initialize(self.get_url())
142
        SampleRepositoryFormat().initialize(dir)
143
        self.assertRaises(UnknownFormatError,
144
                          repository.RepositoryFormat.find_format,
145
                          dir)
146
147
    def test_register_unregister_format(self):
148
        format = SampleRepositoryFormat()
149
        # make a control dir
150
        dir = bzrdir.BzrDirMetaFormat1().initialize(self.get_url())
151
        # make a repo
152
        format.initialize(dir)
153
        # register a format for it.
154
        repository.RepositoryFormat.register_format(format)
155
        # which repository.Open will refuse (not supported)
156
        self.assertRaises(UnsupportedFormatError, repository.Repository.open, self.get_url())
157
        # but open(unsupported) will work
158
        self.assertEqual(format.open(dir), "opened repository.")
159
        # unregister the format
160
        repository.RepositoryFormat.unregister_format(format)
161
162
1534.4.41 by Robert Collins
Branch now uses BzrDir reasonably sanely.
163
class TestFormat6(TestCaseWithTransport):
164
3565.3.1 by Robert Collins
* The generic fetch code now uses two attributes on Repository objects
165
    def test_attribute__fetch_order(self):
166
        """Weaves need topological data insertion."""
167
        control = bzrdir.BzrDirFormat6().initialize(self.get_url())
168
        repo = weaverepo.RepositoryFormat6().initialize(control)
4053.1.4 by Robert Collins
Move the fetch control attributes from Repository to RepositoryFormat.
169
        self.assertEqual('topological', repo._format._fetch_order)
3565.3.1 by Robert Collins
* The generic fetch code now uses two attributes on Repository objects
170
171
    def test_attribute__fetch_uses_deltas(self):
172
        """Weaves do not reuse deltas."""
173
        control = bzrdir.BzrDirFormat6().initialize(self.get_url())
174
        repo = weaverepo.RepositoryFormat6().initialize(control)
4053.1.4 by Robert Collins
Move the fetch control attributes from Repository to RepositoryFormat.
175
        self.assertEqual(False, repo._format._fetch_uses_deltas)
3565.3.1 by Robert Collins
* The generic fetch code now uses two attributes on Repository objects
176
3565.3.4 by Robert Collins
Defer decision to reconcile to the repository being fetched into.
177
    def test_attribute__fetch_reconcile(self):
178
        """Weave repositories need a reconcile after fetch."""
179
        control = bzrdir.BzrDirFormat6().initialize(self.get_url())
180
        repo = weaverepo.RepositoryFormat6().initialize(control)
4053.1.4 by Robert Collins
Move the fetch control attributes from Repository to RepositoryFormat.
181
        self.assertEqual(True, repo._format._fetch_reconcile)
3565.3.4 by Robert Collins
Defer decision to reconcile to the repository being fetched into.
182
1534.4.41 by Robert Collins
Branch now uses BzrDir reasonably sanely.
183
    def test_no_ancestry_weave(self):
184
        control = bzrdir.BzrDirFormat6().initialize(self.get_url())
2241.1.4 by Martin Pool
Moved old weave-based repository formats into bzrlib.repofmt.weaverepo.
185
        repo = weaverepo.RepositoryFormat6().initialize(control)
1534.4.41 by Robert Collins
Branch now uses BzrDir reasonably sanely.
186
        # We no longer need to create the ancestry.weave file
187
        # since it is *never* used.
188
        self.assertRaises(NoSuchFile,
189
                          control.transport.get,
190
                          'ancestry.weave')
191
3221.3.1 by Robert Collins
* Repository formats have a new supported-feature attribute
192
    def test_supports_external_lookups(self):
193
        control = bzrdir.BzrDirFormat6().initialize(self.get_url())
194
        repo = weaverepo.RepositoryFormat6().initialize(control)
195
        self.assertFalse(repo._format.supports_external_lookups)
196
1534.4.47 by Robert Collins
Split out repository into .bzr/repository
197
198
class TestFormat7(TestCaseWithTransport):
3565.3.1 by Robert Collins
* The generic fetch code now uses two attributes on Repository objects
199
200
    def test_attribute__fetch_order(self):
201
        """Weaves need topological data insertion."""
202
        control = bzrdir.BzrDirMetaFormat1().initialize(self.get_url())
203
        repo = weaverepo.RepositoryFormat7().initialize(control)
4053.1.4 by Robert Collins
Move the fetch control attributes from Repository to RepositoryFormat.
204
        self.assertEqual('topological', repo._format._fetch_order)
3565.3.1 by Robert Collins
* The generic fetch code now uses two attributes on Repository objects
205
206
    def test_attribute__fetch_uses_deltas(self):
207
        """Weaves do not reuse deltas."""
208
        control = bzrdir.BzrDirMetaFormat1().initialize(self.get_url())
209
        repo = weaverepo.RepositoryFormat7().initialize(control)
4053.1.4 by Robert Collins
Move the fetch control attributes from Repository to RepositoryFormat.
210
        self.assertEqual(False, repo._format._fetch_uses_deltas)
3565.3.1 by Robert Collins
* The generic fetch code now uses two attributes on Repository objects
211
3565.3.4 by Robert Collins
Defer decision to reconcile to the repository being fetched into.
212
    def test_attribute__fetch_reconcile(self):
213
        """Weave repositories need a reconcile after fetch."""
214
        control = bzrdir.BzrDirMetaFormat1().initialize(self.get_url())
215
        repo = weaverepo.RepositoryFormat7().initialize(control)
4053.1.4 by Robert Collins
Move the fetch control attributes from Repository to RepositoryFormat.
216
        self.assertEqual(True, repo._format._fetch_reconcile)
3565.3.4 by Robert Collins
Defer decision to reconcile to the repository being fetched into.
217
1534.4.47 by Robert Collins
Split out repository into .bzr/repository
218
    def test_disk_layout(self):
219
        control = bzrdir.BzrDirMetaFormat1().initialize(self.get_url())
2241.1.4 by Martin Pool
Moved old weave-based repository formats into bzrlib.repofmt.weaverepo.
220
        repo = weaverepo.RepositoryFormat7().initialize(control)
1534.5.3 by Robert Collins
Make format 4/5/6 branches share a single LockableFiles instance across wt/branch/repository.
221
        # in case of side effects of locking.
222
        repo.lock_write()
223
        repo.unlock()
1534.4.47 by Robert Collins
Split out repository into .bzr/repository
224
        # we want:
225
        # format 'Bazaar-NG Repository format 7'
226
        # lock ''
227
        # inventory.weave == empty_weave
228
        # empty revision-store directory
229
        # empty weaves directory
230
        t = control.get_repository_transport(None)
231
        self.assertEqualDiff('Bazaar-NG Repository format 7',
232
                             t.get('format').read())
233
        self.assertTrue(S_ISDIR(t.stat('revision-store').st_mode))
234
        self.assertTrue(S_ISDIR(t.stat('weaves').st_mode))
235
        self.assertEqualDiff('# bzr weave file v5\n'
236
                             'w\n'
237
                             'W\n',
238
                             t.get('inventory.weave').read())
3350.6.4 by Robert Collins
First cut at pluralised VersionedFiles. Some rather massive API incompatabilities, primarily because of the difficulty of coherence among competing stores.
239
        # Creating a file with id Foo:Bar results in a non-escaped file name on
240
        # disk.
241
        control.create_branch()
242
        tree = control.create_workingtree()
243
        tree.add(['foo'], ['Foo:Bar'], ['file'])
244
        tree.put_file_bytes_non_atomic('Foo:Bar', 'content\n')
4789.25.4 by John Arbash Meinel
Turn a repository format 7 failure into a KnownFailure.
245
        try:
246
            tree.commit('first post', rev_id='first')
247
        except errors.IllegalPath:
248
            if sys.platform != 'win32':
249
                raise
250
            self.knownFailure('Foo:Bar cannot be used as a file-id on windows'
251
                              ' in repo format 7')
252
            return
3350.6.4 by Robert Collins
First cut at pluralised VersionedFiles. Some rather massive API incompatabilities, primarily because of the difficulty of coherence among competing stores.
253
        self.assertEqualDiff(
254
            '# bzr weave file v5\n'
255
            'i\n'
256
            '1 7fe70820e08a1aac0ef224d9c66ab66831cc4ab1\n'
257
            'n first\n'
258
            '\n'
259
            'w\n'
260
            '{ 0\n'
261
            '. content\n'
262
            '}\n'
263
            'W\n',
264
            t.get('weaves/74/Foo%3ABar.weave').read())
1534.6.1 by Robert Collins
allow API creation of shared repositories
265
266
    def test_shared_disk_layout(self):
267
        control = bzrdir.BzrDirMetaFormat1().initialize(self.get_url())
2241.1.4 by Martin Pool
Moved old weave-based repository formats into bzrlib.repofmt.weaverepo.
268
        repo = weaverepo.RepositoryFormat7().initialize(control, shared=True)
1534.6.1 by Robert Collins
allow API creation of shared repositories
269
        # we want:
270
        # format 'Bazaar-NG Repository format 7'
271
        # inventory.weave == empty_weave
272
        # empty revision-store directory
273
        # empty weaves directory
274
        # a 'shared-storage' marker file.
1553.5.49 by Martin Pool
Use LockDirs for repo format 7
275
        # lock is not present when unlocked
1534.6.1 by Robert Collins
allow API creation of shared repositories
276
        t = control.get_repository_transport(None)
277
        self.assertEqualDiff('Bazaar-NG Repository format 7',
278
                             t.get('format').read())
279
        self.assertEqualDiff('', t.get('shared-storage').read())
280
        self.assertTrue(S_ISDIR(t.stat('revision-store').st_mode))
281
        self.assertTrue(S_ISDIR(t.stat('weaves').st_mode))
282
        self.assertEqualDiff('# bzr weave file v5\n'
283
                             'w\n'
284
                             'W\n',
285
                             t.get('inventory.weave').read())
1553.5.49 by Martin Pool
Use LockDirs for repo format 7
286
        self.assertFalse(t.has('branch-lock'))
287
1553.5.56 by Martin Pool
Format 7 repo now uses LockDir!
288
    def test_creates_lockdir(self):
1553.5.49 by Martin Pool
Use LockDirs for repo format 7
289
        """Make sure it appears to be controlled by a LockDir existence"""
290
        control = bzrdir.BzrDirMetaFormat1().initialize(self.get_url())
2241.1.4 by Martin Pool
Moved old weave-based repository formats into bzrlib.repofmt.weaverepo.
291
        repo = weaverepo.RepositoryFormat7().initialize(control, shared=True)
1553.5.49 by Martin Pool
Use LockDirs for repo format 7
292
        t = control.get_repository_transport(None)
3943.8.1 by Marius Kruger
remove all trailing whitespace from bzr source
293
        # TODO: Should check there is a 'lock' toplevel directory,
1553.5.58 by Martin Pool
Change LockDirs to format "lock-name/held/info"
294
        # regardless of contents
295
        self.assertFalse(t.has('lock/held/info'))
1553.5.49 by Martin Pool
Use LockDirs for repo format 7
296
        repo.lock_write()
1658.1.4 by Martin Pool
Quieten warning from TestFormat7.test_creates_lockdir about failing to unlock
297
        try:
298
            self.assertTrue(t.has('lock/held/info'))
299
        finally:
300
            # unlock so we don't get a warning about failing to do so
301
            repo.unlock()
1553.5.56 by Martin Pool
Format 7 repo now uses LockDir!
302
303
    def test_uses_lockdir(self):
304
        """repo format 7 actually locks on lockdir"""
305
        base_url = self.get_url()
306
        control = bzrdir.BzrDirMetaFormat1().initialize(base_url)
2241.1.4 by Martin Pool
Moved old weave-based repository formats into bzrlib.repofmt.weaverepo.
307
        repo = weaverepo.RepositoryFormat7().initialize(control, shared=True)
1553.5.56 by Martin Pool
Format 7 repo now uses LockDir!
308
        t = control.get_repository_transport(None)
309
        repo.lock_write()
310
        repo.unlock()
311
        del repo
312
        # make sure the same lock is created by opening it
313
        repo = repository.Repository.open(base_url)
314
        repo.lock_write()
1553.5.58 by Martin Pool
Change LockDirs to format "lock-name/held/info"
315
        self.assertTrue(t.has('lock/held/info'))
1553.5.56 by Martin Pool
Format 7 repo now uses LockDir!
316
        repo.unlock()
1553.5.58 by Martin Pool
Change LockDirs to format "lock-name/held/info"
317
        self.assertFalse(t.has('lock/held/info'))
1534.6.5 by Robert Collins
Cloning of repos preserves shared and make-working-tree attributes.
318
319
    def test_shared_no_tree_disk_layout(self):
320
        control = bzrdir.BzrDirMetaFormat1().initialize(self.get_url())
2241.1.4 by Martin Pool
Moved old weave-based repository formats into bzrlib.repofmt.weaverepo.
321
        repo = weaverepo.RepositoryFormat7().initialize(control, shared=True)
1534.6.5 by Robert Collins
Cloning of repos preserves shared and make-working-tree attributes.
322
        repo.set_make_working_trees(False)
323
        # we want:
324
        # format 'Bazaar-NG Repository format 7'
325
        # lock ''
326
        # inventory.weave == empty_weave
327
        # empty revision-store directory
328
        # empty weaves directory
329
        # a 'shared-storage' marker file.
330
        t = control.get_repository_transport(None)
331
        self.assertEqualDiff('Bazaar-NG Repository format 7',
332
                             t.get('format').read())
1553.5.56 by Martin Pool
Format 7 repo now uses LockDir!
333
        ## self.assertEqualDiff('', t.get('lock').read())
1534.6.5 by Robert Collins
Cloning of repos preserves shared and make-working-tree attributes.
334
        self.assertEqualDiff('', t.get('shared-storage').read())
335
        self.assertEqualDiff('', t.get('no-working-trees').read())
336
        repo.set_make_working_trees(True)
337
        self.assertFalse(t.has('no-working-trees'))
338
        self.assertTrue(S_ISDIR(t.stat('revision-store').st_mode))
339
        self.assertTrue(S_ISDIR(t.stat('weaves').st_mode))
340
        self.assertEqualDiff('# bzr weave file v5\n'
341
                             'w\n'
342
                             'W\n',
343
                             t.get('inventory.weave').read())
1534.1.27 by Robert Collins
Start InterRepository with InterRepository.get.
344
3221.3.1 by Robert Collins
* Repository formats have a new supported-feature attribute
345
    def test_supports_external_lookups(self):
346
        control = bzrdir.BzrDirMetaFormat1().initialize(self.get_url())
347
        repo = weaverepo.RepositoryFormat7().initialize(control)
348
        self.assertFalse(repo._format.supports_external_lookups)
349
1534.1.27 by Robert Collins
Start InterRepository with InterRepository.get.
350
1556.1.3 by Robert Collins
Rearrangment of Repository logic to be less type code driven, and bugfix InterRepository.missing_revision_ids
351
class TestFormatKnit1(TestCaseWithTransport):
3943.8.1 by Marius Kruger
remove all trailing whitespace from bzr source
352
3565.3.1 by Robert Collins
* The generic fetch code now uses two attributes on Repository objects
353
    def test_attribute__fetch_order(self):
354
        """Knits need topological data insertion."""
355
        repo = self.make_repository('.',
356
                format=bzrdir.format_registry.get('knit')())
4053.1.4 by Robert Collins
Move the fetch control attributes from Repository to RepositoryFormat.
357
        self.assertEqual('topological', repo._format._fetch_order)
3565.3.1 by Robert Collins
* The generic fetch code now uses two attributes on Repository objects
358
359
    def test_attribute__fetch_uses_deltas(self):
360
        """Knits reuse deltas."""
361
        repo = self.make_repository('.',
362
                format=bzrdir.format_registry.get('knit')())
4053.1.4 by Robert Collins
Move the fetch control attributes from Repository to RepositoryFormat.
363
        self.assertEqual(True, repo._format._fetch_uses_deltas)
3565.3.1 by Robert Collins
* The generic fetch code now uses two attributes on Repository objects
364
1556.1.3 by Robert Collins
Rearrangment of Repository logic to be less type code driven, and bugfix InterRepository.missing_revision_ids
365
    def test_disk_layout(self):
366
        control = bzrdir.BzrDirMetaFormat1().initialize(self.get_url())
2241.1.6 by Martin Pool
Move Knit repositories into the submodule bzrlib.repofmt.knitrepo and
367
        repo = knitrepo.RepositoryFormatKnit1().initialize(control)
1556.1.3 by Robert Collins
Rearrangment of Repository logic to be less type code driven, and bugfix InterRepository.missing_revision_ids
368
        # in case of side effects of locking.
369
        repo.lock_write()
370
        repo.unlock()
371
        # we want:
372
        # format 'Bazaar-NG Knit Repository Format 1'
1553.5.62 by Martin Pool
Add tests that MetaDir repositories use LockDirs
373
        # lock: is a directory
1556.1.3 by Robert Collins
Rearrangment of Repository logic to be less type code driven, and bugfix InterRepository.missing_revision_ids
374
        # inventory.weave == empty_weave
375
        # empty revision-store directory
376
        # empty weaves directory
377
        t = control.get_repository_transport(None)
378
        self.assertEqualDiff('Bazaar-NG Knit Repository Format 1',
379
                             t.get('format').read())
1553.5.57 by Martin Pool
[merge] sync from bzr.dev
380
        # XXX: no locks left when unlocked at the moment
381
        # self.assertEqualDiff('', t.get('lock').read())
1556.1.3 by Robert Collins
Rearrangment of Repository logic to be less type code driven, and bugfix InterRepository.missing_revision_ids
382
        self.assertTrue(S_ISDIR(t.stat('knits').st_mode))
1563.2.35 by Robert Collins
cleanup deprecation warnings and finish conversion so the inventory is knit based too.
383
        self.check_knits(t)
3350.6.4 by Robert Collins
First cut at pluralised VersionedFiles. Some rather massive API incompatabilities, primarily because of the difficulty of coherence among competing stores.
384
        # Check per-file knits.
385
        branch = control.create_branch()
386
        tree = control.create_workingtree()
387
        tree.add(['foo'], ['Nasty-IdC:'], ['file'])
388
        tree.put_file_bytes_non_atomic('Nasty-IdC:', '')
389
        tree.commit('1st post', rev_id='foo')
390
        self.assertHasKnit(t, 'knits/e8/%254easty-%2549d%2543%253a',
391
            '\nfoo fulltext 0 81  :')
1563.2.35 by Robert Collins
cleanup deprecation warnings and finish conversion so the inventory is knit based too.
392
3350.6.4 by Robert Collins
First cut at pluralised VersionedFiles. Some rather massive API incompatabilities, primarily because of the difficulty of coherence among competing stores.
393
    def assertHasKnit(self, t, knit_name, extra_content=''):
1654.1.3 by Robert Collins
Refactor repository knit tests slightly to remove duplication - add a assertHasKnit method.
394
        """Assert that knit_name exists on t."""
3350.6.4 by Robert Collins
First cut at pluralised VersionedFiles. Some rather massive API incompatabilities, primarily because of the difficulty of coherence among competing stores.
395
        self.assertEqualDiff('# bzr knit index 8\n' + extra_content,
1654.1.3 by Robert Collins
Refactor repository knit tests slightly to remove duplication - add a assertHasKnit method.
396
                             t.get(knit_name + '.kndx').read())
397
1563.2.35 by Robert Collins
cleanup deprecation warnings and finish conversion so the inventory is knit based too.
398
    def check_knits(self, t):
399
        """check knit content for a repository."""
1654.1.3 by Robert Collins
Refactor repository knit tests slightly to remove duplication - add a assertHasKnit method.
400
        self.assertHasKnit(t, 'inventory')
401
        self.assertHasKnit(t, 'revisions')
402
        self.assertHasKnit(t, 'signatures')
1556.1.3 by Robert Collins
Rearrangment of Repository logic to be less type code driven, and bugfix InterRepository.missing_revision_ids
403
404
    def test_shared_disk_layout(self):
405
        control = bzrdir.BzrDirMetaFormat1().initialize(self.get_url())
2241.1.6 by Martin Pool
Move Knit repositories into the submodule bzrlib.repofmt.knitrepo and
406
        repo = knitrepo.RepositoryFormatKnit1().initialize(control, shared=True)
1556.1.3 by Robert Collins
Rearrangment of Repository logic to be less type code driven, and bugfix InterRepository.missing_revision_ids
407
        # we want:
408
        # format 'Bazaar-NG Knit Repository Format 1'
1553.5.62 by Martin Pool
Add tests that MetaDir repositories use LockDirs
409
        # lock: is a directory
1556.1.3 by Robert Collins
Rearrangment of Repository logic to be less type code driven, and bugfix InterRepository.missing_revision_ids
410
        # inventory.weave == empty_weave
411
        # empty revision-store directory
412
        # empty weaves directory
413
        # a 'shared-storage' marker file.
414
        t = control.get_repository_transport(None)
415
        self.assertEqualDiff('Bazaar-NG Knit Repository Format 1',
416
                             t.get('format').read())
1553.5.57 by Martin Pool
[merge] sync from bzr.dev
417
        # XXX: no locks left when unlocked at the moment
418
        # self.assertEqualDiff('', t.get('lock').read())
1556.1.3 by Robert Collins
Rearrangment of Repository logic to be less type code driven, and bugfix InterRepository.missing_revision_ids
419
        self.assertEqualDiff('', t.get('shared-storage').read())
420
        self.assertTrue(S_ISDIR(t.stat('knits').st_mode))
1563.2.35 by Robert Collins
cleanup deprecation warnings and finish conversion so the inventory is knit based too.
421
        self.check_knits(t)
1556.1.3 by Robert Collins
Rearrangment of Repository logic to be less type code driven, and bugfix InterRepository.missing_revision_ids
422
423
    def test_shared_no_tree_disk_layout(self):
424
        control = bzrdir.BzrDirMetaFormat1().initialize(self.get_url())
2241.1.6 by Martin Pool
Move Knit repositories into the submodule bzrlib.repofmt.knitrepo and
425
        repo = knitrepo.RepositoryFormatKnit1().initialize(control, shared=True)
1556.1.3 by Robert Collins
Rearrangment of Repository logic to be less type code driven, and bugfix InterRepository.missing_revision_ids
426
        repo.set_make_working_trees(False)
427
        # we want:
428
        # format 'Bazaar-NG Knit Repository Format 1'
429
        # lock ''
430
        # inventory.weave == empty_weave
431
        # empty revision-store directory
432
        # empty weaves directory
433
        # a 'shared-storage' marker file.
434
        t = control.get_repository_transport(None)
435
        self.assertEqualDiff('Bazaar-NG Knit Repository Format 1',
436
                             t.get('format').read())
1553.5.57 by Martin Pool
[merge] sync from bzr.dev
437
        # XXX: no locks left when unlocked at the moment
438
        # self.assertEqualDiff('', t.get('lock').read())
1556.1.3 by Robert Collins
Rearrangment of Repository logic to be less type code driven, and bugfix InterRepository.missing_revision_ids
439
        self.assertEqualDiff('', t.get('shared-storage').read())
440
        self.assertEqualDiff('', t.get('no-working-trees').read())
441
        repo.set_make_working_trees(True)
442
        self.assertFalse(t.has('no-working-trees'))
443
        self.assertTrue(S_ISDIR(t.stat('knits').st_mode))
1563.2.35 by Robert Collins
cleanup deprecation warnings and finish conversion so the inventory is knit based too.
444
        self.check_knits(t)
1556.1.3 by Robert Collins
Rearrangment of Repository logic to be less type code driven, and bugfix InterRepository.missing_revision_ids
445
2917.2.1 by John Arbash Meinel
Fix bug #152360. The xml5 serializer should be using
446
    def test_deserialise_sets_root_revision(self):
447
        """We must have a inventory.root.revision
448
449
        Old versions of the XML5 serializer did not set the revision_id for
450
        the whole inventory. So we grab the one from the expected text. Which
451
        is valid when the api is not being abused.
452
        """
453
        repo = self.make_repository('.',
454
                format=bzrdir.format_registry.get('knit')())
455
        inv_xml = '<inventory format="5">\n</inventory>\n'
4988.3.3 by Jelmer Vernooij
rename Repository.deserialise_inventory to Repository._deserialise_inventory.
456
        inv = repo._deserialise_inventory('test-rev-id', inv_xml)
2917.2.1 by John Arbash Meinel
Fix bug #152360. The xml5 serializer should be using
457
        self.assertEqual('test-rev-id', inv.root.revision)
458
459
    def test_deserialise_uses_global_revision_id(self):
460
        """If it is set, then we re-use the global revision id"""
461
        repo = self.make_repository('.',
462
                format=bzrdir.format_registry.get('knit')())
463
        inv_xml = ('<inventory format="5" revision_id="other-rev-id">\n'
464
                   '</inventory>\n')
465
        # Arguably, the deserialise_inventory should detect a mismatch, and
466
        # raise an error, rather than silently using one revision_id over the
467
        # other.
4988.3.3 by Jelmer Vernooij
rename Repository.deserialise_inventory to Repository._deserialise_inventory.
468
        self.assertRaises(AssertionError, repo._deserialise_inventory,
3169.2.2 by Robert Collins
Add a test to Repository.deserialise_inventory that the resulting ivnentory is the one asked for, and update relevant tests. Also tweak the model 1 to 2 regenerate inventories logic to use the revision trees parent marker which is more accurate in some cases.
469
            'test-rev-id', inv_xml)
4988.3.3 by Jelmer Vernooij
rename Repository.deserialise_inventory to Repository._deserialise_inventory.
470
        inv = repo._deserialise_inventory('other-rev-id', inv_xml)
2917.2.1 by John Arbash Meinel
Fix bug #152360. The xml5 serializer should be using
471
        self.assertEqual('other-rev-id', inv.root.revision)
472
3221.3.1 by Robert Collins
* Repository formats have a new supported-feature attribute
473
    def test_supports_external_lookups(self):
474
        repo = self.make_repository('.',
475
                format=bzrdir.format_registry.get('knit')())
476
        self.assertFalse(repo._format.supports_external_lookups)
477
2535.3.53 by Andrew Bennetts
Remove get_stream_as_bytes from KnitVersionedFile's API, make it a function in knitrepo.py instead.
478
2305.2.3 by Andrew Bennetts
Bring across test_repository improvements from the hpss branch to fix the last test failures.
479
class DummyRepository(object):
480
    """A dummy repository for testing."""
481
3452.2.11 by Andrew Bennetts
Merge thread.
482
    _format = None
2305.2.3 by Andrew Bennetts
Bring across test_repository improvements from the hpss branch to fix the last test failures.
483
    _serializer = None
484
485
    def supports_rich_root(self):
4606.4.1 by Robert Collins
Prepare test_repository's inter_repository tests for 2a.
486
        if self._format is not None:
487
            return self._format.rich_root_data
2305.2.3 by Andrew Bennetts
Bring across test_repository improvements from the hpss branch to fix the last test failures.
488
        return False
489
3709.5.10 by Andrew Bennetts
Fix test failure caused by missing attributes on DummyRepository.
490
    def get_graph(self):
491
        raise NotImplementedError
492
493
    def get_parent_map(self, revision_ids):
494
        raise NotImplementedError
495
2305.2.3 by Andrew Bennetts
Bring across test_repository improvements from the hpss branch to fix the last test failures.
496
497
class InterDummy(repository.InterRepository):
498
    """An inter-repository optimised code path for DummyRepository.
499
500
    This is for use during testing where we use DummyRepository as repositories
1534.1.28 by Robert Collins
Allow for optimised InterRepository selection.
501
    so that none of the default regsitered inter-repository classes will
2818.4.2 by Robert Collins
Review feedback.
502
    MATCH.
1534.1.28 by Robert Collins
Allow for optimised InterRepository selection.
503
    """
504
505
    @staticmethod
506
    def is_compatible(repo_source, repo_target):
2305.2.3 by Andrew Bennetts
Bring across test_repository improvements from the hpss branch to fix the last test failures.
507
        """InterDummy is compatible with DummyRepository."""
3943.8.1 by Marius Kruger
remove all trailing whitespace from bzr source
508
        return (isinstance(repo_source, DummyRepository) and
2305.2.3 by Andrew Bennetts
Bring across test_repository improvements from the hpss branch to fix the last test failures.
509
            isinstance(repo_target, DummyRepository))
1534.1.28 by Robert Collins
Allow for optimised InterRepository selection.
510
511
1534.1.27 by Robert Collins
Start InterRepository with InterRepository.get.
512
class TestInterRepository(TestCaseWithTransport):
513
514
    def test_get_default_inter_repository(self):
515
        # test that the InterRepository.get(repo_a, repo_b) probes
516
        # for a inter_repo class where is_compatible(repo_a, repo_b) returns
517
        # true and returns a default inter_repo otherwise.
518
        # This also tests that the default registered optimised interrepository
519
        # classes do not barf inappropriately when a surprising repository type
520
        # is handed to them.
2305.2.3 by Andrew Bennetts
Bring across test_repository improvements from the hpss branch to fix the last test failures.
521
        dummy_a = DummyRepository()
522
        dummy_b = DummyRepository()
1534.1.28 by Robert Collins
Allow for optimised InterRepository selection.
523
        self.assertGetsDefaultInterRepository(dummy_a, dummy_b)
524
525
    def assertGetsDefaultInterRepository(self, repo_a, repo_b):
2305.2.3 by Andrew Bennetts
Bring across test_repository improvements from the hpss branch to fix the last test failures.
526
        """Asserts that InterRepository.get(repo_a, repo_b) -> the default.
3943.8.1 by Marius Kruger
remove all trailing whitespace from bzr source
527
2305.2.3 by Andrew Bennetts
Bring across test_repository improvements from the hpss branch to fix the last test failures.
528
        The effective default is now InterSameDataRepository because there is
529
        no actual sane default in the presence of incompatible data models.
530
        """
1534.1.28 by Robert Collins
Allow for optimised InterRepository selection.
531
        inter_repo = repository.InterRepository.get(repo_a, repo_b)
2305.2.3 by Andrew Bennetts
Bring across test_repository improvements from the hpss branch to fix the last test failures.
532
        self.assertEqual(repository.InterSameDataRepository,
1534.1.27 by Robert Collins
Start InterRepository with InterRepository.get.
533
                         inter_repo.__class__)
1534.1.28 by Robert Collins
Allow for optimised InterRepository selection.
534
        self.assertEqual(repo_a, inter_repo.source)
535
        self.assertEqual(repo_b, inter_repo.target)
536
537
    def test_register_inter_repository_class(self):
538
        # test that a optimised code path provider - a
539
        # InterRepository subclass can be registered and unregistered
540
        # and that it is correctly selected when given a repository
541
        # pair that it returns true on for the is_compatible static method
542
        # check
2305.2.3 by Andrew Bennetts
Bring across test_repository improvements from the hpss branch to fix the last test failures.
543
        dummy_a = DummyRepository()
4606.4.1 by Robert Collins
Prepare test_repository's inter_repository tests for 2a.
544
        dummy_a._format = RepositoryFormat()
2305.2.3 by Andrew Bennetts
Bring across test_repository improvements from the hpss branch to fix the last test failures.
545
        dummy_b = DummyRepository()
4606.4.1 by Robert Collins
Prepare test_repository's inter_repository tests for 2a.
546
        dummy_b._format = RepositoryFormat()
2305.2.3 by Andrew Bennetts
Bring across test_repository improvements from the hpss branch to fix the last test failures.
547
        repo = self.make_repository('.')
548
        # hack dummies to look like repo somewhat.
549
        dummy_a._serializer = repo._serializer
4606.4.1 by Robert Collins
Prepare test_repository's inter_repository tests for 2a.
550
        dummy_a._format.supports_tree_reference = repo._format.supports_tree_reference
551
        dummy_a._format.rich_root_data = repo._format.rich_root_data
2305.2.3 by Andrew Bennetts
Bring across test_repository improvements from the hpss branch to fix the last test failures.
552
        dummy_b._serializer = repo._serializer
4606.4.1 by Robert Collins
Prepare test_repository's inter_repository tests for 2a.
553
        dummy_b._format.supports_tree_reference = repo._format.supports_tree_reference
554
        dummy_b._format.rich_root_data = repo._format.rich_root_data
2305.2.3 by Andrew Bennetts
Bring across test_repository improvements from the hpss branch to fix the last test failures.
555
        repository.InterRepository.register_optimiser(InterDummy)
1534.1.28 by Robert Collins
Allow for optimised InterRepository selection.
556
        try:
2305.2.3 by Andrew Bennetts
Bring across test_repository improvements from the hpss branch to fix the last test failures.
557
            # we should get the default for something InterDummy returns False
1534.1.28 by Robert Collins
Allow for optimised InterRepository selection.
558
            # to
2305.2.3 by Andrew Bennetts
Bring across test_repository improvements from the hpss branch to fix the last test failures.
559
            self.assertFalse(InterDummy.is_compatible(dummy_a, repo))
560
            self.assertGetsDefaultInterRepository(dummy_a, repo)
561
            # and we should get an InterDummy for a pair it 'likes'
562
            self.assertTrue(InterDummy.is_compatible(dummy_a, dummy_b))
1534.1.28 by Robert Collins
Allow for optimised InterRepository selection.
563
            inter_repo = repository.InterRepository.get(dummy_a, dummy_b)
2305.2.3 by Andrew Bennetts
Bring across test_repository improvements from the hpss branch to fix the last test failures.
564
            self.assertEqual(InterDummy, inter_repo.__class__)
1534.1.28 by Robert Collins
Allow for optimised InterRepository selection.
565
            self.assertEqual(dummy_a, inter_repo.source)
566
            self.assertEqual(dummy_b, inter_repo.target)
567
        finally:
2305.2.3 by Andrew Bennetts
Bring across test_repository improvements from the hpss branch to fix the last test failures.
568
            repository.InterRepository.unregister_optimiser(InterDummy)
1534.1.28 by Robert Collins
Allow for optimised InterRepository selection.
569
        # now we should get the default InterRepository object again.
570
        self.assertGetsDefaultInterRepository(dummy_a, dummy_b)
1534.1.33 by Robert Collins
Move copy_content_into into InterRepository and InterWeaveRepo, and disable the default codepath test as we have optimised paths for all current combinations.
571
2241.1.17 by Martin Pool
Restore old InterWeave tests
572
573
class TestInterWeaveRepo(TestCaseWithTransport):
574
575
    def test_is_compatible_and_registered(self):
576
        # InterWeaveRepo is compatible when either side
577
        # is a format 5/6/7 branch
2241.1.20 by mbp at sourcefrog
update tests for new locations of weave repos
578
        from bzrlib.repofmt import knitrepo, weaverepo
579
        formats = [weaverepo.RepositoryFormat5(),
580
                   weaverepo.RepositoryFormat6(),
581
                   weaverepo.RepositoryFormat7()]
582
        incompatible_formats = [weaverepo.RepositoryFormat4(),
583
                                knitrepo.RepositoryFormatKnit1(),
2241.1.17 by Martin Pool
Restore old InterWeave tests
584
                                ]
585
        repo_a = self.make_repository('a')
586
        repo_b = self.make_repository('b')
5537.2.1 by Jelmer Vernooij
Move InterWeaveRepo and InterKnitRepo to related repository files.
587
        is_compatible = weaverepo.InterWeaveRepo.is_compatible
2241.1.17 by Martin Pool
Restore old InterWeave tests
588
        for source in incompatible_formats:
589
            # force incompatible left then right
590
            repo_a._format = source
591
            repo_b._format = formats[0]
592
            self.assertFalse(is_compatible(repo_a, repo_b))
593
            self.assertFalse(is_compatible(repo_b, repo_a))
594
        for source in formats:
595
            repo_a._format = source
596
            for target in formats:
597
                repo_b._format = target
598
                self.assertTrue(is_compatible(repo_a, repo_b))
5537.2.1 by Jelmer Vernooij
Move InterWeaveRepo and InterKnitRepo to related repository files.
599
        self.assertEqual(weaverepo.InterWeaveRepo,
2241.1.17 by Martin Pool
Restore old InterWeave tests
600
                         repository.InterRepository.get(repo_a,
601
                                                        repo_b).__class__)
602
1556.1.4 by Robert Collins
Add a new format for what will become knit, and the surrounding logic to upgrade repositories within metadirs, and tests for the same.
603
604
class TestRepositoryConverter(TestCaseWithTransport):
605
606
    def test_convert_empty(self):
5609.9.4 by Vincent Ladeuil
Use self.get_transport instead of transport.get_transport where possible.
607
        t = self.get_transport()
1556.1.4 by Robert Collins
Add a new format for what will become knit, and the surrounding logic to upgrade repositories within metadirs, and tests for the same.
608
        t.mkdir('repository')
609
        repo_dir = bzrdir.BzrDirMetaFormat1().initialize('repository')
2241.1.4 by Martin Pool
Moved old weave-based repository formats into bzrlib.repofmt.weaverepo.
610
        repo = weaverepo.RepositoryFormat7().initialize(repo_dir)
2241.1.6 by Martin Pool
Move Knit repositories into the submodule bzrlib.repofmt.knitrepo and
611
        target_format = knitrepo.RepositoryFormatKnit1()
1556.1.4 by Robert Collins
Add a new format for what will become knit, and the surrounding logic to upgrade repositories within metadirs, and tests for the same.
612
        converter = repository.CopyConverter(target_format)
1594.1.3 by Robert Collins
Fixup pb usage to use nested_progress_bar.
613
        pb = bzrlib.ui.ui_factory.nested_progress_bar()
614
        try:
615
            converter.convert(repo, pb)
616
        finally:
617
            pb.finished()
1556.1.4 by Robert Collins
Add a new format for what will become knit, and the surrounding logic to upgrade repositories within metadirs, and tests for the same.
618
        repo = repo_dir.open_repository()
619
        self.assertTrue(isinstance(target_format, repo._format.__class__))
1843.2.5 by Aaron Bentley
Add test of _unescape_xml
620
621
622
class TestMisc(TestCase):
3943.8.1 by Marius Kruger
remove all trailing whitespace from bzr source
623
1843.2.5 by Aaron Bentley
Add test of _unescape_xml
624
    def test_unescape_xml(self):
625
        """We get some kind of error when malformed entities are passed"""
3943.8.1 by Marius Kruger
remove all trailing whitespace from bzr source
626
        self.assertRaises(KeyError, repository._unescape_xml, 'foo&bar;')
1910.2.13 by Aaron Bentley
Start work on converter
627
628
2255.2.211 by Robert Collins
Remove knit2 repository format- it has never been supported.
629
class TestRepositoryFormatKnit3(TestCaseWithTransport):
1910.2.13 by Aaron Bentley
Start work on converter
630
3565.3.1 by Robert Collins
* The generic fetch code now uses two attributes on Repository objects
631
    def test_attribute__fetch_order(self):
632
        """Knits need topological data insertion."""
633
        format = bzrdir.BzrDirMetaFormat1()
634
        format.repository_format = knitrepo.RepositoryFormatKnit3()
635
        repo = self.make_repository('.', format=format)
4053.1.4 by Robert Collins
Move the fetch control attributes from Repository to RepositoryFormat.
636
        self.assertEqual('topological', repo._format._fetch_order)
3565.3.1 by Robert Collins
* The generic fetch code now uses two attributes on Repository objects
637
638
    def test_attribute__fetch_uses_deltas(self):
639
        """Knits reuse deltas."""
640
        format = bzrdir.BzrDirMetaFormat1()
641
        format.repository_format = knitrepo.RepositoryFormatKnit3()
642
        repo = self.make_repository('.', format=format)
4053.1.4 by Robert Collins
Move the fetch control attributes from Repository to RepositoryFormat.
643
        self.assertEqual(True, repo._format._fetch_uses_deltas)
3565.3.1 by Robert Collins
* The generic fetch code now uses two attributes on Repository objects
644
1910.2.13 by Aaron Bentley
Start work on converter
645
    def test_convert(self):
646
        """Ensure the upgrade adds weaves for roots"""
1910.2.35 by Aaron Bentley
Better fix for convesion test
647
        format = bzrdir.BzrDirMetaFormat1()
2241.1.6 by Martin Pool
Move Knit repositories into the submodule bzrlib.repofmt.knitrepo and
648
        format.repository_format = knitrepo.RepositoryFormatKnit1()
1910.2.35 by Aaron Bentley
Better fix for convesion test
649
        tree = self.make_branch_and_tree('.', format)
1910.2.13 by Aaron Bentley
Start work on converter
650
        tree.commit("Dull commit", rev_id="dull")
651
        revision_tree = tree.branch.repository.revision_tree('dull')
3350.6.4 by Robert Collins
First cut at pluralised VersionedFiles. Some rather massive API incompatabilities, primarily because of the difficulty of coherence among competing stores.
652
        revision_tree.lock_read()
653
        try:
654
            self.assertRaises(errors.NoSuchFile, revision_tree.get_file_lines,
655
                revision_tree.inventory.root.file_id)
656
        finally:
657
            revision_tree.unlock()
1910.2.13 by Aaron Bentley
Start work on converter
658
        format = bzrdir.BzrDirMetaFormat1()
2255.2.211 by Robert Collins
Remove knit2 repository format- it has never been supported.
659
        format.repository_format = knitrepo.RepositoryFormatKnit3()
1910.2.13 by Aaron Bentley
Start work on converter
660
        upgrade.Convert('.', format)
1910.2.27 by Aaron Bentley
Fixed conversion test
661
        tree = workingtree.WorkingTree.open('.')
1910.2.13 by Aaron Bentley
Start work on converter
662
        revision_tree = tree.branch.repository.revision_tree('dull')
3350.6.4 by Robert Collins
First cut at pluralised VersionedFiles. Some rather massive API incompatabilities, primarily because of the difficulty of coherence among competing stores.
663
        revision_tree.lock_read()
664
        try:
665
            revision_tree.get_file_lines(revision_tree.inventory.root.file_id)
666
        finally:
667
            revision_tree.unlock()
1910.2.27 by Aaron Bentley
Fixed conversion test
668
        tree.commit("Another dull commit", rev_id='dull2')
669
        revision_tree = tree.branch.repository.revision_tree('dull2')
3350.6.4 by Robert Collins
First cut at pluralised VersionedFiles. Some rather massive API incompatabilities, primarily because of the difficulty of coherence among competing stores.
670
        revision_tree.lock_read()
671
        self.addCleanup(revision_tree.unlock)
1910.2.27 by Aaron Bentley
Fixed conversion test
672
        self.assertEqual('dull', revision_tree.inventory.root.revision)
2220.2.2 by Martin Pool
Add tag command and basic implementation
673
3221.3.1 by Robert Collins
* Repository formats have a new supported-feature attribute
674
    def test_supports_external_lookups(self):
675
        format = bzrdir.BzrDirMetaFormat1()
676
        format.repository_format = knitrepo.RepositoryFormatKnit3()
677
        repo = self.make_repository('.', format=format)
678
        self.assertFalse(repo._format.supports_external_lookups)
679
2535.3.57 by Andrew Bennetts
Perform some sanity checking of data streams rather than blindly inserting them into our repository.
680
4667.1.1 by John Arbash Meinel
Drop the Test2a test times from 5+s down to 1.4s
681
class Test2a(tests.TestCaseWithMemoryTransport):
4431.3.7 by Jonathan Lange
Cherrypick bzr.dev 4470, resolving conflicts.
682
5365.5.20 by John Arbash Meinel
Add some tests that check the leaf factory is correct.
683
    def test_chk_bytes_uses_custom_btree_parser(self):
684
        mt = self.make_branch_and_memory_tree('test', format='2a')
685
        mt.lock_write()
686
        self.addCleanup(mt.unlock)
687
        mt.add([''], ['root-id'])
688
        mt.commit('first')
689
        index = mt.branch.repository.chk_bytes._index._graph_index._indices[0]
690
        self.assertEqual(btree_index._gcchk_factory, index._leaf_factory)
691
        # It should also work if we re-open the repo
692
        repo = mt.branch.repository.bzrdir.open_repository()
693
        repo.lock_read()
694
        self.addCleanup(repo.unlock)
695
        index = repo.chk_bytes._index._graph_index._indices[0]
696
        self.assertEqual(btree_index._gcchk_factory, index._leaf_factory)
697
4634.20.1 by Robert Collins
Fix bug 402652 by recompressing all texts that are streamed - slightly slower at fetch, substantially faster and more compact at read.
698
    def test_fetch_combines_groups(self):
699
        builder = self.make_branch_builder('source', format='2a')
700
        builder.start_series()
701
        builder.build_snapshot('1', None, [
702
            ('add', ('', 'root-id', 'directory', '')),
703
            ('add', ('file', 'file-id', 'file', 'content\n'))])
704
        builder.build_snapshot('2', ['1'], [
705
            ('modify', ('file-id', 'content-2\n'))])
706
        builder.finish_series()
707
        source = builder.get_branch()
708
        target = self.make_repository('target', format='2a')
709
        target.fetch(source.repository)
710
        target.lock_read()
4665.3.2 by John Arbash Meinel
An alternative implementation that passes both tests.
711
        self.addCleanup(target.unlock)
4634.20.1 by Robert Collins
Fix bug 402652 by recompressing all texts that are streamed - slightly slower at fetch, substantially faster and more compact at read.
712
        details = target.texts._index.get_build_details(
713
            [('file-id', '1',), ('file-id', '2',)])
714
        file_1_details = details[('file-id', '1')]
715
        file_2_details = details[('file-id', '2')]
716
        # The index, and what to read off disk, should be the same for both
717
        # versions of the file.
718
        self.assertEqual(file_1_details[0][:3], file_2_details[0][:3])
719
4634.23.1 by Robert Collins
Cherrypick from bzr.dev: Fix bug 402652: recompress badly packed groups during fetch. (John Arbash Meinel, Robert Collins)
720
    def test_fetch_combines_groups(self):
721
        builder = self.make_branch_builder('source', format='2a')
722
        builder.start_series()
723
        builder.build_snapshot('1', None, [
724
            ('add', ('', 'root-id', 'directory', '')),
725
            ('add', ('file', 'file-id', 'file', 'content\n'))])
726
        builder.build_snapshot('2', ['1'], [
727
            ('modify', ('file-id', 'content-2\n'))])
728
        builder.finish_series()
729
        source = builder.get_branch()
730
        target = self.make_repository('target', format='2a')
731
        target.fetch(source.repository)
732
        target.lock_read()
733
        self.addCleanup(target.unlock)
734
        details = target.texts._index.get_build_details(
735
            [('file-id', '1',), ('file-id', '2',)])
736
        file_1_details = details[('file-id', '1')]
737
        file_2_details = details[('file-id', '2')]
738
        # The index, and what to read off disk, should be the same for both
739
        # versions of the file.
740
        self.assertEqual(file_1_details[0][:3], file_2_details[0][:3])
741
742
    def test_fetch_combines_groups(self):
743
        builder = self.make_branch_builder('source', format='2a')
744
        builder.start_series()
745
        builder.build_snapshot('1', None, [
746
            ('add', ('', 'root-id', 'directory', '')),
747
            ('add', ('file', 'file-id', 'file', 'content\n'))])
748
        builder.build_snapshot('2', ['1'], [
749
            ('modify', ('file-id', 'content-2\n'))])
750
        builder.finish_series()
751
        source = builder.get_branch()
752
        target = self.make_repository('target', format='2a')
753
        target.fetch(source.repository)
754
        target.lock_read()
755
        self.addCleanup(target.unlock)
756
        details = target.texts._index.get_build_details(
757
            [('file-id', '1',), ('file-id', '2',)])
758
        file_1_details = details[('file-id', '1')]
759
        file_2_details = details[('file-id', '2')]
760
        # The index, and what to read off disk, should be the same for both
761
        # versions of the file.
762
        self.assertEqual(file_1_details[0][:3], file_2_details[0][:3])
763
4431.3.7 by Jonathan Lange
Cherrypick bzr.dev 4470, resolving conflicts.
764
    def test_format_pack_compresses_True(self):
765
        repo = self.make_repository('repo', format='2a')
766
        self.assertTrue(repo._format.pack_compresses)
3735.2.40 by Robert Collins
Add development4 which has a parent_id to basename index on CHKInventory objects.
767
768
    def test_inventories_use_chk_map_with_parent_base_dict(self):
4667.1.1 by John Arbash Meinel
Drop the Test2a test times from 5+s down to 1.4s
769
        tree = self.make_branch_and_memory_tree('repo', format="2a")
770
        tree.lock_write()
771
        tree.add([''], ['TREE_ROOT'])
3735.2.40 by Robert Collins
Add development4 which has a parent_id to basename index on CHKInventory objects.
772
        revid = tree.commit("foo")
4667.1.1 by John Arbash Meinel
Drop the Test2a test times from 5+s down to 1.4s
773
        tree.unlock()
3735.2.40 by Robert Collins
Add development4 which has a parent_id to basename index on CHKInventory objects.
774
        tree.lock_read()
775
        self.addCleanup(tree.unlock)
776
        inv = tree.branch.repository.get_inventory(revid)
3735.2.41 by Robert Collins
Make the parent_id_basename index be updated during CHKInventory.apply_delta.
777
        self.assertNotEqual(None, inv.parent_id_basename_to_file_id)
778
        inv.parent_id_basename_to_file_id._ensure_root()
3735.2.40 by Robert Collins
Add development4 which has a parent_id to basename index on CHKInventory objects.
779
        inv.id_to_entry._ensure_root()
4241.6.8 by Robert Collins, John Arbash Meinel, Ian Clatworthy, Vincent Ladeuil
Add --development6-rich-root, disabling the legacy and unneeded development2 format, and activating the tests for CHK features disabled pending this format. (Robert Collins, John Arbash Meinel, Ian Clatworthy, Vincent Ladeuil)
780
        self.assertEqual(65536, inv.id_to_entry._root_node.maximum_size)
781
        self.assertEqual(65536,
3735.2.41 by Robert Collins
Make the parent_id_basename index be updated during CHKInventory.apply_delta.
782
            inv.parent_id_basename_to_file_id._root_node.maximum_size)
3735.2.40 by Robert Collins
Add development4 which has a parent_id to basename index on CHKInventory objects.
783
4431.3.7 by Jonathan Lange
Cherrypick bzr.dev 4470, resolving conflicts.
784
    def test_autopack_unchanged_chk_nodes(self):
785
        # at 20 unchanged commits, chk pages are packed that are split into
786
        # two groups such that the new pack being made doesn't have all its
787
        # pages in the source packs (though they are in the repository).
4667.1.1 by John Arbash Meinel
Drop the Test2a test times from 5+s down to 1.4s
788
        # Use a memory backed repository, we don't need to hit disk for this
789
        tree = self.make_branch_and_memory_tree('tree', format='2a')
790
        tree.lock_write()
791
        self.addCleanup(tree.unlock)
792
        tree.add([''], ['TREE_ROOT'])
4431.3.7 by Jonathan Lange
Cherrypick bzr.dev 4470, resolving conflicts.
793
        for pos in range(20):
794
            tree.commit(str(pos))
795
796
    def test_pack_with_hint(self):
4667.1.1 by John Arbash Meinel
Drop the Test2a test times from 5+s down to 1.4s
797
        tree = self.make_branch_and_memory_tree('tree', format='2a')
798
        tree.lock_write()
799
        self.addCleanup(tree.unlock)
800
        tree.add([''], ['TREE_ROOT'])
4431.3.7 by Jonathan Lange
Cherrypick bzr.dev 4470, resolving conflicts.
801
        # 1 commit to leave untouched
802
        tree.commit('1')
803
        to_keep = tree.branch.repository._pack_collection.names()
804
        # 2 to combine
805
        tree.commit('2')
806
        tree.commit('3')
807
        all = tree.branch.repository._pack_collection.names()
808
        combine = list(set(all) - set(to_keep))
809
        self.assertLength(3, all)
810
        self.assertLength(2, combine)
811
        tree.branch.repository.pack(hint=combine)
812
        final = tree.branch.repository._pack_collection.names()
813
        self.assertLength(2, final)
814
        self.assertFalse(combine[0] in final)
815
        self.assertFalse(combine[1] in final)
816
        self.assertSubset(to_keep, final)
817
4360.4.3 by John Arbash Meinel
Introduce a KnitPackStreamSource which is used when
818
    def test_stream_source_to_gc(self):
4462.2.1 by Robert Collins
Add new attribute to RepositoryFormat pack_compresses, hinting when pack can be useful.
819
        source = self.make_repository('source', format='2a')
820
        target = self.make_repository('target', format='2a')
4360.4.3 by John Arbash Meinel
Introduce a KnitPackStreamSource which is used when
821
        stream = source._get_source(target._format)
822
        self.assertIsInstance(stream, groupcompress_repo.GroupCHKStreamSource)
823
824
    def test_stream_source_to_non_gc(self):
4462.2.1 by Robert Collins
Add new attribute to RepositoryFormat pack_compresses, hinting when pack can be useful.
825
        source = self.make_repository('source', format='2a')
4360.4.3 by John Arbash Meinel
Introduce a KnitPackStreamSource which is used when
826
        target = self.make_repository('target', format='rich-root-pack')
827
        stream = source._get_source(target._format)
828
        # We don't want the child GroupCHKStreamSource
829
        self.assertIs(type(stream), repository.StreamSource)
830
4360.4.9 by John Arbash Meinel
Merge bzr.dev, bringing in the gc stacking fixes.
831
    def test_get_stream_for_missing_keys_includes_all_chk_refs(self):
832
        source_builder = self.make_branch_builder('source',
4462.2.1 by Robert Collins
Add new attribute to RepositoryFormat pack_compresses, hinting when pack can be useful.
833
                            format='2a')
4360.4.9 by John Arbash Meinel
Merge bzr.dev, bringing in the gc stacking fixes.
834
        # We have to build a fairly large tree, so that we are sure the chk
835
        # pages will have split into multiple pages.
836
        entries = [('add', ('', 'a-root-id', 'directory', None))]
837
        for i in 'abcdefghijklmnopqrstuvwxyz123456789':
838
            for j in 'abcdefghijklmnopqrstuvwxyz123456789':
839
                fname = i + j
840
                fid = fname + '-id'
841
                content = 'content for %s\n' % (fname,)
842
                entries.append(('add', (fname, fid, 'file', content)))
843
        source_builder.start_series()
844
        source_builder.build_snapshot('rev-1', None, entries)
845
        # Now change a few of them, so we get a few new pages for the second
846
        # revision
847
        source_builder.build_snapshot('rev-2', ['rev-1'], [
848
            ('modify', ('aa-id', 'new content for aa-id\n')),
849
            ('modify', ('cc-id', 'new content for cc-id\n')),
850
            ('modify', ('zz-id', 'new content for zz-id\n')),
851
            ])
852
        source_builder.finish_series()
853
        source_branch = source_builder.get_branch()
854
        source_branch.lock_read()
855
        self.addCleanup(source_branch.unlock)
4462.2.1 by Robert Collins
Add new attribute to RepositoryFormat pack_compresses, hinting when pack can be useful.
856
        target = self.make_repository('target', format='2a')
4360.4.9 by John Arbash Meinel
Merge bzr.dev, bringing in the gc stacking fixes.
857
        source = source_branch.repository._get_source(target._format)
858
        self.assertIsInstance(source, groupcompress_repo.GroupCHKStreamSource)
859
860
        # On a regular pass, getting the inventories and chk pages for rev-2
861
        # would only get the newly created chk pages
862
        search = graph.SearchResult(set(['rev-2']), set(['rev-1']), 1,
863
                                    set(['rev-2']))
864
        simple_chk_records = []
865
        for vf_name, substream in source.get_stream(search):
866
            if vf_name == 'chk_bytes':
867
                for record in substream:
868
                    simple_chk_records.append(record.key)
869
            else:
870
                for _ in substream:
871
                    continue
872
        # 3 pages, the root (InternalNode), + 2 pages which actually changed
873
        self.assertEqual([('sha1:91481f539e802c76542ea5e4c83ad416bf219f73',),
874
                          ('sha1:4ff91971043668583985aec83f4f0ab10a907d3f',),
875
                          ('sha1:81e7324507c5ca132eedaf2d8414ee4bb2226187',),
876
                          ('sha1:b101b7da280596c71a4540e9a1eeba8045985ee0',)],
877
                         simple_chk_records)
878
        # Now, when we do a similar call using 'get_stream_for_missing_keys'
879
        # we should get a much larger set of pages.
880
        missing = [('inventories', 'rev-2')]
881
        full_chk_records = []
882
        for vf_name, substream in source.get_stream_for_missing_keys(missing):
883
            if vf_name == 'inventories':
884
                for record in substream:
885
                    self.assertEqual(('rev-2',), record.key)
886
            elif vf_name == 'chk_bytes':
887
                for record in substream:
888
                    full_chk_records.append(record.key)
889
            else:
890
                self.fail('Should not be getting a stream of %s' % (vf_name,))
891
        # We have 257 records now. This is because we have 1 root page, and 256
892
        # leaf pages in a complete listing.
893
        self.assertEqual(257, len(full_chk_records))
894
        self.assertSubset(simple_chk_records, full_chk_records)
895
4465.2.7 by Aaron Bentley
Move test_inconsistency_fatal to test_repository
896
    def test_inconsistency_fatal(self):
897
        repo = self.make_repository('repo', format='2a')
898
        self.assertTrue(repo.revisions._index._inconsistency_fatal)
899
        self.assertFalse(repo.texts._index._inconsistency_fatal)
900
        self.assertFalse(repo.inventories._index._inconsistency_fatal)
901
        self.assertFalse(repo.signatures._index._inconsistency_fatal)
902
        self.assertFalse(repo.chk_bytes._index._inconsistency_fatal)
903
4360.4.3 by John Arbash Meinel
Introduce a KnitPackStreamSource which is used when
904
905
class TestKnitPackStreamSource(tests.TestCaseWithMemoryTransport):
906
907
    def test_source_to_exact_pack_092(self):
908
        source = self.make_repository('source', format='pack-0.92')
909
        target = self.make_repository('target', format='pack-0.92')
910
        stream_source = source._get_source(target._format)
911
        self.assertIsInstance(stream_source, pack_repo.KnitPackStreamSource)
912
913
    def test_source_to_exact_pack_rich_root_pack(self):
914
        source = self.make_repository('source', format='rich-root-pack')
915
        target = self.make_repository('target', format='rich-root-pack')
916
        stream_source = source._get_source(target._format)
917
        self.assertIsInstance(stream_source, pack_repo.KnitPackStreamSource)
918
919
    def test_source_to_exact_pack_19(self):
920
        source = self.make_repository('source', format='1.9')
921
        target = self.make_repository('target', format='1.9')
922
        stream_source = source._get_source(target._format)
923
        self.assertIsInstance(stream_source, pack_repo.KnitPackStreamSource)
924
925
    def test_source_to_exact_pack_19_rich_root(self):
926
        source = self.make_repository('source', format='1.9-rich-root')
927
        target = self.make_repository('target', format='1.9-rich-root')
928
        stream_source = source._get_source(target._format)
929
        self.assertIsInstance(stream_source, pack_repo.KnitPackStreamSource)
930
931
    def test_source_to_remote_exact_pack_19(self):
932
        trans = self.make_smart_server('target')
933
        trans.ensure_base()
934
        source = self.make_repository('source', format='1.9')
935
        target = self.make_repository('target', format='1.9')
936
        target = repository.Repository.open(trans.base)
937
        stream_source = source._get_source(target._format)
938
        self.assertIsInstance(stream_source, pack_repo.KnitPackStreamSource)
939
940
    def test_stream_source_to_non_exact(self):
941
        source = self.make_repository('source', format='pack-0.92')
942
        target = self.make_repository('target', format='1.9')
943
        stream = source._get_source(target._format)
944
        self.assertIs(type(stream), repository.StreamSource)
945
946
    def test_stream_source_to_non_exact_rich_root(self):
947
        source = self.make_repository('source', format='1.9')
948
        target = self.make_repository('target', format='1.9-rich-root')
949
        stream = source._get_source(target._format)
950
        self.assertIs(type(stream), repository.StreamSource)
951
952
    def test_source_to_remote_non_exact_pack_19(self):
953
        trans = self.make_smart_server('target')
954
        trans.ensure_base()
955
        source = self.make_repository('source', format='1.9')
956
        target = self.make_repository('target', format='1.6')
957
        target = repository.Repository.open(trans.base)
958
        stream_source = source._get_source(target._format)
959
        self.assertIs(type(stream_source), repository.StreamSource)
960
961
    def test_stream_source_to_knit(self):
962
        source = self.make_repository('source', format='pack-0.92')
963
        target = self.make_repository('target', format='dirstate')
964
        stream = source._get_source(target._format)
965
        self.assertIs(type(stream), repository.StreamSource)
966
3735.2.40 by Robert Collins
Add development4 which has a parent_id to basename index on CHKInventory objects.
967
4343.3.32 by John Arbash Meinel
Change the tests for _find_revision_outside_set to the new _find_parent_ids function.
968
class TestDevelopment6FindParentIdsOfRevisions(TestCaseWithTransport):
969
    """Tests for _find_parent_ids_of_revisions."""
3735.4.1 by Andrew Bennetts
Add _find_revision_outside_set.
970
971
    def setUp(self):
4343.3.32 by John Arbash Meinel
Change the tests for _find_revision_outside_set to the new _find_parent_ids function.
972
        super(TestDevelopment6FindParentIdsOfRevisions, self).setUp()
5546.1.1 by Andrew Bennetts
Remove RepositoryFormatCHK1 and RepositoryFormatCHK2.
973
        self.builder = self.make_branch_builder('source')
3735.4.1 by Andrew Bennetts
Add _find_revision_outside_set.
974
        self.builder.start_series()
975
        self.builder.build_snapshot('initial', None,
976
            [('add', ('', 'tree-root', 'directory', None))])
977
        self.repo = self.builder.get_branch().repository
978
        self.addCleanup(self.builder.finish_series)
3735.2.99 by John Arbash Meinel
Merge bzr.dev 4034. Whitespace cleanup
979
4343.3.32 by John Arbash Meinel
Change the tests for _find_revision_outside_set to the new _find_parent_ids function.
980
    def assertParentIds(self, expected_result, rev_set):
981
        self.assertEqual(sorted(expected_result),
982
            sorted(self.repo._find_parent_ids_of_revisions(rev_set)))
3735.4.1 by Andrew Bennetts
Add _find_revision_outside_set.
983
984
    def test_simple(self):
985
        self.builder.build_snapshot('revid1', None, [])
4343.3.32 by John Arbash Meinel
Change the tests for _find_revision_outside_set to the new _find_parent_ids function.
986
        self.builder.build_snapshot('revid2', ['revid1'], [])
3735.4.1 by Andrew Bennetts
Add _find_revision_outside_set.
987
        rev_set = ['revid2']
4343.3.32 by John Arbash Meinel
Change the tests for _find_revision_outside_set to the new _find_parent_ids function.
988
        self.assertParentIds(['revid1'], rev_set)
3735.4.1 by Andrew Bennetts
Add _find_revision_outside_set.
989
990
    def test_not_first_parent(self):
991
        self.builder.build_snapshot('revid1', None, [])
4343.3.32 by John Arbash Meinel
Change the tests for _find_revision_outside_set to the new _find_parent_ids function.
992
        self.builder.build_snapshot('revid2', ['revid1'], [])
993
        self.builder.build_snapshot('revid3', ['revid2'], [])
3735.4.1 by Andrew Bennetts
Add _find_revision_outside_set.
994
        rev_set = ['revid3', 'revid2']
4343.3.32 by John Arbash Meinel
Change the tests for _find_revision_outside_set to the new _find_parent_ids function.
995
        self.assertParentIds(['revid1'], rev_set)
3735.4.1 by Andrew Bennetts
Add _find_revision_outside_set.
996
997
    def test_not_null(self):
998
        rev_set = ['initial']
4343.3.32 by John Arbash Meinel
Change the tests for _find_revision_outside_set to the new _find_parent_ids function.
999
        self.assertParentIds([], rev_set)
3735.4.1 by Andrew Bennetts
Add _find_revision_outside_set.
1000
1001
    def test_not_null_set(self):
1002
        self.builder.build_snapshot('revid1', None, [])
1003
        rev_set = [_mod_revision.NULL_REVISION]
4343.3.32 by John Arbash Meinel
Change the tests for _find_revision_outside_set to the new _find_parent_ids function.
1004
        self.assertParentIds([], rev_set)
3735.4.1 by Andrew Bennetts
Add _find_revision_outside_set.
1005
1006
    def test_ghost(self):
1007
        self.builder.build_snapshot('revid1', None, [])
1008
        rev_set = ['ghost', 'revid1']
4343.3.32 by John Arbash Meinel
Change the tests for _find_revision_outside_set to the new _find_parent_ids function.
1009
        self.assertParentIds(['initial'], rev_set)
3735.4.1 by Andrew Bennetts
Add _find_revision_outside_set.
1010
1011
    def test_ghost_parent(self):
1012
        self.builder.build_snapshot('revid1', None, [])
1013
        self.builder.build_snapshot('revid2', ['revid1', 'ghost'], [])
1014
        rev_set = ['revid2', 'revid1']
4343.3.32 by John Arbash Meinel
Change the tests for _find_revision_outside_set to the new _find_parent_ids function.
1015
        self.assertParentIds(['ghost', 'initial'], rev_set)
3735.4.1 by Andrew Bennetts
Add _find_revision_outside_set.
1016
1017
    def test_righthand_parent(self):
1018
        self.builder.build_snapshot('revid1', None, [])
1019
        self.builder.build_snapshot('revid2a', ['revid1'], [])
1020
        self.builder.build_snapshot('revid2b', ['revid1'], [])
1021
        self.builder.build_snapshot('revid3', ['revid2a', 'revid2b'], [])
1022
        rev_set = ['revid3', 'revid2a']
4343.3.32 by John Arbash Meinel
Change the tests for _find_revision_outside_set to the new _find_parent_ids function.
1023
        self.assertParentIds(['revid1', 'revid2b'], rev_set)
3735.4.1 by Andrew Bennetts
Add _find_revision_outside_set.
1024
1025
2535.3.57 by Andrew Bennetts
Perform some sanity checking of data streams rather than blindly inserting them into our repository.
1026
class TestWithBrokenRepo(TestCaseWithTransport):
2592.3.214 by Robert Collins
Merge bzr.dev.
1027
    """These tests seem to be more appropriate as interface tests?"""
2535.3.57 by Andrew Bennetts
Perform some sanity checking of data streams rather than blindly inserting them into our repository.
1028
1029
    def make_broken_repository(self):
1030
        # XXX: This function is borrowed from Aaron's "Reconcile can fix bad
1031
        # parent references" branch which is due to land in bzr.dev soon.  Once
1032
        # it does, this duplication should be removed.
1033
        repo = self.make_repository('broken-repo')
1034
        cleanups = []
1035
        try:
1036
            repo.lock_write()
1037
            cleanups.append(repo.unlock)
1038
            repo.start_write_group()
1039
            cleanups.append(repo.commit_write_group)
1040
            # make rev1a: A well-formed revision, containing 'file1'
1041
            inv = inventory.Inventory(revision_id='rev1a')
1042
            inv.root.revision = 'rev1a'
1043
            self.add_file(repo, inv, 'file1', 'rev1a', [])
4634.35.21 by Andrew Bennetts
Fix test_insert_from_broken_repo in test_repository.
1044
            repo.texts.add_lines((inv.root.file_id, 'rev1a'), [], [])
2535.3.57 by Andrew Bennetts
Perform some sanity checking of data streams rather than blindly inserting them into our repository.
1045
            repo.add_inventory('rev1a', inv, [])
1046
            revision = _mod_revision.Revision('rev1a',
1047
                committer='jrandom@example.com', timestamp=0,
1048
                inventory_sha1='', timezone=0, message='foo', parent_ids=[])
1049
            repo.add_revision('rev1a',revision, inv)
1050
1051
            # make rev1b, which has no Revision, but has an Inventory, and
1052
            # file1
1053
            inv = inventory.Inventory(revision_id='rev1b')
1054
            inv.root.revision = 'rev1b'
1055
            self.add_file(repo, inv, 'file1', 'rev1b', [])
1056
            repo.add_inventory('rev1b', inv, [])
1057
1058
            # make rev2, with file1 and file2
1059
            # file2 is sane
1060
            # file1 has 'rev1b' as an ancestor, even though this is not
1061
            # mentioned by 'rev1a', making it an unreferenced ancestor
1062
            inv = inventory.Inventory()
1063
            self.add_file(repo, inv, 'file1', 'rev2', ['rev1a', 'rev1b'])
1064
            self.add_file(repo, inv, 'file2', 'rev2', [])
1065
            self.add_revision(repo, 'rev2', inv, ['rev1a'])
1066
1067
            # make ghost revision rev1c
1068
            inv = inventory.Inventory()
1069
            self.add_file(repo, inv, 'file2', 'rev1c', [])
1070
1071
            # make rev3 with file2
1072
            # file2 refers to 'rev1c', which is a ghost in this repository, so
1073
            # file2 cannot have rev1c as its ancestor.
1074
            inv = inventory.Inventory()
1075
            self.add_file(repo, inv, 'file2', 'rev3', ['rev1c'])
1076
            self.add_revision(repo, 'rev3', inv, ['rev1c'])
1077
            return repo
1078
        finally:
1079
            for cleanup in reversed(cleanups):
1080
                cleanup()
1081
1082
    def add_revision(self, repo, revision_id, inv, parent_ids):
1083
        inv.revision_id = revision_id
1084
        inv.root.revision = revision_id
4634.35.21 by Andrew Bennetts
Fix test_insert_from_broken_repo in test_repository.
1085
        repo.texts.add_lines((inv.root.file_id, revision_id), [], [])
2535.3.57 by Andrew Bennetts
Perform some sanity checking of data streams rather than blindly inserting them into our repository.
1086
        repo.add_inventory(revision_id, inv, parent_ids)
1087
        revision = _mod_revision.Revision(revision_id,
1088
            committer='jrandom@example.com', timestamp=0, inventory_sha1='',
1089
            timezone=0, message='foo', parent_ids=parent_ids)
1090
        repo.add_revision(revision_id,revision, inv)
1091
1092
    def add_file(self, repo, inv, filename, revision, parents):
1093
        file_id = filename + '-id'
1094
        entry = inventory.InventoryFile(file_id, filename, 'TREE_ROOT')
1095
        entry.revision = revision
2535.4.10 by Andrew Bennetts
Fix one failing test, disable another.
1096
        entry.text_size = 0
2535.3.57 by Andrew Bennetts
Perform some sanity checking of data streams rather than blindly inserting them into our repository.
1097
        inv.add(entry)
3350.6.4 by Robert Collins
First cut at pluralised VersionedFiles. Some rather massive API incompatabilities, primarily because of the difficulty of coherence among competing stores.
1098
        text_key = (file_id, revision)
1099
        parent_keys = [(file_id, parent) for parent in parents]
1100
        repo.texts.add_lines(text_key, parent_keys, ['line\n'])
2535.3.57 by Andrew Bennetts
Perform some sanity checking of data streams rather than blindly inserting them into our repository.
1101
1102
    def test_insert_from_broken_repo(self):
1103
        """Inserting a data stream from a broken repository won't silently
1104
        corrupt the target repository.
1105
        """
1106
        broken_repo = self.make_broken_repository()
1107
        empty_repo = self.make_repository('empty-repo')
4606.1.1 by Robert Collins
Change test_insert_from_broken_repo from a known failure to a working test.
1108
        try:
1109
            empty_repo.fetch(broken_repo)
1110
        except (errors.RevisionNotPresent, errors.BzrCheckError):
1111
            # Test successful: compression parent not being copied leads to
1112
            # error.
1113
            return
1114
        empty_repo.lock_read()
1115
        self.addCleanup(empty_repo.unlock)
1116
        text = empty_repo.texts.get_record_stream(
1117
            [('file2-id', 'rev3')], 'topological', True).next()
1118
        self.assertEqual('line\n', text.get_bytes_as('fulltext'))
2592.3.214 by Robert Collins
Merge bzr.dev.
1119
1120
2592.3.84 by Robert Collins
Start of autopacking logic.
1121
class TestRepositoryPackCollection(TestCaseWithTransport):
1122
1123
    def get_format(self):
3010.3.3 by Martin Pool
Merge trunk
1124
        return bzrdir.format_registry.make_bzrdir('pack-0.92')
2592.3.84 by Robert Collins
Start of autopacking logic.
1125
3711.4.1 by John Arbash Meinel
Fix bug #242510, when determining the autopack sequence,
1126
    def get_packs(self):
1127
        format = self.get_format()
1128
        repo = self.make_repository('.', format=format)
1129
        return repo._pack_collection
1130
3789.2.20 by John Arbash Meinel
The autopack code can now trigger itself to retry when _copy_revision_texts fails.
1131
    def make_packs_and_alt_repo(self, write_lock=False):
3789.2.19 by John Arbash Meinel
Refactor to make the tests a bit simpler
1132
        """Create a pack repo with 3 packs, and access it via a second repo."""
4617.4.1 by Robert Collins
Fix a pack specific test which didn't lock its format down.
1133
        tree = self.make_branch_and_tree('.', format=self.get_format())
3789.2.19 by John Arbash Meinel
Refactor to make the tests a bit simpler
1134
        tree.lock_write()
1135
        self.addCleanup(tree.unlock)
1136
        rev1 = tree.commit('one')
1137
        rev2 = tree.commit('two')
1138
        rev3 = tree.commit('three')
1139
        r = repository.Repository.open('.')
3789.2.20 by John Arbash Meinel
The autopack code can now trigger itself to retry when _copy_revision_texts fails.
1140
        if write_lock:
1141
            r.lock_write()
1142
        else:
1143
            r.lock_read()
3789.2.19 by John Arbash Meinel
Refactor to make the tests a bit simpler
1144
        self.addCleanup(r.unlock)
1145
        packs = r._pack_collection
1146
        packs.ensure_loaded()
1147
        return tree, r, packs, [rev1, rev2, rev3]
1148
4634.127.1 by John Arbash Meinel
Partial fix for bug #507557.
1149
    def test__clear_obsolete_packs(self):
1150
        packs = self.get_packs()
1151
        obsolete_pack_trans = packs.transport.clone('obsolete_packs')
1152
        obsolete_pack_trans.put_bytes('a-pack.pack', 'content\n')
1153
        obsolete_pack_trans.put_bytes('a-pack.rix', 'content\n')
1154
        obsolete_pack_trans.put_bytes('a-pack.iix', 'content\n')
1155
        obsolete_pack_trans.put_bytes('another-pack.pack', 'foo\n')
1156
        obsolete_pack_trans.put_bytes('not-a-pack.rix', 'foo\n')
1157
        res = packs._clear_obsolete_packs()
1158
        self.assertEqual(['a-pack', 'another-pack'], sorted(res))
1159
        self.assertEqual([], obsolete_pack_trans.list_dir('.'))
1160
1161
    def test__clear_obsolete_packs_preserve(self):
1162
        packs = self.get_packs()
1163
        obsolete_pack_trans = packs.transport.clone('obsolete_packs')
1164
        obsolete_pack_trans.put_bytes('a-pack.pack', 'content\n')
1165
        obsolete_pack_trans.put_bytes('a-pack.rix', 'content\n')
1166
        obsolete_pack_trans.put_bytes('a-pack.iix', 'content\n')
1167
        obsolete_pack_trans.put_bytes('another-pack.pack', 'foo\n')
1168
        obsolete_pack_trans.put_bytes('not-a-pack.rix', 'foo\n')
1169
        res = packs._clear_obsolete_packs(preserve=set(['a-pack']))
1170
        self.assertEqual(['a-pack', 'another-pack'], sorted(res))
1171
        self.assertEqual(['a-pack.iix', 'a-pack.pack', 'a-pack.rix'],
1172
                         sorted(obsolete_pack_trans.list_dir('.')))
1173
2592.3.84 by Robert Collins
Start of autopacking logic.
1174
    def test__max_pack_count(self):
2592.3.219 by Robert Collins
Review feedback.
1175
        """The maximum pack count is a function of the number of revisions."""
2592.3.84 by Robert Collins
Start of autopacking logic.
1176
        # no revisions - one pack, so that we can have a revision free repo
1177
        # without it blowing up
3711.4.1 by John Arbash Meinel
Fix bug #242510, when determining the autopack sequence,
1178
        packs = self.get_packs()
2592.3.84 by Robert Collins
Start of autopacking logic.
1179
        self.assertEqual(1, packs._max_pack_count(0))
1180
        # after that the sum of the digits, - check the first 1-9
1181
        self.assertEqual(1, packs._max_pack_count(1))
1182
        self.assertEqual(2, packs._max_pack_count(2))
1183
        self.assertEqual(3, packs._max_pack_count(3))
1184
        self.assertEqual(4, packs._max_pack_count(4))
1185
        self.assertEqual(5, packs._max_pack_count(5))
1186
        self.assertEqual(6, packs._max_pack_count(6))
1187
        self.assertEqual(7, packs._max_pack_count(7))
1188
        self.assertEqual(8, packs._max_pack_count(8))
1189
        self.assertEqual(9, packs._max_pack_count(9))
1190
        # check the boundary cases with two digits for the next decade
1191
        self.assertEqual(1, packs._max_pack_count(10))
1192
        self.assertEqual(2, packs._max_pack_count(11))
1193
        self.assertEqual(10, packs._max_pack_count(19))
1194
        self.assertEqual(2, packs._max_pack_count(20))
1195
        self.assertEqual(3, packs._max_pack_count(21))
1196
        # check some arbitrary big numbers
1197
        self.assertEqual(25, packs._max_pack_count(112894))
1198
4928.1.1 by Martin Pool
Give RepositoryPackCollection a repr
1199
    def test_repr(self):
1200
        packs = self.get_packs()
1201
        self.assertContainsRe(repr(packs),
1202
            'RepositoryPackCollection(.*Repository(.*))')
1203
4634.127.2 by John Arbash Meinel
Change the _obsolete_packs code to handle files that are already gone.
1204
    def test__obsolete_packs(self):
1205
        tree, r, packs, revs = self.make_packs_and_alt_repo(write_lock=True)
1206
        names = packs.names()
1207
        pack = packs.get_pack_by_name(names[0])
1208
        # Schedule this one for removal
1209
        packs._remove_pack_from_memory(pack)
1210
        # Simulate a concurrent update by renaming the .pack file and one of
1211
        # the indices
1212
        packs.transport.rename('packs/%s.pack' % (names[0],),
1213
                               'obsolete_packs/%s.pack' % (names[0],))
1214
        packs.transport.rename('indices/%s.iix' % (names[0],),
1215
                               'obsolete_packs/%s.iix' % (names[0],))
1216
        # Now trigger the obsoletion, and ensure that all the remaining files
1217
        # are still renamed
1218
        packs._obsolete_packs([pack])
1219
        self.assertEqual([n + '.pack' for n in names[1:]],
1220
                         sorted(packs._pack_transport.list_dir('.')))
1221
        # names[0] should not be present in the index anymore
1222
        self.assertEqual(names[1:],
1223
            sorted(set([osutils.splitext(n)[0] for n in
1224
                        packs._index_transport.list_dir('.')])))
1225
2592.3.84 by Robert Collins
Start of autopacking logic.
1226
    def test_pack_distribution_zero(self):
3711.4.1 by John Arbash Meinel
Fix bug #242510, when determining the autopack sequence,
1227
        packs = self.get_packs()
2592.3.84 by Robert Collins
Start of autopacking logic.
1228
        self.assertEqual([0], packs.pack_distribution(0))
3052.1.6 by John Arbash Meinel
Change the lock check to raise ObjectNotLocked.
1229
1230
    def test_ensure_loaded_unlocked(self):
3711.4.1 by John Arbash Meinel
Fix bug #242510, when determining the autopack sequence,
1231
        packs = self.get_packs()
3052.1.6 by John Arbash Meinel
Change the lock check to raise ObjectNotLocked.
1232
        self.assertRaises(errors.ObjectNotLocked,
3711.4.1 by John Arbash Meinel
Fix bug #242510, when determining the autopack sequence,
1233
                          packs.ensure_loaded)
3052.1.6 by John Arbash Meinel
Change the lock check to raise ObjectNotLocked.
1234
2592.3.84 by Robert Collins
Start of autopacking logic.
1235
    def test_pack_distribution_one_to_nine(self):
3711.4.1 by John Arbash Meinel
Fix bug #242510, when determining the autopack sequence,
1236
        packs = self.get_packs()
2592.3.84 by Robert Collins
Start of autopacking logic.
1237
        self.assertEqual([1],
1238
            packs.pack_distribution(1))
1239
        self.assertEqual([1, 1],
1240
            packs.pack_distribution(2))
1241
        self.assertEqual([1, 1, 1],
1242
            packs.pack_distribution(3))
1243
        self.assertEqual([1, 1, 1, 1],
1244
            packs.pack_distribution(4))
1245
        self.assertEqual([1, 1, 1, 1, 1],
1246
            packs.pack_distribution(5))
1247
        self.assertEqual([1, 1, 1, 1, 1, 1],
1248
            packs.pack_distribution(6))
1249
        self.assertEqual([1, 1, 1, 1, 1, 1, 1],
1250
            packs.pack_distribution(7))
1251
        self.assertEqual([1, 1, 1, 1, 1, 1, 1, 1],
1252
            packs.pack_distribution(8))
1253
        self.assertEqual([1, 1, 1, 1, 1, 1, 1, 1, 1],
1254
            packs.pack_distribution(9))
1255
1256
    def test_pack_distribution_stable_at_boundaries(self):
1257
        """When there are multi-rev packs the counts are stable."""
3711.4.1 by John Arbash Meinel
Fix bug #242510, when determining the autopack sequence,
1258
        packs = self.get_packs()
2592.3.84 by Robert Collins
Start of autopacking logic.
1259
        # in 10s:
1260
        self.assertEqual([10], packs.pack_distribution(10))
1261
        self.assertEqual([10, 1], packs.pack_distribution(11))
1262
        self.assertEqual([10, 10], packs.pack_distribution(20))
1263
        self.assertEqual([10, 10, 1], packs.pack_distribution(21))
1264
        # 100s
1265
        self.assertEqual([100], packs.pack_distribution(100))
1266
        self.assertEqual([100, 1], packs.pack_distribution(101))
1267
        self.assertEqual([100, 10, 1], packs.pack_distribution(111))
1268
        self.assertEqual([100, 100], packs.pack_distribution(200))
1269
        self.assertEqual([100, 100, 1], packs.pack_distribution(201))
1270
        self.assertEqual([100, 100, 10, 1], packs.pack_distribution(211))
1271
2592.3.85 by Robert Collins
Finish autopack corner cases.
1272
    def test_plan_pack_operations_2009_revisions_skip_all_packs(self):
3711.4.1 by John Arbash Meinel
Fix bug #242510, when determining the autopack sequence,
1273
        packs = self.get_packs()
2592.3.85 by Robert Collins
Finish autopack corner cases.
1274
        existing_packs = [(2000, "big"), (9, "medium")]
1275
        # rev count - 2009 -> 2x1000 + 9x1
1276
        pack_operations = packs.plan_autopack_combinations(
1277
            existing_packs, [1000, 1000, 1, 1, 1, 1, 1, 1, 1, 1, 1])
1278
        self.assertEqual([], pack_operations)
1279
1280
    def test_plan_pack_operations_2010_revisions_skip_all_packs(self):
3711.4.1 by John Arbash Meinel
Fix bug #242510, when determining the autopack sequence,
1281
        packs = self.get_packs()
2592.3.85 by Robert Collins
Finish autopack corner cases.
1282
        existing_packs = [(2000, "big"), (9, "medium"), (1, "single")]
1283
        # rev count - 2010 -> 2x1000 + 1x10
1284
        pack_operations = packs.plan_autopack_combinations(
1285
            existing_packs, [1000, 1000, 10])
1286
        self.assertEqual([], pack_operations)
1287
1288
    def test_plan_pack_operations_2010_combines_smallest_two(self):
3711.4.1 by John Arbash Meinel
Fix bug #242510, when determining the autopack sequence,
1289
        packs = self.get_packs()
2592.3.85 by Robert Collins
Finish autopack corner cases.
1290
        existing_packs = [(1999, "big"), (9, "medium"), (1, "single2"),
1291
            (1, "single1")]
1292
        # rev count - 2010 -> 2x1000 + 1x10 (3)
1293
        pack_operations = packs.plan_autopack_combinations(
1294
            existing_packs, [1000, 1000, 10])
3711.4.2 by John Arbash Meinel
Change the logic to solve it in a different way.
1295
        self.assertEqual([[2, ["single2", "single1"]]], pack_operations)
2592.3.85 by Robert Collins
Finish autopack corner cases.
1296
3711.4.2 by John Arbash Meinel
Change the logic to solve it in a different way.
1297
    def test_plan_pack_operations_creates_a_single_op(self):
3711.4.1 by John Arbash Meinel
Fix bug #242510, when determining the autopack sequence,
1298
        packs = self.get_packs()
3711.4.2 by John Arbash Meinel
Change the logic to solve it in a different way.
1299
        existing_packs = [(50, 'a'), (40, 'b'), (30, 'c'), (10, 'd'),
1300
                          (10, 'e'), (6, 'f'), (4, 'g')]
1301
        # rev count 150 -> 1x100 and 5x10
1302
        # The two size 10 packs do not need to be touched. The 50, 40, 30 would
1303
        # be combined into a single 120 size pack, and the 6 & 4 would
1304
        # becombined into a size 10 pack. However, if we have to rewrite them,
1305
        # we save a pack file with no increased I/O by putting them into the
1306
        # same file.
1307
        distribution = packs.pack_distribution(150)
3711.4.1 by John Arbash Meinel
Fix bug #242510, when determining the autopack sequence,
1308
        pack_operations = packs.plan_autopack_combinations(existing_packs,
3711.4.2 by John Arbash Meinel
Change the logic to solve it in a different way.
1309
                                                           distribution)
1310
        self.assertEqual([[130, ['a', 'b', 'c', 'f', 'g']]], pack_operations)
3711.4.1 by John Arbash Meinel
Fix bug #242510, when determining the autopack sequence,
1311
2592.3.173 by Robert Collins
Basic implementation of all_packs.
1312
    def test_all_packs_none(self):
1313
        format = self.get_format()
1314
        tree = self.make_branch_and_tree('.', format=format)
1315
        tree.lock_read()
1316
        self.addCleanup(tree.unlock)
2592.3.232 by Martin Pool
Disambiguate two member variables called _packs into _packs_by_name and _pack_collection
1317
        packs = tree.branch.repository._pack_collection
2592.3.173 by Robert Collins
Basic implementation of all_packs.
1318
        packs.ensure_loaded()
1319
        self.assertEqual([], packs.all_packs())
1320
1321
    def test_all_packs_one(self):
1322
        format = self.get_format()
1323
        tree = self.make_branch_and_tree('.', format=format)
1324
        tree.commit('start')
1325
        tree.lock_read()
1326
        self.addCleanup(tree.unlock)
2592.3.232 by Martin Pool
Disambiguate two member variables called _packs into _packs_by_name and _pack_collection
1327
        packs = tree.branch.repository._pack_collection
2592.3.173 by Robert Collins
Basic implementation of all_packs.
1328
        packs.ensure_loaded()
2592.3.176 by Robert Collins
Various pack refactorings.
1329
        self.assertEqual([
1330
            packs.get_pack_by_name(packs.names()[0])],
1331
            packs.all_packs())
2592.3.173 by Robert Collins
Basic implementation of all_packs.
1332
1333
    def test_all_packs_two(self):
1334
        format = self.get_format()
1335
        tree = self.make_branch_and_tree('.', format=format)
1336
        tree.commit('start')
1337
        tree.commit('continue')
1338
        tree.lock_read()
1339
        self.addCleanup(tree.unlock)
2592.3.232 by Martin Pool
Disambiguate two member variables called _packs into _packs_by_name and _pack_collection
1340
        packs = tree.branch.repository._pack_collection
2592.3.173 by Robert Collins
Basic implementation of all_packs.
1341
        packs.ensure_loaded()
1342
        self.assertEqual([
2592.3.176 by Robert Collins
Various pack refactorings.
1343
            packs.get_pack_by_name(packs.names()[0]),
1344
            packs.get_pack_by_name(packs.names()[1]),
2592.3.173 by Robert Collins
Basic implementation of all_packs.
1345
            ], packs.all_packs())
1346
2592.3.176 by Robert Collins
Various pack refactorings.
1347
    def test_get_pack_by_name(self):
1348
        format = self.get_format()
1349
        tree = self.make_branch_and_tree('.', format=format)
1350
        tree.commit('start')
1351
        tree.lock_read()
1352
        self.addCleanup(tree.unlock)
2592.3.232 by Martin Pool
Disambiguate two member variables called _packs into _packs_by_name and _pack_collection
1353
        packs = tree.branch.repository._pack_collection
4145.1.6 by Robert Collins
More test fallout, but all caught now.
1354
        packs.reset()
2592.3.176 by Robert Collins
Various pack refactorings.
1355
        packs.ensure_loaded()
1356
        name = packs.names()[0]
1357
        pack_1 = packs.get_pack_by_name(name)
1358
        # the pack should be correctly initialised
3517.4.5 by Martin Pool
Correct use of packs._names in test_get_pack_by_name
1359
        sizes = packs._names[name]
3221.12.4 by Robert Collins
Implement basic repository supporting external references.
1360
        rev_index = GraphIndex(packs._index_transport, name + '.rix', sizes[0])
1361
        inv_index = GraphIndex(packs._index_transport, name + '.iix', sizes[1])
1362
        txt_index = GraphIndex(packs._index_transport, name + '.tix', sizes[2])
1363
        sig_index = GraphIndex(packs._index_transport, name + '.six', sizes[3])
2592.3.191 by Robert Collins
Give Pack responsibility for index naming, and two concrete classes - NewPack for new packs and ExistingPack for packs we read from disk.
1364
        self.assertEqual(pack_repo.ExistingPack(packs._pack_transport,
2592.3.219 by Robert Collins
Review feedback.
1365
            name, rev_index, inv_index, txt_index, sig_index), pack_1)
2592.3.176 by Robert Collins
Various pack refactorings.
1366
        # and the same instance should be returned on successive calls.
1367
        self.assertTrue(pack_1 is packs.get_pack_by_name(name))
1368
3789.1.2 by John Arbash Meinel
Add RepositoryPackCollection.reload_pack_names()
1369
    def test_reload_pack_names_new_entry(self):
3789.2.19 by John Arbash Meinel
Refactor to make the tests a bit simpler
1370
        tree, r, packs, revs = self.make_packs_and_alt_repo()
3789.1.2 by John Arbash Meinel
Add RepositoryPackCollection.reload_pack_names()
1371
        names = packs.names()
1372
        # Add a new pack file into the repository
3789.2.19 by John Arbash Meinel
Refactor to make the tests a bit simpler
1373
        rev4 = tree.commit('four')
3789.1.2 by John Arbash Meinel
Add RepositoryPackCollection.reload_pack_names()
1374
        new_names = tree.branch.repository._pack_collection.names()
1375
        new_name = set(new_names).difference(names)
1376
        self.assertEqual(1, len(new_name))
1377
        new_name = new_name.pop()
1378
        # The old collection hasn't noticed yet
1379
        self.assertEqual(names, packs.names())
3789.1.8 by John Arbash Meinel
Change the api of reload_pack_names().
1380
        self.assertTrue(packs.reload_pack_names())
3789.1.2 by John Arbash Meinel
Add RepositoryPackCollection.reload_pack_names()
1381
        self.assertEqual(new_names, packs.names())
1382
        # And the repository can access the new revision
3789.2.19 by John Arbash Meinel
Refactor to make the tests a bit simpler
1383
        self.assertEqual({rev4:(revs[-1],)}, r.get_parent_map([rev4]))
3789.1.8 by John Arbash Meinel
Change the api of reload_pack_names().
1384
        self.assertFalse(packs.reload_pack_names())
3789.1.2 by John Arbash Meinel
Add RepositoryPackCollection.reload_pack_names()
1385
1386
    def test_reload_pack_names_added_and_removed(self):
3789.2.19 by John Arbash Meinel
Refactor to make the tests a bit simpler
1387
        tree, r, packs, revs = self.make_packs_and_alt_repo()
3789.1.2 by John Arbash Meinel
Add RepositoryPackCollection.reload_pack_names()
1388
        names = packs.names()
1389
        # Now repack the whole thing
1390
        tree.branch.repository.pack()
1391
        new_names = tree.branch.repository._pack_collection.names()
1392
        # The other collection hasn't noticed yet
1393
        self.assertEqual(names, packs.names())
3789.1.8 by John Arbash Meinel
Change the api of reload_pack_names().
1394
        self.assertTrue(packs.reload_pack_names())
3789.1.2 by John Arbash Meinel
Add RepositoryPackCollection.reload_pack_names()
1395
        self.assertEqual(new_names, packs.names())
3789.2.19 by John Arbash Meinel
Refactor to make the tests a bit simpler
1396
        self.assertEqual({revs[-1]:(revs[-2],)}, r.get_parent_map([revs[-1]]))
3789.1.8 by John Arbash Meinel
Change the api of reload_pack_names().
1397
        self.assertFalse(packs.reload_pack_names())
3789.1.2 by John Arbash Meinel
Add RepositoryPackCollection.reload_pack_names()
1398
4634.126.1 by John Arbash Meinel
(jam) Fix bug #507566, concurrent autopacking correctness.
1399
    def test_reload_pack_names_preserves_pending(self):
1400
        # TODO: Update this to also test for pending-deleted names
1401
        tree, r, packs, revs = self.make_packs_and_alt_repo(write_lock=True)
1402
        # We will add one pack (via start_write_group + insert_record_stream),
1403
        # and remove another pack (via _remove_pack_from_memory)
1404
        orig_names = packs.names()
1405
        orig_at_load = packs._packs_at_load
1406
        to_remove_name = iter(orig_names).next()
1407
        r.start_write_group()
1408
        self.addCleanup(r.abort_write_group)
1409
        r.texts.insert_record_stream([versionedfile.FulltextContentFactory(
1410
            ('text', 'rev'), (), None, 'content\n')])
1411
        new_pack = packs._new_pack
1412
        self.assertTrue(new_pack.data_inserted())
1413
        new_pack.finish()
1414
        packs.allocate(new_pack)
1415
        packs._new_pack = None
1416
        removed_pack = packs.get_pack_by_name(to_remove_name)
1417
        packs._remove_pack_from_memory(removed_pack)
1418
        names = packs.names()
4634.127.3 by John Arbash Meinel
Add code so we don't try to obsolete files someone else has 'claimed'.
1419
        all_nodes, deleted_nodes, new_nodes, _ = packs._diff_pack_names()
4634.126.1 by John Arbash Meinel
(jam) Fix bug #507566, concurrent autopacking correctness.
1420
        new_names = set([x[0][0] for x in new_nodes])
1421
        self.assertEqual(names, sorted([x[0][0] for x in all_nodes]))
1422
        self.assertEqual(set(names) - set(orig_names), new_names)
1423
        self.assertEqual(set([new_pack.name]), new_names)
1424
        self.assertEqual([to_remove_name],
1425
                         sorted([x[0][0] for x in deleted_nodes]))
1426
        packs.reload_pack_names()
1427
        reloaded_names = packs.names()
1428
        self.assertEqual(orig_at_load, packs._packs_at_load)
1429
        self.assertEqual(names, reloaded_names)
4634.127.3 by John Arbash Meinel
Add code so we don't try to obsolete files someone else has 'claimed'.
1430
        all_nodes, deleted_nodes, new_nodes, _ = packs._diff_pack_names()
4634.126.1 by John Arbash Meinel
(jam) Fix bug #507566, concurrent autopacking correctness.
1431
        new_names = set([x[0][0] for x in new_nodes])
1432
        self.assertEqual(names, sorted([x[0][0] for x in all_nodes]))
1433
        self.assertEqual(set(names) - set(orig_names), new_names)
1434
        self.assertEqual(set([new_pack.name]), new_names)
1435
        self.assertEqual([to_remove_name],
1436
                         sorted([x[0][0] for x in deleted_nodes]))
1437
4634.127.5 by John Arbash Meinel
Possible fix for making sure packs triggering autopacking get cleaned up.
1438
    def test_autopack_obsoletes_new_pack(self):
1439
        tree, r, packs, revs = self.make_packs_and_alt_repo(write_lock=True)
1440
        packs._max_pack_count = lambda x: 1
1441
        packs.pack_distribution = lambda x: [10]
1442
        r.start_write_group()
1443
        r.revisions.insert_record_stream([versionedfile.FulltextContentFactory(
1444
            ('bogus-rev',), (), None, 'bogus-content\n')])
1445
        # This should trigger an autopack, which will combine everything into a
1446
        # single pack file.
1447
        new_names = r.commit_write_group()
1448
        names = packs.names()
1449
        self.assertEqual(1, len(names))
1450
        self.assertEqual([names[0] + '.pack'],
1451
                         packs._pack_transport.list_dir('.'))
1452
3789.2.20 by John Arbash Meinel
The autopack code can now trigger itself to retry when _copy_revision_texts fails.
1453
    def test_autopack_reloads_and_stops(self):
1454
        tree, r, packs, revs = self.make_packs_and_alt_repo(write_lock=True)
1455
        # After we have determined what needs to be autopacked, trigger a
1456
        # full-pack via the other repo which will cause us to re-evaluate and
1457
        # decide we don't need to do anything
1458
        orig_execute = packs._execute_pack_operations
1459
        def _munged_execute_pack_ops(*args, **kwargs):
1460
            tree.branch.repository.pack()
1461
            return orig_execute(*args, **kwargs)
1462
        packs._execute_pack_operations = _munged_execute_pack_ops
1463
        packs._max_pack_count = lambda x: 1
1464
        packs.pack_distribution = lambda x: [10]
1465
        self.assertFalse(packs.autopack())
1466
        self.assertEqual(1, len(packs.names()))
1467
        self.assertEqual(tree.branch.repository._pack_collection.names(),
1468
                         packs.names())
1469
4634.127.1 by John Arbash Meinel
Partial fix for bug #507557.
1470
    def test__save_pack_names(self):
1471
        tree, r, packs, revs = self.make_packs_and_alt_repo(write_lock=True)
1472
        names = packs.names()
1473
        pack = packs.get_pack_by_name(names[0])
1474
        packs._remove_pack_from_memory(pack)
1475
        packs._save_pack_names(obsolete_packs=[pack])
1476
        cur_packs = packs._pack_transport.list_dir('.')
1477
        self.assertEqual([n + '.pack' for n in names[1:]], sorted(cur_packs))
1478
        # obsolete_packs will also have stuff like .rix and .iix present.
1479
        obsolete_packs = packs.transport.list_dir('obsolete_packs')
1480
        obsolete_names = set([osutils.splitext(n)[0] for n in obsolete_packs])
1481
        self.assertEqual([pack.name], sorted(obsolete_names))
1482
1483
    def test__save_pack_names_already_obsoleted(self):
1484
        tree, r, packs, revs = self.make_packs_and_alt_repo(write_lock=True)
1485
        names = packs.names()
1486
        pack = packs.get_pack_by_name(names[0])
1487
        packs._remove_pack_from_memory(pack)
1488
        # We are going to simulate a concurrent autopack by manually obsoleting
1489
        # the pack directly.
1490
        packs._obsolete_packs([pack])
1491
        packs._save_pack_names(clear_obsolete_packs=True,
1492
                               obsolete_packs=[pack])
1493
        cur_packs = packs._pack_transport.list_dir('.')
1494
        self.assertEqual([n + '.pack' for n in names[1:]], sorted(cur_packs))
1495
        # Note that while we set clear_obsolete_packs=True, it should not
1496
        # delete a pack file that we have also scheduled for obsoletion.
1497
        obsolete_packs = packs.transport.list_dir('obsolete_packs')
1498
        obsolete_names = set([osutils.splitext(n)[0] for n in obsolete_packs])
1499
        self.assertEqual([pack.name], sorted(obsolete_names))
1500
4634.127.3 by John Arbash Meinel
Add code so we don't try to obsolete files someone else has 'claimed'.
1501
2592.3.173 by Robert Collins
Basic implementation of all_packs.
1502
1503
class TestPack(TestCaseWithTransport):
1504
    """Tests for the Pack object."""
1505
1506
    def assertCurrentlyEqual(self, left, right):
1507
        self.assertTrue(left == right)
1508
        self.assertTrue(right == left)
1509
        self.assertFalse(left != right)
1510
        self.assertFalse(right != left)
1511
1512
    def assertCurrentlyNotEqual(self, left, right):
1513
        self.assertFalse(left == right)
1514
        self.assertFalse(right == left)
1515
        self.assertTrue(left != right)
1516
        self.assertTrue(right != left)
1517
1518
    def test___eq____ne__(self):
2592.3.191 by Robert Collins
Give Pack responsibility for index naming, and two concrete classes - NewPack for new packs and ExistingPack for packs we read from disk.
1519
        left = pack_repo.ExistingPack('', '', '', '', '', '')
1520
        right = pack_repo.ExistingPack('', '', '', '', '', '')
2592.3.173 by Robert Collins
Basic implementation of all_packs.
1521
        self.assertCurrentlyEqual(left, right)
1522
        # change all attributes and ensure equality changes as we do.
1523
        left.revision_index = 'a'
1524
        self.assertCurrentlyNotEqual(left, right)
1525
        right.revision_index = 'a'
1526
        self.assertCurrentlyEqual(left, right)
1527
        left.inventory_index = 'a'
1528
        self.assertCurrentlyNotEqual(left, right)
1529
        right.inventory_index = 'a'
1530
        self.assertCurrentlyEqual(left, right)
1531
        left.text_index = 'a'
1532
        self.assertCurrentlyNotEqual(left, right)
1533
        right.text_index = 'a'
1534
        self.assertCurrentlyEqual(left, right)
1535
        left.signature_index = 'a'
1536
        self.assertCurrentlyNotEqual(left, right)
1537
        right.signature_index = 'a'
1538
        self.assertCurrentlyEqual(left, right)
1539
        left.name = 'a'
1540
        self.assertCurrentlyNotEqual(left, right)
1541
        right.name = 'a'
1542
        self.assertCurrentlyEqual(left, right)
1543
        left.transport = 'a'
1544
        self.assertCurrentlyNotEqual(left, right)
1545
        right.transport = 'a'
1546
        self.assertCurrentlyEqual(left, right)
2592.3.179 by Robert Collins
Generate the revision_index_map for packing during the core operation, from the pack objects.
1547
1548
    def test_file_name(self):
2592.3.191 by Robert Collins
Give Pack responsibility for index naming, and two concrete classes - NewPack for new packs and ExistingPack for packs we read from disk.
1549
        pack = pack_repo.ExistingPack('', 'a_name', '', '', '', '')
2592.3.179 by Robert Collins
Generate the revision_index_map for packing during the core operation, from the pack objects.
1550
        self.assertEqual('a_name.pack', pack.file_name())
2592.3.192 by Robert Collins
Move new revision index management to NewPack.
1551
1552
1553
class TestNewPack(TestCaseWithTransport):
1554
    """Tests for pack_repo.NewPack."""
1555
2592.3.193 by Robert Collins
Move hash tracking of new packs into NewPack.
1556
    def test_new_instance_attributes(self):
2592.3.194 by Robert Collins
Output the revision index from NewPack.finish
1557
        upload_transport = self.get_transport('upload')
1558
        pack_transport = self.get_transport('pack')
1559
        index_transport = self.get_transport('index')
1560
        upload_transport.mkdir('.')
4241.6.8 by Robert Collins, John Arbash Meinel, Ian Clatworthy, Vincent Ladeuil
Add --development6-rich-root, disabling the legacy and unneeded development2 format, and activating the tests for CHK features disabled pending this format. (Robert Collins, John Arbash Meinel, Ian Clatworthy, Vincent Ladeuil)
1561
        collection = pack_repo.RepositoryPackCollection(
1562
            repo=None,
3830.3.1 by Martin Pool
NewPack should be constructed from the PackCollection, rather than attributes of it
1563
            transport=self.get_transport('.'),
1564
            index_transport=index_transport,
1565
            upload_transport=upload_transport,
1566
            pack_transport=pack_transport,
1567
            index_builder_class=BTreeBuilder,
4241.6.8 by Robert Collins, John Arbash Meinel, Ian Clatworthy, Vincent Ladeuil
Add --development6-rich-root, disabling the legacy and unneeded development2 format, and activating the tests for CHK features disabled pending this format. (Robert Collins, John Arbash Meinel, Ian Clatworthy, Vincent Ladeuil)
1568
            index_class=BTreeGraphIndex,
1569
            use_chk_index=False)
3830.3.1 by Martin Pool
NewPack should be constructed from the PackCollection, rather than attributes of it
1570
        pack = pack_repo.NewPack(collection)
4857.2.1 by John Arbash Meinel
2 test_repository tests weren't adding cleanups when opening files.
1571
        self.addCleanup(pack.abort) # Make sure the write stream gets closed
3735.1.1 by Robert Collins
Add development2 formats using BTree indices.
1572
        self.assertIsInstance(pack.revision_index, BTreeBuilder)
1573
        self.assertIsInstance(pack.inventory_index, BTreeBuilder)
2929.3.5 by Vincent Ladeuil
New files, same warnings, same fixes.
1574
        self.assertIsInstance(pack._hash, type(osutils.md5()))
2592.3.194 by Robert Collins
Output the revision index from NewPack.finish
1575
        self.assertTrue(pack.upload_transport is upload_transport)
1576
        self.assertTrue(pack.index_transport is index_transport)
1577
        self.assertTrue(pack.pack_transport is pack_transport)
1578
        self.assertEqual(None, pack.index_sizes)
1579
        self.assertEqual(20, len(pack.random_name))
1580
        self.assertIsInstance(pack.random_name, str)
1581
        self.assertIsInstance(pack.start_time, float)
2951.1.2 by Robert Collins
Partial refactoring of pack_repo to create a Packer object for packing.
1582
1583
1584
class TestPacker(TestCaseWithTransport):
1585
    """Tests for the packs repository Packer class."""
2951.1.10 by Robert Collins
Peer review feedback with Ian.
1586
3824.2.4 by John Arbash Meinel
Add a test that ensures the pack ordering changes as part of calling .pack()
1587
    def test_pack_optimizes_pack_order(self):
4617.8.1 by Robert Collins
Lock down another test assuming the default was a PackRepository.
1588
        builder = self.make_branch_builder('.', format="1.9")
3824.2.4 by John Arbash Meinel
Add a test that ensures the pack ordering changes as part of calling .pack()
1589
        builder.start_series()
1590
        builder.build_snapshot('A', None, [
1591
            ('add', ('', 'root-id', 'directory', None)),
1592
            ('add', ('f', 'f-id', 'file', 'content\n'))])
1593
        builder.build_snapshot('B', ['A'],
1594
            [('modify', ('f-id', 'new-content\n'))])
1595
        builder.build_snapshot('C', ['B'],
1596
            [('modify', ('f-id', 'third-content\n'))])
1597
        builder.build_snapshot('D', ['C'],
1598
            [('modify', ('f-id', 'fourth-content\n'))])
1599
        b = builder.get_branch()
1600
        b.lock_read()
1601
        builder.finish_series()
1602
        self.addCleanup(b.unlock)
1603
        # At this point, we should have 4 pack files available
1604
        # Because of how they were built, they correspond to
1605
        # ['D', 'C', 'B', 'A']
1606
        packs = b.repository._pack_collection.packs
1607
        packer = pack_repo.Packer(b.repository._pack_collection,
1608
                                  packs, 'testing',
1609
                                  revision_ids=['B', 'C'])
1610
        # Now, when we are copying the B & C revisions, their pack files should
1611
        # be moved to the front of the stack
3824.2.5 by Andrew Bennetts
Minor tweaks to comments etc.
1612
        # The new ordering moves B & C to the front of the .packs attribute,
1613
        # and leaves the others in the original order.
3824.2.4 by John Arbash Meinel
Add a test that ensures the pack ordering changes as part of calling .pack()
1614
        new_packs = [packs[1], packs[2], packs[0], packs[3]]
1615
        new_pack = packer.pack()
1616
        self.assertEqual(new_packs, packer.packs)
3146.6.1 by Aaron Bentley
InterDifferingSerializer shows a progress bar
1617
1618
3777.5.4 by John Arbash Meinel
OptimisingPacker now sets the optimize flags for the indexes being built.
1619
class TestOptimisingPacker(TestCaseWithTransport):
1620
    """Tests for the OptimisingPacker class."""
1621
1622
    def get_pack_collection(self):
1623
        repo = self.make_repository('.')
1624
        return repo._pack_collection
1625
1626
    def test_open_pack_will_optimise(self):
1627
        packer = pack_repo.OptimisingPacker(self.get_pack_collection(),
1628
                                            [], '.test')
1629
        new_pack = packer.open_pack()
4857.2.1 by John Arbash Meinel
2 test_repository tests weren't adding cleanups when opening files.
1630
        self.addCleanup(new_pack.abort) # ensure cleanup
3777.5.4 by John Arbash Meinel
OptimisingPacker now sets the optimize flags for the indexes being built.
1631
        self.assertIsInstance(new_pack, pack_repo.NewPack)
1632
        self.assertTrue(new_pack.revision_index._optimize_for_size)
1633
        self.assertTrue(new_pack.inventory_index._optimize_for_size)
1634
        self.assertTrue(new_pack.text_index._optimize_for_size)
1635
        self.assertTrue(new_pack.signature_index._optimize_for_size)
4462.2.6 by Robert Collins
Cause StreamSink to partially pack repositories after cross format fetches when beneficial.
1636
1637
4431.3.7 by Jonathan Lange
Cherrypick bzr.dev 4470, resolving conflicts.
1638
class TestCrossFormatPacks(TestCaseWithTransport):
1639
1640
    def log_pack(self, hint=None):
1641
        self.calls.append(('pack', hint))
1642
        self.orig_pack(hint=hint)
1643
        if self.expect_hint:
1644
            self.assertTrue(hint)
1645
1646
    def run_stream(self, src_fmt, target_fmt, expect_pack_called):
1647
        self.expect_hint = expect_pack_called
1648
        self.calls = []
1649
        source_tree = self.make_branch_and_tree('src', format=src_fmt)
1650
        source_tree.lock_write()
1651
        self.addCleanup(source_tree.unlock)
1652
        tip = source_tree.commit('foo')
1653
        target = self.make_repository('target', format=target_fmt)
1654
        target.lock_write()
1655
        self.addCleanup(target.unlock)
1656
        source = source_tree.branch.repository._get_source(target._format)
1657
        self.orig_pack = target.pack
1658
        target.pack = self.log_pack
1659
        search = target.search_missing_revision_ids(
5539.2.11 by Andrew Bennetts
Fix deprecation warning from test suite.
1660
            source_tree.branch.repository, revision_ids=[tip])
4431.3.7 by Jonathan Lange
Cherrypick bzr.dev 4470, resolving conflicts.
1661
        stream = source.get_stream(search)
1662
        from_format = source_tree.branch.repository._format
1663
        sink = target._get_sink()
1664
        sink.insert_stream(stream, from_format, [])
1665
        if expect_pack_called:
1666
            self.assertLength(1, self.calls)
1667
        else:
1668
            self.assertLength(0, self.calls)
1669
1670
    def run_fetch(self, src_fmt, target_fmt, expect_pack_called):
1671
        self.expect_hint = expect_pack_called
1672
        self.calls = []
1673
        source_tree = self.make_branch_and_tree('src', format=src_fmt)
1674
        source_tree.lock_write()
1675
        self.addCleanup(source_tree.unlock)
1676
        tip = source_tree.commit('foo')
1677
        target = self.make_repository('target', format=target_fmt)
1678
        target.lock_write()
1679
        self.addCleanup(target.unlock)
1680
        source = source_tree.branch.repository
1681
        self.orig_pack = target.pack
1682
        target.pack = self.log_pack
1683
        target.fetch(source)
1684
        if expect_pack_called:
1685
            self.assertLength(1, self.calls)
1686
        else:
1687
            self.assertLength(0, self.calls)
1688
1689
    def test_sink_format_hint_no(self):
1690
        # When the target format says packing makes no difference, pack is not
1691
        # called.
1692
        self.run_stream('1.9', 'rich-root-pack', False)
1693
1694
    def test_sink_format_hint_yes(self):
1695
        # When the target format says packing makes a difference, pack is
1696
        # called.
1697
        self.run_stream('1.9', '2a', True)
1698
1699
    def test_sink_format_same_no(self):
1700
        # When the formats are the same, pack is not called.
1701
        self.run_stream('2a', '2a', False)
1702
1703
    def test_IDS_format_hint_no(self):
1704
        # When the target format says packing makes no difference, pack is not
1705
        # called.
1706
        self.run_fetch('1.9', 'rich-root-pack', False)
1707
1708
    def test_IDS_format_hint_yes(self):
1709
        # When the target format says packing makes a difference, pack is
1710
        # called.
1711
        self.run_fetch('1.9', '2a', True)
1712
1713
    def test_IDS_format_same_no(self):
1714
        # When the formats are the same, pack is not called.
1715
        self.run_fetch('2a', '2a', False)