~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: 2008-03-13 23:45:11 UTC
  • mfrom: (3272.1.1 ianc-integration)
  • Revision ID: pqm@pqm.ubuntu.com-20080313234511-fkj5oa8gm3nrfcro
(Neil Martinsen-Burrell) Explain version-info --custom in the User
        Guide

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
# Copyright (C) 2005-2011 Canonical Ltd
 
1
# Copyright (C) 2005, 2006 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
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
 
18
18
import os
21
21
from bzrlib import (
22
22
    bzrdir,
23
23
    errors,
 
24
    lockdir,
 
25
    osutils,
 
26
    tests,
24
27
    )
25
28
from bzrlib.branch import Branch
26
 
from bzrlib.bzrdir import BzrDirMetaFormat1
 
29
from bzrlib.bzrdir import BzrDir, BzrDirMetaFormat1
27
30
from bzrlib.commit import Commit, NullCommitReporter
28
31
from bzrlib.config import BranchConfig
29
 
from bzrlib.errors import (
30
 
    PointlessCommit,
31
 
    BzrError,
32
 
    SigningFailed,
33
 
    LockContention,
34
 
    )
35
 
from bzrlib.tests import (
36
 
    TestCaseWithTransport,
37
 
    test_foreign,
38
 
    )
39
 
from bzrlib.tests.features import (
40
 
    SymlinkFeature,
41
 
    )
42
 
from bzrlib.tests.matchers import MatchesAncestry
 
32
from bzrlib.errors import (PointlessCommit, BzrError, SigningFailed, 
 
33
                           LockContention)
 
34
from bzrlib.tests import SymlinkFeature, TestCaseWithTransport
 
35
from bzrlib.workingtree import WorkingTree
43
36
 
44
37
 
45
38
# TODO: Test commit with some added, and added-but-missing files
114
107
        tree2.unlock()
115
108
        self.assertEqual('version 2', text)
116
109
 
117
 
    def test_commit_lossy_native(self):
118
 
        """Attempt a lossy commit to a native branch."""
119
 
        wt = self.make_branch_and_tree('.')
120
 
        b = wt.branch
121
 
        file('hello', 'w').write('hello world')
122
 
        wt.add('hello')
123
 
        revid = wt.commit(message='add hello', rev_id='revid', lossy=True)
124
 
        self.assertEquals('revid', revid)
125
 
 
126
 
    def test_commit_lossy_foreign(self):
127
 
        """Attempt a lossy commit to a foreign branch."""
128
 
        test_foreign.register_dummy_foreign_for_test(self)
129
 
        wt = self.make_branch_and_tree('.',
130
 
            format=test_foreign.DummyForeignVcsDirFormat())
131
 
        b = wt.branch
132
 
        file('hello', 'w').write('hello world')
133
 
        wt.add('hello')
134
 
        revid = wt.commit(message='add hello', lossy=True,
135
 
            timestamp=1302659388, timezone=0)
136
 
        self.assertEquals('dummy-v1:1302659388.0-0-UNKNOWN', revid)
137
 
 
138
 
    def test_commit_bound_lossy_foreign(self):
139
 
        """Attempt a lossy commit to a bzr branch bound to a foreign branch."""
140
 
        test_foreign.register_dummy_foreign_for_test(self)
141
 
        foreign_branch = self.make_branch('foreign',
142
 
            format=test_foreign.DummyForeignVcsDirFormat())
143
 
        wt = foreign_branch.create_checkout("local")
144
 
        b = wt.branch
145
 
        file('local/hello', 'w').write('hello world')
146
 
        wt.add('hello')
147
 
        revid = wt.commit(message='add hello', lossy=True,
148
 
            timestamp=1302659388, timezone=0)
149
 
        self.assertEquals('dummy-v1:1302659388.0-0-0', revid)
150
 
        self.assertEquals('dummy-v1:1302659388.0-0-0',
151
 
            foreign_branch.last_revision())
152
 
        self.assertEquals('dummy-v1:1302659388.0-0-0',
153
 
            wt.branch.last_revision())
154
 
 
155
 
    def test_missing_commit(self):
156
 
        """Test a commit with a missing file"""
 
110
    def test_delete_commit(self):
 
111
        """Test a commit with a deleted file"""
157
112
        wt = self.make_branch_and_tree('.')
158
113
        b = wt.branch
159
114
        file('hello', 'w').write('hello world')
161
116
        wt.commit(message='add hello')
162
117
 
163
118
        os.remove('hello')
164
 
        reporter = CapturingReporter()
165
 
        wt.commit('removed hello', rev_id='rev2', reporter=reporter)
166
 
        self.assertEquals(
167
 
            [('missing', u'hello'), ('deleted', u'hello')],
168
 
            reporter.calls)
 
119
        wt.commit('removed hello', rev_id='rev2')
169
120
 
170
121
        tree = b.repository.revision_tree('rev2')
171
122
        self.assertFalse(tree.has_id('hello-id'))
172
123
 
173
 
    def test_partial_commit_move(self):
174
 
        """Test a partial commit where a file was renamed but not committed.
175
 
 
176
 
        https://bugs.launchpad.net/bzr/+bug/83039
177
 
 
178
 
        If not handled properly, commit will try to snapshot
179
 
        dialog.py with olive/ as a parent, while
180
 
        olive/ has not been snapshotted yet.
181
 
        """
182
 
        wt = self.make_branch_and_tree('.')
183
 
        b = wt.branch
184
 
        self.build_tree(['annotate/', 'annotate/foo.py',
185
 
                         'olive/', 'olive/dialog.py'
186
 
                        ])
187
 
        wt.add(['annotate', 'olive', 'annotate/foo.py', 'olive/dialog.py'])
188
 
        wt.commit(message='add files')
189
 
        wt.rename_one("olive/dialog.py", "aaa")
190
 
        self.build_tree_contents([('annotate/foo.py', 'modified\n')])
191
 
        wt.commit('renamed hello', specific_files=["annotate"])
192
 
 
193
124
    def test_pointless_commit(self):
194
125
        """Commit refuses unless there are changes or it's forced."""
195
126
        wt = self.make_branch_and_tree('.')
203
134
                          message='fails',
204
135
                          allow_pointless=False)
205
136
        self.assertEquals(b.revno(), 1)
206
 
 
 
137
        
207
138
    def test_commit_empty(self):
208
139
        """Commiting an empty tree works."""
209
140
        wt = self.make_branch_and_tree('.')
226
157
              ['hello-id', 'buongia-id'])
227
158
        wt.commit(message='add files',
228
159
                 rev_id='test@rev-1')
229
 
 
 
160
        
230
161
        os.remove('hello')
231
162
        file('buongia', 'w').write('new text')
232
163
        wt.commit(message='update text',
248
179
        self.assertTrue(tree2.has_filename('hello'))
249
180
        self.assertEquals(tree2.get_file_text('hello-id'), 'hello')
250
181
        self.assertEquals(tree2.get_file_text('buongia-id'), 'new text')
251
 
 
 
182
        
252
183
        tree3 = b.repository.revision_tree('test@rev-3')
253
184
        tree3.lock_read()
254
185
        self.addCleanup(tree3.unlock)
273
204
        eq(tree1.id2path('hello-id'), 'hello')
274
205
        eq(tree1.get_file_text('hello-id'), 'contents of hello\n')
275
206
        self.assertFalse(tree1.has_filename('fruity'))
276
 
        self.check_tree_shape(tree1, ['hello'])
277
 
        eq(tree1.get_file_revision('hello-id'), 'test@rev-1')
 
207
        self.check_inventory_shape(tree1.inventory, ['hello'])
 
208
        ie = tree1.inventory['hello-id']
 
209
        eq(ie.revision, 'test@rev-1')
278
210
 
279
211
        tree2 = b.repository.revision_tree('test@rev-2')
280
212
        tree2.lock_read()
281
213
        self.addCleanup(tree2.unlock)
282
214
        eq(tree2.id2path('hello-id'), 'fruity')
283
215
        eq(tree2.get_file_text('hello-id'), 'contents of hello\n')
284
 
        self.check_tree_shape(tree2, ['fruity'])
285
 
        eq(tree2.get_file_revision('hello-id'), 'test@rev-2')
 
216
        self.check_inventory_shape(tree2.inventory, ['fruity'])
 
217
        ie = tree2.inventory['hello-id']
 
218
        eq(ie.revision, 'test@rev-2')
286
219
 
287
220
    def test_reused_rev_id(self):
288
221
        """Test that a revision id cannot be reused in a branch"""
309
242
        wt.commit('two', rev_id=r2, allow_pointless=False)
310
243
        wt.lock_read()
311
244
        try:
312
 
            self.check_tree_shape(wt, ['a/', 'a/hello', 'b/'])
 
245
            self.check_inventory_shape(wt.read_working_inventory(),
 
246
                                       ['a/', 'a/hello', 'b/'])
313
247
        finally:
314
248
            wt.unlock()
315
249
 
318
252
        wt.commit('three', rev_id=r3, allow_pointless=False)
319
253
        wt.lock_read()
320
254
        try:
321
 
            self.check_tree_shape(wt,
 
255
            self.check_inventory_shape(wt.read_working_inventory(),
322
256
                                       ['a/', 'a/hello', 'a/b/'])
323
 
            self.check_tree_shape(b.repository.revision_tree(r3),
 
257
            self.check_inventory_shape(b.repository.get_revision_inventory(r3),
324
258
                                       ['a/', 'a/hello', 'a/b/'])
325
259
        finally:
326
260
            wt.unlock()
330
264
        wt.commit('four', rev_id=r4, allow_pointless=False)
331
265
        wt.lock_read()
332
266
        try:
333
 
            self.check_tree_shape(wt, ['a/', 'a/b/hello', 'a/b/'])
 
267
            self.check_inventory_shape(wt.read_working_inventory(),
 
268
                                       ['a/', 'a/b/hello', 'a/b/'])
334
269
        finally:
335
270
            wt.unlock()
336
271
 
337
 
        inv = b.repository.get_inventory(r4)
 
272
        inv = b.repository.get_revision_inventory(r4)
338
273
        eq(inv['hello-id'].revision, r4)
339
274
        eq(inv['a-id'].revision, r1)
340
275
        eq(inv['b-id'].revision, r3)
368
303
        eq = self.assertEquals
369
304
        eq(b.revision_history(), rev_ids)
370
305
        for i in range(4):
371
 
            self.assertThat(rev_ids[:i+1],
372
 
                MatchesAncestry(b.repository, rev_ids[i]))
 
306
            anc = b.repository.get_ancestry(rev_ids[i])
 
307
            eq(anc, [None] + rev_ids[:i+1])
373
308
 
374
309
    def test_commit_new_subdir_child_selective(self):
375
310
        wt = self.make_branch_and_tree('.')
398
333
    def test_strict_commit_without_unknowns(self):
399
334
        """Try and commit with no unknown files and strict = True,
400
335
        should work."""
 
336
        from bzrlib.errors import StrictCommitFailed
401
337
        wt = self.make_branch_and_tree('.')
402
338
        b = wt.branch
403
339
        file('hello', 'w').write('hello world')
429
365
        wt = self.make_branch_and_tree('.')
430
366
        branch = wt.branch
431
367
        wt.commit("base", allow_pointless=True, rev_id='A')
432
 
        self.assertFalse(branch.repository.has_signature_for_revision_id('A'))
 
368
        self.failIf(branch.repository.has_signature_for_revision_id('A'))
433
369
        try:
434
370
            from bzrlib.testament import Testament
435
371
            # monkey patch gpg signing mechanism
453
389
        wt = self.make_branch_and_tree('.')
454
390
        branch = wt.branch
455
391
        wt.commit("base", allow_pointless=True, rev_id='A')
456
 
        self.assertFalse(branch.repository.has_signature_for_revision_id('A'))
 
392
        self.failIf(branch.repository.has_signature_for_revision_id('A'))
457
393
        try:
 
394
            from bzrlib.testament import Testament
458
395
            # monkey patch gpg signing mechanism
459
396
            bzrlib.gpg.GPGStrategy = bzrlib.gpg.DisabledGPGStrategy
460
397
            config = MustSignConfig(branch)
466
403
                              working_tree=wt)
467
404
            branch = Branch.open(self.get_url('.'))
468
405
            self.assertEqual(branch.revision_history(), ['A'])
469
 
            self.assertFalse(branch.repository.has_revision('B'))
 
406
            self.failIf(branch.repository.has_revision('B'))
470
407
        finally:
471
408
            bzrlib.gpg.GPGStrategy = oldstrategy
472
409
 
507
444
        bound = master.sprout('bound')
508
445
        wt = bound.open_workingtree()
509
446
        wt.branch.set_bound_location(os.path.realpath('master'))
 
447
 
 
448
        orig_default = lockdir._DEFAULT_TIMEOUT_SECONDS
510
449
        master_branch.lock_write()
511
450
        try:
 
451
            lockdir._DEFAULT_TIMEOUT_SECONDS = 1
512
452
            self.assertRaises(LockContention, wt.commit, 'silly')
513
453
        finally:
 
454
            lockdir._DEFAULT_TIMEOUT_SECONDS = orig_default
514
455
            master_branch.unlock()
515
456
 
516
457
    def test_commit_bound_merge(self):
527
468
        other_bzrdir = master_branch.bzrdir.sprout('other')
528
469
        other_tree = other_bzrdir.open_workingtree()
529
470
 
530
 
        # do a commit to the other branch changing the content file so
 
471
        # do a commit to the the other branch changing the content file so
531
472
        # that our commit after merging will have a merged revision in the
532
473
        # content file history.
533
474
        self.build_tree_contents([('other/content_file', 'change in other\n')])
544
485
        bound_tree.commit(message='commit of merge in bound tree')
545
486
 
546
487
    def test_commit_reporting_after_merge(self):
547
 
        # when doing a commit of a merge, the reporter needs to still
 
488
        # when doing a commit of a merge, the reporter needs to still 
548
489
        # be called for each item that is added/removed/deleted.
549
490
        this_tree = self.make_branch_and_tree('this')
550
491
        # we need a bunch of files and dirs, to perform one action on each.
593
534
        this_tree.merge_from_branch(other_tree.branch)
594
535
        reporter = CapturingReporter()
595
536
        this_tree.commit('do the commit', reporter=reporter)
596
 
        expected = set([
 
537
        self.assertEqual([
 
538
            ('change', 'unchanged', ''),
 
539
            ('change', 'unchanged', 'dirtoleave'),
 
540
            ('change', 'unchanged', 'filetoleave'),
597
541
            ('change', 'modified', 'filetomodify'),
598
542
            ('change', 'added', 'newdir'),
599
543
            ('change', 'added', 'newfile'),
603
547
            ('renamed', 'renamed', 'filetoreparent', 'renameddir/reparentedfile'),
604
548
            ('deleted', 'dirtoremove'),
605
549
            ('deleted', 'filetoremove'),
606
 
            ])
607
 
        result = set(reporter.calls)
608
 
        missing = expected - result
609
 
        new = result - expected
610
 
        self.assertEqual((set(), set()), (missing, new))
 
550
            ],
 
551
            reporter.calls)
611
552
 
612
553
    def test_commit_removals_respects_filespec(self):
613
554
        """Commit respects the specified_files for removals."""
703
644
    def test_commit_unversioned_specified(self):
704
645
        """Commit should raise if specified files isn't in basis or worktree"""
705
646
        tree = self.make_branch_and_tree('.')
706
 
        self.assertRaises(errors.PathsNotVersionedError, tree.commit,
 
647
        self.assertRaises(errors.PathsNotVersionedError, tree.commit, 
707
648
                          'message', specific_files=['bogus'])
708
649
 
709
650
    class Callback(object):
710
 
 
 
651
        
711
652
        def __init__(self, message, testcase):
712
653
            self.called = False
713
654
            self.message = message
741
682
        """Callback should not be invoked for pointless commit"""
742
683
        tree = self.make_branch_and_tree('.')
743
684
        cb = self.Callback(u'commit 2', self)
744
 
        self.assertRaises(PointlessCommit, tree.commit, message_callback=cb,
 
685
        self.assertRaises(PointlessCommit, tree.commit, message_callback=cb, 
745
686
                          allow_pointless=False)
746
687
        self.assertFalse(cb.called)
747
688
 
751
692
        cb = self.Callback(u'commit 2', self)
752
693
        repository = tree.branch.repository
753
694
        # simulate network failure
754
 
        def raise_(self, arg, arg2, arg3=None, arg4=None):
 
695
        def raise_(self, arg, arg2):
755
696
            raise errors.NoSuchFile('foo')
756
697
        repository.add_inventory = raise_
757
 
        repository.add_inventory_by_delta = raise_
758
698
        self.assertRaises(errors.NoSuchFile, tree.commit, message_callback=cb)
759
699
        self.assertFalse(cb.called)
760
700
 
782
722
        tree.add('a/c/d')
783
723
        tree.rename_one('a/z/x', 'a/c/d/x')
784
724
        tree.commit('test', specific_files=['a/z/y'])
785
 
 
 
725
 
786
726
    def test_commit_no_author(self):
787
727
        """The default kwarg author in MutableTree.commit should not add
788
728
        the 'author' revision property.
791
731
        rev_id = tree.commit('commit 1')
792
732
        rev = tree.branch.repository.get_revision(rev_id)
793
733
        self.assertFalse('author' in rev.properties)
794
 
        self.assertFalse('authors' in rev.properties)
795
734
 
796
735
    def test_commit_author(self):
797
736
        """Passing a non-empty author kwarg to MutableTree.commit should add
798
737
        the 'author' revision property.
799
738
        """
800
739
        tree = self.make_branch_and_tree('foo')
801
 
        rev_id = self.callDeprecated(['The parameter author was '
802
 
                'deprecated in version 1.13. Use authors instead'],
803
 
                tree.commit, 'commit 1', author='John Doe <jdoe@example.com>')
 
740
        rev_id = tree.commit('commit 1', author='John Doe <jdoe@example.com>')
804
741
        rev = tree.branch.repository.get_revision(rev_id)
805
742
        self.assertEqual('John Doe <jdoe@example.com>',
806
 
                         rev.properties['authors'])
807
 
        self.assertFalse('author' in rev.properties)
808
 
 
809
 
    def test_commit_empty_authors_list(self):
810
 
        """Passing an empty list to authors shouldn't add the property."""
811
 
        tree = self.make_branch_and_tree('foo')
812
 
        rev_id = tree.commit('commit 1', authors=[])
813
 
        rev = tree.branch.repository.get_revision(rev_id)
814
 
        self.assertFalse('author' in rev.properties)
815
 
        self.assertFalse('authors' in rev.properties)
816
 
 
817
 
    def test_multiple_authors(self):
818
 
        tree = self.make_branch_and_tree('foo')
819
 
        rev_id = tree.commit('commit 1',
820
 
                authors=['John Doe <jdoe@example.com>',
821
 
                         'Jane Rey <jrey@example.com>'])
822
 
        rev = tree.branch.repository.get_revision(rev_id)
823
 
        self.assertEqual('John Doe <jdoe@example.com>\n'
824
 
                'Jane Rey <jrey@example.com>', rev.properties['authors'])
825
 
        self.assertFalse('author' in rev.properties)
826
 
 
827
 
    def test_author_and_authors_incompatible(self):
828
 
        tree = self.make_branch_and_tree('foo')
829
 
        self.assertRaises(AssertionError, tree.commit, 'commit 1',
830
 
                authors=['John Doe <jdoe@example.com>',
831
 
                         'Jane Rey <jrey@example.com>'],
832
 
                author="Jack Me <jme@example.com>")
833
 
 
834
 
    def test_author_with_newline_rejected(self):
835
 
        tree = self.make_branch_and_tree('foo')
836
 
        self.assertRaises(AssertionError, tree.commit, 'commit 1',
837
 
                authors=['John\nDoe <jdoe@example.com>'])
 
743
                         rev.properties['author'])
838
744
 
839
745
    def test_commit_with_checkout_and_branch_sharing_repo(self):
840
746
        repo = self.make_repository('repo', shared=True)