~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):
4943.1.1 by Robert Collins
Do not fiddle with exceptions in the pre_change_branch_tip hook running code.
211
        """If a hook raises an exception, the change does not take effect."""
3517.2.2 by Andrew Bennetts
Add test for a pre_change_branch_tip hook rejecting a change.
212
        branch = self.make_branch_with_revision_ids(
213
            'one-\xc2\xb5', 'two-\xc2\xb5')
214
        class PearShapedError(Exception):
215
            pass
216
        def hook_that_raises(params):
217
            raise PearShapedError()
218
        Branch.hooks.install_named_hook(
219
            '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.
220
        hook_failed_exc = self.assertRaises(
4943.1.1 by Robert Collins
Do not fiddle with exceptions in the pre_change_branch_tip hook running code.
221
            PearShapedError, branch.set_last_revision_info, 0, NULL_REVISION)
3517.2.2 by Andrew Bennetts
Add test for a pre_change_branch_tip hook rejecting a change.
222
        # The revision info is unchanged.
223
        self.assertEqual((2, 'two-\xc2\xb5'), branch.last_revision_info())
3943.8.1 by Marius Kruger
remove all trailing whitespace from bzr source
224
3517.2.5 by Andrew Bennetts
Reduce duplication in test_hooks a little.
225
    def test_empty_history(self):
3517.2.1 by Andrew Bennetts
Quick draft of pre_change_branch_tip hook.
226
        branch = self.make_branch('source')
3517.2.5 by Andrew Bennetts
Reduce duplication in test_hooks a little.
227
        hook_calls = self.install_logging_hook('pre')
3517.2.1 by Andrew Bennetts
Quick draft of pre_change_branch_tip hook.
228
        branch.set_last_revision_info(0, NULL_REVISION)
3517.2.3 by Andrew Bennetts
Better tests for {pre,post}_change_branch_tip hooks.
229
        expected_params = ChangeBranchTipParams(
230
            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.
231
        self.assertHookCalls(expected_params, branch, hook_calls, pre=True)
3517.2.1 by Andrew Bennetts
Quick draft of pre_change_branch_tip hook.
232
3517.2.5 by Andrew Bennetts
Reduce duplication in test_hooks a little.
233
    def test_nonempty_history(self):
3517.2.3 by Andrew Bennetts
Better tests for {pre,post}_change_branch_tip hooks.
234
        # some branches require that their history be set to a revision in the
235
        # repository, so we need to make a branch with non-empty history for
236
        # this test.
3517.2.2 by Andrew Bennetts
Add test for a pre_change_branch_tip hook rejecting a change.
237
        branch = self.make_branch_with_revision_ids(
238
            'one-\xc2\xb5', 'two-\xc2\xb5')
3517.2.5 by Andrew Bennetts
Reduce duplication in test_hooks a little.
239
        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.
240
        branch.set_last_revision_info(1, 'one-\xc2\xb5')
3517.2.3 by Andrew Bennetts
Better tests for {pre,post}_change_branch_tip hooks.
241
        expected_params = ChangeBranchTipParams(
242
            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.
243
        self.assertHookCalls(expected_params, branch, hook_calls, pre=True)
3517.2.1 by Andrew Bennetts
Quick draft of pre_change_branch_tip hook.
244
3517.2.5 by Andrew Bennetts
Reduce duplication in test_hooks a little.
245
    def test_branch_is_locked(self):
3517.2.1 by Andrew Bennetts
Quick draft of pre_change_branch_tip hook.
246
        branch = self.make_branch('source')
3517.2.3 by Andrew Bennetts
Better tests for {pre,post}_change_branch_tip hooks.
247
        def assertBranchIsLocked(params):
248
            self.assertTrue(params.branch.is_locked())
3517.2.1 by Andrew Bennetts
Quick draft of pre_change_branch_tip hook.
249
        Branch.hooks.install_named_hook(
3517.2.3 by Andrew Bennetts
Better tests for {pre,post}_change_branch_tip hooks.
250
            'pre_change_branch_tip', assertBranchIsLocked, None)
3517.2.1 by Andrew Bennetts
Quick draft of pre_change_branch_tip hook.
251
        branch.set_last_revision_info(0, NULL_REVISION)
252
3517.2.5 by Andrew Bennetts
Reduce duplication in test_hooks a little.
253
    def test_calls_all_hooks_no_errors(self):
254
        """If multiple hooks are registered, all are called (if none raise
255
        errors).
256
        """
3517.2.1 by Andrew Bennetts
Quick draft of pre_change_branch_tip hook.
257
        branch = self.make_branch('source')
3517.2.5 by Andrew Bennetts
Reduce duplication in test_hooks a little.
258
        hook_calls_1 = self.install_logging_hook('pre')
259
        hook_calls_2 = self.install_logging_hook('pre')
3517.2.3 by Andrew Bennetts
Better tests for {pre,post}_change_branch_tip hooks.
260
        self.assertIsNot(hook_calls_1, hook_calls_2)
3517.2.1 by Andrew Bennetts
Quick draft of pre_change_branch_tip hook.
261
        branch.set_last_revision_info(0, NULL_REVISION)
3517.2.3 by Andrew Bennetts
Better tests for {pre,post}_change_branch_tip hooks.
262
        # 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.
263
        if isinstance(branch, RemoteBranch):
264
            count = 2
265
        else:
266
            count = 1
267
        self.assertEqual(len(hook_calls_1), count)
268
        self.assertEqual(len(hook_calls_2), count)
3517.2.1 by Andrew Bennetts
Quick draft of pre_change_branch_tip hook.
269
3577.1.1 by Andrew Bennetts
Cherry-pick TipChangeRejected changes from pre-branch-tip-changed-hook loom.
270
    def test_explicit_reject_by_hook(self):
271
        """If a hook raises TipChangeRejected, the change does not take effect.
3943.8.1 by Marius Kruger
remove all trailing whitespace from bzr source
272
3577.1.1 by Andrew Bennetts
Cherry-pick TipChangeRejected changes from pre-branch-tip-changed-hook loom.
273
        TipChangeRejected exceptions are propagated, not wrapped in HookFailed.
274
        """
275
        branch = self.make_branch_with_revision_ids(
276
            'one-\xc2\xb5', 'two-\xc2\xb5')
277
        def hook_that_rejects(params):
278
            raise TipChangeRejected('rejection message')
279
        Branch.hooks.install_named_hook(
280
            'pre_change_branch_tip', hook_that_rejects, None)
281
        self.assertRaises(
282
            TipChangeRejected, branch.set_last_revision_info, 0, NULL_REVISION)
283
        # The revision info is unchanged.
284
        self.assertEqual((2, 'two-\xc2\xb5'), branch.last_revision_info())
3943.8.1 by Marius Kruger
remove all trailing whitespace from bzr source
285
3517.2.1 by Andrew Bennetts
Quick draft of pre_change_branch_tip hook.
286
3517.2.5 by Andrew Bennetts
Reduce duplication in test_hooks a little.
287
class TestPostChangeBranchTip(ChangeBranchTipTestCase):
3517.2.3 by Andrew Bennetts
Better tests for {pre,post}_change_branch_tip hooks.
288
    """Tests for post_change_branch_tip hook.
289
290
    Most of these tests are very similar to the tests in
291
    TestPostChangeBranchTip.
292
    """
293
294
    def test_hook_runs_after_change(self):
295
        """The hook runs *after* the branch's last_revision_info has changed.
296
        """
297
        branch = self.make_branch_with_revision_ids('revid-one')
298
        def assertBranchAtRevision1(params):
299
            self.assertEquals(
300
                (0, NULL_REVISION), params.branch.last_revision_info())
3256.2.26 by Daniel Watkins
Updated tests to use install_named_hook.
301
        Branch.hooks.install_named_hook(
3517.2.3 by Andrew Bennetts
Better tests for {pre,post}_change_branch_tip hooks.
302
            'post_change_branch_tip', assertBranchAtRevision1, None)
303
        branch.set_last_revision_info(0, NULL_REVISION)
304
3517.2.5 by Andrew Bennetts
Reduce duplication in test_hooks a little.
305
    def test_empty_history(self):
3517.2.3 by Andrew Bennetts
Better tests for {pre,post}_change_branch_tip hooks.
306
        branch = self.make_branch('source')
3517.2.5 by Andrew Bennetts
Reduce duplication in test_hooks a little.
307
        hook_calls = self.install_logging_hook('post')
3517.2.3 by Andrew Bennetts
Better tests for {pre,post}_change_branch_tip hooks.
308
        branch.set_last_revision_info(0, NULL_REVISION)
309
        expected_params = ChangeBranchTipParams(
310
            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.
311
        self.assertHookCalls(expected_params, branch, hook_calls)
3517.2.3 by Andrew Bennetts
Better tests for {pre,post}_change_branch_tip hooks.
312
3517.2.5 by Andrew Bennetts
Reduce duplication in test_hooks a little.
313
    def test_nonempty_history(self):
3331.1.2 by James Henstridge
Add calls to set_last_revision_info hook to both BzrBranch and
314
        # 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.
315
        # repository, so we need to make a branch with non-empty history for
316
        # this test.
317
        branch = self.make_branch_with_revision_ids(
318
            'one-\xc2\xb5', 'two-\xc2\xb5')
3517.2.5 by Andrew Bennetts
Reduce duplication in test_hooks a little.
319
        hook_calls = self.install_logging_hook('post')
3517.2.3 by Andrew Bennetts
Better tests for {pre,post}_change_branch_tip hooks.
320
        branch.set_last_revision_info(1, 'one-\xc2\xb5')
321
        expected_params = ChangeBranchTipParams(
322
            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.
323
        self.assertHookCalls(expected_params, branch, hook_calls)
3517.2.3 by Andrew Bennetts
Better tests for {pre,post}_change_branch_tip hooks.
324
3517.2.5 by Andrew Bennetts
Reduce duplication in test_hooks a little.
325
    def test_branch_is_locked(self):
3517.2.3 by Andrew Bennetts
Better tests for {pre,post}_change_branch_tip hooks.
326
        """The branch passed to the hook is locked."""
327
        branch = self.make_branch('source')
328
        def assertBranchIsLocked(params):
329
            self.assertTrue(params.branch.is_locked())
330
        Branch.hooks.install_named_hook(
3517.2.4 by Andrew Bennetts
Fix typo.
331
            'post_change_branch_tip', assertBranchIsLocked, None)
3517.2.3 by Andrew Bennetts
Better tests for {pre,post}_change_branch_tip hooks.
332
        branch.set_last_revision_info(0, NULL_REVISION)
333
3517.2.5 by Andrew Bennetts
Reduce duplication in test_hooks a little.
334
    def test_calls_all_hooks_no_errors(self):
335
        """If multiple hooks are registered, all are called (if none raise
336
        errors).
337
        """
3517.2.3 by Andrew Bennetts
Better tests for {pre,post}_change_branch_tip hooks.
338
        branch = self.make_branch('source')
3517.2.5 by Andrew Bennetts
Reduce duplication in test_hooks a little.
339
        hook_calls_1 = self.install_logging_hook('post')
340
        hook_calls_2 = self.install_logging_hook('post')
3517.2.3 by Andrew Bennetts
Better tests for {pre,post}_change_branch_tip hooks.
341
        self.assertIsNot(hook_calls_1, hook_calls_2)
342
        branch.set_last_revision_info(0, NULL_REVISION)
343
        # 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.
344
        if isinstance(branch, RemoteBranch):
345
            count = 2
346
        else:
347
            count = 1
348
        self.assertEqual(len(hook_calls_1), count)
349
        self.assertEqual(len(hook_calls_2), count)
3577.1.1 by Andrew Bennetts
Cherry-pick TipChangeRejected changes from pre-branch-tip-changed-hook loom.
350
351
352
class TestAllMethodsThatChangeTipWillRunHooks(ChangeBranchTipTestCase):
353
    """Every method of Branch that changes a branch tip will invoke the
354
    pre/post_change_branch_tip hooks.
355
    """
356
357
    def setUp(self):
358
        ChangeBranchTipTestCase.setUp(self)
359
        self.installPreAndPostHooks()
3943.8.1 by Marius Kruger
remove all trailing whitespace from bzr source
360
3577.1.1 by Andrew Bennetts
Cherry-pick TipChangeRejected changes from pre-branch-tip-changed-hook loom.
361
    def installPreAndPostHooks(self):
362
        self.pre_hook_calls = self.install_logging_hook('pre')
363
        self.post_hook_calls = self.install_logging_hook('post')
364
365
    def resetHookCalls(self):
366
        del self.pre_hook_calls[:], self.post_hook_calls[:]
367
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.
368
    def assertPreAndPostHooksWereInvoked(self, branch, smart_enabled):
369
        """assert that both pre and post hooks were called
370
371
        :param smart_enabled: The method invoked is one that should be
372
            smart server ready.
373
        """
374
        # Check for the number of invocations expected. One invocation is
375
        # local, one is remote (if the branch is remote).
376
        if smart_enabled and isinstance(branch, RemoteBranch):
377
            length = 2
378
        else:
379
            length = 1
380
        self.assertEqual(length, len(self.pre_hook_calls))
381
        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.
382
383
    def test_set_revision_history(self):
384
        branch = self.make_branch('')
385
        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.
386
        self.assertPreAndPostHooksWereInvoked(branch, True)
3577.1.1 by Andrew Bennetts
Cherry-pick TipChangeRejected changes from pre-branch-tip-changed-hook loom.
387
388
    def test_set_last_revision_info(self):
389
        branch = self.make_branch('')
390
        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.
391
        self.assertPreAndPostHooksWereInvoked(branch, True)
3577.1.1 by Andrew Bennetts
Cherry-pick TipChangeRejected changes from pre-branch-tip-changed-hook loom.
392
393
    def test_generate_revision_history(self):
394
        branch = self.make_branch('')
395
        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.
396
        # NB: for HPSS protocols < v3, the server does not invoke branch tip
397
        # change events on generate_revision_history, as the change is done
398
        # directly by the client over the VFS.
399
        self.assertPreAndPostHooksWereInvoked(branch, True)
3577.1.1 by Andrew Bennetts
Cherry-pick TipChangeRejected changes from pre-branch-tip-changed-hook loom.
400
401
    def test_pull(self):
402
        source_branch = self.make_branch_with_revision_ids('rev-1', 'rev-2')
403
        self.resetHookCalls()
404
        destination_branch = self.make_branch('destination')
405
        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.
406
        self.assertPreAndPostHooksWereInvoked(destination_branch, False)
3577.1.1 by Andrew Bennetts
Cherry-pick TipChangeRejected changes from pre-branch-tip-changed-hook loom.
407
408
    def test_push(self):
409
        source_branch = self.make_branch_with_revision_ids('rev-1', 'rev-2')
410
        self.resetHookCalls()
411
        destination_branch = self.make_branch('destination')
412
        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.
413
        self.assertPreAndPostHooksWereInvoked(destination_branch, True)