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
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"
49
OVERRIDE_PYTHON = None
51
LOGFILENAME = 'testbzr.log'
55
from subprocess import call, Popen, PIPE
56
except ImportError, e:
57
sys.stderr.write("testbzr: sorry, this test suite requires modules from python2.4\n"
62
class CommandFailed(Exception):
67
if isinstance(cmd, basestring):
73
cmd.insert(0, OVERRIDE_PYTHON)
75
logfile.write('$ %r\n' % cmd)
80
def runcmd(cmd, retcode=0):
81
"""Run one command and check the return code.
83
Returns a tuple of (stdout,stderr) strings.
85
If a single string is based, it is split into words.
86
For commands that are not simple space-separated words, please
87
pass a list instead."""
91
actual_retcode = call(cmd, stdout=logfile, stderr=logfile)
93
if retcode != actual_retcode:
94
raise CommandFailed("test failed: %r returned %d, expected %d"
95
% (cmd, actual_retcode, retcode))
99
def backtick(cmd, retcode=0):
102
child = Popen(cmd, stdout=PIPE, stderr=logfile)
103
outd, errd = child.communicate()
105
actual_retcode = child.wait()
107
outd = outd.replace('\r', '')
109
if retcode != actual_retcode:
110
raise CommandFailed("test failed: %r returned %d, expected %d"
111
% (cmd, actual_retcode, retcode))
119
logfile.write('* '+ msg + '\n')
124
logfile.write('$ cd %s\n' % dirname)
129
def log_linenumber():
130
"""Log the stack frame location two things up."""
131
stack = traceback.extract_stack()[-3]
132
logfile.write(' at %s:%d\n' % stack[:2])
136
# prepare an empty scratch directory
137
if os.path.exists(TESTDIR):
138
shutil.rmtree(TESTDIR)
140
start_dir = os.getcwd()
143
logfile = open(LOGFILENAME, 'wt', buffering=1)
147
from getopt import getopt
148
opts, args = getopt(sys.argv[1:], 'p:')
150
for option, value in opts:
152
OVERRIDE_PYTHON = value
155
mypath = os.path.abspath(sys.argv[0])
156
print '%-30s %s' % ('running tests from', mypath)
163
BZRPATH = os.path.join(os.path.split(mypath)[0], 'bzr')
165
print '%-30s %s' % ('against bzr', BZRPATH)
166
print '%-30s %s' % ('in directory', os.getcwd())
167
print '%-30s %s' % ('with python', (OVERRIDE_PYTHON or '(default)'))
169
print backtick([BZRPATH, 'version'])
171
runcmd(['mkdir', TESTDIR])
173
test_root = os.getcwd()
175
progress("introductory commands")
176
runcmd("bzr version")
177
runcmd("bzr --version")
181
progress("internal tests")
182
runcmd("bzr selftest")
184
progress("user identity")
185
# this should always identify something, if only "john@localhost"
187
runcmd("bzr whoami --email")
188
assert backtick("bzr whoami --email").count('@') == 1
190
progress("invalid commands")
191
runcmd("bzr pants", retcode=1)
192
runcmd("bzr --pants off", retcode=1)
193
runcmd("bzr diff --message foo", retcode=1)
195
progress("basic branch creation")
196
runcmd(['mkdir', 'branch1'])
200
assert backtick('bzr root')[:-1] == os.path.join(test_root, 'branch1')
202
progress("status of new file")
204
f = file('test.txt', 'wt')
205
f.write('hello world!\n')
208
out = backtick("bzr unknowns")
209
assert out == 'test.txt\n'
211
out = backtick("bzr status")
212
assert out == 'unknown:\n test.txt\n'
214
out = backtick("bzr status --all")
215
assert out == "unknown:\n test.txt\n"
217
out = backtick("bzr status test.txt --all")
218
assert out == "unknown:\n test.txt\n"
220
f = file('test2.txt', 'wt')
221
f.write('goodbye cruel world...\n')
224
out = backtick("bzr status test.txt")
225
assert out == "unknown:\n test.txt\n"
227
out = backtick("bzr status")
228
assert out == ("unknown:\n"
232
os.unlink('test2.txt')
234
progress("command aliases")
235
out = backtick("bzr st --all")
236
assert out == ("unknown:\n"
239
out = backtick("bzr stat")
240
assert out == ("unknown:\n"
243
progress("command help")
244
runcmd("bzr help st")
246
runcmd("bzr help commands")
247
runcmd("bzr help slartibartfast", 1)
249
out = backtick("bzr help ci")
250
out.index('aliases: ')
252
progress("can't rename unversioned file")
253
runcmd("bzr rename test.txt new-test.txt", 1)
255
progress("adding a file")
257
runcmd("bzr add test.txt")
258
assert backtick("bzr unknowns") == ''
259
assert backtick("bzr status --all") == ("added:\n"
262
progress("rename newly-added file")
263
runcmd("bzr rename test.txt hello.txt")
264
assert os.path.exists("hello.txt")
265
assert not os.path.exists("test.txt")
267
assert backtick("bzr revno") == '0\n'
269
progress("add first revision")
270
runcmd(["bzr", "commit", "-m", 'add first revision'])
272
progress("more complex renames")
274
runcmd("bzr rename hello.txt sub1", 1)
275
runcmd("bzr rename hello.txt sub1/hello.txt", 1)
276
runcmd("bzr move hello.txt sub1", 1)
278
runcmd("bzr add sub1")
279
runcmd("bzr rename sub1 sub2")
280
runcmd("bzr move hello.txt sub2")
281
assert backtick("bzr relpath sub2/hello.txt") == os.path.join("sub2", "hello.txt\n")
283
assert exists("sub2")
284
assert exists("sub2/hello.txt")
285
assert not exists("sub1")
286
assert not exists("hello.txt")
288
runcmd(['bzr', 'commit', '-m', 'commit with some things moved to subdirs'])
291
runcmd('bzr add sub1')
292
runcmd('bzr move sub2/hello.txt sub1')
293
assert not exists('sub2/hello.txt')
294
assert exists('sub1/hello.txt')
295
runcmd('bzr move sub2 sub1')
296
assert not exists('sub2')
297
assert exists('sub1/sub2')
299
runcmd(['bzr', 'commit', '-m', 'rename nested subdirectories'])
302
assert backtick('bzr root')[:-1] == os.path.join(test_root, 'branch1')
303
runcmd('bzr move ../hello.txt .')
304
assert exists('./hello.txt')
305
assert backtick('bzr relpath hello.txt') == os.path.join('sub1', 'sub2', 'hello.txt\n')
306
assert backtick('bzr relpath ../../sub1/sub2/hello.txt') == os.path.join('sub1', 'sub2', 'hello.txt\n')
307
runcmd(['bzr', 'commit', '-m', 'move to parent directory'])
309
assert backtick('bzr relpath sub2/hello.txt') == os.path.join('sub1', 'sub2', 'hello.txt\n')
311
runcmd('bzr move sub2/hello.txt .')
312
assert exists('hello.txt')
314
f = file('hello.txt', 'wt')
315
f.write('some nice new content\n')
318
f = file('msg.tmp', 'wt')
319
f.write('this is my new commit\n')
322
runcmd('bzr commit -F msg.tmp')
324
assert backtick('bzr revno') == '5\n'
325
runcmd('bzr export -r 5 export-5.tmp')
326
runcmd('bzr export export.tmp')
333
progress("file with spaces in name")
334
mkdir('sub directory')
335
file('sub directory/file with spaces ', 'wt').write('see how this works\n')
338
runcmd('bzr commit -m add-spaces')
342
runcmd('bzr log --forward')
351
progress('status after remove')
352
mkdir('status-after-remove')
353
# see mail from William Dodé, 2005-05-25
354
# $ bzr init; touch a; bzr add a; bzr commit -m "add a"
355
# * looking for changes...
360
# bzr: local variable 'kind' referenced before assignment
361
# at /vrac/python/bazaar-ng/bzrlib/diff.py:286 in compare_trees()
362
# see ~/.bzr.log for debug information
363
cd('status-after-remove')
365
file('a', 'w').write('foo')
367
runcmd(['bzr', 'commit', '-m', 'add a'])
368
runcmd('bzr remove a')
373
progress('ignore patterns')
374
mkdir('ignorebranch')
377
assert backtick('bzr unknowns') == ''
379
file('foo.tmp', 'wt').write('tmp files are ignored')
380
assert backtick('bzr unknowns') == ''
382
file('foo.c', 'wt').write('int main() {}')
383
assert backtick('bzr unknowns') == 'foo.c\n'
384
runcmd('bzr add foo.c')
385
assert backtick('bzr unknowns') == ''
387
# 'ignore' works when creating the .bzignore file
388
file('foo.blah', 'wt').write('blah')
389
assert backtick('bzr unknowns') == 'foo.blah\n'
390
runcmd('bzr ignore *.blah')
391
assert backtick('bzr unknowns') == ''
392
assert file('.bzrignore', 'rb').read() == '*.blah\n'
394
# 'ignore' works when then .bzrignore file already exists
395
file('garh', 'wt').write('garh')
396
assert backtick('bzr unknowns') == 'garh\n'
397
runcmd('bzr ignore garh')
398
assert backtick('bzr unknowns') == ''
399
assert file('.bzrignore', 'rb').read() == '*.blah\ngarh\n'
403
progress("all tests passed!")
405
sys.stderr.write('*' * 50 + '\n'
406
+ 'testbzr: tests failed\n'
407
+ 'see ' + LOGFILENAME + ' for more information\n'
409
logfile.write('tests failed!\n')
410
traceback.print_exc(None, logfile)
413
sys.stdout.writelines(file(os.path.join(start_dir, LOGFILENAME), 'rt').readlines()[-50:])