~bzr-pqm/bzr/bzr.dev

2245.1.1 by Robert Collins
New Branch hooks facility, with one initial hook 'set_rh' which triggers
1
# Copyright (C) 2007 Canonical Ltd
2
#
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.
7
#
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.
12
#
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
4183.7.1 by Sabin Iacob
update FSF mailing address
15
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
2245.1.1 by Robert Collins
New Branch hooks facility, with one initial hook 'set_rh' which triggers
16
2245.1.2 by Robert Collins
Remove the static DefaultHooks method from Branch, replacing it with a derived dict BranchHooks object, which is easier to use and provides a place to put the policy-checking add method discussed on list.
17
"""Tests that branch classes implement hook callouts correctly."""
2245.1.1 by Robert Collins
New Branch hooks facility, with one initial hook 'set_rh' which triggers
18
3681.1.3 by Robert Collins
Update branch open tests to accomodate stacking.
19
from bzrlib.branch import Branch, ChangeBranchTipParams
3577.1.1 by Andrew Bennetts
Cherry-pick TipChangeRejected changes from pre-branch-tip-changed-hook loom.
20
from bzrlib.errors import HookFailed, TipChangeRejected
3681.1.3 by Robert Collins
Update branch open tests to accomodate stacking.
21
from bzrlib.remote import RemoteBranch
3331.1.2 by James Henstridge
Add calls to set_last_revision_info hook to both BzrBranch and
22
from bzrlib.revision import NULL_REVISION
4032.3.2 by Robert Collins
Create and use a RPC call to create branches on bzr servers rather than using VFS calls.
23
from bzrlib.smart import server
2245.1.1 by Robert Collins
New Branch hooks facility, with one initial hook 'set_rh' which triggers
24
from bzrlib.tests import TestCaseWithMemoryTransport
25
26
4005.2.1 by Robert Collins
Fix RemoteBranch to be used correctly in tests using bzr+ssh, to fire off Branch hooks correctly, and improve the branch_implementations tests to check that making a branch gets the right format under test.
27
class ChangeBranchTipTestCase(TestCaseWithMemoryTransport):
28
    """Base TestCase for testing pre/post_change_branch_tip hooks."""
29
30
    def install_logging_hook(self, prefix):
31
        """Add a hook that logs calls made to it.
32
33
        :returns: the list that the calls will be appended to.
34
        """
35
        hook_calls = []
36
        Branch.hooks.install_named_hook(
37
            prefix + '_change_branch_tip', hook_calls.append, None)
38
        return hook_calls
39
40
    def make_branch_with_revision_ids(self, *revision_ids):
41
        """Makes a branch with the given commits."""
42
        tree = self.make_branch_and_memory_tree('source')
43
        tree.lock_write()
44
        tree.add('')
45
        for revision_id in revision_ids:
46
            tree.commit(u'Message of ' + revision_id.decode('utf8'),
47
                        rev_id=revision_id)
48
        tree.unlock()
49
        branch = tree.branch
50
        return branch
51
52
    def assertHookCalls(self, expected_params, branch, hook_calls=None,
53
        pre=False):
54
        if hook_calls is None:
55
            hook_calls = self.hook_calls
56
        if isinstance(branch, RemoteBranch):
57
            # For a remote branch, both the server and the client will raise
58
            # this hook, and we see both in the test environment. The remote
59
            # instance comes in between the clients - the client doe pre, the
60
            # server does pre, the server does post, the client does post.
61
            if pre:
62
                offset = 0
63
            else:
64
                offset = 1
65
            self.assertEqual(expected_params, hook_calls[offset])
66
            self.assertEqual(2, len(hook_calls))
67
        else:
68
            self.assertEqual([expected_params], hook_calls)
69
70
71
class TestSetRevisionHistoryHook(ChangeBranchTipTestCase):
2245.1.1 by Robert Collins
New Branch hooks facility, with one initial hook 'set_rh' which triggers
72
73
    def setUp(self):
74
        self.hook_calls = []
75
        TestCaseWithMemoryTransport.setUp(self)
76
77
    def capture_set_rh_hook(self, branch, rev_history):
2246.1.3 by Robert Collins
New branch hooks: post_push, post_pull, post_commit, post_uncommit. These
78
        """Capture post set-rh hook calls to self.hook_calls.
3943.8.1 by Marius Kruger
remove all trailing whitespace from bzr source
79
2246.1.3 by Robert Collins
New branch hooks: post_push, post_pull, post_commit, post_uncommit. These
80
        The call is logged, as is some state of the branch.
2245.1.1 by Robert Collins
New Branch hooks facility, with one initial hook 'set_rh' which triggers
81
        """
82
        self.hook_calls.append(
83
            ('set_rh', branch, rev_history, branch.is_locked()))
84
85
    def test_set_rh_empty_history(self):
86
        branch = self.make_branch('source')
3256.2.15 by Daniel Watkins
Updated uses of Hooks.install_hook to Hooks.install_named_hook in tests.branch_implementation.test_hooks.
87
        Branch.hooks.install_named_hook('set_rh', self.capture_set_rh_hook,
88
                                        None)
2245.1.1 by Robert Collins
New Branch hooks facility, with one initial hook 'set_rh' which triggers
89
        branch.set_revision_history([])
4005.2.1 by Robert Collins
Fix RemoteBranch to be used correctly in tests using bzr+ssh, to fire off Branch hooks correctly, and improve the branch_implementations tests to check that making a branch gets the right format under test.
90
        expected_params = ('set_rh', branch, [], True)
91
        self.assertHookCalls(expected_params, branch)
2245.1.1 by Robert Collins
New Branch hooks facility, with one initial hook 'set_rh' which triggers
92
93
    def test_set_rh_nonempty_history(self):
2230.3.20 by Aaron Bentley
Add hooking for set_revision_history
94
        tree = self.make_branch_and_memory_tree('source')
95
        tree.lock_write()
96
        tree.add('')
2696.3.7 by Martin Pool
Update hook test to cope with branches that can't set their last revision to one that's not present
97
        tree.commit('another commit', rev_id='f\xc2\xb5')
2230.3.20 by Aaron Bentley
Add hooking for set_revision_history
98
        tree.commit('empty commit', rev_id='foo')
99
        tree.unlock()
100
        branch = tree.branch
3256.2.15 by Daniel Watkins
Updated uses of Hooks.install_hook to Hooks.install_named_hook in tests.branch_implementation.test_hooks.
101
        Branch.hooks.install_named_hook('set_rh', self.capture_set_rh_hook,
102
                                        None)
2696.3.7 by Martin Pool
Update hook test to cope with branches that can't set their last revision to one that's not present
103
        # some branches require that their history be set to a revision in the
104
        # repository
2309.4.10 by John Arbash Meinel
(fixed) Fix the last few tests that were explicitly passing around unicode ids
105
        branch.set_revision_history(['f\xc2\xb5'])
4005.2.1 by Robert Collins
Fix RemoteBranch to be used correctly in tests using bzr+ssh, to fire off Branch hooks correctly, and improve the branch_implementations tests to check that making a branch gets the right format under test.
106
        expected_params =('set_rh', branch, ['f\xc2\xb5'], True)
107
        self.assertHookCalls(expected_params, branch)
2245.1.1 by Robert Collins
New Branch hooks facility, with one initial hook 'set_rh' which triggers
108
109
    def test_set_rh_branch_is_locked(self):
110
        branch = self.make_branch('source')
3256.2.15 by Daniel Watkins
Updated uses of Hooks.install_hook to Hooks.install_named_hook in tests.branch_implementation.test_hooks.
111
        Branch.hooks.install_named_hook('set_rh', self.capture_set_rh_hook,
112
                                        None)
2245.1.1 by Robert Collins
New Branch hooks facility, with one initial hook 'set_rh' which triggers
113
        branch.set_revision_history([])
4005.2.1 by Robert Collins
Fix RemoteBranch to be used correctly in tests using bzr+ssh, to fire off Branch hooks correctly, and improve the branch_implementations tests to check that making a branch gets the right format under test.
114
        expected_params = ('set_rh', branch, [], True)
115
        self.assertHookCalls(expected_params, branch)
2245.1.1 by Robert Collins
New Branch hooks facility, with one initial hook 'set_rh' which triggers
116
117
    def test_set_rh_calls_all_hooks_no_errors(self):
118
        branch = self.make_branch('source')
3256.2.15 by Daniel Watkins
Updated uses of Hooks.install_hook to Hooks.install_named_hook in tests.branch_implementation.test_hooks.
119
        Branch.hooks.install_named_hook('set_rh', self.capture_set_rh_hook,
120
                                        None)
121
        Branch.hooks.install_named_hook('set_rh', self.capture_set_rh_hook,
122
                                        None)
2245.1.1 by Robert Collins
New Branch hooks facility, with one initial hook 'set_rh' which triggers
123
        branch.set_revision_history([])
4005.2.1 by Robert Collins
Fix RemoteBranch to be used correctly in tests using bzr+ssh, to fire off Branch hooks correctly, and improve the branch_implementations tests to check that making a branch gets the right format under test.
124
        expected_calls = [('set_rh', branch, [], True),
125
            ('set_rh', branch, [], True),
126
            ]
127
        if isinstance(branch, RemoteBranch):
128
            # For a remote branch, both the server and the client will raise
129
            # set_rh, and the server will do so first because that is where
130
            # the change takes place.
131
            self.assertEqual(expected_calls, self.hook_calls[2:])
132
            self.assertEqual(4, len(self.hook_calls))
133
        else:
134
            self.assertEqual(expected_calls, self.hook_calls)
3517.2.5 by Andrew Bennetts
Reduce duplication in test_hooks a little.
135
136
3681.1.1 by Robert Collins
Create a new hook Branch.open. (Robert Collins)
137
class TestOpen(TestCaseWithMemoryTransport):
138
139
    def capture_hook(self, branch):
140
        self.hook_calls.append(branch)
141
142
    def install_hook(self):
143
        self.hook_calls = []
144
        Branch.hooks.install_named_hook('open', self.capture_hook, None)
145
146
    def test_create(self):
147
        self.install_hook()
148
        b = self.make_branch('.')
4005.2.1 by Robert Collins
Fix RemoteBranch to be used correctly in tests using bzr+ssh, to fire off Branch hooks correctly, and improve the branch_implementations tests to check that making a branch gets the right format under test.
149
        if isinstance(b, RemoteBranch):
150
            # RemoteBranch creation:
4032.3.2 by Robert Collins
Create and use a RPC call to create branches on bzr servers rather than using VFS calls.
151
            if (self.transport_readonly_server ==
152
                server.ReadonlySmartTCPServer_for_testing_v2_only):
153
                # Older servers:
4084.2.3 by Andrew Bennetts
Adjust test_hooks.py for create_branch RPC.
154
                self.assertEqual(3, len(self.hook_calls))
155
                # creates the branch via the VFS (for older servers)
4032.3.2 by Robert Collins
Create and use a RPC call to create branches on bzr servers rather than using VFS calls.
156
                self.assertEqual(b._real_branch, self.hook_calls[0])
4084.2.3 by Andrew Bennetts
Adjust test_hooks.py for create_branch RPC.
157
                # creates a RemoteBranch object
158
                self.assertEqual(b, self.hook_calls[1])
159
                # get_stacked_on_url RPC
160
                self.assertRealBranch(self.hook_calls[2])
4032.3.2 by Robert Collins
Create and use a RPC call to create branches on bzr servers rather than using VFS calls.
161
            else:
4084.2.3 by Andrew Bennetts
Adjust test_hooks.py for create_branch RPC.
162
                self.assertEqual(2, len(self.hook_calls))
163
                # create_branch RPC
164
                self.assertRealBranch(self.hook_calls[0])
165
                # create RemoteBranch locally
166
                self.assertEqual(b, self.hook_calls[1])
4005.2.1 by Robert Collins
Fix RemoteBranch to be used correctly in tests using bzr+ssh, to fire off Branch hooks correctly, and improve the branch_implementations tests to check that making a branch gets the right format under test.
167
        else:
168
            self.assertEqual([b], self.hook_calls)
3681.1.1 by Robert Collins
Create a new hook Branch.open. (Robert Collins)
169
170
    def test_open(self):
171
        branch_url = self.make_branch('.').bzrdir.root_transport.base
172
        self.install_hook()
173
        b = Branch.open(branch_url)
3681.1.3 by Robert Collins
Update branch open tests to accomodate stacking.
174
        if isinstance(b, RemoteBranch):
4084.2.3 by Andrew Bennetts
Adjust test_hooks.py for create_branch RPC.
175
            self.assertEqual(3, len(self.hook_calls))
176
            # open_branchV2 RPC
177
            self.assertRealBranch(self.hook_calls[0])
178
            # create RemoteBranch locally
179
            self.assertEqual(b, self.hook_calls[1])
180
            # get_stacked_on_url RPC
181
            self.assertRealBranch(self.hook_calls[2])
3681.1.3 by Robert Collins
Update branch open tests to accomodate stacking.
182
        else:
183
            self.assertEqual([b], self.hook_calls)
3681.1.1 by Robert Collins
Create a new hook Branch.open. (Robert Collins)
184
4084.2.3 by Andrew Bennetts
Adjust test_hooks.py for create_branch RPC.
185
    def assertRealBranch(self, b):
186
        # Branches opened on the server don't have comparable URLs, so we just
187
        # assert that it is not a RemoteBranch.
188
        self.assertIsInstance(b, Branch)
189
        self.assertFalse(isinstance(b, RemoteBranch))
4005.2.1 by Robert Collins
Fix RemoteBranch to be used correctly in tests using bzr+ssh, to fire off Branch hooks correctly, and improve the branch_implementations tests to check that making a branch gets the right format under test.
190
3681.1.1 by Robert Collins
Create a new hook Branch.open. (Robert Collins)
191
3517.2.5 by Andrew Bennetts
Reduce duplication in test_hooks a little.
192
class TestPreChangeBranchTip(ChangeBranchTipTestCase):
3517.2.3 by Andrew Bennetts
Better tests for {pre,post}_change_branch_tip hooks.
193
    """Tests for pre_change_branch_tip hook.
3943.8.1 by Marius Kruger
remove all trailing whitespace from bzr source
194
3517.2.3 by Andrew Bennetts
Better tests for {pre,post}_change_branch_tip hooks.
195
    Most of these tests are very similar to the tests in
196
    TestPostChangeBranchTip.
197
    """
198
199
    def test_hook_runs_before_change(self):
200
        """The hook runs *before* the branch's last_revision_info has changed.
201
        """
202
        branch = self.make_branch_with_revision_ids('revid-one')
203
        def assertBranchAtRevision1(params):
204
            self.assertEquals(
205
                (1, 'revid-one'), params.branch.last_revision_info())
206
        Branch.hooks.install_named_hook(
207
            'pre_change_branch_tip', assertBranchAtRevision1, None)
208
        branch.set_last_revision_info(0, NULL_REVISION)
209
3577.1.1 by Andrew Bennetts
Cherry-pick TipChangeRejected changes from pre-branch-tip-changed-hook loom.
210
    def test_hook_failure_prevents_change(self):
3517.2.3 by Andrew Bennetts
Better tests for {pre,post}_change_branch_tip hooks.
211
        """If a hook raises an exception, the change does not take effect.
3943.8.1 by Marius Kruger
remove all trailing whitespace from bzr source
212
3577.1.1 by Andrew Bennetts
Cherry-pick TipChangeRejected changes from pre-branch-tip-changed-hook loom.
213
        Also, a HookFailed exception will be raised.
3517.2.3 by Andrew Bennetts
Better tests for {pre,post}_change_branch_tip hooks.
214
        """
3517.2.2 by Andrew Bennetts
Add test for a pre_change_branch_tip hook rejecting a change.
215
        branch = self.make_branch_with_revision_ids(
216
            'one-\xc2\xb5', 'two-\xc2\xb5')
217
        class PearShapedError(Exception):
218
            pass
219
        def hook_that_raises(params):
220
            raise PearShapedError()
221
        Branch.hooks.install_named_hook(
222
            'pre_change_branch_tip', hook_that_raises, None)
3577.1.1 by Andrew Bennetts
Cherry-pick TipChangeRejected changes from pre-branch-tip-changed-hook loom.
223
        hook_failed_exc = self.assertRaises(
224
            HookFailed, branch.set_last_revision_info, 0, NULL_REVISION)
225
        self.assertIsInstance(hook_failed_exc.exc_value, PearShapedError)
3517.2.2 by Andrew Bennetts
Add test for a pre_change_branch_tip hook rejecting a change.
226
        # The revision info is unchanged.
227
        self.assertEqual((2, 'two-\xc2\xb5'), branch.last_revision_info())
3943.8.1 by Marius Kruger
remove all trailing whitespace from bzr source
228
3517.2.5 by Andrew Bennetts
Reduce duplication in test_hooks a little.
229
    def test_empty_history(self):
3517.2.1 by Andrew Bennetts
Quick draft of pre_change_branch_tip hook.
230
        branch = self.make_branch('source')
3517.2.5 by Andrew Bennetts
Reduce duplication in test_hooks a little.
231
        hook_calls = self.install_logging_hook('pre')
3517.2.1 by Andrew Bennetts
Quick draft of pre_change_branch_tip hook.
232
        branch.set_last_revision_info(0, NULL_REVISION)
3517.2.3 by Andrew Bennetts
Better tests for {pre,post}_change_branch_tip hooks.
233
        expected_params = ChangeBranchTipParams(
234
            branch, 0, 0, NULL_REVISION, NULL_REVISION)
4005.2.1 by Robert Collins
Fix RemoteBranch to be used correctly in tests using bzr+ssh, to fire off Branch hooks correctly, and improve the branch_implementations tests to check that making a branch gets the right format under test.
235
        self.assertHookCalls(expected_params, branch, hook_calls, pre=True)
3517.2.1 by Andrew Bennetts
Quick draft of pre_change_branch_tip hook.
236
3517.2.5 by Andrew Bennetts
Reduce duplication in test_hooks a little.
237
    def test_nonempty_history(self):
3517.2.3 by Andrew Bennetts
Better tests for {pre,post}_change_branch_tip hooks.
238
        # some branches require that their history be set to a revision in the
239
        # repository, so we need to make a branch with non-empty history for
240
        # this test.
3517.2.2 by Andrew Bennetts
Add test for a pre_change_branch_tip hook rejecting a change.
241
        branch = self.make_branch_with_revision_ids(
242
            'one-\xc2\xb5', 'two-\xc2\xb5')
3517.2.5 by Andrew Bennetts
Reduce duplication in test_hooks a little.
243
        hook_calls = self.install_logging_hook('pre')
3517.2.2 by Andrew Bennetts
Add test for a pre_change_branch_tip hook rejecting a change.
244
        branch.set_last_revision_info(1, 'one-\xc2\xb5')
3517.2.3 by Andrew Bennetts
Better tests for {pre,post}_change_branch_tip hooks.
245
        expected_params = ChangeBranchTipParams(
246
            branch, 2, 1, 'two-\xc2\xb5', 'one-\xc2\xb5')
4005.2.1 by Robert Collins
Fix RemoteBranch to be used correctly in tests using bzr+ssh, to fire off Branch hooks correctly, and improve the branch_implementations tests to check that making a branch gets the right format under test.
247
        self.assertHookCalls(expected_params, branch, hook_calls, pre=True)
3517.2.1 by Andrew Bennetts
Quick draft of pre_change_branch_tip hook.
248
3517.2.5 by Andrew Bennetts
Reduce duplication in test_hooks a little.
249
    def test_branch_is_locked(self):
3517.2.1 by Andrew Bennetts
Quick draft of pre_change_branch_tip hook.
250
        branch = self.make_branch('source')
3517.2.3 by Andrew Bennetts
Better tests for {pre,post}_change_branch_tip hooks.
251
        def assertBranchIsLocked(params):
252
            self.assertTrue(params.branch.is_locked())
3517.2.1 by Andrew Bennetts
Quick draft of pre_change_branch_tip hook.
253
        Branch.hooks.install_named_hook(
3517.2.3 by Andrew Bennetts
Better tests for {pre,post}_change_branch_tip hooks.
254
            'pre_change_branch_tip', assertBranchIsLocked, None)
3517.2.1 by Andrew Bennetts
Quick draft of pre_change_branch_tip hook.
255
        branch.set_last_revision_info(0, NULL_REVISION)
256
3517.2.5 by Andrew Bennetts
Reduce duplication in test_hooks a little.
257
    def test_calls_all_hooks_no_errors(self):
258
        """If multiple hooks are registered, all are called (if none raise
259
        errors).
260
        """
3517.2.1 by Andrew Bennetts
Quick draft of pre_change_branch_tip hook.
261
        branch = self.make_branch('source')
3517.2.5 by Andrew Bennetts
Reduce duplication in test_hooks a little.
262
        hook_calls_1 = self.install_logging_hook('pre')
263
        hook_calls_2 = self.install_logging_hook('pre')
3517.2.3 by Andrew Bennetts
Better tests for {pre,post}_change_branch_tip hooks.
264
        self.assertIsNot(hook_calls_1, hook_calls_2)
3517.2.1 by Andrew Bennetts
Quick draft of pre_change_branch_tip hook.
265
        branch.set_last_revision_info(0, NULL_REVISION)
3517.2.3 by Andrew Bennetts
Better tests for {pre,post}_change_branch_tip hooks.
266
        # Both hooks are called.
4005.2.1 by Robert Collins
Fix RemoteBranch to be used correctly in tests using bzr+ssh, to fire off Branch hooks correctly, and improve the branch_implementations tests to check that making a branch gets the right format under test.
267
        if isinstance(branch, RemoteBranch):
268
            count = 2
269
        else:
270
            count = 1
271
        self.assertEqual(len(hook_calls_1), count)
272
        self.assertEqual(len(hook_calls_2), count)
3517.2.1 by Andrew Bennetts
Quick draft of pre_change_branch_tip hook.
273
3577.1.1 by Andrew Bennetts
Cherry-pick TipChangeRejected changes from pre-branch-tip-changed-hook loom.
274
    def test_explicit_reject_by_hook(self):
275
        """If a hook raises TipChangeRejected, the change does not take effect.
3943.8.1 by Marius Kruger
remove all trailing whitespace from bzr source
276
3577.1.1 by Andrew Bennetts
Cherry-pick TipChangeRejected changes from pre-branch-tip-changed-hook loom.
277
        TipChangeRejected exceptions are propagated, not wrapped in HookFailed.
278
        """
279
        branch = self.make_branch_with_revision_ids(
280
            'one-\xc2\xb5', 'two-\xc2\xb5')
281
        def hook_that_rejects(params):
282
            raise TipChangeRejected('rejection message')
283
        Branch.hooks.install_named_hook(
284
            'pre_change_branch_tip', hook_that_rejects, None)
285
        self.assertRaises(
286
            TipChangeRejected, branch.set_last_revision_info, 0, NULL_REVISION)
287
        # The revision info is unchanged.
288
        self.assertEqual((2, 'two-\xc2\xb5'), branch.last_revision_info())
3943.8.1 by Marius Kruger
remove all trailing whitespace from bzr source
289
3517.2.1 by Andrew Bennetts
Quick draft of pre_change_branch_tip hook.
290
3517.2.5 by Andrew Bennetts
Reduce duplication in test_hooks a little.
291
class TestPostChangeBranchTip(ChangeBranchTipTestCase):
3517.2.3 by Andrew Bennetts
Better tests for {pre,post}_change_branch_tip hooks.
292
    """Tests for post_change_branch_tip hook.
293
294
    Most of these tests are very similar to the tests in
295
    TestPostChangeBranchTip.
296
    """
297
298
    def test_hook_runs_after_change(self):
299
        """The hook runs *after* the branch's last_revision_info has changed.
300
        """
301
        branch = self.make_branch_with_revision_ids('revid-one')
302
        def assertBranchAtRevision1(params):
303
            self.assertEquals(
304
                (0, NULL_REVISION), params.branch.last_revision_info())
3256.2.26 by Daniel Watkins
Updated tests to use install_named_hook.
305
        Branch.hooks.install_named_hook(
3517.2.3 by Andrew Bennetts
Better tests for {pre,post}_change_branch_tip hooks.
306
            'post_change_branch_tip', assertBranchAtRevision1, None)
307
        branch.set_last_revision_info(0, NULL_REVISION)
308
3517.2.5 by Andrew Bennetts
Reduce duplication in test_hooks a little.
309
    def test_empty_history(self):
3517.2.3 by Andrew Bennetts
Better tests for {pre,post}_change_branch_tip hooks.
310
        branch = self.make_branch('source')
3517.2.5 by Andrew Bennetts
Reduce duplication in test_hooks a little.
311
        hook_calls = self.install_logging_hook('post')
3517.2.3 by Andrew Bennetts
Better tests for {pre,post}_change_branch_tip hooks.
312
        branch.set_last_revision_info(0, NULL_REVISION)
313
        expected_params = ChangeBranchTipParams(
314
            branch, 0, 0, NULL_REVISION, NULL_REVISION)
4005.2.1 by Robert Collins
Fix RemoteBranch to be used correctly in tests using bzr+ssh, to fire off Branch hooks correctly, and improve the branch_implementations tests to check that making a branch gets the right format under test.
315
        self.assertHookCalls(expected_params, branch, hook_calls)
3517.2.3 by Andrew Bennetts
Better tests for {pre,post}_change_branch_tip hooks.
316
3517.2.5 by Andrew Bennetts
Reduce duplication in test_hooks a little.
317
    def test_nonempty_history(self):
3331.1.2 by James Henstridge
Add calls to set_last_revision_info hook to both BzrBranch and
318
        # some branches require that their history be set to a revision in the
3517.2.3 by Andrew Bennetts
Better tests for {pre,post}_change_branch_tip hooks.
319
        # repository, so we need to make a branch with non-empty history for
320
        # this test.
321
        branch = self.make_branch_with_revision_ids(
322
            'one-\xc2\xb5', 'two-\xc2\xb5')
3517.2.5 by Andrew Bennetts
Reduce duplication in test_hooks a little.
323
        hook_calls = self.install_logging_hook('post')
3517.2.3 by Andrew Bennetts
Better tests for {pre,post}_change_branch_tip hooks.
324
        branch.set_last_revision_info(1, 'one-\xc2\xb5')
325
        expected_params = ChangeBranchTipParams(
326
            branch, 2, 1, 'two-\xc2\xb5', 'one-\xc2\xb5')
4005.2.1 by Robert Collins
Fix RemoteBranch to be used correctly in tests using bzr+ssh, to fire off Branch hooks correctly, and improve the branch_implementations tests to check that making a branch gets the right format under test.
327
        self.assertHookCalls(expected_params, branch, hook_calls)
3517.2.3 by Andrew Bennetts
Better tests for {pre,post}_change_branch_tip hooks.
328
3517.2.5 by Andrew Bennetts
Reduce duplication in test_hooks a little.
329
    def test_branch_is_locked(self):
3517.2.3 by Andrew Bennetts
Better tests for {pre,post}_change_branch_tip hooks.
330
        """The branch passed to the hook is locked."""
331
        branch = self.make_branch('source')
332
        def assertBranchIsLocked(params):
333
            self.assertTrue(params.branch.is_locked())
334
        Branch.hooks.install_named_hook(
3517.2.4 by Andrew Bennetts
Fix typo.
335
            'post_change_branch_tip', assertBranchIsLocked, None)
3517.2.3 by Andrew Bennetts
Better tests for {pre,post}_change_branch_tip hooks.
336
        branch.set_last_revision_info(0, NULL_REVISION)
337
3517.2.5 by Andrew Bennetts
Reduce duplication in test_hooks a little.
338
    def test_calls_all_hooks_no_errors(self):
339
        """If multiple hooks are registered, all are called (if none raise
340
        errors).
341
        """
3517.2.3 by Andrew Bennetts
Better tests for {pre,post}_change_branch_tip hooks.
342
        branch = self.make_branch('source')
3517.2.5 by Andrew Bennetts
Reduce duplication in test_hooks a little.
343
        hook_calls_1 = self.install_logging_hook('post')
344
        hook_calls_2 = self.install_logging_hook('post')
3517.2.3 by Andrew Bennetts
Better tests for {pre,post}_change_branch_tip hooks.
345
        self.assertIsNot(hook_calls_1, hook_calls_2)
346
        branch.set_last_revision_info(0, NULL_REVISION)
347
        # Both hooks are called.
4005.2.1 by Robert Collins
Fix RemoteBranch to be used correctly in tests using bzr+ssh, to fire off Branch hooks correctly, and improve the branch_implementations tests to check that making a branch gets the right format under test.
348
        if isinstance(branch, RemoteBranch):
349
            count = 2
350
        else:
351
            count = 1
352
        self.assertEqual(len(hook_calls_1), count)
353
        self.assertEqual(len(hook_calls_2), count)
3577.1.1 by Andrew Bennetts
Cherry-pick TipChangeRejected changes from pre-branch-tip-changed-hook loom.
354
355
356
class TestAllMethodsThatChangeTipWillRunHooks(ChangeBranchTipTestCase):
357
    """Every method of Branch that changes a branch tip will invoke the
358
    pre/post_change_branch_tip hooks.
359
    """
360
361
    def setUp(self):
362
        ChangeBranchTipTestCase.setUp(self)
363
        self.installPreAndPostHooks()
3943.8.1 by Marius Kruger
remove all trailing whitespace from bzr source
364
3577.1.1 by Andrew Bennetts
Cherry-pick TipChangeRejected changes from pre-branch-tip-changed-hook loom.
365
    def installPreAndPostHooks(self):
366
        self.pre_hook_calls = self.install_logging_hook('pre')
367
        self.post_hook_calls = self.install_logging_hook('post')
368
369
    def resetHookCalls(self):
370
        del self.pre_hook_calls[:], self.post_hook_calls[:]
371
4005.2.1 by Robert Collins
Fix RemoteBranch to be used correctly in tests using bzr+ssh, to fire off Branch hooks correctly, and improve the branch_implementations tests to check that making a branch gets the right format under test.
372
    def assertPreAndPostHooksWereInvoked(self, branch, smart_enabled):
373
        """assert that both pre and post hooks were called
374
375
        :param smart_enabled: The method invoked is one that should be
376
            smart server ready.
377
        """
378
        # Check for the number of invocations expected. One invocation is
379
        # local, one is remote (if the branch is remote).
380
        if smart_enabled and isinstance(branch, RemoteBranch):
381
            length = 2
382
        else:
383
            length = 1
384
        self.assertEqual(length, len(self.pre_hook_calls))
385
        self.assertEqual(length, len(self.post_hook_calls))
3577.1.1 by Andrew Bennetts
Cherry-pick TipChangeRejected changes from pre-branch-tip-changed-hook loom.
386
387
    def test_set_revision_history(self):
388
        branch = self.make_branch('')
389
        branch.set_revision_history([])
4005.2.1 by Robert Collins
Fix RemoteBranch to be used correctly in tests using bzr+ssh, to fire off Branch hooks correctly, and improve the branch_implementations tests to check that making a branch gets the right format under test.
390
        self.assertPreAndPostHooksWereInvoked(branch, True)
3577.1.1 by Andrew Bennetts
Cherry-pick TipChangeRejected changes from pre-branch-tip-changed-hook loom.
391
392
    def test_set_last_revision_info(self):
393
        branch = self.make_branch('')
394
        branch.set_last_revision_info(0, NULL_REVISION)
4005.2.1 by Robert Collins
Fix RemoteBranch to be used correctly in tests using bzr+ssh, to fire off Branch hooks correctly, and improve the branch_implementations tests to check that making a branch gets the right format under test.
395
        self.assertPreAndPostHooksWereInvoked(branch, True)
3577.1.1 by Andrew Bennetts
Cherry-pick TipChangeRejected changes from pre-branch-tip-changed-hook loom.
396
397
    def test_generate_revision_history(self):
398
        branch = self.make_branch('')
399
        branch.generate_revision_history(NULL_REVISION)
4005.2.1 by Robert Collins
Fix RemoteBranch to be used correctly in tests using bzr+ssh, to fire off Branch hooks correctly, and improve the branch_implementations tests to check that making a branch gets the right format under test.
400
        # NB: for HPSS protocols < v3, the server does not invoke branch tip
401
        # change events on generate_revision_history, as the change is done
402
        # directly by the client over the VFS.
403
        self.assertPreAndPostHooksWereInvoked(branch, True)
3577.1.1 by Andrew Bennetts
Cherry-pick TipChangeRejected changes from pre-branch-tip-changed-hook loom.
404
405
    def test_pull(self):
406
        source_branch = self.make_branch_with_revision_ids('rev-1', 'rev-2')
407
        self.resetHookCalls()
408
        destination_branch = self.make_branch('destination')
409
        destination_branch.pull(source_branch)
4005.2.1 by Robert Collins
Fix RemoteBranch to be used correctly in tests using bzr+ssh, to fire off Branch hooks correctly, and improve the branch_implementations tests to check that making a branch gets the right format under test.
410
        self.assertPreAndPostHooksWereInvoked(destination_branch, False)
3577.1.1 by Andrew Bennetts
Cherry-pick TipChangeRejected changes from pre-branch-tip-changed-hook loom.
411
412
    def test_push(self):
413
        source_branch = self.make_branch_with_revision_ids('rev-1', 'rev-2')
414
        self.resetHookCalls()
415
        destination_branch = self.make_branch('destination')
416
        source_branch.push(destination_branch)
4005.2.1 by Robert Collins
Fix RemoteBranch to be used correctly in tests using bzr+ssh, to fire off Branch hooks correctly, and improve the branch_implementations tests to check that making a branch gets the right format under test.
417
        self.assertPreAndPostHooksWereInvoked(destination_branch, True)