1
# Copyright (C) 2005 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
17
"""UI tests for the test framework."""
28
from bzrlib.errors import ParamikoNotPresent
29
from bzrlib.tests import (
32
TestCaseWithMemoryTransport,
33
TestCaseWithTransport,
37
from bzrlib.tests.blackbox import ExternalBase
40
class TestOptions(TestCase):
44
def test_transport_set_to_sftp(self):
45
# test the --transport option has taken effect from within the
48
import bzrlib.transport.sftp
49
except ParamikoNotPresent:
50
raise TestSkipped("Paramiko not present")
51
if TestOptions.current_test != "test_transport_set_to_sftp":
53
self.assertEqual(bzrlib.transport.sftp.SFTPAbsoluteServer,
54
bzrlib.tests.default_transport)
56
def test_transport_set_to_memory(self):
57
# test the --transport option has taken effect from within the
59
import bzrlib.transport.memory
60
if TestOptions.current_test != "test_transport_set_to_memory":
62
self.assertEqual(bzrlib.transport.memory.MemoryServer,
63
bzrlib.tests.default_transport)
65
def test_transport(self):
66
# test that --transport=sftp works
68
import bzrlib.transport.sftp
69
except ParamikoNotPresent:
70
raise TestSkipped("Paramiko not present")
71
old_transport = bzrlib.tests.default_transport
72
old_root = TestCaseWithMemoryTransport.TEST_ROOT
73
TestCaseWithMemoryTransport.TEST_ROOT = None
75
TestOptions.current_test = "test_transport_set_to_sftp"
76
stdout = self.capture('selftest --transport=sftp test_transport_set_to_sftp')
78
self.assertContainsRe(stdout, 'Ran 1 test')
79
self.assertEqual(old_transport, bzrlib.tests.default_transport)
81
TestOptions.current_test = "test_transport_set_to_memory"
82
stdout = self.capture('selftest --transport=memory test_transport_set_to_memory')
83
self.assertContainsRe(stdout, 'Ran 1 test')
84
self.assertEqual(old_transport, bzrlib.tests.default_transport)
86
bzrlib.tests.default_transport = old_transport
87
TestOptions.current_test = None
88
TestCaseWithMemoryTransport.TEST_ROOT = old_root
91
class TestRunBzr(ExternalBase):
93
def run_bzr_captured(self, argv, retcode=0, encoding=None, stdin=None,
95
"""Override run_bzr_captured to test how it is invoked by run_bzr.
97
We test how run_bzr_captured actually invokes bzr in another location.
98
Here we only need to test that it is run_bzr passes the right
99
parameters to run_bzr_captured.
102
self.retcode = retcode
103
self.encoding = encoding
105
self.working_dir = working_dir
108
"""Test that run_bzr passes args correctly to run_bzr_captured"""
109
self.run_bzr('arg1', 'arg2', 'arg3', retcode=1)
110
self.assertEqual(('arg1', 'arg2', 'arg3'), self.argv)
112
def test_encoding(self):
113
"""Test that run_bzr passes encoding to run_bzr_captured"""
114
self.run_bzr('foo', 'bar')
115
self.assertEqual(None, self.encoding)
116
self.assertEqual(('foo', 'bar'), self.argv)
118
self.run_bzr('foo', 'bar', encoding='baz')
119
self.assertEqual('baz', self.encoding)
120
self.assertEqual(('foo', 'bar'), self.argv)
122
def test_retcode(self):
123
"""Test that run_bzr passes retcode to run_bzr_captured"""
124
# Default is retcode == 0
125
self.run_bzr('foo', 'bar')
126
self.assertEqual(0, self.retcode)
127
self.assertEqual(('foo', 'bar'), self.argv)
129
self.run_bzr('foo', 'bar', retcode=1)
130
self.assertEqual(1, self.retcode)
131
self.assertEqual(('foo', 'bar'), self.argv)
133
self.run_bzr('foo', 'bar', retcode=None)
134
self.assertEqual(None, self.retcode)
135
self.assertEqual(('foo', 'bar'), self.argv)
137
self.run_bzr('foo', 'bar', retcode=3)
138
self.assertEqual(3, self.retcode)
139
self.assertEqual(('foo', 'bar'), self.argv)
141
def test_stdin(self):
142
# test that the stdin keyword to run_bzr is passed through to
143
# run_bzr_captured as-is. We do this by overriding
144
# run_bzr_captured in this class, and then calling run_bzr,
145
# which is a convenience function for run_bzr_captured, so
147
self.run_bzr('foo', 'bar', stdin='gam')
148
self.assertEqual('gam', self.stdin)
149
self.assertEqual(('foo', 'bar'), self.argv)
151
self.run_bzr('foo', 'bar', stdin='zippy')
152
self.assertEqual('zippy', self.stdin)
153
self.assertEqual(('foo', 'bar'), self.argv)
155
def test_working_dir(self):
156
"""Test that run_bzr passes working_dir to run_bzr_captured"""
157
self.run_bzr('foo', 'bar')
158
self.assertEqual(None, self.working_dir)
159
self.assertEqual(('foo', 'bar'), self.argv)
161
self.run_bzr('foo', 'bar', working_dir='baz')
162
self.assertEqual('baz', self.working_dir)
163
self.assertEqual(('foo', 'bar'), self.argv)
166
class TestBenchmarkTests(TestCaseWithTransport):
168
def test_benchmark_runs_benchmark_tests(self):
169
"""bzr selftest --benchmark should not run the default test suite."""
170
# We test this by passing a regression test name to --benchmark, which
171
# should result in 0 rests run.
172
old_root = TestCaseWithMemoryTransport.TEST_ROOT
174
TestCaseWithMemoryTransport.TEST_ROOT = None
175
out, err = self.run_bzr('selftest', '--benchmark', 'workingtree_implementations')
177
TestCaseWithMemoryTransport.TEST_ROOT = old_root
178
self.assertContainsRe(out, 'Ran 0 tests.*\n\nOK')
182
benchfile = open(".perf_history", "rt")
184
lines = benchfile.readlines()
187
self.assertEqual(1, len(lines))
188
self.assertContainsRe(lines[0], "--date [0-9.]+")
191
class TestRunBzrCaptured(ExternalBase):
193
def apply_redirected(self, stdin=None, stdout=None, stderr=None,
194
a_callable=None, *args, **kwargs):
196
self.factory_stdin = getattr(bzrlib.ui.ui_factory, "stdin", None)
197
self.factory = bzrlib.ui.ui_factory
198
self.working_dir = osutils.getcwd()
199
stdout.write('foo\n')
200
stderr.write('bar\n')
203
def test_stdin(self):
204
# test that the stdin keyword to run_bzr_captured is passed through to
205
# apply_redirected as a StringIO. We do this by overriding
206
# apply_redirected in this class, and then calling run_bzr_captured,
207
# which calls apply_redirected.
208
self.run_bzr_captured(['foo', 'bar'], stdin='gam')
209
self.assertEqual('gam', self.stdin.read())
210
self.assertTrue(self.stdin is self.factory_stdin)
211
self.run_bzr_captured(['foo', 'bar'], stdin='zippy')
212
self.assertEqual('zippy', self.stdin.read())
213
self.assertTrue(self.stdin is self.factory_stdin)
215
def test_ui_factory(self):
216
# each invocation of self.run_bzr_captured should get its
217
# own UI factory, which is an instance of TestUIFactory,
218
# with stdin, stdout and stderr attached to the stdin,
219
# stdout and stderr of the invoked run_bzr_captured
220
current_factory = bzrlib.ui.ui_factory
221
self.run_bzr_captured(['foo'])
222
self.failIf(current_factory is self.factory)
223
self.assertNotEqual(sys.stdout, self.factory.stdout)
224
self.assertNotEqual(sys.stderr, self.factory.stderr)
225
self.assertEqual('foo\n', self.factory.stdout.getvalue())
226
self.assertEqual('bar\n', self.factory.stderr.getvalue())
227
self.assertIsInstance(self.factory, TestUIFactory)
229
def test_working_dir(self):
230
self.build_tree(['one/', 'two/'])
231
cwd = osutils.getcwd()
233
# Default is to work in the current directory
234
self.run_bzr_captured(['foo', 'bar'])
235
self.assertEqual(cwd, self.working_dir)
237
self.run_bzr_captured(['foo', 'bar'], working_dir=None)
238
self.assertEqual(cwd, self.working_dir)
240
# The function should be run in the alternative directory
241
# but afterwards the current working dir shouldn't be changed
242
self.run_bzr_captured(['foo', 'bar'], working_dir='one')
243
self.assertNotEqual(cwd, self.working_dir)
244
self.assertEndsWith(self.working_dir, 'one')
245
self.assertEqual(cwd, osutils.getcwd())
247
self.run_bzr_captured(['foo', 'bar'], working_dir='two')
248
self.assertNotEqual(cwd, self.working_dir)
249
self.assertEndsWith(self.working_dir, 'two')
250
self.assertEqual(cwd, osutils.getcwd())
253
class TestRunBzrSubprocess(TestCaseWithTransport):
255
def test_run_bzr_subprocess(self):
256
"""The run_bzr_helper_external comand behaves nicely."""
257
result = self.run_bzr_subprocess('--version')
258
result = self.run_bzr_subprocess('--version', retcode=None)
259
self.assertContainsRe(result[0], 'is free software')
260
self.assertRaises(AssertionError, self.run_bzr_subprocess,
262
result = self.run_bzr_subprocess('--versionn', retcode=3)
263
result = self.run_bzr_subprocess('--versionn', retcode=None)
264
self.assertContainsRe(result[1], 'unknown command')
265
err = self.run_bzr_subprocess('merge', '--merge-type', 'magic merge',
267
self.assertContainsRe(err, 'Bad value "magic merge" for option'
270
def test_run_bzr_subprocess_env(self):
271
"""run_bzr_subprocess can set environment variables in the child only.
273
These changes should not change the running process, only the child.
275
# The test suite should unset this variable
276
self.assertEqual(None, os.environ.get('BZR_EMAIL'))
277
out, err = self.run_bzr_subprocess('whoami', env_changes={
278
'BZR_EMAIL':'Joe Foo <joe@foo.com>'
279
}, universal_newlines=True)
280
self.assertEqual('', err)
281
self.assertEqual('Joe Foo <joe@foo.com>\n', out)
282
# And it should not be modified
283
self.assertEqual(None, os.environ.get('BZR_EMAIL'))
285
# Do it again with a different address, just to make sure
286
# it is actually changing
287
out, err = self.run_bzr_subprocess('whoami', env_changes={
288
'BZR_EMAIL':'Barry <bar@foo.com>'
289
}, universal_newlines=True)
290
self.assertEqual('', err)
291
self.assertEqual('Barry <bar@foo.com>\n', out)
292
self.assertEqual(None, os.environ.get('BZR_EMAIL'))
294
def test_run_bzr_subprocess_env_del(self):
295
"""run_bzr_subprocess can remove environment variables too."""
296
# Create a random email, so we are sure this won't collide
297
rand_bzr_email = 'John Doe <jdoe@%s.com>' % (osutils.rand_chars(20),)
298
rand_email = 'Jane Doe <jdoe@%s.com>' % (osutils.rand_chars(20),)
299
os.environ['BZR_EMAIL'] = rand_bzr_email
300
os.environ['EMAIL'] = rand_email
302
# By default, the child will inherit the current env setting
303
out, err = self.run_bzr_subprocess('whoami', universal_newlines=True)
304
self.assertEqual('', err)
305
self.assertEqual(rand_bzr_email + '\n', out)
307
# Now that BZR_EMAIL is not set, it should fall back to EMAIL
308
out, err = self.run_bzr_subprocess('whoami',
309
env_changes={'BZR_EMAIL':None},
310
universal_newlines=True)
311
self.assertEqual('', err)
312
self.assertEqual(rand_email + '\n', out)
314
# This switches back to the default email guessing logic
315
# Which shouldn't match either of the above addresses
316
out, err = self.run_bzr_subprocess('whoami',
317
env_changes={'BZR_EMAIL':None, 'EMAIL':None},
318
universal_newlines=True)
320
self.assertEqual('', err)
321
self.assertNotEqual(rand_bzr_email + '\n', out)
322
self.assertNotEqual(rand_email + '\n', out)
324
# TestCase cleans up BZR_EMAIL, and EMAIL at startup
325
del os.environ['BZR_EMAIL']
326
del os.environ['EMAIL']
328
def test_run_bzr_subprocess_env_del_missing(self):
329
"""run_bzr_subprocess won't fail if deleting a nonexistant env var"""
330
self.failIf('NON_EXISTANT_ENV_VAR' in os.environ)
331
out, err = self.run_bzr_subprocess('rocks',
332
env_changes={'NON_EXISTANT_ENV_VAR':None},
333
universal_newlines=True)
334
self.assertEqual('It sure does!\n', out)
335
self.assertEqual('', err)
337
def test_run_bzr_subprocess_working_dir(self):
338
"""Test that we can specify the working dir for the child"""
339
cwd = osutils.getcwd()
341
self.make_branch_and_tree('.')
342
self.make_branch_and_tree('one')
343
self.make_branch_and_tree('two')
345
def get_root(**kwargs):
346
"""Spawn a process to get the 'root' of the tree.
348
You can pass in arbitrary new arguments. This just makes
349
sure that the returned path doesn't have trailing whitespace.
351
return self.run_bzr_subprocess('root', **kwargs)[0].rstrip()
353
self.assertEqual(cwd, get_root())
354
self.assertEqual(cwd, get_root(working_dir=None))
355
# Has our path changed?
356
self.assertEqual(cwd, osutils.getcwd())
358
dir1 = get_root(working_dir='one')
359
self.assertEndsWith(dir1, 'one')
360
self.assertEqual(cwd, osutils.getcwd())
362
dir2 = get_root(working_dir='two')
363
self.assertEndsWith(dir2, 'two')
364
self.assertEqual(cwd, osutils.getcwd())
367
class _DontSpawnProcess(Exception):
368
"""A simple exception which just allows us to skip unnecessary steps"""
371
class TestRunBzrSubprocessCommands(TestCaseWithTransport):
373
def _popen(self, *args, **kwargs):
374
"""Record the command that is run, so that we can ensure it is correct"""
375
self._popen_args = args
376
self._popen_kwargs = kwargs
377
raise _DontSpawnProcess()
379
def test_run_bzr_subprocess_no_plugins(self):
380
self.assertRaises(_DontSpawnProcess, self.run_bzr_subprocess)
381
command = self._popen_args[0]
382
self.assertEqual(sys.executable, command[0])
383
self.assertEqual(self.get_bzr_path(), command[1])
384
self.assertEqual(['--no-plugins'], command[2:])
386
def test_allow_plugins(self):
387
self.assertRaises(_DontSpawnProcess,
388
self.run_bzr_subprocess, allow_plugins=True)
389
command = self._popen_args[0]
390
self.assertEqual([], command[2:])
393
class TestBzrSubprocess(TestCaseWithTransport):
395
def test_start_and_stop_bzr_subprocess(self):
396
"""We can start and perform other test actions while that process is
399
process = self.start_bzr_subprocess(['--version'])
400
result = self.finish_bzr_subprocess(process)
401
self.assertContainsRe(result[0], 'is free software')
402
self.assertEqual('', result[1])
404
def test_start_and_stop_bzr_subprocess_with_error(self):
405
"""finish_bzr_subprocess allows specification of the desired exit code.
407
process = self.start_bzr_subprocess(['--versionn'])
408
result = self.finish_bzr_subprocess(process, retcode=3)
409
self.assertEqual('', result[0])
410
self.assertContainsRe(result[1], 'unknown command')
412
def test_start_and_stop_bzr_subprocess_ignoring_retcode(self):
413
"""finish_bzr_subprocess allows the exit code to be ignored."""
414
process = self.start_bzr_subprocess(['--versionn'])
415
result = self.finish_bzr_subprocess(process, retcode=None)
416
self.assertEqual('', result[0])
417
self.assertContainsRe(result[1], 'unknown command')
419
def test_start_and_stop_bzr_subprocess_with_unexpected_retcode(self):
420
"""finish_bzr_subprocess raises self.failureException if the retcode is
421
not the expected one.
423
process = self.start_bzr_subprocess(['--versionn'])
424
self.assertRaises(self.failureException, self.finish_bzr_subprocess,
427
def test_start_and_stop_bzr_subprocess_send_signal(self):
428
"""finish_bzr_subprocess raises self.failureException if the retcode is
429
not the expected one.
431
process = self.start_bzr_subprocess(['wait-until-signalled'],
432
skip_if_plan_to_signal=True)
433
self.assertEqual('running\n', process.stdout.readline())
434
result = self.finish_bzr_subprocess(process, send_signal=signal.SIGINT,
436
self.assertEqual('', result[0])
437
self.assertEqual('bzr: interrupted\n', result[1])
439
def test_start_and_stop_working_dir(self):
440
cwd = osutils.getcwd()
442
self.make_branch_and_tree('one')
444
process = self.start_bzr_subprocess(['root'], working_dir='one')
445
result = self.finish_bzr_subprocess(process, universal_newlines=True)
446
self.assertEndsWith(result[0], 'one\n')
447
self.assertEqual('', result[1])
450
class TestRunBzrError(ExternalBase):
452
def test_run_bzr_error(self):
453
out, err = self.run_bzr_error(['^$'], 'rocks', retcode=0)
454
self.assertEqual(out, 'It sure does!\n')
456
out, err = self.run_bzr_error(["bzr: ERROR: foobarbaz is not versioned"],
457
'file-id', 'foobarbaz')
460
class TestSelftestCleanOutput(TestCaseInTempDir):
462
def test_clean_output(self):
463
# check that 'bzr selftest --clean-output' works correct
464
dirs = ('test0000.tmp', 'test0001.tmp', 'bzrlib', 'tests')
465
files = ('bzr', 'setup.py', 'test9999.tmp')
470
f.write('content of ')
475
before = os.listdir(root)
477
self.assertEquals(['bzr','bzrlib','setup.py',
478
'test0000.tmp','test0001.tmp',
479
'test9999.tmp','tests'],
482
out,err = self.run_bzr_captured(['selftest','--clean-output'],
485
self.assertEquals(['delete directory: test0000.tmp',
486
'delete directory: test0001.tmp'],
487
sorted(out.splitlines()))
488
self.assertEquals('', err)
490
after = os.listdir(root)
492
self.assertEquals(['bzr','bzrlib','setup.py',
493
'test9999.tmp','tests'],
497
class TestSelftestListOnly(TestCase):
500
def _parse_test_list(lines, newlines_in_header=1):
501
"Parse a list of lines into a tuple of 3 lists (header,body,footer)."
508
header_newlines_found = 0
512
header_newlines_found += 1
513
if header_newlines_found >= newlines_in_header:
518
if line.startswith('-------'):
524
# If the last body line is blank, drop it off the list
525
if len(body) > 0 and body[-1] == '':
527
return (header,body,footer)
529
def test_list_only(self):
530
# check that bzr selftest --list-only works correctly
531
out,err = self.run_bzr_captured(['selftest', 'selftest',
533
self.assertEndsWith(err, 'tests passed\n')
534
(header,body,footer) = self._parse_test_list(out.splitlines())
535
num_tests = len(body)
536
self.assertContainsRe(footer[0], 'Listed %s tests in' % num_tests)
538
def test_list_only_filtered(self):
539
# check that a filtered --list-only works, both include and exclude
540
out_all,err_all = self.run_bzr_captured(['selftest', '--list-only'])
541
tests_all = self._parse_test_list(out_all.splitlines())[1]
542
out_incl,err_incl = self.run_bzr_captured(['selftest', '--list-only',
544
tests_incl = self._parse_test_list(out_incl.splitlines())[1]
545
self.assertSubset(tests_incl, tests_all)
546
out_excl,err_excl = self.run_bzr_captured(['selftest', '--list-only',
547
'--exclude', 'selftest'])
548
tests_excl = self._parse_test_list(out_excl.splitlines())[1]
549
self.assertSubset(tests_excl, tests_all)
550
set_incl = set(tests_incl)
551
set_excl = set(tests_excl)
552
intersection = set_incl.intersection(set_excl)
553
self.assertEquals(0, len(intersection))
554
self.assertEquals(len(tests_all), len(tests_incl) + len(tests_excl))
556
def test_list_only_random(self):
557
# check that --randomize works correctly
558
out_all,err_all = self.run_bzr_captured(['selftest', '--list-only',
560
tests_all = self._parse_test_list(out_all.splitlines())[1]
561
out_rand,err_rand = self.run_bzr_captured(['selftest', '--list-only',
562
'selftest', '--randomize', 'now'])
563
(header_rand,tests_rand,dummy) = self._parse_test_list(
564
out_rand.splitlines(), 2)
565
self.assertNotEqual(tests_all, tests_rand)
566
self.assertEqual(sorted(tests_all), sorted(tests_rand))
567
# Check that the seed can be reused to get the exact same order
568
seed_re = re.compile('Randomizing test order using seed (\w+)')
569
match_obj = seed_re.search(header_rand[-1])
570
seed = match_obj.group(1)
571
out_rand2,err_rand2 = self.run_bzr_captured(['selftest', '--list-only',
572
'selftest', '--randomize', seed])
573
(header_rand2,tests_rand2,dummy) = self._parse_test_list(
574
out_rand2.splitlines(), 2)
575
self.assertEqual(tests_rand, tests_rand2)