~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
139
335 by Martin Pool
- add new failing test for command parsing
140
logfile = open(LOGFILENAME, 'wt', buffering=1)
292 by Martin Pool
- start adding a pure-python blackbox test suite
141
142
300 by Martin Pool
- more tests
143
try:
507 by Martin Pool
- new -p option for testbzr to use a different version of python
144
    from getopt import getopt
145
    opts, args = getopt(sys.argv[1:], 'p:')
146
147
    for option, value in opts:
148
        if option == '-p':
149
            OVERRIDE_PYTHON = value
150
            
151
    
398 by Martin Pool
- testbzr finds the right version of bzr to test
152
    mypath = os.path.abspath(sys.argv[0])
413 by Martin Pool
- more indicators at top of test output
153
    print '%-30s %s' % ('running tests from', mypath)
398 by Martin Pool
- testbzr finds the right version of bzr to test
154
155
    global BZRPATH
156
507 by Martin Pool
- new -p option for testbzr to use a different version of python
157
    if args:
158
        BZRPATH = args[1]
398 by Martin Pool
- testbzr finds the right version of bzr to test
159
    else:
160
        BZRPATH = os.path.join(os.path.split(mypath)[0], 'bzr')
161
413 by Martin Pool
- more indicators at top of test output
162
    print '%-30s %s' % ('against bzr', BZRPATH)
163
    print '%-30s %s' % ('in directory', os.getcwd())
507 by Martin Pool
- new -p option for testbzr to use a different version of python
164
    print '%-30s %s' % ('with python', (OVERRIDE_PYTHON or '(default)'))
398 by Martin Pool
- testbzr finds the right version of bzr to test
165
    print
166
    print backtick([BZRPATH, 'version'])
167
    
300 by Martin Pool
- more tests
168
    runcmd(['mkdir', TESTDIR])
299 by Martin Pool
testbzr:
169
    cd(TESTDIR)
456 by Martin Pool
- tests for bzr root
170
    test_root = os.getcwd()
296 by Martin Pool
- better reports from testbzr when it fails
171
300 by Martin Pool
- more tests
172
    progress("introductory commands")
296 by Martin Pool
- better reports from testbzr when it fails
173
    runcmd("bzr version")
335 by Martin Pool
- add new failing test for command parsing
174
    runcmd("bzr --version")
296 by Martin Pool
- better reports from testbzr when it fails
175
    runcmd("bzr help")
297 by Martin Pool
- fix intentional testcase failure
176
    runcmd("bzr --help")
177
399 by Martin Pool
- testbzr also runs selftests
178
    progress("internal tests")
179
    runcmd("bzr selftest")
180
300 by Martin Pool
- more tests
181
    progress("user identity")
297 by Martin Pool
- fix intentional testcase failure
182
    # this should always identify something, if only "john@localhost"
183
    runcmd("bzr whoami")
298 by Martin Pool
- test some commands known to fail
184
    runcmd("bzr whoami --email")
302 by Martin Pool
testbzr: new backtick() helper
185
    assert backtick("bzr whoami --email").count('@') == 1
298 by Martin Pool
- test some commands known to fail
186
300 by Martin Pool
- more tests
187
    progress("invalid commands")
298 by Martin Pool
- test some commands known to fail
188
    runcmd("bzr pants", retcode=1)
189
    runcmd("bzr --pants off", retcode=1)
382 by Martin Pool
- test previous commit
190
    runcmd("bzr diff --message foo", retcode=1)
296 by Martin Pool
- better reports from testbzr when it fails
191
300 by Martin Pool
- more tests
192
    progress("basic branch creation")
193
    runcmd(['mkdir', 'branch1'])
194
    cd('branch1')
195
    runcmd('bzr init')
303 by Martin Pool
- more tests for unknown file
196
456 by Martin Pool
- tests for bzr root
197
    assert backtick('bzr root')[:-1] == os.path.join(test_root, 'branch1')
198
303 by Martin Pool
- more tests for unknown file
199
    progress("status of new file")
300 by Martin Pool
- more tests
200
    
201
    f = file('test.txt', 'wt')
202
    f.write('hello world!\n')
203
    f.close()
204
307 by Martin Pool
testbzr: clean up crlf handling
205
    out = backtick("bzr unknowns")
206
    assert out == 'test.txt\n'
303 by Martin Pool
- more tests for unknown file
207
307 by Martin Pool
testbzr: clean up crlf handling
208
    out = backtick("bzr status")
477 by Martin Pool
- fix header for listing of unknown files
209
    assert out == 'unknown:\n  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 --all")
477 by Martin Pool
- fix header for listing of unknown files
212
    assert out == "unknown:\n  test.txt\n"
304 by Martin Pool
testbzr: test adding a file
213
404 by Martin Pool
- bzr status now optionally takes filenames to check
214
    out = backtick("bzr status test.txt --all")
477 by Martin Pool
- fix header for listing of unknown files
215
    assert out == "unknown:\n  test.txt\n"
404 by Martin Pool
- bzr status now optionally takes filenames to check
216
217
    f = file('test2.txt', 'wt')
218
    f.write('goodbye cruel world...\n')
219
    f.close()
220
221
    out = backtick("bzr status test.txt")
480 by Martin Pool
- more status form test fixes
222
    assert out == "unknown:\n  test.txt\n"
404 by Martin Pool
- bzr status now optionally takes filenames to check
223
224
    out = backtick("bzr status")
480 by Martin Pool
- more status form test fixes
225
    assert out == ("unknown:\n"
226
                   "  test.txt\n"
227
                   "  test2.txt\n")
404 by Martin Pool
- bzr status now optionally takes filenames to check
228
229
    os.unlink('test2.txt')
230
350 by Martin Pool
- refactor command aliases into command classes
231
    progress("command aliases")
232
    out = backtick("bzr st --all")
482 by Martin Pool
- more status form test fixes
233
    assert out == ("unknown:\n"
234
                   "  test.txt\n")
235
    
350 by Martin Pool
- refactor command aliases into command classes
236
    out = backtick("bzr stat")
482 by Martin Pool
- more status form test fixes
237
    assert out == ("unknown:\n"
238
                   "  test.txt\n")
350 by Martin Pool
- refactor command aliases into command classes
239
240
    progress("command help")
241
    runcmd("bzr help st")
242
    runcmd("bzr help")
243
    runcmd("bzr help commands")
352 by Martin Pool
- Show aliases in command help
244
    runcmd("bzr help slartibartfast", 1)
245
246
    out = backtick("bzr help ci")
247
    out.index('aliases: ')
350 by Martin Pool
- refactor command aliases into command classes
248
305 by Martin Pool
testbzr: test renames
249
    progress("can't rename unversioned file")
250
    runcmd("bzr rename test.txt new-test.txt", 1)
251
304 by Martin Pool
testbzr: test adding a file
252
    progress("adding a file")
253
254
    runcmd("bzr add test.txt")
255
    assert backtick("bzr unknowns") == ''
482 by Martin Pool
- more status form test fixes
256
    assert backtick("bzr status --all") == ("added:\n"
257
                                            "  test.txt\n")
300 by Martin Pool
- more tests
258
305 by Martin Pool
testbzr: test renames
259
    progress("rename newly-added file")
260
    runcmd("bzr rename test.txt hello.txt")
306 by Martin Pool
testbzr: test renames
261
    assert os.path.exists("hello.txt")
262
    assert not os.path.exists("test.txt")
305 by Martin Pool
testbzr: test renames
263
308 by Martin Pool
fix test suite
264
    assert backtick("bzr revno") == '0\n'
307 by Martin Pool
testbzr: clean up crlf handling
265
339 by Martin Pool
many more diffs
266
    progress("add first revision")
267
    runcmd(["bzr", "commit", "-m", 'add first revision'])
268
269
    progress("more complex renames")
270
    os.mkdir("sub1")
271
    runcmd("bzr rename hello.txt sub1", 1)
272
    runcmd("bzr rename hello.txt sub1/hello.txt", 1)
273
    runcmd("bzr move hello.txt sub1", 1)
274
275
    runcmd("bzr add sub1")
276
    runcmd("bzr rename sub1 sub2")
277
    runcmd("bzr move hello.txt sub2")
392 by Martin Pool
- fix relpath and add tests
278
    assert backtick("bzr relpath sub2/hello.txt") == "sub2/hello.txt\n"
339 by Martin Pool
many more diffs
279
280
    assert exists("sub2")
281
    assert exists("sub2/hello.txt")
282
    assert not exists("sub1")
283
    assert not exists("hello.txt")
284
285
    runcmd(['bzr', 'commit', '-m', 'commit with some things moved to subdirs'])
286
287
    mkdir("sub1")
288
    runcmd('bzr add sub1')
289
    runcmd('bzr move sub2/hello.txt sub1')
290
    assert not exists('sub2/hello.txt')
291
    assert exists('sub1/hello.txt')
292
    runcmd('bzr move sub2 sub1')
293
    assert not exists('sub2')
294
    assert exists('sub1/sub2')
295
296
    runcmd(['bzr', 'commit', '-m', 'rename nested subdirectories'])
297
298
    cd('sub1/sub2')
456 by Martin Pool
- tests for bzr root
299
    assert backtick('bzr root')[:-1] == os.path.join(test_root, 'branch1')
339 by Martin Pool
many more diffs
300
    runcmd('bzr move ../hello.txt .')
340 by Martin Pool
- more testcase fixes
301
    assert exists('./hello.txt')
392 by Martin Pool
- fix relpath and add tests
302
    assert backtick('bzr relpath hello.txt') == 'sub1/sub2/hello.txt\n'
303
    assert backtick('bzr relpath ../../sub1/sub2/hello.txt') == 'sub1/sub2/hello.txt\n'
339 by Martin Pool
many more diffs
304
    runcmd(['bzr', 'commit', '-m', 'move to parent directory'])
305
    cd('..')
392 by Martin Pool
- fix relpath and add tests
306
    assert backtick('bzr relpath sub2/hello.txt') == 'sub1/sub2/hello.txt\n'
340 by Martin Pool
- more testcase fixes
307
308
    runcmd('bzr move sub2/hello.txt .')
309
    assert exists('hello.txt')
389 by Martin Pool
- new commit --file option!
310
311
    f = file('hello.txt', 'wt')
312
    f.write('some nice new content\n')
313
    f.close()
314
315
    f = file('msg.tmp', 'wt')
316
    f.write('this is my new commit\n')
317
    f.close()
318
319
    runcmd('bzr commit -F msg.tmp')
394 by Martin Pool
- Fix argument handling in export command
320
321
    assert backtick('bzr revno') == '5\n'
322
    runcmd('bzr export -r 5 export-5.tmp')
323
    runcmd('bzr export export.tmp')
461 by Martin Pool
- remove compare_inventories() in favor of compare_trees()
324
325
    runcmd('bzr log')
326
    runcmd('bzr log -v')
339 by Martin Pool
many more diffs
327
    
300 by Martin Pool
- more tests
328
    cd('..')
410 by Martin Pool
- Fix ignore command and add tests
329
    cd('..')
330
331
    progress('ignore patterns')
332
    mkdir('ignorebranch')
333
    cd('ignorebranch')
334
    runcmd('bzr init')
335
    assert backtick('bzr unknowns') == ''
336
337
    file('foo.tmp', 'wt').write('tmp files are ignored')
338
    assert backtick('bzr unknowns') == ''
339
340
    file('foo.c', 'wt').write('int main() {}')
341
    assert backtick('bzr unknowns') == 'foo.c\n'
342
    runcmd('bzr add foo.c')
343
    assert backtick('bzr unknowns') == ''
344
499 by Martin Pool
- new bzr ignore test cases from ddaa
345
    # 'ignore' works when creating the .bzignore file
410 by Martin Pool
- Fix ignore command and add tests
346
    file('foo.blah', 'wt').write('blah')
347
    assert backtick('bzr unknowns') == 'foo.blah\n'
348
    runcmd('bzr ignore *.blah')
349
    assert backtick('bzr unknowns') == ''
499 by Martin Pool
- new bzr ignore test cases from ddaa
350
    assert file('.bzrignore', 'rb').read() == '*.blah\n'
410 by Martin Pool
- Fix ignore command and add tests
351
499 by Martin Pool
- new bzr ignore test cases from ddaa
352
    # 'ignore' works when then .bzrignore file already exists
353
    file('garh', 'wt').write('garh')
354
    assert backtick('bzr unknowns') == 'garh\n'
355
    runcmd('bzr ignore garh')
356
    assert backtick('bzr unknowns') == ''
357
    assert file('.bzrignore', 'rb').read() == '*.blah\ngarh\n'
300 by Martin Pool
- more tests
358
296 by Martin Pool
- better reports from testbzr when it fails
359
    progress("all tests passed!")
360
except Exception, e:
361
    sys.stderr.write('*' * 50 + '\n'
362
                     + 'testbzr: tests failed\n'
335 by Martin Pool
- add new failing test for command parsing
363
                     + 'see ' + LOGFILENAME + ' for more information\n'
296 by Martin Pool
- better reports from testbzr when it fails
364
                     + '*' * 50 + '\n')
365
    logfile.write('tests failed!\n')
366
    traceback.print_exc(None, logfile)
367
    sys.exit(1)