/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/branch_implementations/test_hooks.py

  • Committer: Andrew Bennetts
  • Date: 2008-09-08 12:59:00 UTC
  • mfrom: (3695 +trunk)
  • mto: This revision was merged to the branch mainline in revision 3756.
  • Revision ID: andrew.bennetts@canonical.com-20080908125900-8ywtsr7jqyyatjz0
Merge from bzr.dev.

Show diffs side-by-side

added added

removed removed

Lines of Context:
16
16
 
17
17
"""Tests that branch classes implement hook callouts correctly."""
18
18
 
19
 
from bzrlib.branch import Branch
 
19
from bzrlib.errors import HookFailed, TipChangeRejected
 
20
from bzrlib.branch import Branch, ChangeBranchTipParams
 
21
from bzrlib.revision import NULL_REVISION
20
22
from bzrlib.tests import TestCaseWithMemoryTransport
21
23
 
22
24
 
36
38
 
37
39
    def test_set_rh_empty_history(self):
38
40
        branch = self.make_branch('source')
39
 
        Branch.hooks.install_hook('set_rh', self.capture_set_rh_hook)
 
41
        Branch.hooks.install_named_hook('set_rh', self.capture_set_rh_hook,
 
42
                                        None)
40
43
        branch.set_revision_history([])
41
44
        self.assertEqual(self.hook_calls,
42
45
            [('set_rh', branch, [], True)])
49
52
        tree.commit('empty commit', rev_id='foo')
50
53
        tree.unlock()
51
54
        branch = tree.branch
52
 
        Branch.hooks.install_hook('set_rh', self.capture_set_rh_hook)
 
55
        Branch.hooks.install_named_hook('set_rh', self.capture_set_rh_hook,
 
56
                                        None)
53
57
        # some branches require that their history be set to a revision in the
54
58
        # repository
55
59
        branch.set_revision_history(['f\xc2\xb5'])
58
62
 
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,
 
66
                                        None)
62
67
        branch.set_revision_history([])
63
68
        self.assertEqual(self.hook_calls,
64
69
            [('set_rh', branch, [], True)])
65
70
 
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,
 
74
                                        None)
 
75
        Branch.hooks.install_named_hook('set_rh', self.capture_set_rh_hook,
 
76
                                        None)
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),
74
81
            ])
 
82
 
 
83
 
 
84
class ChangeBranchTipTestCase(TestCaseWithMemoryTransport):
 
85
    """Base TestCase for testing pre/post_change_branch_tip hooks."""
 
86
 
 
87
    def install_logging_hook(self, prefix):
 
88
        """Add a hook that logs calls made to it.
 
89
        
 
90
        :returns: the list that the calls will be appended to.
 
91
        """
 
92
        hook_calls = []
 
93
        Branch.hooks.install_named_hook(
 
94
            prefix + '_change_branch_tip', hook_calls.append, None)
 
95
        return hook_calls
 
96
 
 
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')
 
100
        tree.lock_write()
 
101
        tree.add('')
 
102
        for revision_id in revision_ids:
 
103
            tree.commit(u'Message of ' + revision_id.decode('utf8'),
 
104
                        rev_id=revision_id)
 
105
        tree.unlock()
 
106
        branch = tree.branch
 
107
        return branch
 
108
 
 
109
 
 
110
class TestPreChangeBranchTip(ChangeBranchTipTestCase):
 
111
    """Tests for pre_change_branch_tip hook.
 
112
    
 
113
    Most of these tests are very similar to the tests in
 
114
    TestPostChangeBranchTip.
 
115
    """
 
116
 
 
117
    def test_hook_runs_before_change(self):
 
118
        """The hook runs *before* the branch's last_revision_info has changed.
 
119
        """
 
120
        branch = self.make_branch_with_revision_ids('revid-one')
 
121
        def assertBranchAtRevision1(params):
 
122
            self.assertEquals(
 
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)
 
127
 
 
128
    def test_hook_failure_prevents_change(self):
 
129
        """If a hook raises an exception, the change does not take effect.
 
130
        
 
131
        Also, a HookFailed exception will be raised.
 
132
        """
 
133
        branch = self.make_branch_with_revision_ids(
 
134
            'one-\xc2\xb5', 'two-\xc2\xb5')
 
135
        class PearShapedError(Exception):
 
136
            pass
 
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())
 
146
        
 
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)
 
154
 
 
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
 
158
        # this test.
 
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)
 
166
 
 
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)
 
174
 
 
175
    def test_calls_all_hooks_no_errors(self):
 
176
        """If multiple hooks are registered, all are called (if none raise
 
177
        errors).
 
178
        """
 
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)
 
187
 
 
188
    def test_explicit_reject_by_hook(self):
 
189
        """If a hook raises TipChangeRejected, the change does not take effect.
 
190
        
 
191
        TipChangeRejected exceptions are propagated, not wrapped in HookFailed.
 
192
        """
 
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)
 
199
        self.assertRaises(
 
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())
 
203
        
 
204
 
 
205
class TestPostChangeBranchTip(ChangeBranchTipTestCase):
 
206
    """Tests for post_change_branch_tip hook.
 
207
 
 
208
    Most of these tests are very similar to the tests in
 
209
    TestPostChangeBranchTip.
 
210
    """
 
211
 
 
212
    def test_hook_runs_after_change(self):
 
213
        """The hook runs *after* the branch's last_revision_info has changed.
 
214
        """
 
215
        branch = self.make_branch_with_revision_ids('revid-one')
 
216
        def assertBranchAtRevision1(params):
 
217
            self.assertEquals(
 
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)
 
222
 
 
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)
 
230
 
 
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
 
234
        # this test.
 
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)
 
242
 
 
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)
 
251
 
 
252
    def test_calls_all_hooks_no_errors(self):
 
253
        """If multiple hooks are registered, all are called (if none raise
 
254
        errors).
 
255
        """
 
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)
 
264
 
 
265
 
 
266
class TestAllMethodsThatChangeTipWillRunHooks(ChangeBranchTipTestCase):
 
267
    """Every method of Branch that changes a branch tip will invoke the
 
268
    pre/post_change_branch_tip hooks.
 
269
    """
 
270
 
 
271
    def setUp(self):
 
272
        ChangeBranchTipTestCase.setUp(self)
 
273
        self.installPreAndPostHooks()
 
274
        
 
275
    def installPreAndPostHooks(self):
 
276
        self.pre_hook_calls = self.install_logging_hook('pre')
 
277
        self.post_hook_calls = self.install_logging_hook('post')
 
278
 
 
279
    def resetHookCalls(self):
 
280
        del self.pre_hook_calls[:], self.post_hook_calls[:]
 
281
 
 
282
    def assertPreAndPostHooksWereInvoked(self):
 
283
        # Check for len == 1, because the hooks should only be be invoked once
 
284
        # by an operation.
 
285
        self.assertEqual(1, len(self.pre_hook_calls))
 
286
        self.assertEqual(1, len(self.post_hook_calls))
 
287
 
 
288
    def test_set_revision_history(self):
 
289
        branch = self.make_branch('')
 
290
        branch.set_revision_history([])
 
291
        self.assertPreAndPostHooksWereInvoked()
 
292
 
 
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()
 
297
 
 
298
    def test_generate_revision_history(self):
 
299
        branch = self.make_branch('')
 
300
        branch.generate_revision_history(NULL_REVISION)
 
301
        self.assertPreAndPostHooksWereInvoked()
 
302
 
 
303
    def test_pull(self):
 
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()
 
309
 
 
310
    def test_push(self):
 
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()
 
316
 
 
317