~bzr-pqm/bzr/bzr.dev

« back to all changes in this revision

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

  • Committer: Martin Pool
  • Date: 2005-08-24 08:59:32 UTC
  • Revision ID: mbp@sourcefrog.net-20050824085932-c61f1f1f1c930e13
- Add a simple UIFactory 

  The idea of this is to let a client of bzrlib set some 
  policy about how output is displayed.

  In this revision all that's done is that progress bars
  are constructed by a policy established by the application
  rather than being randomly constructed in the library 
  or passed down the calls.  This avoids progress bars
  popping up while running the test suite and cleans up
  some code.

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
# Copyright (C) 2006-2010 Canonical Ltd
2
 
#
3
 
# This program is free software; you can redistribute it and/or modify
4
 
# it under the terms of the GNU General Public License as published by
5
 
# the Free Software Foundation; either version 2 of the License, or
6
 
# (at your option) any later version.
7
 
#
8
 
# This program is distributed in the hope that it will be useful,
9
 
# but WITHOUT ANY WARRANTY; without even the implied warranty of
10
 
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
11
 
# GNU General Public License for more details.
12
 
#
13
 
# You should have received a copy of the GNU General Public License
14
 
# along with this program; if not, write to the Free Software
15
 
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
16
 
 
17
 
 
18
 
"""Black-box tests for bzr branch."""
19
 
 
20
 
import os
21
 
 
22
 
from bzrlib import (
23
 
    branch,
24
 
    bzrdir,
25
 
    errors,
26
 
    repository,
27
 
    revision as _mod_revision,
28
 
    )
29
 
from bzrlib.repofmt.knitrepo import RepositoryFormatKnit1
30
 
from bzrlib.tests.blackbox import ExternalBase
31
 
from bzrlib.tests import (
32
 
    KnownFailure,
33
 
    HardlinkFeature,
34
 
    test_server,
35
 
    )
36
 
from bzrlib.tests.test_sftp_transport import TestCaseWithSFTPServer
37
 
from bzrlib.urlutils import local_path_to_url, strip_trailing_slash
38
 
from bzrlib.workingtree import WorkingTree
39
 
 
40
 
 
41
 
class TestBranch(ExternalBase):
42
 
 
43
 
    def example_branch(self, path='.'):
44
 
        tree = self.make_branch_and_tree(path)
45
 
        self.build_tree_contents([(path + '/hello', 'foo')])
46
 
        tree.add('hello')
47
 
        tree.commit(message='setup')
48
 
        self.build_tree_contents([(path + '/goodbye', 'baz')])
49
 
        tree.add('goodbye')
50
 
        tree.commit(message='setup')
51
 
 
52
 
    def test_branch(self):
53
 
        """Branch from one branch to another."""
54
 
        self.example_branch('a')
55
 
        self.run_bzr('branch a b')
56
 
        b = branch.Branch.open('b')
57
 
        self.run_bzr('branch a c -r 1')
58
 
        # previously was erroneously created by branching
59
 
        self.assertFalse(b._transport.has('branch-name'))
60
 
        b.bzrdir.open_workingtree().commit(message='foo', allow_pointless=True)
61
 
 
62
 
    def test_branch_switch_no_branch(self):
63
 
        # No branch in the current directory:
64
 
        #  => new branch will be created, but switch fails
65
 
        self.example_branch('a')
66
 
        self.make_repository('current')
67
 
        self.run_bzr_error(['No WorkingTree exists for'],
68
 
            'branch --switch ../a ../b', working_dir='current')
69
 
        a = branch.Branch.open('a')
70
 
        b = branch.Branch.open('b')
71
 
        self.assertEqual(a.last_revision(), b.last_revision())
72
 
 
73
 
    def test_branch_switch_no_wt(self):
74
 
        # No working tree in the current directory:
75
 
        #  => new branch will be created, but switch fails and the current
76
 
        #     branch is unmodified
77
 
        self.example_branch('a')
78
 
        self.make_branch('current')
79
 
        self.run_bzr_error(['No WorkingTree exists for'],
80
 
            'branch --switch ../a ../b', working_dir='current')
81
 
        a = branch.Branch.open('a')
82
 
        b = branch.Branch.open('b')
83
 
        self.assertEqual(a.last_revision(), b.last_revision())
84
 
        work = branch.Branch.open('current')
85
 
        self.assertEqual(work.last_revision(), _mod_revision.NULL_REVISION)
86
 
 
87
 
    def test_branch_switch_no_checkout(self):
88
 
        # Standalone branch in the current directory:
89
 
        #  => new branch will be created, but switch fails and the current
90
 
        #     branch is unmodified
91
 
        self.example_branch('a')
92
 
        self.make_branch_and_tree('current')
93
 
        self.run_bzr_error(['Cannot switch a branch, only a checkout'],
94
 
            'branch --switch ../a ../b', working_dir='current')
95
 
        a = branch.Branch.open('a')
96
 
        b = branch.Branch.open('b')
97
 
        self.assertEqual(a.last_revision(), b.last_revision())
98
 
        work = branch.Branch.open('current')
99
 
        self.assertEqual(work.last_revision(), _mod_revision.NULL_REVISION)
100
 
 
101
 
    def test_branch_switch_checkout(self):
102
 
        # Checkout in the current directory:
103
 
        #  => new branch will be created and checkout bound to the new branch
104
 
        self.example_branch('a')
105
 
        self.run_bzr('checkout a current')
106
 
        out, err = self.run_bzr('branch --switch ../a ../b', working_dir='current')
107
 
        a = branch.Branch.open('a')
108
 
        b = branch.Branch.open('b')
109
 
        self.assertEqual(a.last_revision(), b.last_revision())
110
 
        work = WorkingTree.open('current')
111
 
        self.assertEndsWith(work.branch.get_bound_location(), '/b/')
112
 
        self.assertContainsRe(err, "Switched to branch: .*/b/")
113
 
 
114
 
    def test_branch_switch_lightweight_checkout(self):
115
 
        # Lightweight checkout in the current directory:
116
 
        #  => new branch will be created and lightweight checkout pointed to
117
 
        #     the new branch
118
 
        self.example_branch('a')
119
 
        self.run_bzr('checkout --lightweight a current')
120
 
        out, err = self.run_bzr('branch --switch ../a ../b', working_dir='current')
121
 
        a = branch.Branch.open('a')
122
 
        b = branch.Branch.open('b')
123
 
        self.assertEqual(a.last_revision(), b.last_revision())
124
 
        work = WorkingTree.open('current')
125
 
        self.assertEndsWith(work.branch.base, '/b/')
126
 
        self.assertContainsRe(err, "Switched to branch: .*/b/")
127
 
 
128
 
    def test_branch_only_copies_history(self):
129
 
        # Knit branches should only push the history for the current revision.
130
 
        format = bzrdir.BzrDirMetaFormat1()
131
 
        format.repository_format = RepositoryFormatKnit1()
132
 
        shared_repo = self.make_repository('repo', format=format, shared=True)
133
 
        shared_repo.set_make_working_trees(True)
134
 
 
135
 
        def make_shared_tree(path):
136
 
            shared_repo.bzrdir.root_transport.mkdir(path)
137
 
            shared_repo.bzrdir.create_branch_convenience('repo/' + path)
138
 
            return WorkingTree.open('repo/' + path)
139
 
        tree_a = make_shared_tree('a')
140
 
        self.build_tree(['repo/a/file'])
141
 
        tree_a.add('file')
142
 
        tree_a.commit('commit a-1', rev_id='a-1')
143
 
        f = open('repo/a/file', 'ab')
144
 
        f.write('more stuff\n')
145
 
        f.close()
146
 
        tree_a.commit('commit a-2', rev_id='a-2')
147
 
 
148
 
        tree_b = make_shared_tree('b')
149
 
        self.build_tree(['repo/b/file'])
150
 
        tree_b.add('file')
151
 
        tree_b.commit('commit b-1', rev_id='b-1')
152
 
 
153
 
        self.assertTrue(shared_repo.has_revision('a-1'))
154
 
        self.assertTrue(shared_repo.has_revision('a-2'))
155
 
        self.assertTrue(shared_repo.has_revision('b-1'))
156
 
 
157
 
        # Now that we have a repository with shared files, make sure
158
 
        # that things aren't copied out by a 'branch'
159
 
        self.run_bzr('branch repo/b branch-b')
160
 
        pushed_tree = WorkingTree.open('branch-b')
161
 
        pushed_repo = pushed_tree.branch.repository
162
 
        self.assertFalse(pushed_repo.has_revision('a-1'))
163
 
        self.assertFalse(pushed_repo.has_revision('a-2'))
164
 
        self.assertTrue(pushed_repo.has_revision('b-1'))
165
 
 
166
 
    def test_branch_hardlink(self):
167
 
        self.requireFeature(HardlinkFeature)
168
 
        source = self.make_branch_and_tree('source')
169
 
        self.build_tree(['source/file1'])
170
 
        source.add('file1')
171
 
        source.commit('added file')
172
 
        out, err = self.run_bzr(['branch', 'source', 'target', '--hardlink'])
173
 
        source_stat = os.stat('source/file1')
174
 
        target_stat = os.stat('target/file1')
175
 
        self.assertEqual(source_stat, target_stat)
176
 
 
177
 
    def test_branch_standalone(self):
178
 
        shared_repo = self.make_repository('repo', shared=True)
179
 
        self.example_branch('source')
180
 
        self.run_bzr('branch --standalone source repo/target')
181
 
        b = branch.Branch.open('repo/target')
182
 
        expected_repo_path = os.path.abspath('repo/target/.bzr/repository')
183
 
        self.assertEqual(strip_trailing_slash(b.repository.base),
184
 
            strip_trailing_slash(local_path_to_url(expected_repo_path)))
185
 
 
186
 
    def test_branch_no_tree(self):
187
 
        self.example_branch('source')
188
 
        self.run_bzr('branch --no-tree source target')
189
 
        self.failIfExists('target/hello')
190
 
        self.failIfExists('target/goodbye')
191
 
 
192
 
    def test_branch_into_existing_dir(self):
193
 
        self.example_branch('a')
194
 
        # existing dir with similar files but no .bzr dir
195
 
        self.build_tree_contents([('b/',)])
196
 
        self.build_tree_contents([('b/hello', 'bar')])  # different content
197
 
        self.build_tree_contents([('b/goodbye', 'baz')])# same content
198
 
        # fails without --use-existing-dir
199
 
        out,err = self.run_bzr('branch a b', retcode=3)
200
 
        self.assertEqual('', out)
201
 
        self.assertEqual('bzr: ERROR: Target directory "b" already exists.\n',
202
 
            err)
203
 
        # force operation
204
 
        self.run_bzr('branch a b --use-existing-dir')
205
 
        # check conflicts
206
 
        self.failUnlessExists('b/hello.moved')
207
 
        self.failIfExists('b/godbye.moved')
208
 
        # we can't branch into branch
209
 
        out,err = self.run_bzr('branch a b --use-existing-dir', retcode=3)
210
 
        self.assertEqual('', out)
211
 
        self.assertEqual('bzr: ERROR: Already a branch: "b".\n', err)
212
 
 
213
 
    def test_branch_bind(self):
214
 
        self.example_branch('a')
215
 
        out, err = self.run_bzr('branch a b --bind')
216
 
        self.assertEndsWith(err, "New branch bound to a\n")
217
 
        b = branch.Branch.open('b')
218
 
        self.assertEndsWith(b.get_bound_location(), '/a/')
219
 
 
220
 
    def test_branch_with_post_branch_init_hook(self):
221
 
        calls = []
222
 
        branch.Branch.hooks.install_named_hook('post_branch_init',
223
 
            calls.append, None)
224
 
        self.assertLength(0, calls)
225
 
        self.example_branch('a')
226
 
        self.assertLength(1, calls)
227
 
        self.run_bzr('branch a b')
228
 
        self.assertLength(2, calls)
229
 
 
230
 
    def test_checkout_with_post_branch_init_hook(self):
231
 
        calls = []
232
 
        branch.Branch.hooks.install_named_hook('post_branch_init',
233
 
            calls.append, None)
234
 
        self.assertLength(0, calls)
235
 
        self.example_branch('a')
236
 
        self.assertLength(1, calls)
237
 
        self.run_bzr('checkout a b')
238
 
        self.assertLength(2, calls)
239
 
 
240
 
    def test_lightweight_checkout_with_post_branch_init_hook(self):
241
 
        calls = []
242
 
        branch.Branch.hooks.install_named_hook('post_branch_init',
243
 
            calls.append, None)
244
 
        self.assertLength(0, calls)
245
 
        self.example_branch('a')
246
 
        self.assertLength(1, calls)
247
 
        self.run_bzr('checkout --lightweight a b')
248
 
        self.assertLength(2, calls)
249
 
 
250
 
 
251
 
class TestBranchStacked(ExternalBase):
252
 
    """Tests for branch --stacked"""
253
 
 
254
 
    def assertRevisionInRepository(self, repo_path, revid):
255
 
        """Check that a revision is in a repository, disregarding stacking."""
256
 
        repo = bzrdir.BzrDir.open(repo_path).open_repository()
257
 
        self.assertTrue(repo.has_revision(revid))
258
 
 
259
 
    def assertRevisionNotInRepository(self, repo_path, revid):
260
 
        """Check that a revision is not in a repository, disregarding stacking."""
261
 
        repo = bzrdir.BzrDir.open(repo_path).open_repository()
262
 
        self.assertFalse(repo.has_revision(revid))
263
 
 
264
 
    def assertRevisionsInBranchRepository(self, revid_list, branch_path):
265
 
        repo = branch.Branch.open(branch_path).repository
266
 
        self.assertEqual(set(revid_list),
267
 
            repo.has_revisions(revid_list))
268
 
 
269
 
    def test_branch_stacked_branch_not_stacked(self):
270
 
        """Branching a stacked branch is not stacked by default"""
271
 
        # We have a mainline
272
 
        trunk_tree = self.make_branch_and_tree('target',
273
 
            format='1.9')
274
 
        trunk_tree.commit('mainline')
275
 
        # and a branch from it which is stacked
276
 
        branch_tree = self.make_branch_and_tree('branch',
277
 
            format='1.9')
278
 
        branch_tree.branch.set_stacked_on_url(trunk_tree.branch.base)
279
 
        # with some work on it
280
 
        work_tree = trunk_tree.branch.bzrdir.sprout('local').open_workingtree()
281
 
        work_tree.commit('moar work plz')
282
 
        work_tree.branch.push(branch_tree.branch)
283
 
        # branching our local branch gives us a new stacked branch pointing at
284
 
        # mainline.
285
 
        out, err = self.run_bzr(['branch', 'branch', 'newbranch'])
286
 
        self.assertEqual('', out)
287
 
        self.assertEqual('Branched 2 revision(s).\n',
288
 
            err)
289
 
        # it should have preserved the branch format, and so it should be
290
 
        # capable of supporting stacking, but not actually have a stacked_on
291
 
        # branch configured
292
 
        self.assertRaises(errors.NotStacked,
293
 
            bzrdir.BzrDir.open('newbranch').open_branch().get_stacked_on_url)
294
 
 
295
 
    def test_branch_stacked_branch_stacked(self):
296
 
        """Asking to stack on a stacked branch does work"""
297
 
        # We have a mainline
298
 
        trunk_tree = self.make_branch_and_tree('target',
299
 
            format='1.9')
300
 
        trunk_revid = trunk_tree.commit('mainline')
301
 
        # and a branch from it which is stacked
302
 
        branch_tree = self.make_branch_and_tree('branch',
303
 
            format='1.9')
304
 
        branch_tree.branch.set_stacked_on_url(trunk_tree.branch.base)
305
 
        # with some work on it
306
 
        work_tree = trunk_tree.branch.bzrdir.sprout('local').open_workingtree()
307
 
        branch_revid = work_tree.commit('moar work plz')
308
 
        work_tree.branch.push(branch_tree.branch)
309
 
        # you can chain branches on from there
310
 
        out, err = self.run_bzr(['branch', 'branch', '--stacked', 'branch2'])
311
 
        self.assertEqual('', out)
312
 
        self.assertEqual('Created new stacked branch referring to %s.\n' %
313
 
            branch_tree.branch.base, err)
314
 
        self.assertEqual(branch_tree.branch.base,
315
 
            branch.Branch.open('branch2').get_stacked_on_url())
316
 
        branch2_tree = WorkingTree.open('branch2')
317
 
        branch2_revid = work_tree.commit('work on second stacked branch')
318
 
        work_tree.branch.push(branch2_tree.branch)
319
 
        self.assertRevisionInRepository('branch2', branch2_revid)
320
 
        self.assertRevisionsInBranchRepository(
321
 
            [trunk_revid, branch_revid, branch2_revid],
322
 
            'branch2')
323
 
 
324
 
    def test_branch_stacked(self):
325
 
        # We have a mainline
326
 
        trunk_tree = self.make_branch_and_tree('mainline',
327
 
            format='1.9')
328
 
        original_revid = trunk_tree.commit('mainline')
329
 
        self.assertRevisionInRepository('mainline', original_revid)
330
 
        # and a branch from it which is stacked
331
 
        out, err = self.run_bzr(['branch', '--stacked', 'mainline',
332
 
            'newbranch'])
333
 
        self.assertEqual('', out)
334
 
        self.assertEqual('Created new stacked branch referring to %s.\n' %
335
 
            trunk_tree.branch.base, err)
336
 
        self.assertRevisionNotInRepository('newbranch', original_revid)
337
 
        new_branch = branch.Branch.open('newbranch')
338
 
        self.assertEqual(trunk_tree.branch.base, new_branch.get_stacked_on_url())
339
 
 
340
 
    def test_branch_stacked_from_smart_server(self):
341
 
        # We can branch stacking on a smart server
342
 
        self.transport_server = test_server.SmartTCPServer_for_testing
343
 
        trunk = self.make_branch('mainline', format='1.9')
344
 
        out, err = self.run_bzr(
345
 
            ['branch', '--stacked', self.get_url('mainline'), 'shallow'])
346
 
 
347
 
    def test_branch_stacked_from_non_stacked_format(self):
348
 
        """The origin format doesn't support stacking"""
349
 
        trunk = self.make_branch('trunk', format='pack-0.92')
350
 
        out, err = self.run_bzr(
351
 
            ['branch', '--stacked', 'trunk', 'shallow'])
352
 
        # We should notify the user that we upgraded their format
353
 
        self.assertEqualDiff(
354
 
            'Source repository format does not support stacking, using format:\n'
355
 
            '  Packs 5 (adds stacking support, requires bzr 1.6)\n'
356
 
            'Source branch format does not support stacking, using format:\n'
357
 
            '  Branch format 7\n'
358
 
            'Doing on-the-fly conversion from RepositoryFormatKnitPack1() to RepositoryFormatKnitPack5().\n'
359
 
            'This may take some time. Upgrade the repositories to the same format for better performance.\n'
360
 
            'Created new stacked branch referring to %s.\n' % (trunk.base,),
361
 
            err)
362
 
 
363
 
    def test_branch_stacked_from_rich_root_non_stackable(self):
364
 
        trunk = self.make_branch('trunk', format='rich-root-pack')
365
 
        out, err = self.run_bzr(
366
 
            ['branch', '--stacked', 'trunk', 'shallow'])
367
 
        # We should notify the user that we upgraded their format
368
 
        self.assertEqualDiff(
369
 
            'Source repository format does not support stacking, using format:\n'
370
 
            '  Packs 5 rich-root (adds stacking support, requires bzr 1.6.1)\n'
371
 
            'Source branch format does not support stacking, using format:\n'
372
 
            '  Branch format 7\n'
373
 
            'Doing on-the-fly conversion from RepositoryFormatKnitPack4() to RepositoryFormatKnitPack5RichRoot().\n'
374
 
            'This may take some time. Upgrade the repositories to the same format for better performance.\n'
375
 
            'Created new stacked branch referring to %s.\n' % (trunk.base,),
376
 
            err)
377
 
 
378
 
 
379
 
class TestSmartServerBranching(ExternalBase):
380
 
 
381
 
    def test_branch_from_trivial_branch_to_same_server_branch_acceptance(self):
382
 
        self.setup_smart_server_with_call_log()
383
 
        t = self.make_branch_and_tree('from')
384
 
        for count in range(9):
385
 
            t.commit(message='commit %d' % count)
386
 
        self.reset_smart_call_log()
387
 
        out, err = self.run_bzr(['branch', self.get_url('from'),
388
 
            self.get_url('target')])
389
 
        # This figure represent the amount of work to perform this use case. It
390
 
        # is entirely ok to reduce this number if a test fails due to rpc_count
391
 
        # being too low. If rpc_count increases, more network roundtrips have
392
 
        # become necessary for this use case. Please do not adjust this number
393
 
        # upwards without agreement from bzr's network support maintainers.
394
 
        self.assertLength(38, self.hpss_calls)
395
 
 
396
 
    def test_branch_from_trivial_branch_streaming_acceptance(self):
397
 
        self.setup_smart_server_with_call_log()
398
 
        t = self.make_branch_and_tree('from')
399
 
        for count in range(9):
400
 
            t.commit(message='commit %d' % count)
401
 
        self.reset_smart_call_log()
402
 
        out, err = self.run_bzr(['branch', self.get_url('from'),
403
 
            'local-target'])
404
 
        # This figure represent the amount of work to perform this use case. It
405
 
        # is entirely ok to reduce this number if a test fails due to rpc_count
406
 
        # being too low. If rpc_count increases, more network roundtrips have
407
 
        # become necessary for this use case. Please do not adjust this number
408
 
        # upwards without agreement from bzr's network support maintainers.
409
 
        self.assertLength(10, self.hpss_calls)
410
 
 
411
 
    def test_branch_from_trivial_stacked_branch_streaming_acceptance(self):
412
 
        self.setup_smart_server_with_call_log()
413
 
        t = self.make_branch_and_tree('trunk')
414
 
        for count in range(8):
415
 
            t.commit(message='commit %d' % count)
416
 
        tree2 = t.branch.bzrdir.sprout('feature', stacked=True
417
 
            ).open_workingtree()
418
 
        local_tree = t.branch.bzrdir.sprout('local-working').open_workingtree()
419
 
        local_tree.commit('feature change')
420
 
        local_tree.branch.push(tree2.branch)
421
 
        self.reset_smart_call_log()
422
 
        out, err = self.run_bzr(['branch', self.get_url('feature'),
423
 
            'local-target'])
424
 
        # This figure represent the amount of work to perform this use case. It
425
 
        # is entirely ok to reduce this number if a test fails due to rpc_count
426
 
        # being too low. If rpc_count increases, more network roundtrips have
427
 
        # become necessary for this use case. Please do not adjust this number
428
 
        # upwards without agreement from bzr's network support maintainers.
429
 
        self.assertLength(15, self.hpss_calls)
430
 
 
431
 
 
432
 
class TestRemoteBranch(TestCaseWithSFTPServer):
433
 
 
434
 
    def setUp(self):
435
 
        super(TestRemoteBranch, self).setUp()
436
 
        tree = self.make_branch_and_tree('branch')
437
 
        self.build_tree_contents([('branch/file', 'file content\n')])
438
 
        tree.add('file')
439
 
        tree.commit('file created')
440
 
 
441
 
    def test_branch_local_remote(self):
442
 
        self.run_bzr(['branch', 'branch', self.get_url('remote')])
443
 
        t = self.get_transport()
444
 
        # Ensure that no working tree what created remotely
445
 
        self.assertFalse(t.has('remote/file'))
446
 
 
447
 
    def test_branch_remote_remote(self):
448
 
        # Light cheat: we access the branch remotely
449
 
        self.run_bzr(['branch', self.get_url('branch'),
450
 
                      self.get_url('remote')])
451
 
        t = self.get_transport()
452
 
        # Ensure that no working tree what created remotely
453
 
        self.assertFalse(t.has('remote/file'))
454