~bzr-pqm/bzr/bzr.dev

« back to all changes in this revision

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

  • Committer: Vincent Ladeuil
  • Date: 2009-06-22 14:32:48 UTC
  • mto: (4471.1.1 integration)
  • mto: This revision was merged to the branch mainline in revision 4472.
  • Revision ID: v.ladeuil+lp@free.fr-20090622143248-pe4av866hxgzn60e
Use the same method or function names for _dirstate_helpers in pyrex and
python modules.

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
# Copyright (C) 2005, 2006, 2008, 2009 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 (branch, bzrdir, errors, repository)
 
23
from bzrlib.repofmt.knitrepo import RepositoryFormatKnit1
 
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
 
28
from bzrlib.workingtree import WorkingTree
 
29
 
 
30
 
 
31
class TestBranch(ExternalBase):
 
32
 
 
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')
 
41
 
 
42
    def test_branch(self):
 
43
        """Branch from one branch to another."""
 
44
        self.example_branch('a')
 
45
        self.run_bzr('branch a b')
 
46
        b = branch.Branch.open('b')
 
47
        self.run_bzr('branch a c -r 1')
 
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)
 
51
 
 
52
    def test_branch_only_copies_history(self):
 
53
        # Knit branches should only push the history for the current revision.
 
54
        format = bzrdir.BzrDirMetaFormat1()
 
55
        format.repository_format = RepositoryFormatKnit1()
 
56
        shared_repo = self.make_repository('repo', format=format, shared=True)
 
57
        shared_repo.set_make_working_trees(True)
 
58
 
 
59
        def make_shared_tree(path):
 
60
            shared_repo.bzrdir.root_transport.mkdir(path)
 
61
            shared_repo.bzrdir.create_branch_convenience('repo/' + path)
 
62
            return WorkingTree.open('repo/' + path)
 
63
        tree_a = make_shared_tree('a')
 
64
        self.build_tree(['repo/a/file'])
 
65
        tree_a.add('file')
 
66
        tree_a.commit('commit a-1', rev_id='a-1')
 
67
        f = open('repo/a/file', 'ab')
 
68
        f.write('more stuff\n')
 
69
        f.close()
 
70
        tree_a.commit('commit a-2', rev_id='a-2')
 
71
 
 
72
        tree_b = make_shared_tree('b')
 
73
        self.build_tree(['repo/b/file'])
 
74
        tree_b.add('file')
 
75
        tree_b.commit('commit b-1', rev_id='b-1')
 
76
 
 
77
        self.assertTrue(shared_repo.has_revision('a-1'))
 
78
        self.assertTrue(shared_repo.has_revision('a-2'))
 
79
        self.assertTrue(shared_repo.has_revision('b-1'))
 
80
 
 
81
        # Now that we have a repository with shared files, make sure
 
82
        # that things aren't copied out by a 'branch'
 
83
        self.run_bzr('branch repo/b branch-b')
 
84
        pushed_tree = WorkingTree.open('branch-b')
 
85
        pushed_repo = pushed_tree.branch.repository
 
86
        self.assertFalse(pushed_repo.has_revision('a-1'))
 
87
        self.assertFalse(pushed_repo.has_revision('a-2'))
 
88
        self.assertTrue(pushed_repo.has_revision('b-1'))
 
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
 
 
117
class TestBranchStacked(ExternalBase):
 
118
    """Tests for branch --stacked"""
 
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
 
 
143
    def assertRevisionInRepository(self, repo_path, revid):
 
144
        """Check that a revision is in a repository, disregarding stacking."""
 
145
        repo = bzrdir.BzrDir.open(repo_path).open_repository()
 
146
        self.assertTrue(repo.has_revision(revid))
 
147
 
 
148
    def assertRevisionNotInRepository(self, repo_path, revid):
 
149
        """Check that a revision is not in a repository, disregarding stacking."""
 
150
        repo = bzrdir.BzrDir.open(repo_path).open_repository()
 
151
        self.assertFalse(repo.has_revision(revid))
 
152
 
 
153
    def assertRevisionsInBranchRepository(self, revid_list, branch_path):
 
154
        repo = branch.Branch.open(branch_path).repository
 
155
        self.assertEqual(set(revid_list),
 
156
            repo.has_revisions(revid_list))
 
157
 
 
158
    def test_branch_stacked_branch_not_stacked(self):
 
159
        """Branching a stacked branch is not stacked by default"""
 
160
        # We have a mainline
 
161
        trunk_tree = self.make_branch_and_tree('target',
 
162
            format='1.9')
 
163
        trunk_tree.commit('mainline')
 
164
        # and a branch from it which is stacked
 
165
        branch_tree = self.make_branch_and_tree('branch',
 
166
            format='1.9')
 
167
        branch_tree.branch.set_stacked_on_url(trunk_tree.branch.base)
 
168
        # with some work on it
 
169
        branch_tree.commit('moar work plz')
 
170
        # branching our local branch gives us a new stacked branch pointing at
 
171
        # mainline.
 
172
        out, err = self.run_bzr(['branch', 'branch', 'newbranch'])
 
173
        self.assertEqual('', out)
 
174
        self.assertEqual('Branched 1 revision(s).\n',
 
175
            err)
 
176
        # it should have preserved the branch format, and so it should be
 
177
        # capable of supporting stacking, but not actually have a stacked_on
 
178
        # branch configured
 
179
        self.assertRaises(errors.NotStacked,
 
180
            bzrdir.BzrDir.open('newbranch').open_branch().get_stacked_on_url)
 
181
 
 
182
    def test_branch_stacked_branch_stacked(self):
 
183
        """Asking to stack on a stacked branch does work"""
 
184
        # We have a mainline
 
185
        trunk_tree = self.make_branch_and_tree('target',
 
186
            format='1.9')
 
187
        trunk_revid = trunk_tree.commit('mainline')
 
188
        # and a branch from it which is stacked
 
189
        branch_tree = self.make_branch_and_tree('branch',
 
190
            format='1.9')
 
191
        branch_tree.branch.set_stacked_on_url(trunk_tree.branch.base)
 
192
        # with some work on it
 
193
        branch_revid = branch_tree.commit('moar work plz')
 
194
        # you can chain branches on from there
 
195
        out, err = self.run_bzr(['branch', 'branch', '--stacked', 'branch2'])
 
196
        self.assertEqual('', out)
 
197
        self.assertEqual('Created new stacked branch referring to %s.\n' %
 
198
            branch_tree.branch.base, err)
 
199
        self.assertEqual(branch_tree.branch.base,
 
200
            branch.Branch.open('branch2').get_stacked_on_url())
 
201
        branch2_tree = WorkingTree.open('branch2')
 
202
        branch2_revid = branch2_tree.commit('work on second stacked branch')
 
203
        self.assertRevisionInRepository('branch2', branch2_revid)
 
204
        self.assertRevisionsInBranchRepository(
 
205
            [trunk_revid, branch_revid, branch2_revid],
 
206
            'branch2')
 
207
 
 
208
    def test_branch_stacked(self):
 
209
        # We have a mainline
 
210
        trunk_tree = self.make_branch_and_tree('mainline',
 
211
            format='1.9')
 
212
        original_revid = trunk_tree.commit('mainline')
 
213
        self.assertRevisionInRepository('mainline', original_revid)
 
214
        # and a branch from it which is stacked
 
215
        out, err = self.run_bzr(['branch', '--stacked', 'mainline',
 
216
            'newbranch'])
 
217
        self.assertEqual('', out)
 
218
        self.assertEqual('Created new stacked branch referring to %s.\n' %
 
219
            trunk_tree.branch.base, err)
 
220
        self.assertRevisionNotInRepository('newbranch', original_revid)
 
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)
 
224
 
 
225
    def test_branch_stacked_from_smart_server(self):
 
226
        # We can branch stacking on a smart server
 
227
        from bzrlib.smart.server import SmartTCPServer_for_testing
 
228
        self.transport_server = SmartTCPServer_for_testing
 
229
        trunk = self.make_branch('mainline', format='1.9')
 
230
        out, err = self.run_bzr(
 
231
            ['branch', '--stacked', self.get_url('mainline'), 'shallow'])
 
232
 
 
233
    def test_branch_stacked_from_non_stacked_format(self):
 
234
        """The origin format doesn't support stacking"""
 
235
        trunk = self.make_branch('trunk', format='pack-0.92')
 
236
        out, err = self.run_bzr(
 
237
            ['branch', '--stacked', 'trunk', 'shallow'])
 
238
        # We should notify the user that we upgraded their format
 
239
        self.assertEqualDiff(
 
240
            'Source repository format does not support stacking, using format:\n'
 
241
            '  Packs 5 (adds stacking support, requires bzr 1.6)\n'
 
242
            'Source branch format does not support stacking, using format:\n'
 
243
            '  Branch format 7\n'
 
244
            'Created new stacked branch referring to %s.\n' % (trunk.base,),
 
245
            err)
 
246
 
 
247
    def test_branch_stacked_from_rich_root_non_stackable(self):
 
248
        trunk = self.make_branch('trunk', format='rich-root-pack')
 
249
        out, err = self.run_bzr(
 
250
            ['branch', '--stacked', 'trunk', 'shallow'])
 
251
        # We should notify the user that we upgraded their format
 
252
        self.assertEqualDiff(
 
253
            'Source repository format does not support stacking, using format:\n'
 
254
            '  Packs 5 rich-root (adds stacking support, requires bzr 1.6.1)\n'
 
255
            'Source branch format does not support stacking, using format:\n'
 
256
            '  Branch format 7\n'
 
257
            'Created new stacked branch referring to %s.\n' % (trunk.base,),
 
258
            err)
 
259
 
 
260
 
 
261
class TestSmartServerBranching(ExternalBase):
 
262
 
 
263
    def test_branch_from_trivial_branch_to_same_server_branch_acceptance(self):
 
264
        self.setup_smart_server_with_call_log()
 
265
        t = self.make_branch_and_tree('from')
 
266
        for count in range(9):
 
267
            t.commit(message='commit %d' % count)
 
268
        self.reset_smart_call_log()
 
269
        out, err = self.run_bzr(['branch', self.get_url('from'),
 
270
            self.get_url('target')])
 
271
        # This figure represent the amount of work to perform this use case. It
 
272
        # is entirely ok to reduce this number if a test fails due to rpc_count
 
273
        # being too low. If rpc_count increases, more network roundtrips have
 
274
        # become necessary for this use case. Please do not adjust this number
 
275
        # upwards without agreement from bzr's network support maintainers.
 
276
        self.assertLength(38, self.hpss_calls)
 
277
 
 
278
    def test_branch_from_trivial_branch_streaming_acceptance(self):
 
279
        self.setup_smart_server_with_call_log()
 
280
        t = self.make_branch_and_tree('from')
 
281
        for count in range(9):
 
282
            t.commit(message='commit %d' % count)
 
283
        self.reset_smart_call_log()
 
284
        out, err = self.run_bzr(['branch', self.get_url('from'),
 
285
            'local-target'])
 
286
        # This figure represent the amount of work to perform this use case. It
 
287
        # is entirely ok to reduce this number if a test fails due to rpc_count
 
288
        # being too low. If rpc_count increases, more network roundtrips have
 
289
        # become necessary for this use case. Please do not adjust this number
 
290
        # upwards without agreement from bzr's network support maintainers.
 
291
        self.assertLength(10, self.hpss_calls)
 
292
 
 
293
    def test_branch_from_trivial_stacked_branch_streaming_acceptance(self):
 
294
        self.setup_smart_server_with_call_log()
 
295
        t = self.make_branch_and_tree('trunk')
 
296
        for count in range(8):
 
297
            t.commit(message='commit %d' % count)
 
298
        tree2 = t.branch.bzrdir.sprout('feature', stacked=True
 
299
            ).open_workingtree()
 
300
        tree2.commit('feature change')
 
301
        self.reset_smart_call_log()
 
302
        out, err = self.run_bzr(['branch', self.get_url('feature'),
 
303
            'local-target'])
 
304
        # This figure represent the amount of work to perform this use case. It
 
305
        # is entirely ok to reduce this number if a test fails due to rpc_count
 
306
        # being too low. If rpc_count increases, more network roundtrips have
 
307
        # become necessary for this use case. Please do not adjust this number
 
308
        # upwards without agreement from bzr's network support maintainers.
 
309
        self.assertLength(15, self.hpss_calls)
 
310
 
 
311
 
 
312
class TestRemoteBranch(TestCaseWithSFTPServer):
 
313
 
 
314
    def setUp(self):
 
315
        super(TestRemoteBranch, self).setUp()
 
316
        tree = self.make_branch_and_tree('branch')
 
317
        self.build_tree_contents([('branch/file', 'file content\n')])
 
318
        tree.add('file')
 
319
        tree.commit('file created')
 
320
 
 
321
    def test_branch_local_remote(self):
 
322
        self.run_bzr(['branch', 'branch', self.get_url('remote')])
 
323
        t = self.get_transport()
 
324
        # Ensure that no working tree what created remotely
 
325
        self.assertFalse(t.has('remote/file'))
 
326
 
 
327
    def test_branch_remote_remote(self):
 
328
        # Light cheat: we access the branch remotely
 
329
        self.run_bzr(['branch', self.get_url('branch'),
 
330
                      self.get_url('remote')])
 
331
        t = self.get_transport()
 
332
        # Ensure that no working tree what created remotely
 
333
        self.assertFalse(t.has('remote/file'))
 
334