18
18
"""Black-box tests for bzr push."""
22
23
from bzrlib import (
33
from bzrlib.repofmt import knitrepo
34
from bzrlib.tests import (
40
from bzrlib.transport import memory
43
def load_tests(standard_tests, module, loader):
44
"""Multiply tests for the push command."""
45
result = loader.suiteClass()
47
# one for each king of change
48
changes_tests, remaining_tests = tests.split_suite_by_condition(
49
standard_tests, tests.condition_isinstance((
50
TestPushStrictWithChanges,
54
dict(_changes_type= '_uncommitted_changes')),
56
dict(_changes_type= '_pending_merges')),
58
dict(_changes_type= '_out_of_sync_trees')),
60
tests.multiply_tests(changes_tests, changes_scenarios, result)
61
# No parametrization for the remaining tests
62
result.addTests(remaining_tests)
67
class TestPush(tests.TestCaseWithTransport):
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
41
class TestPush(ExternalBase):
69
43
def test_push_error_on_vfs_http(self):
70
44
""" pushing a branch to a HTTP server fails cleanly. """
71
45
# the trunk is published on a web server
72
self.transport_readonly_server = http_server.HttpServer
46
self.transport_readonly_server = HttpServer
73
47
self.make_branch('source')
74
48
public_url = self.get_readonly_url('target')
75
49
self.run_bzr_error(['http does not support mkdir'],
98
72
self.assertEqual(None, branch_b.get_push_location())
100
74
# test push for failure without push location set
101
out = self.run_bzr('push', working_dir='branch_a', retcode=3)
76
out = self.run_bzr('push', retcode=3)
102
77
self.assertEquals(out,
103
78
('','bzr: ERROR: No push location known or specified.\n'))
105
80
# test not remembered if cannot actually push
106
self.run_bzr('push path/which/doesnt/exist',
107
working_dir='branch_a', retcode=3)
108
out = self.run_bzr('push', working_dir='branch_a', retcode=3)
81
self.run_bzr('push ../path/which/doesnt/exist', retcode=3)
82
out = self.run_bzr('push', retcode=3)
109
83
self.assertEquals(
110
84
('', 'bzr: ERROR: No push location known or specified.\n'),
113
87
# test implicit --remember when no push location set, push fails
114
out = self.run_bzr('push ../branch_b',
115
working_dir='branch_a', retcode=3)
88
out = self.run_bzr('push ../branch_b', retcode=3)
116
89
self.assertEquals(out,
117
90
('','bzr: ERROR: These branches have diverged. '
118
'See "bzr help diverged-branches" for more information.\n'))
119
self.assertEquals(osutils.abspath(branch_a.get_push_location()),
120
osutils.abspath(branch_b.bzrdir.root_transport.base))
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))
122
95
# test implicit --remember after resolving previous failure
123
uncommit.uncommit(branch=branch_b, tree=tree_b)
96
uncommit(branch=branch_b, tree=tree_b)
124
97
transport.delete('branch_b/c')
125
out, err = self.run_bzr('push', working_dir='branch_a')
98
out, err = self.run_bzr('push')
126
99
path = branch_a.get_push_location()
127
100
self.assertEquals(out,
128
101
'Using saved push location: %s\n'
129
% urlutils.local_path_from_url(path))
102
% local_path_from_url(path))
130
103
self.assertEqual(err,
131
104
'All changes applied successfully.\n'
132
105
'Pushed up to revision 2.\n')
133
106
self.assertEqual(path,
134
107
branch_b.bzrdir.root_transport.base)
135
108
# test explicit --remember
136
self.run_bzr('push ../branch_c --remember', working_dir='branch_a')
109
self.run_bzr('push ../branch_c --remember')
137
110
self.assertEquals(branch_a.get_push_location(),
138
111
branch_c.bzrdir.root_transport.base)
240
217
# being too low. If rpc_count increases, more network roundtrips have
241
218
# become necessary for this use case. Please do not adjust this number
242
219
# upwards without agreement from bzr's network support maintainers.
243
self.assertLength(14, self.hpss_calls)
244
remote = branch.Branch.open('public')
220
self.assertLength(47, self.hpss_calls)
221
remote = Branch.open('public')
245
222
self.assertEndsWith(remote.get_stacked_on_url(), '/parent')
247
def test_push_smart_tags_streaming_acceptance(self):
248
self.setup_smart_server_with_call_log()
249
t = self.make_branch_and_tree('from')
250
rev_id = t.commit(allow_pointless=True, message='first commit')
251
t.branch.tags.set_tag('new-tag', rev_id)
252
self.reset_smart_call_log()
253
self.run_bzr(['push', self.get_url('to-one')], working_dir='from')
254
# This figure represent the amount of work to perform this use case. It
255
# is entirely ok to reduce this number if a test fails due to rpc_count
256
# being too low. If rpc_count increases, more network roundtrips have
257
# become necessary for this use case. Please do not adjust this number
258
# upwards without agreement from bzr's network support maintainers.
259
self.assertLength(11, self.hpss_calls)
261
def test_push_smart_incremental_acceptance(self):
262
self.setup_smart_server_with_call_log()
263
t = self.make_branch_and_tree('from')
264
rev_id1 = t.commit(allow_pointless=True, message='first commit')
265
rev_id2 = t.commit(allow_pointless=True, message='second commit')
267
['push', self.get_url('to-one'), '-r1'], working_dir='from')
268
self.reset_smart_call_log()
269
self.run_bzr(['push', self.get_url('to-one')], working_dir='from')
270
# This figure represent the amount of work to perform this use case. It
271
# is entirely ok to reduce this number if a test fails due to rpc_count
272
# being too low. If rpc_count increases, more network roundtrips have
273
# become necessary for this use case. Please do not adjust this number
274
# upwards without agreement from bzr's network support maintainers.
275
self.assertLength(11, self.hpss_calls)
277
def test_push_smart_with_default_stacking_url_path_segment(self):
278
# If the default stacked-on location is a path element then branches
279
# we push there over the smart server are stacked and their
280
# stacked_on_url is that exact path segment. Added to nail bug 385132.
281
self.setup_smart_server_with_call_log()
282
self.make_branch('stack-on', format='1.9')
283
self.make_bzrdir('.').get_config().set_default_stack_on(
285
self.make_branch('from', format='1.9')
286
out, err = self.run_bzr(['push', '-d', 'from', self.get_url('to')])
287
b = branch.Branch.open(self.get_url('to'))
288
self.assertEqual('/extra/stack-on', b.get_stacked_on_url())
290
def test_push_smart_with_default_stacking_relative_path(self):
291
# If the default stacked-on location is a relative path then branches
292
# we push there over the smart server are stacked and their
293
# stacked_on_url is a relative path. Added to nail bug 385132.
294
self.setup_smart_server_with_call_log()
295
self.make_branch('stack-on', format='1.9')
296
self.make_bzrdir('.').get_config().set_default_stack_on('stack-on')
297
self.make_branch('from', format='1.9')
298
out, err = self.run_bzr(['push', '-d', 'from', self.get_url('to')])
299
b = branch.Branch.open(self.get_url('to'))
300
self.assertEqual('../stack-on', b.get_stacked_on_url())
302
224
def create_simple_tree(self):
303
225
tree = self.make_branch_and_tree('tree')
304
226
self.build_tree(['tree/a'])
639
535
% re.escape(destination_url)],
640
536
['push', '-d', 'tree', destination_url], retcode=3)
641
537
self.assertEqual('', out)
644
class TestPushStrictMixin(object):
646
def make_local_branch_and_tree(self):
647
self.tree = self.make_branch_and_tree('local')
648
self.build_tree_contents([('local/file', 'initial')])
649
self.tree.add('file')
650
self.tree.commit('adding file', rev_id='added')
651
self.build_tree_contents([('local/file', 'modified')])
652
self.tree.commit('modify file', rev_id='modified')
654
def set_config_push_strict(self, value):
655
# set config var (any of bazaar.conf, locations.conf, branch.conf
657
conf = self.tree.branch.get_config()
658
conf.set_user_option('push_strict', value)
660
_default_command = ['push', '../to']
661
_default_wd = 'local'
662
_default_errors = ['Working tree ".*/local/" has uncommitted '
663
'changes \(See bzr status\)\.',]
664
_default_additional_error = 'Use --no-strict to force the push.\n'
665
_default_additional_warning = 'Uncommitted changes will not be pushed.'
668
def assertPushFails(self, args):
669
out, err = self.run_bzr_error(self._default_errors,
670
self._default_command + args,
671
working_dir=self._default_wd, retcode=3)
672
self.assertContainsRe(err, self._default_additional_error)
674
def assertPushSucceeds(self, args, with_warning=False, revid_to_push=None):
676
error_regexes = self._default_errors
679
out, err = self.run_bzr(self._default_command + args,
680
working_dir=self._default_wd,
681
error_regexes=error_regexes)
683
self.assertContainsRe(err, self._default_additional_warning)
685
self.assertNotContainsRe(err, self._default_additional_warning)
686
branch_from = branch.Branch.open(self._default_wd)
687
if revid_to_push is None:
688
revid_to_push = branch_from.last_revision()
689
branch_to = branch.Branch.open('to')
690
repo_to = branch_to.repository
691
self.assertTrue(repo_to.has_revision(revid_to_push))
692
self.assertEqual(revid_to_push, branch_to.last_revision())
696
class TestPushStrictWithoutChanges(tests.TestCaseWithTransport,
697
TestPushStrictMixin):
700
super(TestPushStrictWithoutChanges, self).setUp()
701
self.make_local_branch_and_tree()
703
def test_push_default(self):
704
self.assertPushSucceeds([])
706
def test_push_strict(self):
707
self.assertPushSucceeds(['--strict'])
709
def test_push_no_strict(self):
710
self.assertPushSucceeds(['--no-strict'])
712
def test_push_config_var_strict(self):
713
self.set_config_push_strict('true')
714
self.assertPushSucceeds([])
716
def test_push_config_var_no_strict(self):
717
self.set_config_push_strict('false')
718
self.assertPushSucceeds([])
721
class TestPushStrictWithChanges(tests.TestCaseWithTransport,
722
TestPushStrictMixin):
724
_changes_type = None # Set by load_tests
727
super(TestPushStrictWithChanges, self).setUp()
728
# Apply the changes defined in load_tests: one of _uncommitted_changes,
729
# _pending_merges or _out_of_sync_trees
730
getattr(self, self._changes_type)()
732
def _uncommitted_changes(self):
733
self.make_local_branch_and_tree()
734
# Make a change without committing it
735
self.build_tree_contents([('local/file', 'in progress')])
737
def _pending_merges(self):
738
self.make_local_branch_and_tree()
739
# Create 'other' branch containing a new file
740
other_bzrdir = self.tree.bzrdir.sprout('other')
741
other_tree = other_bzrdir.open_workingtree()
742
self.build_tree_contents([('other/other-file', 'other')])
743
other_tree.add('other-file')
744
other_tree.commit('other commit', rev_id='other')
745
# Merge and revert, leaving a pending merge
746
self.tree.merge_from_branch(other_tree.branch)
747
self.tree.revert(filenames=['other-file'], backups=False)
749
def _out_of_sync_trees(self):
750
self.make_local_branch_and_tree()
751
self.run_bzr(['checkout', '--lightweight', 'local', 'checkout'])
752
# Make a change and commit it
753
self.build_tree_contents([('local/file', 'modified in local')])
754
self.tree.commit('modify file', rev_id='modified-in-local')
755
# Exercise commands from the checkout directory
756
self._default_wd = 'checkout'
757
self._default_errors = ["Working tree is out of date, please run"
760
def test_push_default(self):
761
self.assertPushSucceeds([], with_warning=True)
763
def test_push_with_revision(self):
764
self.assertPushSucceeds(['-r', 'revid:added'], revid_to_push='added')
766
def test_push_no_strict(self):
767
self.assertPushSucceeds(['--no-strict'])
769
def test_push_strict_with_changes(self):
770
self.assertPushFails(['--strict'])
772
def test_push_respect_config_var_strict(self):
773
self.set_config_push_strict('true')
774
self.assertPushFails([])
776
def test_push_bogus_config_var_ignored(self):
777
self.set_config_push_strict("I don't want you to be strict")
778
self.assertPushSucceeds([], with_warning=True)
780
def test_push_no_strict_command_line_override_config(self):
781
self.set_config_push_strict('yES')
782
self.assertPushFails([])
783
self.assertPushSucceeds(['--no-strict'])
785
def test_push_strict_command_line_override_config(self):
786
self.set_config_push_strict('oFF')
787
self.assertPushFails(['--strict'])
788
self.assertPushSucceeds([])
791
class TestPushForeign(tests.TestCaseWithTransport):
794
super(TestPushForeign, self).setUp()
795
test_foreign.register_dummy_foreign_for_test(self)
797
def make_dummy_builder(self, relpath):
798
builder = self.make_branch_builder(
799
relpath, format=test_foreign.DummyForeignVcsDirFormat())
800
builder.build_snapshot('revid', None,
801
[('add', ('', 'TREE_ROOT', 'directory', None)),
802
('add', ('foo', 'fooid', 'file', 'bar'))])
805
def test_no_roundtripping(self):
806
target_branch = self.make_dummy_builder('dp').get_branch()
807
source_tree = self.make_branch_and_tree("dc")
808
output, error = self.run_bzr("push -d dc dp", retcode=3)
809
self.assertEquals("", output)
810
self.assertEquals(error, "bzr: ERROR: It is not possible to losslessly"
811
" push to dummy. You may want to use dpush instead.\n")