/brz/remove-bazaar

To get this branch, use:
bzr branch http://gegoxaren.bato24.eu/bzr/brz/remove-bazaar
3602.2.1 by Martin Pool
Fix and test for problem upgrading stacked branches
1
# Copyright (C) 2006, 2007, 2008 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
15
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
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
1534.4.40 by Robert Collins
Add RepositoryFormats and allow bzrdir.open or create _repository to be used.
26
from StringIO import StringIO
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
1534.4.40 by Robert Collins
Add RepositoryFormats and allow bzrdir.open or create _repository to be used.
29
from bzrlib.errors import (NotBranchError,
1534.4.41 by Robert Collins
Branch now uses BzrDir reasonably sanely.
30
                           NoSuchFile,
1534.4.40 by Robert Collins
Add RepositoryFormats and allow bzrdir.open or create _repository to be used.
31
                           UnknownFormatError,
32
                           UnsupportedFormatError,
33
                           )
3184.1.9 by Robert Collins
* ``Repository.get_data_stream`` is now deprecated in favour of
34
from bzrlib import graph
3735.1.1 by Robert Collins
Add development2 formats using BTree indices.
35
from bzrlib.btree_index import BTreeBuilder, BTreeGraphIndex
2592.3.192 by Robert Collins
Move new revision index management to NewPack.
36
from bzrlib.index import GraphIndex, InMemoryGraphIndex
2241.1.1 by Martin Pool
Change RepositoryFormat to use a Registry rather than ad-hoc dictionary
37
from bzrlib.repository import RepositoryFormat
2535.3.41 by Andrew Bennetts
Add tests for InterRemoteToOther.is_compatible.
38
from bzrlib.smart import server
2670.3.5 by Andrew Bennetts
Remove get_stream_as_bytes from KnitVersionedFile's API, make it a function in knitrepo.py instead.
39
from bzrlib.tests import (
40
    TestCase,
41
    TestCaseWithTransport,
3446.2.1 by Martin Pool
Failure to delete an obsolete pack file should not be fatal.
42
    TestSkipped,
2670.3.5 by Andrew Bennetts
Remove get_stream_as_bytes from KnitVersionedFile's API, make it a function in knitrepo.py instead.
43
    test_knit,
44
    )
3446.2.1 by Martin Pool
Failure to delete an obsolete pack file should not be fatal.
45
from bzrlib.transport import (
46
    fakenfs,
47
    get_transport,
48
    )
1534.4.40 by Robert Collins
Add RepositoryFormats and allow bzrdir.open or create _repository to be used.
49
from bzrlib.transport.memory import MemoryServer
2535.3.53 by Andrew Bennetts
Remove get_stream_as_bytes from KnitVersionedFile's API, make it a function in knitrepo.py instead.
50
from bzrlib.util import bencode
2241.1.1 by Martin Pool
Change RepositoryFormat to use a Registry rather than ad-hoc dictionary
51
from bzrlib import (
2535.3.41 by Andrew Bennetts
Add tests for InterRemoteToOther.is_compatible.
52
    bzrdir,
53
    errors,
2535.3.57 by Andrew Bennetts
Perform some sanity checking of data streams rather than blindly inserting them into our repository.
54
    inventory,
3734.2.4 by Vincent Ladeuil
Fix python2.6 deprecation warnings related to hashlib.
55
    osutils,
3146.6.1 by Aaron Bentley
InterDifferingSerializer shows a progress bar
56
    progress,
2241.1.1 by Martin Pool
Change RepositoryFormat to use a Registry rather than ad-hoc dictionary
57
    repository,
2535.3.57 by Andrew Bennetts
Perform some sanity checking of data streams rather than blindly inserting them into our repository.
58
    revision as _mod_revision,
2535.3.41 by Andrew Bennetts
Add tests for InterRemoteToOther.is_compatible.
59
    symbol_versioning,
2241.1.1 by Martin Pool
Change RepositoryFormat to use a Registry rather than ad-hoc dictionary
60
    upgrade,
61
    workingtree,
62
    )
2592.3.173 by Robert Collins
Basic implementation of all_packs.
63
from bzrlib.repofmt import knitrepo, weaverepo, pack_repo
1534.4.40 by Robert Collins
Add RepositoryFormats and allow bzrdir.open or create _repository to be used.
64
65
66
class TestDefaultFormat(TestCase):
67
1534.4.41 by Robert Collins
Branch now uses BzrDir reasonably sanely.
68
    def test_get_set_default_format(self):
2204.5.3 by Aaron Bentley
zap old repository default handling
69
        old_default = bzrdir.format_registry.get('default')
70
        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.
71
        old_format = repository.RepositoryFormat.get_default_format()
1910.2.33 by Aaron Bentley
Fix default format test
72
        self.assertTrue(isinstance(old_format, private_default))
2204.5.3 by Aaron Bentley
zap old repository default handling
73
        def make_sample_bzrdir():
74
            my_bzrdir = bzrdir.BzrDirMetaFormat1()
75
            my_bzrdir.repository_format = SampleRepositoryFormat()
76
            return my_bzrdir
77
        bzrdir.format_registry.remove('default')
78
        bzrdir.format_registry.register('sample', make_sample_bzrdir, '')
79
        bzrdir.format_registry.set_default('sample')
1534.4.40 by Robert Collins
Add RepositoryFormats and allow bzrdir.open or create _repository to be used.
80
        # creating a repository should now create an instrumented dir.
81
        try:
1534.4.47 by Robert Collins
Split out repository into .bzr/repository
82
            # the default branch format is used by the meta dir format
83
            # which is not the default bzrdir format at this point
1685.1.63 by Martin Pool
Small Transport fixups
84
            dir = bzrdir.BzrDirMetaFormat1().initialize('memory:///')
1534.4.47 by Robert Collins
Split out repository into .bzr/repository
85
            result = dir.create_repository()
1534.4.40 by Robert Collins
Add RepositoryFormats and allow bzrdir.open or create _repository to be used.
86
            self.assertEqual(result, 'A bzr repository dir')
2241.1.1 by Martin Pool
Change RepositoryFormat to use a Registry rather than ad-hoc dictionary
87
        finally:
2204.5.3 by Aaron Bentley
zap old repository default handling
88
            bzrdir.format_registry.remove('default')
2363.5.14 by Aaron Bentley
Prevent repository.get_set_default_format from corrupting inventory
89
            bzrdir.format_registry.remove('sample')
2204.5.3 by Aaron Bentley
zap old repository default handling
90
            bzrdir.format_registry.register('default', old_default, '')
91
        self.assertIsInstance(repository.RepositoryFormat.get_default_format(),
92
                              old_format.__class__)
1534.4.40 by Robert Collins
Add RepositoryFormats and allow bzrdir.open or create _repository to be used.
93
94
95
class SampleRepositoryFormat(repository.RepositoryFormat):
96
    """A sample format
97
98
    this format is initializable, unsupported to aid in testing the 
1534.4.47 by Robert Collins
Split out repository into .bzr/repository
99
    open and open(unsupported=True) routines.
1534.4.40 by Robert Collins
Add RepositoryFormats and allow bzrdir.open or create _repository to be used.
100
    """
101
102
    def get_format_string(self):
103
        """See RepositoryFormat.get_format_string()."""
104
        return "Sample .bzr repository format."
105
1534.6.1 by Robert Collins
allow API creation of shared repositories
106
    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.
107
        """Initialize a repository in a BzrDir"""
1534.4.47 by Robert Collins
Split out repository into .bzr/repository
108
        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.
109
        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.
110
        return 'A bzr repository dir'
111
112
    def is_supported(self):
113
        return False
114
1534.4.47 by Robert Collins
Split out repository into .bzr/repository
115
    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.
116
        return "opened repository."
1534.4.41 by Robert Collins
Branch now uses BzrDir reasonably sanely.
117
118
1534.4.47 by Robert Collins
Split out repository into .bzr/repository
119
class TestRepositoryFormat(TestCaseWithTransport):
120
    """Tests for the Repository format detection used by the bzr meta dir facility.BzrBranchFormat facility."""
121
122
    def test_find_format(self):
123
        # is the right format object found for a repository?
124
        # create a branch with a few known format objects.
125
        # this is not quite the same as 
126
        self.build_tree(["foo/", "bar/"])
127
        def check_format(format, url):
128
            dir = format._matchingbzrdir.initialize(url)
129
            format.initialize(dir)
130
            t = get_transport(url)
131
            found_format = repository.RepositoryFormat.find_format(dir)
132
            self.failUnless(isinstance(found_format, format.__class__))
2241.1.4 by Martin Pool
Moved old weave-based repository formats into bzrlib.repofmt.weaverepo.
133
        check_format(weaverepo.RepositoryFormat7(), "bar")
1534.4.47 by Robert Collins
Split out repository into .bzr/repository
134
        
135
    def test_find_format_no_repository(self):
136
        dir = bzrdir.BzrDirMetaFormat1().initialize(self.get_url())
137
        self.assertRaises(errors.NoRepositoryPresent,
138
                          repository.RepositoryFormat.find_format,
139
                          dir)
140
141
    def test_find_format_unknown_format(self):
142
        dir = bzrdir.BzrDirMetaFormat1().initialize(self.get_url())
143
        SampleRepositoryFormat().initialize(dir)
144
        self.assertRaises(UnknownFormatError,
145
                          repository.RepositoryFormat.find_format,
146
                          dir)
147
148
    def test_register_unregister_format(self):
149
        format = SampleRepositoryFormat()
150
        # make a control dir
151
        dir = bzrdir.BzrDirMetaFormat1().initialize(self.get_url())
152
        # make a repo
153
        format.initialize(dir)
154
        # register a format for it.
155
        repository.RepositoryFormat.register_format(format)
156
        # which repository.Open will refuse (not supported)
157
        self.assertRaises(UnsupportedFormatError, repository.Repository.open, self.get_url())
158
        # but open(unsupported) will work
159
        self.assertEqual(format.open(dir), "opened repository.")
160
        # unregister the format
161
        repository.RepositoryFormat.unregister_format(format)
162
163
1534.4.41 by Robert Collins
Branch now uses BzrDir reasonably sanely.
164
class TestFormat6(TestCaseWithTransport):
165
3565.3.1 by Robert Collins
* The generic fetch code now uses two attributes on Repository objects
166
    def test_attribute__fetch_order(self):
167
        """Weaves need topological data insertion."""
168
        control = bzrdir.BzrDirFormat6().initialize(self.get_url())
169
        repo = weaverepo.RepositoryFormat6().initialize(control)
170
        self.assertEqual('topological', repo._fetch_order)
171
172
    def test_attribute__fetch_uses_deltas(self):
173
        """Weaves do not reuse deltas."""
174
        control = bzrdir.BzrDirFormat6().initialize(self.get_url())
175
        repo = weaverepo.RepositoryFormat6().initialize(control)
176
        self.assertEqual(False, repo._fetch_uses_deltas)
177
3565.3.4 by Robert Collins
Defer decision to reconcile to the repository being fetched into.
178
    def test_attribute__fetch_reconcile(self):
179
        """Weave repositories need a reconcile after fetch."""
180
        control = bzrdir.BzrDirFormat6().initialize(self.get_url())
181
        repo = weaverepo.RepositoryFormat6().initialize(control)
182
        self.assertEqual(True, repo._fetch_reconcile)
183
1534.4.41 by Robert Collins
Branch now uses BzrDir reasonably sanely.
184
    def test_no_ancestry_weave(self):
185
        control = bzrdir.BzrDirFormat6().initialize(self.get_url())
2241.1.4 by Martin Pool
Moved old weave-based repository formats into bzrlib.repofmt.weaverepo.
186
        repo = weaverepo.RepositoryFormat6().initialize(control)
1534.4.41 by Robert Collins
Branch now uses BzrDir reasonably sanely.
187
        # We no longer need to create the ancestry.weave file
188
        # since it is *never* used.
189
        self.assertRaises(NoSuchFile,
190
                          control.transport.get,
191
                          'ancestry.weave')
192
3221.3.1 by Robert Collins
* Repository formats have a new supported-feature attribute
193
    def test_supports_external_lookups(self):
194
        control = bzrdir.BzrDirFormat6().initialize(self.get_url())
195
        repo = weaverepo.RepositoryFormat6().initialize(control)
196
        self.assertFalse(repo._format.supports_external_lookups)
197
1534.4.47 by Robert Collins
Split out repository into .bzr/repository
198
199
class TestFormat7(TestCaseWithTransport):
3565.3.1 by Robert Collins
* The generic fetch code now uses two attributes on Repository objects
200
201
    def test_attribute__fetch_order(self):
202
        """Weaves need topological data insertion."""
203
        control = bzrdir.BzrDirMetaFormat1().initialize(self.get_url())
204
        repo = weaverepo.RepositoryFormat7().initialize(control)
205
        self.assertEqual('topological', repo._fetch_order)
206
207
    def test_attribute__fetch_uses_deltas(self):
208
        """Weaves do not reuse deltas."""
209
        control = bzrdir.BzrDirMetaFormat1().initialize(self.get_url())
210
        repo = weaverepo.RepositoryFormat7().initialize(control)
211
        self.assertEqual(False, repo._fetch_uses_deltas)
212
3565.3.4 by Robert Collins
Defer decision to reconcile to the repository being fetched into.
213
    def test_attribute__fetch_reconcile(self):
214
        """Weave repositories need a reconcile after fetch."""
215
        control = bzrdir.BzrDirMetaFormat1().initialize(self.get_url())
216
        repo = weaverepo.RepositoryFormat7().initialize(control)
217
        self.assertEqual(True, repo._fetch_reconcile)
218
1534.4.47 by Robert Collins
Split out repository into .bzr/repository
219
    def test_disk_layout(self):
220
        control = bzrdir.BzrDirMetaFormat1().initialize(self.get_url())
2241.1.4 by Martin Pool
Moved old weave-based repository formats into bzrlib.repofmt.weaverepo.
221
        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.
222
        # in case of side effects of locking.
223
        repo.lock_write()
224
        repo.unlock()
1534.4.47 by Robert Collins
Split out repository into .bzr/repository
225
        # we want:
226
        # format 'Bazaar-NG Repository format 7'
227
        # lock ''
228
        # inventory.weave == empty_weave
229
        # empty revision-store directory
230
        # empty weaves directory
231
        t = control.get_repository_transport(None)
232
        self.assertEqualDiff('Bazaar-NG Repository format 7',
233
                             t.get('format').read())
234
        self.assertTrue(S_ISDIR(t.stat('revision-store').st_mode))
235
        self.assertTrue(S_ISDIR(t.stat('weaves').st_mode))
236
        self.assertEqualDiff('# bzr weave file v5\n'
237
                             'w\n'
238
                             'W\n',
239
                             t.get('inventory.weave').read())
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.
240
        # Creating a file with id Foo:Bar results in a non-escaped file name on
241
        # disk.
242
        control.create_branch()
243
        tree = control.create_workingtree()
244
        tree.add(['foo'], ['Foo:Bar'], ['file'])
245
        tree.put_file_bytes_non_atomic('Foo:Bar', 'content\n')
246
        tree.commit('first post', rev_id='first')
247
        self.assertEqualDiff(
248
            '# bzr weave file v5\n'
249
            'i\n'
250
            '1 7fe70820e08a1aac0ef224d9c66ab66831cc4ab1\n'
251
            'n first\n'
252
            '\n'
253
            'w\n'
254
            '{ 0\n'
255
            '. content\n'
256
            '}\n'
257
            'W\n',
258
            t.get('weaves/74/Foo%3ABar.weave').read())
1534.6.1 by Robert Collins
allow API creation of shared repositories
259
260
    def test_shared_disk_layout(self):
261
        control = bzrdir.BzrDirMetaFormat1().initialize(self.get_url())
2241.1.4 by Martin Pool
Moved old weave-based repository formats into bzrlib.repofmt.weaverepo.
262
        repo = weaverepo.RepositoryFormat7().initialize(control, shared=True)
1534.6.1 by Robert Collins
allow API creation of shared repositories
263
        # we want:
264
        # format 'Bazaar-NG Repository format 7'
265
        # inventory.weave == empty_weave
266
        # empty revision-store directory
267
        # empty weaves directory
268
        # a 'shared-storage' marker file.
1553.5.49 by Martin Pool
Use LockDirs for repo format 7
269
        # lock is not present when unlocked
1534.6.1 by Robert Collins
allow API creation of shared repositories
270
        t = control.get_repository_transport(None)
271
        self.assertEqualDiff('Bazaar-NG Repository format 7',
272
                             t.get('format').read())
273
        self.assertEqualDiff('', t.get('shared-storage').read())
274
        self.assertTrue(S_ISDIR(t.stat('revision-store').st_mode))
275
        self.assertTrue(S_ISDIR(t.stat('weaves').st_mode))
276
        self.assertEqualDiff('# bzr weave file v5\n'
277
                             'w\n'
278
                             'W\n',
279
                             t.get('inventory.weave').read())
1553.5.49 by Martin Pool
Use LockDirs for repo format 7
280
        self.assertFalse(t.has('branch-lock'))
281
1553.5.56 by Martin Pool
Format 7 repo now uses LockDir!
282
    def test_creates_lockdir(self):
1553.5.49 by Martin Pool
Use LockDirs for repo format 7
283
        """Make sure it appears to be controlled by a LockDir existence"""
284
        control = bzrdir.BzrDirMetaFormat1().initialize(self.get_url())
2241.1.4 by Martin Pool
Moved old weave-based repository formats into bzrlib.repofmt.weaverepo.
285
        repo = weaverepo.RepositoryFormat7().initialize(control, shared=True)
1553.5.49 by Martin Pool
Use LockDirs for repo format 7
286
        t = control.get_repository_transport(None)
1553.5.58 by Martin Pool
Change LockDirs to format "lock-name/held/info"
287
        # TODO: Should check there is a 'lock' toplevel directory, 
288
        # regardless of contents
289
        self.assertFalse(t.has('lock/held/info'))
1553.5.49 by Martin Pool
Use LockDirs for repo format 7
290
        repo.lock_write()
1658.1.4 by Martin Pool
Quieten warning from TestFormat7.test_creates_lockdir about failing to unlock
291
        try:
292
            self.assertTrue(t.has('lock/held/info'))
293
        finally:
294
            # unlock so we don't get a warning about failing to do so
295
            repo.unlock()
1553.5.56 by Martin Pool
Format 7 repo now uses LockDir!
296
297
    def test_uses_lockdir(self):
298
        """repo format 7 actually locks on lockdir"""
299
        base_url = self.get_url()
300
        control = bzrdir.BzrDirMetaFormat1().initialize(base_url)
2241.1.4 by Martin Pool
Moved old weave-based repository formats into bzrlib.repofmt.weaverepo.
301
        repo = weaverepo.RepositoryFormat7().initialize(control, shared=True)
1553.5.56 by Martin Pool
Format 7 repo now uses LockDir!
302
        t = control.get_repository_transport(None)
303
        repo.lock_write()
304
        repo.unlock()
305
        del repo
306
        # make sure the same lock is created by opening it
307
        repo = repository.Repository.open(base_url)
308
        repo.lock_write()
1553.5.58 by Martin Pool
Change LockDirs to format "lock-name/held/info"
309
        self.assertTrue(t.has('lock/held/info'))
1553.5.56 by Martin Pool
Format 7 repo now uses LockDir!
310
        repo.unlock()
1553.5.58 by Martin Pool
Change LockDirs to format "lock-name/held/info"
311
        self.assertFalse(t.has('lock/held/info'))
1534.6.5 by Robert Collins
Cloning of repos preserves shared and make-working-tree attributes.
312
313
    def test_shared_no_tree_disk_layout(self):
314
        control = bzrdir.BzrDirMetaFormat1().initialize(self.get_url())
2241.1.4 by Martin Pool
Moved old weave-based repository formats into bzrlib.repofmt.weaverepo.
315
        repo = weaverepo.RepositoryFormat7().initialize(control, shared=True)
1534.6.5 by Robert Collins
Cloning of repos preserves shared and make-working-tree attributes.
316
        repo.set_make_working_trees(False)
317
        # we want:
318
        # format 'Bazaar-NG Repository format 7'
319
        # lock ''
320
        # inventory.weave == empty_weave
321
        # empty revision-store directory
322
        # empty weaves directory
323
        # a 'shared-storage' marker file.
324
        t = control.get_repository_transport(None)
325
        self.assertEqualDiff('Bazaar-NG Repository format 7',
326
                             t.get('format').read())
1553.5.56 by Martin Pool
Format 7 repo now uses LockDir!
327
        ## self.assertEqualDiff('', t.get('lock').read())
1534.6.5 by Robert Collins
Cloning of repos preserves shared and make-working-tree attributes.
328
        self.assertEqualDiff('', t.get('shared-storage').read())
329
        self.assertEqualDiff('', t.get('no-working-trees').read())
330
        repo.set_make_working_trees(True)
331
        self.assertFalse(t.has('no-working-trees'))
332
        self.assertTrue(S_ISDIR(t.stat('revision-store').st_mode))
333
        self.assertTrue(S_ISDIR(t.stat('weaves').st_mode))
334
        self.assertEqualDiff('# bzr weave file v5\n'
335
                             'w\n'
336
                             'W\n',
337
                             t.get('inventory.weave').read())
1534.1.27 by Robert Collins
Start InterRepository with InterRepository.get.
338
3221.3.1 by Robert Collins
* Repository formats have a new supported-feature attribute
339
    def test_supports_external_lookups(self):
340
        control = bzrdir.BzrDirMetaFormat1().initialize(self.get_url())
341
        repo = weaverepo.RepositoryFormat7().initialize(control)
342
        self.assertFalse(repo._format.supports_external_lookups)
343
1534.1.27 by Robert Collins
Start InterRepository with InterRepository.get.
344
1556.1.3 by Robert Collins
Rearrangment of Repository logic to be less type code driven, and bugfix InterRepository.missing_revision_ids
345
class TestFormatKnit1(TestCaseWithTransport):
346
    
3565.3.1 by Robert Collins
* The generic fetch code now uses two attributes on Repository objects
347
    def test_attribute__fetch_order(self):
348
        """Knits need topological data insertion."""
349
        repo = self.make_repository('.',
350
                format=bzrdir.format_registry.get('knit')())
351
        self.assertEqual('topological', repo._fetch_order)
352
353
    def test_attribute__fetch_uses_deltas(self):
354
        """Knits reuse deltas."""
355
        repo = self.make_repository('.',
356
                format=bzrdir.format_registry.get('knit')())
357
        self.assertEqual(True, repo._fetch_uses_deltas)
358
1556.1.3 by Robert Collins
Rearrangment of Repository logic to be less type code driven, and bugfix InterRepository.missing_revision_ids
359
    def test_disk_layout(self):
360
        control = bzrdir.BzrDirMetaFormat1().initialize(self.get_url())
2241.1.6 by Martin Pool
Move Knit repositories into the submodule bzrlib.repofmt.knitrepo and
361
        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
362
        # in case of side effects of locking.
363
        repo.lock_write()
364
        repo.unlock()
365
        # we want:
366
        # format 'Bazaar-NG Knit Repository Format 1'
1553.5.62 by Martin Pool
Add tests that MetaDir repositories use LockDirs
367
        # 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
368
        # inventory.weave == empty_weave
369
        # empty revision-store directory
370
        # empty weaves directory
371
        t = control.get_repository_transport(None)
372
        self.assertEqualDiff('Bazaar-NG Knit Repository Format 1',
373
                             t.get('format').read())
1553.5.57 by Martin Pool
[merge] sync from bzr.dev
374
        # XXX: no locks left when unlocked at the moment
375
        # 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
376
        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.
377
        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.
378
        # Check per-file knits.
379
        branch = control.create_branch()
380
        tree = control.create_workingtree()
381
        tree.add(['foo'], ['Nasty-IdC:'], ['file'])
382
        tree.put_file_bytes_non_atomic('Nasty-IdC:', '')
383
        tree.commit('1st post', rev_id='foo')
384
        self.assertHasKnit(t, 'knits/e8/%254easty-%2549d%2543%253a',
385
            '\nfoo fulltext 0 81  :')
1563.2.35 by Robert Collins
cleanup deprecation warnings and finish conversion so the inventory is knit based too.
386
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.
387
    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.
388
        """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.
389
        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.
390
                             t.get(knit_name + '.kndx').read())
391
1563.2.35 by Robert Collins
cleanup deprecation warnings and finish conversion so the inventory is knit based too.
392
    def check_knits(self, t):
393
        """check knit content for a repository."""
1654.1.3 by Robert Collins
Refactor repository knit tests slightly to remove duplication - add a assertHasKnit method.
394
        self.assertHasKnit(t, 'inventory')
395
        self.assertHasKnit(t, 'revisions')
396
        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
397
398
    def test_shared_disk_layout(self):
399
        control = bzrdir.BzrDirMetaFormat1().initialize(self.get_url())
2241.1.6 by Martin Pool
Move Knit repositories into the submodule bzrlib.repofmt.knitrepo and
400
        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
401
        # we want:
402
        # format 'Bazaar-NG Knit Repository Format 1'
1553.5.62 by Martin Pool
Add tests that MetaDir repositories use LockDirs
403
        # 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
404
        # inventory.weave == empty_weave
405
        # empty revision-store directory
406
        # empty weaves directory
407
        # a 'shared-storage' marker file.
408
        t = control.get_repository_transport(None)
409
        self.assertEqualDiff('Bazaar-NG Knit Repository Format 1',
410
                             t.get('format').read())
1553.5.57 by Martin Pool
[merge] sync from bzr.dev
411
        # XXX: no locks left when unlocked at the moment
412
        # 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
413
        self.assertEqualDiff('', t.get('shared-storage').read())
414
        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.
415
        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
416
417
    def test_shared_no_tree_disk_layout(self):
418
        control = bzrdir.BzrDirMetaFormat1().initialize(self.get_url())
2241.1.6 by Martin Pool
Move Knit repositories into the submodule bzrlib.repofmt.knitrepo and
419
        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
420
        repo.set_make_working_trees(False)
421
        # we want:
422
        # format 'Bazaar-NG Knit Repository Format 1'
423
        # lock ''
424
        # inventory.weave == empty_weave
425
        # empty revision-store directory
426
        # empty weaves directory
427
        # a 'shared-storage' marker file.
428
        t = control.get_repository_transport(None)
429
        self.assertEqualDiff('Bazaar-NG Knit Repository Format 1',
430
                             t.get('format').read())
1553.5.57 by Martin Pool
[merge] sync from bzr.dev
431
        # XXX: no locks left when unlocked at the moment
432
        # 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
433
        self.assertEqualDiff('', t.get('shared-storage').read())
434
        self.assertEqualDiff('', t.get('no-working-trees').read())
435
        repo.set_make_working_trees(True)
436
        self.assertFalse(t.has('no-working-trees'))
437
        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.
438
        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
439
2917.2.1 by John Arbash Meinel
Fix bug #152360. The xml5 serializer should be using
440
    def test_deserialise_sets_root_revision(self):
441
        """We must have a inventory.root.revision
442
443
        Old versions of the XML5 serializer did not set the revision_id for
444
        the whole inventory. So we grab the one from the expected text. Which
445
        is valid when the api is not being abused.
446
        """
447
        repo = self.make_repository('.',
448
                format=bzrdir.format_registry.get('knit')())
449
        inv_xml = '<inventory format="5">\n</inventory>\n'
450
        inv = repo.deserialise_inventory('test-rev-id', inv_xml)
451
        self.assertEqual('test-rev-id', inv.root.revision)
452
453
    def test_deserialise_uses_global_revision_id(self):
454
        """If it is set, then we re-use the global revision id"""
455
        repo = self.make_repository('.',
456
                format=bzrdir.format_registry.get('knit')())
457
        inv_xml = ('<inventory format="5" revision_id="other-rev-id">\n'
458
                   '</inventory>\n')
459
        # Arguably, the deserialise_inventory should detect a mismatch, and
460
        # raise an error, rather than silently using one revision_id over the
461
        # other.
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.
462
        self.assertRaises(AssertionError, repo.deserialise_inventory,
463
            'test-rev-id', inv_xml)
464
        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
465
        self.assertEqual('other-rev-id', inv.root.revision)
466
3221.3.1 by Robert Collins
* Repository formats have a new supported-feature attribute
467
    def test_supports_external_lookups(self):
468
        repo = self.make_repository('.',
469
                format=bzrdir.format_registry.get('knit')())
470
        self.assertFalse(repo._format.supports_external_lookups)
471
2305.2.3 by Andrew Bennetts
Bring across test_repository improvements from the hpss branch to fix the last test failures.
472
473
class DummyRepository(object):
474
    """A dummy repository for testing."""
475
476
    _serializer = None
477
478
    def supports_rich_root(self):
479
        return False
480
3709.5.10 by Andrew Bennetts
Fix test failure caused by missing attributes on DummyRepository.
481
    def get_graph(self):
482
        raise NotImplementedError
483
484
    def get_parent_map(self, revision_ids):
485
        raise NotImplementedError
486
2305.2.3 by Andrew Bennetts
Bring across test_repository improvements from the hpss branch to fix the last test failures.
487
488
class InterDummy(repository.InterRepository):
489
    """An inter-repository optimised code path for DummyRepository.
490
491
    This is for use during testing where we use DummyRepository as repositories
1534.1.28 by Robert Collins
Allow for optimised InterRepository selection.
492
    so that none of the default regsitered inter-repository classes will
2818.4.2 by Robert Collins
Review feedback.
493
    MATCH.
1534.1.28 by Robert Collins
Allow for optimised InterRepository selection.
494
    """
495
496
    @staticmethod
497
    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.
498
        """InterDummy is compatible with DummyRepository."""
499
        return (isinstance(repo_source, DummyRepository) and 
500
            isinstance(repo_target, DummyRepository))
1534.1.28 by Robert Collins
Allow for optimised InterRepository selection.
501
502
1534.1.27 by Robert Collins
Start InterRepository with InterRepository.get.
503
class TestInterRepository(TestCaseWithTransport):
504
505
    def test_get_default_inter_repository(self):
506
        # test that the InterRepository.get(repo_a, repo_b) probes
507
        # for a inter_repo class where is_compatible(repo_a, repo_b) returns
508
        # true and returns a default inter_repo otherwise.
509
        # This also tests that the default registered optimised interrepository
510
        # classes do not barf inappropriately when a surprising repository type
511
        # 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.
512
        dummy_a = DummyRepository()
513
        dummy_b = DummyRepository()
1534.1.28 by Robert Collins
Allow for optimised InterRepository selection.
514
        self.assertGetsDefaultInterRepository(dummy_a, dummy_b)
515
516
    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.
517
        """Asserts that InterRepository.get(repo_a, repo_b) -> the default.
518
        
519
        The effective default is now InterSameDataRepository because there is
520
        no actual sane default in the presence of incompatible data models.
521
        """
1534.1.28 by Robert Collins
Allow for optimised InterRepository selection.
522
        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.
523
        self.assertEqual(repository.InterSameDataRepository,
1534.1.27 by Robert Collins
Start InterRepository with InterRepository.get.
524
                         inter_repo.__class__)
1534.1.28 by Robert Collins
Allow for optimised InterRepository selection.
525
        self.assertEqual(repo_a, inter_repo.source)
526
        self.assertEqual(repo_b, inter_repo.target)
527
528
    def test_register_inter_repository_class(self):
529
        # test that a optimised code path provider - a
530
        # InterRepository subclass can be registered and unregistered
531
        # and that it is correctly selected when given a repository
532
        # pair that it returns true on for the is_compatible static method
533
        # check
2305.2.3 by Andrew Bennetts
Bring across test_repository improvements from the hpss branch to fix the last test failures.
534
        dummy_a = DummyRepository()
535
        dummy_b = DummyRepository()
536
        repo = self.make_repository('.')
537
        # hack dummies to look like repo somewhat.
538
        dummy_a._serializer = repo._serializer
539
        dummy_b._serializer = repo._serializer
540
        repository.InterRepository.register_optimiser(InterDummy)
1534.1.28 by Robert Collins
Allow for optimised InterRepository selection.
541
        try:
2305.2.3 by Andrew Bennetts
Bring across test_repository improvements from the hpss branch to fix the last test failures.
542
            # we should get the default for something InterDummy returns False
1534.1.28 by Robert Collins
Allow for optimised InterRepository selection.
543
            # to
2305.2.3 by Andrew Bennetts
Bring across test_repository improvements from the hpss branch to fix the last test failures.
544
            self.assertFalse(InterDummy.is_compatible(dummy_a, repo))
545
            self.assertGetsDefaultInterRepository(dummy_a, repo)
546
            # and we should get an InterDummy for a pair it 'likes'
547
            self.assertTrue(InterDummy.is_compatible(dummy_a, dummy_b))
1534.1.28 by Robert Collins
Allow for optimised InterRepository selection.
548
            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.
549
            self.assertEqual(InterDummy, inter_repo.__class__)
1534.1.28 by Robert Collins
Allow for optimised InterRepository selection.
550
            self.assertEqual(dummy_a, inter_repo.source)
551
            self.assertEqual(dummy_b, inter_repo.target)
552
        finally:
2305.2.3 by Andrew Bennetts
Bring across test_repository improvements from the hpss branch to fix the last test failures.
553
            repository.InterRepository.unregister_optimiser(InterDummy)
1534.1.28 by Robert Collins
Allow for optimised InterRepository selection.
554
        # now we should get the default InterRepository object again.
555
        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.
556
2241.1.17 by Martin Pool
Restore old InterWeave tests
557
558
class TestInterWeaveRepo(TestCaseWithTransport):
559
560
    def test_is_compatible_and_registered(self):
561
        # InterWeaveRepo is compatible when either side
562
        # is a format 5/6/7 branch
2241.1.20 by mbp at sourcefrog
update tests for new locations of weave repos
563
        from bzrlib.repofmt import knitrepo, weaverepo
564
        formats = [weaverepo.RepositoryFormat5(),
565
                   weaverepo.RepositoryFormat6(),
566
                   weaverepo.RepositoryFormat7()]
567
        incompatible_formats = [weaverepo.RepositoryFormat4(),
568
                                knitrepo.RepositoryFormatKnit1(),
2241.1.17 by Martin Pool
Restore old InterWeave tests
569
                                ]
570
        repo_a = self.make_repository('a')
571
        repo_b = self.make_repository('b')
572
        is_compatible = repository.InterWeaveRepo.is_compatible
573
        for source in incompatible_formats:
574
            # force incompatible left then right
575
            repo_a._format = source
576
            repo_b._format = formats[0]
577
            self.assertFalse(is_compatible(repo_a, repo_b))
578
            self.assertFalse(is_compatible(repo_b, repo_a))
579
        for source in formats:
580
            repo_a._format = source
581
            for target in formats:
582
                repo_b._format = target
583
                self.assertTrue(is_compatible(repo_a, repo_b))
584
        self.assertEqual(repository.InterWeaveRepo,
585
                         repository.InterRepository.get(repo_a,
586
                                                        repo_b).__class__)
587
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.
588
589
class TestRepositoryConverter(TestCaseWithTransport):
590
591
    def test_convert_empty(self):
592
        t = get_transport(self.get_url('.'))
593
        t.mkdir('repository')
594
        repo_dir = bzrdir.BzrDirMetaFormat1().initialize('repository')
2241.1.4 by Martin Pool
Moved old weave-based repository formats into bzrlib.repofmt.weaverepo.
595
        repo = weaverepo.RepositoryFormat7().initialize(repo_dir)
2241.1.6 by Martin Pool
Move Knit repositories into the submodule bzrlib.repofmt.knitrepo and
596
        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.
597
        converter = repository.CopyConverter(target_format)
1594.1.3 by Robert Collins
Fixup pb usage to use nested_progress_bar.
598
        pb = bzrlib.ui.ui_factory.nested_progress_bar()
599
        try:
600
            converter.convert(repo, pb)
601
        finally:
602
            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.
603
        repo = repo_dir.open_repository()
604
        self.assertTrue(isinstance(target_format, repo._format.__class__))
1843.2.5 by Aaron Bentley
Add test of _unescape_xml
605
606
607
class TestMisc(TestCase):
608
    
609
    def test_unescape_xml(self):
610
        """We get some kind of error when malformed entities are passed"""
611
        self.assertRaises(KeyError, repository._unescape_xml, 'foo&bar;') 
1910.2.13 by Aaron Bentley
Start work on converter
612
613
2255.2.211 by Robert Collins
Remove knit2 repository format- it has never been supported.
614
class TestRepositoryFormatKnit3(TestCaseWithTransport):
1910.2.13 by Aaron Bentley
Start work on converter
615
3565.3.1 by Robert Collins
* The generic fetch code now uses two attributes on Repository objects
616
    def test_attribute__fetch_order(self):
617
        """Knits need topological data insertion."""
618
        format = bzrdir.BzrDirMetaFormat1()
619
        format.repository_format = knitrepo.RepositoryFormatKnit3()
620
        repo = self.make_repository('.', format=format)
621
        self.assertEqual('topological', repo._fetch_order)
622
623
    def test_attribute__fetch_uses_deltas(self):
624
        """Knits reuse deltas."""
625
        format = bzrdir.BzrDirMetaFormat1()
626
        format.repository_format = knitrepo.RepositoryFormatKnit3()
627
        repo = self.make_repository('.', format=format)
628
        self.assertEqual(True, repo._fetch_uses_deltas)
629
1910.2.13 by Aaron Bentley
Start work on converter
630
    def test_convert(self):
631
        """Ensure the upgrade adds weaves for roots"""
1910.2.35 by Aaron Bentley
Better fix for convesion test
632
        format = bzrdir.BzrDirMetaFormat1()
2241.1.6 by Martin Pool
Move Knit repositories into the submodule bzrlib.repofmt.knitrepo and
633
        format.repository_format = knitrepo.RepositoryFormatKnit1()
1910.2.35 by Aaron Bentley
Better fix for convesion test
634
        tree = self.make_branch_and_tree('.', format)
1910.2.13 by Aaron Bentley
Start work on converter
635
        tree.commit("Dull commit", rev_id="dull")
636
        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.
637
        revision_tree.lock_read()
638
        try:
639
            self.assertRaises(errors.NoSuchFile, revision_tree.get_file_lines,
640
                revision_tree.inventory.root.file_id)
641
        finally:
642
            revision_tree.unlock()
1910.2.13 by Aaron Bentley
Start work on converter
643
        format = bzrdir.BzrDirMetaFormat1()
2255.2.211 by Robert Collins
Remove knit2 repository format- it has never been supported.
644
        format.repository_format = knitrepo.RepositoryFormatKnit3()
1910.2.13 by Aaron Bentley
Start work on converter
645
        upgrade.Convert('.', format)
1910.2.27 by Aaron Bentley
Fixed conversion test
646
        tree = workingtree.WorkingTree.open('.')
1910.2.13 by Aaron Bentley
Start work on converter
647
        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.
648
        revision_tree.lock_read()
649
        try:
650
            revision_tree.get_file_lines(revision_tree.inventory.root.file_id)
651
        finally:
652
            revision_tree.unlock()
1910.2.27 by Aaron Bentley
Fixed conversion test
653
        tree.commit("Another dull commit", rev_id='dull2')
654
        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.
655
        revision_tree.lock_read()
656
        self.addCleanup(revision_tree.unlock)
1910.2.27 by Aaron Bentley
Fixed conversion test
657
        self.assertEqual('dull', revision_tree.inventory.root.revision)
2220.2.2 by Martin Pool
Add tag command and basic implementation
658
3221.3.1 by Robert Collins
* Repository formats have a new supported-feature attribute
659
    def test_supports_external_lookups(self):
660
        format = bzrdir.BzrDirMetaFormat1()
661
        format.repository_format = knitrepo.RepositoryFormatKnit3()
662
        repo = self.make_repository('.', format=format)
663
        self.assertFalse(repo._format.supports_external_lookups)
664
2535.3.57 by Andrew Bennetts
Perform some sanity checking of data streams rather than blindly inserting them into our repository.
665
666
class TestWithBrokenRepo(TestCaseWithTransport):
2592.3.214 by Robert Collins
Merge bzr.dev.
667
    """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.
668
669
    def make_broken_repository(self):
670
        # XXX: This function is borrowed from Aaron's "Reconcile can fix bad
671
        # parent references" branch which is due to land in bzr.dev soon.  Once
672
        # it does, this duplication should be removed.
673
        repo = self.make_repository('broken-repo')
674
        cleanups = []
675
        try:
676
            repo.lock_write()
677
            cleanups.append(repo.unlock)
678
            repo.start_write_group()
679
            cleanups.append(repo.commit_write_group)
680
            # make rev1a: A well-formed revision, containing 'file1'
681
            inv = inventory.Inventory(revision_id='rev1a')
682
            inv.root.revision = 'rev1a'
683
            self.add_file(repo, inv, 'file1', 'rev1a', [])
684
            repo.add_inventory('rev1a', inv, [])
685
            revision = _mod_revision.Revision('rev1a',
686
                committer='jrandom@example.com', timestamp=0,
687
                inventory_sha1='', timezone=0, message='foo', parent_ids=[])
688
            repo.add_revision('rev1a',revision, inv)
689
690
            # make rev1b, which has no Revision, but has an Inventory, and
691
            # file1
692
            inv = inventory.Inventory(revision_id='rev1b')
693
            inv.root.revision = 'rev1b'
694
            self.add_file(repo, inv, 'file1', 'rev1b', [])
695
            repo.add_inventory('rev1b', inv, [])
696
697
            # make rev2, with file1 and file2
698
            # file2 is sane
699
            # file1 has 'rev1b' as an ancestor, even though this is not
700
            # mentioned by 'rev1a', making it an unreferenced ancestor
701
            inv = inventory.Inventory()
702
            self.add_file(repo, inv, 'file1', 'rev2', ['rev1a', 'rev1b'])
703
            self.add_file(repo, inv, 'file2', 'rev2', [])
704
            self.add_revision(repo, 'rev2', inv, ['rev1a'])
705
706
            # make ghost revision rev1c
707
            inv = inventory.Inventory()
708
            self.add_file(repo, inv, 'file2', 'rev1c', [])
709
710
            # make rev3 with file2
711
            # file2 refers to 'rev1c', which is a ghost in this repository, so
712
            # file2 cannot have rev1c as its ancestor.
713
            inv = inventory.Inventory()
714
            self.add_file(repo, inv, 'file2', 'rev3', ['rev1c'])
715
            self.add_revision(repo, 'rev3', inv, ['rev1c'])
716
            return repo
717
        finally:
718
            for cleanup in reversed(cleanups):
719
                cleanup()
720
721
    def add_revision(self, repo, revision_id, inv, parent_ids):
722
        inv.revision_id = revision_id
723
        inv.root.revision = revision_id
724
        repo.add_inventory(revision_id, inv, parent_ids)
725
        revision = _mod_revision.Revision(revision_id,
726
            committer='jrandom@example.com', timestamp=0, inventory_sha1='',
727
            timezone=0, message='foo', parent_ids=parent_ids)
728
        repo.add_revision(revision_id,revision, inv)
729
730
    def add_file(self, repo, inv, filename, revision, parents):
731
        file_id = filename + '-id'
732
        entry = inventory.InventoryFile(file_id, filename, 'TREE_ROOT')
733
        entry.revision = revision
2535.4.10 by Andrew Bennetts
Fix one failing test, disable another.
734
        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.
735
        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.
736
        text_key = (file_id, revision)
737
        parent_keys = [(file_id, parent) for parent in parents]
738
        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.
739
740
    def test_insert_from_broken_repo(self):
741
        """Inserting a data stream from a broken repository won't silently
742
        corrupt the target repository.
743
        """
744
        broken_repo = self.make_broken_repository()
745
        empty_repo = self.make_repository('empty-repo')
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.
746
        self.assertRaises(errors.RevisionNotPresent, empty_repo.fetch, broken_repo)
2592.3.214 by Robert Collins
Merge bzr.dev.
747
748
2592.3.84 by Robert Collins
Start of autopacking logic.
749
class TestRepositoryPackCollection(TestCaseWithTransport):
750
751
    def get_format(self):
3010.3.3 by Martin Pool
Merge trunk
752
        return bzrdir.format_registry.make_bzrdir('pack-0.92')
2592.3.84 by Robert Collins
Start of autopacking logic.
753
3711.4.1 by John Arbash Meinel
Fix bug #242510, when determining the autopack sequence,
754
    def get_packs(self):
755
        format = self.get_format()
756
        repo = self.make_repository('.', format=format)
757
        return repo._pack_collection
758
2592.3.84 by Robert Collins
Start of autopacking logic.
759
    def test__max_pack_count(self):
2592.3.219 by Robert Collins
Review feedback.
760
        """The maximum pack count is a function of the number of revisions."""
2592.3.84 by Robert Collins
Start of autopacking logic.
761
        # no revisions - one pack, so that we can have a revision free repo
762
        # without it blowing up
3711.4.1 by John Arbash Meinel
Fix bug #242510, when determining the autopack sequence,
763
        packs = self.get_packs()
2592.3.84 by Robert Collins
Start of autopacking logic.
764
        self.assertEqual(1, packs._max_pack_count(0))
765
        # after that the sum of the digits, - check the first 1-9
766
        self.assertEqual(1, packs._max_pack_count(1))
767
        self.assertEqual(2, packs._max_pack_count(2))
768
        self.assertEqual(3, packs._max_pack_count(3))
769
        self.assertEqual(4, packs._max_pack_count(4))
770
        self.assertEqual(5, packs._max_pack_count(5))
771
        self.assertEqual(6, packs._max_pack_count(6))
772
        self.assertEqual(7, packs._max_pack_count(7))
773
        self.assertEqual(8, packs._max_pack_count(8))
774
        self.assertEqual(9, packs._max_pack_count(9))
775
        # check the boundary cases with two digits for the next decade
776
        self.assertEqual(1, packs._max_pack_count(10))
777
        self.assertEqual(2, packs._max_pack_count(11))
778
        self.assertEqual(10, packs._max_pack_count(19))
779
        self.assertEqual(2, packs._max_pack_count(20))
780
        self.assertEqual(3, packs._max_pack_count(21))
781
        # check some arbitrary big numbers
782
        self.assertEqual(25, packs._max_pack_count(112894))
783
784
    def test_pack_distribution_zero(self):
3711.4.1 by John Arbash Meinel
Fix bug #242510, when determining the autopack sequence,
785
        packs = self.get_packs()
2592.3.84 by Robert Collins
Start of autopacking logic.
786
        self.assertEqual([0], packs.pack_distribution(0))
3052.1.6 by John Arbash Meinel
Change the lock check to raise ObjectNotLocked.
787
788
    def test_ensure_loaded_unlocked(self):
3711.4.1 by John Arbash Meinel
Fix bug #242510, when determining the autopack sequence,
789
        packs = self.get_packs()
3052.1.6 by John Arbash Meinel
Change the lock check to raise ObjectNotLocked.
790
        self.assertRaises(errors.ObjectNotLocked,
3711.4.1 by John Arbash Meinel
Fix bug #242510, when determining the autopack sequence,
791
                          packs.ensure_loaded)
3052.1.6 by John Arbash Meinel
Change the lock check to raise ObjectNotLocked.
792
2592.3.84 by Robert Collins
Start of autopacking logic.
793
    def test_pack_distribution_one_to_nine(self):
3711.4.1 by John Arbash Meinel
Fix bug #242510, when determining the autopack sequence,
794
        packs = self.get_packs()
2592.3.84 by Robert Collins
Start of autopacking logic.
795
        self.assertEqual([1],
796
            packs.pack_distribution(1))
797
        self.assertEqual([1, 1],
798
            packs.pack_distribution(2))
799
        self.assertEqual([1, 1, 1],
800
            packs.pack_distribution(3))
801
        self.assertEqual([1, 1, 1, 1],
802
            packs.pack_distribution(4))
803
        self.assertEqual([1, 1, 1, 1, 1],
804
            packs.pack_distribution(5))
805
        self.assertEqual([1, 1, 1, 1, 1, 1],
806
            packs.pack_distribution(6))
807
        self.assertEqual([1, 1, 1, 1, 1, 1, 1],
808
            packs.pack_distribution(7))
809
        self.assertEqual([1, 1, 1, 1, 1, 1, 1, 1],
810
            packs.pack_distribution(8))
811
        self.assertEqual([1, 1, 1, 1, 1, 1, 1, 1, 1],
812
            packs.pack_distribution(9))
813
814
    def test_pack_distribution_stable_at_boundaries(self):
815
        """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,
816
        packs = self.get_packs()
2592.3.84 by Robert Collins
Start of autopacking logic.
817
        # in 10s:
818
        self.assertEqual([10], packs.pack_distribution(10))
819
        self.assertEqual([10, 1], packs.pack_distribution(11))
820
        self.assertEqual([10, 10], packs.pack_distribution(20))
821
        self.assertEqual([10, 10, 1], packs.pack_distribution(21))
822
        # 100s
823
        self.assertEqual([100], packs.pack_distribution(100))
824
        self.assertEqual([100, 1], packs.pack_distribution(101))
825
        self.assertEqual([100, 10, 1], packs.pack_distribution(111))
826
        self.assertEqual([100, 100], packs.pack_distribution(200))
827
        self.assertEqual([100, 100, 1], packs.pack_distribution(201))
828
        self.assertEqual([100, 100, 10, 1], packs.pack_distribution(211))
829
2592.3.85 by Robert Collins
Finish autopack corner cases.
830
    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,
831
        packs = self.get_packs()
2592.3.85 by Robert Collins
Finish autopack corner cases.
832
        existing_packs = [(2000, "big"), (9, "medium")]
833
        # rev count - 2009 -> 2x1000 + 9x1
834
        pack_operations = packs.plan_autopack_combinations(
835
            existing_packs, [1000, 1000, 1, 1, 1, 1, 1, 1, 1, 1, 1])
836
        self.assertEqual([], pack_operations)
837
838
    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,
839
        packs = self.get_packs()
2592.3.85 by Robert Collins
Finish autopack corner cases.
840
        existing_packs = [(2000, "big"), (9, "medium"), (1, "single")]
841
        # rev count - 2010 -> 2x1000 + 1x10
842
        pack_operations = packs.plan_autopack_combinations(
843
            existing_packs, [1000, 1000, 10])
844
        self.assertEqual([], pack_operations)
845
846
    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,
847
        packs = self.get_packs()
2592.3.85 by Robert Collins
Finish autopack corner cases.
848
        existing_packs = [(1999, "big"), (9, "medium"), (1, "single2"),
849
            (1, "single1")]
850
        # rev count - 2010 -> 2x1000 + 1x10 (3)
851
        pack_operations = packs.plan_autopack_combinations(
852
            existing_packs, [1000, 1000, 10])
3711.4.2 by John Arbash Meinel
Change the logic to solve it in a different way.
853
        self.assertEqual([[2, ["single2", "single1"]]], pack_operations)
2592.3.85 by Robert Collins
Finish autopack corner cases.
854
3711.4.2 by John Arbash Meinel
Change the logic to solve it in a different way.
855
    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,
856
        packs = self.get_packs()
3711.4.2 by John Arbash Meinel
Change the logic to solve it in a different way.
857
        existing_packs = [(50, 'a'), (40, 'b'), (30, 'c'), (10, 'd'),
858
                          (10, 'e'), (6, 'f'), (4, 'g')]
859
        # rev count 150 -> 1x100 and 5x10
860
        # The two size 10 packs do not need to be touched. The 50, 40, 30 would
861
        # be combined into a single 120 size pack, and the 6 & 4 would
862
        # becombined into a size 10 pack. However, if we have to rewrite them,
863
        # we save a pack file with no increased I/O by putting them into the
864
        # same file.
865
        distribution = packs.pack_distribution(150)
3711.4.1 by John Arbash Meinel
Fix bug #242510, when determining the autopack sequence,
866
        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.
867
                                                           distribution)
868
        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,
869
2592.3.173 by Robert Collins
Basic implementation of all_packs.
870
    def test_all_packs_none(self):
871
        format = self.get_format()
872
        tree = self.make_branch_and_tree('.', format=format)
873
        tree.lock_read()
874
        self.addCleanup(tree.unlock)
2592.3.232 by Martin Pool
Disambiguate two member variables called _packs into _packs_by_name and _pack_collection
875
        packs = tree.branch.repository._pack_collection
2592.3.173 by Robert Collins
Basic implementation of all_packs.
876
        packs.ensure_loaded()
877
        self.assertEqual([], packs.all_packs())
878
879
    def test_all_packs_one(self):
880
        format = self.get_format()
881
        tree = self.make_branch_and_tree('.', format=format)
882
        tree.commit('start')
883
        tree.lock_read()
884
        self.addCleanup(tree.unlock)
2592.3.232 by Martin Pool
Disambiguate two member variables called _packs into _packs_by_name and _pack_collection
885
        packs = tree.branch.repository._pack_collection
2592.3.173 by Robert Collins
Basic implementation of all_packs.
886
        packs.ensure_loaded()
2592.3.176 by Robert Collins
Various pack refactorings.
887
        self.assertEqual([
888
            packs.get_pack_by_name(packs.names()[0])],
889
            packs.all_packs())
2592.3.173 by Robert Collins
Basic implementation of all_packs.
890
891
    def test_all_packs_two(self):
892
        format = self.get_format()
893
        tree = self.make_branch_and_tree('.', format=format)
894
        tree.commit('start')
895
        tree.commit('continue')
896
        tree.lock_read()
897
        self.addCleanup(tree.unlock)
2592.3.232 by Martin Pool
Disambiguate two member variables called _packs into _packs_by_name and _pack_collection
898
        packs = tree.branch.repository._pack_collection
2592.3.173 by Robert Collins
Basic implementation of all_packs.
899
        packs.ensure_loaded()
900
        self.assertEqual([
2592.3.176 by Robert Collins
Various pack refactorings.
901
            packs.get_pack_by_name(packs.names()[0]),
902
            packs.get_pack_by_name(packs.names()[1]),
2592.3.173 by Robert Collins
Basic implementation of all_packs.
903
            ], packs.all_packs())
904
2592.3.176 by Robert Collins
Various pack refactorings.
905
    def test_get_pack_by_name(self):
906
        format = self.get_format()
907
        tree = self.make_branch_and_tree('.', format=format)
908
        tree.commit('start')
909
        tree.lock_read()
910
        self.addCleanup(tree.unlock)
2592.3.232 by Martin Pool
Disambiguate two member variables called _packs into _packs_by_name and _pack_collection
911
        packs = tree.branch.repository._pack_collection
2592.3.176 by Robert Collins
Various pack refactorings.
912
        packs.ensure_loaded()
913
        name = packs.names()[0]
914
        pack_1 = packs.get_pack_by_name(name)
915
        # the pack should be correctly initialised
3517.4.5 by Martin Pool
Correct use of packs._names in test_get_pack_by_name
916
        sizes = packs._names[name]
3221.12.4 by Robert Collins
Implement basic repository supporting external references.
917
        rev_index = GraphIndex(packs._index_transport, name + '.rix', sizes[0])
918
        inv_index = GraphIndex(packs._index_transport, name + '.iix', sizes[1])
919
        txt_index = GraphIndex(packs._index_transport, name + '.tix', sizes[2])
920
        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.
921
        self.assertEqual(pack_repo.ExistingPack(packs._pack_transport,
2592.3.219 by Robert Collins
Review feedback.
922
            name, rev_index, inv_index, txt_index, sig_index), pack_1)
2592.3.176 by Robert Collins
Various pack refactorings.
923
        # and the same instance should be returned on successive calls.
924
        self.assertTrue(pack_1 is packs.get_pack_by_name(name))
925
3789.1.2 by John Arbash Meinel
Add RepositoryPackCollection.reload_pack_names()
926
    def test_reload_pack_names_new_entry(self):
927
        tree = self.make_branch_and_tree('.')
928
        tree.lock_write()
929
        self.addCleanup(tree.unlock)
930
        rev1 = tree.commit('one')
931
        rev2 = tree.commit('two')
932
        r = repository.Repository.open('.')
933
        r.lock_read()
934
        self.addCleanup(r.unlock)
935
        packs = r._pack_collection
936
        packs.ensure_loaded()
937
        names = packs.names()
938
        # Add a new pack file into the repository
939
        rev3 = tree.commit('three')
940
        new_names = tree.branch.repository._pack_collection.names()
941
        new_name = set(new_names).difference(names)
942
        self.assertEqual(1, len(new_name))
943
        new_name = new_name.pop()
944
        # The old collection hasn't noticed yet
945
        self.assertEqual(names, packs.names())
3789.1.8 by John Arbash Meinel
Change the api of reload_pack_names().
946
        self.assertTrue(packs.reload_pack_names())
3789.1.2 by John Arbash Meinel
Add RepositoryPackCollection.reload_pack_names()
947
        self.assertEqual(new_names, packs.names())
948
        # And the repository can access the new revision
949
        self.assertEqual({rev3:(rev2,)}, r.get_parent_map([rev3]))
3789.1.8 by John Arbash Meinel
Change the api of reload_pack_names().
950
        self.assertFalse(packs.reload_pack_names())
3789.1.2 by John Arbash Meinel
Add RepositoryPackCollection.reload_pack_names()
951
952
    def test_reload_pack_names_added_and_removed(self):
953
        tree = self.make_branch_and_tree('.')
954
        tree.lock_write()
955
        self.addCleanup(tree.unlock)
956
        rev1 = tree.commit('one')
957
        rev2 = tree.commit('two')
958
        r = repository.Repository.open('.')
959
        r.lock_read()
960
        self.addCleanup(r.unlock)
961
        packs = r._pack_collection
962
        packs.ensure_loaded()
963
        names = packs.names()
964
        # Now repack the whole thing
965
        tree.branch.repository.pack()
966
        new_names = tree.branch.repository._pack_collection.names()
967
        # The other collection hasn't noticed yet
968
        self.assertEqual(names, packs.names())
3789.1.8 by John Arbash Meinel
Change the api of reload_pack_names().
969
        self.assertTrue(packs.reload_pack_names())
3789.1.2 by John Arbash Meinel
Add RepositoryPackCollection.reload_pack_names()
970
        self.assertEqual(new_names, packs.names())
971
        self.assertEqual({rev2:(rev1,)}, r.get_parent_map([rev2]))
3789.1.8 by John Arbash Meinel
Change the api of reload_pack_names().
972
        self.assertFalse(packs.reload_pack_names())
3789.1.2 by John Arbash Meinel
Add RepositoryPackCollection.reload_pack_names()
973
2592.3.173 by Robert Collins
Basic implementation of all_packs.
974
975
class TestPack(TestCaseWithTransport):
976
    """Tests for the Pack object."""
977
978
    def assertCurrentlyEqual(self, left, right):
979
        self.assertTrue(left == right)
980
        self.assertTrue(right == left)
981
        self.assertFalse(left != right)
982
        self.assertFalse(right != left)
983
984
    def assertCurrentlyNotEqual(self, left, right):
985
        self.assertFalse(left == right)
986
        self.assertFalse(right == left)
987
        self.assertTrue(left != right)
988
        self.assertTrue(right != left)
989
990
    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.
991
        left = pack_repo.ExistingPack('', '', '', '', '', '')
992
        right = pack_repo.ExistingPack('', '', '', '', '', '')
2592.3.173 by Robert Collins
Basic implementation of all_packs.
993
        self.assertCurrentlyEqual(left, right)
994
        # change all attributes and ensure equality changes as we do.
995
        left.revision_index = 'a'
996
        self.assertCurrentlyNotEqual(left, right)
997
        right.revision_index = 'a'
998
        self.assertCurrentlyEqual(left, right)
999
        left.inventory_index = 'a'
1000
        self.assertCurrentlyNotEqual(left, right)
1001
        right.inventory_index = 'a'
1002
        self.assertCurrentlyEqual(left, right)
1003
        left.text_index = 'a'
1004
        self.assertCurrentlyNotEqual(left, right)
1005
        right.text_index = 'a'
1006
        self.assertCurrentlyEqual(left, right)
1007
        left.signature_index = 'a'
1008
        self.assertCurrentlyNotEqual(left, right)
1009
        right.signature_index = 'a'
1010
        self.assertCurrentlyEqual(left, right)
1011
        left.name = 'a'
1012
        self.assertCurrentlyNotEqual(left, right)
1013
        right.name = 'a'
1014
        self.assertCurrentlyEqual(left, right)
1015
        left.transport = 'a'
1016
        self.assertCurrentlyNotEqual(left, right)
1017
        right.transport = 'a'
1018
        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.
1019
1020
    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.
1021
        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.
1022
        self.assertEqual('a_name.pack', pack.file_name())
2592.3.192 by Robert Collins
Move new revision index management to NewPack.
1023
1024
1025
class TestNewPack(TestCaseWithTransport):
1026
    """Tests for pack_repo.NewPack."""
1027
2592.3.193 by Robert Collins
Move hash tracking of new packs into NewPack.
1028
    def test_new_instance_attributes(self):
2592.3.194 by Robert Collins
Output the revision index from NewPack.finish
1029
        upload_transport = self.get_transport('upload')
1030
        pack_transport = self.get_transport('pack')
1031
        index_transport = self.get_transport('index')
1032
        upload_transport.mkdir('.')
1033
        pack = pack_repo.NewPack(upload_transport, index_transport,
3735.1.1 by Robert Collins
Add development2 formats using BTree indices.
1034
            pack_transport, index_builder_class=BTreeBuilder,
1035
            index_class=BTreeGraphIndex)
1036
        self.assertIsInstance(pack.revision_index, BTreeBuilder)
1037
        self.assertIsInstance(pack.inventory_index, BTreeBuilder)
3734.2.4 by Vincent Ladeuil
Fix python2.6 deprecation warnings related to hashlib.
1038
        self.assertIsInstance(pack._hash, type(osutils.md5()))
2592.3.194 by Robert Collins
Output the revision index from NewPack.finish
1039
        self.assertTrue(pack.upload_transport is upload_transport)
1040
        self.assertTrue(pack.index_transport is index_transport)
1041
        self.assertTrue(pack.pack_transport is pack_transport)
1042
        self.assertEqual(None, pack.index_sizes)
1043
        self.assertEqual(20, len(pack.random_name))
1044
        self.assertIsInstance(pack.random_name, str)
1045
        self.assertIsInstance(pack.start_time, float)
2951.1.2 by Robert Collins
Partial refactoring of pack_repo to create a Packer object for packing.
1046
1047
1048
class TestPacker(TestCaseWithTransport):
1049
    """Tests for the packs repository Packer class."""
2951.1.10 by Robert Collins
Peer review feedback with Ian.
1050
1051
    # To date, this class has been factored out and nothing new added to it;
1052
    # thus there are not yet any tests.
3146.6.1 by Aaron Bentley
InterDifferingSerializer shows a progress bar
1053
1054
3777.5.4 by John Arbash Meinel
OptimisingPacker now sets the optimize flags for the indexes being built.
1055
class TestOptimisingPacker(TestCaseWithTransport):
1056
    """Tests for the OptimisingPacker class."""
1057
1058
    def get_pack_collection(self):
1059
        repo = self.make_repository('.')
1060
        return repo._pack_collection
1061
1062
    def test_open_pack_will_optimise(self):
1063
        packer = pack_repo.OptimisingPacker(self.get_pack_collection(),
1064
                                            [], '.test')
1065
        new_pack = packer.open_pack()
1066
        self.assertIsInstance(new_pack, pack_repo.NewPack)
1067
        self.assertTrue(new_pack.revision_index._optimize_for_size)
1068
        self.assertTrue(new_pack.inventory_index._optimize_for_size)
1069
        self.assertTrue(new_pack.text_index._optimize_for_size)
1070
        self.assertTrue(new_pack.signature_index._optimize_for_size)
1071
1072
3146.6.1 by Aaron Bentley
InterDifferingSerializer shows a progress bar
1073
class TestInterDifferingSerializer(TestCaseWithTransport):
1074
1075
    def test_progress_bar(self):
1076
        tree = self.make_branch_and_tree('tree')
1077
        tree.commit('rev1', rev_id='rev-1')
1078
        tree.commit('rev2', rev_id='rev-2')
1079
        tree.commit('rev3', rev_id='rev-3')
1080
        repo = self.make_repository('repo')
1081
        inter_repo = repository.InterDifferingSerializer(
1082
            tree.branch.repository, repo)
1083
        pb = progress.InstrumentedProgress(to_file=StringIO())
1084
        pb.never_throttle = True
1085
        inter_repo.fetch('rev-1', pb)
1086
        self.assertEqual('Transferring revisions', pb.last_msg)
1087
        self.assertEqual(1, pb.last_cnt)
1088
        self.assertEqual(1, pb.last_total)
1089
        inter_repo.fetch('rev-3', pb)
1090
        self.assertEqual(2, pb.last_cnt)
1091
        self.assertEqual(2, pb.last_total)