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
from getopt import getopt
154
opts, args = getopt(sys.argv[1:], 'p:')
156
for option, value in opts:
158
OVERRIDE_PYTHON = value
161
mypath = os.path.abspath(sys.argv[0])
162
print '%-30s %s' % ('running tests from', mypath)
169
BZRPATH = os.path.join(os.path.split(mypath)[0], 'bzr')
171
print '%-30s %s' % ('against bzr', BZRPATH)
172
print '%-30s %s' % ('in directory', os.getcwd())
173
print '%-30s %s' % ('with python', (OVERRIDE_PYTHON or '(default)'))
175
print backtick('bzr version')
177
runcmd(['mkdir', TESTDIR])
179
# This means that any command that is naively run in this directory
180
# Won't affect the parent directory.
182
test_root = os.getcwd()
184
progress("introductory commands")
185
runcmd("bzr version")
186
runcmd("bzr --version")
190
progress("internal tests")
191
runcmd("bzr selftest")
193
progress("invalid commands")
194
runcmd("bzr pants", retcode=1)
195
runcmd("bzr --pants off", retcode=1)
196
runcmd("bzr diff --message foo", retcode=1)
198
progress("basic branch creation")
199
runcmd(['mkdir', 'branch1'])
203
assert backtick('bzr root')[:-1] == os.path.join(test_root, 'branch1')
205
progress("status of new file")
207
f = file('test.txt', 'wt')
208
f.write('hello world!\n')
211
out = backtick("bzr unknowns")
212
assert out == 'test.txt\n'
214
out = backtick("bzr status")
215
assert out == 'unknown:\n test.txt\n'
217
out = backtick("bzr status --all")
218
assert out == "unknown:\n test.txt\n"
220
out = backtick("bzr status test.txt --all")
221
assert out == "unknown:\n test.txt\n"
223
f = file('test2.txt', 'wt')
224
f.write('goodbye cruel world...\n')
227
out = backtick("bzr status test.txt")
228
assert out == "unknown:\n test.txt\n"
230
out = backtick("bzr status")
231
assert out == ("unknown:\n"
235
os.unlink('test2.txt')
237
progress("command aliases")
238
out = backtick("bzr st --all")
239
assert out == ("unknown:\n"
242
out = backtick("bzr stat")
243
assert out == ("unknown:\n"
246
progress("command help")
247
runcmd("bzr help st")
249
runcmd("bzr help commands")
250
runcmd("bzr help slartibartfast", 1)
252
out = backtick("bzr help ci")
253
out.index('aliases: ')
255
progress("can't rename unversioned file")
256
runcmd("bzr rename test.txt new-test.txt", 1)
258
progress("adding a file")
260
runcmd("bzr add test.txt")
261
assert backtick("bzr unknowns") == ''
262
assert backtick("bzr status --all") == ("added:\n"
265
progress("rename newly-added file")
266
runcmd("bzr rename test.txt hello.txt")
267
assert os.path.exists("hello.txt")
268
assert not os.path.exists("test.txt")
270
assert backtick("bzr revno") == '0\n'
272
progress("add first revision")
273
runcmd(["bzr", "commit", "-m", 'add first revision'])
275
progress("more complex renames")
277
runcmd("bzr rename hello.txt sub1", 1)
278
runcmd("bzr rename hello.txt sub1/hello.txt", 1)
279
runcmd("bzr move hello.txt sub1", 1)
281
runcmd("bzr add sub1")
282
runcmd("bzr rename sub1 sub2")
283
runcmd("bzr move hello.txt sub2")
284
assert backtick("bzr relpath sub2/hello.txt") == os.path.join("sub2", "hello.txt\n")
286
assert exists("sub2")
287
assert exists("sub2/hello.txt")
288
assert not exists("sub1")
289
assert not exists("hello.txt")
291
runcmd(['bzr', 'commit', '-m', 'commit with some things moved to subdirs'])
294
runcmd('bzr add sub1')
295
runcmd('bzr move sub2/hello.txt sub1')
296
assert not exists('sub2/hello.txt')
297
assert exists('sub1/hello.txt')
298
runcmd('bzr move sub2 sub1')
299
assert not exists('sub2')
300
assert exists('sub1/sub2')
302
runcmd(['bzr', 'commit', '-m', 'rename nested subdirectories'])
305
assert backtick('bzr root')[:-1] == os.path.join(test_root, 'branch1')
306
runcmd('bzr move ../hello.txt .')
307
assert exists('./hello.txt')
308
assert backtick('bzr relpath hello.txt') == os.path.join('sub1', 'sub2', 'hello.txt\n')
309
assert backtick('bzr relpath ../../sub1/sub2/hello.txt') == os.path.join('sub1', 'sub2', 'hello.txt\n')
310
runcmd(['bzr', 'commit', '-m', 'move to parent directory'])
312
assert backtick('bzr relpath sub2/hello.txt') == os.path.join('sub1', 'sub2', 'hello.txt\n')
314
runcmd('bzr move sub2/hello.txt .')
315
assert exists('hello.txt')
317
f = file('hello.txt', 'wt')
318
f.write('some nice new content\n')
321
f = file('msg.tmp', 'wt')
322
f.write('this is my new commit\n')
325
runcmd('bzr commit -F msg.tmp')
327
assert backtick('bzr revno') == '5\n'
328
runcmd('bzr export -r 5 export-5.tmp')
329
runcmd('bzr export export.tmp')
336
progress("file with spaces in name")
337
mkdir('sub directory')
338
file('sub directory/file with spaces ', 'wt').write('see how this works\n')
341
runcmd('bzr commit -m add-spaces')
345
runcmd('bzr log --forward')
357
# Can't create a branch if it already exists
358
runcmd('bzr branch branch1', retcode=1)
359
# Can't create a branch if its parent doesn't exist
360
runcmd('bzr branch /unlikely/to/exist', retcode=1)
361
runcmd('bzr branch branch1 branch2')
365
runcmd('bzr pull', retcode=1)
366
runcmd('bzr pull ../branch2')
369
runcmd('bzr commit -m empty')
373
runcmd('bzr commit -m empty')
375
runcmd('bzr commit -m empty')
376
runcmd('bzr pull', retcode=1)
379
progress('status after remove')
380
mkdir('status-after-remove')
381
# see mail from William Dodé, 2005-05-25
382
# $ bzr init; touch a; bzr add a; bzr commit -m "add a"
383
# * looking for changes...
388
# bzr: local variable 'kind' referenced before assignment
389
# at /vrac/python/bazaar-ng/bzrlib/diff.py:286 in compare_trees()
390
# see ~/.bzr.log for debug information
391
cd('status-after-remove')
393
file('a', 'w').write('foo')
395
runcmd(['bzr', 'commit', '-m', 'add a'])
396
runcmd('bzr remove a')
401
progress('ignore patterns')
402
mkdir('ignorebranch')
405
assert backtick('bzr unknowns') == ''
407
file('foo.tmp', 'wt').write('tmp files are ignored')
408
assert backtick('bzr unknowns') == ''
410
file('foo.c', 'wt').write('int main() {}')
411
assert backtick('bzr unknowns') == 'foo.c\n'
412
runcmd('bzr add foo.c')
413
assert backtick('bzr unknowns') == ''
415
# 'ignore' works when creating the .bzignore file
416
file('foo.blah', 'wt').write('blah')
417
assert backtick('bzr unknowns') == 'foo.blah\n'
418
runcmd('bzr ignore *.blah')
419
assert backtick('bzr unknowns') == ''
420
assert file('.bzrignore', 'rb').read() == '*.blah\n'
422
# 'ignore' works when then .bzrignore file already exists
423
file('garh', 'wt').write('garh')
424
assert backtick('bzr unknowns') == 'garh\n'
425
runcmd('bzr ignore garh')
426
assert backtick('bzr unknowns') == ''
427
assert file('.bzrignore', 'rb').read() == '*.blah\ngarh\n'
434
progress("recursive and non-recursive add")
439
fp = os.path.join('foo', 'test.txt')
443
runcmd('bzr add --no-recurse foo')
444
runcmd('bzr file-id foo')
445
runcmd('bzr file-id ' + fp, 1) # not versioned yet
446
runcmd('bzr commit -m add-dir-only')
448
runcmd('bzr file-id ' + fp, 1) # still not versioned
450
runcmd('bzr add foo')
451
runcmd('bzr file-id ' + fp)
452
runcmd('bzr commit -m add-sub-file')
459
# Run any function in this
464
if k.startswith('test_') and callable(g[k]):
465
progress(k[5:].replace('_', ' '))
468
progress("all tests passed!")
470
sys.stderr.write('*' * 50 + '\n'
471
+ 'testbzr: tests failed\n'
472
+ 'see ' + LOGFILENAME + ' for more information\n'
474
logfile.write('tests failed!\n')
475
traceback.print_exc(None, logfile)
478
sys.stdout.writelines(file(os.path.join(start_dir, LOGFILENAME), 'rt').readlines()[-50:])