~bzr-pqm/bzr/bzr.dev

« back to all changes in this revision

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

merge merge tweaks from aaron, which includes latest .dev

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'))