13
13
# You should have received a copy of the GNU General Public License
14
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
15
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
17
17
"""Tests that branch classes implement hook callouts correctly."""
20
20
from bzrlib.errors import HookFailed, TipChangeRejected
21
21
from bzrlib.remote import RemoteBranch
22
22
from bzrlib.revision import NULL_REVISION
23
from bzrlib.smart import server
23
24
from bzrlib.tests import TestCaseWithMemoryTransport
76
77
def capture_set_rh_hook(self, branch, rev_history):
77
78
"""Capture post set-rh hook calls to self.hook_calls.
79
80
The call is logged, as is some state of the branch.
81
82
self.hook_calls.append(
147
148
b = self.make_branch('.')
148
149
if isinstance(b, RemoteBranch):
149
150
# RemoteBranch creation:
150
# - creates the branch via the VFS
151
# - does a branch open (by creating a RemoteBranch object)
152
# - this has the same behaviour as simple branch opening, with an
153
# additional VFS open at the front.
154
self.assertEqual(b._real_branch, self.hook_calls[0])
155
self.assertOpenedRemoteBranch(self.hook_calls[1:], b)
151
if (self.transport_readonly_server ==
152
server.ReadonlySmartTCPServer_for_testing_v2_only):
154
self.assertEqual(3, len(self.hook_calls))
155
# creates the branch via the VFS (for older servers)
156
self.assertEqual(b._real_branch, self.hook_calls[0])
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])
162
self.assertEqual(2, len(self.hook_calls))
164
self.assertRealBranch(self.hook_calls[0])
165
# create RemoteBranch locally
166
self.assertEqual(b, self.hook_calls[1])
157
168
self.assertEqual([b], self.hook_calls)
161
172
self.install_hook()
162
173
b = Branch.open(branch_url)
163
174
if isinstance(b, RemoteBranch):
164
self.assertOpenedRemoteBranch(self.hook_calls, b)
175
self.assertEqual(3, len(self.hook_calls))
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])
166
183
self.assertEqual([b], self.hook_calls)
168
def assertOpenedRemoteBranch(self, hook_calls, b):
169
"""Assert that the expected calls were recorded for opening 'b'."""
170
# RemoteBranch open always opens the backing branch to get stacking
171
# details. As that is done remotely we can't see the branch object
172
# nor even compare base url's etc. So we just assert that the first
173
# branch returned is the RemoteBranch, and that the second is a
174
# Branch but not a RemoteBranch.
175
self.assertEqual(2, len(hook_calls))
176
self.assertEqual(b, hook_calls[0])
177
self.assertIsInstance(hook_calls[1], Branch)
178
self.assertFalse(isinstance(hook_calls[1], RemoteBranch))
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))
181
192
class TestPreChangeBranchTip(ChangeBranchTipTestCase):
182
193
"""Tests for pre_change_branch_tip hook.
184
195
Most of these tests are very similar to the tests in
185
196
TestPostChangeBranchTip.
199
210
def test_hook_failure_prevents_change(self):
200
211
"""If a hook raises an exception, the change does not take effect.
202
213
Also, a HookFailed exception will be raised.
204
215
branch = self.make_branch_with_revision_ids(
214
225
self.assertIsInstance(hook_failed_exc.exc_value, PearShapedError)
215
226
# The revision info is unchanged.
216
227
self.assertEqual((2, 'two-\xc2\xb5'), branch.last_revision_info())
218
229
def test_empty_history(self):
219
230
branch = self.make_branch('source')
220
231
hook_calls = self.install_logging_hook('pre')
263
274
def test_explicit_reject_by_hook(self):
264
275
"""If a hook raises TipChangeRejected, the change does not take effect.
266
277
TipChangeRejected exceptions are propagated, not wrapped in HookFailed.
268
279
branch = self.make_branch_with_revision_ids(
275
286
TipChangeRejected, branch.set_last_revision_info, 0, NULL_REVISION)
276
287
# The revision info is unchanged.
277
288
self.assertEqual((2, 'two-\xc2\xb5'), branch.last_revision_info())
280
291
class TestPostChangeBranchTip(ChangeBranchTipTestCase):
281
292
"""Tests for post_change_branch_tip hook.
351
362
ChangeBranchTipTestCase.setUp(self)
352
363
self.installPreAndPostHooks()
354
365
def installPreAndPostHooks(self):
355
366
self.pre_hook_calls = self.install_logging_hook('pre')
356
367
self.post_hook_calls = self.install_logging_hook('post')