/brz/remove-bazaar

To get this branch, use:
bzr branch http://gegoxaren.bato24.eu/bzr/brz/remove-bazaar

« back to all changes in this revision

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

  • Committer: Ian Clatworthy
  • Date: 2009-02-26 06:15:24 UTC
  • mto: (4157.1.1 ianc-integration)
  • mto: This revision was merged to the branch mainline in revision 4158.
  • Revision ID: ian.clatworthy@canonical.com-20090226061524-kpy3n8na3mk4ubuy
help xxx is full help; xxx -h is concise help

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
# Copyright (C) 2005, 2007, 2008 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., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 
16
 
 
17
 
 
18
"""Black-box tests for bzr push."""
 
19
 
 
20
import os
 
21
import re
 
22
 
 
23
from bzrlib import (
 
24
    errors,
 
25
    transport,
 
26
    urlutils,
 
27
    )
 
28
from bzrlib.branch import Branch
 
29
from bzrlib.bzrdir import BzrDirMetaFormat1
 
30
from bzrlib.osutils import abspath
 
31
from bzrlib.repofmt.knitrepo import RepositoryFormatKnit1
 
32
from bzrlib.smart import client, server
 
33
from bzrlib.tests.blackbox import ExternalBase
 
34
from bzrlib.tests.http_server import HttpServer
 
35
from bzrlib.transport.memory import MemoryServer, MemoryTransport
 
36
from bzrlib.uncommit import uncommit
 
37
from bzrlib.urlutils import local_path_from_url
 
38
from bzrlib.workingtree import WorkingTree
 
39
 
 
40
 
 
41
class TestPush(ExternalBase):
 
42
 
 
43
    def test_push_error_on_vfs_http(self):
 
44
        """ pushing a branch to a HTTP server fails cleanly. """
 
45
        # the trunk is published on a web server
 
46
        self.transport_readonly_server = HttpServer
 
47
        self.make_branch('source')
 
48
        public_url = self.get_readonly_url('target')
 
49
        self.run_bzr_error(['http does not support mkdir'],
 
50
                           ['push', public_url],
 
51
                           working_dir='source')
 
52
 
 
53
    def test_push_remember(self):
 
54
        """Push changes from one branch to another and test push location."""
 
55
        transport = self.get_transport()
 
56
        tree_a = self.make_branch_and_tree('branch_a')
 
57
        branch_a = tree_a.branch
 
58
        self.build_tree(['branch_a/a'])
 
59
        tree_a.add('a')
 
60
        tree_a.commit('commit a')
 
61
        tree_b = branch_a.bzrdir.sprout('branch_b').open_workingtree()
 
62
        branch_b = tree_b.branch
 
63
        tree_c = branch_a.bzrdir.sprout('branch_c').open_workingtree()
 
64
        branch_c = tree_c.branch
 
65
        self.build_tree(['branch_a/b'])
 
66
        tree_a.add('b')
 
67
        tree_a.commit('commit b')
 
68
        self.build_tree(['branch_b/c'])
 
69
        tree_b.add('c')
 
70
        tree_b.commit('commit c')
 
71
        # initial push location must be empty
 
72
        self.assertEqual(None, branch_b.get_push_location())
 
73
 
 
74
        # test push for failure without push location set
 
75
        os.chdir('branch_a')
 
76
        out = self.run_bzr('push', retcode=3)
 
77
        self.assertEquals(out,
 
78
                ('','bzr: ERROR: No push location known or specified.\n'))
 
79
 
 
80
        # test not remembered if cannot actually push
 
81
        self.run_bzr('push ../path/which/doesnt/exist', retcode=3)
 
82
        out = self.run_bzr('push', retcode=3)
 
83
        self.assertEquals(
 
84
                ('', 'bzr: ERROR: No push location known or specified.\n'),
 
85
                out)
 
86
 
 
87
        # test implicit --remember when no push location set, push fails
 
88
        out = self.run_bzr('push ../branch_b', retcode=3)
 
89
        self.assertEquals(out,
 
90
                ('','bzr: ERROR: These branches have diverged.  '
 
91
                    'Try using "merge" and then "push".\n'))
 
92
        self.assertEquals(abspath(branch_a.get_push_location()),
 
93
                          abspath(branch_b.bzrdir.root_transport.base))
 
94
 
 
95
        # test implicit --remember after resolving previous failure
 
96
        uncommit(branch=branch_b, tree=tree_b)
 
97
        transport.delete('branch_b/c')
 
98
        out, err = self.run_bzr('push')
 
99
        path = branch_a.get_push_location()
 
100
        self.assertEquals(out,
 
101
                          'Using saved push location: %s\n'
 
102
                          % local_path_from_url(path))
 
103
        self.assertEqual(err,
 
104
                         'All changes applied successfully.\n'
 
105
                         'Pushed up to revision 2.\n')
 
106
        self.assertEqual(path,
 
107
                         branch_b.bzrdir.root_transport.base)
 
108
        # test explicit --remember
 
109
        self.run_bzr('push ../branch_c --remember')
 
110
        self.assertEquals(branch_a.get_push_location(),
 
111
                          branch_c.bzrdir.root_transport.base)
 
112
 
 
113
    def test_push_without_tree(self):
 
114
        # bzr push from a branch that does not have a checkout should work.
 
115
        b = self.make_branch('.')
 
116
        out, err = self.run_bzr('push pushed-location')
 
117
        self.assertEqual('', out)
 
118
        self.assertEqual('Created new branch.\n', err)
 
119
        b2 = Branch.open('pushed-location')
 
120
        self.assertEndsWith(b2.base, 'pushed-location/')
 
121
 
 
122
    def test_push_new_branch_revision_count(self):
 
123
        # bzr push of a branch with revisions to a new location
 
124
        # should print the number of revisions equal to the length of the
 
125
        # local branch.
 
126
        t = self.make_branch_and_tree('tree')
 
127
        self.build_tree(['tree/file'])
 
128
        t.add('file')
 
129
        t.commit('commit 1')
 
130
        os.chdir('tree')
 
131
        out, err = self.run_bzr('push pushed-to')
 
132
        os.chdir('..')
 
133
        self.assertEqual('', out)
 
134
        self.assertEqual('Created new branch.\n', err)
 
135
 
 
136
    def test_push_only_pushes_history(self):
 
137
        # Knit branches should only push the history for the current revision.
 
138
        format = BzrDirMetaFormat1()
 
139
        format.repository_format = RepositoryFormatKnit1()
 
140
        shared_repo = self.make_repository('repo', format=format, shared=True)
 
141
        shared_repo.set_make_working_trees(True)
 
142
 
 
143
        def make_shared_tree(path):
 
144
            shared_repo.bzrdir.root_transport.mkdir(path)
 
145
            shared_repo.bzrdir.create_branch_convenience('repo/' + path)
 
146
            return WorkingTree.open('repo/' + path)
 
147
        tree_a = make_shared_tree('a')
 
148
        self.build_tree(['repo/a/file'])
 
149
        tree_a.add('file')
 
150
        tree_a.commit('commit a-1', rev_id='a-1')
 
151
        f = open('repo/a/file', 'ab')
 
152
        f.write('more stuff\n')
 
153
        f.close()
 
154
        tree_a.commit('commit a-2', rev_id='a-2')
 
155
 
 
156
        tree_b = make_shared_tree('b')
 
157
        self.build_tree(['repo/b/file'])
 
158
        tree_b.add('file')
 
159
        tree_b.commit('commit b-1', rev_id='b-1')
 
160
 
 
161
        self.assertTrue(shared_repo.has_revision('a-1'))
 
162
        self.assertTrue(shared_repo.has_revision('a-2'))
 
163
        self.assertTrue(shared_repo.has_revision('b-1'))
 
164
 
 
165
        # Now that we have a repository with shared files, make sure
 
166
        # that things aren't copied out by a 'push'
 
167
        os.chdir('repo/b')
 
168
        self.run_bzr('push ../../push-b')
 
169
        pushed_tree = WorkingTree.open('../../push-b')
 
170
        pushed_repo = pushed_tree.branch.repository
 
171
        self.assertFalse(pushed_repo.has_revision('a-1'))
 
172
        self.assertFalse(pushed_repo.has_revision('a-2'))
 
173
        self.assertTrue(pushed_repo.has_revision('b-1'))
 
174
 
 
175
    def test_push_funky_id(self):
 
176
        t = self.make_branch_and_tree('tree')
 
177
        os.chdir('tree')
 
178
        self.build_tree(['filename'])
 
179
        t.add('filename', 'funky-chars<>%&;"\'')
 
180
        t.commit('commit filename')
 
181
        self.run_bzr('push ../new-tree')
 
182
 
 
183
    def test_push_dash_d(self):
 
184
        t = self.make_branch_and_tree('from')
 
185
        t.commit(allow_pointless=True,
 
186
                message='first commit')
 
187
        self.run_bzr('push -d from to-one')
 
188
        self.failUnlessExists('to-one')
 
189
        self.run_bzr('push -d %s %s'
 
190
            % tuple(map(urlutils.local_path_to_url, ['from', 'to-two'])))
 
191
        self.failUnlessExists('to-two')
 
192
 
 
193
    def test_push_smart_non_stacked_streaming_acceptance(self):
 
194
        self.setup_smart_server_with_call_log()
 
195
        t = self.make_branch_and_tree('from')
 
196
        t.commit(allow_pointless=True, message='first commit')
 
197
        self.reset_smart_call_log()
 
198
        self.run_bzr(['push', self.get_url('to-one')], working_dir='from')
 
199
        rpc_count = len(self.hpss_calls)
 
200
        # This figure represent the amount of work to perform this use case. It
 
201
        # is entirely ok to reduce this number if a test fails due to rpc_count
 
202
        # being too low. If rpc_count increases, more network roundtrips have
 
203
        # become necessary for this use case. Please do not adjust this number
 
204
        # upwards without agreement from bzr's network support maintainers.
 
205
        self.assertEqual(27, rpc_count)
 
206
 
 
207
    def test_push_smart_stacked_streaming_acceptance(self):
 
208
        self.setup_smart_server_with_call_log()
 
209
        parent = self.make_branch_and_tree('parent', format='1.9')
 
210
        parent.commit(message='first commit')
 
211
        local = parent.bzrdir.sprout('local').open_workingtree()
 
212
        local.commit(message='local commit')
 
213
        self.reset_smart_call_log()
 
214
        self.run_bzr(['push', '--stacked', '--stacked-on', '../parent',
 
215
            self.get_url('public')], working_dir='local')
 
216
        rpc_count = len(self.hpss_calls)
 
217
        # This figure represent the amount of work to perform this use case. It
 
218
        # is entirely ok to reduce this number if a test fails due to rpc_count
 
219
        # being too low. If rpc_count increases, more network roundtrips have
 
220
        # become necessary for this use case. Please do not adjust this number
 
221
        # upwards without agreement from bzr's network support maintainers.
 
222
        self.assertEqual(56, rpc_count)
 
223
        remote = Branch.open('public')
 
224
        self.assertEndsWith(remote.get_stacked_on_url(), '/parent')
 
225
 
 
226
    def create_simple_tree(self):
 
227
        tree = self.make_branch_and_tree('tree')
 
228
        self.build_tree(['tree/a'])
 
229
        tree.add(['a'], ['a-id'])
 
230
        tree.commit('one', rev_id='r1')
 
231
        return tree
 
232
 
 
233
    def test_push_create_prefix(self):
 
234
        """'bzr push --create-prefix' will create leading directories."""
 
235
        tree = self.create_simple_tree()
 
236
 
 
237
        self.run_bzr_error(['Parent directory of ../new/tree does not exist'],
 
238
                           'push ../new/tree',
 
239
                           working_dir='tree')
 
240
        self.run_bzr('push ../new/tree --create-prefix',
 
241
                     working_dir='tree')
 
242
        new_tree = WorkingTree.open('new/tree')
 
243
        self.assertEqual(tree.last_revision(), new_tree.last_revision())
 
244
        self.failUnlessExists('new/tree/a')
 
245
 
 
246
    def test_push_use_existing(self):
 
247
        """'bzr push --use-existing-dir' can push into an existing dir.
 
248
 
 
249
        By default, 'bzr push' will not use an existing, non-versioned dir.
 
250
        """
 
251
        tree = self.create_simple_tree()
 
252
        self.build_tree(['target/'])
 
253
 
 
254
        self.run_bzr_error(['Target directory ../target already exists',
 
255
                            'Supply --use-existing-dir',
 
256
                           ],
 
257
                           'push ../target', working_dir='tree')
 
258
 
 
259
        self.run_bzr('push --use-existing-dir ../target',
 
260
                     working_dir='tree')
 
261
 
 
262
        new_tree = WorkingTree.open('target')
 
263
        self.assertEqual(tree.last_revision(), new_tree.last_revision())
 
264
        # The push should have created target/a
 
265
        self.failUnlessExists('target/a')
 
266
 
 
267
    def test_push_onto_repo(self):
 
268
        """We should be able to 'bzr push' into an existing bzrdir."""
 
269
        tree = self.create_simple_tree()
 
270
        repo = self.make_repository('repo', shared=True)
 
271
 
 
272
        self.run_bzr('push ../repo',
 
273
                     working_dir='tree')
 
274
 
 
275
        # Pushing onto an existing bzrdir will create a repository and
 
276
        # branch as needed, but will only create a working tree if there was
 
277
        # no BzrDir before.
 
278
        self.assertRaises(errors.NoWorkingTree, WorkingTree.open, 'repo')
 
279
        new_branch = Branch.open('repo')
 
280
        self.assertEqual(tree.last_revision(), new_branch.last_revision())
 
281
 
 
282
    def test_push_onto_just_bzrdir(self):
 
283
        """We don't handle when the target is just a bzrdir.
 
284
 
 
285
        Because you shouldn't be able to create *just* a bzrdir in the wild.
 
286
        """
 
287
        # TODO: jam 20070109 Maybe it would be better to create the repository
 
288
        #       if at this point
 
289
        tree = self.create_simple_tree()
 
290
        a_bzrdir = self.make_bzrdir('dir')
 
291
 
 
292
        self.run_bzr_error(['At ../dir you have a valid .bzr control'],
 
293
                'push ../dir',
 
294
                working_dir='tree')
 
295
 
 
296
    def test_push_with_revisionspec(self):
 
297
        """We should be able to push a revision older than the tip."""
 
298
        tree_from = self.make_branch_and_tree('from')
 
299
        tree_from.commit("One.", rev_id="from-1")
 
300
        tree_from.commit("Two.", rev_id="from-2")
 
301
 
 
302
        self.run_bzr('push -r1 ../to', working_dir='from')
 
303
 
 
304
        tree_to = WorkingTree.open('to')
 
305
        repo_to = tree_to.branch.repository
 
306
        self.assertTrue(repo_to.has_revision('from-1'))
 
307
        self.assertFalse(repo_to.has_revision('from-2'))
 
308
        self.assertEqual(tree_to.branch.last_revision_info()[1], 'from-1')
 
309
 
 
310
        self.run_bzr_error(
 
311
            "bzr: ERROR: bzr push --revision takes one value.\n",
 
312
            'push -r0..2 ../to', working_dir='from')
 
313
 
 
314
    def create_trunk_and_feature_branch(self):
 
315
        # We have a mainline
 
316
        trunk_tree = self.make_branch_and_tree('target',
 
317
            format='development')
 
318
        trunk_tree.commit('mainline')
 
319
        # and a branch from it
 
320
        branch_tree = self.make_branch_and_tree('branch',
 
321
            format='development')
 
322
        branch_tree.pull(trunk_tree.branch)
 
323
        branch_tree.branch.set_parent(trunk_tree.branch.base)
 
324
        # with some work on it
 
325
        branch_tree.commit('moar work plz')
 
326
        return trunk_tree, branch_tree
 
327
 
 
328
    def assertPublished(self, branch_revid, stacked_on):
 
329
        """Assert that the branch 'published' has been published correctly."""
 
330
        published_branch = Branch.open('published')
 
331
        # The published branch refers to the mainline
 
332
        self.assertEqual(stacked_on, published_branch.get_stacked_on_url())
 
333
        # and the branch's work was pushed
 
334
        self.assertTrue(published_branch.repository.has_revision(branch_revid))
 
335
 
 
336
    def test_push_new_branch_stacked_on(self):
 
337
        """Pushing a new branch with --stacked-on creates a stacked branch."""
 
338
        trunk_tree, branch_tree = self.create_trunk_and_feature_branch()
 
339
        # we publish branch_tree with a reference to the mainline.
 
340
        out, err = self.run_bzr(['push', '--stacked-on', trunk_tree.branch.base,
 
341
            self.get_url('published')], working_dir='branch')
 
342
        self.assertEqual('', out)
 
343
        self.assertEqual('Created new stacked branch referring to %s.\n' %
 
344
            trunk_tree.branch.base, err)
 
345
        self.assertPublished(branch_tree.last_revision(),
 
346
            trunk_tree.branch.base)
 
347
 
 
348
    def test_push_new_branch_stacked_uses_parent_when_no_public_url(self):
 
349
        """When the parent has no public url the parent is used as-is."""
 
350
        trunk_tree, branch_tree = self.create_trunk_and_feature_branch()
 
351
        # now we do a stacked push, which should determine the public location
 
352
        # for us.
 
353
        out, err = self.run_bzr(['push', '--stacked',
 
354
            self.get_url('published')], working_dir='branch')
 
355
        self.assertEqual('', out)
 
356
        self.assertEqual('Created new stacked branch referring to %s.\n' %
 
357
            trunk_tree.branch.base, err)
 
358
        self.assertPublished(branch_tree.last_revision(), trunk_tree.branch.base)
 
359
 
 
360
    def test_push_new_branch_stacked_uses_parent_public(self):
 
361
        """Pushing a new branch with --stacked creates a stacked branch."""
 
362
        trunk_tree, branch_tree = self.create_trunk_and_feature_branch()
 
363
        # the trunk is published on a web server
 
364
        self.transport_readonly_server = HttpServer
 
365
        trunk_public = self.make_branch('public_trunk', format='development')
 
366
        trunk_public.pull(trunk_tree.branch)
 
367
        trunk_public_url = self.get_readonly_url('public_trunk')
 
368
        trunk_tree.branch.set_public_branch(trunk_public_url)
 
369
        # now we do a stacked push, which should determine the public location
 
370
        # for us.
 
371
        out, err = self.run_bzr(['push', '--stacked',
 
372
            self.get_url('published')], working_dir='branch')
 
373
        self.assertEqual('', out)
 
374
        self.assertEqual('Created new stacked branch referring to %s.\n' %
 
375
            trunk_public_url, err)
 
376
        self.assertPublished(branch_tree.last_revision(), trunk_public_url)
 
377
 
 
378
    def test_push_new_branch_stacked_no_parent(self):
 
379
        """Pushing with --stacked and no parent branch errors."""
 
380
        branch = self.make_branch_and_tree('branch', format='development')
 
381
        # now we do a stacked push, which should fail as the place to refer too
 
382
        # cannot be determined.
 
383
        out, err = self.run_bzr_error(
 
384
            ['Could not determine branch to refer to\\.'], ['push', '--stacked',
 
385
            self.get_url('published')], working_dir='branch')
 
386
        self.assertEqual('', out)
 
387
        self.assertFalse(self.get_transport('published').has('.'))
 
388
 
 
389
    def test_push_notifies_default_stacking(self):
 
390
        self.make_branch('stack_on', format='1.6')
 
391
        self.make_bzrdir('.').get_config().set_default_stack_on('stack_on')
 
392
        self.make_branch('from', format='1.6')
 
393
        out, err = self.run_bzr('push -d from to')
 
394
        self.assertContainsRe(err,
 
395
                              'Using default stacking branch stack_on at .*')
 
396
 
 
397
    def test_push_doesnt_create_broken_branch(self):
 
398
        """Pushing a new standalone branch works even when there's a default
 
399
        stacking policy at the destination.
 
400
 
 
401
        The new branch will preserve the repo format (even if it isn't the
 
402
        default for the branch), and will be stacked when the repo format
 
403
        allows (which means that the branch format isn't necessarly preserved).
 
404
        """
 
405
        self.make_repository('repo', shared=True, format='1.6')
 
406
        builder = self.make_branch_builder('repo/local', format='pack-0.92')
 
407
        builder.start_series()
 
408
        builder.build_snapshot('rev-1', None, [
 
409
            ('add', ('', 'root-id', 'directory', '')),
 
410
            ('add', ('filename', 'f-id', 'file', 'content\n'))])
 
411
        builder.build_snapshot('rev-2', ['rev-1'], [])
 
412
        builder.build_snapshot('rev-3', ['rev-2'],
 
413
            [('modify', ('f-id', 'new-content\n'))])
 
414
        builder.finish_series()
 
415
        branch = builder.get_branch()
 
416
        # Push rev-1 to "trunk", so that we can stack on it.
 
417
        self.run_bzr('push -d repo/local trunk -r 1')
 
418
        # Set a default stacking policy so that new branches will automatically
 
419
        # stack on trunk.
 
420
        self.make_bzrdir('.').get_config().set_default_stack_on('trunk')
 
421
        # Push rev-2 to a new branch "remote".  It will be stacked on "trunk".
 
422
        out, err = self.run_bzr('push -d repo/local remote -r 2')
 
423
        self.assertContainsRe(
 
424
            err, 'Using default stacking branch trunk at .*')
 
425
        # Push rev-3 onto "remote".  If "remote" not stacked and is missing the
 
426
        # fulltext record for f-id @ rev-1, then this will fail.
 
427
        out, err = self.run_bzr('push -d repo/local remote -r 3')
 
428
 
 
429
    def test_push_verbose_shows_log(self):
 
430
        tree = self.make_branch_and_tree('source')
 
431
        tree.commit('rev1')
 
432
        out, err = self.run_bzr('push -v -d source target')
 
433
        # initial push contains log
 
434
        self.assertContainsRe(out, 'rev1')
 
435
        tree.commit('rev2')
 
436
        out, err = self.run_bzr('push -v -d source target')
 
437
        # subsequent push contains log
 
438
        self.assertContainsRe(out, 'rev2')
 
439
        # subsequent log is accurate
 
440
        self.assertNotContainsRe(out, 'rev1')
 
441
 
 
442
 
 
443
class RedirectingMemoryTransport(MemoryTransport):
 
444
 
 
445
    def mkdir(self, relpath, mode=None):
 
446
        from bzrlib.trace import mutter
 
447
        mutter('cwd: %r, rel: %r, abs: %r' % (self._cwd, relpath, abspath))
 
448
        if self._cwd == '/source/':
 
449
            raise errors.RedirectRequested(self.abspath(relpath),
 
450
                                           self.abspath('../target'),
 
451
                                           is_permanent=True)
 
452
        elif self._cwd == '/infinite-loop/':
 
453
            raise errors.RedirectRequested(self.abspath(relpath),
 
454
                                           self.abspath('../infinite-loop'),
 
455
                                           is_permanent=True)
 
456
        else:
 
457
            return super(RedirectingMemoryTransport, self).mkdir(
 
458
                relpath, mode)
 
459
 
 
460
    def _redirected_to(self, source, target):
 
461
        # We do accept redirections
 
462
        return transport.get_transport(target)
 
463
 
 
464
 
 
465
class RedirectingMemoryServer(MemoryServer):
 
466
 
 
467
    def setUp(self):
 
468
        self._dirs = {'/': None}
 
469
        self._files = {}
 
470
        self._locks = {}
 
471
        self._scheme = 'redirecting-memory+%s:///' % id(self)
 
472
        transport.register_transport(self._scheme, self._memory_factory)
 
473
 
 
474
    def _memory_factory(self, url):
 
475
        result = RedirectingMemoryTransport(url)
 
476
        result._dirs = self._dirs
 
477
        result._files = self._files
 
478
        result._locks = self._locks
 
479
        return result
 
480
 
 
481
    def tearDown(self):
 
482
        transport.unregister_transport(self._scheme, self._memory_factory)
 
483
 
 
484
 
 
485
class TestPushRedirect(ExternalBase):
 
486
 
 
487
    def setUp(self):
 
488
        ExternalBase.setUp(self)
 
489
        self.memory_server = RedirectingMemoryServer()
 
490
        self.memory_server.setUp()
 
491
        self.addCleanup(self.memory_server.tearDown)
 
492
 
 
493
        # Make the branch and tree that we'll be pushing.
 
494
        t = self.make_branch_and_tree('tree')
 
495
        self.build_tree(['tree/file'])
 
496
        t.add('file')
 
497
        t.commit('commit 1')
 
498
 
 
499
    def test_push_redirects_on_mkdir(self):
 
500
        """If the push requires a mkdir, push respects redirect requests.
 
501
 
 
502
        This is added primarily to handle lp:/ URI support, so that users can
 
503
        push to new branches by specifying lp:/ URIs.
 
504
        """
 
505
        destination_url = self.memory_server.get_url() + 'source'
 
506
        self.run_bzr(['push', '-d', 'tree', destination_url])
 
507
 
 
508
        local_revision = Branch.open('tree').last_revision()
 
509
        remote_revision = Branch.open(
 
510
            self.memory_server.get_url() + 'target').last_revision()
 
511
        self.assertEqual(remote_revision, local_revision)
 
512
 
 
513
    def test_push_gracefully_handles_too_many_redirects(self):
 
514
        """Push fails gracefully if the mkdir generates a large number of
 
515
        redirects.
 
516
        """
 
517
        destination_url = self.memory_server.get_url() + 'infinite-loop'
 
518
        out, err = self.run_bzr_error(
 
519
            ['Too many redirections trying to make %s\\.\n'
 
520
             % re.escape(destination_url)],
 
521
            ['push', '-d', 'tree', destination_url], retcode=3)
 
522
        self.assertEqual('', out)