~bzr-pqm/bzr/bzr.dev

2220.2.2 by Martin Pool
Add tag command and basic implementation
1
# Copyright (C) 2006, 2007 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
19
For interface tests see tests/repository_implementations/*.py.
20
21
For concrete class tests see this file, and for storage formats tests
22
also see this file.
23
"""
24
2592.3.193 by Robert Collins
Move hash tracking of new packs into NewPack.
25
import md5
1773.4.1 by Martin Pool
Add pyflakes makefile target; fix many warnings
26
from stat import S_ISDIR
1534.4.40 by Robert Collins
Add RepositoryFormats and allow bzrdir.open or create _repository to be used.
27
from StringIO import StringIO
28
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.
29
import bzrlib
1534.4.40 by Robert Collins
Add RepositoryFormats and allow bzrdir.open or create _repository to be used.
30
from bzrlib.errors import (NotBranchError,
1534.4.41 by Robert Collins
Branch now uses BzrDir reasonably sanely.
31
                           NoSuchFile,
1534.4.40 by Robert Collins
Add RepositoryFormats and allow bzrdir.open or create _repository to be used.
32
                           UnknownFormatError,
33
                           UnsupportedFormatError,
34
                           )
3184.1.9 by Robert Collins
* ``Repository.get_data_stream`` is now deprecated in favour of
35
from bzrlib import graph
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,
3146.6.1 by Aaron Bentley
InterDifferingSerializer shows a progress bar
55
    progress,
2241.1.1 by Martin Pool
Change RepositoryFormat to use a Registry rather than ad-hoc dictionary
56
    repository,
2535.3.57 by Andrew Bennetts
Perform some sanity checking of data streams rather than blindly inserting them into our repository.
57
    revision as _mod_revision,
2535.3.41 by Andrew Bennetts
Add tests for InterRemoteToOther.is_compatible.
58
    symbol_versioning,
2241.1.1 by Martin Pool
Change RepositoryFormat to use a Registry rather than ad-hoc dictionary
59
    upgrade,
60
    workingtree,
61
    )
2592.3.173 by Robert Collins
Basic implementation of all_packs.
62
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.
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
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.
124
        # this is not quite the same as 
125
        self.build_tree(["foo/", "bar/"])
126
        def check_format(format, url):
127
            dir = format._matchingbzrdir.initialize(url)
128
            format.initialize(dir)
129
            t = get_transport(url)
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")
1534.4.47 by Robert Collins
Split out repository into .bzr/repository
133
        
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
165
    def test_no_ancestry_weave(self):
166
        control = bzrdir.BzrDirFormat6().initialize(self.get_url())
2241.1.4 by Martin Pool
Moved old weave-based repository formats into bzrlib.repofmt.weaverepo.
167
        repo = weaverepo.RepositoryFormat6().initialize(control)
1534.4.41 by Robert Collins
Branch now uses BzrDir reasonably sanely.
168
        # We no longer need to create the ancestry.weave file
169
        # since it is *never* used.
170
        self.assertRaises(NoSuchFile,
171
                          control.transport.get,
172
                          'ancestry.weave')
173
2818.4.2 by Robert Collins
Review feedback.
174
    def test_exposed_versioned_files_are_marked_dirty(self):
175
        control = bzrdir.BzrDirFormat6().initialize(self.get_url())
176
        repo = weaverepo.RepositoryFormat6().initialize(control)
177
        repo.lock_write()
178
        inv = repo.get_inventory_weave()
179
        repo.unlock()
180
        self.assertRaises(errors.OutSideTransaction,
181
            inv.add_lines, 'foo', [], [])
182
3221.3.1 by Robert Collins
* Repository formats have a new supported-feature attribute
183
    def test_supports_external_lookups(self):
184
        control = bzrdir.BzrDirFormat6().initialize(self.get_url())
185
        repo = weaverepo.RepositoryFormat6().initialize(control)
186
        self.assertFalse(repo._format.supports_external_lookups)
187
1534.4.47 by Robert Collins
Split out repository into .bzr/repository
188
189
class TestFormat7(TestCaseWithTransport):
190
    
191
    def test_disk_layout(self):
192
        control = bzrdir.BzrDirMetaFormat1().initialize(self.get_url())
2241.1.4 by Martin Pool
Moved old weave-based repository formats into bzrlib.repofmt.weaverepo.
193
        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.
194
        # in case of side effects of locking.
195
        repo.lock_write()
196
        repo.unlock()
1534.4.47 by Robert Collins
Split out repository into .bzr/repository
197
        # we want:
198
        # format 'Bazaar-NG Repository format 7'
199
        # lock ''
200
        # inventory.weave == empty_weave
201
        # empty revision-store directory
202
        # empty weaves directory
203
        t = control.get_repository_transport(None)
204
        self.assertEqualDiff('Bazaar-NG Repository format 7',
205
                             t.get('format').read())
206
        self.assertTrue(S_ISDIR(t.stat('revision-store').st_mode))
207
        self.assertTrue(S_ISDIR(t.stat('weaves').st_mode))
208
        self.assertEqualDiff('# bzr weave file v5\n'
209
                             'w\n'
210
                             'W\n',
211
                             t.get('inventory.weave').read())
1534.6.1 by Robert Collins
allow API creation of shared repositories
212
213
    def test_shared_disk_layout(self):
214
        control = bzrdir.BzrDirMetaFormat1().initialize(self.get_url())
2241.1.4 by Martin Pool
Moved old weave-based repository formats into bzrlib.repofmt.weaverepo.
215
        repo = weaverepo.RepositoryFormat7().initialize(control, shared=True)
1534.6.1 by Robert Collins
allow API creation of shared repositories
216
        # we want:
217
        # format 'Bazaar-NG Repository format 7'
218
        # inventory.weave == empty_weave
219
        # empty revision-store directory
220
        # empty weaves directory
221
        # a 'shared-storage' marker file.
1553.5.49 by Martin Pool
Use LockDirs for repo format 7
222
        # lock is not present when unlocked
1534.6.1 by Robert Collins
allow API creation of shared repositories
223
        t = control.get_repository_transport(None)
224
        self.assertEqualDiff('Bazaar-NG Repository format 7',
225
                             t.get('format').read())
226
        self.assertEqualDiff('', t.get('shared-storage').read())
227
        self.assertTrue(S_ISDIR(t.stat('revision-store').st_mode))
228
        self.assertTrue(S_ISDIR(t.stat('weaves').st_mode))
229
        self.assertEqualDiff('# bzr weave file v5\n'
230
                             'w\n'
231
                             'W\n',
232
                             t.get('inventory.weave').read())
1553.5.49 by Martin Pool
Use LockDirs for repo format 7
233
        self.assertFalse(t.has('branch-lock'))
234
1553.5.56 by Martin Pool
Format 7 repo now uses LockDir!
235
    def test_creates_lockdir(self):
1553.5.49 by Martin Pool
Use LockDirs for repo format 7
236
        """Make sure it appears to be controlled by a LockDir existence"""
237
        control = bzrdir.BzrDirMetaFormat1().initialize(self.get_url())
2241.1.4 by Martin Pool
Moved old weave-based repository formats into bzrlib.repofmt.weaverepo.
238
        repo = weaverepo.RepositoryFormat7().initialize(control, shared=True)
1553.5.49 by Martin Pool
Use LockDirs for repo format 7
239
        t = control.get_repository_transport(None)
1553.5.58 by Martin Pool
Change LockDirs to format "lock-name/held/info"
240
        # TODO: Should check there is a 'lock' toplevel directory, 
241
        # regardless of contents
242
        self.assertFalse(t.has('lock/held/info'))
1553.5.49 by Martin Pool
Use LockDirs for repo format 7
243
        repo.lock_write()
1658.1.4 by Martin Pool
Quieten warning from TestFormat7.test_creates_lockdir about failing to unlock
244
        try:
245
            self.assertTrue(t.has('lock/held/info'))
246
        finally:
247
            # unlock so we don't get a warning about failing to do so
248
            repo.unlock()
1553.5.56 by Martin Pool
Format 7 repo now uses LockDir!
249
250
    def test_uses_lockdir(self):
251
        """repo format 7 actually locks on lockdir"""
252
        base_url = self.get_url()
253
        control = bzrdir.BzrDirMetaFormat1().initialize(base_url)
2241.1.4 by Martin Pool
Moved old weave-based repository formats into bzrlib.repofmt.weaverepo.
254
        repo = weaverepo.RepositoryFormat7().initialize(control, shared=True)
1553.5.56 by Martin Pool
Format 7 repo now uses LockDir!
255
        t = control.get_repository_transport(None)
256
        repo.lock_write()
257
        repo.unlock()
258
        del repo
259
        # make sure the same lock is created by opening it
260
        repo = repository.Repository.open(base_url)
261
        repo.lock_write()
1553.5.58 by Martin Pool
Change LockDirs to format "lock-name/held/info"
262
        self.assertTrue(t.has('lock/held/info'))
1553.5.56 by Martin Pool
Format 7 repo now uses LockDir!
263
        repo.unlock()
1553.5.58 by Martin Pool
Change LockDirs to format "lock-name/held/info"
264
        self.assertFalse(t.has('lock/held/info'))
1534.6.5 by Robert Collins
Cloning of repos preserves shared and make-working-tree attributes.
265
266
    def test_shared_no_tree_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.5 by Robert Collins
Cloning of repos preserves shared and make-working-tree attributes.
269
        repo.set_make_working_trees(False)
270
        # we want:
271
        # format 'Bazaar-NG Repository format 7'
272
        # lock ''
273
        # inventory.weave == empty_weave
274
        # empty revision-store directory
275
        # empty weaves directory
276
        # a 'shared-storage' marker file.
277
        t = control.get_repository_transport(None)
278
        self.assertEqualDiff('Bazaar-NG Repository format 7',
279
                             t.get('format').read())
1553.5.56 by Martin Pool
Format 7 repo now uses LockDir!
280
        ## self.assertEqualDiff('', t.get('lock').read())
1534.6.5 by Robert Collins
Cloning of repos preserves shared and make-working-tree attributes.
281
        self.assertEqualDiff('', t.get('shared-storage').read())
282
        self.assertEqualDiff('', t.get('no-working-trees').read())
283
        repo.set_make_working_trees(True)
284
        self.assertFalse(t.has('no-working-trees'))
285
        self.assertTrue(S_ISDIR(t.stat('revision-store').st_mode))
286
        self.assertTrue(S_ISDIR(t.stat('weaves').st_mode))
287
        self.assertEqualDiff('# bzr weave file v5\n'
288
                             'w\n'
289
                             'W\n',
290
                             t.get('inventory.weave').read())
1534.1.27 by Robert Collins
Start InterRepository with InterRepository.get.
291
2818.4.2 by Robert Collins
Review feedback.
292
    def test_exposed_versioned_files_are_marked_dirty(self):
293
        control = bzrdir.BzrDirMetaFormat1().initialize(self.get_url())
294
        repo = weaverepo.RepositoryFormat7().initialize(control)
295
        repo.lock_write()
296
        inv = repo.get_inventory_weave()
297
        repo.unlock()
298
        self.assertRaises(errors.OutSideTransaction,
299
            inv.add_lines, 'foo', [], [])
300
3221.3.1 by Robert Collins
* Repository formats have a new supported-feature attribute
301
    def test_supports_external_lookups(self):
302
        control = bzrdir.BzrDirMetaFormat1().initialize(self.get_url())
303
        repo = weaverepo.RepositoryFormat7().initialize(control)
304
        self.assertFalse(repo._format.supports_external_lookups)
305
1534.1.27 by Robert Collins
Start InterRepository with InterRepository.get.
306
1556.1.3 by Robert Collins
Rearrangment of Repository logic to be less type code driven, and bugfix InterRepository.missing_revision_ids
307
class TestFormatKnit1(TestCaseWithTransport):
308
    
309
    def test_disk_layout(self):
310
        control = bzrdir.BzrDirMetaFormat1().initialize(self.get_url())
2241.1.6 by Martin Pool
Move Knit repositories into the submodule bzrlib.repofmt.knitrepo and
311
        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
312
        # in case of side effects of locking.
313
        repo.lock_write()
314
        repo.unlock()
315
        # we want:
316
        # format 'Bazaar-NG Knit Repository Format 1'
1553.5.62 by Martin Pool
Add tests that MetaDir repositories use LockDirs
317
        # 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
318
        # inventory.weave == empty_weave
319
        # empty revision-store directory
320
        # empty weaves directory
321
        t = control.get_repository_transport(None)
322
        self.assertEqualDiff('Bazaar-NG Knit Repository Format 1',
323
                             t.get('format').read())
1553.5.57 by Martin Pool
[merge] sync from bzr.dev
324
        # XXX: no locks left when unlocked at the moment
325
        # 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
326
        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.
327
        self.check_knits(t)
328
1654.1.3 by Robert Collins
Refactor repository knit tests slightly to remove duplication - add a assertHasKnit method.
329
    def assertHasKnit(self, t, knit_name):
330
        """Assert that knit_name exists on t."""
1666.1.7 by Robert Collins
Update repository format check to read knit correct header
331
        self.assertEqualDiff('# bzr knit index 8\n',
1654.1.3 by Robert Collins
Refactor repository knit tests slightly to remove duplication - add a assertHasKnit method.
332
                             t.get(knit_name + '.kndx').read())
333
        # no default content
334
        self.assertTrue(t.has(knit_name + '.knit'))
335
1563.2.35 by Robert Collins
cleanup deprecation warnings and finish conversion so the inventory is knit based too.
336
    def check_knits(self, t):
337
        """check knit content for a repository."""
1654.1.3 by Robert Collins
Refactor repository knit tests slightly to remove duplication - add a assertHasKnit method.
338
        self.assertHasKnit(t, 'inventory')
339
        self.assertHasKnit(t, 'revisions')
340
        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
341
342
    def test_shared_disk_layout(self):
343
        control = bzrdir.BzrDirMetaFormat1().initialize(self.get_url())
2241.1.6 by Martin Pool
Move Knit repositories into the submodule bzrlib.repofmt.knitrepo and
344
        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
345
        # we want:
346
        # format 'Bazaar-NG Knit Repository Format 1'
1553.5.62 by Martin Pool
Add tests that MetaDir repositories use LockDirs
347
        # 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
348
        # inventory.weave == empty_weave
349
        # empty revision-store directory
350
        # empty weaves directory
351
        # a 'shared-storage' marker file.
352
        t = control.get_repository_transport(None)
353
        self.assertEqualDiff('Bazaar-NG Knit Repository Format 1',
354
                             t.get('format').read())
1553.5.57 by Martin Pool
[merge] sync from bzr.dev
355
        # XXX: no locks left when unlocked at the moment
356
        # 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
357
        self.assertEqualDiff('', t.get('shared-storage').read())
358
        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.
359
        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
360
361
    def test_shared_no_tree_disk_layout(self):
362
        control = bzrdir.BzrDirMetaFormat1().initialize(self.get_url())
2241.1.6 by Martin Pool
Move Knit repositories into the submodule bzrlib.repofmt.knitrepo and
363
        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
364
        repo.set_make_working_trees(False)
365
        # we want:
366
        # format 'Bazaar-NG Knit Repository Format 1'
367
        # lock ''
368
        # inventory.weave == empty_weave
369
        # empty revision-store directory
370
        # empty weaves directory
371
        # a 'shared-storage' marker file.
372
        t = control.get_repository_transport(None)
373
        self.assertEqualDiff('Bazaar-NG Knit Repository Format 1',
374
                             t.get('format').read())
1553.5.57 by Martin Pool
[merge] sync from bzr.dev
375
        # XXX: no locks left when unlocked at the moment
376
        # 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
377
        self.assertEqualDiff('', t.get('shared-storage').read())
378
        self.assertEqualDiff('', t.get('no-working-trees').read())
379
        repo.set_make_working_trees(True)
380
        self.assertFalse(t.has('no-working-trees'))
381
        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.
382
        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
383
2818.4.2 by Robert Collins
Review feedback.
384
    def test_exposed_versioned_files_are_marked_dirty(self):
385
        format = bzrdir.BzrDirMetaFormat1()
386
        format.repository_format = knitrepo.RepositoryFormatKnit1()
387
        repo = self.make_repository('.', format=format)
388
        repo.lock_write()
389
        inv = repo.get_inventory_weave()
390
        repo.unlock()
391
        self.assertRaises(errors.OutSideTransaction,
392
            inv.add_lines, 'foo', [], [])
393
2917.2.1 by John Arbash Meinel
Fix bug #152360. The xml5 serializer should be using
394
    def test_deserialise_sets_root_revision(self):
395
        """We must have a inventory.root.revision
396
397
        Old versions of the XML5 serializer did not set the revision_id for
398
        the whole inventory. So we grab the one from the expected text. Which
399
        is valid when the api is not being abused.
400
        """
401
        repo = self.make_repository('.',
402
                format=bzrdir.format_registry.get('knit')())
403
        inv_xml = '<inventory format="5">\n</inventory>\n'
404
        inv = repo.deserialise_inventory('test-rev-id', inv_xml)
405
        self.assertEqual('test-rev-id', inv.root.revision)
406
407
    def test_deserialise_uses_global_revision_id(self):
408
        """If it is set, then we re-use the global revision id"""
409
        repo = self.make_repository('.',
410
                format=bzrdir.format_registry.get('knit')())
411
        inv_xml = ('<inventory format="5" revision_id="other-rev-id">\n'
412
                   '</inventory>\n')
413
        # Arguably, the deserialise_inventory should detect a mismatch, and
414
        # raise an error, rather than silently using one revision_id over the
415
        # 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.
416
        self.assertRaises(AssertionError, repo.deserialise_inventory,
417
            'test-rev-id', inv_xml)
418
        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
419
        self.assertEqual('other-rev-id', inv.root.revision)
420
3221.3.1 by Robert Collins
* Repository formats have a new supported-feature attribute
421
    def test_supports_external_lookups(self):
422
        repo = self.make_repository('.',
423
                format=bzrdir.format_registry.get('knit')())
424
        self.assertFalse(repo._format.supports_external_lookups)
425
2305.2.3 by Andrew Bennetts
Bring across test_repository improvements from the hpss branch to fix the last test failures.
426
2535.3.53 by Andrew Bennetts
Remove get_stream_as_bytes from KnitVersionedFile's API, make it a function in knitrepo.py instead.
427
class KnitRepositoryStreamTests(test_knit.KnitTests):
428
    """Tests for knitrepo._get_stream_as_bytes."""
429
430
    def test_get_stream_as_bytes(self):
431
        # Make a simple knit
432
        k1 = self.make_test_knit()
433
        k1.add_lines('text-a', [], test_knit.split_lines(test_knit.TEXT_1))
434
        
435
        # Serialise it, check the output.
436
        bytes = knitrepo._get_stream_as_bytes(k1, ['text-a'])
437
        data = bencode.bdecode(bytes)
438
        format, record = data
439
        self.assertEqual('knit-plain', format)
440
        self.assertEqual(['text-a', ['fulltext'], []], record[:3])
441
        self.assertRecordContentEqual(k1, 'text-a', record[3])
442
443
    def test_get_stream_as_bytes_all(self):
444
        """Get a serialised data stream for all the records in a knit.
445
446
        Much like test_get_stream_all, except for get_stream_as_bytes.
447
        """
448
        k1 = self.make_test_knit()
449
        # Insert the same data as BasicKnitTests.test_knit_join, as they seem
450
        # to cover a range of cases (no parents, one parent, multiple parents).
451
        test_data = [
452
            ('text-a', [], test_knit.TEXT_1),
453
            ('text-b', ['text-a'], test_knit.TEXT_1),
454
            ('text-c', [], test_knit.TEXT_1),
455
            ('text-d', ['text-c'], test_knit.TEXT_1),
456
            ('text-m', ['text-b', 'text-d'], test_knit.TEXT_1),
457
           ]
3023.2.3 by Martin Pool
Update tests for new ordering of results from get_data_stream - the order is not defined by the interface, but is stable
458
        # This test is actually a bit strict as the order in which they're
459
        # returned is not defined.  This matches the current (deterministic)
460
        # behaviour.
2535.3.53 by Andrew Bennetts
Remove get_stream_as_bytes from KnitVersionedFile's API, make it a function in knitrepo.py instead.
461
        expected_data_list = [
462
            # version, options, parents
463
            ('text-a', ['fulltext'], []),
464
            ('text-b', ['line-delta'], ['text-a']),
3023.2.3 by Martin Pool
Update tests for new ordering of results from get_data_stream - the order is not defined by the interface, but is stable
465
            ('text-m', ['line-delta'], ['text-b', 'text-d']),
2535.3.53 by Andrew Bennetts
Remove get_stream_as_bytes from KnitVersionedFile's API, make it a function in knitrepo.py instead.
466
            ('text-c', ['fulltext'], []),
467
            ('text-d', ['line-delta'], ['text-c']),
468
            ]
469
        for version_id, parents, lines in test_data:
470
            k1.add_lines(version_id, parents, test_knit.split_lines(lines))
471
472
        bytes = knitrepo._get_stream_as_bytes(
3023.2.3 by Martin Pool
Update tests for new ordering of results from get_data_stream - the order is not defined by the interface, but is stable
473
            k1, ['text-a', 'text-b', 'text-m', 'text-c', 'text-d', ])
2535.3.53 by Andrew Bennetts
Remove get_stream_as_bytes from KnitVersionedFile's API, make it a function in knitrepo.py instead.
474
475
        data = bencode.bdecode(bytes)
476
        format = data.pop(0)
477
        self.assertEqual('knit-plain', format)
478
479
        for expected, actual in zip(expected_data_list, data):
480
            expected_version = expected[0]
481
            expected_options = expected[1]
482
            expected_parents = expected[2]
483
            version, options, parents, bytes = actual
484
            self.assertEqual(expected_version, version)
485
            self.assertEqual(expected_options, options)
486
            self.assertEqual(expected_parents, parents)
487
            self.assertRecordContentEqual(k1, version, bytes)
488
489
2305.2.3 by Andrew Bennetts
Bring across test_repository improvements from the hpss branch to fix the last test failures.
490
class DummyRepository(object):
491
    """A dummy repository for testing."""
492
493
    _serializer = None
494
495
    def supports_rich_root(self):
496
        return False
497
498
499
class InterDummy(repository.InterRepository):
500
    """An inter-repository optimised code path for DummyRepository.
501
502
    This is for use during testing where we use DummyRepository as repositories
1534.1.28 by Robert Collins
Allow for optimised InterRepository selection.
503
    so that none of the default regsitered inter-repository classes will
2818.4.2 by Robert Collins
Review feedback.
504
    MATCH.
1534.1.28 by Robert Collins
Allow for optimised InterRepository selection.
505
    """
506
507
    @staticmethod
508
    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.
509
        """InterDummy is compatible with DummyRepository."""
510
        return (isinstance(repo_source, DummyRepository) and 
511
            isinstance(repo_target, DummyRepository))
1534.1.28 by Robert Collins
Allow for optimised InterRepository selection.
512
513
1534.1.27 by Robert Collins
Start InterRepository with InterRepository.get.
514
class TestInterRepository(TestCaseWithTransport):
515
516
    def test_get_default_inter_repository(self):
517
        # test that the InterRepository.get(repo_a, repo_b) probes
518
        # for a inter_repo class where is_compatible(repo_a, repo_b) returns
519
        # true and returns a default inter_repo otherwise.
520
        # This also tests that the default registered optimised interrepository
521
        # classes do not barf inappropriately when a surprising repository type
522
        # 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.
523
        dummy_a = DummyRepository()
524
        dummy_b = DummyRepository()
1534.1.28 by Robert Collins
Allow for optimised InterRepository selection.
525
        self.assertGetsDefaultInterRepository(dummy_a, dummy_b)
526
527
    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.
528
        """Asserts that InterRepository.get(repo_a, repo_b) -> the default.
529
        
530
        The effective default is now InterSameDataRepository because there is
531
        no actual sane default in the presence of incompatible data models.
532
        """
1534.1.28 by Robert Collins
Allow for optimised InterRepository selection.
533
        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.
534
        self.assertEqual(repository.InterSameDataRepository,
1534.1.27 by Robert Collins
Start InterRepository with InterRepository.get.
535
                         inter_repo.__class__)
1534.1.28 by Robert Collins
Allow for optimised InterRepository selection.
536
        self.assertEqual(repo_a, inter_repo.source)
537
        self.assertEqual(repo_b, inter_repo.target)
538
539
    def test_register_inter_repository_class(self):
540
        # test that a optimised code path provider - a
541
        # InterRepository subclass can be registered and unregistered
542
        # and that it is correctly selected when given a repository
543
        # pair that it returns true on for the is_compatible static method
544
        # check
2305.2.3 by Andrew Bennetts
Bring across test_repository improvements from the hpss branch to fix the last test failures.
545
        dummy_a = DummyRepository()
546
        dummy_b = DummyRepository()
547
        repo = self.make_repository('.')
548
        # hack dummies to look like repo somewhat.
549
        dummy_a._serializer = repo._serializer
550
        dummy_b._serializer = repo._serializer
551
        repository.InterRepository.register_optimiser(InterDummy)
1534.1.28 by Robert Collins
Allow for optimised InterRepository selection.
552
        try:
2305.2.3 by Andrew Bennetts
Bring across test_repository improvements from the hpss branch to fix the last test failures.
553
            # we should get the default for something InterDummy returns False
1534.1.28 by Robert Collins
Allow for optimised InterRepository selection.
554
            # to
2305.2.3 by Andrew Bennetts
Bring across test_repository improvements from the hpss branch to fix the last test failures.
555
            self.assertFalse(InterDummy.is_compatible(dummy_a, repo))
556
            self.assertGetsDefaultInterRepository(dummy_a, repo)
557
            # and we should get an InterDummy for a pair it 'likes'
558
            self.assertTrue(InterDummy.is_compatible(dummy_a, dummy_b))
1534.1.28 by Robert Collins
Allow for optimised InterRepository selection.
559
            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.
560
            self.assertEqual(InterDummy, inter_repo.__class__)
1534.1.28 by Robert Collins
Allow for optimised InterRepository selection.
561
            self.assertEqual(dummy_a, inter_repo.source)
562
            self.assertEqual(dummy_b, inter_repo.target)
563
        finally:
2305.2.3 by Andrew Bennetts
Bring across test_repository improvements from the hpss branch to fix the last test failures.
564
            repository.InterRepository.unregister_optimiser(InterDummy)
1534.1.28 by Robert Collins
Allow for optimised InterRepository selection.
565
        # now we should get the default InterRepository object again.
566
        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.
567
2241.1.17 by Martin Pool
Restore old InterWeave tests
568
569
class TestInterWeaveRepo(TestCaseWithTransport):
570
571
    def test_is_compatible_and_registered(self):
572
        # InterWeaveRepo is compatible when either side
573
        # is a format 5/6/7 branch
2241.1.20 by mbp at sourcefrog
update tests for new locations of weave repos
574
        from bzrlib.repofmt import knitrepo, weaverepo
575
        formats = [weaverepo.RepositoryFormat5(),
576
                   weaverepo.RepositoryFormat6(),
577
                   weaverepo.RepositoryFormat7()]
578
        incompatible_formats = [weaverepo.RepositoryFormat4(),
579
                                knitrepo.RepositoryFormatKnit1(),
2241.1.17 by Martin Pool
Restore old InterWeave tests
580
                                ]
581
        repo_a = self.make_repository('a')
582
        repo_b = self.make_repository('b')
583
        is_compatible = repository.InterWeaveRepo.is_compatible
584
        for source in incompatible_formats:
585
            # force incompatible left then right
586
            repo_a._format = source
587
            repo_b._format = formats[0]
588
            self.assertFalse(is_compatible(repo_a, repo_b))
589
            self.assertFalse(is_compatible(repo_b, repo_a))
590
        for source in formats:
591
            repo_a._format = source
592
            for target in formats:
593
                repo_b._format = target
594
                self.assertTrue(is_compatible(repo_a, repo_b))
595
        self.assertEqual(repository.InterWeaveRepo,
596
                         repository.InterRepository.get(repo_a,
597
                                                        repo_b).__class__)
598
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.
599
2535.3.41 by Andrew Bennetts
Add tests for InterRemoteToOther.is_compatible.
600
class TestInterRemoteToOther(TestCaseWithTransport):
601
602
    def make_remote_repository(self, path, backing_format=None):
603
        """Make a RemoteRepository object backed by a real repository that will
604
        be created at the given path."""
605
        self.make_repository(path, format=backing_format)
606
        smart_server = server.SmartTCPServer_for_testing()
607
        smart_server.setUp()
608
        remote_transport = get_transport(smart_server.get_url()).clone(path)
609
        self.addCleanup(smart_server.tearDown)
610
        remote_bzrdir = bzrdir.BzrDir.open_from_transport(remote_transport)
611
        remote_repo = remote_bzrdir.open_repository()
612
        return remote_repo
613
614
    def test_is_compatible_same_format(self):
615
        """InterRemoteToOther is compatible with a remote repository and a
616
        second repository that have the same format."""
617
        local_repo = self.make_repository('local')
618
        remote_repo = self.make_remote_repository('remote')
2535.3.62 by Andrew Bennetts
Cosmetic changes.
619
        is_compatible = repository.InterRemoteToOther.is_compatible
2535.3.41 by Andrew Bennetts
Add tests for InterRemoteToOther.is_compatible.
620
        self.assertTrue(
2535.3.62 by Andrew Bennetts
Cosmetic changes.
621
            is_compatible(remote_repo, local_repo),
2535.3.41 by Andrew Bennetts
Add tests for InterRemoteToOther.is_compatible.
622
            "InterRemoteToOther(%r, %r) is false" % (remote_repo, local_repo))
623
          
624
    def test_is_incompatible_different_format(self):
625
        local_repo = self.make_repository('local', 'dirstate')
626
        remote_repo = self.make_remote_repository('a', 'dirstate-with-subtree')
2535.3.62 by Andrew Bennetts
Cosmetic changes.
627
        is_compatible = repository.InterRemoteToOther.is_compatible
2535.3.65 by Andrew Bennetts
Correct test failure caused by typo.
628
        self.assertFalse(
2535.3.62 by Andrew Bennetts
Cosmetic changes.
629
            is_compatible(remote_repo, local_repo),
2535.3.65 by Andrew Bennetts
Correct test failure caused by typo.
630
            "InterRemoteToOther(%r, %r) is true" % (local_repo, remote_repo))
2535.3.41 by Andrew Bennetts
Add tests for InterRemoteToOther.is_compatible.
631
632
    def test_is_incompatible_different_format_both_remote(self):
2535.3.66 by Andrew Bennetts
Tidy a couple more long lines.
633
        remote_repo_a = self.make_remote_repository(
634
            'a', 'dirstate-with-subtree')
2535.3.41 by Andrew Bennetts
Add tests for InterRemoteToOther.is_compatible.
635
        remote_repo_b = self.make_remote_repository('b', 'dirstate')
2535.3.62 by Andrew Bennetts
Cosmetic changes.
636
        is_compatible = repository.InterRemoteToOther.is_compatible
2535.3.41 by Andrew Bennetts
Add tests for InterRemoteToOther.is_compatible.
637
        self.assertFalse(
2535.3.62 by Andrew Bennetts
Cosmetic changes.
638
            is_compatible(remote_repo_a, remote_repo_b),
2535.3.66 by Andrew Bennetts
Tidy a couple more long lines.
639
            "InterRemoteToOther(%r, %r) is true"
640
            % (remote_repo_a, remote_repo_b))
2535.3.41 by Andrew Bennetts
Add tests for InterRemoteToOther.is_compatible.
641
642
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.
643
class TestRepositoryConverter(TestCaseWithTransport):
644
645
    def test_convert_empty(self):
646
        t = get_transport(self.get_url('.'))
647
        t.mkdir('repository')
648
        repo_dir = bzrdir.BzrDirMetaFormat1().initialize('repository')
2241.1.4 by Martin Pool
Moved old weave-based repository formats into bzrlib.repofmt.weaverepo.
649
        repo = weaverepo.RepositoryFormat7().initialize(repo_dir)
2241.1.6 by Martin Pool
Move Knit repositories into the submodule bzrlib.repofmt.knitrepo and
650
        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.
651
        converter = repository.CopyConverter(target_format)
1594.1.3 by Robert Collins
Fixup pb usage to use nested_progress_bar.
652
        pb = bzrlib.ui.ui_factory.nested_progress_bar()
653
        try:
654
            converter.convert(repo, pb)
655
        finally:
656
            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.
657
        repo = repo_dir.open_repository()
658
        self.assertTrue(isinstance(target_format, repo._format.__class__))
1843.2.5 by Aaron Bentley
Add test of _unescape_xml
659
660
661
class TestMisc(TestCase):
662
    
663
    def test_unescape_xml(self):
664
        """We get some kind of error when malformed entities are passed"""
665
        self.assertRaises(KeyError, repository._unescape_xml, 'foo&bar;') 
1910.2.13 by Aaron Bentley
Start work on converter
666
667
2255.2.211 by Robert Collins
Remove knit2 repository format- it has never been supported.
668
class TestRepositoryFormatKnit3(TestCaseWithTransport):
1910.2.13 by Aaron Bentley
Start work on converter
669
670
    def test_convert(self):
671
        """Ensure the upgrade adds weaves for roots"""
1910.2.35 by Aaron Bentley
Better fix for convesion test
672
        format = bzrdir.BzrDirMetaFormat1()
2241.1.6 by Martin Pool
Move Knit repositories into the submodule bzrlib.repofmt.knitrepo and
673
        format.repository_format = knitrepo.RepositoryFormatKnit1()
1910.2.35 by Aaron Bentley
Better fix for convesion test
674
        tree = self.make_branch_and_tree('.', format)
1910.2.13 by Aaron Bentley
Start work on converter
675
        tree.commit("Dull commit", rev_id="dull")
676
        revision_tree = tree.branch.repository.revision_tree('dull')
677
        self.assertRaises(errors.NoSuchFile, revision_tree.get_file_lines,
678
            revision_tree.inventory.root.file_id)
679
        format = bzrdir.BzrDirMetaFormat1()
2255.2.211 by Robert Collins
Remove knit2 repository format- it has never been supported.
680
        format.repository_format = knitrepo.RepositoryFormatKnit3()
1910.2.13 by Aaron Bentley
Start work on converter
681
        upgrade.Convert('.', format)
1910.2.27 by Aaron Bentley
Fixed conversion test
682
        tree = workingtree.WorkingTree.open('.')
1910.2.13 by Aaron Bentley
Start work on converter
683
        revision_tree = tree.branch.repository.revision_tree('dull')
684
        revision_tree.get_file_lines(revision_tree.inventory.root.file_id)
1910.2.27 by Aaron Bentley
Fixed conversion test
685
        tree.commit("Another dull commit", rev_id='dull2')
686
        revision_tree = tree.branch.repository.revision_tree('dull2')
687
        self.assertEqual('dull', revision_tree.inventory.root.revision)
2220.2.2 by Martin Pool
Add tag command and basic implementation
688
2818.4.2 by Robert Collins
Review feedback.
689
    def test_exposed_versioned_files_are_marked_dirty(self):
690
        format = bzrdir.BzrDirMetaFormat1()
691
        format.repository_format = knitrepo.RepositoryFormatKnit3()
692
        repo = self.make_repository('.', format=format)
693
        repo.lock_write()
694
        inv = repo.get_inventory_weave()
695
        repo.unlock()
696
        self.assertRaises(errors.OutSideTransaction,
697
            inv.add_lines, 'foo', [], [])
2535.4.9 by Andrew Bennetts
Merge from bzr.dev
698
3221.3.1 by Robert Collins
* Repository formats have a new supported-feature attribute
699
    def test_supports_external_lookups(self):
700
        format = bzrdir.BzrDirMetaFormat1()
701
        format.repository_format = knitrepo.RepositoryFormatKnit3()
702
        repo = self.make_repository('.', format=format)
703
        self.assertFalse(repo._format.supports_external_lookups)
704
2535.3.57 by Andrew Bennetts
Perform some sanity checking of data streams rather than blindly inserting them into our repository.
705
706
class TestWithBrokenRepo(TestCaseWithTransport):
2592.3.214 by Robert Collins
Merge bzr.dev.
707
    """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.
708
709
    def make_broken_repository(self):
710
        # XXX: This function is borrowed from Aaron's "Reconcile can fix bad
711
        # parent references" branch which is due to land in bzr.dev soon.  Once
712
        # it does, this duplication should be removed.
713
        repo = self.make_repository('broken-repo')
714
        cleanups = []
715
        try:
716
            repo.lock_write()
717
            cleanups.append(repo.unlock)
718
            repo.start_write_group()
719
            cleanups.append(repo.commit_write_group)
720
            # make rev1a: A well-formed revision, containing 'file1'
721
            inv = inventory.Inventory(revision_id='rev1a')
722
            inv.root.revision = 'rev1a'
723
            self.add_file(repo, inv, 'file1', 'rev1a', [])
724
            repo.add_inventory('rev1a', inv, [])
725
            revision = _mod_revision.Revision('rev1a',
726
                committer='jrandom@example.com', timestamp=0,
727
                inventory_sha1='', timezone=0, message='foo', parent_ids=[])
728
            repo.add_revision('rev1a',revision, inv)
729
730
            # make rev1b, which has no Revision, but has an Inventory, and
731
            # file1
732
            inv = inventory.Inventory(revision_id='rev1b')
733
            inv.root.revision = 'rev1b'
734
            self.add_file(repo, inv, 'file1', 'rev1b', [])
735
            repo.add_inventory('rev1b', inv, [])
736
737
            # make rev2, with file1 and file2
738
            # file2 is sane
739
            # file1 has 'rev1b' as an ancestor, even though this is not
740
            # mentioned by 'rev1a', making it an unreferenced ancestor
741
            inv = inventory.Inventory()
742
            self.add_file(repo, inv, 'file1', 'rev2', ['rev1a', 'rev1b'])
743
            self.add_file(repo, inv, 'file2', 'rev2', [])
744
            self.add_revision(repo, 'rev2', inv, ['rev1a'])
745
746
            # make ghost revision rev1c
747
            inv = inventory.Inventory()
748
            self.add_file(repo, inv, 'file2', 'rev1c', [])
749
750
            # make rev3 with file2
751
            # file2 refers to 'rev1c', which is a ghost in this repository, so
752
            # file2 cannot have rev1c as its ancestor.
753
            inv = inventory.Inventory()
754
            self.add_file(repo, inv, 'file2', 'rev3', ['rev1c'])
755
            self.add_revision(repo, 'rev3', inv, ['rev1c'])
756
            return repo
757
        finally:
758
            for cleanup in reversed(cleanups):
759
                cleanup()
760
761
    def add_revision(self, repo, revision_id, inv, parent_ids):
762
        inv.revision_id = revision_id
763
        inv.root.revision = revision_id
764
        repo.add_inventory(revision_id, inv, parent_ids)
765
        revision = _mod_revision.Revision(revision_id,
766
            committer='jrandom@example.com', timestamp=0, inventory_sha1='',
767
            timezone=0, message='foo', parent_ids=parent_ids)
768
        repo.add_revision(revision_id,revision, inv)
769
770
    def add_file(self, repo, inv, filename, revision, parents):
771
        file_id = filename + '-id'
772
        entry = inventory.InventoryFile(file_id, filename, 'TREE_ROOT')
773
        entry.revision = revision
2535.4.10 by Andrew Bennetts
Fix one failing test, disable another.
774
        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.
775
        inv.add(entry)
776
        vf = repo.weave_store.get_weave_or_empty(file_id,
777
                                                 repo.get_transaction())
778
        vf.add_lines(revision, parents, ['line\n'])
779
780
    def test_insert_from_broken_repo(self):
781
        """Inserting a data stream from a broken repository won't silently
782
        corrupt the target repository.
783
        """
784
        broken_repo = self.make_broken_repository()
785
        empty_repo = self.make_repository('empty-repo')
3184.1.9 by Robert Collins
* ``Repository.get_data_stream`` is now deprecated in favour of
786
        search = graph.SearchResult(set(['rev1a', 'rev2', 'rev3']),
787
            set(), 3, ['rev1a', 'rev2', 'rev3'])
3381.1.3 by Aaron Bentley
Stop locking in get_data_stream_for_search
788
        broken_repo.lock_read()
789
        self.addCleanup(broken_repo.unlock)
3184.1.9 by Robert Collins
* ``Repository.get_data_stream`` is now deprecated in favour of
790
        stream = broken_repo.get_data_stream_for_search(search)
2592.3.214 by Robert Collins
Merge bzr.dev.
791
        empty_repo.lock_write()
792
        self.addCleanup(empty_repo.unlock)
793
        empty_repo.start_write_group()
794
        try:
795
            self.assertRaises(
796
                errors.KnitCorrupt, empty_repo.insert_data_stream, stream)
797
        finally:
798
            empty_repo.abort_write_group()
799
800
2939.2.1 by Ian Clatworthy
use 'knitpack' naming instead of 'experimental' for pack formats
801
class TestKnitPackNoSubtrees(TestCaseWithTransport):
2592.3.24 by Robert Collins
Knit1 disk layout specified.
802
803
    def get_format(self):
3010.3.3 by Martin Pool
Merge trunk
804
        return bzrdir.format_registry.make_bzrdir('pack-0.92')
2592.3.24 by Robert Collins
Knit1 disk layout specified.
805
806
    def test_disk_layout(self):
807
        format = self.get_format()
2592.3.36 by Robert Collins
Change the revision index name to NAME.rix.
808
        repo = self.make_repository('.', format=format)
2592.3.24 by Robert Collins
Knit1 disk layout specified.
809
        # in case of side effects of locking.
810
        repo.lock_write()
811
        repo.unlock()
812
        t = repo.bzrdir.get_repository_transport(None)
813
        self.check_format(t)
814
        # XXX: no locks left when unlocked at the moment
815
        # self.assertEqualDiff('', t.get('lock').read())
816
        self.check_databases(t)
817
818
    def check_format(self, t):
2939.2.5 by Ian Clatworthy
review feedback from lifeless
819
        self.assertEqualDiff(
2939.2.7 by Ian Clatworthy
fix strings used in on-disk unit tests
820
            "Bazaar pack repository format 1 (needs bzr 0.92)\n",
2592.3.24 by Robert Collins
Knit1 disk layout specified.
821
                             t.get('format').read())
822
823
    def assertHasKndx(self, t, knit_name):
824
        """Assert that knit_name exists on t."""
825
        self.assertEqualDiff('# bzr knit index 8\n',
826
                             t.get(knit_name + '.kndx').read())
827
828
    def assertHasNoKndx(self, t, knit_name):
829
        """Assert that knit_name has no index on t."""
830
        self.assertFalse(t.has(knit_name + '.kndx'))
831
2592.3.81 by Robert Collins
Merge FileName allocation change, leading to hash based pack file names.
832
    def assertHasNoKnit(self, t, knit_name):
2592.3.24 by Robert Collins
Knit1 disk layout specified.
833
        """Assert that knit_name exists on t."""
834
        # no default content
2592.3.81 by Robert Collins
Merge FileName allocation change, leading to hash based pack file names.
835
        self.assertFalse(t.has(knit_name + '.knit'))
2592.3.24 by Robert Collins
Knit1 disk layout specified.
836
837
    def check_databases(self, t):
838
        """check knit content for a repository."""
2592.3.81 by Robert Collins
Merge FileName allocation change, leading to hash based pack file names.
839
        # check conversion worked
2592.3.61 by Robert Collins
Remove inventory.kndx.
840
        self.assertHasNoKndx(t, 'inventory')
2592.3.81 by Robert Collins
Merge FileName allocation change, leading to hash based pack file names.
841
        self.assertHasNoKnit(t, 'inventory')
2592.3.24 by Robert Collins
Knit1 disk layout specified.
842
        self.assertHasNoKndx(t, 'revisions')
2592.3.81 by Robert Collins
Merge FileName allocation change, leading to hash based pack file names.
843
        self.assertHasNoKnit(t, 'revisions')
2592.3.39 by Robert Collins
Fugly version to remove signatures.kndx
844
        self.assertHasNoKndx(t, 'signatures')
2592.3.81 by Robert Collins
Merge FileName allocation change, leading to hash based pack file names.
845
        self.assertHasNoKnit(t, 'signatures')
846
        self.assertFalse(t.has('knits'))
2592.3.24 by Robert Collins
Knit1 disk layout specified.
847
        # revision-indexes file-container directory
2592.3.83 by Robert Collins
Merge bzr.dev, dropping FileNames for a trivial GraphIndex layer.
848
        self.assertEqual([],
2592.3.175 by Robert Collins
Update for GraphIndex constructor changes.
849
            list(GraphIndex(t, 'pack-names', None).iter_all_entries()))
2592.3.81 by Robert Collins
Merge FileName allocation change, leading to hash based pack file names.
850
        self.assertTrue(S_ISDIR(t.stat('packs').st_mode))
851
        self.assertTrue(S_ISDIR(t.stat('upload').st_mode))
2592.3.219 by Robert Collins
Review feedback.
852
        self.assertTrue(S_ISDIR(t.stat('indices').st_mode))
853
        self.assertTrue(S_ISDIR(t.stat('obsolete_packs').st_mode))
2592.3.24 by Robert Collins
Knit1 disk layout specified.
854
855
    def test_shared_disk_layout(self):
856
        format = self.get_format()
2592.3.36 by Robert Collins
Change the revision index name to NAME.rix.
857
        repo = self.make_repository('.', shared=True, format=format)
2592.3.24 by Robert Collins
Knit1 disk layout specified.
858
        # we want:
859
        t = repo.bzrdir.get_repository_transport(None)
860
        self.check_format(t)
861
        # XXX: no locks left when unlocked at the moment
862
        # self.assertEqualDiff('', t.get('lock').read())
2592.3.219 by Robert Collins
Review feedback.
863
        # We should have a 'shared-storage' marker file.
2592.3.24 by Robert Collins
Knit1 disk layout specified.
864
        self.assertEqualDiff('', t.get('shared-storage').read())
865
        self.check_databases(t)
866
867
    def test_shared_no_tree_disk_layout(self):
868
        format = self.get_format()
2592.3.36 by Robert Collins
Change the revision index name to NAME.rix.
869
        repo = self.make_repository('.', shared=True, format=format)
2592.3.24 by Robert Collins
Knit1 disk layout specified.
870
        repo.set_make_working_trees(False)
871
        # we want:
872
        t = repo.bzrdir.get_repository_transport(None)
873
        self.check_format(t)
874
        # XXX: no locks left when unlocked at the moment
875
        # self.assertEqualDiff('', t.get('lock').read())
2592.3.219 by Robert Collins
Review feedback.
876
        # We should have a 'shared-storage' marker file.
2592.3.24 by Robert Collins
Knit1 disk layout specified.
877
        self.assertEqualDiff('', t.get('shared-storage').read())
2592.3.219 by Robert Collins
Review feedback.
878
        # We should have a marker for the no-working-trees flag.
2592.3.24 by Robert Collins
Knit1 disk layout specified.
879
        self.assertEqualDiff('', t.get('no-working-trees').read())
2592.3.219 by Robert Collins
Review feedback.
880
        # The marker should go when we toggle the setting.
2592.3.24 by Robert Collins
Knit1 disk layout specified.
881
        repo.set_make_working_trees(True)
882
        self.assertFalse(t.has('no-working-trees'))
883
        self.check_databases(t)
2592.3.25 by Robert Collins
experimental-subtrees layout defined.
884
2592.3.188 by Robert Collins
Allow pack repositories to have multiple writers active at one time, for greater concurrency.
885
    def test_adding_revision_creates_pack_indices(self):
2592.3.118 by Robert Collins
Record the size of the index files in the pack-names index.
886
        format = self.get_format()
887
        tree = self.make_branch_and_tree('.', format=format)
888
        trans = tree.branch.repository.bzrdir.get_repository_transport(None)
889
        self.assertEqual([],
2592.3.175 by Robert Collins
Update for GraphIndex constructor changes.
890
            list(GraphIndex(trans, 'pack-names', None).iter_all_entries()))
2592.3.118 by Robert Collins
Record the size of the index files in the pack-names index.
891
        tree.commit('foobarbaz')
2592.3.175 by Robert Collins
Update for GraphIndex constructor changes.
892
        index = GraphIndex(trans, 'pack-names', None)
2592.3.219 by Robert Collins
Review feedback.
893
        index_nodes = list(index.iter_all_entries())
894
        self.assertEqual(1, len(index_nodes))
895
        node = index_nodes[0]
2592.3.118 by Robert Collins
Record the size of the index files in the pack-names index.
896
        name = node[1][0]
897
        # the pack sizes should be listed in the index
898
        pack_value = node[2]
899
        sizes = [int(digits) for digits in pack_value.split(' ')]
900
        for size, suffix in zip(sizes, ['.rix', '.iix', '.tix', '.six']):
901
            stat = trans.stat('indices/%s%s' % (name, suffix))
902
            self.assertEqual(size, stat.st_size)
2592.3.60 by Robert Collins
Nuke per-fileid indices for a single unified index.
903
2592.3.52 by Robert Collins
Stop allocating new names unless new data has been inserted.
904
    def test_pulling_nothing_leads_to_no_new_names(self):
905
        format = self.get_format()
906
        tree1 = self.make_branch_and_tree('1', format=format)
907
        tree2 = self.make_branch_and_tree('2', format=format)
908
        tree1.branch.repository.fetch(tree2.branch.repository)
909
        trans = tree1.branch.repository.bzrdir.get_repository_transport(None)
2592.3.83 by Robert Collins
Merge bzr.dev, dropping FileNames for a trivial GraphIndex layer.
910
        self.assertEqual([],
2592.3.175 by Robert Collins
Update for GraphIndex constructor changes.
911
            list(GraphIndex(trans, 'pack-names', None).iter_all_entries()))
2592.3.39 by Robert Collins
Fugly version to remove signatures.kndx
912
2592.3.84 by Robert Collins
Start of autopacking logic.
913
    def test_commit_across_pack_shape_boundary_autopacks(self):
914
        format = self.get_format()
915
        tree = self.make_branch_and_tree('.', format=format)
916
        trans = tree.branch.repository.bzrdir.get_repository_transport(None)
917
        # This test could be a little cheaper by replacing the packs
918
        # attribute on the repository to allow a different pack distribution
2592.3.219 by Robert Collins
Review feedback.
919
        # and max packs policy - so we are checking the policy is honoured
2592.3.84 by Robert Collins
Start of autopacking logic.
920
        # in the test. But for now 11 commits is not a big deal in a single
921
        # test.
922
        for x in range(9):
923
            tree.commit('commit %s' % x)
924
        # there should be 9 packs:
2592.3.175 by Robert Collins
Update for GraphIndex constructor changes.
925
        index = GraphIndex(trans, 'pack-names', None)
2592.3.84 by Robert Collins
Start of autopacking logic.
926
        self.assertEqual(9, len(list(index.iter_all_entries())))
2948.1.1 by Robert Collins
* Obsolete packs are now cleaned up by pack and autopack operations.
927
        # insert some files in obsolete_packs which should be removed by pack.
928
        trans.put_bytes('obsolete_packs/foo', '123')
929
        trans.put_bytes('obsolete_packs/bar', '321')
2592.3.84 by Robert Collins
Start of autopacking logic.
930
        # committing one more should coalesce to 1 of 10.
931
        tree.commit('commit triggering pack')
2592.3.175 by Robert Collins
Update for GraphIndex constructor changes.
932
        index = GraphIndex(trans, 'pack-names', None)
2592.3.84 by Robert Collins
Start of autopacking logic.
933
        self.assertEqual(1, len(list(index.iter_all_entries())))
934
        # packing should not damage data
935
        tree = tree.bzrdir.open_workingtree()
936
        check_result = tree.branch.repository.check(
937
            [tree.branch.last_revision()])
2948.1.1 by Robert Collins
* Obsolete packs are now cleaned up by pack and autopack operations.
938
        # We should have 50 (10x5) files in the obsolete_packs directory.
939
        obsolete_files = list(trans.list_dir('obsolete_packs'))
940
        self.assertFalse('foo' in obsolete_files)
941
        self.assertFalse('bar' in obsolete_files)
942
        self.assertEqual(50, len(obsolete_files))
2592.3.84 by Robert Collins
Start of autopacking logic.
943
        # XXX: Todo check packs obsoleted correctly - old packs and indices
944
        # in the obsolete_packs directory.
945
        large_pack_name = list(index.iter_all_entries())[0][1][0]
946
        # finally, committing again should not touch the large pack.
947
        tree.commit('commit not triggering pack')
2592.3.175 by Robert Collins
Update for GraphIndex constructor changes.
948
        index = GraphIndex(trans, 'pack-names', None)
2592.3.84 by Robert Collins
Start of autopacking logic.
949
        self.assertEqual(2, len(list(index.iter_all_entries())))
950
        pack_names = [node[1][0] for node in index.iter_all_entries()]
951
        self.assertTrue(large_pack_name in pack_names)
952
3446.2.1 by Martin Pool
Failure to delete an obsolete pack file should not be fatal.
953
    def test_fail_obsolete_deletion(self):
954
        # failing to delete obsolete packs is not fatal
955
        format = self.get_format()
956
        server = fakenfs.FakeNFSServer()
957
        server.setUp()
958
        self.addCleanup(server.tearDown)
959
        transport = get_transport(server.get_url())
960
        bzrdir = self.get_format().initialize_on_transport(transport)
961
        repo = bzrdir.create_repository()
962
        repo_transport = bzrdir.get_repository_transport(None)
963
        self.assertTrue(repo_transport.has('obsolete_packs'))
964
        # these files are in use by another client and typically can't be deleted
965
        repo_transport.put_bytes('obsolete_packs/.nfsblahblah', 'contents')
966
        repo._pack_collection._clear_obsolete_packs()
967
        self.assertTrue(repo_transport.has('obsolete_packs/.nfsblahblah'))
968
2592.3.86 by Robert Collins
Implement the pack commands for knit repositories.
969
    def test_pack_after_two_commits_packs_everything(self):
970
        format = self.get_format()
971
        tree = self.make_branch_and_tree('.', format=format)
972
        trans = tree.branch.repository.bzrdir.get_repository_transport(None)
973
        tree.commit('start')
974
        tree.commit('more work')
975
        tree.branch.repository.pack()
2592.3.219 by Robert Collins
Review feedback.
976
        # there should be 1 pack:
2592.3.175 by Robert Collins
Update for GraphIndex constructor changes.
977
        index = GraphIndex(trans, 'pack-names', None)
2592.3.86 by Robert Collins
Implement the pack commands for knit repositories.
978
        self.assertEqual(1, len(list(index.iter_all_entries())))
979
        self.assertEqual(2, len(tree.branch.repository.all_revision_ids()))
980
3070.1.1 by Robert Collins
* ``bzr pack`` now orders revision texts in topological order, with newest
981
    def test_pack_layout(self):
982
        format = self.get_format()
983
        tree = self.make_branch_and_tree('.', format=format)
984
        trans = tree.branch.repository.bzrdir.get_repository_transport(None)
985
        tree.commit('start', rev_id='1')
986
        tree.commit('more work', rev_id='2')
987
        tree.branch.repository.pack()
988
        tree.lock_read()
989
        self.addCleanup(tree.unlock)
990
        pack = tree.branch.repository._pack_collection.get_pack_by_name(
991
            tree.branch.repository._pack_collection.names()[0])
992
        # revision access tends to be tip->ancestor, so ordering that way on 
993
        # disk is a good idea.
994
        for _1, key, val, refs in pack.revision_index.iter_all_entries():
995
            if key == ('1',):
996
                pos_1 = int(val[1:].split()[0])
997
            else:
998
                pos_2 = int(val[1:].split()[0])
999
        self.assertTrue(pos_2 < pos_1)
1000
2592.3.188 by Robert Collins
Allow pack repositories to have multiple writers active at one time, for greater concurrency.
1001
    def test_pack_repositories_support_multiple_write_locks(self):
1002
        format = self.get_format()
1003
        self.make_repository('.', shared=True, format=format)
1004
        r1 = repository.Repository.open('.')
1005
        r2 = repository.Repository.open('.')
1006
        r1.lock_write()
1007
        self.addCleanup(r1.unlock)
1008
        r2.lock_write()
1009
        r2.unlock()
1010
1011
    def _add_text(self, repo, fileid):
1012
        """Add a text to the repository within a write group."""
1013
        vf =repo.weave_store.get_weave(fileid, repo.get_transaction())
1014
        vf.add_lines('samplerev+' + fileid, [], [])
1015
1016
    def test_concurrent_writers_merge_new_packs(self):
1017
        format = self.get_format()
1018
        self.make_repository('.', shared=True, format=format)
1019
        r1 = repository.Repository.open('.')
1020
        r2 = repository.Repository.open('.')
1021
        r1.lock_write()
1022
        try:
1023
            # access enough data to load the names list
1024
            list(r1.all_revision_ids())
1025
            r2.lock_write()
1026
            try:
1027
                # access enough data to load the names list
1028
                list(r2.all_revision_ids())
1029
                r1.start_write_group()
1030
                try:
1031
                    r2.start_write_group()
1032
                    try:
1033
                        self._add_text(r1, 'fileidr1')
1034
                        self._add_text(r2, 'fileidr2')
1035
                    except:
1036
                        r2.abort_write_group()
1037
                        raise
1038
                except:
1039
                    r1.abort_write_group()
1040
                    raise
1041
                # both r1 and r2 have open write groups with data in them
1042
                # created while the other's write group was open.
1043
                # Commit both which requires a merge to the pack-names.
1044
                try:
1045
                    r1.commit_write_group()
1046
                except:
2592.3.219 by Robert Collins
Review feedback.
1047
                    r1.abort_write_group()
2592.3.188 by Robert Collins
Allow pack repositories to have multiple writers active at one time, for greater concurrency.
1048
                    r2.abort_write_group()
1049
                    raise
1050
                r2.commit_write_group()
2592.3.213 by Robert Collins
Retain packs and indices in memory within a lock, even when write groups are entered and exited.
1051
                # tell r1 to reload from disk
2592.3.232 by Martin Pool
Disambiguate two member variables called _packs into _packs_by_name and _pack_collection
1052
                r1._pack_collection.reset()
2592.3.219 by Robert Collins
Review feedback.
1053
                # Now both repositories should know about both names
2592.3.232 by Martin Pool
Disambiguate two member variables called _packs into _packs_by_name and _pack_collection
1054
                r1._pack_collection.ensure_loaded()
1055
                r2._pack_collection.ensure_loaded()
1056
                self.assertEqual(r1._pack_collection.names(), r2._pack_collection.names())
1057
                self.assertEqual(2, len(r1._pack_collection.names()))
2592.3.188 by Robert Collins
Allow pack repositories to have multiple writers active at one time, for greater concurrency.
1058
            finally:
2939.1.1 by Martin Pool
Fix up mismatched lock/unlock pairs.
1059
                r2.unlock()
2592.3.188 by Robert Collins
Allow pack repositories to have multiple writers active at one time, for greater concurrency.
1060
        finally:
2939.1.1 by Martin Pool
Fix up mismatched lock/unlock pairs.
1061
            r1.unlock()
2592.3.188 by Robert Collins
Allow pack repositories to have multiple writers active at one time, for greater concurrency.
1062
1063
    def test_concurrent_writer_second_preserves_dropping_a_pack(self):
1064
        format = self.get_format()
1065
        self.make_repository('.', shared=True, format=format)
1066
        r1 = repository.Repository.open('.')
1067
        r2 = repository.Repository.open('.')
1068
        # add a pack to drop
1069
        r1.lock_write()
1070
        try:
1071
            r1.start_write_group()
1072
            try:
1073
                self._add_text(r1, 'fileidr1')
1074
            except:
1075
                r1.abort_write_group()
1076
                raise
1077
            else:
1078
                r1.commit_write_group()
2592.3.232 by Martin Pool
Disambiguate two member variables called _packs into _packs_by_name and _pack_collection
1079
            r1._pack_collection.ensure_loaded()
1080
            name_to_drop = r1._pack_collection.all_packs()[0].name
2592.3.188 by Robert Collins
Allow pack repositories to have multiple writers active at one time, for greater concurrency.
1081
        finally:
1082
            r1.unlock()
1083
        r1.lock_write()
1084
        try:
1085
            # access enough data to load the names list
1086
            list(r1.all_revision_ids())
1087
            r2.lock_write()
1088
            try:
1089
                # access enough data to load the names list
1090
                list(r2.all_revision_ids())
2592.3.232 by Martin Pool
Disambiguate two member variables called _packs into _packs_by_name and _pack_collection
1091
                r1._pack_collection.ensure_loaded()
2592.3.188 by Robert Collins
Allow pack repositories to have multiple writers active at one time, for greater concurrency.
1092
                try:
1093
                    r2.start_write_group()
1094
                    try:
1095
                        # in r1, drop the pack
2592.3.236 by Martin Pool
Make RepositoryPackCollection.remove_pack_from_memory private
1096
                        r1._pack_collection._remove_pack_from_memory(
2592.3.232 by Martin Pool
Disambiguate two member variables called _packs into _packs_by_name and _pack_collection
1097
                            r1._pack_collection.get_pack_by_name(name_to_drop))
2592.3.188 by Robert Collins
Allow pack repositories to have multiple writers active at one time, for greater concurrency.
1098
                        # in r2, add a pack
1099
                        self._add_text(r2, 'fileidr2')
1100
                    except:
1101
                        r2.abort_write_group()
1102
                        raise
1103
                except:
2592.3.232 by Martin Pool
Disambiguate two member variables called _packs into _packs_by_name and _pack_collection
1104
                    r1._pack_collection.reset()
2592.3.188 by Robert Collins
Allow pack repositories to have multiple writers active at one time, for greater concurrency.
1105
                    raise
1106
                # r1 has a changed names list, and r2 an open write groups with
1107
                # changes.
2592.3.208 by Robert Collins
Start refactoring the knit-pack thunking to be clearer.
1108
                # save r1, and then commit the r2 write group, which requires a
2592.3.188 by Robert Collins
Allow pack repositories to have multiple writers active at one time, for greater concurrency.
1109
                # merge to the pack-names, which should not reinstate
1110
                # name_to_drop
1111
                try:
2592.3.232 by Martin Pool
Disambiguate two member variables called _packs into _packs_by_name and _pack_collection
1112
                    r1._pack_collection._save_pack_names()
1113
                    r1._pack_collection.reset()
2592.3.188 by Robert Collins
Allow pack repositories to have multiple writers active at one time, for greater concurrency.
1114
                except:
1115
                    r2.abort_write_group()
1116
                    raise
1117
                try:
1118
                    r2.commit_write_group()
1119
                except:
1120
                    r2.abort_write_group()
1121
                    raise
1122
                # Now both repositories should now about just one name.
2592.3.232 by Martin Pool
Disambiguate two member variables called _packs into _packs_by_name and _pack_collection
1123
                r1._pack_collection.ensure_loaded()
1124
                r2._pack_collection.ensure_loaded()
1125
                self.assertEqual(r1._pack_collection.names(), r2._pack_collection.names())
1126
                self.assertEqual(1, len(r1._pack_collection.names()))
1127
                self.assertFalse(name_to_drop in r1._pack_collection.names())
2592.3.188 by Robert Collins
Allow pack repositories to have multiple writers active at one time, for greater concurrency.
1128
            finally:
2939.1.1 by Martin Pool
Fix up mismatched lock/unlock pairs.
1129
                r2.unlock()
2592.3.188 by Robert Collins
Allow pack repositories to have multiple writers active at one time, for greater concurrency.
1130
        finally:
2939.1.1 by Martin Pool
Fix up mismatched lock/unlock pairs.
1131
            r1.unlock()
2592.3.188 by Robert Collins
Allow pack repositories to have multiple writers active at one time, for greater concurrency.
1132
1133
    def test_lock_write_does_not_physically_lock(self):
1134
        repo = self.make_repository('.', format=self.get_format())
1135
        repo.lock_write()
1136
        self.addCleanup(repo.unlock)
1137
        self.assertFalse(repo.get_physical_lock_status())
1138
1139
    def prepare_for_break_lock(self):
2592.3.219 by Robert Collins
Review feedback.
1140
        # Setup the global ui factory state so that a break-lock method call
1141
        # will find usable input in the input stream.
2592.3.188 by Robert Collins
Allow pack repositories to have multiple writers active at one time, for greater concurrency.
1142
        old_factory = bzrlib.ui.ui_factory
1143
        def restoreFactory():
1144
            bzrlib.ui.ui_factory = old_factory
1145
        self.addCleanup(restoreFactory)
1146
        bzrlib.ui.ui_factory = bzrlib.ui.SilentUIFactory()
1147
        bzrlib.ui.ui_factory.stdin = StringIO("y\n")
1148
1149
    def test_break_lock_breaks_physical_lock(self):
1150
        repo = self.make_repository('.', format=self.get_format())
2592.3.232 by Martin Pool
Disambiguate two member variables called _packs into _packs_by_name and _pack_collection
1151
        repo._pack_collection.lock_names()
2592.3.188 by Robert Collins
Allow pack repositories to have multiple writers active at one time, for greater concurrency.
1152
        repo2 = repository.Repository.open('.')
1153
        self.assertTrue(repo.get_physical_lock_status())
1154
        self.prepare_for_break_lock()
1155
        repo2.break_lock()
1156
        self.assertFalse(repo.get_physical_lock_status())
1157
2592.3.240 by Martin Pool
Rename RepositoryPackCollection.release_names to _unlock_names
1158
    def test_broken_physical_locks_error_on__unlock_names_lock(self):
2592.3.188 by Robert Collins
Allow pack repositories to have multiple writers active at one time, for greater concurrency.
1159
        repo = self.make_repository('.', format=self.get_format())
2592.3.232 by Martin Pool
Disambiguate two member variables called _packs into _packs_by_name and _pack_collection
1160
        repo._pack_collection.lock_names()
2592.3.188 by Robert Collins
Allow pack repositories to have multiple writers active at one time, for greater concurrency.
1161
        self.assertTrue(repo.get_physical_lock_status())
1162
        repo2 = repository.Repository.open('.')
1163
        self.prepare_for_break_lock()
1164
        repo2.break_lock()
2592.3.240 by Martin Pool
Rename RepositoryPackCollection.release_names to _unlock_names
1165
        self.assertRaises(errors.LockBroken, repo._pack_collection._unlock_names)
2592.3.188 by Robert Collins
Allow pack repositories to have multiple writers active at one time, for greater concurrency.
1166
2949.1.2 by Robert Collins
* Fetch with pack repositories will no longer read the entire history graph.
1167
    def test_fetch_without_find_ghosts_ignores_ghosts(self):
1168
        # we want two repositories at this point:
1169
        # one with a revision that is a ghost in the other
1170
        # repository.
1171
        # 'ghost' is present in has_ghost, 'ghost' is absent in 'missing_ghost'.
1172
        # 'references' is present in both repositories, and 'tip' is present
1173
        # just in has_ghost.
1174
        # has_ghost       missing_ghost
1175
        #------------------------------
1176
        # 'ghost'             -
1177
        # 'references'    'references'
1178
        # 'tip'               -
1179
        # In this test we fetch 'tip' which should not fetch 'ghost'
1180
        has_ghost = self.make_repository('has_ghost', format=self.get_format())
1181
        missing_ghost = self.make_repository('missing_ghost',
1182
            format=self.get_format())
1183
1184
        def add_commit(repo, revision_id, parent_ids):
1185
            repo.lock_write()
1186
            repo.start_write_group()
1187
            inv = inventory.Inventory(revision_id=revision_id)
1188
            inv.root.revision = revision_id
1189
            root_id = inv.root.file_id
1190
            sha1 = repo.add_inventory(revision_id, inv, [])
1191
            vf = repo.weave_store.get_weave_or_empty(root_id,
1192
                repo.get_transaction())
1193
            vf.add_lines(revision_id, [], [])
1194
            rev = bzrlib.revision.Revision(timestamp=0,
1195
                                           timezone=None,
1196
                                           committer="Foo Bar <foo@example.com>",
1197
                                           message="Message",
1198
                                           inventory_sha1=sha1,
1199
                                           revision_id=revision_id)
1200
            rev.parent_ids = parent_ids
1201
            repo.add_revision(revision_id, rev)
1202
            repo.commit_write_group()
1203
            repo.unlock()
1204
        add_commit(has_ghost, 'ghost', [])
1205
        add_commit(has_ghost, 'references', ['ghost'])
1206
        add_commit(missing_ghost, 'references', ['ghost'])
1207
        add_commit(has_ghost, 'tip', ['references'])
1208
        missing_ghost.fetch(has_ghost, 'tip')
1209
        # missing ghost now has tip and not ghost.
1210
        rev = missing_ghost.get_revision('tip')
1211
        inv = missing_ghost.get_inventory('tip')
1212
        self.assertRaises(errors.NoSuchRevision,
1213
            missing_ghost.get_revision, 'ghost')
1214
        self.assertRaises(errors.RevisionNotPresent,
1215
            missing_ghost.get_inventory, 'ghost')
1216
3221.3.1 by Robert Collins
* Repository formats have a new supported-feature attribute
1217
    def test_supports_external_lookups(self):
1218
        repo = self.make_repository('.', format=self.get_format())
1219
        self.assertFalse(repo._format.supports_external_lookups)
1220
2592.3.188 by Robert Collins
Allow pack repositories to have multiple writers active at one time, for greater concurrency.
1221
2939.2.1 by Ian Clatworthy
use 'knitpack' naming instead of 'experimental' for pack formats
1222
class TestKnitPackSubtrees(TestKnitPackNoSubtrees):
2592.3.173 by Robert Collins
Basic implementation of all_packs.
1223
1224
    def get_format(self):
2939.2.5 by Ian Clatworthy
review feedback from lifeless
1225
        return bzrdir.format_registry.make_bzrdir(
3010.3.3 by Martin Pool
Merge trunk
1226
            'pack-0.92-subtree')
2592.3.173 by Robert Collins
Basic implementation of all_packs.
1227
1228
    def check_format(self, t):
2939.2.5 by Ian Clatworthy
review feedback from lifeless
1229
        self.assertEqualDiff(
2939.2.7 by Ian Clatworthy
fix strings used in on-disk unit tests
1230
            "Bazaar pack repository format 1 with subtree support (needs bzr 0.92)\n",
2939.2.5 by Ian Clatworthy
review feedback from lifeless
1231
            t.get('format').read())
2592.3.173 by Robert Collins
Basic implementation of all_packs.
1232
1233
3152.2.1 by Robert Collins
* A new repository format 'development' has been added. This format will
1234
class TestDevelopment0(TestKnitPackNoSubtrees):
1235
1236
    def get_format(self):
1237
        return bzrdir.format_registry.make_bzrdir(
1238
            'development')
1239
1240
    def check_format(self, t):
1241
        self.assertEqualDiff(
3152.2.3 by Robert Collins
Merge up with bzr.dev.
1242
            "Bazaar development format 0 (needs bzr.dev from before 1.3)\n",
3152.2.1 by Robert Collins
* A new repository format 'development' has been added. This format will
1243
            t.get('format').read())
1244
1245
1246
class TestDevelopment0Subtree(TestKnitPackNoSubtrees):
1247
1248
    def get_format(self):
1249
        return bzrdir.format_registry.make_bzrdir(
1250
            'development-subtree')
1251
1252
    def check_format(self, t):
1253
        self.assertEqualDiff(
1254
            "Bazaar development format 0 with subtree support "
3152.2.3 by Robert Collins
Merge up with bzr.dev.
1255
            "(needs bzr.dev from before 1.3)\n",
3152.2.1 by Robert Collins
* A new repository format 'development' has been added. This format will
1256
            t.get('format').read())
1257
1258
2592.3.84 by Robert Collins
Start of autopacking logic.
1259
class TestRepositoryPackCollection(TestCaseWithTransport):
1260
1261
    def get_format(self):
3010.3.3 by Martin Pool
Merge trunk
1262
        return bzrdir.format_registry.make_bzrdir('pack-0.92')
2592.3.84 by Robert Collins
Start of autopacking logic.
1263
1264
    def test__max_pack_count(self):
2592.3.219 by Robert Collins
Review feedback.
1265
        """The maximum pack count is a function of the number of revisions."""
2592.3.84 by Robert Collins
Start of autopacking logic.
1266
        format = self.get_format()
1267
        repo = self.make_repository('.', format=format)
2592.3.232 by Martin Pool
Disambiguate two member variables called _packs into _packs_by_name and _pack_collection
1268
        packs = repo._pack_collection
2592.3.84 by Robert Collins
Start of autopacking logic.
1269
        # no revisions - one pack, so that we can have a revision free repo
1270
        # without it blowing up
1271
        self.assertEqual(1, packs._max_pack_count(0))
1272
        # after that the sum of the digits, - check the first 1-9
1273
        self.assertEqual(1, packs._max_pack_count(1))
1274
        self.assertEqual(2, packs._max_pack_count(2))
1275
        self.assertEqual(3, packs._max_pack_count(3))
1276
        self.assertEqual(4, packs._max_pack_count(4))
1277
        self.assertEqual(5, packs._max_pack_count(5))
1278
        self.assertEqual(6, packs._max_pack_count(6))
1279
        self.assertEqual(7, packs._max_pack_count(7))
1280
        self.assertEqual(8, packs._max_pack_count(8))
1281
        self.assertEqual(9, packs._max_pack_count(9))
1282
        # check the boundary cases with two digits for the next decade
1283
        self.assertEqual(1, packs._max_pack_count(10))
1284
        self.assertEqual(2, packs._max_pack_count(11))
1285
        self.assertEqual(10, packs._max_pack_count(19))
1286
        self.assertEqual(2, packs._max_pack_count(20))
1287
        self.assertEqual(3, packs._max_pack_count(21))
1288
        # check some arbitrary big numbers
1289
        self.assertEqual(25, packs._max_pack_count(112894))
1290
1291
    def test_pack_distribution_zero(self):
1292
        format = self.get_format()
1293
        repo = self.make_repository('.', format=format)
2592.3.232 by Martin Pool
Disambiguate two member variables called _packs into _packs_by_name and _pack_collection
1294
        packs = repo._pack_collection
2592.3.84 by Robert Collins
Start of autopacking logic.
1295
        self.assertEqual([0], packs.pack_distribution(0))
3052.1.6 by John Arbash Meinel
Change the lock check to raise ObjectNotLocked.
1296
1297
    def test_ensure_loaded_unlocked(self):
1298
        format = self.get_format()
1299
        repo = self.make_repository('.', format=format)
1300
        self.assertRaises(errors.ObjectNotLocked,
1301
                          repo._pack_collection.ensure_loaded)
1302
2592.3.84 by Robert Collins
Start of autopacking logic.
1303
    def test_pack_distribution_one_to_nine(self):
1304
        format = self.get_format()
1305
        repo = self.make_repository('.', format=format)
2592.3.232 by Martin Pool
Disambiguate two member variables called _packs into _packs_by_name and _pack_collection
1306
        packs = repo._pack_collection
2592.3.84 by Robert Collins
Start of autopacking logic.
1307
        self.assertEqual([1],
1308
            packs.pack_distribution(1))
1309
        self.assertEqual([1, 1],
1310
            packs.pack_distribution(2))
1311
        self.assertEqual([1, 1, 1],
1312
            packs.pack_distribution(3))
1313
        self.assertEqual([1, 1, 1, 1],
1314
            packs.pack_distribution(4))
1315
        self.assertEqual([1, 1, 1, 1, 1],
1316
            packs.pack_distribution(5))
1317
        self.assertEqual([1, 1, 1, 1, 1, 1],
1318
            packs.pack_distribution(6))
1319
        self.assertEqual([1, 1, 1, 1, 1, 1, 1],
1320
            packs.pack_distribution(7))
1321
        self.assertEqual([1, 1, 1, 1, 1, 1, 1, 1],
1322
            packs.pack_distribution(8))
1323
        self.assertEqual([1, 1, 1, 1, 1, 1, 1, 1, 1],
1324
            packs.pack_distribution(9))
1325
1326
    def test_pack_distribution_stable_at_boundaries(self):
1327
        """When there are multi-rev packs the counts are stable."""
1328
        format = self.get_format()
1329
        repo = self.make_repository('.', format=format)
2592.3.232 by Martin Pool
Disambiguate two member variables called _packs into _packs_by_name and _pack_collection
1330
        packs = repo._pack_collection
2592.3.84 by Robert Collins
Start of autopacking logic.
1331
        # in 10s:
1332
        self.assertEqual([10], packs.pack_distribution(10))
1333
        self.assertEqual([10, 1], packs.pack_distribution(11))
1334
        self.assertEqual([10, 10], packs.pack_distribution(20))
1335
        self.assertEqual([10, 10, 1], packs.pack_distribution(21))
1336
        # 100s
1337
        self.assertEqual([100], packs.pack_distribution(100))
1338
        self.assertEqual([100, 1], packs.pack_distribution(101))
1339
        self.assertEqual([100, 10, 1], packs.pack_distribution(111))
1340
        self.assertEqual([100, 100], packs.pack_distribution(200))
1341
        self.assertEqual([100, 100, 1], packs.pack_distribution(201))
1342
        self.assertEqual([100, 100, 10, 1], packs.pack_distribution(211))
1343
2592.3.85 by Robert Collins
Finish autopack corner cases.
1344
    def test_plan_pack_operations_2009_revisions_skip_all_packs(self):
1345
        format = self.get_format()
1346
        repo = self.make_repository('.', format=format)
2592.3.232 by Martin Pool
Disambiguate two member variables called _packs into _packs_by_name and _pack_collection
1347
        packs = repo._pack_collection
2592.3.85 by Robert Collins
Finish autopack corner cases.
1348
        existing_packs = [(2000, "big"), (9, "medium")]
1349
        # rev count - 2009 -> 2x1000 + 9x1
1350
        pack_operations = packs.plan_autopack_combinations(
1351
            existing_packs, [1000, 1000, 1, 1, 1, 1, 1, 1, 1, 1, 1])
1352
        self.assertEqual([], pack_operations)
1353
1354
    def test_plan_pack_operations_2010_revisions_skip_all_packs(self):
1355
        format = self.get_format()
1356
        repo = self.make_repository('.', format=format)
2592.3.232 by Martin Pool
Disambiguate two member variables called _packs into _packs_by_name and _pack_collection
1357
        packs = repo._pack_collection
2592.3.85 by Robert Collins
Finish autopack corner cases.
1358
        existing_packs = [(2000, "big"), (9, "medium"), (1, "single")]
1359
        # rev count - 2010 -> 2x1000 + 1x10
1360
        pack_operations = packs.plan_autopack_combinations(
1361
            existing_packs, [1000, 1000, 10])
1362
        self.assertEqual([], pack_operations)
1363
1364
    def test_plan_pack_operations_2010_combines_smallest_two(self):
1365
        format = self.get_format()
1366
        repo = self.make_repository('.', format=format)
2592.3.232 by Martin Pool
Disambiguate two member variables called _packs into _packs_by_name and _pack_collection
1367
        packs = repo._pack_collection
2592.3.85 by Robert Collins
Finish autopack corner cases.
1368
        existing_packs = [(1999, "big"), (9, "medium"), (1, "single2"),
1369
            (1, "single1")]
1370
        # rev count - 2010 -> 2x1000 + 1x10 (3)
1371
        pack_operations = packs.plan_autopack_combinations(
1372
            existing_packs, [1000, 1000, 10])
1373
        self.assertEqual([[2, ["single2", "single1"]], [0, []]], pack_operations)
1374
2592.3.173 by Robert Collins
Basic implementation of all_packs.
1375
    def test_all_packs_none(self):
1376
        format = self.get_format()
1377
        tree = self.make_branch_and_tree('.', format=format)
1378
        tree.lock_read()
1379
        self.addCleanup(tree.unlock)
2592.3.232 by Martin Pool
Disambiguate two member variables called _packs into _packs_by_name and _pack_collection
1380
        packs = tree.branch.repository._pack_collection
2592.3.173 by Robert Collins
Basic implementation of all_packs.
1381
        packs.ensure_loaded()
1382
        self.assertEqual([], packs.all_packs())
1383
1384
    def test_all_packs_one(self):
1385
        format = self.get_format()
1386
        tree = self.make_branch_and_tree('.', format=format)
1387
        tree.commit('start')
1388
        tree.lock_read()
1389
        self.addCleanup(tree.unlock)
2592.3.232 by Martin Pool
Disambiguate two member variables called _packs into _packs_by_name and _pack_collection
1390
        packs = tree.branch.repository._pack_collection
2592.3.173 by Robert Collins
Basic implementation of all_packs.
1391
        packs.ensure_loaded()
2592.3.176 by Robert Collins
Various pack refactorings.
1392
        self.assertEqual([
1393
            packs.get_pack_by_name(packs.names()[0])],
1394
            packs.all_packs())
2592.3.173 by Robert Collins
Basic implementation of all_packs.
1395
1396
    def test_all_packs_two(self):
1397
        format = self.get_format()
1398
        tree = self.make_branch_and_tree('.', format=format)
1399
        tree.commit('start')
1400
        tree.commit('continue')
1401
        tree.lock_read()
1402
        self.addCleanup(tree.unlock)
2592.3.232 by Martin Pool
Disambiguate two member variables called _packs into _packs_by_name and _pack_collection
1403
        packs = tree.branch.repository._pack_collection
2592.3.173 by Robert Collins
Basic implementation of all_packs.
1404
        packs.ensure_loaded()
1405
        self.assertEqual([
2592.3.176 by Robert Collins
Various pack refactorings.
1406
            packs.get_pack_by_name(packs.names()[0]),
1407
            packs.get_pack_by_name(packs.names()[1]),
2592.3.173 by Robert Collins
Basic implementation of all_packs.
1408
            ], packs.all_packs())
1409
2592.3.176 by Robert Collins
Various pack refactorings.
1410
    def test_get_pack_by_name(self):
1411
        format = self.get_format()
1412
        tree = self.make_branch_and_tree('.', format=format)
1413
        tree.commit('start')
1414
        tree.lock_read()
1415
        self.addCleanup(tree.unlock)
2592.3.232 by Martin Pool
Disambiguate two member variables called _packs into _packs_by_name and _pack_collection
1416
        packs = tree.branch.repository._pack_collection
2592.3.176 by Robert Collins
Various pack refactorings.
1417
        packs.ensure_loaded()
1418
        name = packs.names()[0]
1419
        pack_1 = packs.get_pack_by_name(name)
1420
        # the pack should be correctly initialised
1421
        rev_index = GraphIndex(packs._index_transport, name + '.rix',
1422
            packs._names[name][0])
1423
        inv_index = GraphIndex(packs._index_transport, name + '.iix',
1424
            packs._names[name][1])
1425
        txt_index = GraphIndex(packs._index_transport, name + '.tix',
1426
            packs._names[name][2])
1427
        sig_index = GraphIndex(packs._index_transport, name + '.six',
1428
            packs._names[name][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.
1429
        self.assertEqual(pack_repo.ExistingPack(packs._pack_transport,
2592.3.219 by Robert Collins
Review feedback.
1430
            name, rev_index, inv_index, txt_index, sig_index), pack_1)
2592.3.176 by Robert Collins
Various pack refactorings.
1431
        # and the same instance should be returned on successive calls.
1432
        self.assertTrue(pack_1 is packs.get_pack_by_name(name))
1433
2592.3.173 by Robert Collins
Basic implementation of all_packs.
1434
1435
class TestPack(TestCaseWithTransport):
1436
    """Tests for the Pack object."""
1437
1438
    def assertCurrentlyEqual(self, left, right):
1439
        self.assertTrue(left == right)
1440
        self.assertTrue(right == left)
1441
        self.assertFalse(left != right)
1442
        self.assertFalse(right != left)
1443
1444
    def assertCurrentlyNotEqual(self, left, right):
1445
        self.assertFalse(left == right)
1446
        self.assertFalse(right == left)
1447
        self.assertTrue(left != right)
1448
        self.assertTrue(right != left)
1449
1450
    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.
1451
        left = pack_repo.ExistingPack('', '', '', '', '', '')
1452
        right = pack_repo.ExistingPack('', '', '', '', '', '')
2592.3.173 by Robert Collins
Basic implementation of all_packs.
1453
        self.assertCurrentlyEqual(left, right)
1454
        # change all attributes and ensure equality changes as we do.
1455
        left.revision_index = 'a'
1456
        self.assertCurrentlyNotEqual(left, right)
1457
        right.revision_index = 'a'
1458
        self.assertCurrentlyEqual(left, right)
1459
        left.inventory_index = 'a'
1460
        self.assertCurrentlyNotEqual(left, right)
1461
        right.inventory_index = 'a'
1462
        self.assertCurrentlyEqual(left, right)
1463
        left.text_index = 'a'
1464
        self.assertCurrentlyNotEqual(left, right)
1465
        right.text_index = 'a'
1466
        self.assertCurrentlyEqual(left, right)
1467
        left.signature_index = 'a'
1468
        self.assertCurrentlyNotEqual(left, right)
1469
        right.signature_index = 'a'
1470
        self.assertCurrentlyEqual(left, right)
1471
        left.name = 'a'
1472
        self.assertCurrentlyNotEqual(left, right)
1473
        right.name = 'a'
1474
        self.assertCurrentlyEqual(left, right)
1475
        left.transport = 'a'
1476
        self.assertCurrentlyNotEqual(left, right)
1477
        right.transport = 'a'
1478
        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.
1479
1480
    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.
1481
        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.
1482
        self.assertEqual('a_name.pack', pack.file_name())
2592.3.192 by Robert Collins
Move new revision index management to NewPack.
1483
1484
1485
class TestNewPack(TestCaseWithTransport):
1486
    """Tests for pack_repo.NewPack."""
1487
2592.3.193 by Robert Collins
Move hash tracking of new packs into NewPack.
1488
    def test_new_instance_attributes(self):
2592.3.194 by Robert Collins
Output the revision index from NewPack.finish
1489
        upload_transport = self.get_transport('upload')
1490
        pack_transport = self.get_transport('pack')
1491
        index_transport = self.get_transport('index')
1492
        upload_transport.mkdir('.')
1493
        pack = pack_repo.NewPack(upload_transport, index_transport,
1494
            pack_transport)
2592.3.192 by Robert Collins
Move new revision index management to NewPack.
1495
        self.assertIsInstance(pack.revision_index, InMemoryGraphIndex)
2592.3.195 by Robert Collins
Move some inventory index logic to NewPack.
1496
        self.assertIsInstance(pack.inventory_index, InMemoryGraphIndex)
2592.3.193 by Robert Collins
Move hash tracking of new packs into NewPack.
1497
        self.assertIsInstance(pack._hash, type(md5.new()))
2592.3.194 by Robert Collins
Output the revision index from NewPack.finish
1498
        self.assertTrue(pack.upload_transport is upload_transport)
1499
        self.assertTrue(pack.index_transport is index_transport)
1500
        self.assertTrue(pack.pack_transport is pack_transport)
1501
        self.assertEqual(None, pack.index_sizes)
1502
        self.assertEqual(20, len(pack.random_name))
1503
        self.assertIsInstance(pack.random_name, str)
1504
        self.assertIsInstance(pack.start_time, float)
2951.1.2 by Robert Collins
Partial refactoring of pack_repo to create a Packer object for packing.
1505
1506
1507
class TestPacker(TestCaseWithTransport):
1508
    """Tests for the packs repository Packer class."""
2951.1.10 by Robert Collins
Peer review feedback with Ian.
1509
1510
    # To date, this class has been factored out and nothing new added to it;
1511
    # thus there are not yet any tests.
3146.6.1 by Aaron Bentley
InterDifferingSerializer shows a progress bar
1512
1513
1514
class TestInterDifferingSerializer(TestCaseWithTransport):
1515
1516
    def test_progress_bar(self):
1517
        tree = self.make_branch_and_tree('tree')
1518
        tree.commit('rev1', rev_id='rev-1')
1519
        tree.commit('rev2', rev_id='rev-2')
1520
        tree.commit('rev3', rev_id='rev-3')
1521
        repo = self.make_repository('repo')
1522
        inter_repo = repository.InterDifferingSerializer(
1523
            tree.branch.repository, repo)
1524
        pb = progress.InstrumentedProgress(to_file=StringIO())
1525
        pb.never_throttle = True
1526
        inter_repo.fetch('rev-1', pb)
1527
        self.assertEqual('Transferring revisions', pb.last_msg)
1528
        self.assertEqual(1, pb.last_cnt)
1529
        self.assertEqual(1, pb.last_total)
1530
        inter_repo.fetch('rev-3', pb)
1531
        self.assertEqual(2, pb.last_cnt)
1532
        self.assertEqual(2, pb.last_total)