18
18
"""Black-box tests for bzr push."""
22
23
from bzrlib import (
33
from bzrlib.repofmt import knitrepo
34
from bzrlib.tests import http_server
35
from bzrlib.transport import memory
38
def load_tests(standard_tests, module, loader):
39
"""Multiply tests for the push command."""
40
result = loader.suiteClass()
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,
49
dict(_changes_type= '_uncommitted_changes')),
51
dict(_changes_type= '_pending_merges')),
53
dict(_changes_type= '_out_of_sync_trees')),
55
tests.multiply_tests(changes_tests, changes_scenarios, result)
56
# No parametrization for the remaining tests
57
result.addTests(remaining_tests)
62
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):
64
43
def test_push_error_on_vfs_http(self):
65
44
""" pushing a branch to a HTTP server fails cleanly. """
66
45
# the trunk is published on a web server
67
self.transport_readonly_server = http_server.HttpServer
46
self.transport_readonly_server = HttpServer
68
47
self.make_branch('source')
69
48
public_url = self.get_readonly_url('target')
70
49
self.run_bzr_error(['http does not support mkdir'],
93
72
self.assertEqual(None, branch_b.get_push_location())
95
74
# test push for failure without push location set
96
out = self.run_bzr('push', working_dir='branch_a', retcode=3)
76
out = self.run_bzr('push', retcode=3)
97
77
self.assertEquals(out,
98
78
('','bzr: ERROR: No push location known or specified.\n'))
100
80
# test not remembered if cannot actually push
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)
81
self.run_bzr('push ../path/which/doesnt/exist', retcode=3)
82
out = self.run_bzr('push', retcode=3)
104
83
self.assertEquals(
105
84
('', 'bzr: ERROR: No push location known or specified.\n'),
108
87
# test implicit --remember when no push location set, push fails
109
out = self.run_bzr('push ../branch_b',
110
working_dir='branch_a', retcode=3)
88
out = self.run_bzr('push ../branch_b', retcode=3)
111
89
self.assertEquals(out,
112
90
('','bzr: ERROR: These branches have diverged. '
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))
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))
117
95
# test implicit --remember after resolving previous failure
118
uncommit.uncommit(branch=branch_b, tree=tree_b)
96
uncommit(branch=branch_b, tree=tree_b)
119
97
transport.delete('branch_b/c')
120
out, err = self.run_bzr('push', working_dir='branch_a')
98
out, err = self.run_bzr('push')
121
99
path = branch_a.get_push_location()
122
100
self.assertEquals(out,
123
101
'Using saved push location: %s\n'
124
% urlutils.local_path_from_url(path))
102
% local_path_from_url(path))
125
103
self.assertEqual(err,
126
104
'All changes applied successfully.\n'
127
105
'Pushed up to revision 2.\n')
128
106
self.assertEqual(path,
129
107
branch_b.bzrdir.root_transport.base)
130
108
# test explicit --remember
131
self.run_bzr('push ../branch_c --remember', working_dir='branch_a')
109
self.run_bzr('push ../branch_c --remember')
132
110
self.assertEquals(branch_a.get_push_location(),
133
111
branch_c.bzrdir.root_transport.base)
149
127
self.build_tree(['tree/file'])
151
129
t.commit('commit 1')
152
out, err = self.run_bzr('push -d tree pushed-to')
131
out, err = self.run_bzr('push pushed-to')
153
133
self.assertEqual('', out)
154
134
self.assertEqual('Created new branch.\n', err)
156
136
def test_push_only_pushes_history(self):
157
137
# Knit branches should only push the history for the current revision.
158
format = bzrdir.BzrDirMetaFormat1()
159
format.repository_format = knitrepo.RepositoryFormatKnit1()
138
format = BzrDirMetaFormat1()
139
format.repository_format = RepositoryFormatKnit1()
160
140
shared_repo = self.make_repository('repo', format=format, shared=True)
161
141
shared_repo.set_make_working_trees(True)
163
143
def make_shared_tree(path):
164
144
shared_repo.bzrdir.root_transport.mkdir(path)
165
145
shared_repo.bzrdir.create_branch_convenience('repo/' + path)
166
return workingtree.WorkingTree.open('repo/' + path)
146
return WorkingTree.open('repo/' + path)
167
147
tree_a = make_shared_tree('a')
168
148
self.build_tree(['repo/a/file'])
169
149
tree_a.add('file')
236
218
# become necessary for this use case. Please do not adjust this number
237
219
# upwards without agreement from bzr's network support maintainers.
238
220
self.assertLength(14, self.hpss_calls)
239
remote = branch.Branch.open('public')
221
remote = Branch.open('public')
240
222
self.assertEndsWith(remote.get_stacked_on_url(), '/parent')
242
def test_push_smart_tags_streaming_acceptance(self):
243
self.setup_smart_server_with_call_log()
244
t = self.make_branch_and_tree('from')
245
rev_id = t.commit(allow_pointless=True, message='first commit')
246
t.branch.tags.set_tag('new-tag', rev_id)
247
self.reset_smart_call_log()
248
self.run_bzr(['push', self.get_url('to-one')], working_dir='from')
249
# This figure represent the amount of work to perform this use case. It
250
# is entirely ok to reduce this number if a test fails due to rpc_count
251
# being too low. If rpc_count increases, more network roundtrips have
252
# become necessary for this use case. Please do not adjust this number
253
# upwards without agreement from bzr's network support maintainers.
254
self.assertLength(11, self.hpss_calls)
256
def test_push_smart_with_default_stacking_url_path_segment(self):
257
# If the default stacked-on location is a path element then branches
258
# we push there over the smart server are stacked and their
259
# stacked_on_url is that exact path segment. Added to nail bug 385132.
260
self.setup_smart_server_with_call_log()
261
self.make_branch('stack-on', format='1.9')
262
self.make_bzrdir('.').get_config().set_default_stack_on(
264
self.make_branch('from', format='1.9')
265
out, err = self.run_bzr(['push', '-d', 'from', self.get_url('to')])
266
b = branch.Branch.open(self.get_url('to'))
267
self.assertEqual('/extra/stack-on', b.get_stacked_on_url())
269
def test_push_smart_with_default_stacking_relative_path(self):
270
# If the default stacked-on location is a relative path then branches
271
# we push there over the smart server are stacked and their
272
# stacked_on_url is a relative path. Added to nail bug 385132.
273
self.setup_smart_server_with_call_log()
274
self.make_branch('stack-on', format='1.9')
275
self.make_bzrdir('.').get_config().set_default_stack_on('stack-on')
276
self.make_branch('from', format='1.9')
277
out, err = self.run_bzr(['push', '-d', 'from', self.get_url('to')])
278
b = branch.Branch.open(self.get_url('to'))
279
self.assertEqual('../stack-on', b.get_stacked_on_url())
281
224
def create_simple_tree(self):
282
225
tree = self.make_branch_and_tree('tree')
283
226
self.build_tree(['tree/a'])
457
398
self.make_bzrdir('.').get_config().set_default_stack_on('stack_on')
458
399
self.make_branch('from', format='pack-0.92')
459
400
out, err = self.run_bzr('push -d from to')
460
b = branch.Branch.open('to')
461
self.assertEqual('../stack_on', b.get_stacked_on_url())
401
branch = Branch.open('to')
402
self.assertEqual('../stack_on', branch.get_stacked_on_url())
463
404
def test_push_does_not_change_format_with_default_if_target_cannot(self):
464
405
self.make_branch('stack_on', format='pack-0.92')
465
406
self.make_bzrdir('.').get_config().set_default_stack_on('stack_on')
466
407
self.make_branch('from', format='pack-0.92')
467
408
out, err = self.run_bzr('push -d from to')
468
b = branch.Branch.open('to')
469
self.assertRaises(errors.UnstackableBranchFormat, b.get_stacked_on_url)
409
branch = Branch.open('to')
410
self.assertRaises(errors.UnstackableBranchFormat,
411
branch.get_stacked_on_url)
471
413
def test_push_doesnt_create_broken_branch(self):
472
414
"""Pushing a new standalone branch works even when there's a default
513
455
# subsequent log is accurate
514
456
self.assertNotContainsRe(out, 'rev1')
516
def test_push_from_subdir(self):
517
t = self.make_branch_and_tree('tree')
518
self.build_tree(['tree/dir/', 'tree/dir/file'])
519
t.add('dir', 'dir/file')
521
out, err = self.run_bzr('push ../../pushloc', working_dir='tree/dir')
522
self.assertEqual('', out)
523
self.assertEqual('Created new branch.\n', err)
526
class RedirectingMemoryTransport(memory.MemoryTransport):
459
class RedirectingMemoryTransport(MemoryTransport):
528
461
def mkdir(self, relpath, mode=None):
462
from bzrlib.trace import mutter
463
mutter('cwd: %r, rel: %r, abs: %r' % (self._cwd, relpath, abspath))
529
464
if self._cwd == '/source/':
530
465
raise errors.RedirectRequested(self.abspath(relpath),
531
466
self.abspath('../target'),
607
536
% re.escape(destination_url)],
608
537
['push', '-d', 'tree', destination_url], retcode=3)
609
538
self.assertEqual('', out)
612
class TestPushStrictMixin(object):
614
def make_local_branch_and_tree(self):
615
self.tree = self.make_branch_and_tree('local')
616
self.build_tree_contents([('local/file', 'initial')])
617
self.tree.add('file')
618
self.tree.commit('adding file', rev_id='added')
619
self.build_tree_contents([('local/file', 'modified')])
620
self.tree.commit('modify file', rev_id='modified')
622
def set_config_push_strict(self, value):
623
# set config var (any of bazaar.conf, locations.conf, branch.conf
625
conf = self.tree.branch.get_config()
626
conf.set_user_option('push_strict', value)
628
_default_command = ['push', '../to']
629
_default_wd = 'local'
630
_default_errors = ['Working tree ".*/local/" has uncommitted '
631
'changes \(See bzr status\)\.',]
632
_default_pushed_revid = 'modified'
634
def assertPushFails(self, args):
635
self.run_bzr_error(self._default_errors, self._default_command + args,
636
working_dir=self._default_wd, retcode=3)
638
def assertPushSucceeds(self, args, pushed_revid=None):
639
self.run_bzr(self._default_command + args,
640
working_dir=self._default_wd)
641
if pushed_revid is None:
642
pushed_revid = self._default_pushed_revid
643
tree_to = workingtree.WorkingTree.open('to')
644
repo_to = tree_to.branch.repository
645
self.assertTrue(repo_to.has_revision(pushed_revid))
646
self.assertEqual(tree_to.branch.last_revision_info()[1], pushed_revid)
650
class TestPushStrictWithoutChanges(tests.TestCaseWithTransport,
651
TestPushStrictMixin):
654
super(TestPushStrictWithoutChanges, self).setUp()
655
self.make_local_branch_and_tree()
657
def test_push_default(self):
658
self.assertPushSucceeds([])
660
def test_push_strict(self):
661
self.assertPushSucceeds(['--strict'])
663
def test_push_no_strict(self):
664
self.assertPushSucceeds(['--no-strict'])
666
def test_push_config_var_strict(self):
667
self.set_config_push_strict('true')
668
self.assertPushSucceeds([])
670
def test_push_config_var_no_strict(self):
671
self.set_config_push_strict('false')
672
self.assertPushSucceeds([])
675
class TestPushStrictWithChanges(tests.TestCaseWithTransport,
676
TestPushStrictMixin):
678
_changes_type = None # Set by load_tests
681
super(TestPushStrictWithChanges, self).setUp()
682
getattr(self, self._changes_type)()
684
def _uncommitted_changes(self):
685
self.make_local_branch_and_tree()
686
# Make a change without committing it
687
self.build_tree_contents([('local/file', 'in progress')])
689
def _pending_merges(self):
690
self.make_local_branch_and_tree()
691
# Create 'other' branch containing a new file
692
other_bzrdir = self.tree.bzrdir.sprout('other')
693
other_tree = other_bzrdir.open_workingtree()
694
self.build_tree_contents([('other/other-file', 'other')])
695
other_tree.add('other-file')
696
other_tree.commit('other commit', rev_id='other')
697
# Merge and revert, leaving a pending merge
698
self.tree.merge_from_branch(other_tree.branch)
699
self.tree.revert(filenames=['other-file'], backups=False)
701
def _out_of_sync_trees(self):
702
self.make_local_branch_and_tree()
703
self.run_bzr(['checkout', '--lightweight', 'local', 'checkout'])
704
# Make a change and commit it
705
self.build_tree_contents([('local/file', 'modified in local')])
706
self.tree.commit('modify file', rev_id='modified-in-local')
707
# Exercise commands from the checkout directory
708
self._default_wd = 'checkout'
709
self._default_errors = ["Working tree is out of date, please run"
711
self._default_pushed_revid = 'modified-in-local'
713
def test_push_default(self):
714
self.assertPushFails([])
716
def test_push_with_revision(self):
717
self.assertPushSucceeds(['-r', 'revid:added'], pushed_revid='added')
719
def test_push_no_strict(self):
720
self.assertPushSucceeds(['--no-strict'])
722
def test_push_strict_with_changes(self):
723
self.assertPushFails(['--strict'])
725
def test_push_respect_config_var_strict(self):
726
self.set_config_push_strict('true')
727
self.assertPushFails([])
729
def test_push_bogus_config_var_ignored(self):
730
self.set_config_push_strict("I don't want you to be strict")
731
self.assertPushFails([])
733
def test_push_no_strict_command_line_override_config(self):
734
self.set_config_push_strict('yES')
735
self.assertPushFails([])
736
self.assertPushSucceeds(['--no-strict'])
738
def test_push_strict_command_line_override_config(self):
739
self.set_config_push_strict('oFF')
740
self.assertPushFails(['--strict'])
741
self.assertPushSucceeds([])