~bzr-pqm/bzr/bzr.dev

« back to all changes in this revision

Viewing changes to bzrlib/tests/test_branch.py

  • Committer: Ian Clatworthy
  • Date: 2007-12-07 04:21:59 UTC
  • mto: This revision was merged to the branch mainline in revision 3092.
  • Revision ID: ian.clatworthy@internode.on.net-20071207042159-n9rmhanqid1l7olh
Better PDF for Qiock Start Card (Ian Clatworthy)

Show diffs side-by-side

added added

removed removed

Lines of Context:
12
12
#
13
13
# You should have received a copy of the GNU General Public License
14
14
# along with this program; if not, write to the Free Software
15
 
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
 
15
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
16
16
 
17
17
"""Tests for the Branch facility that are not interface  tests.
18
18
 
19
 
For interface tests see tests/per_branch/*.py.
 
19
For interface tests see tests/branch_implementations/*.py.
20
20
 
21
21
For concrete class tests see this file, and for meta-branch tests
22
22
also see this file.
40
40
    BzrBranch5,
41
41
    BzrBranchFormat5,
42
42
    BzrBranchFormat6,
43
 
    BzrBranchFormat7,
44
43
    PullResult,
45
 
    _run_with_write_locked_target,
46
44
    )
47
 
from bzrlib.bzrdir import (BzrDirMetaFormat1, BzrDirMeta1,
 
45
from bzrlib.bzrdir import (BzrDirMetaFormat1, BzrDirMeta1, 
48
46
                           BzrDir, BzrDirFormat)
49
47
from bzrlib.errors import (NotBranchError,
50
48
                           UnknownFormatError,
55
53
from bzrlib.tests import TestCase, TestCaseWithTransport
56
54
from bzrlib.transport import get_transport
57
55
 
58
 
 
59
56
class TestDefaultFormat(TestCase):
60
57
 
61
58
    def test_default_format(self):
62
59
        # update this if you change the default branch format
63
60
        self.assertIsInstance(BranchFormat.get_default_format(),
64
 
                BzrBranchFormat7)
 
61
                BzrBranchFormat6)
65
62
 
66
63
    def test_default_format_is_same_as_bzrdir_default(self):
67
64
        # XXX: it might be nice if there was only one place the default was
68
 
        # set, but at the moment that's not true -- mbp 20070814 --
 
65
        # set, but at the moment that's not true -- mbp 20070814 -- 
69
66
        # https://bugs.launchpad.net/bzr/+bug/132376
70
67
        self.assertEqual(BranchFormat.get_default_format(),
71
68
                BzrDirFormat.get_default_format().get_branch_format())
125
122
        self.assertFileEqual("# comment\n"
126
123
                             "[%s]\n"
127
124
                             "push_location = foo\n"
128
 
                             "push_location:policy = norecurse\n" % local_path,
 
125
                             "push_location:policy = norecurse" % local_path,
129
126
                             fn)
130
127
 
131
128
    # TODO RBC 20051029 test getting a push location from a branch in a
135
132
class SampleBranchFormat(BranchFormat):
136
133
    """A sample format
137
134
 
138
 
    this format is initializable, unsupported to aid in testing the
 
135
    this format is initializable, unsupported to aid in testing the 
139
136
    open and open_downlevel routines.
140
137
    """
141
138
 
152
149
    def is_supported(self):
153
150
        return False
154
151
 
155
 
    def open(self, transport, _found=False, ignore_fallbacks=False):
 
152
    def open(self, transport, _found=False):
156
153
        return "opened branch."
157
154
 
158
155
 
162
159
    def test_find_format(self):
163
160
        # is the right format object found for a branch?
164
161
        # create a branch with a few known format objects.
165
 
        # this is not quite the same as
 
162
        # this is not quite the same as 
166
163
        self.build_tree(["foo/", "bar/"])
167
164
        def check_format(format, url):
168
165
            dir = format._matchingbzrdir.initialize(url)
171
168
            found_format = BranchFormat.find_format(dir)
172
169
            self.failUnless(isinstance(found_format, format.__class__))
173
170
        check_format(BzrBranchFormat5(), "bar")
174
 
 
 
171
        
175
172
    def test_find_format_not_branch(self):
176
173
        dir = bzrdir.BzrDirMetaFormat1().initialize(self.get_url())
177
174
        self.assertRaises(NotBranchError,
203
200
        self.make_branch_and_tree('bar')
204
201
 
205
202
 
206
 
class TestBranch67(object):
207
 
    """Common tests for both branch 6 and 7 which are mostly the same."""
208
 
 
209
 
    def get_format_name(self):
210
 
        raise NotImplementedError(self.get_format_name)
211
 
 
212
 
    def get_format_name_subtree(self):
213
 
        raise NotImplementedError(self.get_format_name)
214
 
 
215
 
    def get_class(self):
216
 
        raise NotImplementedError(self.get_class)
 
203
class TestBranch6(TestCaseWithTransport):
217
204
 
218
205
    def test_creation(self):
219
206
        format = BzrDirMetaFormat1()
220
207
        format.set_branch_format(_mod_branch.BzrBranchFormat6())
221
208
        branch = self.make_branch('a', format=format)
222
 
        self.assertIsInstance(branch, self.get_class())
223
 
        branch = self.make_branch('b', format=self.get_format_name())
224
 
        self.assertIsInstance(branch, self.get_class())
 
209
        self.assertIsInstance(branch, _mod_branch.BzrBranch6)
 
210
        branch = self.make_branch('b', format='dirstate-tags')
 
211
        self.assertIsInstance(branch, _mod_branch.BzrBranch6)
225
212
        branch = _mod_branch.Branch.open('a')
226
 
        self.assertIsInstance(branch, self.get_class())
 
213
        self.assertIsInstance(branch, _mod_branch.BzrBranch6)
227
214
 
228
215
    def test_layout(self):
229
 
        branch = self.make_branch('a', format=self.get_format_name())
 
216
        branch = self.make_branch('a', format='dirstate-tags')
230
217
        self.failUnlessExists('a/.bzr/branch/last-revision')
231
218
        self.failIfExists('a/.bzr/branch/revision-history')
232
 
        self.failIfExists('a/.bzr/branch/references')
233
219
 
234
220
    def test_config(self):
235
221
        """Ensure that all configuration data is stored in the branch"""
236
 
        branch = self.make_branch('a', format=self.get_format_name())
 
222
        branch = self.make_branch('a', format='dirstate-tags')
237
223
        branch.set_parent('http://bazaar-vcs.org')
238
224
        self.failIfExists('a/.bzr/branch/parent')
239
225
        self.assertEqual('http://bazaar-vcs.org', branch.get_parent())
246
232
        self.assertEqual('ftp://bazaar-vcs.org', branch.get_bound_location())
247
233
 
248
234
    def test_set_revision_history(self):
249
 
        builder = self.make_branch_builder('.', format=self.get_format_name())
250
 
        builder.build_snapshot('foo', None,
251
 
            [('add', ('', None, 'directory', None))],
252
 
            message='foo')
253
 
        builder.build_snapshot('bar', None, [], message='bar')
254
 
        branch = builder.get_branch()
255
 
        branch.lock_write()
256
 
        self.addCleanup(branch.unlock)
257
 
        branch.set_revision_history(['foo', 'bar'])
258
 
        branch.set_revision_history(['foo'])
259
 
        self.assertRaises(errors.NotLefthandHistory,
260
 
                          branch.set_revision_history, ['bar'])
 
235
        tree = self.make_branch_and_memory_tree('.',
 
236
            format='dirstate-tags')
 
237
        tree.lock_write()
 
238
        try:
 
239
            tree.add('.')
 
240
            tree.commit('foo', rev_id='foo')
 
241
            tree.commit('bar', rev_id='bar')
 
242
            tree.branch.set_revision_history(['foo', 'bar'])
 
243
            tree.branch.set_revision_history(['foo'])
 
244
            self.assertRaises(errors.NotLefthandHistory,
 
245
                              tree.branch.set_revision_history, ['bar'])
 
246
        finally:
 
247
            tree.unlock()
261
248
 
262
249
    def do_checkout_test(self, lightweight=False):
263
 
        tree = self.make_branch_and_tree('source',
264
 
            format=self.get_format_name_subtree())
 
250
        tree = self.make_branch_and_tree('source', format='dirstate-with-subtree')
265
251
        subtree = self.make_branch_and_tree('source/subtree',
266
 
            format=self.get_format_name_subtree())
 
252
            format='dirstate-with-subtree')
267
253
        subsubtree = self.make_branch_and_tree('source/subtree/subsubtree',
268
 
            format=self.get_format_name_subtree())
 
254
            format='dirstate-with-subtree')
269
255
        self.build_tree(['source/subtree/file',
270
256
                         'source/subtree/subsubtree/file'])
271
257
        subsubtree.add('file')
293
279
        self.do_checkout_test(lightweight=True)
294
280
 
295
281
    def test_set_push(self):
296
 
        branch = self.make_branch('source', format=self.get_format_name())
 
282
        branch = self.make_branch('source', format='dirstate-tags')
297
283
        branch.get_config().set_user_option('push_location', 'old',
298
284
            store=config.STORE_LOCATION)
299
285
        warnings = []
308
294
        self.assertEqual(warnings[0], 'Value "new" is masked by "old" from '
309
295
                         'locations.conf')
310
296
 
311
 
 
312
 
class TestBranch6(TestBranch67, TestCaseWithTransport):
313
 
 
314
 
    def get_class(self):
315
 
        return _mod_branch.BzrBranch6
316
 
 
317
 
    def get_format_name(self):
318
 
        return "dirstate-tags"
319
 
 
320
 
    def get_format_name_subtree(self):
321
 
        return "dirstate-with-subtree"
322
 
 
323
 
    def test_set_stacked_on_url_errors(self):
324
 
        branch = self.make_branch('a', format=self.get_format_name())
325
 
        self.assertRaises(errors.UnstackableBranchFormat,
326
 
            branch.set_stacked_on_url, None)
327
 
 
328
 
    def test_default_stacked_location(self):
329
 
        branch = self.make_branch('a', format=self.get_format_name())
330
 
        self.assertRaises(errors.UnstackableBranchFormat, branch.get_stacked_on_url)
331
 
 
332
 
 
333
 
class TestBranch7(TestBranch67, TestCaseWithTransport):
334
 
 
335
 
    def get_class(self):
336
 
        return _mod_branch.BzrBranch7
337
 
 
338
 
    def get_format_name(self):
339
 
        return "1.9"
340
 
 
341
 
    def get_format_name_subtree(self):
342
 
        return "development-subtree"
343
 
 
344
 
    def test_set_stacked_on_url_unstackable_repo(self):
345
 
        repo = self.make_repository('a', format='dirstate-tags')
346
 
        control = repo.bzrdir
347
 
        branch = _mod_branch.BzrBranchFormat7().initialize(control)
348
 
        target = self.make_branch('b')
349
 
        self.assertRaises(errors.UnstackableRepositoryFormat,
350
 
            branch.set_stacked_on_url, target.base)
351
 
 
352
 
    def test_clone_stacked_on_unstackable_repo(self):
353
 
        repo = self.make_repository('a', format='dirstate-tags')
354
 
        control = repo.bzrdir
355
 
        branch = _mod_branch.BzrBranchFormat7().initialize(control)
356
 
        # Calling clone should not raise UnstackableRepositoryFormat.
357
 
        cloned_bzrdir = control.clone('cloned')
358
 
 
359
 
    def _test_default_stacked_location(self):
360
 
        branch = self.make_branch('a', format=self.get_format_name())
361
 
        self.assertRaises(errors.NotStacked, branch.get_stacked_on_url)
362
 
 
363
 
    def test_stack_and_unstack(self):
364
 
        branch = self.make_branch('a', format=self.get_format_name())
365
 
        target = self.make_branch_and_tree('b', format=self.get_format_name())
366
 
        branch.set_stacked_on_url(target.branch.base)
367
 
        self.assertEqual(target.branch.base, branch.get_stacked_on_url())
368
 
        revid = target.commit('foo')
369
 
        self.assertTrue(branch.repository.has_revision(revid))
370
 
        branch.set_stacked_on_url(None)
371
 
        self.assertRaises(errors.NotStacked, branch.get_stacked_on_url)
372
 
        self.assertFalse(branch.repository.has_revision(revid))
373
 
 
374
 
    def test_open_opens_stacked_reference(self):
375
 
        branch = self.make_branch('a', format=self.get_format_name())
376
 
        target = self.make_branch_and_tree('b', format=self.get_format_name())
377
 
        branch.set_stacked_on_url(target.branch.base)
378
 
        branch = branch.bzrdir.open_branch()
379
 
        revid = target.commit('foo')
380
 
        self.assertTrue(branch.repository.has_revision(revid))
381
 
 
382
 
 
383
 
class BzrBranch8(TestCaseWithTransport):
384
 
 
385
 
    def make_branch(self, location, format=None):
386
 
        if format is None:
387
 
            format = bzrdir.format_registry.make_bzrdir('1.9')
388
 
            format.set_branch_format(_mod_branch.BzrBranchFormat8())
389
 
        return TestCaseWithTransport.make_branch(self, location, format=format)
390
 
 
391
 
    def create_branch_with_reference(self):
392
 
        branch = self.make_branch('branch')
393
 
        branch._set_all_reference_info({'file-id': ('path', 'location')})
394
 
        return branch
395
 
 
396
 
    @staticmethod
397
 
    def instrument_branch(branch, gets):
398
 
        old_get = branch._transport.get
399
 
        def get(*args, **kwargs):
400
 
            gets.append((args, kwargs))
401
 
            return old_get(*args, **kwargs)
402
 
        branch._transport.get = get
403
 
 
404
 
    def test_reference_info_caching_read_locked(self):
405
 
        gets = []
406
 
        branch = self.create_branch_with_reference()
407
 
        branch.lock_read()
408
 
        self.addCleanup(branch.unlock)
409
 
        self.instrument_branch(branch, gets)
410
 
        branch.get_reference_info('file-id')
411
 
        branch.get_reference_info('file-id')
412
 
        self.assertEqual(1, len(gets))
413
 
 
414
 
    def test_reference_info_caching_read_unlocked(self):
415
 
        gets = []
416
 
        branch = self.create_branch_with_reference()
417
 
        self.instrument_branch(branch, gets)
418
 
        branch.get_reference_info('file-id')
419
 
        branch.get_reference_info('file-id')
420
 
        self.assertEqual(2, len(gets))
421
 
 
422
 
    def test_reference_info_caching_write_locked(self):
423
 
        gets = []
424
 
        branch = self.make_branch('branch')
425
 
        branch.lock_write()
426
 
        self.instrument_branch(branch, gets)
427
 
        self.addCleanup(branch.unlock)
428
 
        branch._set_all_reference_info({'file-id': ('path2', 'location2')})
429
 
        path, location = branch.get_reference_info('file-id')
430
 
        self.assertEqual(0, len(gets))
431
 
        self.assertEqual('path2', path)
432
 
        self.assertEqual('location2', location)
433
 
 
434
 
    def test_reference_info_caches_cleared(self):
435
 
        branch = self.make_branch('branch')
436
 
        branch.lock_write()
437
 
        branch.set_reference_info('file-id', 'path2', 'location2')
438
 
        branch.unlock()
439
 
        doppelganger = Branch.open('branch')
440
 
        doppelganger.set_reference_info('file-id', 'path3', 'location3')
441
 
        self.assertEqual(('path3', 'location3'),
442
 
                         branch.get_reference_info('file-id'))
443
 
 
444
297
class TestBranchReference(TestCaseWithTransport):
445
298
    """Tests for the branch reference facility."""
446
299
 
481
334
        self.assertTrue("pre_commit" in hooks, "pre_commit not in %s" % hooks)
482
335
        self.assertTrue("post_pull" in hooks, "post_pull not in %s" % hooks)
483
336
        self.assertTrue("post_uncommit" in hooks, "post_uncommit not in %s" % hooks)
484
 
        self.assertTrue("post_change_branch_tip" in hooks,
485
 
                        "post_change_branch_tip not in %s" % hooks)
486
337
 
487
338
    def test_installed_hooks_are_BranchHooks(self):
488
339
        """The installed hooks object should be a BranchHooks."""
489
340
        # the installed hooks are saved in self._preserved_hooks.
490
 
        self.assertIsInstance(self._preserved_hooks[_mod_branch.Branch][1],
491
 
            BranchHooks)
 
341
        self.assertIsInstance(self._preserved_hooks[_mod_branch.Branch], BranchHooks)
492
342
 
493
343
 
494
344
class TestPullResult(TestCase):
503
353
        # it's still supported
504
354
        a = "%d revisions pulled" % r
505
355
        self.assertEqual(a, "10 revisions pulled")
506
 
 
507
 
 
508
 
 
509
 
class _StubLockable(object):
510
 
    """Helper for TestRunWithWriteLockedTarget."""
511
 
 
512
 
    def __init__(self, calls, unlock_exc=None):
513
 
        self.calls = calls
514
 
        self.unlock_exc = unlock_exc
515
 
 
516
 
    def lock_write(self):
517
 
        self.calls.append('lock_write')
518
 
 
519
 
    def unlock(self):
520
 
        self.calls.append('unlock')
521
 
        if self.unlock_exc is not None:
522
 
            raise self.unlock_exc
523
 
 
524
 
 
525
 
class _ErrorFromCallable(Exception):
526
 
    """Helper for TestRunWithWriteLockedTarget."""
527
 
 
528
 
 
529
 
class _ErrorFromUnlock(Exception):
530
 
    """Helper for TestRunWithWriteLockedTarget."""
531
 
 
532
 
 
533
 
class TestRunWithWriteLockedTarget(TestCase):
534
 
    """Tests for _run_with_write_locked_target."""
535
 
 
536
 
    def setUp(self):
537
 
        TestCase.setUp(self)
538
 
        self._calls = []
539
 
 
540
 
    def func_that_returns_ok(self):
541
 
        self._calls.append('func called')
542
 
        return 'ok'
543
 
 
544
 
    def func_that_raises(self):
545
 
        self._calls.append('func called')
546
 
        raise _ErrorFromCallable()
547
 
 
548
 
    def test_success_unlocks(self):
549
 
        lockable = _StubLockable(self._calls)
550
 
        result = _run_with_write_locked_target(
551
 
            lockable, self.func_that_returns_ok)
552
 
        self.assertEqual('ok', result)
553
 
        self.assertEqual(['lock_write', 'func called', 'unlock'], self._calls)
554
 
 
555
 
    def test_exception_unlocks_and_propagates(self):
556
 
        lockable = _StubLockable(self._calls)
557
 
        self.assertRaises(_ErrorFromCallable,
558
 
            _run_with_write_locked_target, lockable, self.func_that_raises)
559
 
        self.assertEqual(['lock_write', 'func called', 'unlock'], self._calls)
560
 
 
561
 
    def test_callable_succeeds_but_error_during_unlock(self):
562
 
        lockable = _StubLockable(self._calls, unlock_exc=_ErrorFromUnlock())
563
 
        self.assertRaises(_ErrorFromUnlock,
564
 
            _run_with_write_locked_target, lockable, self.func_that_returns_ok)
565
 
        self.assertEqual(['lock_write', 'func called', 'unlock'], self._calls)
566
 
 
567
 
    def test_error_during_unlock_does_not_mask_original_error(self):
568
 
        lockable = _StubLockable(self._calls, unlock_exc=_ErrorFromUnlock())
569
 
        self.assertRaises(_ErrorFromCallable,
570
 
            _run_with_write_locked_target, lockable, self.func_that_raises)
571
 
        self.assertEqual(['lock_write', 'func called', 'unlock'], self._calls)
572
 
 
573