~bzr-pqm/bzr/bzr.dev

« back to all changes in this revision

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

  • Committer: John Arbash Meinel
  • Date: 2009-07-06 18:59:24 UTC
  • mto: This revision was merged to the branch mainline in revision 4522.
  • Revision ID: john@arbash-meinel.com-20090706185924-qlhn1j607117lgdj
Start implementing an Annotator.add_special_text functionality.

The Python implementation supports it. Basically, it is meant to allow things
like WT and PreviewTree to insert the 'current' content into the graph, so that
we can get local modifications into the annotations.
There is also some work here to get support for texts that are already cached
in the annotator. So that we avoid extracting them, and can shortcut the
history.

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
# Copyright (C) 2006, 2007, 2008, 2009 Canonical Ltd
 
2
# Authors: Aaron Bentley
 
3
#
 
4
# This program is free software; you can redistribute it and/or modify
 
5
# it under the terms of the GNU General Public License as published by
 
6
# the Free Software Foundation; either version 2 of the License, or
 
7
# (at your option) any later version.
 
8
#
 
9
# This program is distributed in the hope that it will be useful,
 
10
# but WITHOUT ANY WARRANTY; without even the implied warranty of
 
11
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 
12
# GNU General Public License for more details.
 
13
#
 
14
# You should have received a copy of the GNU General Public License
 
15
# along with this program; if not, write to the Free Software
 
16
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
 
17
 
 
18
 
 
19
import sys
 
20
from cStringIO import StringIO
 
21
 
 
22
from bzrlib import (
 
23
    branch,
 
24
    bzrdir,
 
25
    merge_directive,
 
26
    tests,
 
27
    )
 
28
from bzrlib.bundle import serializer
 
29
 
 
30
 
 
31
def load_tests(standard_tests, module, loader):
 
32
    """Multiply tests for the send command."""
 
33
    result = loader.suiteClass()
 
34
 
 
35
    # one for each king of change
 
36
    changes_tests, remaining_tests = tests.split_suite_by_condition(
 
37
        standard_tests, tests.condition_isinstance((
 
38
                TestSendStrictWithChanges,
 
39
                )))
 
40
    changes_scenarios = [
 
41
        ('uncommitted',
 
42
         dict(_changes_type='_uncommitted_changes')),
 
43
        ('pending_merges',
 
44
         dict(_changes_type='_pending_merges')),
 
45
        ('out-of-sync-trees',
 
46
         dict(_changes_type='_out_of_sync_trees')),
 
47
        ]
 
48
    tests.multiply_tests(changes_tests, changes_scenarios, result)
 
49
    # No parametrization for the remaining tests
 
50
    result.addTests(remaining_tests)
 
51
 
 
52
    return result
 
53
 
 
54
 
 
55
class TestSendMixin(object):
 
56
 
 
57
    _default_command = ['send', '-o-']
 
58
    _default_wd = 'branch'
 
59
 
 
60
    def run_send(self, args, cmd=None, rc=0, wd=None, err_re=None):
 
61
        if cmd is None: cmd = self._default_command
 
62
        if wd is None: wd = self._default_wd
 
63
        if err_re is None: err_re = []
 
64
        return self.run_bzr(cmd + args, retcode=rc,
 
65
                            working_dir=wd,
 
66
                            error_regexes=err_re)
 
67
 
 
68
    def get_MD(self, args, cmd=None, wd='branch'):
 
69
        out = StringIO(self.run_send(args, cmd=cmd, wd=wd)[0])
 
70
        return merge_directive.MergeDirective.from_lines(out.readlines())
 
71
 
 
72
    def assertBundleContains(self, revs, args, cmd=None, wd='branch'):
 
73
        md = self.get_MD(args, cmd=cmd, wd=wd)
 
74
        br = serializer.read_bundle(StringIO(md.get_raw_bundle()))
 
75
        self.assertEqual(set(revs), set(r.revision_id for r in br.revisions))
 
76
 
 
77
 
 
78
class TestSend(tests.TestCaseWithTransport, TestSendMixin):
 
79
 
 
80
    def setUp(self):
 
81
        super(TestSend, self).setUp()
 
82
        grandparent_tree = bzrdir.BzrDir.create_standalone_workingtree(
 
83
            'grandparent')
 
84
        self.build_tree_contents([('grandparent/file1', 'grandparent')])
 
85
        grandparent_tree.add('file1')
 
86
        grandparent_tree.commit('initial commit', rev_id='rev1')
 
87
 
 
88
        parent_bzrdir = grandparent_tree.bzrdir.sprout('parent')
 
89
        parent_tree = parent_bzrdir.open_workingtree()
 
90
        parent_tree.commit('next commit', rev_id='rev2')
 
91
 
 
92
        branch_tree = parent_tree.bzrdir.sprout('branch').open_workingtree()
 
93
        self.build_tree_contents([('branch/file1', 'branch')])
 
94
        branch_tree.commit('last commit', rev_id='rev3')
 
95
 
 
96
    def assertFormatIs(self, fmt_string, md):
 
97
        self.assertEqual(fmt_string, md.get_raw_bundle().splitlines()[0])
 
98
 
 
99
    def test_uses_parent(self):
 
100
        """Parent location is used as a basis by default"""
 
101
        errmsg = self.run_send([], rc=3, wd='grandparent')[1]
 
102
        self.assertContainsRe(errmsg, 'No submit branch known or specified')
 
103
        stdout, stderr = self.run_send([])
 
104
        self.assertEqual(stderr.count('Using saved parent location'), 1)
 
105
        self.assertBundleContains(['rev3'], [])
 
106
 
 
107
    def test_bundle(self):
 
108
        """Bundle works like send, except -o is not required"""
 
109
        errmsg = self.run_send([], cmd=['bundle'], rc=3, wd='grandparent')[1]
 
110
        self.assertContainsRe(errmsg, 'No submit branch known or specified')
 
111
        stdout, stderr = self.run_send([], cmd=['bundle'])
 
112
        self.assertEqual(stderr.count('Using saved parent location'), 1)
 
113
        self.assertBundleContains(['rev3'], [], cmd=['bundle'])
 
114
 
 
115
    def test_uses_submit(self):
 
116
        """Submit location can be used and set"""
 
117
        self.assertBundleContains(['rev3'], [])
 
118
        self.assertBundleContains(['rev3', 'rev2'], ['../grandparent'])
 
119
        # submit location should be auto-remembered
 
120
        self.assertBundleContains(['rev3', 'rev2'], [])
 
121
 
 
122
        self.run_send(['../parent'])
 
123
        # We still point to ../grandparent
 
124
        self.assertBundleContains(['rev3', 'rev2'], [])
 
125
        # Remember parent now
 
126
        self.run_send(['../parent', '--remember'])
 
127
        # Now we point to parent
 
128
        self.assertBundleContains(['rev3'], [])
 
129
 
 
130
        err = self.run_send(['--remember'], rc=3)[1]
 
131
        self.assertContainsRe(err,
 
132
                              '--remember requires a branch to be specified.')
 
133
 
 
134
    def test_revision_branch_interaction(self):
 
135
        self.assertBundleContains(['rev3', 'rev2'], ['../grandparent'])
 
136
        self.assertBundleContains(['rev2'], ['../grandparent', '-r-2'])
 
137
        self.assertBundleContains(['rev3', 'rev2'],
 
138
                                  ['../grandparent', '-r-2..-1'])
 
139
        md = self.get_MD(['-r-2..-1'])
 
140
        self.assertEqual('rev2', md.base_revision_id)
 
141
        self.assertEqual('rev3', md.revision_id)
 
142
 
 
143
    def test_output(self):
 
144
        # check output for consistency
 
145
        # win32 stdout converts LF to CRLF,
 
146
        # which would break patch-based bundles
 
147
        self.assertBundleContains(['rev3'], [])
 
148
 
 
149
    def test_no_common_ancestor(self):
 
150
        foo = self.make_branch_and_tree('foo')
 
151
        foo.commit('rev a')
 
152
        bar = self.make_branch_and_tree('bar')
 
153
        bar.commit('rev b')
 
154
        self.run_send(['--from', 'foo', '../bar'], wd='foo')
 
155
 
 
156
    def test_content_options(self):
 
157
        """--no-patch and --no-bundle should work and be independant"""
 
158
        md = self.get_MD([])
 
159
        self.assertIsNot(None, md.bundle)
 
160
        self.assertIsNot(None, md.patch)
 
161
 
 
162
        md = self.get_MD(['--format=0.9'])
 
163
        self.assertIsNot(None, md.bundle)
 
164
        self.assertIsNot(None, md.patch)
 
165
 
 
166
        md = self.get_MD(['--no-patch'])
 
167
        self.assertIsNot(None, md.bundle)
 
168
        self.assertIs(None, md.patch)
 
169
        self.run_bzr_error(['Format 0.9 does not permit bundle with no patch'],
 
170
                           ['send', '--no-patch', '--format=0.9', '-o-'],
 
171
                           working_dir='branch')
 
172
        md = self.get_MD(['--no-bundle', '.', '.'])
 
173
        self.assertIs(None, md.bundle)
 
174
        self.assertIsNot(None, md.patch)
 
175
 
 
176
        md = self.get_MD(['--no-bundle', '--format=0.9', '../parent',
 
177
                                  '.'])
 
178
        self.assertIs(None, md.bundle)
 
179
        self.assertIsNot(None, md.patch)
 
180
 
 
181
        md = self.get_MD(['--no-bundle', '--no-patch', '.', '.'])
 
182
        self.assertIs(None, md.bundle)
 
183
        self.assertIs(None, md.patch)
 
184
 
 
185
        md = self.get_MD(['--no-bundle', '--no-patch', '--format=0.9',
 
186
                          '../parent', '.'])
 
187
        self.assertIs(None, md.bundle)
 
188
        self.assertIs(None, md.patch)
 
189
 
 
190
    def test_from_option(self):
 
191
        self.run_bzr('send', retcode=3)
 
192
        md = self.get_MD(['--from', 'branch'])
 
193
        self.assertEqual('rev3', md.revision_id)
 
194
        md = self.get_MD(['-f', 'branch'])
 
195
        self.assertEqual('rev3', md.revision_id)
 
196
 
 
197
    def test_output_option(self):
 
198
        stdout = self.run_bzr('send -f branch --output file1')[0]
 
199
        self.assertEqual('', stdout)
 
200
        md_file = open('file1', 'rb')
 
201
        self.addCleanup(md_file.close)
 
202
        self.assertContainsRe(md_file.read(), 'rev3')
 
203
        stdout = self.run_bzr('send -f branch --output -')[0]
 
204
        self.assertContainsRe(stdout, 'rev3')
 
205
 
 
206
    def test_note_revisions(self):
 
207
        stderr = self.run_send([])[1]
 
208
        self.assertEndsWith(stderr, '\nBundling 1 revision(s).\n')
 
209
 
 
210
    def test_mailto_option(self):
 
211
        b = branch.Branch.open('branch')
 
212
        b.get_config().set_user_option('mail_client', 'editor')
 
213
        self.run_bzr_error(
 
214
            ('No mail-to address \\(--mail-to\\) or output \\(-o\\) specified',
 
215
            ), 'send -f branch')
 
216
        b.get_config().set_user_option('mail_client', 'bogus')
 
217
        self.run_send([])
 
218
        self.run_bzr_error(('Unknown mail client: bogus',),
 
219
                           'send -f branch --mail-to jrandom@example.org')
 
220
        b.get_config().set_user_option('submit_to', 'jrandom@example.org')
 
221
        self.run_bzr_error(('Unknown mail client: bogus',),
 
222
                           'send -f branch')
 
223
 
 
224
    def test_mailto_child_option(self):
 
225
        """Make sure that child_submit_to is used."""
 
226
        b = branch.Branch.open('branch')
 
227
        b.get_config().set_user_option('mail_client', 'bogus')
 
228
        parent = branch.Branch.open('parent')
 
229
        parent.get_config().set_user_option('child_submit_to',
 
230
                           'somebody@example.org')
 
231
        self.run_bzr_error(('Unknown mail client: bogus',),
 
232
                           'send -f branch')
 
233
 
 
234
    def test_format(self):
 
235
        md = self.get_MD(['--format=4'])
 
236
        self.assertIs(merge_directive.MergeDirective2, md.__class__)
 
237
        self.assertFormatIs('# Bazaar revision bundle v4', md)
 
238
 
 
239
        md = self.get_MD(['--format=0.9'])
 
240
        self.assertFormatIs('# Bazaar revision bundle v0.9', md)
 
241
 
 
242
        md = self.get_MD(['--format=0.9'], cmd=['bundle'])
 
243
        self.assertFormatIs('# Bazaar revision bundle v0.9', md)
 
244
        self.assertIs(merge_directive.MergeDirective, md.__class__)
 
245
 
 
246
        self.run_bzr_error(['Bad value .* for option .format.'],
 
247
                            'send -f branch -o- --format=0.999')[0]
 
248
 
 
249
    def test_format_child_option(self):
 
250
        parent_config = branch.Branch.open('parent').get_config()
 
251
        parent_config.set_user_option('child_submit_format', '4')
 
252
        md = self.get_MD([])
 
253
        self.assertIs(merge_directive.MergeDirective2, md.__class__)
 
254
 
 
255
        parent_config.set_user_option('child_submit_format', '0.9')
 
256
        md = self.get_MD([])
 
257
        self.assertFormatIs('# Bazaar revision bundle v0.9', md)
 
258
 
 
259
        md = self.get_MD([], cmd=['bundle'])
 
260
        self.assertFormatIs('# Bazaar revision bundle v0.9', md)
 
261
        self.assertIs(merge_directive.MergeDirective, md.__class__)
 
262
 
 
263
        parent_config.set_user_option('child_submit_format', '0.999')
 
264
        self.run_bzr_error(["No such send format '0.999'"],
 
265
                            'send -f branch -o-')[0]
 
266
 
 
267
    def test_message_option(self):
 
268
        self.run_bzr('send', retcode=3)
 
269
        md = self.get_MD([])
 
270
        self.assertIs(None, md.message)
 
271
        md = self.get_MD(['-m', 'my message'])
 
272
        self.assertEqual('my message', md.message)
 
273
 
 
274
    def test_omitted_revision(self):
 
275
        md = self.get_MD(['-r-2..'])
 
276
        self.assertEqual('rev2', md.base_revision_id)
 
277
        self.assertEqual('rev3', md.revision_id)
 
278
        md = self.get_MD(['-r..3', '--from', 'branch', 'grandparent'], wd='.')
 
279
        self.assertEqual('rev1', md.base_revision_id)
 
280
        self.assertEqual('rev3', md.revision_id)
 
281
 
 
282
    def test_nonexistant_branch(self):
 
283
        if sys.platform == "win32":
 
284
            location = "C:/i/do/not/exist/"
 
285
        else:
 
286
            location = "/i/do/not/exist/"
 
287
        out, err = self.run_bzr(["send", "--from", location], retcode=3)
 
288
        self.assertEqual(out, '')
 
289
        self.assertEqual(err, 'bzr: ERROR: Not a branch: "%s".\n' % location)
 
290
 
 
291
 
 
292
class TestSendStrictMixin(TestSendMixin):
 
293
 
 
294
    def make_parent_and_local_branches(self):
 
295
        # Create a 'parent' branch as the base
 
296
        self.parent_tree = bzrdir.BzrDir.create_standalone_workingtree('parent')
 
297
        self.build_tree_contents([('parent/file', 'parent')])
 
298
        self.parent_tree.add('file')
 
299
        self.parent_tree.commit('first commit', rev_id='parent')
 
300
        # Branch 'local' from parent and do a change
 
301
        local_bzrdir = self.parent_tree.bzrdir.sprout('local')
 
302
        self.local_tree = local_bzrdir.open_workingtree()
 
303
        self.build_tree_contents([('local/file', 'local')])
 
304
        self.local_tree.commit('second commit', rev_id='local')
 
305
 
 
306
    _default_command = ['send', '-o-', '../parent']
 
307
    _default_wd = 'local'
 
308
    _default_sent_revs = ['local']
 
309
    _default_errors = ['Working tree ".*/local/" has uncommitted '
 
310
                       'changes \(See bzr status\)\.',]
 
311
 
 
312
    def set_config_send_strict(self, value):
 
313
        # set config var (any of bazaar.conf, locations.conf, branch.conf
 
314
        # should do)
 
315
        conf = self.local_tree.branch.get_config()
 
316
        conf.set_user_option('send_strict', value)
 
317
 
 
318
    def assertSendFails(self, args):
 
319
        self.run_send(args, rc=3, err_re=self._default_errors)
 
320
 
 
321
    def assertSendSucceeds(self, args, revs=None):
 
322
        if revs is None:
 
323
            revs = self._default_sent_revs
 
324
        out, err = self.run_send(args)
 
325
        self.assertEquals(
 
326
            'Bundling %d revision(s).\n' % len(revs), err)
 
327
        md = merge_directive.MergeDirective.from_lines(
 
328
                StringIO(out).readlines())
 
329
        self.assertEqual('parent', md.base_revision_id)
 
330
        br = serializer.read_bundle(StringIO(md.get_raw_bundle()))
 
331
        self.assertEqual(set(revs), set(r.revision_id for r in br.revisions))
 
332
 
 
333
 
 
334
class TestSendStrictWithoutChanges(tests.TestCaseWithTransport,
 
335
                                   TestSendStrictMixin):
 
336
 
 
337
    def setUp(self):
 
338
        super(TestSendStrictWithoutChanges, self).setUp()
 
339
        self.make_parent_and_local_branches()
 
340
 
 
341
    def test_send_default(self):
 
342
        self.assertSendSucceeds([])
 
343
 
 
344
    def test_send_strict(self):
 
345
        self.assertSendSucceeds(['--strict'])
 
346
 
 
347
    def test_send_no_strict(self):
 
348
        self.assertSendSucceeds(['--no-strict'])
 
349
 
 
350
    def test_send_config_var_strict(self):
 
351
        self.set_config_send_strict('true')
 
352
        self.assertSendSucceeds([])
 
353
 
 
354
    def test_send_config_var_no_strict(self):
 
355
        self.set_config_send_strict('false')
 
356
        self.assertSendSucceeds([])
 
357
 
 
358
 
 
359
class TestSendStrictWithChanges(tests.TestCaseWithTransport,
 
360
                                   TestSendStrictMixin):
 
361
 
 
362
    _changes_type = None # Set by load_tests
 
363
 
 
364
    def setUp(self):
 
365
        super(TestSendStrictWithChanges, self).setUp()
 
366
        # load tests set _changes_types to the name of the method we want to
 
367
        # call now
 
368
        do_changes_func = getattr(self, self._changes_type)
 
369
        do_changes_func()
 
370
 
 
371
    def _uncommitted_changes(self):
 
372
        self.make_parent_and_local_branches()
 
373
        # Make a change without committing it
 
374
        self.build_tree_contents([('local/file', 'modified')])
 
375
 
 
376
    def _pending_merges(self):
 
377
        self.make_parent_and_local_branches()
 
378
        # Create 'other' branch containing a new file
 
379
        other_bzrdir = self.parent_tree.bzrdir.sprout('other')
 
380
        other_tree = other_bzrdir.open_workingtree()
 
381
        self.build_tree_contents([('other/other-file', 'other')])
 
382
        other_tree.add('other-file')
 
383
        other_tree.commit('other commit', rev_id='other')
 
384
        # Merge and revert, leaving a pending merge
 
385
        self.local_tree.merge_from_branch(other_tree.branch)
 
386
        self.local_tree.revert(filenames=['other-file'], backups=False)
 
387
 
 
388
    def _out_of_sync_trees(self):
 
389
        self.make_parent_and_local_branches()
 
390
        self.run_bzr(['checkout', '--lightweight', 'local', 'checkout'])
 
391
        # Make a change and commit it
 
392
        self.build_tree_contents([('local/file', 'modified in local')])
 
393
        self.local_tree.commit('modify file', rev_id='modified-in-local')
 
394
        # Exercise commands from the checkout directory
 
395
        self._default_wd = 'checkout'
 
396
        self._default_errors = ["Working tree is out of date, please run"
 
397
                                " 'bzr update'\.",]
 
398
        self._default_sent_revs = ['modified-in-local', 'local']
 
399
 
 
400
    def test_send_default(self):
 
401
        self.assertSendFails([])
 
402
 
 
403
    def test_send_with_revision(self):
 
404
        self.assertSendSucceeds(['-r', 'revid:local'], revs=['local'])
 
405
 
 
406
    def test_send_no_strict(self):
 
407
        self.assertSendSucceeds(['--no-strict'])
 
408
 
 
409
    def test_send_strict_with_changes(self):
 
410
        self.assertSendFails(['--strict'])
 
411
 
 
412
    def test_send_respect_config_var_strict(self):
 
413
        self.set_config_send_strict('true')
 
414
        self.assertSendFails([])
 
415
        self.assertSendSucceeds(['--no-strict'])
 
416
 
 
417
 
 
418
    def test_send_bogus_config_var_ignored(self):
 
419
        self.set_config_send_strict("I'm unsure")
 
420
        self.assertSendFails([])
 
421
 
 
422
 
 
423
    def test_send_no_strict_command_line_override_config(self):
 
424
        self.set_config_send_strict('true')
 
425
        self.assertSendFails([])
 
426
        self.assertSendSucceeds(['--no-strict'])
 
427
 
 
428
    def test_push_strict_command_line_override_config(self):
 
429
        self.set_config_send_strict('false')
 
430
        self.assertSendSucceeds([])
 
431
        self.assertSendFails(['--strict'])
 
432
 
 
433
 
 
434
class TestBundleStrictWithoutChanges(TestSendStrictWithoutChanges):
 
435
 
 
436
    _default_command = ['bundle-revisions', '../parent']