~bzr-pqm/bzr/bzr.dev

« back to all changes in this revision

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

  • Committer: Andrew Bennetts
  • Date: 2007-03-26 06:24:01 UTC
  • mto: This revision was merged to the branch mainline in revision 2376.
  • Revision ID: andrew.bennetts@canonical.com-20070326062401-k3nbefzje5332jaf
Deal with review comments from Robert:

  * Add my name to the NEWS file
  * Move the test case to a new module in branch_implementations
  * Remove revision_history cruft from identitymap and test_identitymap
  * Improve some docstrings

Also, this fixes a bug where revision_history was not returning a copy of the
cached data, allowing the cache to be corrupted.

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
# Copyright (C) 2005, 2007, 2008 Canonical Ltd
 
1
# Copyright (C) 2005, 2007 Canonical Ltd
2
2
#
3
3
# This program is free software; you can redistribute it and/or modify
4
4
# it under the terms of the GNU General Public License as published by
18
18
"""Black-box tests for bzr push."""
19
19
 
20
20
import os
21
 
import re
22
21
 
23
22
from bzrlib import (
24
23
    errors,
29
28
from bzrlib.osutils import abspath
30
29
from bzrlib.repofmt.knitrepo import RepositoryFormatKnit1
31
30
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
31
from bzrlib.uncommit import uncommit
36
32
from bzrlib.urlutils import local_path_from_url
37
33
from bzrlib.workingtree import WorkingTree
62
58
 
63
59
        # test push for failure without push location set
64
60
        os.chdir('branch_a')
65
 
        out = self.run_bzr('push', retcode=3)
 
61
        out = self.runbzr('push', retcode=3)
66
62
        self.assertEquals(out,
67
63
                ('','bzr: ERROR: No push location known or specified.\n'))
68
64
 
69
65
        # test not remembered if cannot actually push
70
 
        self.run_bzr('push ../path/which/doesnt/exist', retcode=3)
 
66
        self.run_bzr('push', '../path/which/doesnt/exist', retcode=3)
71
67
        out = self.run_bzr('push', retcode=3)
72
68
        self.assertEquals(
73
69
                ('', 'bzr: ERROR: No push location known or specified.\n'),
74
70
                out)
75
71
 
76
72
        # test implicit --remember when no push location set, push fails
77
 
        out = self.run_bzr('push ../branch_b', retcode=3)
 
73
        out = self.run_bzr('push', '../branch_b', retcode=3)
78
74
        self.assertEquals(out,
79
75
                ('','bzr: ERROR: These branches have diverged.  '
80
76
                    'Try using "merge" and then "push".\n'))
95
91
        self.assertEqual(path,
96
92
                         branch_b.bzrdir.root_transport.base)
97
93
        # test explicit --remember
98
 
        self.run_bzr('push ../branch_c --remember')
 
94
        self.run_bzr('push', '../branch_c', '--remember')
99
95
        self.assertEquals(branch_a.get_push_location(),
100
96
                          branch_c.bzrdir.root_transport.base)
101
97
    
102
98
    def test_push_without_tree(self):
103
99
        # bzr push from a branch that does not have a checkout should work.
104
100
        b = self.make_branch('.')
105
 
        out, err = self.run_bzr('push pushed-location')
 
101
        out, err = self.run_bzr('push', 'pushed-location')
106
102
        self.assertEqual('', out)
107
103
        self.assertEqual('Created new branch.\n', err)
108
104
        b2 = Branch.open('pushed-location')
117
113
        t.add('file')
118
114
        t.commit('commit 1')
119
115
        os.chdir('tree')
120
 
        out, err = self.run_bzr('push pushed-to')
 
116
        out, err = self.run_bzr('push', 'pushed-to')
121
117
        os.chdir('..')
122
118
        self.assertEqual('', out)
123
119
        self.assertEqual('Created new branch.\n', err)
154
150
        # Now that we have a repository with shared files, make sure
155
151
        # that things aren't copied out by a 'push'
156
152
        os.chdir('repo/b')
157
 
        self.run_bzr('push ../../push-b')
 
153
        self.run_bzr('push', '../../push-b')
158
154
        pushed_tree = WorkingTree.open('../../push-b')
159
155
        pushed_repo = pushed_tree.branch.repository
160
156
        self.assertFalse(pushed_repo.has_revision('a-1'))
167
163
        self.build_tree(['filename'])
168
164
        t.add('filename', 'funky-chars<>%&;"\'')
169
165
        t.commit('commit filename')
170
 
        self.run_bzr('push ../new-tree')
 
166
        self.run_bzr('push', '../new-tree')
171
167
 
172
168
    def test_push_dash_d(self):
173
169
        t = self.make_branch_and_tree('from')
174
170
        t.commit(allow_pointless=True,
175
171
                message='first commit')
176
 
        self.run_bzr('push -d from to-one')
 
172
        self.runbzr('push -d from to-one')
177
173
        self.failUnlessExists('to-one')
178
 
        self.run_bzr('push -d %s %s' 
 
174
        self.runbzr('push -d %s %s' 
179
175
            % tuple(map(urlutils.local_path_to_url, ['from', 'to-two'])))
180
176
        self.failUnlessExists('to-two')
181
177
 
191
187
        tree = self.create_simple_tree()
192
188
 
193
189
        self.run_bzr_error(['Parent directory of ../new/tree does not exist'],
194
 
                           'push ../new/tree',
 
190
                           'push', '../new/tree',
195
191
                           working_dir='tree')
196
 
        self.run_bzr('push ../new/tree --create-prefix',
 
192
        self.run_bzr('push', '../new/tree', '--create-prefix',
197
193
                     working_dir='tree')
198
194
        new_tree = WorkingTree.open('new/tree')
199
195
        self.assertEqual(tree.last_revision(), new_tree.last_revision())
209
205
 
210
206
        self.run_bzr_error(['Target directory ../target already exists',
211
207
                            'Supply --use-existing-dir',
212
 
                           ],
213
 
                           'push ../target', working_dir='tree')
 
208
                           ], 'push', '../target',
 
209
                           working_dir='tree')
214
210
 
215
 
        self.run_bzr('push --use-existing-dir ../target',
 
211
        self.run_bzr('push', '--use-existing-dir', '../target',
216
212
                     working_dir='tree')
217
213
 
218
214
        new_tree = WorkingTree.open('target')
225
221
        tree = self.create_simple_tree()
226
222
        repo = self.make_repository('repo', shared=True)
227
223
 
228
 
        self.run_bzr('push ../repo',
 
224
        self.run_bzr('push', '../repo',
229
225
                     working_dir='tree')
230
226
 
231
227
        # Pushing onto an existing bzrdir will create a repository and
246
242
        a_bzrdir = self.make_bzrdir('dir')
247
243
 
248
244
        self.run_bzr_error(['At ../dir you have a valid .bzr control'],
249
 
                'push ../dir',
 
245
                'push', '../dir',
250
246
                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='development1')
347
 
        self.make_bzrdir('.').get_config().set_default_stack_on('stack_on')
348
 
        self.make_branch('from', format='development1')
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)