2
# -*- coding: utf-8 -*-
4
# Copyright (C) 2005 Canonical Ltd
6
# This program is free software; you can redistribute it and/or modify
7
# it under the terms of the GNU General Public License as published by
8
# the Free Software Foundation; either version 2 of the License, or
9
# (at your option) any later version.
11
# This program is distributed in the hope that it will be useful,
12
# but WITHOUT ANY WARRANTY; without even the implied warranty of
13
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14
# GNU General Public License for more details.
16
# You should have received a copy of the GNU General Public License
17
# along with this program; if not, write to the Free Software
18
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
20
print 'please use "bzr selftest" instead'
27
"""External black-box test for bzr.
29
This always runs bzr as an external process to try to catch bugs
30
related to argument processing, startup, etc.
34
testbzr [-p PYTHON] [BZR]
36
By default this tests the copy of bzr found in the same directory as
37
testbzr, or the first one found on the $PATH. A copy of bzr may be
38
given on the command line to override this, for example when applying
39
a new test suite to an old copy of bzr or vice versa.
41
testbzr normally invokes bzr using the same version of python as it
42
would normally use to run -- that is, the system default python,
43
unless that is older than 2.3. The -p option allows specification of
44
a different Python interpreter, such as when testing that bzr still
47
This replaces the previous test.sh which was not very portable."""
49
import sys, os, traceback
51
from os.path import exists
53
TESTDIR = "testbzr.tmp"
56
# we always invoke bzr as 'python bzr' (or e.g. 'python2.3 bzr')
57
# partly so as to cope if the bzr binary is not marked executable
58
OVERRIDE_PYTHON = 'python'
60
LOGFILENAME = 'testbzr.log'
64
from subprocess import call, Popen, PIPE
65
except ImportError, e:
66
sys.stderr.write("testbzr: sorry, this test suite requires modules from python2.4\n"
74
if isinstance(cmd, basestring):
80
cmd.insert(0, OVERRIDE_PYTHON)
82
logfile.write('$ %r\n' % cmd)
87
def runcmd(cmd, retcode=0):
88
"""Run one command and check the return code.
90
Returns a tuple of (stdout,stderr) strings.
92
If a single string is based, it is split into words.
93
For commands that are not simple space-separated words, please
94
pass a list instead."""
98
actual_retcode = call(cmd, stdout=logfile, stderr=logfile)
100
if retcode != actual_retcode:
101
raise CommandFailed("test failed: %r returned %d, expected %d"
102
% (cmd, actual_retcode, retcode))
106
def backtick(cmd, retcode=0):
109
child = Popen(cmd, stdout=PIPE, stderr=logfile)
110
outd, errd = child.communicate()
112
actual_retcode = child.wait()
114
outd = outd.replace('\r', '')
116
if retcode != actual_retcode:
117
raise CommandFailed("test failed: %r returned %d, expected %d"
118
% (cmd, actual_retcode, retcode))
126
logfile.write('* '+ msg + '\n')
131
logfile.write('$ cd %s\n' % dirname)
136
def log_linenumber():
137
"""Log the stack frame location two things up."""
138
stack = traceback.extract_stack()[-3]
139
logfile.write(' at %s:%d\n' % stack[:2])
143
# prepare an empty scratch directory
144
if os.path.exists(TESTDIR):
145
shutil.rmtree(TESTDIR)
147
start_dir = os.getcwd()
150
logfile = open(LOGFILENAME, 'wt', buffering=1)
153
"""Run a test involving creating a plugin to load,
154
and making sure it is seen properly.
156
orig_help = backtick('bzr help commands') # No plugins yet
158
f = open(os.path.join('plugin_test', 'myplug.py'), 'wb')
159
f.write("""import bzrlib, bzrlib.commands
160
class cmd_myplug(bzrlib.commands.Command):
161
'''Just a simple test plugin.'''
164
print 'Hello from my plugin'
168
os.environ['BZRPLUGINPATH'] = os.path.abspath('plugin_test')
169
help = backtick('bzr help commands')
170
assert help.find('myplug') != -1
171
assert help.find('Just a simple test plugin.') != -1
174
assert backtick('bzr myplug') == 'Hello from my plugin\n'
175
assert backtick('bzr mplg') == 'Hello from my plugin\n'
177
f = open(os.path.join('plugin_test', 'override.py'), 'wb')
178
f.write("""import bzrlib, bzrlib.commands
179
class cmd_commit(bzrlib.commands.cmd_commit):
180
'''Commit changes into a new revision.'''
181
def run(self, *args, **kwargs):
182
print "I'm sorry dave, you can't do that"
184
class cmd_help(bzrlib.commands.cmd_help):
185
'''Show help on a command or other topic.'''
186
def run(self, *args, **kwargs):
187
print "You have been overridden"
188
bzrlib.commands.cmd_help.run(self, *args, **kwargs)
193
newhelp = backtick('bzr help commands')
194
assert newhelp.startswith('You have been overridden\n')
195
# We added a line, but the rest should work
196
assert newhelp[25:] == help
198
assert backtick('bzr commit -m test') == "I'm sorry dave, you can't do that\n"
200
shutil.rmtree('plugin_test')
203
from getopt import getopt
204
opts, args = getopt(sys.argv[1:], 'p:')
206
for option, value in opts:
208
OVERRIDE_PYTHON = value
211
mypath = os.path.abspath(sys.argv[0])
212
print '%-30s %s' % ('running tests from', mypath)
219
BZRPATH = os.path.join(os.path.split(mypath)[0], 'bzr')
221
print '%-30s %s' % ('against bzr', BZRPATH)
222
print '%-30s %s' % ('in directory', os.getcwd())
223
print '%-30s %s' % ('with python', (OVERRIDE_PYTHON or '(default)'))
225
print backtick('bzr version')
227
runcmd(['mkdir', TESTDIR])
229
# This means that any command that is naively run in this directory
230
# Won't affect the parent directory.
232
test_root = os.getcwd()
234
progress("introductory commands")
235
runcmd("bzr version")
236
runcmd("bzr --version")
240
progress("internal tests")
241
runcmd("bzr selftest")
243
progress("user identity")
244
# this should always identify something, if only "john@localhost"
246
runcmd("bzr whoami --email")
247
assert backtick("bzr whoami --email").count('@') == 1
249
progress("invalid commands")
250
runcmd("bzr pants", retcode=1)
251
runcmd("bzr --pants off", retcode=1)
252
runcmd("bzr diff --message foo", retcode=1)
254
progress("basic branch creation")
255
runcmd(['mkdir', 'branch1'])
259
assert backtick('bzr root')[:-1] == os.path.join(test_root, 'branch1')
261
progress("status of new file")
263
f = file('test.txt', 'wt')
264
f.write('hello world!\n')
267
out = backtick("bzr unknowns")
268
assert out == 'test.txt\n'
270
out = backtick("bzr status")
271
assert out == 'unknown:\n test.txt\n'
273
out = backtick("bzr status --all")
274
assert out == "unknown:\n test.txt\n"
276
out = backtick("bzr status test.txt --all")
277
assert out == "unknown:\n test.txt\n"
279
f = file('test2.txt', 'wt')
280
f.write('goodbye cruel world...\n')
283
out = backtick("bzr status test.txt")
284
assert out == "unknown:\n test.txt\n"
286
out = backtick("bzr status")
287
assert out == ("unknown:\n"
291
os.unlink('test2.txt')
293
progress("command aliases")
294
out = backtick("bzr st --all")
295
assert out == ("unknown:\n"
298
out = backtick("bzr stat")
299
assert out == ("unknown:\n"
302
progress("command help")
303
runcmd("bzr help st")
305
runcmd("bzr help commands")
306
runcmd("bzr help slartibartfast", 1)
308
out = backtick("bzr help ci")
309
out.index('aliases: ')
311
progress("can't rename unversioned file")
312
runcmd("bzr rename test.txt new-test.txt", 1)
314
progress("adding a file")
316
runcmd("bzr add test.txt")
317
assert backtick("bzr unknowns") == ''
318
assert backtick("bzr status --all") == ("added:\n"
321
progress("rename newly-added file")
322
runcmd("bzr rename test.txt hello.txt")
323
assert os.path.exists("hello.txt")
324
assert not os.path.exists("test.txt")
326
assert backtick("bzr revno") == '0\n'
328
progress("add first revision")
329
runcmd(["bzr", "commit", "-m", 'add first revision'])
331
progress("more complex renames")
333
runcmd("bzr rename hello.txt sub1", 1)
334
runcmd("bzr rename hello.txt sub1/hello.txt", 1)
335
runcmd("bzr move hello.txt sub1", 1)
337
runcmd("bzr add sub1")
338
runcmd("bzr rename sub1 sub2")
339
runcmd("bzr move hello.txt sub2")
340
assert backtick("bzr relpath sub2/hello.txt") == os.path.join("sub2", "hello.txt\n")
342
assert exists("sub2")
343
assert exists("sub2/hello.txt")
344
assert not exists("sub1")
345
assert not exists("hello.txt")
347
runcmd(['bzr', 'commit', '-m', 'commit with some things moved to subdirs'])
350
runcmd('bzr add sub1')
351
runcmd('bzr move sub2/hello.txt sub1')
352
assert not exists('sub2/hello.txt')
353
assert exists('sub1/hello.txt')
354
runcmd('bzr move sub2 sub1')
355
assert not exists('sub2')
356
assert exists('sub1/sub2')
358
runcmd(['bzr', 'commit', '-m', 'rename nested subdirectories'])
361
assert backtick('bzr root')[:-1] == os.path.join(test_root, 'branch1')
362
runcmd('bzr move ../hello.txt .')
363
assert exists('./hello.txt')
364
assert backtick('bzr relpath hello.txt') == os.path.join('sub1', 'sub2', 'hello.txt\n')
365
assert backtick('bzr relpath ../../sub1/sub2/hello.txt') == os.path.join('sub1', 'sub2', 'hello.txt\n')
366
runcmd(['bzr', 'commit', '-m', 'move to parent directory'])
368
assert backtick('bzr relpath sub2/hello.txt') == os.path.join('sub1', 'sub2', 'hello.txt\n')
370
runcmd('bzr move sub2/hello.txt .')
371
assert exists('hello.txt')
373
f = file('hello.txt', 'wt')
374
f.write('some nice new content\n')
377
f = file('msg.tmp', 'wt')
378
f.write('this is my new commit\n')
381
runcmd('bzr commit -F msg.tmp')
383
assert backtick('bzr revno') == '5\n'
384
runcmd('bzr export -r 5 export-5.tmp')
385
runcmd('bzr export export.tmp')
392
progress("file with spaces in name")
393
mkdir('sub directory')
394
file('sub directory/file with spaces ', 'wt').write('see how this works\n')
397
runcmd('bzr commit -m add-spaces')
401
runcmd('bzr log --forward')
413
# Can't create a branch if it already exists
414
runcmd('bzr branch branch1', retcode=1)
415
# Can't create a branch if its parent doesn't exist
416
runcmd('bzr branch /unlikely/to/exist', retcode=1)
417
runcmd('bzr branch branch1 branch2')
421
runcmd('bzr pull', retcode=1)
422
runcmd('bzr pull ../branch2')
425
runcmd('bzr commit -m empty')
429
runcmd('bzr commit -m empty')
431
runcmd('bzr commit -m empty')
432
runcmd('bzr pull', retcode=1)
435
progress('status after remove')
436
mkdir('status-after-remove')
437
# see mail from William Dodé, 2005-05-25
438
# $ bzr init; touch a; bzr add a; bzr commit -m "add a"
439
# * looking for changes...
444
# bzr: local variable 'kind' referenced before assignment
445
# at /vrac/python/bazaar-ng/bzrlib/diff.py:286 in compare_trees()
446
# see ~/.bzr.log for debug information
447
cd('status-after-remove')
449
file('a', 'w').write('foo')
451
runcmd(['bzr', 'commit', '-m', 'add a'])
452
runcmd('bzr remove a')
457
progress('ignore patterns')
458
mkdir('ignorebranch')
461
assert backtick('bzr unknowns') == ''
463
file('foo.tmp', 'wt').write('tmp files are ignored')
464
assert backtick('bzr unknowns') == ''
466
file('foo.c', 'wt').write('int main() {}')
467
assert backtick('bzr unknowns') == 'foo.c\n'
468
runcmd('bzr add foo.c')
469
assert backtick('bzr unknowns') == ''
471
# 'ignore' works when creating the .bzignore file
472
file('foo.blah', 'wt').write('blah')
473
assert backtick('bzr unknowns') == 'foo.blah\n'
474
runcmd('bzr ignore *.blah')
475
assert backtick('bzr unknowns') == ''
476
assert file('.bzrignore', 'rb').read() == '*.blah\n'
478
# 'ignore' works when then .bzrignore file already exists
479
file('garh', 'wt').write('garh')
480
assert backtick('bzr unknowns') == 'garh\n'
481
runcmd('bzr ignore garh')
482
assert backtick('bzr unknowns') == ''
483
assert file('.bzrignore', 'rb').read() == '*.blah\ngarh\n'
490
progress("recursive and non-recursive add")
495
fp = os.path.join('foo', 'test.txt')
499
runcmd('bzr add --no-recurse foo')
500
runcmd('bzr file-id foo')
501
runcmd('bzr file-id ' + fp, 1) # not versioned yet
502
runcmd('bzr commit -m add-dir-only')
504
runcmd('bzr file-id ' + fp, 1) # still not versioned
506
runcmd('bzr add foo')
507
runcmd('bzr file-id ' + fp)
508
runcmd('bzr commit -m add-sub-file')
515
# Run any function in this
520
if k.startswith('test_') and callable(g[k]):
521
progress(k[5:].replace('_', ' '))
524
progress("all tests passed!")
526
sys.stderr.write('*' * 50 + '\n'
527
+ 'testbzr: tests failed\n'
528
+ 'see ' + LOGFILENAME + ' for more information\n'
530
logfile.write('tests failed!\n')
531
traceback.print_exc(None, logfile)
534
sys.stdout.writelines(file(os.path.join(start_dir, LOGFILENAME), 'rt').readlines()[-50:])