~bzr-pqm/bzr/bzr.dev

« back to all changes in this revision

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

  • Committer: Martin Pool
  • Date: 2006-04-13 05:37:24 UTC
  • mto: This revision was merged to the branch mainline in revision 1662.
  • Revision ID: mbp@sourcefrog.net-20060413053724-8c0053ac31492637
Give an error for bzr diff on an nonexistent file (Malone #3619)

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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 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
 
        # This figure represent the amount of work to perform this use case. It
200
 
        # is entirely ok to reduce this number if a test fails due to rpc_count
201
 
        # being too low. If rpc_count increases, more network roundtrips have
202
 
        # become necessary for this use case. Please do not adjust this number
203
 
        # upwards without agreement from bzr's network support maintainers.
204
 
        self.assertLength(20, self.hpss_calls)
205
 
 
206
 
    def test_push_smart_stacked_streaming_acceptance(self):
207
 
        self.setup_smart_server_with_call_log()
208
 
        parent = self.make_branch_and_tree('parent', format='1.9')
209
 
        parent.commit(message='first commit')
210
 
        local = parent.bzrdir.sprout('local').open_workingtree()
211
 
        local.commit(message='local commit')
212
 
        self.reset_smart_call_log()
213
 
        self.run_bzr(['push', '--stacked', '--stacked-on', '../parent',
214
 
            self.get_url('public')], working_dir='local')
215
 
        # This figure represent the amount of work to perform this use case. It
216
 
        # is entirely ok to reduce this number if a test fails due to rpc_count
217
 
        # being too low. If rpc_count increases, more network roundtrips have
218
 
        # become necessary for this use case. Please do not adjust this number
219
 
        # upwards without agreement from bzr's network support maintainers.
220
 
        self.assertLength(42, self.hpss_calls)
221
 
        remote = Branch.open('public')
222
 
        self.assertEndsWith(remote.get_stacked_on_url(), '/parent')
223
 
 
224
 
    def create_simple_tree(self):
225
 
        tree = self.make_branch_and_tree('tree')
226
 
        self.build_tree(['tree/a'])
227
 
        tree.add(['a'], ['a-id'])
228
 
        tree.commit('one', rev_id='r1')
229
 
        return tree
230
 
 
231
 
    def test_push_create_prefix(self):
232
 
        """'bzr push --create-prefix' will create leading directories."""
233
 
        tree = self.create_simple_tree()
234
 
 
235
 
        self.run_bzr_error(['Parent directory of ../new/tree does not exist'],
236
 
                           'push ../new/tree',
237
 
                           working_dir='tree')
238
 
        self.run_bzr('push ../new/tree --create-prefix',
239
 
                     working_dir='tree')
240
 
        new_tree = WorkingTree.open('new/tree')
241
 
        self.assertEqual(tree.last_revision(), new_tree.last_revision())
242
 
        self.failUnlessExists('new/tree/a')
243
 
 
244
 
    def test_push_use_existing(self):
245
 
        """'bzr push --use-existing-dir' can push into an existing dir.
246
 
 
247
 
        By default, 'bzr push' will not use an existing, non-versioned dir.
248
 
        """
249
 
        tree = self.create_simple_tree()
250
 
        self.build_tree(['target/'])
251
 
 
252
 
        self.run_bzr_error(['Target directory ../target already exists',
253
 
                            'Supply --use-existing-dir',
254
 
                           ],
255
 
                           'push ../target', working_dir='tree')
256
 
 
257
 
        self.run_bzr('push --use-existing-dir ../target',
258
 
                     working_dir='tree')
259
 
 
260
 
        new_tree = WorkingTree.open('target')
261
 
        self.assertEqual(tree.last_revision(), new_tree.last_revision())
262
 
        # The push should have created target/a
263
 
        self.failUnlessExists('target/a')
264
 
 
265
 
    def test_push_onto_repo(self):
266
 
        """We should be able to 'bzr push' into an existing bzrdir."""
267
 
        tree = self.create_simple_tree()
268
 
        repo = self.make_repository('repo', shared=True)
269
 
 
270
 
        self.run_bzr('push ../repo',
271
 
                     working_dir='tree')
272
 
 
273
 
        # Pushing onto an existing bzrdir will create a repository and
274
 
        # branch as needed, but will only create a working tree if there was
275
 
        # no BzrDir before.
276
 
        self.assertRaises(errors.NoWorkingTree, WorkingTree.open, 'repo')
277
 
        new_branch = Branch.open('repo')
278
 
        self.assertEqual(tree.last_revision(), new_branch.last_revision())
279
 
 
280
 
    def test_push_onto_just_bzrdir(self):
281
 
        """We don't handle when the target is just a bzrdir.
282
 
 
283
 
        Because you shouldn't be able to create *just* a bzrdir in the wild.
284
 
        """
285
 
        # TODO: jam 20070109 Maybe it would be better to create the repository
286
 
        #       if at this point
287
 
        tree = self.create_simple_tree()
288
 
        a_bzrdir = self.make_bzrdir('dir')
289
 
 
290
 
        self.run_bzr_error(['At ../dir you have a valid .bzr control'],
291
 
                'push ../dir',
292
 
                working_dir='tree')
293
 
 
294
 
    def test_push_with_revisionspec(self):
295
 
        """We should be able to push a revision older than the tip."""
296
 
        tree_from = self.make_branch_and_tree('from')
297
 
        tree_from.commit("One.", rev_id="from-1")
298
 
        tree_from.commit("Two.", rev_id="from-2")
299
 
 
300
 
        self.run_bzr('push -r1 ../to', working_dir='from')
301
 
 
302
 
        tree_to = WorkingTree.open('to')
303
 
        repo_to = tree_to.branch.repository
304
 
        self.assertTrue(repo_to.has_revision('from-1'))
305
 
        self.assertFalse(repo_to.has_revision('from-2'))
306
 
        self.assertEqual(tree_to.branch.last_revision_info()[1], 'from-1')
307
 
 
308
 
        self.run_bzr_error(
309
 
            "bzr: ERROR: bzr push --revision takes one value.\n",
310
 
            'push -r0..2 ../to', working_dir='from')
311
 
 
312
 
    def create_trunk_and_feature_branch(self):
313
 
        # We have a mainline
314
 
        trunk_tree = self.make_branch_and_tree('target',
315
 
            format='development')
316
 
        trunk_tree.commit('mainline')
317
 
        # and a branch from it
318
 
        branch_tree = self.make_branch_and_tree('branch',
319
 
            format='development')
320
 
        branch_tree.pull(trunk_tree.branch)
321
 
        branch_tree.branch.set_parent(trunk_tree.branch.base)
322
 
        # with some work on it
323
 
        branch_tree.commit('moar work plz')
324
 
        return trunk_tree, branch_tree
325
 
 
326
 
    def assertPublished(self, branch_revid, stacked_on):
327
 
        """Assert that the branch 'published' has been published correctly."""
328
 
        published_branch = Branch.open('published')
329
 
        # The published branch refers to the mainline
330
 
        self.assertEqual(stacked_on, published_branch.get_stacked_on_url())
331
 
        # and the branch's work was pushed
332
 
        self.assertTrue(published_branch.repository.has_revision(branch_revid))
333
 
 
334
 
    def test_push_new_branch_stacked_on(self):
335
 
        """Pushing a new branch with --stacked-on creates a stacked branch."""
336
 
        trunk_tree, branch_tree = self.create_trunk_and_feature_branch()
337
 
        # we publish branch_tree with a reference to the mainline.
338
 
        out, err = self.run_bzr(['push', '--stacked-on', trunk_tree.branch.base,
339
 
            self.get_url('published')], working_dir='branch')
340
 
        self.assertEqual('', out)
341
 
        self.assertEqual('Created new stacked branch referring to %s.\n' %
342
 
            trunk_tree.branch.base, err)
343
 
        self.assertPublished(branch_tree.last_revision(),
344
 
            trunk_tree.branch.base)
345
 
 
346
 
    def test_push_new_branch_stacked_uses_parent_when_no_public_url(self):
347
 
        """When the parent has no public url the parent is used as-is."""
348
 
        trunk_tree, branch_tree = self.create_trunk_and_feature_branch()
349
 
        # now we do a stacked push, which should determine the public location
350
 
        # for us.
351
 
        out, err = self.run_bzr(['push', '--stacked',
352
 
            self.get_url('published')], working_dir='branch')
353
 
        self.assertEqual('', out)
354
 
        self.assertEqual('Created new stacked branch referring to %s.\n' %
355
 
            trunk_tree.branch.base, err)
356
 
        self.assertPublished(branch_tree.last_revision(), trunk_tree.branch.base)
357
 
 
358
 
    def test_push_new_branch_stacked_uses_parent_public(self):
359
 
        """Pushing a new branch with --stacked creates a stacked branch."""
360
 
        trunk_tree, branch_tree = self.create_trunk_and_feature_branch()
361
 
        # the trunk is published on a web server
362
 
        self.transport_readonly_server = HttpServer
363
 
        trunk_public = self.make_branch('public_trunk', format='development')
364
 
        trunk_public.pull(trunk_tree.branch)
365
 
        trunk_public_url = self.get_readonly_url('public_trunk')
366
 
        trunk_tree.branch.set_public_branch(trunk_public_url)
367
 
        # now we do a stacked push, which should determine the public location
368
 
        # for us.
369
 
        out, err = self.run_bzr(['push', '--stacked',
370
 
            self.get_url('published')], working_dir='branch')
371
 
        self.assertEqual('', out)
372
 
        self.assertEqual('Created new stacked branch referring to %s.\n' %
373
 
            trunk_public_url, err)
374
 
        self.assertPublished(branch_tree.last_revision(), trunk_public_url)
375
 
 
376
 
    def test_push_new_branch_stacked_no_parent(self):
377
 
        """Pushing with --stacked and no parent branch errors."""
378
 
        branch = self.make_branch_and_tree('branch', format='development')
379
 
        # now we do a stacked push, which should fail as the place to refer too
380
 
        # cannot be determined.
381
 
        out, err = self.run_bzr_error(
382
 
            ['Could not determine branch to refer to\\.'], ['push', '--stacked',
383
 
            self.get_url('published')], working_dir='branch')
384
 
        self.assertEqual('', out)
385
 
        self.assertFalse(self.get_transport('published').has('.'))
386
 
 
387
 
    def test_push_notifies_default_stacking(self):
388
 
        self.make_branch('stack_on', format='1.6')
389
 
        self.make_bzrdir('.').get_config().set_default_stack_on('stack_on')
390
 
        self.make_branch('from', format='1.6')
391
 
        out, err = self.run_bzr('push -d from to')
392
 
        self.assertContainsRe(err,
393
 
                              'Using default stacking branch stack_on at .*')
394
 
 
395
 
    def test_push_stacks_with_default_stacking_if_target_is_stackable(self):
396
 
        self.make_branch('stack_on', format='1.6')
397
 
        self.make_bzrdir('.').get_config().set_default_stack_on('stack_on')
398
 
        self.make_branch('from', format='pack-0.92')
399
 
        out, err = self.run_bzr('push -d from to')
400
 
        branch = Branch.open('to')
401
 
        self.assertEqual('../stack_on', branch.get_stacked_on_url())
402
 
 
403
 
    def test_push_does_not_change_format_with_default_if_target_cannot(self):
404
 
        self.make_branch('stack_on', format='pack-0.92')
405
 
        self.make_bzrdir('.').get_config().set_default_stack_on('stack_on')
406
 
        self.make_branch('from', format='pack-0.92')
407
 
        out, err = self.run_bzr('push -d from to')
408
 
        branch = Branch.open('to')
409
 
        self.assertRaises(errors.UnstackableBranchFormat,
410
 
            branch.get_stacked_on_url)
411
 
 
412
 
    def test_push_doesnt_create_broken_branch(self):
413
 
        """Pushing a new standalone branch works even when there's a default
414
 
        stacking policy at the destination.
415
 
 
416
 
        The new branch will preserve the repo format (even if it isn't the
417
 
        default for the branch), and will be stacked when the repo format
418
 
        allows (which means that the branch format isn't necessarly preserved).
419
 
        """
420
 
        self.make_repository('repo', shared=True, format='1.6')
421
 
        builder = self.make_branch_builder('repo/local', format='pack-0.92')
422
 
        builder.start_series()
423
 
        builder.build_snapshot('rev-1', None, [
424
 
            ('add', ('', 'root-id', 'directory', '')),
425
 
            ('add', ('filename', 'f-id', 'file', 'content\n'))])
426
 
        builder.build_snapshot('rev-2', ['rev-1'], [])
427
 
        builder.build_snapshot('rev-3', ['rev-2'],
428
 
            [('modify', ('f-id', 'new-content\n'))])
429
 
        builder.finish_series()
430
 
        branch = builder.get_branch()
431
 
        # Push rev-1 to "trunk", so that we can stack on it.
432
 
        self.run_bzr('push -d repo/local trunk -r 1')
433
 
        # Set a default stacking policy so that new branches will automatically
434
 
        # stack on trunk.
435
 
        self.make_bzrdir('.').get_config().set_default_stack_on('trunk')
436
 
        # Push rev-2 to a new branch "remote".  It will be stacked on "trunk".
437
 
        out, err = self.run_bzr('push -d repo/local remote -r 2')
438
 
        self.assertContainsRe(
439
 
            err, 'Using default stacking branch trunk at .*')
440
 
        # Push rev-3 onto "remote".  If "remote" not stacked and is missing the
441
 
        # fulltext record for f-id @ rev-1, then this will fail.
442
 
        out, err = self.run_bzr('push -d repo/local remote -r 3')
443
 
 
444
 
    def test_push_verbose_shows_log(self):
445
 
        tree = self.make_branch_and_tree('source')
446
 
        tree.commit('rev1')
447
 
        out, err = self.run_bzr('push -v -d source target')
448
 
        # initial push contains log
449
 
        self.assertContainsRe(out, 'rev1')
450
 
        tree.commit('rev2')
451
 
        out, err = self.run_bzr('push -v -d source target')
452
 
        # subsequent push contains log
453
 
        self.assertContainsRe(out, 'rev2')
454
 
        # subsequent log is accurate
455
 
        self.assertNotContainsRe(out, 'rev1')
456
 
 
457
 
 
458
 
class RedirectingMemoryTransport(MemoryTransport):
459
 
 
460
 
    def mkdir(self, relpath, mode=None):
461
 
        from bzrlib.trace import mutter
462
 
        mutter('cwd: %r, rel: %r, abs: %r' % (self._cwd, relpath, abspath))
463
 
        if self._cwd == '/source/':
464
 
            raise errors.RedirectRequested(self.abspath(relpath),
465
 
                                           self.abspath('../target'),
466
 
                                           is_permanent=True)
467
 
        elif self._cwd == '/infinite-loop/':
468
 
            raise errors.RedirectRequested(self.abspath(relpath),
469
 
                                           self.abspath('../infinite-loop'),
470
 
                                           is_permanent=True)
471
 
        else:
472
 
            return super(RedirectingMemoryTransport, self).mkdir(
473
 
                relpath, mode)
474
 
 
475
 
    def _redirected_to(self, source, target):
476
 
        # We do accept redirections
477
 
        return transport.get_transport(target)
478
 
 
479
 
 
480
 
class RedirectingMemoryServer(MemoryServer):
481
 
 
482
 
    def setUp(self):
483
 
        self._dirs = {'/': None}
484
 
        self._files = {}
485
 
        self._locks = {}
486
 
        self._scheme = 'redirecting-memory+%s:///' % id(self)
487
 
        transport.register_transport(self._scheme, self._memory_factory)
488
 
 
489
 
    def _memory_factory(self, url):
490
 
        result = RedirectingMemoryTransport(url)
491
 
        result._dirs = self._dirs
492
 
        result._files = self._files
493
 
        result._locks = self._locks
494
 
        return result
495
 
 
496
 
    def tearDown(self):
497
 
        transport.unregister_transport(self._scheme, self._memory_factory)
498
 
 
499
 
 
500
 
class TestPushRedirect(ExternalBase):
501
 
 
502
 
    def setUp(self):
503
 
        ExternalBase.setUp(self)
504
 
        self.memory_server = RedirectingMemoryServer()
505
 
        self.memory_server.setUp()
506
 
        self.addCleanup(self.memory_server.tearDown)
507
 
 
508
 
        # Make the branch and tree that we'll be pushing.
509
 
        t = self.make_branch_and_tree('tree')
510
 
        self.build_tree(['tree/file'])
511
 
        t.add('file')
512
 
        t.commit('commit 1')
513
 
 
514
 
    def test_push_redirects_on_mkdir(self):
515
 
        """If the push requires a mkdir, push respects redirect requests.
516
 
 
517
 
        This is added primarily to handle lp:/ URI support, so that users can
518
 
        push to new branches by specifying lp:/ URIs.
519
 
        """
520
 
        destination_url = self.memory_server.get_url() + 'source'
521
 
        self.run_bzr(['push', '-d', 'tree', destination_url])
522
 
 
523
 
        local_revision = Branch.open('tree').last_revision()
524
 
        remote_revision = Branch.open(
525
 
            self.memory_server.get_url() + 'target').last_revision()
526
 
        self.assertEqual(remote_revision, local_revision)
527
 
 
528
 
    def test_push_gracefully_handles_too_many_redirects(self):
529
 
        """Push fails gracefully if the mkdir generates a large number of
530
 
        redirects.
531
 
        """
532
 
        destination_url = self.memory_server.get_url() + 'infinite-loop'
533
 
        out, err = self.run_bzr_error(
534
 
            ['Too many redirections trying to make %s\\.\n'
535
 
             % re.escape(destination_url)],
536
 
            ['push', '-d', 'tree', destination_url], retcode=3)
537
 
        self.assertEqual('', out)