~bzr-pqm/bzr/bzr.dev

« back to all changes in this revision

Viewing changes to bzrlib/tests/blackbox/test_switch.py

  • Committer: Martin Packman
  • Date: 2011-12-23 19:38:22 UTC
  • mto: This revision was merged to the branch mainline in revision 6405.
  • Revision ID: martin.packman@canonical.com-20111223193822-hesheea4o8aqwexv
Accept and document passing the medium rather than transport for smart connections

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
# Copyright (C) 2007-2010 Canonical Ltd
 
2
# -*- coding: utf-8 -*-
 
3
#
 
4
# This program is free software; you can redistribute it and/or modify
 
5
# it under the terms of the GNU General Public License as published by
 
6
# the Free Software Foundation; either version 2 of the License, or
 
7
# (at your option) any later version.
 
8
#
 
9
# This program is distributed in the hope that it will be useful,
 
10
# but WITHOUT ANY WARRANTY; without even the implied warranty of
 
11
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 
12
# GNU General Public License for more details.
 
13
#
 
14
# You should have received a copy of the GNU General Public License
 
15
# along with this program; if not, write to the Free Software
 
16
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
 
17
 
 
18
 
 
19
"""Tests for the switch command of bzr."""
 
20
 
 
21
import os
 
22
 
 
23
from bzrlib.bzrdir import BzrDir
 
24
from bzrlib import (
 
25
        osutils,
 
26
        urlutils,
 
27
        branch,
 
28
        )
 
29
from bzrlib.workingtree import WorkingTree
 
30
from bzrlib.tests import (
 
31
        TestCaseWithTransport,
 
32
        script,
 
33
        )
 
34
from bzrlib.tests.features import UnicodeFilenameFeature
 
35
from bzrlib.directory_service import directories
 
36
 
 
37
 
 
38
class TestSwitch(TestCaseWithTransport):
 
39
 
 
40
    def _create_sample_tree(self):
 
41
        tree = self.make_branch_and_tree('branch-1')
 
42
        self.build_tree(['branch-1/file-1', 'branch-1/file-2'])
 
43
        tree.add('file-1')
 
44
        tree.commit('rev1')
 
45
        tree.add('file-2')
 
46
        tree.commit('rev2')
 
47
        return tree
 
48
 
 
49
    def test_switch_up_to_date_light_checkout(self):
 
50
        self.make_branch_and_tree('branch')
 
51
        self.run_bzr('branch branch branch2')
 
52
        self.run_bzr('checkout --lightweight branch checkout')
 
53
        os.chdir('checkout')
 
54
        out, err = self.run_bzr('switch ../branch2')
 
55
        self.assertContainsRe(err, 'Tree is up to date at revision 0.\n')
 
56
        self.assertContainsRe(err, 'Switched to branch: .*/branch2.\n')
 
57
        self.assertEqual('', out)
 
58
 
 
59
    def test_switch_out_of_date_light_checkout(self):
 
60
        self.make_branch_and_tree('branch')
 
61
        self.run_bzr('branch branch branch2')
 
62
        self.build_tree(['branch2/file'])
 
63
        self.run_bzr('add branch2/file')
 
64
        self.run_bzr('commit -m add-file branch2')
 
65
        self.run_bzr('checkout --lightweight branch checkout')
 
66
        os.chdir('checkout')
 
67
        out, err = self.run_bzr('switch ../branch2')
 
68
        #self.assertContainsRe(err, '\+N  file')
 
69
        self.assertContainsRe(err, 'Updated to revision 1.\n')
 
70
        self.assertContainsRe(err, 'Switched to branch: .*/branch2.\n')
 
71
        self.assertEqual('', out)
 
72
 
 
73
    def _test_switch_nick(self, lightweight):
 
74
        """Check that the nick gets switched too."""
 
75
        tree1 = self.make_branch_and_tree('branch1')
 
76
        tree2 = self.make_branch_and_tree('branch2')
 
77
        tree2.pull(tree1.branch)
 
78
        checkout =  tree1.branch.create_checkout('checkout',
 
79
            lightweight=lightweight)
 
80
        self.assertEqual(checkout.branch.nick, tree1.branch.nick)
 
81
        self.assertEqual(checkout.branch.get_config().has_explicit_nickname(),
 
82
            False)
 
83
        self.run_bzr('switch branch2', working_dir='checkout')
 
84
 
 
85
        # we need to get the tree again, otherwise we don't get the new branch
 
86
        checkout = WorkingTree.open('checkout')
 
87
        self.assertEqual(checkout.branch.nick, tree2.branch.nick)
 
88
        self.assertEqual(checkout.branch.get_config().has_explicit_nickname(),
 
89
            False)
 
90
 
 
91
    def test_switch_nick(self):
 
92
        self._test_switch_nick(lightweight=False)
 
93
 
 
94
    def test_switch_nick_lightweight(self):
 
95
        self._test_switch_nick(lightweight=True)
 
96
 
 
97
    def _test_switch_explicit_nick(self, lightweight):
 
98
        """Check that the nick gets switched too."""
 
99
        tree1 = self.make_branch_and_tree('branch1')
 
100
        tree2 = self.make_branch_and_tree('branch2')
 
101
        tree2.pull(tree1.branch)
 
102
        checkout =  tree1.branch.create_checkout('checkout',
 
103
            lightweight=lightweight)
 
104
        self.assertEqual(checkout.branch.nick, tree1.branch.nick)
 
105
        checkout.branch.nick = "explicit_nick"
 
106
        self.assertEqual(checkout.branch.nick, "explicit_nick")
 
107
        self.assertEqual(checkout.branch.get_config()._get_explicit_nickname(),
 
108
            "explicit_nick")
 
109
        self.run_bzr('switch branch2', working_dir='checkout')
 
110
 
 
111
        # we need to get the tree again, otherwise we don't get the new branch
 
112
        checkout = WorkingTree.open('checkout')
 
113
        self.assertEqual(checkout.branch.nick, tree2.branch.nick)
 
114
        self.assertEqual(checkout.branch.get_config()._get_explicit_nickname(),
 
115
            tree2.branch.nick)
 
116
 
 
117
    def test_switch_explicit_nick(self):
 
118
        self._test_switch_explicit_nick(lightweight=False)
 
119
 
 
120
    def test_switch_explicit_nick_lightweight(self):
 
121
        self._test_switch_explicit_nick(lightweight=True)
 
122
 
 
123
    def test_switch_finds_relative_branch(self):
 
124
        """Switch will find 'foo' relative to the branch the checkout is of."""
 
125
        self.build_tree(['repo/'])
 
126
        tree1 = self.make_branch_and_tree('repo/brancha')
 
127
        tree1.commit('foo')
 
128
        tree2 = self.make_branch_and_tree('repo/branchb')
 
129
        tree2.pull(tree1.branch)
 
130
        branchb_id = tree2.commit('bar')
 
131
        checkout =  tree1.branch.create_checkout('checkout', lightweight=True)
 
132
        self.run_bzr(['switch', 'branchb'], working_dir='checkout')
 
133
        self.assertEqual(branchb_id, checkout.last_revision())
 
134
        checkout = checkout.bzrdir.open_workingtree()
 
135
        self.assertEqual(tree2.branch.base, checkout.branch.base)
 
136
 
 
137
    def test_switch_finds_relative_bound_branch(self):
 
138
        """Using switch on a heavy checkout should find master sibling
 
139
 
 
140
        The behaviour of lighweight and heavy checkouts should be
 
141
        consistent when using the convenient "switch to sibling" feature
 
142
        Both should switch to a sibling of the branch
 
143
        they are bound to, and not a sibling of themself"""
 
144
 
 
145
        self.build_tree(['repo/',
 
146
                         'heavyco/'])
 
147
        tree1 = self.make_branch_and_tree('repo/brancha')
 
148
        tree1.commit('foo')
 
149
        tree2 = self.make_branch_and_tree('repo/branchb')
 
150
        tree2.pull(tree1.branch)
 
151
        branchb_id = tree2.commit('bar')
 
152
        checkout = tree1.branch.create_checkout('heavyco/a', lightweight=False)
 
153
        self.run_bzr(['switch', 'branchb'], working_dir='heavyco/a')
 
154
        self.assertEqual(branchb_id, checkout.last_revision())
 
155
        self.assertEqual(tree2.branch.base, checkout.branch.get_bound_location())
 
156
 
 
157
    def test_switch_finds_relative_unicode_branch(self):
 
158
        """Switch will find 'foo' relative to the branch the checkout is of."""
 
159
        self.requireFeature(UnicodeFilenameFeature)
 
160
        self.build_tree(['repo/'])
 
161
        tree1 = self.make_branch_and_tree('repo/brancha')
 
162
        tree1.commit('foo')
 
163
        tree2 = self.make_branch_and_tree(u'repo/branch\xe9')
 
164
        tree2.pull(tree1.branch)
 
165
        branchb_id = tree2.commit('bar')
 
166
        checkout =  tree1.branch.create_checkout('checkout', lightweight=True)
 
167
        self.run_bzr(['switch', u'branch\xe9'], working_dir='checkout')
 
168
        self.assertEqual(branchb_id, checkout.last_revision())
 
169
        checkout = checkout.bzrdir.open_workingtree()
 
170
        self.assertEqual(tree2.branch.base, checkout.branch.base)
 
171
 
 
172
    def test_switch_revision(self):
 
173
        tree = self._create_sample_tree()
 
174
        checkout = tree.branch.create_checkout('checkout', lightweight=True)
 
175
        self.run_bzr(['switch', 'branch-1', '-r1'], working_dir='checkout')
 
176
        self.assertPathExists('checkout/file-1')
 
177
        self.assertPathDoesNotExist('checkout/file-2')
 
178
 
 
179
    def test_switch_existing_colocated(self):
 
180
        # Create a branch branch-1 that initially is a checkout of 'foo'
 
181
        # Use switch to change it to 'anotherbranch'
 
182
        repo = self.make_repository('branch-1', format='development-colo')
 
183
        target_branch = repo.bzrdir.create_branch(name='foo')
 
184
        branch.BranchReferenceFormat().initialize(
 
185
            repo.bzrdir, target_branch=target_branch)
 
186
        tree = repo.bzrdir.create_workingtree()
 
187
        self.build_tree(['branch-1/file-1', 'branch-1/file-2'])
 
188
        tree.add('file-1')
 
189
        revid1 = tree.commit('rev1')
 
190
        tree.add('file-2')
 
191
        revid2 = tree.commit('rev2')
 
192
        otherbranch = tree.bzrdir.create_branch(name='anotherbranch')
 
193
        otherbranch.generate_revision_history(revid1)
 
194
        self.run_bzr(['switch', 'anotherbranch'], working_dir='branch-1')
 
195
        tree = WorkingTree.open("branch-1")
 
196
        self.assertEquals(tree.last_revision(), revid1)
 
197
        self.assertEquals(tree.branch.control_url, otherbranch.control_url)
 
198
 
 
199
    def test_switch_new_colocated(self):
 
200
        # Create a branch branch-1 that initially is a checkout of 'foo'
 
201
        # Use switch to create 'anotherbranch' which derives from that
 
202
        repo = self.make_repository('branch-1', format='development-colo')
 
203
        target_branch = repo.bzrdir.create_branch(name='foo')
 
204
        branch.BranchReferenceFormat().initialize(
 
205
            repo.bzrdir, target_branch=target_branch)
 
206
        tree = repo.bzrdir.create_workingtree()
 
207
        self.build_tree(['branch-1/file-1', 'branch-1/file-2'])
 
208
        tree.add('file-1')
 
209
        revid1 = tree.commit('rev1')
 
210
        self.run_bzr(['switch', '-b', 'anotherbranch'], working_dir='branch-1')
 
211
        bzrdir = BzrDir.open("branch-1")
 
212
        self.assertEquals(
 
213
            set([b.name for b in bzrdir.list_branches()]),
 
214
            set(["foo", "anotherbranch"]))
 
215
        self.assertEquals(bzrdir.open_branch().name, "anotherbranch")
 
216
        self.assertEquals(bzrdir.open_branch().last_revision(), revid1)
 
217
 
 
218
    def test_switch_new_colocated_unicode(self):
 
219
        # Create a branch branch-1 that initially is a checkout of 'foo'
 
220
        # Use switch to create 'branch\xe9' which derives from that
 
221
        self.requireFeature(UnicodeFilenameFeature)
 
222
        repo = self.make_repository('branch-1', format='development-colo')
 
223
        target_branch = repo.bzrdir.create_branch(name='foo')
 
224
        branch.BranchReferenceFormat().initialize(
 
225
            repo.bzrdir, target_branch=target_branch)
 
226
        tree = repo.bzrdir.create_workingtree()
 
227
        self.build_tree(['branch-1/file-1', 'branch-1/file-2'])
 
228
        tree.add('file-1')
 
229
        revid1 = tree.commit('rev1')
 
230
        self.run_bzr(['switch', '-b', u'branch\xe9'], working_dir='branch-1')
 
231
        bzrdir = BzrDir.open("branch-1")
 
232
        self.assertEquals(
 
233
            set([b.name for b in bzrdir.list_branches()]),
 
234
            set(["foo", u"branch\xe9"]))
 
235
        self.assertEquals(bzrdir.open_branch().name, u"branch\xe9")
 
236
        self.assertEquals(bzrdir.open_branch().last_revision(), revid1)
 
237
 
 
238
    def test_switch_only_revision(self):
 
239
        tree = self._create_sample_tree()
 
240
        checkout = tree.branch.create_checkout('checkout', lightweight=True)
 
241
        self.assertPathExists('checkout/file-1')
 
242
        self.assertPathExists('checkout/file-2')
 
243
        self.run_bzr(['switch', '-r1'], working_dir='checkout')
 
244
        self.assertPathExists('checkout/file-1')
 
245
        self.assertPathDoesNotExist('checkout/file-2')
 
246
        # Check that we don't accept a range
 
247
        self.run_bzr_error(
 
248
            ['bzr switch --revision takes exactly one revision identifier'],
 
249
            ['switch', '-r0..2'], working_dir='checkout')
 
250
 
 
251
    def prepare_lightweight_switch(self):
 
252
        branch = self.make_branch('branch')
 
253
        branch.create_checkout('tree', lightweight=True)
 
254
        osutils.rename('branch', 'branch1')
 
255
 
 
256
    def test_switch_lightweight_after_branch_moved(self):
 
257
        self.prepare_lightweight_switch()
 
258
        self.run_bzr('switch --force ../branch1', working_dir='tree')
 
259
        branch_location = WorkingTree.open('tree').branch.base
 
260
        self.assertEndsWith(branch_location, 'branch1/')
 
261
 
 
262
    def test_switch_lightweight_after_branch_moved_relative(self):
 
263
        self.prepare_lightweight_switch()
 
264
        self.run_bzr('switch --force branch1', working_dir='tree')
 
265
        branch_location = WorkingTree.open('tree').branch.base
 
266
        self.assertEndsWith(branch_location, 'branch1/')
 
267
 
 
268
    def test_create_branch_no_branch(self):
 
269
        self.prepare_lightweight_switch()
 
270
        self.run_bzr_error(['cannot create branch without source branch'],
 
271
            'switch --create-branch ../branch2', working_dir='tree')
 
272
 
 
273
    def test_create_branch(self):
 
274
        branch = self.make_branch('branch')
 
275
        tree = branch.create_checkout('tree', lightweight=True)
 
276
        tree.commit('one', rev_id='rev-1')
 
277
        self.run_bzr('switch --create-branch ../branch2', working_dir='tree')
 
278
        tree = WorkingTree.open('tree')
 
279
        self.assertEndsWith(tree.branch.base, '/branch2/')
 
280
 
 
281
    def test_create_branch_local(self):
 
282
        branch = self.make_branch('branch')
 
283
        tree = branch.create_checkout('tree', lightweight=True)
 
284
        tree.commit('one', rev_id='rev-1')
 
285
        self.run_bzr('switch --create-branch branch2', working_dir='tree')
 
286
        tree = WorkingTree.open('tree')
 
287
        # The new branch should have been created at the same level as
 
288
        # 'branch', because we did not have a '/' segment
 
289
        self.assertEqual(branch.base[:-1] + '2/', tree.branch.base)
 
290
 
 
291
    def test_create_branch_short_name(self):
 
292
        branch = self.make_branch('branch')
 
293
        tree = branch.create_checkout('tree', lightweight=True)
 
294
        tree.commit('one', rev_id='rev-1')
 
295
        self.run_bzr('switch -b branch2', working_dir='tree')
 
296
        tree = WorkingTree.open('tree')
 
297
        # The new branch should have been created at the same level as
 
298
        # 'branch', because we did not have a '/' segment
 
299
        self.assertEqual(branch.base[:-1] + '2/', tree.branch.base)
 
300
 
 
301
    def test_create_branch_directory_services(self):
 
302
        branch = self.make_branch('branch')
 
303
        tree = branch.create_checkout('tree', lightweight=True)
 
304
        class FooLookup(object):
 
305
            def look_up(self, name, url):
 
306
                return 'foo-'+name
 
307
        directories.register('foo:', FooLookup, 'Create branches named foo-')
 
308
        self.addCleanup(directories.remove, 'foo:')
 
309
        self.run_bzr('switch -b foo:branch2', working_dir='tree')
 
310
        tree = WorkingTree.open('tree')
 
311
        self.assertEndsWith(tree.branch.base, 'foo-branch2/')
 
312
 
 
313
    def test_switch_with_post_switch_hook(self):
 
314
        from bzrlib import branch as _mod_branch
 
315
        calls = []
 
316
        _mod_branch.Branch.hooks.install_named_hook('post_switch',
 
317
            calls.append, None)
 
318
        self.make_branch_and_tree('branch')
 
319
        self.run_bzr('branch branch branch2')
 
320
        self.run_bzr('checkout branch checkout')
 
321
        os.chdir('checkout')
 
322
        self.assertLength(0, calls)
 
323
        out, err = self.run_bzr('switch ../branch2')
 
324
        self.assertLength(1, calls)
 
325
 
 
326
    def test_switch_lightweight_co_with_post_switch_hook(self):
 
327
        from bzrlib import branch as _mod_branch
 
328
        calls = []
 
329
        _mod_branch.Branch.hooks.install_named_hook('post_switch',
 
330
            calls.append, None)
 
331
        self.make_branch_and_tree('branch')
 
332
        self.run_bzr('branch branch branch2')
 
333
        self.run_bzr('checkout --lightweight branch checkout')
 
334
        os.chdir('checkout')
 
335
        self.assertLength(0, calls)
 
336
        out, err = self.run_bzr('switch ../branch2')
 
337
        self.assertLength(1, calls)
 
338
 
 
339
    def test_switch_lightweight_directory(self):
 
340
        """Test --directory option"""
 
341
 
 
342
        # create a source branch
 
343
        a_tree = self.make_branch_and_tree('a')
 
344
        self.build_tree_contents([('a/a', 'initial\n')])
 
345
        a_tree.add('a')
 
346
        a_tree.commit(message='initial')
 
347
 
 
348
        # clone and add a differing revision
 
349
        b_tree = a_tree.bzrdir.sprout('b').open_workingtree()
 
350
        self.build_tree_contents([('b/a', 'initial\nmore\n')])
 
351
        b_tree.commit(message='more')
 
352
 
 
353
        self.run_bzr('checkout --lightweight a checkout')
 
354
        self.run_bzr('switch --directory checkout b')
 
355
        self.assertFileEqual('initial\nmore\n', 'checkout/a')
 
356
 
 
357
 
 
358
class TestSwitchParentLocationBase(TestCaseWithTransport):
 
359
 
 
360
    def setUp(self):
 
361
        """Set up a repository and branch ready for testing."""
 
362
        super(TestSwitchParentLocationBase, self).setUp()
 
363
        self.script_runner = script.ScriptRunner()
 
364
        self.script_runner.run_script(self, '''
 
365
                $ bzr init-repo --no-trees repo
 
366
                Shared repository...
 
367
                Location:
 
368
                  shared repository: repo
 
369
                $ bzr init repo/trunk
 
370
                Created a repository branch...
 
371
                Using shared repository: ...
 
372
                ''')
 
373
 
 
374
    def assertParent(self, expected_parent, branch):
 
375
        """Verify that the parent is not None and is set correctly."""
 
376
        actual_parent = branch.get_parent()
 
377
        self.assertIsSameRealPath(urlutils.local_path_to_url(expected_parent),
 
378
                                  branch.get_parent())
 
379
 
 
380
 
 
381
class TestSwitchParentLocation(TestSwitchParentLocationBase):
 
382
 
 
383
    def _checkout_and_switch(self, option=''):
 
384
        self.script_runner.run_script(self, '''
 
385
                $ bzr checkout %(option)s repo/trunk checkout
 
386
                $ cd checkout
 
387
                $ bzr switch --create-branch switched
 
388
                2>Tree is up to date at revision 0.
 
389
                2>Switched to branch:...switched...
 
390
                $ cd ..
 
391
                ''' % locals())
 
392
        bound_branch = branch.Branch.open_containing('checkout')[0]
 
393
        master_branch = branch.Branch.open_containing('repo/switched')[0]
 
394
        return (bound_branch, master_branch)
 
395
 
 
396
    def test_switch_parent_lightweight(self):
 
397
        """Lightweight checkout using bzr switch."""
 
398
        bb, mb = self._checkout_and_switch(option='--lightweight')
 
399
        self.assertParent('repo/trunk', bb)
 
400
        self.assertParent('repo/trunk', mb)
 
401
 
 
402
    def test_switch_parent_heavyweight(self):
 
403
        """Heavyweight checkout using bzr switch."""
 
404
        bb, mb = self._checkout_and_switch()
 
405
        self.assertParent('repo/trunk', bb)
 
406
        self.assertParent('repo/trunk', mb)
 
407
 
 
408
 
 
409
class TestSwitchDoesntOpenMasterBranch(TestCaseWithTransport):
 
410
    # See https://bugs.launchpad.net/bzr/+bug/812285
 
411
    # "bzr switch --create-branch" can point the new branch's parent to the
 
412
    # master branch, but it doesn't have to open it to do so.
 
413
 
 
414
    def test_switch_create_doesnt_open_master_branch(self):
 
415
        master = self.make_branch_and_tree('master')
 
416
        master.commit('one')
 
417
        # Note: not a lightweight checkout
 
418
        checkout = master.branch.create_checkout('checkout')
 
419
        opened = []
 
420
        def open_hook(branch):
 
421
            # Just append the final directory of the branch
 
422
            name = branch.base.rstrip('/').rsplit('/', 1)[1]
 
423
            opened.append(name)
 
424
        branch.Branch.hooks.install_named_hook('open', open_hook,
 
425
                                               'open_hook_logger')
 
426
        self.run_bzr('switch --create-branch -d checkout feature')
 
427
        # We only open the master branch 1 time.
 
428
        # This test should be cleaner to write, but see bug:
 
429
        #  https://bugs.launchpad.net/bzr/+bug/812295
 
430
        self.assertEqual(1, opened.count('master'))