~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:
161
        BZRPATH = args[1]
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
347
348
    cd('..')
349
    cd('..')
350
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...
356
    #     added a
357
    #     * commited r1
358
    #     $ bzr remove a
359
    #     $ bzr status
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')
364
    runcmd('bzr init')
365
    file('a', 'w').write('foo')
366
    runcmd('bzr add a')
367
    runcmd(['bzr', 'commit', '-m', 'add a'])
368
    runcmd('bzr remove a')
369
    runcmd('bzr status')
370
410 by Martin Pool
- Fix ignore command and add tests
371
    cd('..')
372
373
    progress('ignore patterns')
374
    mkdir('ignorebranch')
375
    cd('ignorebranch')
376
    runcmd('bzr init')
377
    assert backtick('bzr unknowns') == ''
378
379
    file('foo.tmp', 'wt').write('tmp files are ignored')
380
    assert backtick('bzr unknowns') == ''
381
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') == ''
386
499 by Martin Pool
- new bzr ignore test cases from ddaa
387
    # 'ignore' works when creating the .bzignore file
410 by Martin Pool
- Fix ignore command and add tests
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') == ''
499 by Martin Pool
- new bzr ignore test cases from ddaa
392
    assert file('.bzrignore', 'rb').read() == '*.blah\n'
410 by Martin Pool
- Fix ignore command and add tests
393
499 by Martin Pool
- new bzr ignore test cases from ddaa
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'
300 by Martin Pool
- more tests
400
511 by Martin Pool
- add tests for files and directories with spaces in name
401
402
296 by Martin Pool
- better reports from testbzr when it fails
403
    progress("all tests passed!")
404
except Exception, e:
405
    sys.stderr.write('*' * 50 + '\n'
406
                     + 'testbzr: tests failed\n'
335 by Martin Pool
- add new failing test for command parsing
407
                     + 'see ' + LOGFILENAME + ' for more information\n'
296 by Martin Pool
- better reports from testbzr when it fails
408
                     + '*' * 50 + '\n')
409
    logfile.write('tests failed!\n')
410
    traceback.print_exc(None, logfile)
513 by Martin Pool
- show some log output if the tests fail
411
    logfile.close()
412
413
    sys.stdout.writelines(file(os.path.join(start_dir, LOGFILENAME), 'rt').readlines()[-50:])
414
    
296 by Martin Pool
- better reports from testbzr when it fails
415
    sys.exit(1)
513 by Martin Pool
- show some log output if the tests fail
416