/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: John Arbash Meinel
  • Date: 2009-07-08 14:37:25 UTC
  • mfrom: (4516 +trunk)
  • mto: This revision was merged to the branch mainline in revision 4517.
  • Revision ID: john@arbash-meinel.com-20090708143725-sc9sjy3mz4cxwxzz
Merge bzr.dev 4516

Show diffs side-by-side

added added

removed removed

Lines of Context:
17
17
 
18
18
"""Black-box tests for bzr push."""
19
19
 
20
 
import os
21
20
import re
22
21
 
23
22
from bzrlib import (
 
23
    branch,
 
24
    bzrdir,
24
25
    errors,
 
26
    osutils,
 
27
    tests,
25
28
    transport,
 
29
    uncommit,
26
30
    urlutils,
 
31
    workingtree
27
32
    )
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):
 
33
from bzrlib.repofmt import knitrepo
 
34
from bzrlib.tests import http_server
 
35
from bzrlib.transport import memory
 
36
 
 
37
 
 
38
def load_tests(standard_tests, module, loader):
 
39
    """Multiply tests for the push command."""
 
40
    result = loader.suiteClass()
 
41
 
 
42
    # one for each king of change
 
43
    changes_tests, remaining_tests = tests.split_suite_by_condition(
 
44
        standard_tests, tests.condition_isinstance((
 
45
                TestPushStrictWithChanges,
 
46
                )))
 
47
    changes_scenarios = [
 
48
        ('uncommitted',
 
49
         dict(_changes_type= '_uncommitted_changes')),
 
50
        ('pending-merges',
 
51
         dict(_changes_type= '_pending_merges')),
 
52
        ('out-of-sync-trees',
 
53
         dict(_changes_type= '_out_of_sync_trees')),
 
54
        ]
 
55
    tests.multiply_tests(changes_tests, changes_scenarios, result)
 
56
    # No parametrization for the remaining tests
 
57
    result.addTests(remaining_tests)
 
58
 
 
59
    return result
 
60
 
 
61
 
 
62
class TestPush(tests.TestCaseWithTransport):
42
63
 
43
64
    def test_push_error_on_vfs_http(self):
44
65
        """ pushing a branch to a HTTP server fails cleanly. """
45
66
        # the trunk is published on a web server
46
 
        self.transport_readonly_server = HttpServer
 
67
        self.transport_readonly_server = http_server.HttpServer
47
68
        self.make_branch('source')
48
69
        public_url = self.get_readonly_url('target')
49
70
        self.run_bzr_error(['http does not support mkdir'],
72
93
        self.assertEqual(None, branch_b.get_push_location())
73
94
 
74
95
        # test push for failure without push location set
75
 
        os.chdir('branch_a')
76
 
        out = self.run_bzr('push', retcode=3)
 
96
        out = self.run_bzr('push', working_dir='branch_a', retcode=3)
77
97
        self.assertEquals(out,
78
98
                ('','bzr: ERROR: No push location known or specified.\n'))
79
99
 
80
100
        # 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)
 
101
        self.run_bzr('push path/which/doesnt/exist',
 
102
                     working_dir='branch_a', retcode=3)
 
103
        out = self.run_bzr('push', working_dir='branch_a', retcode=3)
83
104
        self.assertEquals(
84
105
                ('', 'bzr: ERROR: No push location known or specified.\n'),
85
106
                out)
86
107
 
87
108
        # test implicit --remember when no push location set, push fails
88
 
        out = self.run_bzr('push ../branch_b', retcode=3)
 
109
        out = self.run_bzr('push ../branch_b',
 
110
                           working_dir='branch_a', retcode=3)
89
111
        self.assertEquals(out,
90
112
                ('','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))
 
113
                 'See "bzr help diverged-branches" for more information.\n'))
 
114
        self.assertEquals(osutils.abspath(branch_a.get_push_location()),
 
115
                          osutils.abspath(branch_b.bzrdir.root_transport.base))
94
116
 
95
117
        # test implicit --remember after resolving previous failure
96
 
        uncommit(branch=branch_b, tree=tree_b)
 
118
        uncommit.uncommit(branch=branch_b, tree=tree_b)
97
119
        transport.delete('branch_b/c')
98
 
        out, err = self.run_bzr('push')
 
120
        out, err = self.run_bzr('push', working_dir='branch_a')
99
121
        path = branch_a.get_push_location()
100
122
        self.assertEquals(out,
101
123
                          'Using saved push location: %s\n'
102
 
                          % local_path_from_url(path))
 
124
                          % urlutils.local_path_from_url(path))
103
125
        self.assertEqual(err,
104
126
                         'All changes applied successfully.\n'
105
127
                         'Pushed up to revision 2.\n')
106
128
        self.assertEqual(path,
107
129
                         branch_b.bzrdir.root_transport.base)
108
130
        # test explicit --remember
109
 
        self.run_bzr('push ../branch_c --remember')
 
131
        self.run_bzr('push ../branch_c --remember', working_dir='branch_a')
110
132
        self.assertEquals(branch_a.get_push_location(),
111
133
                          branch_c.bzrdir.root_transport.base)
112
134
 
116
138
        out, err = self.run_bzr('push pushed-location')
117
139
        self.assertEqual('', out)
118
140
        self.assertEqual('Created new branch.\n', err)
119
 
        b2 = Branch.open('pushed-location')
 
141
        b2 = branch.Branch.open('pushed-location')
120
142
        self.assertEndsWith(b2.base, 'pushed-location/')
121
143
 
122
144
    def test_push_new_branch_revision_count(self):
127
149
        self.build_tree(['tree/file'])
128
150
        t.add('file')
129
151
        t.commit('commit 1')
130
 
        os.chdir('tree')
131
 
        out, err = self.run_bzr('push pushed-to')
132
 
        os.chdir('..')
 
152
        out, err = self.run_bzr('push -d tree pushed-to')
133
153
        self.assertEqual('', out)
134
154
        self.assertEqual('Created new branch.\n', err)
135
155
 
136
156
    def test_push_only_pushes_history(self):
137
157
        # Knit branches should only push the history for the current revision.
138
 
        format = BzrDirMetaFormat1()
139
 
        format.repository_format = RepositoryFormatKnit1()
 
158
        format = bzrdir.BzrDirMetaFormat1()
 
159
        format.repository_format = knitrepo.RepositoryFormatKnit1()
140
160
        shared_repo = self.make_repository('repo', format=format, shared=True)
141
161
        shared_repo.set_make_working_trees(True)
142
162
 
143
163
        def make_shared_tree(path):
144
164
            shared_repo.bzrdir.root_transport.mkdir(path)
145
165
            shared_repo.bzrdir.create_branch_convenience('repo/' + path)
146
 
            return WorkingTree.open('repo/' + path)
 
166
            return workingtree.WorkingTree.open('repo/' + path)
147
167
        tree_a = make_shared_tree('a')
148
168
        self.build_tree(['repo/a/file'])
149
169
        tree_a.add('file')
164
184
 
165
185
        # Now that we have a repository with shared files, make sure
166
186
        # 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')
 
187
        self.run_bzr('push ../../push-b', working_dir='repo/b')
 
188
        pushed_tree = workingtree.WorkingTree.open('push-b')
170
189
        pushed_repo = pushed_tree.branch.repository
171
190
        self.assertFalse(pushed_repo.has_revision('a-1'))
172
191
        self.assertFalse(pushed_repo.has_revision('a-2'))
174
193
 
175
194
    def test_push_funky_id(self):
176
195
        t = self.make_branch_and_tree('tree')
177
 
        os.chdir('tree')
178
 
        self.build_tree(['filename'])
 
196
        self.build_tree(['tree/filename'])
179
197
        t.add('filename', 'funky-chars<>%&;"\'')
180
198
        t.commit('commit filename')
181
 
        self.run_bzr('push ../new-tree')
 
199
        self.run_bzr('push -d tree new-tree')
182
200
 
183
201
    def test_push_dash_d(self):
184
202
        t = self.make_branch_and_tree('from')
218
236
        # become necessary for this use case. Please do not adjust this number
219
237
        # upwards without agreement from bzr's network support maintainers.
220
238
        self.assertLength(14, self.hpss_calls)
221
 
        remote = Branch.open('public')
 
239
        remote = branch.Branch.open('public')
222
240
        self.assertEndsWith(remote.get_stacked_on_url(), '/parent')
223
241
 
 
242
    def test_push_smart_with_default_stacking_url_path_segment(self):
 
243
        # If the default stacked-on location is a path element then branches
 
244
        # we push there over the smart server are stacked and their
 
245
        # stacked_on_url is that exact path segment. Added to nail bug 385132.
 
246
        self.setup_smart_server_with_call_log()
 
247
        self.make_branch('stack-on', format='1.9')
 
248
        self.make_bzrdir('.').get_config().set_default_stack_on(
 
249
            '/stack-on')
 
250
        self.make_branch('from', format='1.9')
 
251
        out, err = self.run_bzr(['push', '-d', 'from', self.get_url('to')])
 
252
        b = branch.Branch.open(self.get_url('to'))
 
253
        self.assertEqual('/extra/stack-on', b.get_stacked_on_url())
 
254
 
 
255
    def test_push_smart_with_default_stacking_relative_path(self):
 
256
        # If the default stacked-on location is a relative path then branches
 
257
        # we push there over the smart server are stacked and their
 
258
        # stacked_on_url is a relative path. Added to nail bug 385132.
 
259
        self.setup_smart_server_with_call_log()
 
260
        self.make_branch('stack-on', format='1.9')
 
261
        self.make_bzrdir('.').get_config().set_default_stack_on('stack-on')
 
262
        self.make_branch('from', format='1.9')
 
263
        out, err = self.run_bzr(['push', '-d', 'from', self.get_url('to')])
 
264
        b = branch.Branch.open(self.get_url('to'))
 
265
        self.assertEqual('../stack-on', b.get_stacked_on_url())
 
266
 
224
267
    def create_simple_tree(self):
225
268
        tree = self.make_branch_and_tree('tree')
226
269
        self.build_tree(['tree/a'])
237
280
                           working_dir='tree')
238
281
        self.run_bzr('push ../new/tree --create-prefix',
239
282
                     working_dir='tree')
240
 
        new_tree = WorkingTree.open('new/tree')
 
283
        new_tree = workingtree.WorkingTree.open('new/tree')
241
284
        self.assertEqual(tree.last_revision(), new_tree.last_revision())
242
285
        self.failUnlessExists('new/tree/a')
243
286
 
257
300
        self.run_bzr('push --use-existing-dir ../target',
258
301
                     working_dir='tree')
259
302
 
260
 
        new_tree = WorkingTree.open('target')
 
303
        new_tree = workingtree.WorkingTree.open('target')
261
304
        self.assertEqual(tree.last_revision(), new_tree.last_revision())
262
305
        # The push should have created target/a
263
306
        self.failUnlessExists('target/a')
273
316
        # Pushing onto an existing bzrdir will create a repository and
274
317
        # branch as needed, but will only create a working tree if there was
275
318
        # no BzrDir before.
276
 
        self.assertRaises(errors.NoWorkingTree, WorkingTree.open, 'repo')
277
 
        new_branch = Branch.open('repo')
 
319
        self.assertRaises(errors.NoWorkingTree,
 
320
                          workingtree.WorkingTree.open, 'repo')
 
321
        new_branch = branch.Branch.open('repo')
278
322
        self.assertEqual(tree.last_revision(), new_branch.last_revision())
279
323
 
280
324
    def test_push_onto_just_bzrdir(self):
299
343
 
300
344
        self.run_bzr('push -r1 ../to', working_dir='from')
301
345
 
302
 
        tree_to = WorkingTree.open('to')
 
346
        tree_to = workingtree.WorkingTree.open('to')
303
347
        repo_to = tree_to.branch.repository
304
348
        self.assertTrue(repo_to.has_revision('from-1'))
305
349
        self.assertFalse(repo_to.has_revision('from-2'))
326
370
 
327
371
    def assertPublished(self, branch_revid, stacked_on):
328
372
        """Assert that the branch 'published' has been published correctly."""
329
 
        published_branch = Branch.open('published')
 
373
        published_branch = branch.Branch.open('published')
330
374
        # The published branch refers to the mainline
331
375
        self.assertEqual(stacked_on, published_branch.get_stacked_on_url())
332
376
        # and the branch's work was pushed
354
398
        self.assertEqual('', out)
355
399
        self.assertEqual('Created new stacked branch referring to %s.\n' %
356
400
            trunk_tree.branch.base, err)
357
 
        self.assertPublished(branch_tree.last_revision(), trunk_tree.branch.base)
 
401
        self.assertPublished(branch_tree.last_revision(),
 
402
                             trunk_tree.branch.base)
358
403
 
359
404
    def test_push_new_branch_stacked_uses_parent_public(self):
360
405
        """Pushing a new branch with --stacked creates a stacked branch."""
361
406
        trunk_tree, branch_tree = self.create_trunk_and_feature_branch()
362
407
        # the trunk is published on a web server
363
 
        self.transport_readonly_server = HttpServer
 
408
        self.transport_readonly_server = http_server.HttpServer
364
409
        trunk_public = self.make_branch('public_trunk', format='1.9')
365
410
        trunk_public.pull(trunk_tree.branch)
366
411
        trunk_public_url = self.get_readonly_url('public_trunk')
398
443
        self.make_bzrdir('.').get_config().set_default_stack_on('stack_on')
399
444
        self.make_branch('from', format='pack-0.92')
400
445
        out, err = self.run_bzr('push -d from to')
401
 
        branch = Branch.open('to')
402
 
        self.assertEqual('../stack_on', branch.get_stacked_on_url())
 
446
        b = branch.Branch.open('to')
 
447
        self.assertEqual('../stack_on', b.get_stacked_on_url())
403
448
 
404
449
    def test_push_does_not_change_format_with_default_if_target_cannot(self):
405
450
        self.make_branch('stack_on', format='pack-0.92')
406
451
        self.make_bzrdir('.').get_config().set_default_stack_on('stack_on')
407
452
        self.make_branch('from', format='pack-0.92')
408
453
        out, err = self.run_bzr('push -d from to')
409
 
        branch = Branch.open('to')
410
 
        self.assertRaises(errors.UnstackableBranchFormat,
411
 
            branch.get_stacked_on_url)
 
454
        b = branch.Branch.open('to')
 
455
        self.assertRaises(errors.UnstackableBranchFormat, b.get_stacked_on_url)
412
456
 
413
457
    def test_push_doesnt_create_broken_branch(self):
414
458
        """Pushing a new standalone branch works even when there's a default
455
499
        # subsequent log is accurate
456
500
        self.assertNotContainsRe(out, 'rev1')
457
501
 
458
 
 
459
 
class RedirectingMemoryTransport(MemoryTransport):
 
502
    def test_push_from_subdir(self):
 
503
        t = self.make_branch_and_tree('tree')
 
504
        self.build_tree(['tree/dir/', 'tree/dir/file'])
 
505
        t.add('dir', 'dir/file')
 
506
        t.commit('r1')
 
507
        out, err = self.run_bzr('push ../../pushloc', working_dir='tree/dir')
 
508
        self.assertEqual('', out)
 
509
        self.assertEqual('Created new branch.\n', err)
 
510
 
 
511
 
 
512
class RedirectingMemoryTransport(memory.MemoryTransport):
460
513
 
461
514
    def mkdir(self, relpath, mode=None):
462
515
        from bzrlib.trace import mutter
463
 
        mutter('cwd: %r, rel: %r, abs: %r' % (self._cwd, relpath, abspath))
464
516
        if self._cwd == '/source/':
465
517
            raise errors.RedirectRequested(self.abspath(relpath),
466
518
                                           self.abspath('../target'),
478
530
        return transport.get_transport(target)
479
531
 
480
532
 
481
 
class RedirectingMemoryServer(MemoryServer):
 
533
class RedirectingMemoryServer(memory.MemoryServer):
482
534
 
483
535
    def setUp(self):
484
536
        self._dirs = {'/': None}
498
550
        transport.unregister_transport(self._scheme, self._memory_factory)
499
551
 
500
552
 
501
 
class TestPushRedirect(ExternalBase):
 
553
class TestPushRedirect(tests.TestCaseWithTransport):
502
554
 
503
555
    def setUp(self):
504
 
        ExternalBase.setUp(self)
 
556
        tests.TestCaseWithTransport.setUp(self)
505
557
        self.memory_server = RedirectingMemoryServer()
506
558
        self.memory_server.setUp()
507
559
        self.addCleanup(self.memory_server.tearDown)
521
573
        destination_url = self.memory_server.get_url() + 'source'
522
574
        self.run_bzr(['push', '-d', 'tree', destination_url])
523
575
 
524
 
        local_revision = Branch.open('tree').last_revision()
525
 
        remote_revision = Branch.open(
 
576
        local_revision = branch.Branch.open('tree').last_revision()
 
577
        remote_revision = branch.Branch.open(
526
578
            self.memory_server.get_url() + 'target').last_revision()
527
579
        self.assertEqual(remote_revision, local_revision)
528
580
 
536
588
             % re.escape(destination_url)],
537
589
            ['push', '-d', 'tree', destination_url], retcode=3)
538
590
        self.assertEqual('', out)
 
591
 
 
592
 
 
593
class TestPushStrictMixin(object):
 
594
 
 
595
    def make_local_branch_and_tree(self):
 
596
        self.tree = self.make_branch_and_tree('local')
 
597
        self.build_tree_contents([('local/file', 'initial')])
 
598
        self.tree.add('file')
 
599
        self.tree.commit('adding file', rev_id='added')
 
600
        self.build_tree_contents([('local/file', 'modified')])
 
601
        self.tree.commit('modify file', rev_id='modified')
 
602
 
 
603
    def set_config_push_strict(self, value):
 
604
        # set config var (any of bazaar.conf, locations.conf, branch.conf
 
605
        # should do)
 
606
        conf = self.tree.branch.get_config()
 
607
        conf.set_user_option('push_strict', value)
 
608
 
 
609
    _default_command = ['push', '../to']
 
610
    _default_wd = 'local'
 
611
    _default_errors = ['Working tree ".*/local/" has uncommitted '
 
612
                       'changes \(See bzr status\)\.',]
 
613
    _default_pushed_revid = 'modified'
 
614
 
 
615
    def assertPushFails(self, args):
 
616
        self.run_bzr_error(self._default_errors, self._default_command + args,
 
617
                           working_dir=self._default_wd, retcode=3)
 
618
 
 
619
    def assertPushSucceeds(self, args, pushed_revid=None):
 
620
        self.run_bzr(self._default_command + args,
 
621
                     working_dir=self._default_wd)
 
622
        if pushed_revid is None:
 
623
            pushed_revid = self._default_pushed_revid
 
624
        tree_to = workingtree.WorkingTree.open('to')
 
625
        repo_to = tree_to.branch.repository
 
626
        self.assertTrue(repo_to.has_revision(pushed_revid))
 
627
        self.assertEqual(tree_to.branch.last_revision_info()[1], pushed_revid)
 
628
 
 
629
 
 
630
 
 
631
class TestPushStrictWithoutChanges(tests.TestCaseWithTransport,
 
632
                                   TestPushStrictMixin):
 
633
 
 
634
    def setUp(self):
 
635
        super(TestPushStrictWithoutChanges, self).setUp()
 
636
        self.make_local_branch_and_tree()
 
637
 
 
638
    def test_push_default(self):
 
639
        self.assertPushSucceeds([])
 
640
 
 
641
    def test_push_strict(self):
 
642
        self.assertPushSucceeds(['--strict'])
 
643
 
 
644
    def test_push_no_strict(self):
 
645
        self.assertPushSucceeds(['--no-strict'])
 
646
 
 
647
    def test_push_config_var_strict(self):
 
648
        self.set_config_push_strict('true')
 
649
        self.assertPushSucceeds([])
 
650
 
 
651
    def test_push_config_var_no_strict(self):
 
652
        self.set_config_push_strict('false')
 
653
        self.assertPushSucceeds([])
 
654
 
 
655
 
 
656
class TestPushStrictWithChanges(tests.TestCaseWithTransport,
 
657
                                TestPushStrictMixin):
 
658
 
 
659
    _changes_type = None # Set by load_tests
 
660
 
 
661
    def setUp(self):
 
662
        super(TestPushStrictWithChanges, self).setUp()
 
663
        getattr(self, self._changes_type)()
 
664
 
 
665
    def _uncommitted_changes(self):
 
666
        self.make_local_branch_and_tree()
 
667
        # Make a change without committing it
 
668
        self.build_tree_contents([('local/file', 'in progress')])
 
669
 
 
670
    def _pending_merges(self):
 
671
        self.make_local_branch_and_tree()
 
672
        # Create 'other' branch containing a new file
 
673
        other_bzrdir = self.tree.bzrdir.sprout('other')
 
674
        other_tree = other_bzrdir.open_workingtree()
 
675
        self.build_tree_contents([('other/other-file', 'other')])
 
676
        other_tree.add('other-file')
 
677
        other_tree.commit('other commit', rev_id='other')
 
678
        # Merge and revert, leaving a pending merge
 
679
        self.tree.merge_from_branch(other_tree.branch)
 
680
        self.tree.revert(filenames=['other-file'], backups=False)
 
681
 
 
682
    def _out_of_sync_trees(self):
 
683
        self.make_local_branch_and_tree()
 
684
        self.run_bzr(['checkout', '--lightweight', 'local', 'checkout'])
 
685
        # Make a change and commit it
 
686
        self.build_tree_contents([('local/file', 'modified in local')])
 
687
        self.tree.commit('modify file', rev_id='modified-in-local')
 
688
        # Exercise commands from the checkout directory
 
689
        self._default_wd = 'checkout'
 
690
        self._default_errors = ["Working tree is out of date, please run"
 
691
                                " 'bzr update'\.",]
 
692
        self._default_pushed_revid = 'modified-in-local'
 
693
 
 
694
    def test_push_default(self):
 
695
        self.assertPushFails([])
 
696
 
 
697
    def test_push_with_revision(self):
 
698
        self.assertPushSucceeds(['-r', 'revid:added'], pushed_revid='added')
 
699
 
 
700
    def test_push_no_strict(self):
 
701
        self.assertPushSucceeds(['--no-strict'])
 
702
 
 
703
    def test_push_strict_with_changes(self):
 
704
        self.assertPushFails(['--strict'])
 
705
 
 
706
    def test_push_respect_config_var_strict(self):
 
707
        self.set_config_push_strict('true')
 
708
        self.assertPushFails([])
 
709
 
 
710
    def test_push_bogus_config_var_ignored(self):
 
711
        self.set_config_push_strict("I don't want you to be strict")
 
712
        self.assertPushFails([])
 
713
 
 
714
    def test_push_no_strict_command_line_override_config(self):
 
715
        self.set_config_push_strict('yES')
 
716
        self.assertPushFails([])
 
717
        self.assertPushSucceeds(['--no-strict'])
 
718
 
 
719
    def test_push_strict_command_line_override_config(self):
 
720
        self.set_config_push_strict('oFF')
 
721
        self.assertPushFails(['--strict'])
 
722
        self.assertPushSucceeds([])