~bzr-pqm/bzr/bzr.dev

« back to all changes in this revision

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

  • Committer: Robert Collins
  • Date: 2005-10-03 01:15:02 UTC
  • mfrom: (1092.2.28)
  • Revision ID: robertc@robertcollins.net-20051003011502-f579a509a136b774
mergeĀ fromĀ baz2bzr

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