~bzr-pqm/bzr/bzr.dev

292 by Martin Pool
- start adding a pure-python blackbox test suite
1
#! /usr/bin/python
2
3
# Copyright (C) 2005 Canonical Ltd
4
5
# This program is free software; you can redistribute it and/or modify
6
# it under the terms of the GNU General Public License as published by
7
# the Free Software Foundation; either version 2 of the License, or
8
# (at your option) any later version.
9
10
# This program is distributed in the hope that it will be useful,
11
# but WITHOUT ANY WARRANTY; without even the implied warranty of
12
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13
# GNU General Public License for more details.
14
15
# You should have received a copy of the GNU General Public License
16
# along with this program; if not, write to the Free Software
17
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
18
19
20
"""External black-box test for bzr.
21
22
This always runs bzr as an external process to try to catch bugs
23
related to argument processing, startup, etc.
24
507 by Martin Pool
- new -p option for testbzr to use a different version of python
25
usage:
26
27
    testbzr [-p PYTHON] [BZR]
28
29
By default this tests the copy of bzr found in the same directory as
30
testbzr, or the first one found on the $PATH.  A copy of bzr may be
31
given on the command line to override this, for example when applying
32
a new test suite to an old copy of bzr or vice versa.
33
34
testbzr normally invokes bzr using the same version of python as it
35
would normally use to run -- that is, the system default python,
36
unless that is older than 2.3.  The -p option allows specification of
37
a different Python interpreter, such as when testing that bzr still
38
works on python2.3.
39
292 by Martin Pool
- start adding a pure-python blackbox test suite
40
This replaces the previous test.sh which was not very portable."""
41
296 by Martin Pool
- better reports from testbzr when it fails
42
import sys, os, traceback
339 by Martin Pool
many more diffs
43
from os import mkdir
44
from os.path import exists
292 by Martin Pool
- start adding a pure-python blackbox test suite
45
335 by Martin Pool
- add new failing test for command parsing
46
TESTDIR = "testbzr.tmp"
47
507 by Martin Pool
- new -p option for testbzr to use a different version of python
48
OVERRIDE_PYTHON = None
49
335 by Martin Pool
- add new failing test for command parsing
50
LOGFILENAME = 'testbzr.log'
51
292 by Martin Pool
- start adding a pure-python blackbox test suite
52
try:
53
    import shutil
301 by Martin Pool
- provide for catching output from shell commands
54
    from subprocess import call, Popen, PIPE
292 by Martin Pool
- start adding a pure-python blackbox test suite
55
except ImportError, e:
56
    sys.stderr.write("testbzr: sorry, this test suite requires modules from python2.4\n"
57
                     + '    ' + str(e))
58
    sys.exit(1)
59
60
296 by Martin Pool
- better reports from testbzr when it fails
61
class CommandFailed(Exception):
62
    pass
63
64
302 by Martin Pool
testbzr: new backtick() helper
65
def formcmd(cmd):
66
    if isinstance(cmd, basestring):
67
        cmd = cmd.split()
68
398 by Martin Pool
- testbzr finds the right version of bzr to test
69
    if cmd[0] == 'bzr':
70
        cmd[0] = BZRPATH
507 by Martin Pool
- new -p option for testbzr to use a different version of python
71
        if OVERRIDE_PYTHON:
72
            cmd.insert(0, OVERRIDE_PYTHON)
398 by Martin Pool
- testbzr finds the right version of bzr to test
73
507 by Martin Pool
- new -p option for testbzr to use a different version of python
74
    logfile.write('$ %r\n' % cmd)
75
    
302 by Martin Pool
testbzr: new backtick() helper
76
    return cmd
77
78
79
def runcmd(cmd, retcode=0):
300 by Martin Pool
- more tests
80
    """Run one command and check the return code.
292 by Martin Pool
- start adding a pure-python blackbox test suite
81
301 by Martin Pool
- provide for catching output from shell commands
82
    Returns a tuple of (stdout,stderr) strings.
83
292 by Martin Pool
- start adding a pure-python blackbox test suite
84
    If a single string is based, it is split into words.
85
    For commands that are not simple space-separated words, please
86
    pass a list instead."""
302 by Martin Pool
testbzr: new backtick() helper
87
    cmd = formcmd(cmd)
88
    log_linenumber()
89
    
90
    actual_retcode = call(cmd, stdout=logfile, stderr=logfile)
91
    
92
    if retcode != actual_retcode:
93
        raise CommandFailed("test failed: %r returned %d, expected %d"
94
                            % (cmd, actual_retcode, retcode))
95
96
97
98
def backtick(cmd, retcode=0):
99
    cmd = formcmd(cmd)
100
    log_linenumber()
101
    child = Popen(cmd, stdout=PIPE, stderr=logfile)
301 by Martin Pool
- provide for catching output from shell commands
102
    outd, errd = child.communicate()
302 by Martin Pool
testbzr: new backtick() helper
103
    logfile.write(outd)
301 by Martin Pool
- provide for catching output from shell commands
104
    actual_retcode = child.wait()
307 by Martin Pool
testbzr: clean up crlf handling
105
106
    outd = outd.replace('\r', '')
301 by Martin Pool
- provide for catching output from shell commands
107
    
298 by Martin Pool
- test some commands known to fail
108
    if retcode != actual_retcode:
109
        raise CommandFailed("test failed: %r returned %d, expected %d"
110
                            % (cmd, actual_retcode, retcode))
292 by Martin Pool
- start adding a pure-python blackbox test suite
111
302 by Martin Pool
testbzr: new backtick() helper
112
    return outd
113
301 by Martin Pool
- provide for catching output from shell commands
114
292 by Martin Pool
- start adding a pure-python blackbox test suite
115
116
def progress(msg):
117
    print '* ' + msg
118
    logfile.write('* '+ msg + '\n')
297 by Martin Pool
- fix intentional testcase failure
119
    log_linenumber()
120
121
299 by Martin Pool
testbzr:
122
def cd(dirname):
123
    logfile.write('$ cd %s\n' % dirname)
124
    os.chdir(dirname)
125
126
300 by Martin Pool
- more tests
127
297 by Martin Pool
- fix intentional testcase failure
128
def log_linenumber():
129
    """Log the stack frame location two things up."""
130
    stack = traceback.extract_stack()[-3]
131
    logfile.write('   at %s:%d\n' % stack[:2])
132
133
340 by Martin Pool
- more testcase fixes
134
292 by Martin Pool
- start adding a pure-python blackbox test suite
135
# prepare an empty scratch directory
136
if os.path.exists(TESTDIR):
137
    shutil.rmtree(TESTDIR)
138
513 by Martin Pool
- show some log output if the tests fail
139
start_dir = os.getcwd()
140
292 by Martin Pool
- start adding a pure-python blackbox test suite
141
335 by Martin Pool
- add new failing test for command parsing
142
logfile = open(LOGFILENAME, 'wt', buffering=1)
292 by Martin Pool
- start adding a pure-python blackbox test suite
143
144
300 by Martin Pool
- more tests
145
try:
507 by Martin Pool
- new -p option for testbzr to use a different version of python
146
    from getopt import getopt
147
    opts, args = getopt(sys.argv[1:], 'p:')
148
149
    for option, value in opts:
150
        if option == '-p':
151
            OVERRIDE_PYTHON = value
152
            
153
    
398 by Martin Pool
- testbzr finds the right version of bzr to test
154
    mypath = os.path.abspath(sys.argv[0])
413 by Martin Pool
- more indicators at top of test output
155
    print '%-30s %s' % ('running tests from', mypath)
398 by Martin Pool
- testbzr finds the right version of bzr to test
156
157
    global BZRPATH
158
507 by Martin Pool
- new -p option for testbzr to use a different version of python
159
    if args:
160
        BZRPATH = args[1]
398 by Martin Pool
- testbzr finds the right version of bzr to test
161
    else:
162
        BZRPATH = os.path.join(os.path.split(mypath)[0], 'bzr')
163
413 by Martin Pool
- more indicators at top of test output
164
    print '%-30s %s' % ('against bzr', BZRPATH)
165
    print '%-30s %s' % ('in directory', os.getcwd())
507 by Martin Pool
- new -p option for testbzr to use a different version of python
166
    print '%-30s %s' % ('with python', (OVERRIDE_PYTHON or '(default)'))
398 by Martin Pool
- testbzr finds the right version of bzr to test
167
    print
168
    print backtick([BZRPATH, 'version'])
169
    
300 by Martin Pool
- more tests
170
    runcmd(['mkdir', TESTDIR])
299 by Martin Pool
testbzr:
171
    cd(TESTDIR)
456 by Martin Pool
- tests for bzr root
172
    test_root = os.getcwd()
296 by Martin Pool
- better reports from testbzr when it fails
173
300 by Martin Pool
- more tests
174
    progress("introductory commands")
296 by Martin Pool
- better reports from testbzr when it fails
175
    runcmd("bzr version")
335 by Martin Pool
- add new failing test for command parsing
176
    runcmd("bzr --version")
296 by Martin Pool
- better reports from testbzr when it fails
177
    runcmd("bzr help")
297 by Martin Pool
- fix intentional testcase failure
178
    runcmd("bzr --help")
179
399 by Martin Pool
- testbzr also runs selftests
180
    progress("internal tests")
181
    runcmd("bzr selftest")
182
300 by Martin Pool
- more tests
183
    progress("user identity")
297 by Martin Pool
- fix intentional testcase failure
184
    # this should always identify something, if only "john@localhost"
185
    runcmd("bzr whoami")
298 by Martin Pool
- test some commands known to fail
186
    runcmd("bzr whoami --email")
302 by Martin Pool
testbzr: new backtick() helper
187
    assert backtick("bzr whoami --email").count('@') == 1
298 by Martin Pool
- test some commands known to fail
188
300 by Martin Pool
- more tests
189
    progress("invalid commands")
298 by Martin Pool
- test some commands known to fail
190
    runcmd("bzr pants", retcode=1)
191
    runcmd("bzr --pants off", retcode=1)
382 by Martin Pool
- test previous commit
192
    runcmd("bzr diff --message foo", retcode=1)
296 by Martin Pool
- better reports from testbzr when it fails
193
300 by Martin Pool
- more tests
194
    progress("basic branch creation")
195
    runcmd(['mkdir', 'branch1'])
196
    cd('branch1')
197
    runcmd('bzr init')
303 by Martin Pool
- more tests for unknown file
198
456 by Martin Pool
- tests for bzr root
199
    assert backtick('bzr root')[:-1] == os.path.join(test_root, 'branch1')
200
303 by Martin Pool
- more tests for unknown file
201
    progress("status of new file")
300 by Martin Pool
- more tests
202
    
203
    f = file('test.txt', 'wt')
204
    f.write('hello world!\n')
205
    f.close()
206
307 by Martin Pool
testbzr: clean up crlf handling
207
    out = backtick("bzr unknowns")
208
    assert out == 'test.txt\n'
303 by Martin Pool
- more tests for unknown file
209
307 by Martin Pool
testbzr: clean up crlf handling
210
    out = backtick("bzr status")
477 by Martin Pool
- fix header for listing of unknown files
211
    assert out == 'unknown:\n  test.txt\n'
303 by Martin Pool
- more tests for unknown file
212
307 by Martin Pool
testbzr: clean up crlf handling
213
    out = backtick("bzr status --all")
477 by Martin Pool
- fix header for listing of unknown files
214
    assert out == "unknown:\n  test.txt\n"
304 by Martin Pool
testbzr: test adding a file
215
404 by Martin Pool
- bzr status now optionally takes filenames to check
216
    out = backtick("bzr status test.txt --all")
477 by Martin Pool
- fix header for listing of unknown files
217
    assert out == "unknown:\n  test.txt\n"
404 by Martin Pool
- bzr status now optionally takes filenames to check
218
219
    f = file('test2.txt', 'wt')
220
    f.write('goodbye cruel world...\n')
221
    f.close()
222
223
    out = backtick("bzr status test.txt")
480 by Martin Pool
- more status form test fixes
224
    assert out == "unknown:\n  test.txt\n"
404 by Martin Pool
- bzr status now optionally takes filenames to check
225
226
    out = backtick("bzr status")
480 by Martin Pool
- more status form test fixes
227
    assert out == ("unknown:\n"
228
                   "  test.txt\n"
229
                   "  test2.txt\n")
404 by Martin Pool
- bzr status now optionally takes filenames to check
230
231
    os.unlink('test2.txt')
232
350 by Martin Pool
- refactor command aliases into command classes
233
    progress("command aliases")
234
    out = backtick("bzr st --all")
482 by Martin Pool
- more status form test fixes
235
    assert out == ("unknown:\n"
236
                   "  test.txt\n")
237
    
350 by Martin Pool
- refactor command aliases into command classes
238
    out = backtick("bzr stat")
482 by Martin Pool
- more status form test fixes
239
    assert out == ("unknown:\n"
240
                   "  test.txt\n")
350 by Martin Pool
- refactor command aliases into command classes
241
242
    progress("command help")
243
    runcmd("bzr help st")
244
    runcmd("bzr help")
245
    runcmd("bzr help commands")
352 by Martin Pool
- Show aliases in command help
246
    runcmd("bzr help slartibartfast", 1)
247
248
    out = backtick("bzr help ci")
249
    out.index('aliases: ')
350 by Martin Pool
- refactor command aliases into command classes
250
305 by Martin Pool
testbzr: test renames
251
    progress("can't rename unversioned file")
252
    runcmd("bzr rename test.txt new-test.txt", 1)
253
304 by Martin Pool
testbzr: test adding a file
254
    progress("adding a file")
255
256
    runcmd("bzr add test.txt")
257
    assert backtick("bzr unknowns") == ''
482 by Martin Pool
- more status form test fixes
258
    assert backtick("bzr status --all") == ("added:\n"
259
                                            "  test.txt\n")
300 by Martin Pool
- more tests
260
305 by Martin Pool
testbzr: test renames
261
    progress("rename newly-added file")
262
    runcmd("bzr rename test.txt hello.txt")
306 by Martin Pool
testbzr: test renames
263
    assert os.path.exists("hello.txt")
264
    assert not os.path.exists("test.txt")
305 by Martin Pool
testbzr: test renames
265
308 by Martin Pool
fix test suite
266
    assert backtick("bzr revno") == '0\n'
307 by Martin Pool
testbzr: clean up crlf handling
267
339 by Martin Pool
many more diffs
268
    progress("add first revision")
269
    runcmd(["bzr", "commit", "-m", 'add first revision'])
270
271
    progress("more complex renames")
272
    os.mkdir("sub1")
273
    runcmd("bzr rename hello.txt sub1", 1)
274
    runcmd("bzr rename hello.txt sub1/hello.txt", 1)
275
    runcmd("bzr move hello.txt sub1", 1)
276
277
    runcmd("bzr add sub1")
278
    runcmd("bzr rename sub1 sub2")
279
    runcmd("bzr move hello.txt sub2")
392 by Martin Pool
- fix relpath and add tests
280
    assert backtick("bzr relpath sub2/hello.txt") == "sub2/hello.txt\n"
339 by Martin Pool
many more diffs
281
282
    assert exists("sub2")
283
    assert exists("sub2/hello.txt")
284
    assert not exists("sub1")
285
    assert not exists("hello.txt")
286
287
    runcmd(['bzr', 'commit', '-m', 'commit with some things moved to subdirs'])
288
289
    mkdir("sub1")
290
    runcmd('bzr add sub1')
291
    runcmd('bzr move sub2/hello.txt sub1')
292
    assert not exists('sub2/hello.txt')
293
    assert exists('sub1/hello.txt')
294
    runcmd('bzr move sub2 sub1')
295
    assert not exists('sub2')
296
    assert exists('sub1/sub2')
297
298
    runcmd(['bzr', 'commit', '-m', 'rename nested subdirectories'])
299
300
    cd('sub1/sub2')
456 by Martin Pool
- tests for bzr root
301
    assert backtick('bzr root')[:-1] == os.path.join(test_root, 'branch1')
339 by Martin Pool
many more diffs
302
    runcmd('bzr move ../hello.txt .')
340 by Martin Pool
- more testcase fixes
303
    assert exists('./hello.txt')
392 by Martin Pool
- fix relpath and add tests
304
    assert backtick('bzr relpath hello.txt') == 'sub1/sub2/hello.txt\n'
305
    assert backtick('bzr relpath ../../sub1/sub2/hello.txt') == 'sub1/sub2/hello.txt\n'
339 by Martin Pool
many more diffs
306
    runcmd(['bzr', 'commit', '-m', 'move to parent directory'])
307
    cd('..')
392 by Martin Pool
- fix relpath and add tests
308
    assert backtick('bzr relpath sub2/hello.txt') == 'sub1/sub2/hello.txt\n'
340 by Martin Pool
- more testcase fixes
309
310
    runcmd('bzr move sub2/hello.txt .')
311
    assert exists('hello.txt')
389 by Martin Pool
- new commit --file option!
312
313
    f = file('hello.txt', 'wt')
314
    f.write('some nice new content\n')
315
    f.close()
316
317
    f = file('msg.tmp', 'wt')
318
    f.write('this is my new commit\n')
319
    f.close()
320
321
    runcmd('bzr commit -F msg.tmp')
394 by Martin Pool
- Fix argument handling in export command
322
323
    assert backtick('bzr revno') == '5\n'
324
    runcmd('bzr export -r 5 export-5.tmp')
325
    runcmd('bzr export export.tmp')
461 by Martin Pool
- remove compare_inventories() in favor of compare_trees()
326
327
    runcmd('bzr log')
328
    runcmd('bzr log -v')
511 by Martin Pool
- add tests for files and directories with spaces in name
329
330
331
332
    progress("file with spaces in name")
333
    mkdir('sub directory')
334
    file('sub directory/file with spaces ', 'wt').write('see how this works\n')
335
    runcmd('bzr add .')
336
    runcmd('bzr diff')
337
    runcmd('bzr commit -m add-spaces')
338
    runcmd('bzr check')
339
340
    
341
    
339 by Martin Pool
many more diffs
342
    
300 by Martin Pool
- more tests
343
    cd('..')
410 by Martin Pool
- Fix ignore command and add tests
344
    cd('..')
345
346
    progress('ignore patterns')
347
    mkdir('ignorebranch')
348
    cd('ignorebranch')
349
    runcmd('bzr init')
350
    assert backtick('bzr unknowns') == ''
351
352
    file('foo.tmp', 'wt').write('tmp files are ignored')
353
    assert backtick('bzr unknowns') == ''
354
355
    file('foo.c', 'wt').write('int main() {}')
356
    assert backtick('bzr unknowns') == 'foo.c\n'
357
    runcmd('bzr add foo.c')
358
    assert backtick('bzr unknowns') == ''
359
499 by Martin Pool
- new bzr ignore test cases from ddaa
360
    # 'ignore' works when creating the .bzignore file
410 by Martin Pool
- Fix ignore command and add tests
361
    file('foo.blah', 'wt').write('blah')
362
    assert backtick('bzr unknowns') == 'foo.blah\n'
363
    runcmd('bzr ignore *.blah')
364
    assert backtick('bzr unknowns') == ''
499 by Martin Pool
- new bzr ignore test cases from ddaa
365
    assert file('.bzrignore', 'rb').read() == '*.blah\n'
410 by Martin Pool
- Fix ignore command and add tests
366
499 by Martin Pool
- new bzr ignore test cases from ddaa
367
    # 'ignore' works when then .bzrignore file already exists
368
    file('garh', 'wt').write('garh')
369
    assert backtick('bzr unknowns') == 'garh\n'
370
    runcmd('bzr ignore garh')
371
    assert backtick('bzr unknowns') == ''
372
    assert file('.bzrignore', 'rb').read() == '*.blah\ngarh\n'
300 by Martin Pool
- more tests
373
511 by Martin Pool
- add tests for files and directories with spaces in name
374
375
296 by Martin Pool
- better reports from testbzr when it fails
376
    progress("all tests passed!")
377
except Exception, e:
378
    sys.stderr.write('*' * 50 + '\n'
379
                     + 'testbzr: tests failed\n'
335 by Martin Pool
- add new failing test for command parsing
380
                     + 'see ' + LOGFILENAME + ' for more information\n'
296 by Martin Pool
- better reports from testbzr when it fails
381
                     + '*' * 50 + '\n')
382
    logfile.write('tests failed!\n')
383
    traceback.print_exc(None, logfile)
513 by Martin Pool
- show some log output if the tests fail
384
    logfile.close()
385
386
    sys.stdout.writelines(file(os.path.join(start_dir, LOGFILENAME), 'rt').readlines()[-50:])
387
    
296 by Martin Pool
- better reports from testbzr when it fails
388
    sys.exit(1)
513 by Martin Pool
- show some log output if the tests fail
389