~bzr-pqm/bzr/bzr.dev

« back to all changes in this revision

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

  • Committer: Vincent Ladeuil
  • Date: 2009-04-06 14:01:16 UTC
  • mto: (4241.10.1 bzr.1.14)
  • mto: This revision was merged to the branch mainline in revision 4267.
  • Revision ID: v.ladeuil+lp@free.fr-20090406140116-zkbvjtaxfhbql4l4
Fix unicode related OSX failures.

* bzrlib/tests/test_export.py: 
Fix imports.

* bzrlib/tests/blackbox/test_export.py:
(TestExport.test_tar_export_unicode,
TestExport.test_zip_export_unicode): Use a less problematic
unicode char for OSX.

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
# Copyright (C) 2006-2010 Canonical Ltd
 
1
# Copyright (C) 2005, 2007, 2008 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
17
17
 
18
18
"""Black-box tests for bzr push."""
19
19
 
 
20
import os
20
21
import re
21
22
 
22
23
from bzrlib import (
23
 
    branch,
24
 
    bzrdir,
25
24
    errors,
26
 
    osutils,
27
 
    tests,
28
25
    transport,
29
 
    uncommit,
30
26
    urlutils,
31
 
    workingtree
32
 
    )
33
 
from bzrlib.repofmt import knitrepo
34
 
from bzrlib.tests import (
35
 
    blackbox,
36
 
    http_server,
37
 
    test_foreign,
38
 
    test_server,
39
 
    )
40
 
from bzrlib.transport import memory
41
 
 
42
 
 
43
 
def load_tests(standard_tests, module, loader):
44
 
    """Multiply tests for the push command."""
45
 
    result = loader.suiteClass()
46
 
 
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,
51
 
                )))
52
 
    changes_scenarios = [
53
 
        ('uncommitted',
54
 
         dict(_changes_type= '_uncommitted_changes')),
55
 
        ('pending-merges',
56
 
         dict(_changes_type= '_pending_merges')),
57
 
        ('out-of-sync-trees',
58
 
         dict(_changes_type= '_out_of_sync_trees')),
59
 
        ]
60
 
    tests.multiply_tests(changes_tests, changes_scenarios, result)
61
 
    # No parametrization for the remaining tests
62
 
    result.addTests(remaining_tests)
63
 
 
64
 
    return result
65
 
 
66
 
 
67
 
class TestPush(tests.TestCaseWithTransport):
 
27
    )
 
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):
68
42
 
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())
99
73
 
100
74
        # test push for failure without push location set
101
 
        out = self.run_bzr('push', working_dir='branch_a', retcode=3)
 
75
        os.chdir('branch_a')
 
76
        out = self.run_bzr('push', retcode=3)
102
77
        self.assertEquals(out,
103
78
                ('','bzr: ERROR: No push location known or specified.\n'))
104
79
 
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'),
111
85
                out)
112
86
 
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))
121
94
 
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)
139
112
 
143
116
        out, err = self.run_bzr('push pushed-location')
144
117
        self.assertEqual('', out)
145
118
        self.assertEqual('Created new branch.\n', err)
146
 
        b2 = branch.Branch.open('pushed-location')
 
119
        b2 = Branch.open('pushed-location')
147
120
        self.assertEndsWith(b2.base, 'pushed-location/')
148
121
 
149
122
    def test_push_new_branch_revision_count(self):
154
127
        self.build_tree(['tree/file'])
155
128
        t.add('file')
156
129
        t.commit('commit 1')
157
 
        out, err = self.run_bzr('push -d tree pushed-to')
 
130
        os.chdir('tree')
 
131
        out, err = self.run_bzr('push pushed-to')
 
132
        os.chdir('..')
158
133
        self.assertEqual('', out)
159
134
        self.assertEqual('Created new branch.\n', err)
160
135
 
161
136
    def test_push_only_pushes_history(self):
162
137
        # Knit branches should only push the history for the current revision.
163
 
        format = bzrdir.BzrDirMetaFormat1()
164
 
        format.repository_format = knitrepo.RepositoryFormatKnit1()
 
138
        format = BzrDirMetaFormat1()
 
139
        format.repository_format = RepositoryFormatKnit1()
165
140
        shared_repo = self.make_repository('repo', format=format, shared=True)
166
141
        shared_repo.set_make_working_trees(True)
167
142
 
168
143
        def make_shared_tree(path):
169
144
            shared_repo.bzrdir.root_transport.mkdir(path)
170
145
            shared_repo.bzrdir.create_branch_convenience('repo/' + path)
171
 
            return workingtree.WorkingTree.open('repo/' + path)
 
146
            return WorkingTree.open('repo/' + path)
172
147
        tree_a = make_shared_tree('a')
173
148
        self.build_tree(['repo/a/file'])
174
149
        tree_a.add('file')
189
164
 
190
165
        # Now that we have a repository with shared files, make sure
191
166
        # that things aren't copied out by a 'push'
192
 
        self.run_bzr('push ../../push-b', working_dir='repo/b')
193
 
        pushed_tree = workingtree.WorkingTree.open('push-b')
 
167
        os.chdir('repo/b')
 
168
        self.run_bzr('push ../../push-b')
 
169
        pushed_tree = WorkingTree.open('../../push-b')
194
170
        pushed_repo = pushed_tree.branch.repository
195
171
        self.assertFalse(pushed_repo.has_revision('a-1'))
196
172
        self.assertFalse(pushed_repo.has_revision('a-2'))
198
174
 
199
175
    def test_push_funky_id(self):
200
176
        t = self.make_branch_and_tree('tree')
201
 
        self.build_tree(['tree/filename'])
 
177
        os.chdir('tree')
 
178
        self.build_tree(['filename'])
202
179
        t.add('filename', 'funky-chars<>%&;"\'')
203
180
        t.commit('commit filename')
204
 
        self.run_bzr('push -d tree new-tree')
 
181
        self.run_bzr('push ../new-tree')
205
182
 
206
183
    def test_push_dash_d(self):
207
184
        t = self.make_branch_and_tree('from')
224
201
        # being too low. If rpc_count increases, more network roundtrips have
225
202
        # become necessary for this use case. Please do not adjust this number
226
203
        # upwards without agreement from bzr's network support maintainers.
227
 
        self.assertLength(9, self.hpss_calls)
 
204
        self.assertLength(20, self.hpss_calls)
228
205
 
229
206
    def test_push_smart_stacked_streaming_acceptance(self):
230
207
        self.setup_smart_server_with_call_log()
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')
246
223
 
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)
260
 
 
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')
266
 
        self.run_bzr(
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)
276
 
 
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(
284
 
            '/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())
289
 
 
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())
301
 
 
302
224
    def create_simple_tree(self):
303
225
        tree = self.make_branch_and_tree('tree')
304
226
        self.build_tree(['tree/a'])
315
237
                           working_dir='tree')
316
238
        self.run_bzr('push ../new/tree --create-prefix',
317
239
                     working_dir='tree')
318
 
        new_tree = workingtree.WorkingTree.open('new/tree')
 
240
        new_tree = WorkingTree.open('new/tree')
319
241
        self.assertEqual(tree.last_revision(), new_tree.last_revision())
320
242
        self.failUnlessExists('new/tree/a')
321
243
 
335
257
        self.run_bzr('push --use-existing-dir ../target',
336
258
                     working_dir='tree')
337
259
 
338
 
        new_tree = workingtree.WorkingTree.open('target')
 
260
        new_tree = WorkingTree.open('target')
339
261
        self.assertEqual(tree.last_revision(), new_tree.last_revision())
340
262
        # The push should have created target/a
341
263
        self.failUnlessExists('target/a')
342
264
 
343
 
    def test_push_use_existing_into_empty_bzrdir(self):
344
 
        """'bzr push --use-existing-dir' into a dir with an empty .bzr dir
345
 
        fails.
346
 
        """
347
 
        tree = self.create_simple_tree()
348
 
        self.build_tree(['target/', 'target/.bzr/'])
349
 
        self.run_bzr_error(
350
 
            ['Target directory ../target already contains a .bzr directory, '
351
 
             'but it is not valid.'],
352
 
            'push ../target --use-existing-dir', working_dir='tree')
353
 
 
354
265
    def test_push_onto_repo(self):
355
266
        """We should be able to 'bzr push' into an existing bzrdir."""
356
267
        tree = self.create_simple_tree()
362
273
        # Pushing onto an existing bzrdir will create a repository and
363
274
        # branch as needed, but will only create a working tree if there was
364
275
        # no BzrDir before.
365
 
        self.assertRaises(errors.NoWorkingTree,
366
 
                          workingtree.WorkingTree.open, 'repo')
367
 
        new_branch = branch.Branch.open('repo')
 
276
        self.assertRaises(errors.NoWorkingTree, WorkingTree.open, 'repo')
 
277
        new_branch = Branch.open('repo')
368
278
        self.assertEqual(tree.last_revision(), new_branch.last_revision())
369
279
 
370
280
    def test_push_onto_just_bzrdir(self):
389
299
 
390
300
        self.run_bzr('push -r1 ../to', working_dir='from')
391
301
 
392
 
        tree_to = workingtree.WorkingTree.open('to')
 
302
        tree_to = WorkingTree.open('to')
393
303
        repo_to = tree_to.branch.repository
394
304
        self.assertTrue(repo_to.has_revision('from-1'))
395
305
        self.assertFalse(repo_to.has_revision('from-2'))
396
306
        self.assertEqual(tree_to.branch.last_revision_info()[1], 'from-1')
397
307
 
398
308
        self.run_bzr_error(
399
 
            ['bzr: ERROR: bzr push --revision '
400
 
             'takes exactly one revision identifier\n'],
 
309
            "bzr: ERROR: bzr push --revision takes one value.\n",
401
310
            'push -r0..2 ../to', working_dir='from')
402
311
 
403
312
    def create_trunk_and_feature_branch(self):
404
313
        # We have a mainline
405
314
        trunk_tree = self.make_branch_and_tree('target',
406
 
            format='1.9')
 
315
            format='development')
407
316
        trunk_tree.commit('mainline')
408
317
        # and a branch from it
409
318
        branch_tree = self.make_branch_and_tree('branch',
410
 
            format='1.9')
 
319
            format='development')
411
320
        branch_tree.pull(trunk_tree.branch)
412
321
        branch_tree.branch.set_parent(trunk_tree.branch.base)
413
322
        # with some work on it
416
325
 
417
326
    def assertPublished(self, branch_revid, stacked_on):
418
327
        """Assert that the branch 'published' has been published correctly."""
419
 
        published_branch = branch.Branch.open('published')
 
328
        published_branch = Branch.open('published')
420
329
        # The published branch refers to the mainline
421
330
        self.assertEqual(stacked_on, published_branch.get_stacked_on_url())
422
331
        # and the branch's work was pushed
444
353
        self.assertEqual('', out)
445
354
        self.assertEqual('Created new stacked branch referring to %s.\n' %
446
355
            trunk_tree.branch.base, err)
447
 
        self.assertPublished(branch_tree.last_revision(),
448
 
                             trunk_tree.branch.base)
 
356
        self.assertPublished(branch_tree.last_revision(), trunk_tree.branch.base)
449
357
 
450
358
    def test_push_new_branch_stacked_uses_parent_public(self):
451
359
        """Pushing a new branch with --stacked creates a stacked branch."""
452
360
        trunk_tree, branch_tree = self.create_trunk_and_feature_branch()
453
361
        # the trunk is published on a web server
454
 
        self.transport_readonly_server = http_server.HttpServer
455
 
        trunk_public = self.make_branch('public_trunk', format='1.9')
 
362
        self.transport_readonly_server = HttpServer
 
363
        trunk_public = self.make_branch('public_trunk', format='development')
456
364
        trunk_public.pull(trunk_tree.branch)
457
365
        trunk_public_url = self.get_readonly_url('public_trunk')
458
366
        trunk_tree.branch.set_public_branch(trunk_public_url)
467
375
 
468
376
    def test_push_new_branch_stacked_no_parent(self):
469
377
        """Pushing with --stacked and no parent branch errors."""
470
 
        branch = self.make_branch_and_tree('branch', format='1.9')
 
378
        branch = self.make_branch_and_tree('branch', format='development')
471
379
        # now we do a stacked push, which should fail as the place to refer too
472
380
        # cannot be determined.
473
381
        out, err = self.run_bzr_error(
489
397
        self.make_bzrdir('.').get_config().set_default_stack_on('stack_on')
490
398
        self.make_branch('from', format='pack-0.92')
491
399
        out, err = self.run_bzr('push -d from to')
492
 
        b = branch.Branch.open('to')
493
 
        self.assertEqual('../stack_on', b.get_stacked_on_url())
 
400
        branch = Branch.open('to')
 
401
        self.assertEqual('../stack_on', branch.get_stacked_on_url())
494
402
 
495
403
    def test_push_does_not_change_format_with_default_if_target_cannot(self):
496
404
        self.make_branch('stack_on', format='pack-0.92')
497
405
        self.make_bzrdir('.').get_config().set_default_stack_on('stack_on')
498
406
        self.make_branch('from', format='pack-0.92')
499
407
        out, err = self.run_bzr('push -d from to')
500
 
        b = branch.Branch.open('to')
501
 
        self.assertRaises(errors.UnstackableBranchFormat, b.get_stacked_on_url)
 
408
        branch = Branch.open('to')
 
409
        self.assertRaises(errors.UnstackableBranchFormat,
 
410
            branch.get_stacked_on_url)
502
411
 
503
412
    def test_push_doesnt_create_broken_branch(self):
504
413
        """Pushing a new standalone branch works even when there's a default
545
454
        # subsequent log is accurate
546
455
        self.assertNotContainsRe(out, 'rev1')
547
456
 
548
 
    def test_push_from_subdir(self):
549
 
        t = self.make_branch_and_tree('tree')
550
 
        self.build_tree(['tree/dir/', 'tree/dir/file'])
551
 
        t.add('dir', 'dir/file')
552
 
        t.commit('r1')
553
 
        out, err = self.run_bzr('push ../../pushloc', working_dir='tree/dir')
554
 
        self.assertEqual('', out)
555
 
        self.assertEqual('Created new branch.\n', err)
556
 
 
557
 
 
558
 
class RedirectingMemoryTransport(memory.MemoryTransport):
 
457
 
 
458
class RedirectingMemoryTransport(MemoryTransport):
559
459
 
560
460
    def mkdir(self, relpath, mode=None):
 
461
        from bzrlib.trace import mutter
 
462
        mutter('cwd: %r, rel: %r, abs: %r' % (self._cwd, relpath, abspath))
561
463
        if self._cwd == '/source/':
562
464
            raise errors.RedirectRequested(self.abspath(relpath),
563
465
                                           self.abspath('../target'),
570
472
            return super(RedirectingMemoryTransport, self).mkdir(
571
473
                relpath, mode)
572
474
 
573
 
    def get(self, relpath):
574
 
        if self.clone(relpath)._cwd == '/infinite-loop/':
575
 
            raise errors.RedirectRequested(self.abspath(relpath),
576
 
                                           self.abspath('../infinite-loop'),
577
 
                                           is_permanent=True)
578
 
        else:
579
 
            return super(RedirectingMemoryTransport, self).get(relpath)
580
 
 
581
475
    def _redirected_to(self, source, target):
582
476
        # We do accept redirections
583
477
        return transport.get_transport(target)
584
478
 
585
479
 
586
 
class RedirectingMemoryServer(memory.MemoryServer):
 
480
class RedirectingMemoryServer(MemoryServer):
587
481
 
588
 
    def start_server(self):
 
482
    def setUp(self):
589
483
        self._dirs = {'/': None}
590
484
        self._files = {}
591
485
        self._locks = {}
599
493
        result._locks = self._locks
600
494
        return result
601
495
 
602
 
    def stop_server(self):
 
496
    def tearDown(self):
603
497
        transport.unregister_transport(self._scheme, self._memory_factory)
604
498
 
605
499
 
606
 
class TestPushRedirect(tests.TestCaseWithTransport):
 
500
class TestPushRedirect(ExternalBase):
607
501
 
608
502
    def setUp(self):
609
 
        tests.TestCaseWithTransport.setUp(self)
 
503
        ExternalBase.setUp(self)
610
504
        self.memory_server = RedirectingMemoryServer()
611
 
        self.start_server(self.memory_server)
 
505
        self.memory_server.setUp()
 
506
        self.addCleanup(self.memory_server.tearDown)
 
507
 
612
508
        # Make the branch and tree that we'll be pushing.
613
509
        t = self.make_branch_and_tree('tree')
614
510
        self.build_tree(['tree/file'])
624
520
        destination_url = self.memory_server.get_url() + 'source'
625
521
        self.run_bzr(['push', '-d', 'tree', destination_url])
626
522
 
627
 
        local_revision = branch.Branch.open('tree').last_revision()
628
 
        remote_revision = branch.Branch.open(
 
523
        local_revision = Branch.open('tree').last_revision()
 
524
        remote_revision = Branch.open(
629
525
            self.memory_server.get_url() + 'target').last_revision()
630
526
        self.assertEqual(remote_revision, local_revision)
631
527
 
639
535
             % re.escape(destination_url)],
640
536
            ['push', '-d', 'tree', destination_url], retcode=3)
641
537
        self.assertEqual('', out)
642
 
 
643
 
 
644
 
class TestPushStrictMixin(object):
645
 
 
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')
653
 
 
654
 
    def set_config_push_strict(self, value):
655
 
        # set config var (any of bazaar.conf, locations.conf, branch.conf
656
 
        # should do)
657
 
        conf = self.tree.branch.get_config()
658
 
        conf.set_user_option('push_strict', value)
659
 
 
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.'
666
 
 
667
 
 
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)
673
 
 
674
 
    def assertPushSucceeds(self, args, with_warning=False, revid_to_push=None):
675
 
        if with_warning:
676
 
            error_regexes = self._default_errors
677
 
        else:
678
 
            error_regexes = []
679
 
        out, err = self.run_bzr(self._default_command + args,
680
 
                                working_dir=self._default_wd,
681
 
                                error_regexes=error_regexes)
682
 
        if with_warning:
683
 
            self.assertContainsRe(err, self._default_additional_warning)
684
 
        else:
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())
693
 
 
694
 
 
695
 
 
696
 
class TestPushStrictWithoutChanges(tests.TestCaseWithTransport,
697
 
                                   TestPushStrictMixin):
698
 
 
699
 
    def setUp(self):
700
 
        super(TestPushStrictWithoutChanges, self).setUp()
701
 
        self.make_local_branch_and_tree()
702
 
 
703
 
    def test_push_default(self):
704
 
        self.assertPushSucceeds([])
705
 
 
706
 
    def test_push_strict(self):
707
 
        self.assertPushSucceeds(['--strict'])
708
 
 
709
 
    def test_push_no_strict(self):
710
 
        self.assertPushSucceeds(['--no-strict'])
711
 
 
712
 
    def test_push_config_var_strict(self):
713
 
        self.set_config_push_strict('true')
714
 
        self.assertPushSucceeds([])
715
 
 
716
 
    def test_push_config_var_no_strict(self):
717
 
        self.set_config_push_strict('false')
718
 
        self.assertPushSucceeds([])
719
 
 
720
 
 
721
 
class TestPushStrictWithChanges(tests.TestCaseWithTransport,
722
 
                                TestPushStrictMixin):
723
 
 
724
 
    _changes_type = None # Set by load_tests
725
 
 
726
 
    def setUp(self):
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)()
731
 
 
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')])
736
 
 
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)
748
 
 
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"
758
 
                                " 'bzr update'\.",]
759
 
 
760
 
    def test_push_default(self):
761
 
        self.assertPushSucceeds([], with_warning=True)
762
 
 
763
 
    def test_push_with_revision(self):
764
 
        self.assertPushSucceeds(['-r', 'revid:added'], revid_to_push='added')
765
 
 
766
 
    def test_push_no_strict(self):
767
 
        self.assertPushSucceeds(['--no-strict'])
768
 
 
769
 
    def test_push_strict_with_changes(self):
770
 
        self.assertPushFails(['--strict'])
771
 
 
772
 
    def test_push_respect_config_var_strict(self):
773
 
        self.set_config_push_strict('true')
774
 
        self.assertPushFails([])
775
 
 
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)
779
 
 
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'])
784
 
 
785
 
    def test_push_strict_command_line_override_config(self):
786
 
        self.set_config_push_strict('oFF')
787
 
        self.assertPushFails(['--strict'])
788
 
        self.assertPushSucceeds([])
789
 
 
790
 
 
791
 
class TestPushForeign(tests.TestCaseWithTransport):
792
 
 
793
 
    def setUp(self):
794
 
        super(TestPushForeign, self).setUp()
795
 
        test_foreign.register_dummy_foreign_for_test(self)
796
 
 
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'))])
803
 
        return builder
804
 
 
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")