~bzr-pqm/bzr/bzr.dev

« back to all changes in this revision

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

  • Committer: Andrew Bennetts
  • Date: 2009-03-04 07:10:07 UTC
  • mto: (4086.1.2 hpss-integration)
  • mto: This revision was merged to the branch mainline in revision 4087.
  • Revision ID: andrew.bennetts@canonical.com-20090304071007-8iqoi1m44ypmzg2a
Rough prototype of allowing a SearchResult to be passed to fetch, and using that to improve network conversations.

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
# Copyright (C) 2006-2010 Canonical Ltd
 
1
# Copyright (C) 2005, 2006, 2008, 2009 Canonical Ltd
2
2
#
3
3
# This program is free software; you can redistribute it and/or modify
4
4
# it under the terms of the GNU General Public License as published by
12
12
#
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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
 
15
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
16
16
 
17
17
 
18
18
"""Black-box tests for bzr branch."""
19
19
 
20
20
import os
21
21
 
22
 
from bzrlib import (
23
 
    branch,
24
 
    bzrdir,
25
 
    errors,
26
 
    repository,
27
 
    revision as _mod_revision,
28
 
    )
 
22
from bzrlib import (branch, bzrdir, errors, repository)
29
23
from bzrlib.repofmt.knitrepo import RepositoryFormatKnit1
30
 
from bzrlib.tests import TestCaseWithTransport
31
 
from bzrlib.tests import (
32
 
    KnownFailure,
33
 
    HardlinkFeature,
34
 
    test_server,
35
 
    )
 
24
from bzrlib.tests.blackbox import ExternalBase
 
25
from bzrlib.tests import HardlinkFeature
36
26
from bzrlib.tests.test_sftp_transport import TestCaseWithSFTPServer
37
27
from bzrlib.urlutils import local_path_to_url, strip_trailing_slash
38
28
from bzrlib.workingtree import WorkingTree
39
29
 
40
30
 
41
 
class TestBranch(TestCaseWithTransport):
 
31
class TestBranch(ExternalBase):
42
32
 
43
33
    def example_branch(self, path='.'):
44
34
        tree = self.make_branch_and_tree(path)
59
49
        self.assertFalse(b._transport.has('branch-name'))
60
50
        b.bzrdir.open_workingtree().commit(message='foo', allow_pointless=True)
61
51
 
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
52
    def test_branch_only_copies_history(self):
129
53
        # Knit branches should only push the history for the current revision.
130
54
        format = bzrdir.BzrDirMetaFormat1()
169
93
        self.build_tree(['source/file1'])
170
94
        source.add('file1')
171
95
        source.commit('added file')
172
 
        out, err = self.run_bzr(['branch', 'source', 'target', '--hardlink'])
 
96
        self.run_bzr(['branch', 'source', 'target', '--hardlink'])
173
97
        source_stat = os.stat('source/file1')
174
98
        target_stat = os.stat('target/file1')
175
99
        self.assertEqual(source_stat, target_stat)
176
100
 
177
 
    def test_branch_files_from(self):
178
 
        source = self.make_branch_and_tree('source')
179
 
        self.build_tree(['source/file1'])
180
 
        source.add('file1')
181
 
        source.commit('added file')
182
 
        out, err = self.run_bzr('branch source target --files-from source')
183
 
        self.failUnlessExists('target/file1')
184
 
 
185
 
    def test_branch_files_from_hardlink(self):
186
 
        self.requireFeature(HardlinkFeature)
187
 
        source = self.make_branch_and_tree('source')
188
 
        self.build_tree(['source/file1'])
189
 
        source.add('file1')
190
 
        source.commit('added file')
191
 
        source.bzrdir.sprout('second')
192
 
        out, err = self.run_bzr('branch source target --files-from second'
193
 
                                ' --hardlink')
194
 
        source_stat = os.stat('source/file1')
195
 
        second_stat = os.stat('second/file1')
196
 
        target_stat = os.stat('target/file1')
197
 
        self.assertNotEqual(source_stat, target_stat)
198
 
        self.assertEqual(second_stat, target_stat)
199
 
 
200
101
    def test_branch_standalone(self):
201
102
        shared_repo = self.make_repository('repo', shared=True)
202
103
        self.example_branch('source')
212
113
        self.failIfExists('target/hello')
213
114
        self.failIfExists('target/goodbye')
214
115
 
215
 
    def test_branch_into_existing_dir(self):
216
 
        self.example_branch('a')
217
 
        # existing dir with similar files but no .bzr dir
218
 
        self.build_tree_contents([('b/',)])
219
 
        self.build_tree_contents([('b/hello', 'bar')])  # different content
220
 
        self.build_tree_contents([('b/goodbye', 'baz')])# same content
221
 
        # fails without --use-existing-dir
222
 
        out,err = self.run_bzr('branch a b', retcode=3)
223
 
        self.assertEqual('', out)
224
 
        self.assertEqual('bzr: ERROR: Target directory "b" already exists.\n',
225
 
            err)
226
 
        # force operation
227
 
        self.run_bzr('branch a b --use-existing-dir')
228
 
        # check conflicts
229
 
        self.failUnlessExists('b/hello.moved')
230
 
        self.failIfExists('b/godbye.moved')
231
 
        # we can't branch into branch
232
 
        out,err = self.run_bzr('branch a b --use-existing-dir', retcode=3)
233
 
        self.assertEqual('', out)
234
 
        self.assertEqual('bzr: ERROR: Already a branch: "b".\n', err)
235
 
 
236
 
    def test_branch_bind(self):
237
 
        self.example_branch('a')
238
 
        out, err = self.run_bzr('branch a b --bind')
239
 
        self.assertEndsWith(err, "New branch bound to a\n")
240
 
        b = branch.Branch.open('b')
241
 
        self.assertEndsWith(b.get_bound_location(), '/a/')
242
 
 
243
 
    def test_branch_with_post_branch_init_hook(self):
244
 
        calls = []
245
 
        branch.Branch.hooks.install_named_hook('post_branch_init',
246
 
            calls.append, None)
247
 
        self.assertLength(0, calls)
248
 
        self.example_branch('a')
249
 
        self.assertLength(1, calls)
250
 
        self.run_bzr('branch a b')
251
 
        self.assertLength(2, calls)
252
 
 
253
 
    def test_checkout_with_post_branch_init_hook(self):
254
 
        calls = []
255
 
        branch.Branch.hooks.install_named_hook('post_branch_init',
256
 
            calls.append, None)
257
 
        self.assertLength(0, calls)
258
 
        self.example_branch('a')
259
 
        self.assertLength(1, calls)
260
 
        self.run_bzr('checkout a b')
261
 
        self.assertLength(2, calls)
262
 
 
263
 
    def test_lightweight_checkout_with_post_branch_init_hook(self):
264
 
        calls = []
265
 
        branch.Branch.hooks.install_named_hook('post_branch_init',
266
 
            calls.append, None)
267
 
        self.assertLength(0, calls)
268
 
        self.example_branch('a')
269
 
        self.assertLength(1, calls)
270
 
        self.run_bzr('checkout --lightweight a b')
271
 
        self.assertLength(2, calls)
272
 
 
273
 
 
274
 
class TestBranchStacked(TestCaseWithTransport):
 
116
 
 
117
class TestBranchStacked(ExternalBase):
275
118
    """Tests for branch --stacked"""
276
119
 
 
120
    def check_shallow_branch(self, branch_revid, stacked_on):
 
121
        """Assert that the branch 'newbranch' has been published correctly.
 
122
 
 
123
        :param stacked_on: url of a branch this one is stacked upon.
 
124
        :param branch_revid: a revision id that should be the only
 
125
            revision present in the stacked branch, and it should not be in
 
126
            the reference branch.
 
127
        """
 
128
        new_branch = branch.Branch.open('newbranch')
 
129
        # The branch refers to the mainline
 
130
        self.assertEqual(stacked_on, new_branch.get_stacked_on_url())
 
131
        # and the branch's work was pushed
 
132
        self.assertTrue(new_branch.repository.has_revision(branch_revid))
 
133
        # The newly committed revision shoud be present in the stacked branch,
 
134
        # but not in the stacked-on branch.  Because stacking is set up by the
 
135
        # branch object, if we open the stacked branch's repository directly,
 
136
        # bypassing the branch, we see only what's in the stacked repository.
 
137
        stacked_repo = bzrdir.BzrDir.open('newbranch').open_repository()
 
138
        stacked_repo_revisions = set(stacked_repo.all_revision_ids())
 
139
        if len(stacked_repo_revisions) != 1:
 
140
            self.fail("wrong revisions in stacked repository: %r"
 
141
                % (stacked_repo_revisions,))
 
142
 
277
143
    def assertRevisionInRepository(self, repo_path, revid):
278
144
        """Check that a revision is in a repository, disregarding stacking."""
279
145
        repo = bzrdir.BzrDir.open(repo_path).open_repository()
293
159
        """Branching a stacked branch is not stacked by default"""
294
160
        # We have a mainline
295
161
        trunk_tree = self.make_branch_and_tree('target',
296
 
            format='1.9')
 
162
            format='development')
297
163
        trunk_tree.commit('mainline')
298
164
        # and a branch from it which is stacked
299
165
        branch_tree = self.make_branch_and_tree('branch',
300
 
            format='1.9')
 
166
            format='development')
301
167
        branch_tree.branch.set_stacked_on_url(trunk_tree.branch.base)
302
168
        # with some work on it
303
 
        work_tree = trunk_tree.branch.bzrdir.sprout('local').open_workingtree()
304
 
        work_tree.commit('moar work plz')
305
 
        work_tree.branch.push(branch_tree.branch)
 
169
        branch_tree.commit('moar work plz')
306
170
        # branching our local branch gives us a new stacked branch pointing at
307
171
        # mainline.
308
172
        out, err = self.run_bzr(['branch', 'branch', 'newbranch'])
309
173
        self.assertEqual('', out)
310
 
        self.assertEqual('Branched 2 revision(s).\n',
 
174
        self.assertEqual('Branched 1 revision(s).\n',
311
175
            err)
312
176
        # it should have preserved the branch format, and so it should be
313
177
        # capable of supporting stacking, but not actually have a stacked_on
319
183
        """Asking to stack on a stacked branch does work"""
320
184
        # We have a mainline
321
185
        trunk_tree = self.make_branch_and_tree('target',
322
 
            format='1.9')
 
186
            format='development')
323
187
        trunk_revid = trunk_tree.commit('mainline')
324
188
        # and a branch from it which is stacked
325
189
        branch_tree = self.make_branch_and_tree('branch',
326
 
            format='1.9')
 
190
            format='development')
327
191
        branch_tree.branch.set_stacked_on_url(trunk_tree.branch.base)
328
192
        # with some work on it
329
 
        work_tree = trunk_tree.branch.bzrdir.sprout('local').open_workingtree()
330
 
        branch_revid = work_tree.commit('moar work plz')
331
 
        work_tree.branch.push(branch_tree.branch)
 
193
        branch_revid = branch_tree.commit('moar work plz')
332
194
        # you can chain branches on from there
333
195
        out, err = self.run_bzr(['branch', 'branch', '--stacked', 'branch2'])
334
196
        self.assertEqual('', out)
337
199
        self.assertEqual(branch_tree.branch.base,
338
200
            branch.Branch.open('branch2').get_stacked_on_url())
339
201
        branch2_tree = WorkingTree.open('branch2')
340
 
        branch2_revid = work_tree.commit('work on second stacked branch')
341
 
        work_tree.branch.push(branch2_tree.branch)
 
202
        branch2_revid = branch2_tree.commit('work on second stacked branch')
342
203
        self.assertRevisionInRepository('branch2', branch2_revid)
343
204
        self.assertRevisionsInBranchRepository(
344
205
            [trunk_revid, branch_revid, branch2_revid],
347
208
    def test_branch_stacked(self):
348
209
        # We have a mainline
349
210
        trunk_tree = self.make_branch_and_tree('mainline',
350
 
            format='1.9')
 
211
            format='development')
351
212
        original_revid = trunk_tree.commit('mainline')
352
213
        self.assertRevisionInRepository('mainline', original_revid)
353
214
        # and a branch from it which is stacked
357
218
        self.assertEqual('Created new stacked branch referring to %s.\n' %
358
219
            trunk_tree.branch.base, err)
359
220
        self.assertRevisionNotInRepository('newbranch', original_revid)
360
 
        new_branch = branch.Branch.open('newbranch')
361
 
        self.assertEqual(trunk_tree.branch.base, new_branch.get_stacked_on_url())
 
221
        new_tree = WorkingTree.open('newbranch')
 
222
        new_revid = new_tree.commit('new work')
 
223
        self.check_shallow_branch(new_revid, trunk_tree.branch.base)
362
224
 
363
225
    def test_branch_stacked_from_smart_server(self):
364
226
        # We can branch stacking on a smart server
365
 
        self.transport_server = test_server.SmartTCPServer_for_testing
366
 
        trunk = self.make_branch('mainline', format='1.9')
 
227
        from bzrlib.smart.server import SmartTCPServer_for_testing
 
228
        self.transport_server = SmartTCPServer_for_testing
 
229
        trunk = self.make_branch('mainline', format='development')
367
230
        out, err = self.run_bzr(
368
231
            ['branch', '--stacked', self.get_url('mainline'), 'shallow'])
369
232
 
374
237
            ['branch', '--stacked', 'trunk', 'shallow'])
375
238
        # We should notify the user that we upgraded their format
376
239
        self.assertEqualDiff(
377
 
            'Source repository format does not support stacking, using format:\n'
 
240
            'Source format does not support stacking, using format: \'1.6\'\n'
378
241
            '  Packs 5 (adds stacking support, requires bzr 1.6)\n'
379
 
            'Source branch format does not support stacking, using format:\n'
380
 
            '  Branch format 7\n'
381
 
            'Doing on-the-fly conversion from RepositoryFormatKnitPack1() to RepositoryFormatKnitPack5().\n'
382
 
            'This may take some time. Upgrade the repositories to the same format for better performance.\n'
 
242
            '\n'
383
243
            'Created new stacked branch referring to %s.\n' % (trunk.base,),
384
244
            err)
385
245
 
389
249
            ['branch', '--stacked', 'trunk', 'shallow'])
390
250
        # We should notify the user that we upgraded their format
391
251
        self.assertEqualDiff(
392
 
            'Source repository format does not support stacking, using format:\n'
 
252
            'Source format does not support stacking, using format:'
 
253
            ' \'1.6.1-rich-root\'\n'
393
254
            '  Packs 5 rich-root (adds stacking support, requires bzr 1.6.1)\n'
394
 
            'Source branch format does not support stacking, using format:\n'
395
 
            '  Branch format 7\n'
396
 
            'Doing on-the-fly conversion from RepositoryFormatKnitPack4() to RepositoryFormatKnitPack5RichRoot().\n'
397
 
            'This may take some time. Upgrade the repositories to the same format for better performance.\n'
 
255
            '\n'
398
256
            'Created new stacked branch referring to %s.\n' % (trunk.base,),
399
257
            err)
400
258
 
401
259
 
402
 
class TestSmartServerBranching(TestCaseWithTransport):
 
260
class TestSmartServerBranching(ExternalBase):
403
261
 
404
262
    def test_branch_from_trivial_branch_to_same_server_branch_acceptance(self):
405
263
        self.setup_smart_server_with_call_log()
409
267
        self.reset_smart_call_log()
410
268
        out, err = self.run_bzr(['branch', self.get_url('from'),
411
269
            self.get_url('target')])
 
270
        rpc_count = len(self.hpss_calls)
412
271
        # This figure represent the amount of work to perform this use case. It
413
272
        # is entirely ok to reduce this number if a test fails due to rpc_count
414
273
        # being too low. If rpc_count increases, more network roundtrips have
415
274
        # become necessary for this use case. Please do not adjust this number
416
275
        # upwards without agreement from bzr's network support maintainers.
417
 
        self.assertLength(38, self.hpss_calls)
 
276
        self.assertEqual(99, rpc_count)
418
277
 
419
278
    def test_branch_from_trivial_branch_streaming_acceptance(self):
420
279
        self.setup_smart_server_with_call_log()
424
283
        self.reset_smart_call_log()
425
284
        out, err = self.run_bzr(['branch', self.get_url('from'),
426
285
            'local-target'])
427
 
        # This figure represent the amount of work to perform this use case. It
428
 
        # is entirely ok to reduce this number if a test fails due to rpc_count
429
 
        # being too low. If rpc_count increases, more network roundtrips have
430
 
        # become necessary for this use case. Please do not adjust this number
431
 
        # upwards without agreement from bzr's network support maintainers.
432
 
        self.assertLength(10, self.hpss_calls)
433
 
 
434
 
    def test_branch_from_trivial_stacked_branch_streaming_acceptance(self):
435
 
        self.setup_smart_server_with_call_log()
436
 
        t = self.make_branch_and_tree('trunk')
437
 
        for count in range(8):
438
 
            t.commit(message='commit %d' % count)
439
 
        tree2 = t.branch.bzrdir.sprout('feature', stacked=True
440
 
            ).open_workingtree()
441
 
        local_tree = t.branch.bzrdir.sprout('local-working').open_workingtree()
442
 
        local_tree.commit('feature change')
443
 
        local_tree.branch.push(tree2.branch)
444
 
        self.reset_smart_call_log()
445
 
        out, err = self.run_bzr(['branch', self.get_url('feature'),
446
 
            'local-target'])
447
 
        # This figure represent the amount of work to perform this use case. It
448
 
        # is entirely ok to reduce this number if a test fails due to rpc_count
449
 
        # being too low. If rpc_count increases, more network roundtrips have
450
 
        # become necessary for this use case. Please do not adjust this number
451
 
        # upwards without agreement from bzr's network support maintainers.
452
 
        self.assertLength(15, self.hpss_calls)
 
286
        rpc_count = len(self.hpss_calls)
 
287
        # This figure represent the amount of work to perform this use case. It
 
288
        # is entirely ok to reduce this number if a test fails due to rpc_count
 
289
        # being too low. If rpc_count increases, more network roundtrips have
 
290
        # become necessary for this use case. Please do not adjust this number
 
291
        # upwards without agreement from bzr's network support maintainers.
 
292
        self.assertEqual(25, rpc_count)
453
293
 
454
294
 
455
295
class TestRemoteBranch(TestCaseWithSFTPServer):