1
# Copyright (C) 2007 Canonical Ltd
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.
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.
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
17
"""Tests for the contract of commit on branches."""
19
from bzrlib.branch import Branch
20
from bzrlib import errors
21
from bzrlib.tests.branch_implementations.test_branch import TestCaseWithBranch
22
from bzrlib.revision import NULL_REVISION
23
from bzrlib.transport import get_transport
24
from bzrlib.delta import TreeDelta
27
class TestCommit(TestCaseWithBranch):
29
def test_commit_nicks(self):
30
"""Nicknames are committed to the revision"""
31
get_transport(self.get_url()).mkdir('bzr.dev')
32
wt = self.make_branch_and_tree('bzr.dev')
34
branch.nick = "My happy branch"
35
wt.commit('My commit respect da nick.')
36
committed = branch.repository.get_revision(branch.last_revision())
37
self.assertEqual(committed.properties["branch-nick"],
41
class TestCommitHook(TestCaseWithBranch):
45
TestCaseWithBranch.setUp(self)
47
def capture_post_commit_hook(self, local, master, old_revno,
48
old_revid, new_revno, new_revid):
49
"""Capture post commit hook calls to self.hook_calls.
51
The call is logged, as is some state of the two branches.
54
local_locked = local.is_locked()
55
local_base = local.base
59
self.hook_calls.append(
60
('post_commit', local_base, master.base, old_revno, old_revid,
61
new_revno, new_revid, local_locked, master.is_locked()))
63
def capture_pre_commit_hook(self, local, master, old_revno, old_revid,
65
tree_delta, future_tree):
66
self.hook_calls.append(('pre_commit', old_revno, old_revid,
67
new_revno, new_revid, tree_delta))
69
def test_post_commit_to_origin(self):
70
tree = self.make_branch_and_memory_tree('branch')
71
Branch.hooks.install_named_hook('post_commit',
72
self.capture_post_commit_hook, None)
75
revid = tree.commit('a revision')
76
# should have had one notification, from origin, and
77
# have the branch locked at notification time.
79
('post_commit', None, tree.branch.base, 0, NULL_REVISION, 1, revid,
85
def test_post_commit_bound(self):
86
master = self.make_branch('master')
87
tree = self.make_branch_and_memory_tree('local')
89
tree.branch.bind(master)
90
except errors.UpgradeRequired:
91
# cant bind this format, the test is irrelevant.
93
Branch.hooks.install_named_hook('post_commit',
94
self.capture_post_commit_hook, None)
97
revid = tree.commit('a revision')
98
# with a bound branch, local is set.
100
('post_commit', tree.branch.base, master.base, 0, NULL_REVISION,
101
1, revid, True, True)
106
def test_post_commit_not_to_origin(self):
107
tree = self.make_branch_and_memory_tree('branch')
110
revid = tree.commit('first revision')
111
Branch.hooks.install_named_hook('post_commit',
112
self.capture_post_commit_hook, None)
113
revid2 = tree.commit('second revision')
114
# having committed from up the branch, we should get the
115
# before and after revnos and revids correctly.
117
('post_commit', None, tree.branch.base, 1, revid, 2, revid2,
123
def test_pre_commit_passes(self):
124
empty_delta = TreeDelta()
125
root_delta = TreeDelta()
126
tree = self.make_branch_and_memory_tree('branch')
129
root_delta.added = [('', tree.path2id(''), 'directory')]
130
Branch.hooks.install_named_hook("pre_commit",
131
self.capture_pre_commit_hook, None)
132
revid1 = tree.commit('first revision')
133
revid2 = tree.commit('second revision')
135
('pre_commit', 0, NULL_REVISION, 1, revid1, root_delta),
136
('pre_commit', 1, revid1, 2, revid2, empty_delta)
141
def test_pre_commit_fails(self):
142
empty_delta = TreeDelta()
143
root_delta = TreeDelta()
144
tree = self.make_branch_and_memory_tree('branch')
147
root_delta.added = [('', tree.path2id(''), 'directory')]
148
class PreCommitException(Exception): pass
149
def hook_func(local, master,
150
old_revno, old_revid, new_revno, new_revid,
151
tree_delta, future_tree):
152
raise PreCommitException(new_revid)
153
Branch.hooks.install_named_hook("pre_commit",
154
self.capture_pre_commit_hook, None)
155
Branch.hooks.install_named_hook("pre_commit", hook_func, None)
156
revids = [None, None, None]
157
# this commit will raise an exception
158
# so the commit is rolled back and revno unchanged
159
err = self.assertRaises(PreCommitException, tree.commit, 'message')
160
# we have to record the revid to use in assertEqual later
162
# unregister all pre_commit hooks
163
Branch.hooks["pre_commit"] = []
164
# and re-register the capture hook
165
Branch.hooks.install_named_hook("pre_commit",
166
self.capture_pre_commit_hook, None)
167
# now these commits should go through
168
for i in range(1, 3):
169
revids[i] = tree.commit('message')
171
('pre_commit', 0, NULL_REVISION, 1, revids[0], root_delta),
172
('pre_commit', 0, NULL_REVISION, 1, revids[1], root_delta),
173
('pre_commit', 1, revids[1], 2, revids[2], empty_delta)
178
def test_pre_commit_delta(self):
179
# This tests the TreeDelta object passed to pre_commit hook.
180
# This does not try to validate data correctness in the delta.
181
self.build_tree(['rootfile', 'dir/', 'dir/subfile'])
182
tree = self.make_branch_and_tree('.')
185
# setting up a playground
186
tree.set_root_id('root_id')
187
tree.add('rootfile', 'rootfile_id')
188
tree.put_file_bytes_non_atomic('rootfile_id', 'abc')
189
tree.add('dir', 'dir_id')
190
tree.add('dir/subfile', 'dir_subfile_id')
191
tree.mkdir('to_be_unversioned', 'to_be_unversioned_id')
192
tree.put_file_bytes_non_atomic('dir_subfile_id', 'def')
193
revid1 = tree.commit('first revision')
200
tree.put_file_bytes_non_atomic('rootfile_id', 'jkl')
201
tree.rename_one('dir/subfile', 'dir/subfile_renamed')
202
tree.unversion(['to_be_unversioned_id'])
203
tree.mkdir('added_dir', 'added_dir_id')
204
# start to capture pre_commit delta
205
Branch.hooks.install_named_hook("pre_commit",
206
self.capture_pre_commit_hook, None)
207
revid2 = tree.commit('second revision')
211
expected_delta = TreeDelta()
212
expected_delta.added = [('added_dir', 'added_dir_id', 'directory')]
213
expected_delta.removed = [('to_be_unversioned',
214
'to_be_unversioned_id', 'directory')]
215
expected_delta.renamed = [('dir/subfile', 'dir/subfile_renamed',
216
'dir_subfile_id', 'file', False, False)]
217
expected_delta.modified=[('rootfile', 'rootfile_id', 'file', True,
219
self.assertEqual([('pre_commit', 1, revid1, 2, revid2,
220
expected_delta)], self.hook_calls)