~bzr-pqm/bzr/bzr.dev

« back to all changes in this revision

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

  • Committer: John Arbash Meinel
  • Date: 2006-05-27 01:54:40 UTC
  • mto: (1711.2.26 jam-integration)
  • mto: This revision was merged to the branch mainline in revision 1734.
  • Revision ID: john@arbash-meinel.com-20060527015440-1a10495d8e56ed5f
deprecating appendpath, it does exactly what pathjoin does

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
# Copyright (C) 2005, 2007, 2008 Canonical Ltd
2
 
#
 
1
# Copyright (C) 2005 by Canonical Ltd
 
2
# -*- coding: utf-8 -*-
 
3
 
3
4
# This program is free software; you can redistribute it and/or modify
4
5
# it under the terms of the GNU General Public License as published by
5
6
# the Free Software Foundation; either version 2 of the License, or
6
7
# (at your option) any later version.
7
 
#
 
8
 
8
9
# This program is distributed in the hope that it will be useful,
9
10
# but WITHOUT ANY WARRANTY; without even the implied warranty of
10
11
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
11
12
# GNU General Public License for more details.
12
 
#
 
13
 
13
14
# You should have received a copy of the GNU General Public License
14
15
# along with this program; if not, write to the Free Software
15
16
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
18
19
"""Black-box tests for bzr push."""
19
20
 
20
21
import os
21
 
import re
22
22
 
23
 
from bzrlib import (
24
 
    errors,
25
 
    urlutils,
26
 
    )
 
23
import bzrlib
27
24
from bzrlib.branch import Branch
28
25
from bzrlib.bzrdir import BzrDirMetaFormat1
29
26
from bzrlib.osutils import abspath
30
 
from bzrlib.repofmt.knitrepo import RepositoryFormatKnit1
 
27
from bzrlib.repository import RepositoryFormatKnit1
31
28
from bzrlib.tests.blackbox import ExternalBase
32
 
from bzrlib.tests.http_server import HttpServer
33
 
from bzrlib.transport import register_transport, unregister_transport
34
 
from bzrlib.transport.memory import MemoryServer, MemoryTransport
35
29
from bzrlib.uncommit import uncommit
36
 
from bzrlib.urlutils import local_path_from_url
37
30
from bzrlib.workingtree import WorkingTree
38
31
 
39
32
 
59
52
        tree_b.commit('commit c')
60
53
        # initial push location must be empty
61
54
        self.assertEqual(None, branch_b.get_push_location())
62
 
 
63
55
        # test push for failure without push location set
64
56
        os.chdir('branch_a')
65
 
        out = self.run_bzr('push', retcode=3)
 
57
        out = self.runbzr('push', retcode=3)
66
58
        self.assertEquals(out,
67
59
                ('','bzr: ERROR: No push location known or specified.\n'))
68
 
 
69
 
        # test not remembered if cannot actually push
70
 
        self.run_bzr('push ../path/which/doesnt/exist', retcode=3)
71
 
        out = self.run_bzr('push', retcode=3)
72
 
        self.assertEquals(
73
 
                ('', 'bzr: ERROR: No push location known or specified.\n'),
74
 
                out)
75
 
 
76
60
        # test implicit --remember when no push location set, push fails
77
 
        out = self.run_bzr('push ../branch_b', retcode=3)
 
61
        out = self.runbzr('push ../branch_b', retcode=3)
78
62
        self.assertEquals(out,
79
63
                ('','bzr: ERROR: These branches have diverged.  '
80
 
                    'Try using "merge" and then "push".\n'))
 
64
                    'Try a merge then push with overwrite.\n'))
81
65
        self.assertEquals(abspath(branch_a.get_push_location()),
82
66
                          abspath(branch_b.bzrdir.root_transport.base))
83
 
 
84
67
        # test implicit --remember after resolving previous failure
85
68
        uncommit(branch=branch_b, tree=tree_b)
86
69
        transport.delete('branch_b/c')
87
 
        out, err = self.run_bzr('push')
88
 
        path = branch_a.get_push_location()
89
 
        self.assertEquals(out,
90
 
                          'Using saved push location: %s\n' 
91
 
                          'Pushed up to revision 2.\n'
92
 
                          % local_path_from_url(path))
93
 
        self.assertEqual(err,
94
 
                         'All changes applied successfully.\n')
95
 
        self.assertEqual(path,
96
 
                         branch_b.bzrdir.root_transport.base)
 
70
        self.runbzr('push')
 
71
        self.assertEquals(abspath(branch_a.get_push_location()),
 
72
                          abspath(branch_b.bzrdir.root_transport.base))
97
73
        # test explicit --remember
98
 
        self.run_bzr('push ../branch_c --remember')
99
 
        self.assertEquals(branch_a.get_push_location(),
100
 
                          branch_c.bzrdir.root_transport.base)
 
74
        self.runbzr('push ../branch_c --remember')
 
75
        self.assertEquals(abspath(branch_a.get_push_location()),
 
76
                          abspath(branch_c.bzrdir.root_transport.base))
101
77
    
102
78
    def test_push_without_tree(self):
103
79
        # bzr push from a branch that does not have a checkout should work.
104
80
        b = self.make_branch('.')
105
 
        out, err = self.run_bzr('push pushed-location')
 
81
        out, err = self.run_bzr('push', 'pushed-location')
106
82
        self.assertEqual('', out)
107
 
        self.assertEqual('Created new branch.\n', err)
108
 
        b2 = Branch.open('pushed-location')
 
83
        self.assertEqual('0 revision(s) pushed.\n', err)
 
84
        b2 = bzrlib.branch.Branch.open('pushed-location')
109
85
        self.assertEndsWith(b2.base, 'pushed-location/')
110
86
 
111
87
    def test_push_new_branch_revision_count(self):
117
93
        t.add('file')
118
94
        t.commit('commit 1')
119
95
        os.chdir('tree')
120
 
        out, err = self.run_bzr('push pushed-to')
 
96
        out, err = self.run_bzr('push', 'pushed-to')
121
97
        os.chdir('..')
122
98
        self.assertEqual('', out)
123
 
        self.assertEqual('Created new branch.\n', err)
 
99
        self.assertEqual('1 revision(s) pushed.\n', err)
124
100
 
125
101
    def test_push_only_pushes_history(self):
126
102
        # Knit branches should only push the history for the current revision.
154
130
        # Now that we have a repository with shared files, make sure
155
131
        # that things aren't copied out by a 'push'
156
132
        os.chdir('repo/b')
157
 
        self.run_bzr('push ../../push-b')
 
133
        self.run_bzr('push', '../../push-b')
158
134
        pushed_tree = WorkingTree.open('../../push-b')
159
135
        pushed_repo = pushed_tree.branch.repository
160
136
        self.assertFalse(pushed_repo.has_revision('a-1'))
161
137
        self.assertFalse(pushed_repo.has_revision('a-2'))
162
138
        self.assertTrue(pushed_repo.has_revision('b-1'))
163
139
 
164
 
    def test_push_funky_id(self):
165
 
        t = self.make_branch_and_tree('tree')
166
 
        os.chdir('tree')
167
 
        self.build_tree(['filename'])
168
 
        t.add('filename', 'funky-chars<>%&;"\'')
169
 
        t.commit('commit filename')
170
 
        self.run_bzr('push ../new-tree')
171
 
 
172
 
    def test_push_dash_d(self):
173
 
        t = self.make_branch_and_tree('from')
174
 
        t.commit(allow_pointless=True,
175
 
                message='first commit')
176
 
        self.run_bzr('push -d from to-one')
177
 
        self.failUnlessExists('to-one')
178
 
        self.run_bzr('push -d %s %s' 
179
 
            % tuple(map(urlutils.local_path_to_url, ['from', 'to-two'])))
180
 
        self.failUnlessExists('to-two')
181
 
 
182
 
    def create_simple_tree(self):
183
 
        tree = self.make_branch_and_tree('tree')
184
 
        self.build_tree(['tree/a'])
185
 
        tree.add(['a'], ['a-id'])
186
 
        tree.commit('one', rev_id='r1')
187
 
        return tree
188
 
 
189
 
    def test_push_create_prefix(self):
190
 
        """'bzr push --create-prefix' will create leading directories."""
191
 
        tree = self.create_simple_tree()
192
 
 
193
 
        self.run_bzr_error(['Parent directory of ../new/tree does not exist'],
194
 
                           'push ../new/tree',
195
 
                           working_dir='tree')
196
 
        self.run_bzr('push ../new/tree --create-prefix',
197
 
                     working_dir='tree')
198
 
        new_tree = WorkingTree.open('new/tree')
199
 
        self.assertEqual(tree.last_revision(), new_tree.last_revision())
200
 
        self.failUnlessExists('new/tree/a')
201
 
 
202
 
    def test_push_use_existing(self):
203
 
        """'bzr push --use-existing-dir' can push into an existing dir.
204
 
 
205
 
        By default, 'bzr push' will not use an existing, non-versioned dir.
206
 
        """
207
 
        tree = self.create_simple_tree()
208
 
        self.build_tree(['target/'])
209
 
 
210
 
        self.run_bzr_error(['Target directory ../target already exists',
211
 
                            'Supply --use-existing-dir',
212
 
                           ],
213
 
                           'push ../target', working_dir='tree')
214
 
 
215
 
        self.run_bzr('push --use-existing-dir ../target',
216
 
                     working_dir='tree')
217
 
 
218
 
        new_tree = WorkingTree.open('target')
219
 
        self.assertEqual(tree.last_revision(), new_tree.last_revision())
220
 
        # The push should have created target/a
221
 
        self.failUnlessExists('target/a')
222
 
 
223
 
    def test_push_onto_repo(self):
224
 
        """We should be able to 'bzr push' into an existing bzrdir."""
225
 
        tree = self.create_simple_tree()
226
 
        repo = self.make_repository('repo', shared=True)
227
 
 
228
 
        self.run_bzr('push ../repo',
229
 
                     working_dir='tree')
230
 
 
231
 
        # Pushing onto an existing bzrdir will create a repository and
232
 
        # branch as needed, but will only create a working tree if there was
233
 
        # no BzrDir before.
234
 
        self.assertRaises(errors.NoWorkingTree, WorkingTree.open, 'repo')
235
 
        new_branch = Branch.open('repo')
236
 
        self.assertEqual(tree.last_revision(), new_branch.last_revision())
237
 
 
238
 
    def test_push_onto_just_bzrdir(self):
239
 
        """We don't handle when the target is just a bzrdir.
240
 
 
241
 
        Because you shouldn't be able to create *just* a bzrdir in the wild.
242
 
        """
243
 
        # TODO: jam 20070109 Maybe it would be better to create the repository
244
 
        #       if at this point
245
 
        tree = self.create_simple_tree()
246
 
        a_bzrdir = self.make_bzrdir('dir')
247
 
 
248
 
        self.run_bzr_error(['At ../dir you have a valid .bzr control'],
249
 
                'push ../dir',
250
 
                working_dir='tree')
251
 
 
252
 
    def test_push_with_revisionspec(self):
253
 
        """We should be able to push a revision older than the tip."""
254
 
        tree_from = self.make_branch_and_tree('from')
255
 
        tree_from.commit("One.", rev_id="from-1")
256
 
        tree_from.commit("Two.", rev_id="from-2")
257
 
 
258
 
        self.run_bzr('push -r1 ../to', working_dir='from')
259
 
 
260
 
        tree_to = WorkingTree.open('to')
261
 
        repo_to = tree_to.branch.repository
262
 
        self.assertTrue(repo_to.has_revision('from-1'))
263
 
        self.assertFalse(repo_to.has_revision('from-2'))
264
 
        self.assertEqual(tree_to.branch.last_revision_info()[1], 'from-1')
265
 
 
266
 
        self.run_bzr_error(
267
 
            "bzr: ERROR: bzr push --revision takes one value.\n",
268
 
            'push -r0..2 ../to', working_dir='from')
269
 
 
270
 
    def create_trunk_and_feature_branch(self):
271
 
        # We have a mainline
272
 
        trunk_tree = self.make_branch_and_tree('target',
273
 
            format='development')
274
 
        trunk_tree.commit('mainline')
275
 
        # and a branch from it
276
 
        branch_tree = self.make_branch_and_tree('branch',
277
 
            format='development')
278
 
        branch_tree.pull(trunk_tree.branch)
279
 
        branch_tree.branch.set_parent(trunk_tree.branch.base)
280
 
        # with some work on it
281
 
        branch_tree.commit('moar work plz')
282
 
        return trunk_tree, branch_tree
283
 
 
284
 
    def assertPublished(self, branch_revid, stacked_on):
285
 
        """Assert that the branch 'published' has been published correctly."""
286
 
        published_branch = Branch.open('published')
287
 
        # The published branch refers to the mainline
288
 
        self.assertEqual(stacked_on, published_branch.get_stacked_on_url())
289
 
        # and the branch's work was pushed
290
 
        self.assertTrue(published_branch.repository.has_revision(branch_revid))
291
 
 
292
 
    def test_push_new_branch_stacked_on(self):
293
 
        """Pushing a new branch with --stacked-on creates a stacked branch."""
294
 
        trunk_tree, branch_tree = self.create_trunk_and_feature_branch()
295
 
        # we publish branch_tree with a reference to the mainline.
296
 
        out, err = self.run_bzr(['push', '--stacked-on', trunk_tree.branch.base,
297
 
            self.get_url('published')], working_dir='branch')
298
 
        self.assertEqual('', out)
299
 
        self.assertEqual('Created new stacked branch referring to %s.\n' %
300
 
            trunk_tree.branch.base, err)
301
 
        self.assertPublished(branch_tree.last_revision(),
302
 
            trunk_tree.branch.base)
303
 
 
304
 
    def test_push_new_branch_stacked_uses_parent_when_no_public_url(self):
305
 
        """When the parent has no public url the parent is used as-is."""
306
 
        trunk_tree, branch_tree = self.create_trunk_and_feature_branch()
307
 
        # now we do a stacked push, which should determine the public location
308
 
        # for us.
309
 
        out, err = self.run_bzr(['push', '--stacked',
310
 
            self.get_url('published')], working_dir='branch')
311
 
        self.assertEqual('', out)
312
 
        self.assertEqual('Created new stacked branch referring to %s.\n' %
313
 
            trunk_tree.branch.base, err)
314
 
        self.assertPublished(branch_tree.last_revision(), trunk_tree.branch.base)
315
 
 
316
 
    def test_push_new_branch_stacked_uses_parent_public(self):
317
 
        """Pushing a new branch with --stacked creates a stacked branch."""
318
 
        trunk_tree, branch_tree = self.create_trunk_and_feature_branch()
319
 
        # the trunk is published on a web server
320
 
        self.transport_readonly_server = HttpServer
321
 
        trunk_public = self.make_branch('public_trunk', format='development')
322
 
        trunk_public.pull(trunk_tree.branch)
323
 
        trunk_public_url = self.get_readonly_url('public_trunk')
324
 
        trunk_tree.branch.set_public_branch(trunk_public_url)
325
 
        # now we do a stacked push, which should determine the public location
326
 
        # for us.
327
 
        out, err = self.run_bzr(['push', '--stacked',
328
 
            self.get_url('published')], working_dir='branch')
329
 
        self.assertEqual('', out)
330
 
        self.assertEqual('Created new stacked branch referring to %s.\n' %
331
 
            trunk_public_url, err)
332
 
        self.assertPublished(branch_tree.last_revision(), trunk_public_url)
333
 
 
334
 
    def test_push_new_branch_stacked_no_parent(self):
335
 
        """Pushing with --stacked and no parent branch errors."""
336
 
        branch = self.make_branch_and_tree('branch', format='development')
337
 
        # now we do a stacked push, which should fail as the place to refer too
338
 
        # cannot be determined.
339
 
        out, err = self.run_bzr_error(
340
 
            ['Could not determine branch to refer to\\.'], ['push', '--stacked',
341
 
            self.get_url('published')], working_dir='branch')
342
 
        self.assertEqual('', out)
343
 
        self.assertFalse(self.get_transport('published').has('.'))
344
 
 
345
 
    def test_push_notifies_default_stacking(self):
346
 
        self.make_branch('stack_on', format='1.6')
347
 
        self.make_bzrdir('.').get_config().set_default_stack_on('stack_on')
348
 
        self.make_branch('from', format='1.6')
349
 
        out, err = self.run_bzr('push -d from to')
350
 
        self.assertContainsRe(err,
351
 
                              'Using default stacking branch stack_on at .*')
352
 
 
353
 
 
354
 
class RedirectingMemoryTransport(MemoryTransport):
355
 
 
356
 
    def mkdir(self, path, mode=None):
357
 
        path = self.abspath(path)[len(self._scheme):]
358
 
        if path == '/source':
359
 
            raise errors.RedirectRequested(
360
 
                path, self._scheme + '/target', is_permanent=True)
361
 
        elif path == '/infinite-loop':
362
 
            raise errors.RedirectRequested(
363
 
                path, self._scheme + '/infinite-loop', is_permanent=True)
364
 
        else:
365
 
            return super(RedirectingMemoryTransport, self).mkdir(
366
 
                path, mode)
367
 
 
368
 
 
369
 
class RedirectingMemoryServer(MemoryServer):
370
 
 
371
 
    def setUp(self):
372
 
        self._dirs = {'/': None}
373
 
        self._files = {}
374
 
        self._locks = {}
375
 
        self._scheme = 'redirecting-memory+%s:///' % id(self)
376
 
        register_transport(self._scheme, self._memory_factory)
377
 
 
378
 
    def _memory_factory(self, url):
379
 
        result = RedirectingMemoryTransport(url)
380
 
        result._dirs = self._dirs
381
 
        result._files = self._files
382
 
        result._locks = self._locks
383
 
        return result
384
 
 
385
 
    def tearDown(self):
386
 
        unregister_transport(self._scheme, self._memory_factory)
387
 
 
388
 
 
389
 
class TestPushRedirect(ExternalBase):
390
 
 
391
 
    def setUp(self):
392
 
        ExternalBase.setUp(self)
393
 
        self.memory_server = RedirectingMemoryServer()
394
 
        self.memory_server.setUp()
395
 
        self.addCleanup(self.memory_server.tearDown)
396
 
 
397
 
        # Make the branch and tree that we'll be pushing.
398
 
        t = self.make_branch_and_tree('tree')
399
 
        self.build_tree(['tree/file'])
400
 
        t.add('file')
401
 
        t.commit('commit 1')
402
 
 
403
 
    def test_push_redirects_on_mkdir(self):
404
 
        """If the push requires a mkdir, push respects redirect requests.
405
 
 
406
 
        This is added primarily to handle lp:/ URI support, so that users can
407
 
        push to new branches by specifying lp:/ URIs.
408
 
        """
409
 
        os.chdir('tree')
410
 
        destination_url = self.memory_server.get_url() + 'source'
411
 
        self.run_bzr('push %s' % destination_url)
412
 
        os.chdir('..')
413
 
 
414
 
        local_revision = Branch.open('tree').last_revision()
415
 
        remote_revision = Branch.open(
416
 
            self.memory_server.get_url() + 'target').last_revision()
417
 
        self.assertEqual(remote_revision, local_revision)
418
 
 
419
 
    def test_push_gracefully_handles_too_many_redirects(self):
420
 
        """Push fails gracefully if the mkdir generates a large number of
421
 
        redirects.
422
 
        """
423
 
        os.chdir('tree')
424
 
        destination_url = self.memory_server.get_url() + 'infinite-loop'
425
 
        out, err = self.run_bzr_error(
426
 
            ['Too many redirections trying to make %s\\.\n'
427
 
             % re.escape(destination_url)],
428
 
            'push %s' % destination_url, retcode=3)
429
 
        os.chdir('..')
430
 
        self.assertEqual('', out)