59
63
def test_set_rh_branch_is_locked(self):
60
64
branch = self.make_branch('source')
61
Branch.hooks.install_hook('set_rh', self.capture_set_rh_hook)
65
Branch.hooks.install_named_hook('set_rh', self.capture_set_rh_hook,
62
67
branch.set_revision_history([])
63
68
self.assertEqual(self.hook_calls,
64
69
[('set_rh', branch, [], True)])
66
71
def test_set_rh_calls_all_hooks_no_errors(self):
67
72
branch = self.make_branch('source')
68
Branch.hooks.install_hook('set_rh', self.capture_set_rh_hook)
69
Branch.hooks.install_hook('set_rh', self.capture_set_rh_hook)
73
Branch.hooks.install_named_hook('set_rh', self.capture_set_rh_hook,
75
Branch.hooks.install_named_hook('set_rh', self.capture_set_rh_hook,
70
77
branch.set_revision_history([])
71
78
self.assertEqual(self.hook_calls,
72
79
[('set_rh', branch, [], True),
73
80
('set_rh', branch, [], True),
84
class ChangeBranchTipTestCase(TestCaseWithMemoryTransport):
85
"""Base TestCase for testing pre/post_change_branch_tip hooks."""
87
def install_logging_hook(self, prefix):
88
"""Add a hook that logs calls made to it.
90
:returns: the list that the calls will be appended to.
93
Branch.hooks.install_named_hook(
94
prefix + '_change_branch_tip', hook_calls.append, None)
97
def make_branch_with_revision_ids(self, *revision_ids):
98
"""Makes a branch with the given commits."""
99
tree = self.make_branch_and_memory_tree('source')
102
for revision_id in revision_ids:
103
tree.commit(u'Message of ' + revision_id.decode('utf8'),
110
class TestPreChangeBranchTip(ChangeBranchTipTestCase):
111
"""Tests for pre_change_branch_tip hook.
113
Most of these tests are very similar to the tests in
114
TestPostChangeBranchTip.
117
def test_hook_runs_before_change(self):
118
"""The hook runs *before* the branch's last_revision_info has changed.
120
branch = self.make_branch_with_revision_ids('revid-one')
121
def assertBranchAtRevision1(params):
123
(1, 'revid-one'), params.branch.last_revision_info())
124
Branch.hooks.install_named_hook(
125
'pre_change_branch_tip', assertBranchAtRevision1, None)
126
branch.set_last_revision_info(0, NULL_REVISION)
128
def test_hook_failure_prevents_change(self):
129
"""If a hook raises an exception, the change does not take effect.
131
Also, a HookFailed exception will be raised.
133
branch = self.make_branch_with_revision_ids(
134
'one-\xc2\xb5', 'two-\xc2\xb5')
135
class PearShapedError(Exception):
137
def hook_that_raises(params):
138
raise PearShapedError()
139
Branch.hooks.install_named_hook(
140
'pre_change_branch_tip', hook_that_raises, None)
141
hook_failed_exc = self.assertRaises(
142
HookFailed, branch.set_last_revision_info, 0, NULL_REVISION)
143
self.assertIsInstance(hook_failed_exc.exc_value, PearShapedError)
144
# The revision info is unchanged.
145
self.assertEqual((2, 'two-\xc2\xb5'), branch.last_revision_info())
147
def test_empty_history(self):
148
branch = self.make_branch('source')
149
hook_calls = self.install_logging_hook('pre')
150
branch.set_last_revision_info(0, NULL_REVISION)
151
expected_params = ChangeBranchTipParams(
152
branch, 0, 0, NULL_REVISION, NULL_REVISION)
153
self.assertEqual([expected_params], hook_calls)
155
def test_nonempty_history(self):
156
# some branches require that their history be set to a revision in the
157
# repository, so we need to make a branch with non-empty history for
159
branch = self.make_branch_with_revision_ids(
160
'one-\xc2\xb5', 'two-\xc2\xb5')
161
hook_calls = self.install_logging_hook('pre')
162
branch.set_last_revision_info(1, 'one-\xc2\xb5')
163
expected_params = ChangeBranchTipParams(
164
branch, 2, 1, 'two-\xc2\xb5', 'one-\xc2\xb5')
165
self.assertEqual([expected_params], hook_calls)
167
def test_branch_is_locked(self):
168
branch = self.make_branch('source')
169
def assertBranchIsLocked(params):
170
self.assertTrue(params.branch.is_locked())
171
Branch.hooks.install_named_hook(
172
'pre_change_branch_tip', assertBranchIsLocked, None)
173
branch.set_last_revision_info(0, NULL_REVISION)
175
def test_calls_all_hooks_no_errors(self):
176
"""If multiple hooks are registered, all are called (if none raise
179
branch = self.make_branch('source')
180
hook_calls_1 = self.install_logging_hook('pre')
181
hook_calls_2 = self.install_logging_hook('pre')
182
self.assertIsNot(hook_calls_1, hook_calls_2)
183
branch.set_last_revision_info(0, NULL_REVISION)
184
# Both hooks are called.
185
self.assertEqual(len(hook_calls_1), 1)
186
self.assertEqual(len(hook_calls_2), 1)
188
def test_explicit_reject_by_hook(self):
189
"""If a hook raises TipChangeRejected, the change does not take effect.
191
TipChangeRejected exceptions are propagated, not wrapped in HookFailed.
193
branch = self.make_branch_with_revision_ids(
194
'one-\xc2\xb5', 'two-\xc2\xb5')
195
def hook_that_rejects(params):
196
raise TipChangeRejected('rejection message')
197
Branch.hooks.install_named_hook(
198
'pre_change_branch_tip', hook_that_rejects, None)
200
TipChangeRejected, branch.set_last_revision_info, 0, NULL_REVISION)
201
# The revision info is unchanged.
202
self.assertEqual((2, 'two-\xc2\xb5'), branch.last_revision_info())
205
class TestPostChangeBranchTip(ChangeBranchTipTestCase):
206
"""Tests for post_change_branch_tip hook.
208
Most of these tests are very similar to the tests in
209
TestPostChangeBranchTip.
212
def test_hook_runs_after_change(self):
213
"""The hook runs *after* the branch's last_revision_info has changed.
215
branch = self.make_branch_with_revision_ids('revid-one')
216
def assertBranchAtRevision1(params):
218
(0, NULL_REVISION), params.branch.last_revision_info())
219
Branch.hooks.install_named_hook(
220
'post_change_branch_tip', assertBranchAtRevision1, None)
221
branch.set_last_revision_info(0, NULL_REVISION)
223
def test_empty_history(self):
224
branch = self.make_branch('source')
225
hook_calls = self.install_logging_hook('post')
226
branch.set_last_revision_info(0, NULL_REVISION)
227
expected_params = ChangeBranchTipParams(
228
branch, 0, 0, NULL_REVISION, NULL_REVISION)
229
self.assertEqual([expected_params], hook_calls)
231
def test_nonempty_history(self):
232
# some branches require that their history be set to a revision in the
233
# repository, so we need to make a branch with non-empty history for
235
branch = self.make_branch_with_revision_ids(
236
'one-\xc2\xb5', 'two-\xc2\xb5')
237
hook_calls = self.install_logging_hook('post')
238
branch.set_last_revision_info(1, 'one-\xc2\xb5')
239
expected_params = ChangeBranchTipParams(
240
branch, 2, 1, 'two-\xc2\xb5', 'one-\xc2\xb5')
241
self.assertEqual([expected_params], hook_calls)
243
def test_branch_is_locked(self):
244
"""The branch passed to the hook is locked."""
245
branch = self.make_branch('source')
246
def assertBranchIsLocked(params):
247
self.assertTrue(params.branch.is_locked())
248
Branch.hooks.install_named_hook(
249
'post_change_branch_tip', assertBranchIsLocked, None)
250
branch.set_last_revision_info(0, NULL_REVISION)
252
def test_calls_all_hooks_no_errors(self):
253
"""If multiple hooks are registered, all are called (if none raise
256
branch = self.make_branch('source')
257
hook_calls_1 = self.install_logging_hook('post')
258
hook_calls_2 = self.install_logging_hook('post')
259
self.assertIsNot(hook_calls_1, hook_calls_2)
260
branch.set_last_revision_info(0, NULL_REVISION)
261
# Both hooks are called.
262
self.assertEqual(len(hook_calls_1), 1)
263
self.assertEqual(len(hook_calls_2), 1)
266
class TestAllMethodsThatChangeTipWillRunHooks(ChangeBranchTipTestCase):
267
"""Every method of Branch that changes a branch tip will invoke the
268
pre/post_change_branch_tip hooks.
272
ChangeBranchTipTestCase.setUp(self)
273
self.installPreAndPostHooks()
275
def installPreAndPostHooks(self):
276
self.pre_hook_calls = self.install_logging_hook('pre')
277
self.post_hook_calls = self.install_logging_hook('post')
279
def resetHookCalls(self):
280
del self.pre_hook_calls[:], self.post_hook_calls[:]
282
def assertPreAndPostHooksWereInvoked(self):
283
# Check for len == 1, because the hooks should only be be invoked once
285
self.assertEqual(1, len(self.pre_hook_calls))
286
self.assertEqual(1, len(self.post_hook_calls))
288
def test_set_revision_history(self):
289
branch = self.make_branch('')
290
branch.set_revision_history([])
291
self.assertPreAndPostHooksWereInvoked()
293
def test_set_last_revision_info(self):
294
branch = self.make_branch('')
295
branch.set_last_revision_info(0, NULL_REVISION)
296
self.assertPreAndPostHooksWereInvoked()
298
def test_generate_revision_history(self):
299
branch = self.make_branch('')
300
branch.generate_revision_history(NULL_REVISION)
301
self.assertPreAndPostHooksWereInvoked()
304
source_branch = self.make_branch_with_revision_ids('rev-1', 'rev-2')
305
self.resetHookCalls()
306
destination_branch = self.make_branch('destination')
307
destination_branch.pull(source_branch)
308
self.assertPreAndPostHooksWereInvoked()
311
source_branch = self.make_branch_with_revision_ids('rev-1', 'rev-2')
312
self.resetHookCalls()
313
destination_branch = self.make_branch('destination')
314
source_branch.push(destination_branch)
315
self.assertPreAndPostHooksWereInvoked()