17
17
# along with this program; if not, write to the Free Software
18
18
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
20
print 'please use "bzr selftest" instead'
21
"""External black-box test for bzr.
23
This always runs bzr as an external process to try to catch bugs
24
related to argument processing, startup, etc.
28
testbzr [-p PYTHON] [BZR]
30
By default this tests the copy of bzr found in the same directory as
31
testbzr, or the first one found on the $PATH. A copy of bzr may be
32
given on the command line to override this, for example when applying
33
a new test suite to an old copy of bzr or vice versa.
35
testbzr normally invokes bzr using the same version of python as it
36
would normally use to run -- that is, the system default python,
37
unless that is older than 2.3. The -p option allows specification of
38
a different Python interpreter, such as when testing that bzr still
41
This replaces the previous test.sh which was not very portable."""
43
import sys, os, traceback
45
from os.path import exists
47
TESTDIR = "testbzr.tmp"
50
# we always invoke bzr as 'python bzr' (or e.g. 'python2.3 bzr')
51
# partly so as to cope if the bzr binary is not marked executable
52
OVERRIDE_PYTHON = 'python'
54
LOGFILENAME = 'testbzr.log'
58
from subprocess import call, Popen, PIPE
59
except ImportError, e:
60
sys.stderr.write("testbzr: sorry, this test suite requires modules from python2.4\n"
65
class CommandFailed(Exception):
70
if isinstance(cmd, basestring):
76
cmd.insert(0, OVERRIDE_PYTHON)
78
logfile.write('$ %r\n' % cmd)
83
def runcmd(cmd, retcode=0):
84
"""Run one command and check the return code.
86
Returns a tuple of (stdout,stderr) strings.
88
If a single string is based, it is split into words.
89
For commands that are not simple space-separated words, please
90
pass a list instead."""
94
actual_retcode = call(cmd, stdout=logfile, stderr=logfile)
96
if retcode != actual_retcode:
97
raise CommandFailed("test failed: %r returned %d, expected %d"
98
% (cmd, actual_retcode, retcode))
102
def backtick(cmd, retcode=0):
105
child = Popen(cmd, stdout=PIPE, stderr=logfile)
106
outd, errd = child.communicate()
108
actual_retcode = child.wait()
110
outd = outd.replace('\r', '')
112
if retcode != actual_retcode:
113
raise CommandFailed("test failed: %r returned %d, expected %d"
114
% (cmd, actual_retcode, retcode))
122
logfile.write('* '+ msg + '\n')
127
logfile.write('$ cd %s\n' % dirname)
132
def log_linenumber():
133
"""Log the stack frame location two things up."""
134
stack = traceback.extract_stack()[-3]
135
logfile.write(' at %s:%d\n' % stack[:2])
139
# prepare an empty scratch directory
140
if os.path.exists(TESTDIR):
141
shutil.rmtree(TESTDIR)
143
start_dir = os.getcwd()
146
logfile = open(LOGFILENAME, 'wt', buffering=1)
149
"""Run a test involving creating a plugin to load,
150
and making sure it is seen properly.
153
f = open(os.path.join('plugin_test', 'myplug.py'), 'wb')
154
f.write("""import bzrlib, bzrlib.commands
155
class cmd_myplug(bzrlib.commands.Command):
156
'''Just a simple test plugin.'''
159
print 'Hello from my plugin'
163
os.environ['BZRPLUGINPATH'] = os.path.abspath('plugin_test')
164
help = backtick('bzr help commands')
165
assert help.find('myplug') != -1
166
assert help.find('Just a simple test plugin.') != -1
169
assert backtick('bzr myplug') == 'Hello from my plugin\n'
170
assert backtick('bzr mplg') == 'Hello from my plugin\n'
172
f = open(os.path.join('plugin_test', 'override.py'), 'wb')
173
f.write("""import bzrlib, bzrlib.commands
174
class cmd_commit(bzrlib.commands.cmd_commit):
175
'''Commit changes into a new revision.'''
176
def run(self, *args, **kwargs):
177
print "I'm sorry dave, you can't do that"
179
class cmd_help(bzrlib.commands.cmd_help):
180
'''Show help on a command or other topic.'''
181
def run(self, *args, **kwargs):
182
print "You have been overridden"
183
bzrlib.commands.cmd_help.run(self, *args, **kwargs)
188
newhelp = backtick('bzr help commands')
189
assert newhelp.startswith('You have been overridden\n')
190
# We added a line, but the rest should work
191
assert newhelp[25:] == help
193
assert backtick('bzr commit -m test') == "I'm sorry dave, you can't do that\n"
195
shutil.rmtree('plugin_test')
198
from getopt import getopt
199
opts, args = getopt(sys.argv[1:], 'p:')
201
for option, value in opts:
203
OVERRIDE_PYTHON = value
206
mypath = os.path.abspath(sys.argv[0])
207
print '%-30s %s' % ('running tests from', mypath)
214
BZRPATH = os.path.join(os.path.split(mypath)[0], 'bzr')
216
print '%-30s %s' % ('against bzr', BZRPATH)
217
print '%-30s %s' % ('in directory', os.getcwd())
218
print '%-30s %s' % ('with python', (OVERRIDE_PYTHON or '(default)'))
220
print backtick('bzr version')
222
runcmd(['mkdir', TESTDIR])
224
test_root = os.getcwd()
226
progress("introductory commands")
227
runcmd("bzr version")
228
runcmd("bzr --version")
232
progress("internal tests")
233
runcmd("bzr selftest")
235
progress("user identity")
236
# this should always identify something, if only "john@localhost"
238
runcmd("bzr whoami --email")
239
assert backtick("bzr whoami --email").count('@') == 1
241
progress("invalid commands")
242
runcmd("bzr pants", retcode=1)
243
runcmd("bzr --pants off", retcode=1)
244
runcmd("bzr diff --message foo", retcode=1)
246
progress("basic branch creation")
247
runcmd(['mkdir', 'branch1'])
251
assert backtick('bzr root')[:-1] == os.path.join(test_root, 'branch1')
253
progress("status of new file")
255
f = file('test.txt', 'wt')
256
f.write('hello world!\n')
259
out = backtick("bzr unknowns")
260
assert out == 'test.txt\n'
262
out = backtick("bzr status")
263
assert out == 'unknown:\n test.txt\n'
265
out = backtick("bzr status --all")
266
assert out == "unknown:\n test.txt\n"
268
out = backtick("bzr status test.txt --all")
269
assert out == "unknown:\n test.txt\n"
271
f = file('test2.txt', 'wt')
272
f.write('goodbye cruel world...\n')
275
out = backtick("bzr status test.txt")
276
assert out == "unknown:\n test.txt\n"
278
out = backtick("bzr status")
279
assert out == ("unknown:\n"
283
os.unlink('test2.txt')
285
progress("command aliases")
286
out = backtick("bzr st --all")
287
assert out == ("unknown:\n"
290
out = backtick("bzr stat")
291
assert out == ("unknown:\n"
294
progress("command help")
295
runcmd("bzr help st")
297
runcmd("bzr help commands")
298
runcmd("bzr help slartibartfast", 1)
300
out = backtick("bzr help ci")
301
out.index('aliases: ')
303
progress("can't rename unversioned file")
304
runcmd("bzr rename test.txt new-test.txt", 1)
306
progress("adding a file")
308
runcmd("bzr add test.txt")
309
assert backtick("bzr unknowns") == ''
310
assert backtick("bzr status --all") == ("added:\n"
313
progress("rename newly-added file")
314
runcmd("bzr rename test.txt hello.txt")
315
assert os.path.exists("hello.txt")
316
assert not os.path.exists("test.txt")
318
assert backtick("bzr revno") == '0\n'
320
progress("add first revision")
321
runcmd(["bzr", "commit", "-m", 'add first revision'])
323
progress("more complex renames")
325
runcmd("bzr rename hello.txt sub1", 1)
326
runcmd("bzr rename hello.txt sub1/hello.txt", 1)
327
runcmd("bzr move hello.txt sub1", 1)
329
runcmd("bzr add sub1")
330
runcmd("bzr rename sub1 sub2")
331
runcmd("bzr move hello.txt sub2")
332
assert backtick("bzr relpath sub2/hello.txt") == os.path.join("sub2", "hello.txt\n")
334
assert exists("sub2")
335
assert exists("sub2/hello.txt")
336
assert not exists("sub1")
337
assert not exists("hello.txt")
339
runcmd(['bzr', 'commit', '-m', 'commit with some things moved to subdirs'])
342
runcmd('bzr add sub1')
343
runcmd('bzr move sub2/hello.txt sub1')
344
assert not exists('sub2/hello.txt')
345
assert exists('sub1/hello.txt')
346
runcmd('bzr move sub2 sub1')
347
assert not exists('sub2')
348
assert exists('sub1/sub2')
350
runcmd(['bzr', 'commit', '-m', 'rename nested subdirectories'])
353
assert backtick('bzr root')[:-1] == os.path.join(test_root, 'branch1')
354
runcmd('bzr move ../hello.txt .')
355
assert exists('./hello.txt')
356
assert backtick('bzr relpath hello.txt') == os.path.join('sub1', 'sub2', 'hello.txt\n')
357
assert backtick('bzr relpath ../../sub1/sub2/hello.txt') == os.path.join('sub1', 'sub2', 'hello.txt\n')
358
runcmd(['bzr', 'commit', '-m', 'move to parent directory'])
360
assert backtick('bzr relpath sub2/hello.txt') == os.path.join('sub1', 'sub2', 'hello.txt\n')
362
runcmd('bzr move sub2/hello.txt .')
363
assert exists('hello.txt')
365
f = file('hello.txt', 'wt')
366
f.write('some nice new content\n')
369
f = file('msg.tmp', 'wt')
370
f.write('this is my new commit\n')
373
runcmd('bzr commit -F msg.tmp')
375
assert backtick('bzr revno') == '5\n'
376
runcmd('bzr export -r 5 export-5.tmp')
377
runcmd('bzr export export.tmp')
384
progress("file with spaces in name")
385
mkdir('sub directory')
386
file('sub directory/file with spaces ', 'wt').write('see how this works\n')
389
runcmd('bzr commit -m add-spaces')
393
runcmd('bzr log --forward')
405
# Can't create a branch if it already exists
406
runcmd('bzr branch branch1', retcode=1)
407
# Can't create a branch if its parent doesn't exist
408
runcmd('bzr branch /unlikely/to/exist', retcode=1)
409
runcmd('bzr branch branch1 branch2')
413
runcmd('bzr pull', retcode=1)
414
runcmd('bzr pull ../branch2')
417
runcmd('bzr commit -m empty')
421
runcmd('bzr commit -m empty')
423
runcmd('bzr commit -m empty')
424
runcmd('bzr pull', retcode=1)
427
progress('status after remove')
428
mkdir('status-after-remove')
429
# see mail from William Dodé, 2005-05-25
430
# $ bzr init; touch a; bzr add a; bzr commit -m "add a"
431
# * looking for changes...
436
# bzr: local variable 'kind' referenced before assignment
437
# at /vrac/python/bazaar-ng/bzrlib/diff.py:286 in compare_trees()
438
# see ~/.bzr.log for debug information
439
cd('status-after-remove')
441
file('a', 'w').write('foo')
443
runcmd(['bzr', 'commit', '-m', 'add a'])
444
runcmd('bzr remove a')
449
progress('ignore patterns')
450
mkdir('ignorebranch')
453
assert backtick('bzr unknowns') == ''
455
file('foo.tmp', 'wt').write('tmp files are ignored')
456
assert backtick('bzr unknowns') == ''
458
file('foo.c', 'wt').write('int main() {}')
459
assert backtick('bzr unknowns') == 'foo.c\n'
460
runcmd('bzr add foo.c')
461
assert backtick('bzr unknowns') == ''
463
# 'ignore' works when creating the .bzignore file
464
file('foo.blah', 'wt').write('blah')
465
assert backtick('bzr unknowns') == 'foo.blah\n'
466
runcmd('bzr ignore *.blah')
467
assert backtick('bzr unknowns') == ''
468
assert file('.bzrignore', 'rb').read() == '*.blah\n'
470
# 'ignore' works when then .bzrignore file already exists
471
file('garh', 'wt').write('garh')
472
assert backtick('bzr unknowns') == 'garh\n'
473
runcmd('bzr ignore garh')
474
assert backtick('bzr unknowns') == ''
475
assert file('.bzrignore', 'rb').read() == '*.blah\ngarh\n'
482
progress("recursive and non-recursive add")
487
fp = os.path.join('foo', 'test.txt')
491
runcmd('bzr add --no-recurse foo')
492
runcmd('bzr file-id foo')
493
runcmd('bzr file-id ' + fp, 1) # not versioned yet
494
runcmd('bzr commit -m add-dir-only')
496
runcmd('bzr file-id ' + fp, 1) # still not versioned
498
runcmd('bzr add foo')
499
runcmd('bzr file-id ' + fp)
500
runcmd('bzr commit -m add-sub-file')
507
# Run any function in this
512
if k.startswith('test_') and callable(g[k]):
513
progress(k[5:].replace('_', ' '))
516
progress("all tests passed!")
518
sys.stderr.write('*' * 50 + '\n'
519
+ 'testbzr: tests failed\n'
520
+ 'see ' + LOGFILENAME + ' for more information\n'
522
logfile.write('tests failed!\n')
523
traceback.print_exc(None, logfile)
526
sys.stdout.writelines(file(os.path.join(start_dir, LOGFILENAME), 'rt').readlines()[-50:])