~bzr-pqm/bzr/bzr.dev

« back to all changes in this revision

Viewing changes to bzrlib/tests/test_commit.py

  • Committer: Canonical.com Patch Queue Manager
  • Date: 2006-08-17 13:49:05 UTC
  • mfrom: (1711.2.129 jam-integration)
  • Revision ID: pqm@pqm.ubuntu.com-20060817134905-0dec610d2fcd6663
(bialix) 'make html-docs' produces html documentation

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
# Copyright (C) 2005, 2006 Canonical Ltd
 
1
# Copyright (C) 2005, 2006 by Canonical Ltd
2
2
#
3
3
# This program is free software; you can redistribute it and/or modify
4
4
# it under the terms of the GNU General Public License as published by
18
18
import os
19
19
 
20
20
import bzrlib
21
 
from bzrlib import (
22
 
    errors,
23
 
    lockdir,
24
 
    osutils,
25
 
    tests,
26
 
    )
 
21
from bzrlib.tests import TestCaseWithTransport
27
22
from bzrlib.branch import Branch
28
23
from bzrlib.bzrdir import BzrDir, BzrDirMetaFormat1
 
24
from bzrlib.workingtree import WorkingTree
29
25
from bzrlib.commit import Commit, NullCommitReporter
30
26
from bzrlib.config import BranchConfig
31
27
from bzrlib.errors import (PointlessCommit, BzrError, SigningFailed, 
32
28
                           LockContention)
33
 
from bzrlib.tests import TestCaseWithTransport
34
 
from bzrlib.workingtree import WorkingTree
35
29
 
36
30
 
37
31
# TODO: Test commit with some added, and added-but-missing files
70
64
    def renamed(self, change, old_path, new_path):
71
65
        self.calls.append(('renamed', change, old_path, new_path))
72
66
 
73
 
    def is_verbose(self):
74
 
        return True
75
 
 
76
67
 
77
68
class TestCommit(TestCaseWithTransport):
78
69
 
226
217
        wt.move(['hello'], 'a')
227
218
        r2 = 'test@rev-2'
228
219
        wt.commit('two', rev_id=r2, allow_pointless=False)
229
 
        wt.lock_read()
230
 
        try:
231
 
            self.check_inventory_shape(wt.read_working_inventory(),
232
 
                                       ['a/', 'a/hello', 'b/'])
233
 
        finally:
234
 
            wt.unlock()
 
220
        self.check_inventory_shape(wt.read_working_inventory(),
 
221
                                   ['a', 'a/hello', 'b'])
235
222
 
236
223
        wt.move(['b'], 'a')
237
224
        r3 = 'test@rev-3'
238
225
        wt.commit('three', rev_id=r3, allow_pointless=False)
239
 
        wt.lock_read()
240
 
        try:
241
 
            self.check_inventory_shape(wt.read_working_inventory(),
242
 
                                       ['a/', 'a/hello', 'a/b/'])
243
 
            self.check_inventory_shape(b.repository.get_revision_inventory(r3),
244
 
                                       ['a/', 'a/hello', 'a/b/'])
245
 
        finally:
246
 
            wt.unlock()
 
226
        self.check_inventory_shape(wt.read_working_inventory(),
 
227
                                   ['a', 'a/hello', 'a/b'])
 
228
        self.check_inventory_shape(b.repository.get_revision_inventory(r3),
 
229
                                   ['a', 'a/hello', 'a/b'])
247
230
 
248
231
        wt.move(['a/hello'], 'a/b')
249
232
        r4 = 'test@rev-4'
250
233
        wt.commit('four', rev_id=r4, allow_pointless=False)
251
 
        wt.lock_read()
252
 
        try:
253
 
            self.check_inventory_shape(wt.read_working_inventory(),
254
 
                                       ['a/', 'a/b/hello', 'a/b/'])
255
 
        finally:
256
 
            wt.unlock()
 
234
        self.check_inventory_shape(wt.read_working_inventory(),
 
235
                                   ['a', 'a/b/hello', 'a/b'])
257
236
 
258
237
        inv = b.repository.get_revision_inventory(r4)
259
238
        eq(inv['hello-id'].revision, r4)
260
239
        eq(inv['a-id'].revision, r1)
261
240
        eq(inv['b-id'].revision, r3)
262
 
 
 
241
        
263
242
    def test_removed_commit(self):
264
243
        """Commit with a removed file"""
265
244
        wt = self.make_branch_and_tree('.')
360
339
                                                      allow_pointless=True,
361
340
                                                      rev_id='B',
362
341
                                                      working_tree=wt)
363
 
            def sign(text):
364
 
                return bzrlib.gpg.LoopbackGPGStrategy(None).sign(text)
365
 
            self.assertEqual(sign(Testament.from_revision(branch.repository,
366
 
                             'B').as_short_text()),
 
342
            self.assertEqual(Testament.from_revision(branch.repository,
 
343
                             'B').as_short_text(),
367
344
                             branch.repository.get_signature_text('B'))
368
345
        finally:
369
346
            bzrlib.gpg.GPGStrategy = oldstrategy
430
407
        bound = master.sprout('bound')
431
408
        wt = bound.open_workingtree()
432
409
        wt.branch.set_bound_location(os.path.realpath('master'))
433
 
 
434
 
        orig_default = lockdir._DEFAULT_TIMEOUT_SECONDS
435
410
        master_branch.lock_write()
436
411
        try:
437
 
            lockdir._DEFAULT_TIMEOUT_SECONDS = 1
438
412
            self.assertRaises(LockContention, wt.commit, 'silly')
439
413
        finally:
440
 
            lockdir._DEFAULT_TIMEOUT_SECONDS = orig_default
441
414
            master_branch.unlock()
442
415
 
443
416
    def test_commit_bound_merge(self):
463
436
        # do a merge into the bound branch from other, and then change the
464
437
        # content file locally to force a new revision (rather than using the
465
438
        # revision from other). This forces extra processing in commit.
466
 
        bound_tree.merge_from_branch(other_tree.branch)
 
439
        self.merge(other_tree.branch, bound_tree)
467
440
        self.build_tree_contents([('bound/content_file', 'change in bound\n')])
468
441
 
469
442
        # before #34959 was fixed, this failed with 'revision not present in
517
490
            other_tree.commit('modify all sample files and dirs.')
518
491
        finally:
519
492
            other_tree.unlock()
520
 
        this_tree.merge_from_branch(other_tree.branch)
 
493
        self.merge(other_tree.branch, this_tree)
521
494
        reporter = CapturingReporter()
522
495
        this_tree.commit('do the commit', reporter=reporter)
523
496
        self.assertEqual([
528
501
            ('change', 'added', 'newdir'),
529
502
            ('change', 'added', 'newfile'),
530
503
            ('renamed', 'renamed', 'dirtorename', 'renameddir'),
531
 
            ('renamed', 'renamed', 'filetorename', 'renamedfile'),
532
504
            ('renamed', 'renamed', 'dirtoreparent', 'renameddir/reparenteddir'),
533
505
            ('renamed', 'renamed', 'filetoreparent', 'renameddir/reparentedfile'),
 
506
            ('renamed', 'renamed', 'filetorename', 'renamedfile'),
534
507
            ('deleted', 'dirtoremove'),
535
508
            ('deleted', 'filetoremove'),
536
509
            ],
544
517
        tree.commit('added a, b')
545
518
        tree.remove(['a', 'b'])
546
519
        tree.commit('removed a', specific_files='a')
547
 
        basis = tree.basis_tree()
548
 
        tree.lock_read()
549
 
        try:
550
 
            self.assertIs(None, basis.path2id('a'))
551
 
            self.assertFalse(basis.path2id('b') is None)
552
 
        finally:
553
 
            tree.unlock()
 
520
        basis = tree.basis_tree().inventory
 
521
        self.assertIs(None, basis.path2id('a'))
 
522
        self.assertFalse(basis.path2id('b') is None)
554
523
 
555
524
    def test_commit_saves_1ms_timestamp(self):
556
525
        """Passing in a timestamp is saved with 1ms resolution"""
574
543
        timestamp = rev.timestamp
575
544
        timestamp_1ms = round(timestamp, 3)
576
545
        self.assertEqual(timestamp_1ms, timestamp)
577
 
 
578
 
    def assertBasisTreeKind(self, kind, tree, file_id):
579
 
        basis = tree.basis_tree()
580
 
        basis.lock_read()
581
 
        try:
582
 
            self.assertEqual(kind, basis.kind(file_id))
583
 
        finally:
584
 
            basis.unlock()
585
 
 
586
 
    def test_commit_kind_changes(self):
587
 
        if not osutils.has_symlinks():
588
 
            raise tests.TestSkipped('Test requires symlink support')
589
 
        tree = self.make_branch_and_tree('.')
590
 
        os.symlink('target', 'name')
591
 
        tree.add('name', 'a-file-id')
592
 
        tree.commit('Added a symlink')
593
 
        self.assertBasisTreeKind('symlink', tree, 'a-file-id')
594
 
 
595
 
        os.unlink('name')
596
 
        self.build_tree(['name'])
597
 
        tree.commit('Changed symlink to file')
598
 
        self.assertBasisTreeKind('file', tree, 'a-file-id')
599
 
 
600
 
        os.unlink('name')
601
 
        os.symlink('target', 'name')
602
 
        tree.commit('file to symlink')
603
 
        self.assertBasisTreeKind('symlink', tree, 'a-file-id')
604
 
 
605
 
        os.unlink('name')
606
 
        os.mkdir('name')
607
 
        tree.commit('symlink to directory')
608
 
        self.assertBasisTreeKind('directory', tree, 'a-file-id')
609
 
 
610
 
        os.rmdir('name')
611
 
        os.symlink('target', 'name')
612
 
        tree.commit('directory to symlink')
613
 
        self.assertBasisTreeKind('symlink', tree, 'a-file-id')
614
 
 
615
 
        # prepare for directory <-> file tests
616
 
        os.unlink('name')
617
 
        os.mkdir('name')
618
 
        tree.commit('symlink to directory')
619
 
        self.assertBasisTreeKind('directory', tree, 'a-file-id')
620
 
 
621
 
        os.rmdir('name')
622
 
        self.build_tree(['name'])
623
 
        tree.commit('Changed directory to file')
624
 
        self.assertBasisTreeKind('file', tree, 'a-file-id')
625
 
 
626
 
        os.unlink('name')
627
 
        os.mkdir('name')
628
 
        tree.commit('file to directory')
629
 
        self.assertBasisTreeKind('directory', tree, 'a-file-id')
630
 
 
631
 
    def test_commit_unversioned_specified(self):
632
 
        """Commit should raise if specified files isn't in basis or worktree"""
633
 
        tree = self.make_branch_and_tree('.')
634
 
        self.assertRaises(errors.PathsNotVersionedError, tree.commit, 
635
 
                          'message', specific_files=['bogus'])
636
 
 
637
 
    class Callback(object):
638
 
        
639
 
        def __init__(self, message, testcase):
640
 
            self.called = False
641
 
            self.message = message
642
 
            self.testcase = testcase
643
 
 
644
 
        def __call__(self, commit_obj):
645
 
            self.called = True
646
 
            self.testcase.assertTrue(isinstance(commit_obj, Commit))
647
 
            return self.message
648
 
 
649
 
    def test_commit_callback(self):
650
 
        """Commit should invoke a callback to get the message"""
651
 
 
652
 
        tree = self.make_branch_and_tree('.')
653
 
        try:
654
 
            tree.commit()
655
 
        except Exception, e:
656
 
            self.assertTrue(isinstance(e, BzrError))
657
 
            self.assertEqual('The message or message_callback keyword'
658
 
                             ' parameter is required for commit().', str(e))
659
 
        else:
660
 
            self.fail('exception not raised')
661
 
        cb = self.Callback(u'commit 1', self)
662
 
        tree.commit(message_callback=cb)
663
 
        self.assertTrue(cb.called)
664
 
        repository = tree.branch.repository
665
 
        message = repository.get_revision(tree.last_revision()).message
666
 
        self.assertEqual('commit 1', message)
667
 
 
668
 
    def test_no_callback_pointless(self):
669
 
        """Callback should not be invoked for pointless commit"""
670
 
        tree = self.make_branch_and_tree('.')
671
 
        cb = self.Callback(u'commit 2', self)
672
 
        self.assertRaises(PointlessCommit, tree.commit, message_callback=cb, 
673
 
                          allow_pointless=False)
674
 
        self.assertFalse(cb.called)
675
 
 
676
 
    def test_no_callback_netfailure(self):
677
 
        """Callback should not be invoked if connectivity fails"""
678
 
        tree = self.make_branch_and_tree('.')
679
 
        cb = self.Callback(u'commit 2', self)
680
 
        repository = tree.branch.repository
681
 
        # simulate network failure
682
 
        def raise_(self, arg, arg2):
683
 
            raise errors.NoSuchFile('foo')
684
 
        repository.add_inventory = raise_
685
 
        self.assertRaises(errors.NoSuchFile, tree.commit, message_callback=cb)
686
 
        self.assertFalse(cb.called)
687
 
 
688
 
    def test_selected_file_merge_commit(self):
689
 
        """Ensure the correct error is raised"""
690
 
        tree = self.make_branch_and_tree('foo')
691
 
        # pending merge would turn into a left parent
692
 
        tree.commit('commit 1')
693
 
        tree.add_parent_tree_id('example')
694
 
        self.build_tree(['foo/bar', 'foo/baz'])
695
 
        tree.add(['bar', 'baz'])
696
 
        err = self.assertRaises(errors.CannotCommitSelectedFileMerge,
697
 
            tree.commit, 'commit 2', specific_files=['bar', 'baz'])
698
 
        self.assertEqual(['bar', 'baz'], err.files)
699
 
        self.assertEqual('Selected-file commit of merges is not supported'
700
 
                         ' yet: files bar, baz', str(err))
701
 
 
702
 
    def test_commit_ordering(self):
703
 
        """Test of corner-case commit ordering error"""
704
 
        tree = self.make_branch_and_tree('.')
705
 
        self.build_tree(['a/', 'a/z/', 'a/c/', 'a/z/x', 'a/z/y'])
706
 
        tree.add(['a/', 'a/z/', 'a/c/', 'a/z/x', 'a/z/y'])
707
 
        tree.commit('setup')
708
 
        self.build_tree(['a/c/d/'])
709
 
        tree.add('a/c/d')
710
 
        tree.rename_one('a/z/x', 'a/c/d/x')
711
 
        tree.commit('test', specific_files=['a/z/y'])
712
 
 
713
 
    def test_commit_no_author(self):
714
 
        """The default kwarg author in MutableTree.commit should not add
715
 
        the 'author' revision property.
716
 
        """
717
 
        tree = self.make_branch_and_tree('foo')
718
 
        rev_id = tree.commit('commit 1')
719
 
        rev = tree.branch.repository.get_revision(rev_id)
720
 
        self.assertFalse('author' in rev.properties)
721
 
 
722
 
    def test_commit_author(self):
723
 
        """Passing a non-empty author kwarg to MutableTree.commit should add
724
 
        the 'author' revision property.
725
 
        """
726
 
        tree = self.make_branch_and_tree('foo')
727
 
        rev_id = tree.commit('commit 1', author='John Doe <jdoe@example.com>')
728
 
        rev = tree.branch.repository.get_revision(rev_id)
729
 
        self.assertEqual('John Doe <jdoe@example.com>',
730
 
                         rev.properties['author'])