/brz/remove-bazaar

To get this branch, use:
bzr branch http://gegoxaren.bato24.eu/bzr/brz/remove-bazaar

« back to all changes in this revision

Viewing changes to bzrlib/tests/test_commit.py

  • Committer: Aaron Bentley
  • Date: 2007-02-15 14:08:23 UTC
  • mto: This revision was merged to the branch mainline in revision 2290.
  • Revision ID: abentley@panoramicfeedback.com-20070215140823-xaqpzdqb5bmox2ak
Updates from review

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
# Copyright (C) 2005 by Canonical Ltd
2
 
 
 
1
# Copyright (C) 2005, 2006 Canonical Ltd
 
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
5
5
# the Free Software Foundation; either version 2 of the License, or
6
6
# (at your option) any later version.
7
 
 
 
7
#
8
8
# This program is distributed in the hope that it will be useful,
9
9
# but WITHOUT ANY WARRANTY; without even the implied warranty of
10
10
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
11
11
# GNU General Public License for more details.
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
15
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
18
18
import os
19
19
 
20
20
import bzrlib
21
 
from bzrlib.tests import TestCaseWithTransport
 
21
from bzrlib import (
 
22
    errors,
 
23
    lockdir,
 
24
    osutils,
 
25
    tests,
 
26
    )
22
27
from bzrlib.branch import Branch
23
28
from bzrlib.bzrdir import BzrDir, BzrDirMetaFormat1
24
 
from bzrlib.workingtree import WorkingTree
25
 
from bzrlib.commit import Commit
 
29
from bzrlib.commit import Commit, NullCommitReporter
26
30
from bzrlib.config import BranchConfig
27
31
from bzrlib.errors import (PointlessCommit, BzrError, SigningFailed, 
28
32
                           LockContention)
 
33
from bzrlib.tests import TestCaseWithTransport
 
34
from bzrlib.workingtree import WorkingTree
29
35
 
30
36
 
31
37
# TODO: Test commit with some added, and added-but-missing files
45
51
        return "bzrlib.ahook bzrlib.ahook"
46
52
 
47
53
 
 
54
class CapturingReporter(NullCommitReporter):
 
55
    """This reporter captures the calls made to it for evaluation later."""
 
56
 
 
57
    def __init__(self):
 
58
        # a list of the calls this received
 
59
        self.calls = []
 
60
 
 
61
    def snapshot_change(self, change, path):
 
62
        self.calls.append(('change', change, path))
 
63
 
 
64
    def deleted(self, file_id):
 
65
        self.calls.append(('deleted', file_id))
 
66
 
 
67
    def missing(self, path):
 
68
        self.calls.append(('missing', path))
 
69
 
 
70
    def renamed(self, change, old_path, new_path):
 
71
        self.calls.append(('renamed', change, old_path, new_path))
 
72
 
 
73
 
48
74
class TestCommit(TestCaseWithTransport):
49
75
 
50
76
    def test_simple_commit(self):
387
413
        bound = master.sprout('bound')
388
414
        wt = bound.open_workingtree()
389
415
        wt.branch.set_bound_location(os.path.realpath('master'))
 
416
 
 
417
        orig_default = lockdir._DEFAULT_TIMEOUT_SECONDS
390
418
        master_branch.lock_write()
391
419
        try:
 
420
            lockdir._DEFAULT_TIMEOUT_SECONDS = 1
392
421
            self.assertRaises(LockContention, wt.commit, 'silly')
393
422
        finally:
 
423
            lockdir._DEFAULT_TIMEOUT_SECONDS = orig_default
394
424
            master_branch.unlock()
 
425
 
 
426
    def test_commit_bound_merge(self):
 
427
        # see bug #43959; commit of a merge in a bound branch fails to push
 
428
        # the new commit into the master
 
429
        master_branch = self.make_branch('master')
 
430
        bound_tree = self.make_branch_and_tree('bound')
 
431
        bound_tree.branch.bind(master_branch)
 
432
 
 
433
        self.build_tree_contents([('bound/content_file', 'initial contents\n')])
 
434
        bound_tree.add(['content_file'])
 
435
        bound_tree.commit(message='woo!')
 
436
 
 
437
        other_bzrdir = master_branch.bzrdir.sprout('other')
 
438
        other_tree = other_bzrdir.open_workingtree()
 
439
 
 
440
        # do a commit to the the other branch changing the content file so
 
441
        # that our commit after merging will have a merged revision in the
 
442
        # content file history.
 
443
        self.build_tree_contents([('other/content_file', 'change in other\n')])
 
444
        other_tree.commit('change in other')
 
445
 
 
446
        # do a merge into the bound branch from other, and then change the
 
447
        # content file locally to force a new revision (rather than using the
 
448
        # revision from other). This forces extra processing in commit.
 
449
        bound_tree.merge_from_branch(other_tree.branch)
 
450
        self.build_tree_contents([('bound/content_file', 'change in bound\n')])
 
451
 
 
452
        # before #34959 was fixed, this failed with 'revision not present in
 
453
        # weave' when trying to implicitly push from the bound branch to the master
 
454
        bound_tree.commit(message='commit of merge in bound tree')
 
455
 
 
456
    def test_commit_reporting_after_merge(self):
 
457
        # when doing a commit of a merge, the reporter needs to still 
 
458
        # be called for each item that is added/removed/deleted.
 
459
        this_tree = self.make_branch_and_tree('this')
 
460
        # we need a bunch of files and dirs, to perform one action on each.
 
461
        self.build_tree([
 
462
            'this/dirtorename/',
 
463
            'this/dirtoreparent/',
 
464
            'this/dirtoleave/',
 
465
            'this/dirtoremove/',
 
466
            'this/filetoreparent',
 
467
            'this/filetorename',
 
468
            'this/filetomodify',
 
469
            'this/filetoremove',
 
470
            'this/filetoleave']
 
471
            )
 
472
        this_tree.add([
 
473
            'dirtorename',
 
474
            'dirtoreparent',
 
475
            'dirtoleave',
 
476
            'dirtoremove',
 
477
            'filetoreparent',
 
478
            'filetorename',
 
479
            'filetomodify',
 
480
            'filetoremove',
 
481
            'filetoleave']
 
482
            )
 
483
        this_tree.commit('create_files')
 
484
        other_dir = this_tree.bzrdir.sprout('other')
 
485
        other_tree = other_dir.open_workingtree()
 
486
        other_tree.lock_write()
 
487
        # perform the needed actions on the files and dirs.
 
488
        try:
 
489
            other_tree.rename_one('dirtorename', 'renameddir')
 
490
            other_tree.rename_one('dirtoreparent', 'renameddir/reparenteddir')
 
491
            other_tree.rename_one('filetorename', 'renamedfile')
 
492
            other_tree.rename_one('filetoreparent', 'renameddir/reparentedfile')
 
493
            other_tree.remove(['dirtoremove', 'filetoremove'])
 
494
            self.build_tree_contents([
 
495
                ('other/newdir/', ),
 
496
                ('other/filetomodify', 'new content'),
 
497
                ('other/newfile', 'new file content')])
 
498
            other_tree.add('newfile')
 
499
            other_tree.add('newdir/')
 
500
            other_tree.commit('modify all sample files and dirs.')
 
501
        finally:
 
502
            other_tree.unlock()
 
503
        this_tree.merge_from_branch(other_tree.branch)
 
504
        reporter = CapturingReporter()
 
505
        this_tree.commit('do the commit', reporter=reporter)
 
506
        self.assertEqual([
 
507
            ('change', 'unchanged', ''),
 
508
            ('change', 'unchanged', 'dirtoleave'),
 
509
            ('change', 'unchanged', 'filetoleave'),
 
510
            ('change', 'modified', 'filetomodify'),
 
511
            ('change', 'added', 'newdir'),
 
512
            ('change', 'added', 'newfile'),
 
513
            ('renamed', 'renamed', 'dirtorename', 'renameddir'),
 
514
            ('renamed', 'renamed', 'dirtoreparent', 'renameddir/reparenteddir'),
 
515
            ('renamed', 'renamed', 'filetoreparent', 'renameddir/reparentedfile'),
 
516
            ('renamed', 'renamed', 'filetorename', 'renamedfile'),
 
517
            ('deleted', 'dirtoremove'),
 
518
            ('deleted', 'filetoremove'),
 
519
            ],
 
520
            reporter.calls)
 
521
 
 
522
    def test_commit_removals_respects_filespec(self):
 
523
        """Commit respects the specified_files for removals."""
 
524
        tree = self.make_branch_and_tree('.')
 
525
        self.build_tree(['a', 'b'])
 
526
        tree.add(['a', 'b'])
 
527
        tree.commit('added a, b')
 
528
        tree.remove(['a', 'b'])
 
529
        tree.commit('removed a', specific_files='a')
 
530
        basis = tree.basis_tree().inventory
 
531
        self.assertIs(None, basis.path2id('a'))
 
532
        self.assertFalse(basis.path2id('b') is None)
 
533
 
 
534
    def test_commit_saves_1ms_timestamp(self):
 
535
        """Passing in a timestamp is saved with 1ms resolution"""
 
536
        tree = self.make_branch_and_tree('.')
 
537
        self.build_tree(['a'])
 
538
        tree.add('a')
 
539
        tree.commit('added a', timestamp=1153248633.4186721, timezone=0,
 
540
                    rev_id='a1')
 
541
 
 
542
        rev = tree.branch.repository.get_revision('a1')
 
543
        self.assertEqual(1153248633.419, rev.timestamp)
 
544
 
 
545
    def test_commit_has_1ms_resolution(self):
 
546
        """Allowing commit to generate the timestamp also has 1ms resolution"""
 
547
        tree = self.make_branch_and_tree('.')
 
548
        self.build_tree(['a'])
 
549
        tree.add('a')
 
550
        tree.commit('added a', rev_id='a1')
 
551
 
 
552
        rev = tree.branch.repository.get_revision('a1')
 
553
        timestamp = rev.timestamp
 
554
        timestamp_1ms = round(timestamp, 3)
 
555
        self.assertEqual(timestamp_1ms, timestamp)
 
556
 
 
557
    def test_commit_kind_changes(self):
 
558
        if not osutils.has_symlinks():
 
559
            raise tests.TestSkipped('Test requires symlink support')
 
560
        tree = self.make_branch_and_tree('.')
 
561
        os.symlink('target', 'name')
 
562
        tree.add('name', 'a-file-id')
 
563
        tree.commit('Added a symlink')
 
564
        self.assertEqual('symlink', tree.basis_tree().kind('a-file-id'))
 
565
 
 
566
        os.unlink('name')
 
567
        self.build_tree(['name'])
 
568
        tree.commit('Changed symlink to file')
 
569
        self.assertEqual('file', tree.basis_tree().kind('a-file-id'))
 
570
 
 
571
        os.unlink('name')
 
572
        os.symlink('target', 'name')
 
573
        tree.commit('file to symlink')
 
574
        self.assertEqual('symlink', tree.basis_tree().kind('a-file-id'))
 
575
 
 
576
        os.unlink('name')
 
577
        os.mkdir('name')
 
578
        tree.commit('symlink to directory')
 
579
        self.assertEqual('directory', tree.basis_tree().kind('a-file-id'))
 
580
 
 
581
        os.rmdir('name')
 
582
        os.symlink('target', 'name')
 
583
        tree.commit('directory to symlink')
 
584
        self.assertEqual('symlink', tree.basis_tree().kind('a-file-id'))
 
585
 
 
586
        # prepare for directory <-> file tests
 
587
        os.unlink('name')
 
588
        os.mkdir('name')
 
589
        tree.commit('symlink to directory')
 
590
        self.assertEqual('directory', tree.basis_tree().kind('a-file-id'))
 
591
 
 
592
        os.rmdir('name')
 
593
        self.build_tree(['name'])
 
594
        tree.commit('Changed directory to file')
 
595
        self.assertEqual('file', tree.basis_tree().kind('a-file-id'))
 
596
 
 
597
        os.unlink('name')
 
598
        os.mkdir('name')
 
599
        tree.commit('file to directory')
 
600
        self.assertEqual('directory', tree.basis_tree().kind('a-file-id'))
 
601
 
 
602
    def test_commit_unversioned_specified(self):
 
603
        """Commit should raise if specified files isn't in basis or worktree"""
 
604
        tree = self.make_branch_and_tree('.')
 
605
        self.assertRaises(errors.PathsNotVersionedError, tree.commit, 
 
606
                          'message', specific_files=['bogus'])
 
607
 
 
608
    class Callback(object):
 
609
        
 
610
        def __init__(self, message, testcase):
 
611
            self.called = False
 
612
            self.message = message
 
613
            self.testcase = testcase
 
614
 
 
615
        def __call__(self, commit_obj):
 
616
            self.called = True
 
617
            self.testcase.assertTrue(isinstance(commit_obj, Commit))
 
618
            return self.message
 
619
 
 
620
    def test_commit_callback(self):
 
621
        """Commit should invoke a callback to get the message"""
 
622
 
 
623
        tree = self.make_branch_and_tree('.')
 
624
        try:
 
625
            tree.commit()
 
626
        except Exception, e:
 
627
            self.assertTrue(isinstance(e, BzrError))
 
628
            self.assertEqual('The message or message_callback keyword'
 
629
                             ' parameter is required for commit().', str(e))
 
630
        else:
 
631
            self.fail('exception not raised')
 
632
        cb = self.Callback(u'commit 1', self)
 
633
        tree.commit(message_callback=cb)
 
634
        self.assertTrue(cb.called)
 
635
        repository = tree.branch.repository
 
636
        message = repository.get_revision(tree.last_revision()).message
 
637
        self.assertEqual('commit 1', message)
 
638
 
 
639
    def test_no_callback_pointless(self):
 
640
        """Callback should not be invoked for pointless commit"""
 
641
        tree = self.make_branch_and_tree('.')
 
642
        cb = self.Callback(u'commit 2', self)
 
643
        self.assertRaises(PointlessCommit, tree.commit, message_callback=cb, 
 
644
                          allow_pointless=False)
 
645
        self.assertFalse(cb.called)
 
646
 
 
647
    def test_no_callback_netfailure(self):
 
648
        """Callback should not be invoked if connectivity fails"""
 
649
        tree = self.make_branch_and_tree('.')
 
650
        cb = self.Callback(u'commit 2', self)
 
651
        repository = tree.branch.repository
 
652
        # simulate network failure
 
653
        def raise_(self, arg, arg2):
 
654
            raise errors.NoSuchFile('foo')
 
655
        repository.add_inventory = raise_
 
656
        self.assertRaises(errors.NoSuchFile, tree.commit, message_callback=cb)
 
657
        self.assertFalse(cb.called)