1
# Copyright (C) 2005, 2007, 2008 Canonical Ltd
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.
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.
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
18
"""Black-box tests for bzr push."""
33
from bzrlib.repofmt import knitrepo
34
from bzrlib.tests import http_server
35
from bzrlib.transport import memory
38
class TestPush(tests.TestCaseWithTransport):
40
def test_push_error_on_vfs_http(self):
41
""" pushing a branch to a HTTP server fails cleanly. """
42
# the trunk is published on a web server
43
self.transport_readonly_server = http_server.HttpServer
44
self.make_branch('source')
45
public_url = self.get_readonly_url('target')
46
self.run_bzr_error(['http does not support mkdir'],
50
def test_push_remember(self):
51
"""Push changes from one branch to another and test push location."""
52
transport = self.get_transport()
53
tree_a = self.make_branch_and_tree('branch_a')
54
branch_a = tree_a.branch
55
self.build_tree(['branch_a/a'])
57
tree_a.commit('commit a')
58
tree_b = branch_a.bzrdir.sprout('branch_b').open_workingtree()
59
branch_b = tree_b.branch
60
tree_c = branch_a.bzrdir.sprout('branch_c').open_workingtree()
61
branch_c = tree_c.branch
62
self.build_tree(['branch_a/b'])
64
tree_a.commit('commit b')
65
self.build_tree(['branch_b/c'])
67
tree_b.commit('commit c')
68
# initial push location must be empty
69
self.assertEqual(None, branch_b.get_push_location())
71
# test push for failure without push location set
72
out = self.run_bzr('push', working_dir='branch_a', retcode=3)
73
self.assertEquals(out,
74
('','bzr: ERROR: No push location known or specified.\n'))
76
# test not remembered if cannot actually push
77
self.run_bzr('push path/which/doesnt/exist',
78
working_dir='branch_a', retcode=3)
79
out = self.run_bzr('push', working_dir='branch_a', retcode=3)
81
('', 'bzr: ERROR: No push location known or specified.\n'),
84
# test implicit --remember when no push location set, push fails
85
out = self.run_bzr('push ../branch_b',
86
working_dir='branch_a', retcode=3)
87
self.assertEquals(out,
88
('','bzr: ERROR: These branches have diverged. '
89
'See "bzr help diverged-branches" for more information.\n'))
90
self.assertEquals(osutils.abspath(branch_a.get_push_location()),
91
osutils.abspath(branch_b.bzrdir.root_transport.base))
93
# test implicit --remember after resolving previous failure
94
uncommit.uncommit(branch=branch_b, tree=tree_b)
95
transport.delete('branch_b/c')
96
out, err = self.run_bzr('push', working_dir='branch_a')
97
path = branch_a.get_push_location()
98
self.assertEquals(out,
99
'Using saved push location: %s\n'
100
% urlutils.local_path_from_url(path))
101
self.assertEqual(err,
102
'All changes applied successfully.\n'
103
'Pushed up to revision 2.\n')
104
self.assertEqual(path,
105
branch_b.bzrdir.root_transport.base)
106
# test explicit --remember
107
self.run_bzr('push ../branch_c --remember', working_dir='branch_a')
108
self.assertEquals(branch_a.get_push_location(),
109
branch_c.bzrdir.root_transport.base)
111
def test_push_without_tree(self):
112
# bzr push from a branch that does not have a checkout should work.
113
b = self.make_branch('.')
114
out, err = self.run_bzr('push pushed-location')
115
self.assertEqual('', out)
116
self.assertEqual('Created new branch.\n', err)
117
b2 = branch.Branch.open('pushed-location')
118
self.assertEndsWith(b2.base, 'pushed-location/')
120
def test_push_new_branch_revision_count(self):
121
# bzr push of a branch with revisions to a new location
122
# should print the number of revisions equal to the length of the
124
t = self.make_branch_and_tree('tree')
125
self.build_tree(['tree/file'])
128
out, err = self.run_bzr('push -d tree pushed-to')
129
self.assertEqual('', out)
130
self.assertEqual('Created new branch.\n', err)
132
def test_push_only_pushes_history(self):
133
# Knit branches should only push the history for the current revision.
134
format = bzrdir.BzrDirMetaFormat1()
135
format.repository_format = knitrepo.RepositoryFormatKnit1()
136
shared_repo = self.make_repository('repo', format=format, shared=True)
137
shared_repo.set_make_working_trees(True)
139
def make_shared_tree(path):
140
shared_repo.bzrdir.root_transport.mkdir(path)
141
shared_repo.bzrdir.create_branch_convenience('repo/' + path)
142
return workingtree.WorkingTree.open('repo/' + path)
143
tree_a = make_shared_tree('a')
144
self.build_tree(['repo/a/file'])
146
tree_a.commit('commit a-1', rev_id='a-1')
147
f = open('repo/a/file', 'ab')
148
f.write('more stuff\n')
150
tree_a.commit('commit a-2', rev_id='a-2')
152
tree_b = make_shared_tree('b')
153
self.build_tree(['repo/b/file'])
155
tree_b.commit('commit b-1', rev_id='b-1')
157
self.assertTrue(shared_repo.has_revision('a-1'))
158
self.assertTrue(shared_repo.has_revision('a-2'))
159
self.assertTrue(shared_repo.has_revision('b-1'))
161
# Now that we have a repository with shared files, make sure
162
# that things aren't copied out by a 'push'
163
self.run_bzr('push ../../push-b', working_dir='repo/b')
164
pushed_tree = workingtree.WorkingTree.open('push-b')
165
pushed_repo = pushed_tree.branch.repository
166
self.assertFalse(pushed_repo.has_revision('a-1'))
167
self.assertFalse(pushed_repo.has_revision('a-2'))
168
self.assertTrue(pushed_repo.has_revision('b-1'))
170
def test_push_funky_id(self):
171
t = self.make_branch_and_tree('tree')
172
self.build_tree(['tree/filename'])
173
t.add('filename', 'funky-chars<>%&;"\'')
174
t.commit('commit filename')
175
self.run_bzr('push -d tree new-tree')
177
def test_push_dash_d(self):
178
t = self.make_branch_and_tree('from')
179
t.commit(allow_pointless=True,
180
message='first commit')
181
self.run_bzr('push -d from to-one')
182
self.failUnlessExists('to-one')
183
self.run_bzr('push -d %s %s'
184
% tuple(map(urlutils.local_path_to_url, ['from', 'to-two'])))
185
self.failUnlessExists('to-two')
187
def test_push_smart_non_stacked_streaming_acceptance(self):
188
self.setup_smart_server_with_call_log()
189
t = self.make_branch_and_tree('from')
190
t.commit(allow_pointless=True, message='first commit')
191
self.reset_smart_call_log()
192
self.run_bzr(['push', self.get_url('to-one')], working_dir='from')
193
# This figure represent the amount of work to perform this use case. It
194
# is entirely ok to reduce this number if a test fails due to rpc_count
195
# being too low. If rpc_count increases, more network roundtrips have
196
# become necessary for this use case. Please do not adjust this number
197
# upwards without agreement from bzr's network support maintainers.
198
self.assertLength(9, self.hpss_calls)
200
def test_push_smart_stacked_streaming_acceptance(self):
201
self.setup_smart_server_with_call_log()
202
parent = self.make_branch_and_tree('parent', format='1.9')
203
parent.commit(message='first commit')
204
local = parent.bzrdir.sprout('local').open_workingtree()
205
local.commit(message='local commit')
206
self.reset_smart_call_log()
207
self.run_bzr(['push', '--stacked', '--stacked-on', '../parent',
208
self.get_url('public')], working_dir='local')
209
# This figure represent the amount of work to perform this use case. It
210
# is entirely ok to reduce this number if a test fails due to rpc_count
211
# being too low. If rpc_count increases, more network roundtrips have
212
# become necessary for this use case. Please do not adjust this number
213
# upwards without agreement from bzr's network support maintainers.
214
self.assertLength(14, self.hpss_calls)
215
remote = branch.Branch.open('public')
216
self.assertEndsWith(remote.get_stacked_on_url(), '/parent')
218
def test_push_smart_with_default_stacking_url_path_segment(self):
219
# If the default stacked-on location is a path element then branches
220
# we push there over the smart server are stacked and their
221
# stacked_on_url is that exact path segment. Added to nail bug 385132.
222
self.setup_smart_server_with_call_log()
223
self.make_branch('stack-on', format='1.9')
224
self.make_bzrdir('.').get_config().set_default_stack_on(
226
self.make_branch('from', format='1.9')
227
out, err = self.run_bzr(['push', '-d', 'from', self.get_url('to')])
228
b = branch.Branch.open(self.get_url('to'))
229
self.assertEqual('/extra/stack-on', b.get_stacked_on_url())
231
def test_push_smart_with_default_stacking_relative_path(self):
232
# If the default stacked-on location is a relative path then branches
233
# we push there over the smart server are stacked and their
234
# stacked_on_url is a relative path. Added to nail bug 385132.
235
self.setup_smart_server_with_call_log()
236
self.make_branch('stack-on', format='1.9')
237
self.make_bzrdir('.').get_config().set_default_stack_on('stack-on')
238
self.make_branch('from', format='1.9')
239
out, err = self.run_bzr(['push', '-d', 'from', self.get_url('to')])
240
b = branch.Branch.open(self.get_url('to'))
241
self.assertEqual('../stack-on', b.get_stacked_on_url())
243
def create_simple_tree(self):
244
tree = self.make_branch_and_tree('tree')
245
self.build_tree(['tree/a'])
246
tree.add(['a'], ['a-id'])
247
tree.commit('one', rev_id='r1')
250
def test_push_create_prefix(self):
251
"""'bzr push --create-prefix' will create leading directories."""
252
tree = self.create_simple_tree()
254
self.run_bzr_error(['Parent directory of ../new/tree does not exist'],
257
self.run_bzr('push ../new/tree --create-prefix',
259
new_tree = workingtree.WorkingTree.open('new/tree')
260
self.assertEqual(tree.last_revision(), new_tree.last_revision())
261
self.failUnlessExists('new/tree/a')
263
def test_push_use_existing(self):
264
"""'bzr push --use-existing-dir' can push into an existing dir.
266
By default, 'bzr push' will not use an existing, non-versioned dir.
268
tree = self.create_simple_tree()
269
self.build_tree(['target/'])
271
self.run_bzr_error(['Target directory ../target already exists',
272
'Supply --use-existing-dir',
274
'push ../target', working_dir='tree')
276
self.run_bzr('push --use-existing-dir ../target',
279
new_tree = workingtree.WorkingTree.open('target')
280
self.assertEqual(tree.last_revision(), new_tree.last_revision())
281
# The push should have created target/a
282
self.failUnlessExists('target/a')
284
def test_push_onto_repo(self):
285
"""We should be able to 'bzr push' into an existing bzrdir."""
286
tree = self.create_simple_tree()
287
repo = self.make_repository('repo', shared=True)
289
self.run_bzr('push ../repo',
292
# Pushing onto an existing bzrdir will create a repository and
293
# branch as needed, but will only create a working tree if there was
295
self.assertRaises(errors.NoWorkingTree,
296
workingtree.WorkingTree.open, 'repo')
297
new_branch = branch.Branch.open('repo')
298
self.assertEqual(tree.last_revision(), new_branch.last_revision())
300
def test_push_onto_just_bzrdir(self):
301
"""We don't handle when the target is just a bzrdir.
303
Because you shouldn't be able to create *just* a bzrdir in the wild.
305
# TODO: jam 20070109 Maybe it would be better to create the repository
307
tree = self.create_simple_tree()
308
a_bzrdir = self.make_bzrdir('dir')
310
self.run_bzr_error(['At ../dir you have a valid .bzr control'],
314
def test_push_with_revisionspec(self):
315
"""We should be able to push a revision older than the tip."""
316
tree_from = self.make_branch_and_tree('from')
317
tree_from.commit("One.", rev_id="from-1")
318
tree_from.commit("Two.", rev_id="from-2")
320
self.run_bzr('push -r1 ../to', working_dir='from')
322
tree_to = workingtree.WorkingTree.open('to')
323
repo_to = tree_to.branch.repository
324
self.assertTrue(repo_to.has_revision('from-1'))
325
self.assertFalse(repo_to.has_revision('from-2'))
326
self.assertEqual(tree_to.branch.last_revision_info()[1], 'from-1')
329
['bzr: ERROR: bzr push --revision '
330
'takes exactly one revision identifier\n'],
331
'push -r0..2 ../to', working_dir='from')
333
def create_trunk_and_feature_branch(self):
335
trunk_tree = self.make_branch_and_tree('target',
337
trunk_tree.commit('mainline')
338
# and a branch from it
339
branch_tree = self.make_branch_and_tree('branch',
341
branch_tree.pull(trunk_tree.branch)
342
branch_tree.branch.set_parent(trunk_tree.branch.base)
343
# with some work on it
344
branch_tree.commit('moar work plz')
345
return trunk_tree, branch_tree
347
def assertPublished(self, branch_revid, stacked_on):
348
"""Assert that the branch 'published' has been published correctly."""
349
published_branch = branch.Branch.open('published')
350
# The published branch refers to the mainline
351
self.assertEqual(stacked_on, published_branch.get_stacked_on_url())
352
# and the branch's work was pushed
353
self.assertTrue(published_branch.repository.has_revision(branch_revid))
355
def test_push_new_branch_stacked_on(self):
356
"""Pushing a new branch with --stacked-on creates a stacked branch."""
357
trunk_tree, branch_tree = self.create_trunk_and_feature_branch()
358
# we publish branch_tree with a reference to the mainline.
359
out, err = self.run_bzr(['push', '--stacked-on', trunk_tree.branch.base,
360
self.get_url('published')], working_dir='branch')
361
self.assertEqual('', out)
362
self.assertEqual('Created new stacked branch referring to %s.\n' %
363
trunk_tree.branch.base, err)
364
self.assertPublished(branch_tree.last_revision(),
365
trunk_tree.branch.base)
367
def test_push_new_branch_stacked_uses_parent_when_no_public_url(self):
368
"""When the parent has no public url the parent is used as-is."""
369
trunk_tree, branch_tree = self.create_trunk_and_feature_branch()
370
# now we do a stacked push, which should determine the public location
372
out, err = self.run_bzr(['push', '--stacked',
373
self.get_url('published')], working_dir='branch')
374
self.assertEqual('', out)
375
self.assertEqual('Created new stacked branch referring to %s.\n' %
376
trunk_tree.branch.base, err)
377
self.assertPublished(branch_tree.last_revision(),
378
trunk_tree.branch.base)
380
def test_push_new_branch_stacked_uses_parent_public(self):
381
"""Pushing a new branch with --stacked creates a stacked branch."""
382
trunk_tree, branch_tree = self.create_trunk_and_feature_branch()
383
# the trunk is published on a web server
384
self.transport_readonly_server = http_server.HttpServer
385
trunk_public = self.make_branch('public_trunk', format='1.9')
386
trunk_public.pull(trunk_tree.branch)
387
trunk_public_url = self.get_readonly_url('public_trunk')
388
trunk_tree.branch.set_public_branch(trunk_public_url)
389
# now we do a stacked push, which should determine the public location
391
out, err = self.run_bzr(['push', '--stacked',
392
self.get_url('published')], working_dir='branch')
393
self.assertEqual('', out)
394
self.assertEqual('Created new stacked branch referring to %s.\n' %
395
trunk_public_url, err)
396
self.assertPublished(branch_tree.last_revision(), trunk_public_url)
398
def test_push_new_branch_stacked_no_parent(self):
399
"""Pushing with --stacked and no parent branch errors."""
400
branch = self.make_branch_and_tree('branch', format='1.9')
401
# now we do a stacked push, which should fail as the place to refer too
402
# cannot be determined.
403
out, err = self.run_bzr_error(
404
['Could not determine branch to refer to\\.'], ['push', '--stacked',
405
self.get_url('published')], working_dir='branch')
406
self.assertEqual('', out)
407
self.assertFalse(self.get_transport('published').has('.'))
409
def test_push_notifies_default_stacking(self):
410
self.make_branch('stack_on', format='1.6')
411
self.make_bzrdir('.').get_config().set_default_stack_on('stack_on')
412
self.make_branch('from', format='1.6')
413
out, err = self.run_bzr('push -d from to')
414
self.assertContainsRe(err,
415
'Using default stacking branch stack_on at .*')
417
def test_push_stacks_with_default_stacking_if_target_is_stackable(self):
418
self.make_branch('stack_on', format='1.6')
419
self.make_bzrdir('.').get_config().set_default_stack_on('stack_on')
420
self.make_branch('from', format='pack-0.92')
421
out, err = self.run_bzr('push -d from to')
422
b = branch.Branch.open('to')
423
self.assertEqual('../stack_on', b.get_stacked_on_url())
425
def test_push_does_not_change_format_with_default_if_target_cannot(self):
426
self.make_branch('stack_on', format='pack-0.92')
427
self.make_bzrdir('.').get_config().set_default_stack_on('stack_on')
428
self.make_branch('from', format='pack-0.92')
429
out, err = self.run_bzr('push -d from to')
430
b = branch.Branch.open('to')
431
self.assertRaises(errors.UnstackableBranchFormat, b.get_stacked_on_url)
433
def test_push_doesnt_create_broken_branch(self):
434
"""Pushing a new standalone branch works even when there's a default
435
stacking policy at the destination.
437
The new branch will preserve the repo format (even if it isn't the
438
default for the branch), and will be stacked when the repo format
439
allows (which means that the branch format isn't necessarly preserved).
441
self.make_repository('repo', shared=True, format='1.6')
442
builder = self.make_branch_builder('repo/local', format='pack-0.92')
443
builder.start_series()
444
builder.build_snapshot('rev-1', None, [
445
('add', ('', 'root-id', 'directory', '')),
446
('add', ('filename', 'f-id', 'file', 'content\n'))])
447
builder.build_snapshot('rev-2', ['rev-1'], [])
448
builder.build_snapshot('rev-3', ['rev-2'],
449
[('modify', ('f-id', 'new-content\n'))])
450
builder.finish_series()
451
branch = builder.get_branch()
452
# Push rev-1 to "trunk", so that we can stack on it.
453
self.run_bzr('push -d repo/local trunk -r 1')
454
# Set a default stacking policy so that new branches will automatically
456
self.make_bzrdir('.').get_config().set_default_stack_on('trunk')
457
# Push rev-2 to a new branch "remote". It will be stacked on "trunk".
458
out, err = self.run_bzr('push -d repo/local remote -r 2')
459
self.assertContainsRe(
460
err, 'Using default stacking branch trunk at .*')
461
# Push rev-3 onto "remote". If "remote" not stacked and is missing the
462
# fulltext record for f-id @ rev-1, then this will fail.
463
out, err = self.run_bzr('push -d repo/local remote -r 3')
465
def test_push_verbose_shows_log(self):
466
tree = self.make_branch_and_tree('source')
468
out, err = self.run_bzr('push -v -d source target')
469
# initial push contains log
470
self.assertContainsRe(out, 'rev1')
472
out, err = self.run_bzr('push -v -d source target')
473
# subsequent push contains log
474
self.assertContainsRe(out, 'rev2')
475
# subsequent log is accurate
476
self.assertNotContainsRe(out, 'rev1')
479
class RedirectingMemoryTransport(memory.MemoryTransport):
481
def mkdir(self, relpath, mode=None):
482
from bzrlib.trace import mutter
483
if self._cwd == '/source/':
484
raise errors.RedirectRequested(self.abspath(relpath),
485
self.abspath('../target'),
487
elif self._cwd == '/infinite-loop/':
488
raise errors.RedirectRequested(self.abspath(relpath),
489
self.abspath('../infinite-loop'),
492
return super(RedirectingMemoryTransport, self).mkdir(
495
def _redirected_to(self, source, target):
496
# We do accept redirections
497
return transport.get_transport(target)
500
class RedirectingMemoryServer(memory.MemoryServer):
503
self._dirs = {'/': None}
506
self._scheme = 'redirecting-memory+%s:///' % id(self)
507
transport.register_transport(self._scheme, self._memory_factory)
509
def _memory_factory(self, url):
510
result = RedirectingMemoryTransport(url)
511
result._dirs = self._dirs
512
result._files = self._files
513
result._locks = self._locks
517
transport.unregister_transport(self._scheme, self._memory_factory)
520
class TestPushRedirect(tests.TestCaseWithTransport):
523
tests.TestCaseWithTransport.setUp(self)
524
self.memory_server = RedirectingMemoryServer()
525
self.memory_server.setUp()
526
self.addCleanup(self.memory_server.tearDown)
528
# Make the branch and tree that we'll be pushing.
529
t = self.make_branch_and_tree('tree')
530
self.build_tree(['tree/file'])
534
def test_push_redirects_on_mkdir(self):
535
"""If the push requires a mkdir, push respects redirect requests.
537
This is added primarily to handle lp:/ URI support, so that users can
538
push to new branches by specifying lp:/ URIs.
540
destination_url = self.memory_server.get_url() + 'source'
541
self.run_bzr(['push', '-d', 'tree', destination_url])
543
local_revision = branch.Branch.open('tree').last_revision()
544
remote_revision = branch.Branch.open(
545
self.memory_server.get_url() + 'target').last_revision()
546
self.assertEqual(remote_revision, local_revision)
548
def test_push_gracefully_handles_too_many_redirects(self):
549
"""Push fails gracefully if the mkdir generates a large number of
552
destination_url = self.memory_server.get_url() + 'infinite-loop'
553
out, err = self.run_bzr_error(
554
['Too many redirections trying to make %s\\.\n'
555
% re.escape(destination_url)],
556
['push', '-d', 'tree', destination_url], retcode=3)
557
self.assertEqual('', out)
560
class TestPushStrict(tests.TestCaseWithTransport):
562
def make_local_branch_and_tree(self):
563
tree = self.make_branch_and_tree('local')
564
self.build_tree_contents([('local/file', 'initial')])
566
tree.commit('adding file', rev_id='from-1')
569
def make_local_branch_and_tree_with_changes(self):
570
tree = self.make_local_branch_and_tree()
572
self.build_tree_contents([('local/file', 'modified')])
575
def set_config_push_strict(self, tree, value):
576
# set config var (any of bazaar.conf, locations.conf, branch.conf
578
conf = tree.branch.get_config()
579
conf.set_user_option('push_strict', value)
581
def assertPushFails(self, location, *args):
582
self.run_bzr_error(['Working tree ".*/local/"'
583
' has uncommitted changes.$',],
584
['push', '../' + location] + list(args),
585
working_dir='local', retcode=3)
587
def assertPushSucceeds(self, location, *args):
588
self.run_bzr(['push', '../' + location] + list(args),
590
tree_to = workingtree.WorkingTree.open(location)
591
repo_to = tree_to.branch.repository
592
self.assertTrue(repo_to.has_revision('from-1'))
593
self.assertEqual(tree_to.branch.last_revision_info()[1], 'from-1')
595
def test_push_default(self):
596
tree = self.make_local_branch_and_tree_with_changes()
597
self.assertPushSucceeds('to')
599
def test_push_no_strict_with_changes(self):
600
tree = self.make_local_branch_and_tree_with_changes()
601
self.assertPushSucceeds('to', '--no-strict')
603
def test_push_strict_with_changes(self):
604
tree = self.make_local_branch_and_tree_with_changes()
605
self.assertPushFails('to', '--strict')
607
def test_push_strict_without_changes(self):
608
tree = self.make_local_branch_and_tree()
609
self.assertPushSucceeds('to', '--strict')
611
def test_push_respect_config_var_strict(self):
612
tree = self.make_local_branch_and_tree_with_changes()
613
self.set_config_push_strict(tree, 'true')
614
self.assertPushFails('to')
616
def test_push_bogus_config_var_ignored(self):
617
tree = self.make_local_branch_and_tree_with_changes()
618
self.set_config_push_strict(tree, "I don't want you to be strict")
619
self.assertPushSucceeds('to')
621
def test_push_no_strict_command_line_override_config(self):
622
tree = self.make_local_branch_and_tree_with_changes()
623
self.set_config_push_strict(tree, 'yES')
624
self.assertPushFails('to')
625
self.assertPushSucceeds('to', '--no-strict')
627
def test_push_strict_command_line_override_config(self):
628
tree = self.make_local_branch_and_tree_with_changes()
629
self.set_config_push_strict(tree, 'oFF')
630
self.assertPushFails('to', '--strict')
631
self.assertPushSucceeds('to')