~bzr-pqm/bzr/bzr.dev

292 by Martin Pool
- start adding a pure-python blackbox test suite
1
#! /usr/bin/python
561 by Martin Pool
- add failing test for problem with stat after remove,
2
# -*- coding: utf-8 -*-
292 by Martin Pool
- start adding a pure-python blackbox test suite
3
4
# Copyright (C) 2005 Canonical Ltd
5
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.
10
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.
15
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
19
20
21
"""External black-box test for bzr.
22
23
This always runs bzr as an external process to try to catch bugs
24
related to argument processing, startup, etc.
25
507 by Martin Pool
- new -p option for testbzr to use a different version of python
26
usage:
27
28
    testbzr [-p PYTHON] [BZR]
29
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.
34
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
39
works on python2.3.
40
292 by Martin Pool
- start adding a pure-python blackbox test suite
41
This replaces the previous test.sh which was not very portable."""
42
296 by Martin Pool
- better reports from testbzr when it fails
43
import sys, os, traceback
339 by Martin Pool
many more diffs
44
from os import mkdir
45
from os.path import exists
292 by Martin Pool
- start adding a pure-python blackbox test suite
46
335 by Martin Pool
- add new failing test for command parsing
47
TESTDIR = "testbzr.tmp"
48
507 by Martin Pool
- new -p option for testbzr to use a different version of python
49
OVERRIDE_PYTHON = None
50
335 by Martin Pool
- add new failing test for command parsing
51
LOGFILENAME = 'testbzr.log'
52
292 by Martin Pool
- start adding a pure-python blackbox test suite
53
try:
54
    import shutil
301 by Martin Pool
- provide for catching output from shell commands
55
    from subprocess import call, Popen, PIPE
292 by Martin Pool
- start adding a pure-python blackbox test suite
56
except ImportError, e:
57
    sys.stderr.write("testbzr: sorry, this test suite requires modules from python2.4\n"
58
                     + '    ' + str(e))
59
    sys.exit(1)
60
61
296 by Martin Pool
- better reports from testbzr when it fails
62
class CommandFailed(Exception):
63
    pass
64
65
302 by Martin Pool
testbzr: new backtick() helper
66
def formcmd(cmd):
67
    if isinstance(cmd, basestring):
68
        cmd = cmd.split()
69
398 by Martin Pool
- testbzr finds the right version of bzr to test
70
    if cmd[0] == 'bzr':
71
        cmd[0] = BZRPATH
507 by Martin Pool
- new -p option for testbzr to use a different version of python
72
        if OVERRIDE_PYTHON:
73
            cmd.insert(0, OVERRIDE_PYTHON)
398 by Martin Pool
- testbzr finds the right version of bzr to test
74
507 by Martin Pool
- new -p option for testbzr to use a different version of python
75
    logfile.write('$ %r\n' % cmd)
76
    
302 by Martin Pool
testbzr: new backtick() helper
77
    return cmd
78
79
80
def runcmd(cmd, retcode=0):
300 by Martin Pool
- more tests
81
    """Run one command and check the return code.
292 by Martin Pool
- start adding a pure-python blackbox test suite
82
301 by Martin Pool
- provide for catching output from shell commands
83
    Returns a tuple of (stdout,stderr) strings.
84
292 by Martin Pool
- start adding a pure-python blackbox test suite
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."""
302 by Martin Pool
testbzr: new backtick() helper
88
    cmd = formcmd(cmd)
89
    log_linenumber()
90
    
91
    actual_retcode = call(cmd, stdout=logfile, stderr=logfile)
92
    
93
    if retcode != actual_retcode:
94
        raise CommandFailed("test failed: %r returned %d, expected %d"
95
                            % (cmd, actual_retcode, retcode))
96
97
98
99
def backtick(cmd, retcode=0):
100
    cmd = formcmd(cmd)
101
    log_linenumber()
102
    child = Popen(cmd, stdout=PIPE, stderr=logfile)
301 by Martin Pool
- provide for catching output from shell commands
103
    outd, errd = child.communicate()
302 by Martin Pool
testbzr: new backtick() helper
104
    logfile.write(outd)
301 by Martin Pool
- provide for catching output from shell commands
105
    actual_retcode = child.wait()
307 by Martin Pool
testbzr: clean up crlf handling
106
107
    outd = outd.replace('\r', '')
301 by Martin Pool
- provide for catching output from shell commands
108
    
298 by Martin Pool
- test some commands known to fail
109
    if retcode != actual_retcode:
110
        raise CommandFailed("test failed: %r returned %d, expected %d"
111
                            % (cmd, actual_retcode, retcode))
292 by Martin Pool
- start adding a pure-python blackbox test suite
112
302 by Martin Pool
testbzr: new backtick() helper
113
    return outd
114
301 by Martin Pool
- provide for catching output from shell commands
115
292 by Martin Pool
- start adding a pure-python blackbox test suite
116
117
def progress(msg):
118
    print '* ' + msg
119
    logfile.write('* '+ msg + '\n')
297 by Martin Pool
- fix intentional testcase failure
120
    log_linenumber()
121
122
299 by Martin Pool
testbzr:
123
def cd(dirname):
124
    logfile.write('$ cd %s\n' % dirname)
125
    os.chdir(dirname)
126
127
300 by Martin Pool
- more tests
128
297 by Martin Pool
- fix intentional testcase failure
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])
133
134
340 by Martin Pool
- more testcase fixes
135
292 by Martin Pool
- start adding a pure-python blackbox test suite
136
# prepare an empty scratch directory
137
if os.path.exists(TESTDIR):
138
    shutil.rmtree(TESTDIR)
139
513 by Martin Pool
- show some log output if the tests fail
140
start_dir = os.getcwd()
141
292 by Martin Pool
- start adding a pure-python blackbox test suite
142
335 by Martin Pool
- add new failing test for command parsing
143
logfile = open(LOGFILENAME, 'wt', buffering=1)
292 by Martin Pool
- start adding a pure-python blackbox test suite
144
145
300 by Martin Pool
- more tests
146
try:
507 by Martin Pool
- new -p option for testbzr to use a different version of python
147
    from getopt import getopt
148
    opts, args = getopt(sys.argv[1:], 'p:')
149
150
    for option, value in opts:
151
        if option == '-p':
152
            OVERRIDE_PYTHON = value
153
            
154
    
398 by Martin Pool
- testbzr finds the right version of bzr to test
155
    mypath = os.path.abspath(sys.argv[0])
413 by Martin Pool
- more indicators at top of test output
156
    print '%-30s %s' % ('running tests from', mypath)
398 by Martin Pool
- testbzr finds the right version of bzr to test
157
158
    global BZRPATH
159
507 by Martin Pool
- new -p option for testbzr to use a different version of python
160
    if args:
623 by Martin Pool
- fix invocation of testbzr when giving explicit bzr location
161
        BZRPATH = args[0]
398 by Martin Pool
- testbzr finds the right version of bzr to test
162
    else:
163
        BZRPATH = os.path.join(os.path.split(mypath)[0], 'bzr')
164
413 by Martin Pool
- more indicators at top of test output
165
    print '%-30s %s' % ('against bzr', BZRPATH)
166
    print '%-30s %s' % ('in directory', os.getcwd())
507 by Martin Pool
- new -p option for testbzr to use a different version of python
167
    print '%-30s %s' % ('with python', (OVERRIDE_PYTHON or '(default)'))
398 by Martin Pool
- testbzr finds the right version of bzr to test
168
    print
169
    print backtick([BZRPATH, 'version'])
170
    
300 by Martin Pool
- more tests
171
    runcmd(['mkdir', TESTDIR])
299 by Martin Pool
testbzr:
172
    cd(TESTDIR)
456 by Martin Pool
- tests for bzr root
173
    test_root = os.getcwd()
296 by Martin Pool
- better reports from testbzr when it fails
174
300 by Martin Pool
- more tests
175
    progress("introductory commands")
296 by Martin Pool
- better reports from testbzr when it fails
176
    runcmd("bzr version")
335 by Martin Pool
- add new failing test for command parsing
177
    runcmd("bzr --version")
296 by Martin Pool
- better reports from testbzr when it fails
178
    runcmd("bzr help")
297 by Martin Pool
- fix intentional testcase failure
179
    runcmd("bzr --help")
180
399 by Martin Pool
- testbzr also runs selftests
181
    progress("internal tests")
182
    runcmd("bzr selftest")
183
300 by Martin Pool
- more tests
184
    progress("user identity")
297 by Martin Pool
- fix intentional testcase failure
185
    # this should always identify something, if only "john@localhost"
186
    runcmd("bzr whoami")
298 by Martin Pool
- test some commands known to fail
187
    runcmd("bzr whoami --email")
302 by Martin Pool
testbzr: new backtick() helper
188
    assert backtick("bzr whoami --email").count('@') == 1
298 by Martin Pool
- test some commands known to fail
189
300 by Martin Pool
- more tests
190
    progress("invalid commands")
298 by Martin Pool
- test some commands known to fail
191
    runcmd("bzr pants", retcode=1)
192
    runcmd("bzr --pants off", retcode=1)
382 by Martin Pool
- test previous commit
193
    runcmd("bzr diff --message foo", retcode=1)
296 by Martin Pool
- better reports from testbzr when it fails
194
300 by Martin Pool
- more tests
195
    progress("basic branch creation")
196
    runcmd(['mkdir', 'branch1'])
197
    cd('branch1')
198
    runcmd('bzr init')
303 by Martin Pool
- more tests for unknown file
199
456 by Martin Pool
- tests for bzr root
200
    assert backtick('bzr root')[:-1] == os.path.join(test_root, 'branch1')
201
303 by Martin Pool
- more tests for unknown file
202
    progress("status of new file")
300 by Martin Pool
- more tests
203
    
204
    f = file('test.txt', 'wt')
205
    f.write('hello world!\n')
206
    f.close()
207
307 by Martin Pool
testbzr: clean up crlf handling
208
    out = backtick("bzr unknowns")
209
    assert out == 'test.txt\n'
303 by Martin Pool
- more tests for unknown file
210
307 by Martin Pool
testbzr: clean up crlf handling
211
    out = backtick("bzr status")
477 by Martin Pool
- fix header for listing of unknown files
212
    assert out == 'unknown:\n  test.txt\n'
303 by Martin Pool
- more tests for unknown file
213
307 by Martin Pool
testbzr: clean up crlf handling
214
    out = backtick("bzr status --all")
477 by Martin Pool
- fix header for listing of unknown files
215
    assert out == "unknown:\n  test.txt\n"
304 by Martin Pool
testbzr: test adding a file
216
404 by Martin Pool
- bzr status now optionally takes filenames to check
217
    out = backtick("bzr status test.txt --all")
477 by Martin Pool
- fix header for listing of unknown files
218
    assert out == "unknown:\n  test.txt\n"
404 by Martin Pool
- bzr status now optionally takes filenames to check
219
220
    f = file('test2.txt', 'wt')
221
    f.write('goodbye cruel world...\n')
222
    f.close()
223
224
    out = backtick("bzr status test.txt")
480 by Martin Pool
- more status form test fixes
225
    assert out == "unknown:\n  test.txt\n"
404 by Martin Pool
- bzr status now optionally takes filenames to check
226
227
    out = backtick("bzr status")
480 by Martin Pool
- more status form test fixes
228
    assert out == ("unknown:\n"
229
                   "  test.txt\n"
230
                   "  test2.txt\n")
404 by Martin Pool
- bzr status now optionally takes filenames to check
231
232
    os.unlink('test2.txt')
233
350 by Martin Pool
- refactor command aliases into command classes
234
    progress("command aliases")
235
    out = backtick("bzr st --all")
482 by Martin Pool
- more status form test fixes
236
    assert out == ("unknown:\n"
237
                   "  test.txt\n")
238
    
350 by Martin Pool
- refactor command aliases into command classes
239
    out = backtick("bzr stat")
482 by Martin Pool
- more status form test fixes
240
    assert out == ("unknown:\n"
241
                   "  test.txt\n")
350 by Martin Pool
- refactor command aliases into command classes
242
243
    progress("command help")
244
    runcmd("bzr help st")
245
    runcmd("bzr help")
246
    runcmd("bzr help commands")
352 by Martin Pool
- Show aliases in command help
247
    runcmd("bzr help slartibartfast", 1)
248
249
    out = backtick("bzr help ci")
250
    out.index('aliases: ')
350 by Martin Pool
- refactor command aliases into command classes
251
305 by Martin Pool
testbzr: test renames
252
    progress("can't rename unversioned file")
253
    runcmd("bzr rename test.txt new-test.txt", 1)
254
304 by Martin Pool
testbzr: test adding a file
255
    progress("adding a file")
256
257
    runcmd("bzr add test.txt")
258
    assert backtick("bzr unknowns") == ''
482 by Martin Pool
- more status form test fixes
259
    assert backtick("bzr status --all") == ("added:\n"
260
                                            "  test.txt\n")
300 by Martin Pool
- more tests
261
305 by Martin Pool
testbzr: test renames
262
    progress("rename newly-added file")
263
    runcmd("bzr rename test.txt hello.txt")
306 by Martin Pool
testbzr: test renames
264
    assert os.path.exists("hello.txt")
265
    assert not os.path.exists("test.txt")
305 by Martin Pool
testbzr: test renames
266
308 by Martin Pool
fix test suite
267
    assert backtick("bzr revno") == '0\n'
307 by Martin Pool
testbzr: clean up crlf handling
268
339 by Martin Pool
many more diffs
269
    progress("add first revision")
270
    runcmd(["bzr", "commit", "-m", 'add first revision'])
271
272
    progress("more complex renames")
273
    os.mkdir("sub1")
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)
277
278
    runcmd("bzr add sub1")
279
    runcmd("bzr rename sub1 sub2")
280
    runcmd("bzr move hello.txt sub2")
560 by Martin Pool
- fix testbzr for win32
281
    assert backtick("bzr relpath sub2/hello.txt") == os.path.join("sub2", "hello.txt\n")
339 by Martin Pool
many more diffs
282
283
    assert exists("sub2")
284
    assert exists("sub2/hello.txt")
285
    assert not exists("sub1")
286
    assert not exists("hello.txt")
287
288
    runcmd(['bzr', 'commit', '-m', 'commit with some things moved to subdirs'])
289
290
    mkdir("sub1")
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')
298
299
    runcmd(['bzr', 'commit', '-m', 'rename nested subdirectories'])
300
301
    cd('sub1/sub2')
456 by Martin Pool
- tests for bzr root
302
    assert backtick('bzr root')[:-1] == os.path.join(test_root, 'branch1')
339 by Martin Pool
many more diffs
303
    runcmd('bzr move ../hello.txt .')
340 by Martin Pool
- more testcase fixes
304
    assert exists('./hello.txt')
560 by Martin Pool
- fix testbzr for win32
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')
339 by Martin Pool
many more diffs
307
    runcmd(['bzr', 'commit', '-m', 'move to parent directory'])
308
    cd('..')
560 by Martin Pool
- fix testbzr for win32
309
    assert backtick('bzr relpath sub2/hello.txt') == os.path.join('sub1', 'sub2', 'hello.txt\n')
340 by Martin Pool
- more testcase fixes
310
311
    runcmd('bzr move sub2/hello.txt .')
312
    assert exists('hello.txt')
389 by Martin Pool
- new commit --file option!
313
314
    f = file('hello.txt', 'wt')
315
    f.write('some nice new content\n')
316
    f.close()
317
318
    f = file('msg.tmp', 'wt')
319
    f.write('this is my new commit\n')
320
    f.close()
321
322
    runcmd('bzr commit -F msg.tmp')
394 by Martin Pool
- Fix argument handling in export command
323
324
    assert backtick('bzr revno') == '5\n'
325
    runcmd('bzr export -r 5 export-5.tmp')
326
    runcmd('bzr export export.tmp')
461 by Martin Pool
- remove compare_inventories() in favor of compare_trees()
327
328
    runcmd('bzr log')
329
    runcmd('bzr log -v')
511 by Martin Pool
- add tests for files and directories with spaces in name
330
331
332
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')
336
    runcmd('bzr add .')
337
    runcmd('bzr diff')
338
    runcmd('bzr commit -m add-spaces')
339
    runcmd('bzr check')
340
545 by Martin Pool
- --forward option for log
341
    runcmd('bzr log')
342
    runcmd('bzr log --forward')
343
541 by Martin Pool
- add lazy test for 'bzr info'
344
    runcmd('bzr info')
561 by Martin Pool
- add failing test for problem with stat after remove,
345
346
595 by Martin Pool
- tests for add --no-recurse
347
    
348
349
561 by Martin Pool
- add failing test for problem with stat after remove,
350
351
    cd('..')
352
    cd('..')
353
354
    progress('status after remove')
355
    mkdir('status-after-remove')
356
    # see mail from William Dodé, 2005-05-25
357
    # $ bzr init; touch a; bzr add a; bzr commit -m "add a"
358
    #     * looking for changes...
359
    #     added a
360
    #     * commited r1
361
    #     $ bzr remove a
362
    #     $ bzr status
363
    #     bzr: local variable 'kind' referenced before assignment
364
    #     at /vrac/python/bazaar-ng/bzrlib/diff.py:286 in compare_trees()
365
    #     see ~/.bzr.log for debug information
366
    cd('status-after-remove')
367
    runcmd('bzr init')
368
    file('a', 'w').write('foo')
369
    runcmd('bzr add a')
370
    runcmd(['bzr', 'commit', '-m', 'add a'])
371
    runcmd('bzr remove a')
372
    runcmd('bzr status')
373
410 by Martin Pool
- Fix ignore command and add tests
374
    cd('..')
375
376
    progress('ignore patterns')
377
    mkdir('ignorebranch')
378
    cd('ignorebranch')
379
    runcmd('bzr init')
380
    assert backtick('bzr unknowns') == ''
381
382
    file('foo.tmp', 'wt').write('tmp files are ignored')
383
    assert backtick('bzr unknowns') == ''
384
385
    file('foo.c', 'wt').write('int main() {}')
386
    assert backtick('bzr unknowns') == 'foo.c\n'
387
    runcmd('bzr add foo.c')
388
    assert backtick('bzr unknowns') == ''
389
499 by Martin Pool
- new bzr ignore test cases from ddaa
390
    # 'ignore' works when creating the .bzignore file
410 by Martin Pool
- Fix ignore command and add tests
391
    file('foo.blah', 'wt').write('blah')
392
    assert backtick('bzr unknowns') == 'foo.blah\n'
393
    runcmd('bzr ignore *.blah')
394
    assert backtick('bzr unknowns') == ''
499 by Martin Pool
- new bzr ignore test cases from ddaa
395
    assert file('.bzrignore', 'rb').read() == '*.blah\n'
410 by Martin Pool
- Fix ignore command and add tests
396
499 by Martin Pool
- new bzr ignore test cases from ddaa
397
    # 'ignore' works when then .bzrignore file already exists
398
    file('garh', 'wt').write('garh')
399
    assert backtick('bzr unknowns') == 'garh\n'
400
    runcmd('bzr ignore garh')
401
    assert backtick('bzr unknowns') == ''
402
    assert file('.bzrignore', 'rb').read() == '*.blah\ngarh\n'
300 by Martin Pool
- more tests
403
595 by Martin Pool
- tests for add --no-recurse
404
    cd('..')
405
406
407
408
409
    progress("recursive and non-recursive add")
410
    mkdir('no-recurse')
411
    cd('no-recurse')
412
    runcmd('bzr init')
413
    mkdir('foo')
414
    fp = os.path.join('foo', 'test.txt')
415
    f = file(fp, 'w')
416
    f.write('hello!\n')
417
    f.close()
418
    runcmd('bzr add --no-recurse foo')
419
    runcmd('bzr file-id foo')
420
    runcmd('bzr file-id ' + fp, 1)      # not versioned yet
421
    runcmd('bzr commit -m add-dir-only')
422
423
    runcmd('bzr file-id ' + fp, 1)      # still not versioned 
424
425
    runcmd('bzr add foo')
426
    runcmd('bzr file-id ' + fp)
427
    runcmd('bzr commit -m add-sub-file')
428
    
429
    cd('..')
430
431
511 by Martin Pool
- add tests for files and directories with spaces in name
432
433
296 by Martin Pool
- better reports from testbzr when it fails
434
    progress("all tests passed!")
435
except Exception, e:
436
    sys.stderr.write('*' * 50 + '\n'
437
                     + 'testbzr: tests failed\n'
335 by Martin Pool
- add new failing test for command parsing
438
                     + 'see ' + LOGFILENAME + ' for more information\n'
296 by Martin Pool
- better reports from testbzr when it fails
439
                     + '*' * 50 + '\n')
440
    logfile.write('tests failed!\n')
441
    traceback.print_exc(None, logfile)
513 by Martin Pool
- show some log output if the tests fail
442
    logfile.close()
443
444
    sys.stdout.writelines(file(os.path.join(start_dir, LOGFILENAME), 'rt').readlines()[-50:])
445
    
296 by Martin Pool
- better reports from testbzr when it fails
446
    sys.exit(1)
513 by Martin Pool
- show some log output if the tests fail
447