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.
157
f = open(os.path.join('plugin_test', 'myplug.py'), 'wb')
158
f.write("""import bzrlib, bzrlib.commands
159
class cmd_myplug(bzrlib.commands.Command):
160
'''Just a simple test plugin.'''
163
print 'Hello from my plugin'
167
os.environ['BZRPLUGINPATH'] = os.path.abspath('plugin_test')
168
help = backtick('bzr help commands')
169
assert help.find('myplug') != -1
170
assert help.find('Just a simple test plugin.') != -1
173
assert backtick('bzr myplug') == 'Hello from my plugin\n'
174
assert backtick('bzr mplg') == 'Hello from my plugin\n'
176
f = open(os.path.join('plugin_test', 'override.py'), 'wb')
177
f.write("""import bzrlib, bzrlib.commands
178
class cmd_commit(bzrlib.commands.cmd_commit):
179
'''Commit changes into a new revision.'''
180
def run(self, *args, **kwargs):
181
print "I'm sorry dave, you can't do that"
183
class cmd_help(bzrlib.commands.cmd_help):
184
'''Show help on a command or other topic.'''
185
def run(self, *args, **kwargs):
186
print "You have been overridden"
187
bzrlib.commands.cmd_help.run(self, *args, **kwargs)
192
newhelp = backtick('bzr help commands')
193
assert newhelp.startswith('You have been overridden\n')
194
# We added a line, but the rest should work
195
assert newhelp[25:] == help
197
assert backtick('bzr commit -m test') == "I'm sorry dave, you can't do that\n"
199
shutil.rmtree('plugin_test')
202
from getopt import getopt
203
opts, args = getopt(sys.argv[1:], 'p:')
205
for option, value in opts:
207
OVERRIDE_PYTHON = value
210
mypath = os.path.abspath(sys.argv[0])
211
print '%-30s %s' % ('running tests from', mypath)
218
BZRPATH = os.path.join(os.path.split(mypath)[0], 'bzr')
220
print '%-30s %s' % ('against bzr', BZRPATH)
221
print '%-30s %s' % ('in directory', os.getcwd())
222
print '%-30s %s' % ('with python', (OVERRIDE_PYTHON or '(default)'))
224
print backtick('bzr version')
226
runcmd(['mkdir', TESTDIR])
228
test_root = os.getcwd()
230
progress("introductory commands")
231
runcmd("bzr version")
232
runcmd("bzr --version")
236
progress("internal tests")
237
runcmd("bzr selftest")
239
progress("user identity")
240
# this should always identify something, if only "john@localhost"
242
runcmd("bzr whoami --email")
243
assert backtick("bzr whoami --email").count('@') == 1
245
progress("invalid commands")
246
runcmd("bzr pants", retcode=1)
247
runcmd("bzr --pants off", retcode=1)
248
runcmd("bzr diff --message foo", retcode=1)
250
progress("basic branch creation")
251
runcmd(['mkdir', 'branch1'])
255
assert backtick('bzr root')[:-1] == os.path.join(test_root, 'branch1')
257
progress("status of new file")
259
f = file('test.txt', 'wt')
260
f.write('hello world!\n')
263
out = backtick("bzr unknowns")
264
assert out == 'test.txt\n'
266
out = backtick("bzr status")
267
assert out == 'unknown:\n test.txt\n'
269
out = backtick("bzr status --all")
270
assert out == "unknown:\n test.txt\n"
272
out = backtick("bzr status test.txt --all")
273
assert out == "unknown:\n test.txt\n"
275
f = file('test2.txt', 'wt')
276
f.write('goodbye cruel world...\n')
279
out = backtick("bzr status test.txt")
280
assert out == "unknown:\n test.txt\n"
282
out = backtick("bzr status")
283
assert out == ("unknown:\n"
287
os.unlink('test2.txt')
289
progress("command aliases")
290
out = backtick("bzr st --all")
291
assert out == ("unknown:\n"
294
out = backtick("bzr stat")
295
assert out == ("unknown:\n"
298
progress("command help")
299
runcmd("bzr help st")
301
runcmd("bzr help commands")
302
runcmd("bzr help slartibartfast", 1)
304
out = backtick("bzr help ci")
305
out.index('aliases: ')
307
progress("can't rename unversioned file")
308
runcmd("bzr rename test.txt new-test.txt", 1)
310
progress("adding a file")
312
runcmd("bzr add test.txt")
313
assert backtick("bzr unknowns") == ''
314
assert backtick("bzr status --all") == ("added:\n"
317
progress("rename newly-added file")
318
runcmd("bzr rename test.txt hello.txt")
319
assert os.path.exists("hello.txt")
320
assert not os.path.exists("test.txt")
322
assert backtick("bzr revno") == '0\n'
324
progress("add first revision")
325
runcmd(["bzr", "commit", "-m", 'add first revision'])
327
progress("more complex renames")
329
runcmd("bzr rename hello.txt sub1", 1)
330
runcmd("bzr rename hello.txt sub1/hello.txt", 1)
331
runcmd("bzr move hello.txt sub1", 1)
333
runcmd("bzr add sub1")
334
runcmd("bzr rename sub1 sub2")
335
runcmd("bzr move hello.txt sub2")
336
assert backtick("bzr relpath sub2/hello.txt") == os.path.join("sub2", "hello.txt\n")
338
assert exists("sub2")
339
assert exists("sub2/hello.txt")
340
assert not exists("sub1")
341
assert not exists("hello.txt")
343
runcmd(['bzr', 'commit', '-m', 'commit with some things moved to subdirs'])
346
runcmd('bzr add sub1')
347
runcmd('bzr move sub2/hello.txt sub1')
348
assert not exists('sub2/hello.txt')
349
assert exists('sub1/hello.txt')
350
runcmd('bzr move sub2 sub1')
351
assert not exists('sub2')
352
assert exists('sub1/sub2')
354
runcmd(['bzr', 'commit', '-m', 'rename nested subdirectories'])
357
assert backtick('bzr root')[:-1] == os.path.join(test_root, 'branch1')
358
runcmd('bzr move ../hello.txt .')
359
assert exists('./hello.txt')
360
assert backtick('bzr relpath hello.txt') == os.path.join('sub1', 'sub2', 'hello.txt\n')
361
assert backtick('bzr relpath ../../sub1/sub2/hello.txt') == os.path.join('sub1', 'sub2', 'hello.txt\n')
362
runcmd(['bzr', 'commit', '-m', 'move to parent directory'])
364
assert backtick('bzr relpath sub2/hello.txt') == os.path.join('sub1', 'sub2', 'hello.txt\n')
366
runcmd('bzr move sub2/hello.txt .')
367
assert exists('hello.txt')
369
f = file('hello.txt', 'wt')
370
f.write('some nice new content\n')
373
f = file('msg.tmp', 'wt')
374
f.write('this is my new commit\n')
377
runcmd('bzr commit -F msg.tmp')
379
assert backtick('bzr revno') == '5\n'
380
runcmd('bzr export -r 5 export-5.tmp')
381
runcmd('bzr export export.tmp')
388
progress("file with spaces in name")
389
mkdir('sub directory')
390
file('sub directory/file with spaces ', 'wt').write('see how this works\n')
393
runcmd('bzr commit -m add-spaces')
397
runcmd('bzr log --forward')
409
# Can't create a branch if it already exists
410
runcmd('bzr branch branch1', retcode=1)
411
# Can't create a branch if its parent doesn't exist
412
runcmd('bzr branch /unlikely/to/exist', retcode=1)
413
runcmd('bzr branch branch1 branch2')
417
runcmd('bzr pull', retcode=1)
418
runcmd('bzr pull ../branch2')
421
runcmd('bzr commit -m empty')
425
runcmd('bzr commit -m empty')
427
runcmd('bzr commit -m empty')
428
runcmd('bzr pull', retcode=1)
431
progress('status after remove')
432
mkdir('status-after-remove')
433
# see mail from William Dodé, 2005-05-25
434
# $ bzr init; touch a; bzr add a; bzr commit -m "add a"
435
# * looking for changes...
440
# bzr: local variable 'kind' referenced before assignment
441
# at /vrac/python/bazaar-ng/bzrlib/diff.py:286 in compare_trees()
442
# see ~/.bzr.log for debug information
443
cd('status-after-remove')
445
file('a', 'w').write('foo')
447
runcmd(['bzr', 'commit', '-m', 'add a'])
448
runcmd('bzr remove a')
453
progress('ignore patterns')
454
mkdir('ignorebranch')
457
assert backtick('bzr unknowns') == ''
459
file('foo.tmp', 'wt').write('tmp files are ignored')
460
assert backtick('bzr unknowns') == ''
462
file('foo.c', 'wt').write('int main() {}')
463
assert backtick('bzr unknowns') == 'foo.c\n'
464
runcmd('bzr add foo.c')
465
assert backtick('bzr unknowns') == ''
467
# 'ignore' works when creating the .bzignore file
468
file('foo.blah', 'wt').write('blah')
469
assert backtick('bzr unknowns') == 'foo.blah\n'
470
runcmd('bzr ignore *.blah')
471
assert backtick('bzr unknowns') == ''
472
assert file('.bzrignore', 'rb').read() == '*.blah\n'
474
# 'ignore' works when then .bzrignore file already exists
475
file('garh', 'wt').write('garh')
476
assert backtick('bzr unknowns') == 'garh\n'
477
runcmd('bzr ignore garh')
478
assert backtick('bzr unknowns') == ''
479
assert file('.bzrignore', 'rb').read() == '*.blah\ngarh\n'
486
progress("recursive and non-recursive add")
491
fp = os.path.join('foo', 'test.txt')
495
runcmd('bzr add --no-recurse foo')
496
runcmd('bzr file-id foo')
497
runcmd('bzr file-id ' + fp, 1) # not versioned yet
498
runcmd('bzr commit -m add-dir-only')
500
runcmd('bzr file-id ' + fp, 1) # still not versioned
502
runcmd('bzr add foo')
503
runcmd('bzr file-id ' + fp)
504
runcmd('bzr commit -m add-sub-file')
511
# Run any function in this
516
if k.startswith('test_') and callable(g[k]):
517
progress(k[5:].replace('_', ' '))
520
progress("all tests passed!")
522
sys.stderr.write('*' * 50 + '\n'
523
+ 'testbzr: tests failed\n'
524
+ 'see ' + LOGFILENAME + ' for more information\n'
526
logfile.write('tests failed!\n')
527
traceback.print_exc(None, logfile)
530
sys.stdout.writelines(file(os.path.join(start_dir, LOGFILENAME), 'rt').readlines()[-50:])