~bzr-pqm/bzr/bzr.dev

« back to all changes in this revision

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

  • Committer: Robert Collins
  • Date: 2009-07-07 04:32:13 UTC
  • mto: This revision was merged to the branch mainline in revision 4524.
  • Revision ID: robertc@robertcollins.net-20090707043213-4hjjhgr40iq7gk2d
More informative assertions in xml serialisation.

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
# Copyright (C) 2005, 2006 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., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 
15
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 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 branch, bzrdir
 
22
from bzrlib import (branch, bzrdir, errors, repository)
23
23
from bzrlib.repofmt.knitrepo import RepositoryFormatKnit1
24
24
from bzrlib.tests.blackbox import ExternalBase
 
25
from bzrlib.tests import HardlinkFeature
 
26
from bzrlib.tests.test_sftp_transport import TestCaseWithSFTPServer
 
27
from bzrlib.urlutils import local_path_to_url, strip_trailing_slash
25
28
from bzrlib.workingtree import WorkingTree
26
29
 
27
30
 
28
31
class TestBranch(ExternalBase):
29
32
 
30
 
    def example_branch(test):
31
 
        test.run_bzr('init')
32
 
        file('hello', 'wt').write('foo')
33
 
        test.run_bzr('add hello')
34
 
        test.run_bzr('commit -m setup hello')
35
 
        file('goodbye', 'wt').write('baz')
36
 
        test.run_bzr('add goodbye')
37
 
        test.run_bzr('commit -m setup goodbye')
 
33
    def example_branch(self, path='.'):
 
34
        tree = self.make_branch_and_tree(path)
 
35
        self.build_tree_contents([(path + '/hello', 'foo')])
 
36
        tree.add('hello')
 
37
        tree.commit(message='setup')
 
38
        self.build_tree_contents([(path + '/goodbye', 'baz')])
 
39
        tree.add('goodbye')
 
40
        tree.commit(message='setup')
38
41
 
39
42
    def test_branch(self):
40
43
        """Branch from one branch to another."""
41
 
        os.mkdir('a')
42
 
        os.chdir('a')
43
 
        self.example_branch()
44
 
        os.chdir('..')
 
44
        self.example_branch('a')
45
45
        self.run_bzr('branch a b')
46
46
        b = branch.Branch.open('b')
47
 
        self.assertEqual('b\n', b.control_files.get_utf8('branch-name').read())
48
47
        self.run_bzr('branch a c -r 1')
49
 
        os.chdir('b')
50
 
        self.run_bzr('commit -m foo --unchanged')
51
 
        os.chdir('..')
 
48
        # previously was erroneously created by branching
 
49
        self.assertFalse(b._transport.has('branch-name'))
 
50
        b.bzrdir.open_workingtree().commit(message='foo', allow_pointless=True)
52
51
 
53
52
    def test_branch_only_copies_history(self):
54
53
        # Knit branches should only push the history for the current revision.
88
87
        self.assertFalse(pushed_repo.has_revision('a-2'))
89
88
        self.assertTrue(pushed_repo.has_revision('b-1'))
90
89
 
 
90
    def test_branch_hardlink(self):
 
91
        self.requireFeature(HardlinkFeature)
 
92
        source = self.make_branch_and_tree('source')
 
93
        self.build_tree(['source/file1'])
 
94
        source.add('file1')
 
95
        source.commit('added file')
 
96
        self.run_bzr(['branch', 'source', 'target', '--hardlink'])
 
97
        source_stat = os.stat('source/file1')
 
98
        target_stat = os.stat('target/file1')
 
99
        self.assertEqual(source_stat, target_stat)
 
100
 
 
101
    def test_branch_standalone(self):
 
102
        shared_repo = self.make_repository('repo', shared=True)
 
103
        self.example_branch('source')
 
104
        self.run_bzr('branch --standalone source repo/target')
 
105
        b = branch.Branch.open('repo/target')
 
106
        expected_repo_path = os.path.abspath('repo/target/.bzr/repository')
 
107
        self.assertEqual(strip_trailing_slash(b.repository.base),
 
108
            strip_trailing_slash(local_path_to_url(expected_repo_path)))
 
109
 
 
110
    def test_branch_no_tree(self):
 
111
        self.example_branch('source')
 
112
        self.run_bzr('branch --no-tree source target')
 
113
        self.failIfExists('target/hello')
 
114
        self.failIfExists('target/goodbye')
 
115
 
 
116
    def test_branch_into_existing_dir(self):
 
117
        self.example_branch('a')
 
118
        # existing dir with similar files but no .bzr dir
 
119
        self.build_tree_contents([('b/',)])
 
120
        self.build_tree_contents([('b/hello', 'bar')])  # different content
 
121
        self.build_tree_contents([('b/goodbye', 'baz')])# same content
 
122
        # fails without --use-existing-dir
 
123
        out,err = self.run_bzr('branch a b', retcode=3)
 
124
        self.assertEqual('', out)
 
125
        self.assertEqual('bzr: ERROR: Target directory "b" already exists.\n',
 
126
            err)
 
127
        # force operation
 
128
        self.run_bzr('branch a b --use-existing-dir')
 
129
        # check conflicts
 
130
        self.failUnlessExists('b/hello.moved')
 
131
        self.failIfExists('b/godbye.moved')
 
132
        # we can't branch into branch
 
133
        out,err = self.run_bzr('branch a b --use-existing-dir', retcode=3)
 
134
        self.assertEqual('', out)
 
135
        self.assertEqual('bzr: ERROR: Already a branch: "b".\n', err)
 
136
 
 
137
 
 
138
class TestBranchStacked(ExternalBase):
 
139
    """Tests for branch --stacked"""
 
140
 
 
141
    def check_shallow_branch(self, branch_revid, stacked_on):
 
142
        """Assert that the branch 'newbranch' has been published correctly.
 
143
 
 
144
        :param stacked_on: url of a branch this one is stacked upon.
 
145
        :param branch_revid: a revision id that should be the only
 
146
            revision present in the stacked branch, and it should not be in
 
147
            the reference branch.
 
148
        """
 
149
        new_branch = branch.Branch.open('newbranch')
 
150
        # The branch refers to the mainline
 
151
        self.assertEqual(stacked_on, new_branch.get_stacked_on_url())
 
152
        # and the branch's work was pushed
 
153
        self.assertTrue(new_branch.repository.has_revision(branch_revid))
 
154
        # The newly committed revision shoud be present in the stacked branch,
 
155
        # but not in the stacked-on branch.  Because stacking is set up by the
 
156
        # branch object, if we open the stacked branch's repository directly,
 
157
        # bypassing the branch, we see only what's in the stacked repository.
 
158
        stacked_repo = bzrdir.BzrDir.open('newbranch').open_repository()
 
159
        stacked_repo_revisions = set(stacked_repo.all_revision_ids())
 
160
        if len(stacked_repo_revisions) != 1:
 
161
            self.fail("wrong revisions in stacked repository: %r"
 
162
                % (stacked_repo_revisions,))
 
163
 
 
164
    def assertRevisionInRepository(self, repo_path, revid):
 
165
        """Check that a revision is in a repository, disregarding stacking."""
 
166
        repo = bzrdir.BzrDir.open(repo_path).open_repository()
 
167
        self.assertTrue(repo.has_revision(revid))
 
168
 
 
169
    def assertRevisionNotInRepository(self, repo_path, revid):
 
170
        """Check that a revision is not in a repository, disregarding stacking."""
 
171
        repo = bzrdir.BzrDir.open(repo_path).open_repository()
 
172
        self.assertFalse(repo.has_revision(revid))
 
173
 
 
174
    def assertRevisionsInBranchRepository(self, revid_list, branch_path):
 
175
        repo = branch.Branch.open(branch_path).repository
 
176
        self.assertEqual(set(revid_list),
 
177
            repo.has_revisions(revid_list))
 
178
 
 
179
    def test_branch_stacked_branch_not_stacked(self):
 
180
        """Branching a stacked branch is not stacked by default"""
 
181
        # We have a mainline
 
182
        trunk_tree = self.make_branch_and_tree('target',
 
183
            format='1.9')
 
184
        trunk_tree.commit('mainline')
 
185
        # and a branch from it which is stacked
 
186
        branch_tree = self.make_branch_and_tree('branch',
 
187
            format='1.9')
 
188
        branch_tree.branch.set_stacked_on_url(trunk_tree.branch.base)
 
189
        # with some work on it
 
190
        branch_tree.commit('moar work plz')
 
191
        # branching our local branch gives us a new stacked branch pointing at
 
192
        # mainline.
 
193
        out, err = self.run_bzr(['branch', 'branch', 'newbranch'])
 
194
        self.assertEqual('', out)
 
195
        self.assertEqual('Branched 1 revision(s).\n',
 
196
            err)
 
197
        # it should have preserved the branch format, and so it should be
 
198
        # capable of supporting stacking, but not actually have a stacked_on
 
199
        # branch configured
 
200
        self.assertRaises(errors.NotStacked,
 
201
            bzrdir.BzrDir.open('newbranch').open_branch().get_stacked_on_url)
 
202
 
 
203
    def test_branch_stacked_branch_stacked(self):
 
204
        """Asking to stack on a stacked branch does work"""
 
205
        # We have a mainline
 
206
        trunk_tree = self.make_branch_and_tree('target',
 
207
            format='1.9')
 
208
        trunk_revid = trunk_tree.commit('mainline')
 
209
        # and a branch from it which is stacked
 
210
        branch_tree = self.make_branch_and_tree('branch',
 
211
            format='1.9')
 
212
        branch_tree.branch.set_stacked_on_url(trunk_tree.branch.base)
 
213
        # with some work on it
 
214
        branch_revid = branch_tree.commit('moar work plz')
 
215
        # you can chain branches on from there
 
216
        out, err = self.run_bzr(['branch', 'branch', '--stacked', 'branch2'])
 
217
        self.assertEqual('', out)
 
218
        self.assertEqual('Created new stacked branch referring to %s.\n' %
 
219
            branch_tree.branch.base, err)
 
220
        self.assertEqual(branch_tree.branch.base,
 
221
            branch.Branch.open('branch2').get_stacked_on_url())
 
222
        branch2_tree = WorkingTree.open('branch2')
 
223
        branch2_revid = branch2_tree.commit('work on second stacked branch')
 
224
        self.assertRevisionInRepository('branch2', branch2_revid)
 
225
        self.assertRevisionsInBranchRepository(
 
226
            [trunk_revid, branch_revid, branch2_revid],
 
227
            'branch2')
 
228
 
 
229
    def test_branch_stacked(self):
 
230
        # We have a mainline
 
231
        trunk_tree = self.make_branch_and_tree('mainline',
 
232
            format='1.9')
 
233
        original_revid = trunk_tree.commit('mainline')
 
234
        self.assertRevisionInRepository('mainline', original_revid)
 
235
        # and a branch from it which is stacked
 
236
        out, err = self.run_bzr(['branch', '--stacked', 'mainline',
 
237
            'newbranch'])
 
238
        self.assertEqual('', out)
 
239
        self.assertEqual('Created new stacked branch referring to %s.\n' %
 
240
            trunk_tree.branch.base, err)
 
241
        self.assertRevisionNotInRepository('newbranch', original_revid)
 
242
        new_tree = WorkingTree.open('newbranch')
 
243
        new_revid = new_tree.commit('new work')
 
244
        self.check_shallow_branch(new_revid, trunk_tree.branch.base)
 
245
 
 
246
    def test_branch_stacked_from_smart_server(self):
 
247
        # We can branch stacking on a smart server
 
248
        from bzrlib.smart.server import SmartTCPServer_for_testing
 
249
        self.transport_server = SmartTCPServer_for_testing
 
250
        trunk = self.make_branch('mainline', format='1.9')
 
251
        out, err = self.run_bzr(
 
252
            ['branch', '--stacked', self.get_url('mainline'), 'shallow'])
 
253
 
 
254
    def test_branch_stacked_from_non_stacked_format(self):
 
255
        """The origin format doesn't support stacking"""
 
256
        trunk = self.make_branch('trunk', format='pack-0.92')
 
257
        out, err = self.run_bzr(
 
258
            ['branch', '--stacked', 'trunk', 'shallow'])
 
259
        # We should notify the user that we upgraded their format
 
260
        self.assertEqualDiff(
 
261
            'Source repository format does not support stacking, using format:\n'
 
262
            '  Packs 5 (adds stacking support, requires bzr 1.6)\n'
 
263
            'Source branch format does not support stacking, using format:\n'
 
264
            '  Branch format 7\n'
 
265
            'Created new stacked branch referring to %s.\n' % (trunk.base,),
 
266
            err)
 
267
 
 
268
    def test_branch_stacked_from_rich_root_non_stackable(self):
 
269
        trunk = self.make_branch('trunk', format='rich-root-pack')
 
270
        out, err = self.run_bzr(
 
271
            ['branch', '--stacked', 'trunk', 'shallow'])
 
272
        # We should notify the user that we upgraded their format
 
273
        self.assertEqualDiff(
 
274
            'Source repository format does not support stacking, using format:\n'
 
275
            '  Packs 5 rich-root (adds stacking support, requires bzr 1.6.1)\n'
 
276
            'Source branch format does not support stacking, using format:\n'
 
277
            '  Branch format 7\n'
 
278
            'Created new stacked branch referring to %s.\n' % (trunk.base,),
 
279
            err)
 
280
 
 
281
 
 
282
class TestSmartServerBranching(ExternalBase):
 
283
 
 
284
    def test_branch_from_trivial_branch_to_same_server_branch_acceptance(self):
 
285
        self.setup_smart_server_with_call_log()
 
286
        t = self.make_branch_and_tree('from')
 
287
        for count in range(9):
 
288
            t.commit(message='commit %d' % count)
 
289
        self.reset_smart_call_log()
 
290
        out, err = self.run_bzr(['branch', self.get_url('from'),
 
291
            self.get_url('target')])
 
292
        # This figure represent the amount of work to perform this use case. It
 
293
        # is entirely ok to reduce this number if a test fails due to rpc_count
 
294
        # being too low. If rpc_count increases, more network roundtrips have
 
295
        # become necessary for this use case. Please do not adjust this number
 
296
        # upwards without agreement from bzr's network support maintainers.
 
297
        self.assertLength(38, self.hpss_calls)
 
298
 
 
299
    def test_branch_from_trivial_branch_streaming_acceptance(self):
 
300
        self.setup_smart_server_with_call_log()
 
301
        t = self.make_branch_and_tree('from')
 
302
        for count in range(9):
 
303
            t.commit(message='commit %d' % count)
 
304
        self.reset_smart_call_log()
 
305
        out, err = self.run_bzr(['branch', self.get_url('from'),
 
306
            'local-target'])
 
307
        # This figure represent the amount of work to perform this use case. It
 
308
        # is entirely ok to reduce this number if a test fails due to rpc_count
 
309
        # being too low. If rpc_count increases, more network roundtrips have
 
310
        # become necessary for this use case. Please do not adjust this number
 
311
        # upwards without agreement from bzr's network support maintainers.
 
312
        self.assertLength(10, self.hpss_calls)
 
313
 
 
314
    def test_branch_from_trivial_stacked_branch_streaming_acceptance(self):
 
315
        self.setup_smart_server_with_call_log()
 
316
        t = self.make_branch_and_tree('trunk')
 
317
        for count in range(8):
 
318
            t.commit(message='commit %d' % count)
 
319
        tree2 = t.branch.bzrdir.sprout('feature', stacked=True
 
320
            ).open_workingtree()
 
321
        tree2.commit('feature change')
 
322
        self.reset_smart_call_log()
 
323
        out, err = self.run_bzr(['branch', self.get_url('feature'),
 
324
            'local-target'])
 
325
        # This figure represent the amount of work to perform this use case. It
 
326
        # is entirely ok to reduce this number if a test fails due to rpc_count
 
327
        # being too low. If rpc_count increases, more network roundtrips have
 
328
        # become necessary for this use case. Please do not adjust this number
 
329
        # upwards without agreement from bzr's network support maintainers.
 
330
        self.assertLength(15, self.hpss_calls)
 
331
 
 
332
 
 
333
class TestRemoteBranch(TestCaseWithSFTPServer):
 
334
 
 
335
    def setUp(self):
 
336
        super(TestRemoteBranch, self).setUp()
 
337
        tree = self.make_branch_and_tree('branch')
 
338
        self.build_tree_contents([('branch/file', 'file content\n')])
 
339
        tree.add('file')
 
340
        tree.commit('file created')
 
341
 
 
342
    def test_branch_local_remote(self):
 
343
        self.run_bzr(['branch', 'branch', self.get_url('remote')])
 
344
        t = self.get_transport()
 
345
        # Ensure that no working tree what created remotely
 
346
        self.assertFalse(t.has('remote/file'))
 
347
 
 
348
    def test_branch_remote_remote(self):
 
349
        # Light cheat: we access the branch remotely
 
350
        self.run_bzr(['branch', self.get_url('branch'),
 
351
                      self.get_url('remote')])
 
352
        t = self.get_transport()
 
353
        # Ensure that no working tree what created remotely
 
354
        self.assertFalse(t.has('remote/file'))
91
355