~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
25
This replaces the previous test.sh which was not very portable."""
26
296 by Martin Pool
- better reports from testbzr when it fails
27
import sys, os, traceback
339 by Martin Pool
many more diffs
28
from os import mkdir
29
from os.path import exists
292 by Martin Pool
- start adding a pure-python blackbox test suite
30
335 by Martin Pool
- add new failing test for command parsing
31
TESTDIR = "testbzr.tmp"
32
33
LOGFILENAME = 'testbzr.log'
34
292 by Martin Pool
- start adding a pure-python blackbox test suite
35
try:
36
    import shutil
301 by Martin Pool
- provide for catching output from shell commands
37
    from subprocess import call, Popen, PIPE
292 by Martin Pool
- start adding a pure-python blackbox test suite
38
except ImportError, e:
39
    sys.stderr.write("testbzr: sorry, this test suite requires modules from python2.4\n"
40
                     + '    ' + str(e))
41
    sys.exit(1)
42
43
296 by Martin Pool
- better reports from testbzr when it fails
44
class CommandFailed(Exception):
45
    pass
46
47
302 by Martin Pool
testbzr: new backtick() helper
48
def formcmd(cmd):
49
    if isinstance(cmd, basestring):
50
        logfile.write('$ %s\n' % cmd)
51
        cmd = cmd.split()
52
    else:
53
        logfile.write('$ %r\n' % cmd)
54
398 by Martin Pool
- testbzr finds the right version of bzr to test
55
    if cmd[0] == 'bzr':
56
        cmd[0] = BZRPATH
57
302 by Martin Pool
testbzr: new backtick() helper
58
    return cmd
59
60
61
def runcmd(cmd, retcode=0):
300 by Martin Pool
- more tests
62
    """Run one command and check the return code.
292 by Martin Pool
- start adding a pure-python blackbox test suite
63
301 by Martin Pool
- provide for catching output from shell commands
64
    Returns a tuple of (stdout,stderr) strings.
65
292 by Martin Pool
- start adding a pure-python blackbox test suite
66
    If a single string is based, it is split into words.
67
    For commands that are not simple space-separated words, please
68
    pass a list instead."""
302 by Martin Pool
testbzr: new backtick() helper
69
    cmd = formcmd(cmd)
70
    log_linenumber()
71
    
72
    actual_retcode = call(cmd, stdout=logfile, stderr=logfile)
73
    
74
    if retcode != actual_retcode:
75
        raise CommandFailed("test failed: %r returned %d, expected %d"
76
                            % (cmd, actual_retcode, retcode))
77
78
79
80
def backtick(cmd, retcode=0):
81
    cmd = formcmd(cmd)
82
    log_linenumber()
83
    child = Popen(cmd, stdout=PIPE, stderr=logfile)
301 by Martin Pool
- provide for catching output from shell commands
84
    outd, errd = child.communicate()
302 by Martin Pool
testbzr: new backtick() helper
85
    logfile.write(outd)
301 by Martin Pool
- provide for catching output from shell commands
86
    actual_retcode = child.wait()
307 by Martin Pool
testbzr: clean up crlf handling
87
88
    outd = outd.replace('\r', '')
301 by Martin Pool
- provide for catching output from shell commands
89
    
298 by Martin Pool
- test some commands known to fail
90
    if retcode != actual_retcode:
91
        raise CommandFailed("test failed: %r returned %d, expected %d"
92
                            % (cmd, actual_retcode, retcode))
292 by Martin Pool
- start adding a pure-python blackbox test suite
93
302 by Martin Pool
testbzr: new backtick() helper
94
    return outd
95
301 by Martin Pool
- provide for catching output from shell commands
96
292 by Martin Pool
- start adding a pure-python blackbox test suite
97
98
def progress(msg):
99
    print '* ' + msg
100
    logfile.write('* '+ msg + '\n')
297 by Martin Pool
- fix intentional testcase failure
101
    log_linenumber()
102
103
299 by Martin Pool
testbzr:
104
def cd(dirname):
105
    logfile.write('$ cd %s\n' % dirname)
106
    os.chdir(dirname)
107
108
300 by Martin Pool
- more tests
109
297 by Martin Pool
- fix intentional testcase failure
110
def log_linenumber():
111
    """Log the stack frame location two things up."""
112
    stack = traceback.extract_stack()[-3]
113
    logfile.write('   at %s:%d\n' % stack[:2])
114
115
340 by Martin Pool
- more testcase fixes
116
292 by Martin Pool
- start adding a pure-python blackbox test suite
117
# prepare an empty scratch directory
118
if os.path.exists(TESTDIR):
119
    shutil.rmtree(TESTDIR)
120
121
335 by Martin Pool
- add new failing test for command parsing
122
logfile = open(LOGFILENAME, 'wt', buffering=1)
292 by Martin Pool
- start adding a pure-python blackbox test suite
123
124
300 by Martin Pool
- more tests
125
try:
398 by Martin Pool
- testbzr finds the right version of bzr to test
126
    mypath = os.path.abspath(sys.argv[0])
413 by Martin Pool
- more indicators at top of test output
127
    print '%-30s %s' % ('running tests from', mypath)
398 by Martin Pool
- testbzr finds the right version of bzr to test
128
129
    global BZRPATH
130
131
    if len(sys.argv) > 1:
132
        BZRPATH = sys.argv[1]
133
    else:
134
        BZRPATH = os.path.join(os.path.split(mypath)[0], 'bzr')
135
413 by Martin Pool
- more indicators at top of test output
136
    print '%-30s %s' % ('against bzr', BZRPATH)
137
    print '%-30s %s' % ('in directory', os.getcwd())
398 by Martin Pool
- testbzr finds the right version of bzr to test
138
    print
139
    print backtick([BZRPATH, 'version'])
140
    
300 by Martin Pool
- more tests
141
    runcmd(['mkdir', TESTDIR])
299 by Martin Pool
testbzr:
142
    cd(TESTDIR)
456 by Martin Pool
- tests for bzr root
143
    test_root = os.getcwd()
296 by Martin Pool
- better reports from testbzr when it fails
144
300 by Martin Pool
- more tests
145
    progress("introductory commands")
296 by Martin Pool
- better reports from testbzr when it fails
146
    runcmd("bzr version")
335 by Martin Pool
- add new failing test for command parsing
147
    runcmd("bzr --version")
296 by Martin Pool
- better reports from testbzr when it fails
148
    runcmd("bzr help")
297 by Martin Pool
- fix intentional testcase failure
149
    runcmd("bzr --help")
150
399 by Martin Pool
- testbzr also runs selftests
151
    progress("internal tests")
152
    runcmd("bzr selftest")
153
300 by Martin Pool
- more tests
154
    progress("user identity")
297 by Martin Pool
- fix intentional testcase failure
155
    # this should always identify something, if only "john@localhost"
156
    runcmd("bzr whoami")
298 by Martin Pool
- test some commands known to fail
157
    runcmd("bzr whoami --email")
302 by Martin Pool
testbzr: new backtick() helper
158
    assert backtick("bzr whoami --email").count('@') == 1
298 by Martin Pool
- test some commands known to fail
159
300 by Martin Pool
- more tests
160
    progress("invalid commands")
298 by Martin Pool
- test some commands known to fail
161
    runcmd("bzr pants", retcode=1)
162
    runcmd("bzr --pants off", retcode=1)
382 by Martin Pool
- test previous commit
163
    runcmd("bzr diff --message foo", retcode=1)
296 by Martin Pool
- better reports from testbzr when it fails
164
300 by Martin Pool
- more tests
165
    progress("basic branch creation")
166
    runcmd(['mkdir', 'branch1'])
167
    cd('branch1')
168
    runcmd('bzr init')
303 by Martin Pool
- more tests for unknown file
169
456 by Martin Pool
- tests for bzr root
170
    assert backtick('bzr root')[:-1] == os.path.join(test_root, 'branch1')
171
303 by Martin Pool
- more tests for unknown file
172
    progress("status of new file")
300 by Martin Pool
- more tests
173
    
174
    f = file('test.txt', 'wt')
175
    f.write('hello world!\n')
176
    f.close()
177
307 by Martin Pool
testbzr: clean up crlf handling
178
    out = backtick("bzr unknowns")
179
    assert out == 'test.txt\n'
303 by Martin Pool
- more tests for unknown file
180
307 by Martin Pool
testbzr: clean up crlf handling
181
    out = backtick("bzr status")
477 by Martin Pool
- fix header for listing of unknown files
182
    assert out == 'unknown:\n  test.txt\n'
303 by Martin Pool
- more tests for unknown file
183
307 by Martin Pool
testbzr: clean up crlf handling
184
    out = backtick("bzr status --all")
477 by Martin Pool
- fix header for listing of unknown files
185
    assert out == "unknown:\n  test.txt\n"
304 by Martin Pool
testbzr: test adding a file
186
404 by Martin Pool
- bzr status now optionally takes filenames to check
187
    out = backtick("bzr status test.txt --all")
477 by Martin Pool
- fix header for listing of unknown files
188
    assert out == "unknown:\n  test.txt\n"
404 by Martin Pool
- bzr status now optionally takes filenames to check
189
190
    f = file('test2.txt', 'wt')
191
    f.write('goodbye cruel world...\n')
192
    f.close()
193
194
    out = backtick("bzr status test.txt")
480 by Martin Pool
- more status form test fixes
195
    assert out == "unknown:\n  test.txt\n"
404 by Martin Pool
- bzr status now optionally takes filenames to check
196
197
    out = backtick("bzr status")
480 by Martin Pool
- more status form test fixes
198
    assert out == ("unknown:\n"
199
                   "  test.txt\n"
200
                   "  test2.txt\n")
404 by Martin Pool
- bzr status now optionally takes filenames to check
201
202
    os.unlink('test2.txt')
203
350 by Martin Pool
- refactor command aliases into command classes
204
    progress("command aliases")
205
    out = backtick("bzr st --all")
482 by Martin Pool
- more status form test fixes
206
    assert out == ("unknown:\n"
207
                   "  test.txt\n")
208
    
350 by Martin Pool
- refactor command aliases into command classes
209
    out = backtick("bzr stat")
482 by Martin Pool
- more status form test fixes
210
    assert out == ("unknown:\n"
211
                   "  test.txt\n")
350 by Martin Pool
- refactor command aliases into command classes
212
213
    progress("command help")
214
    runcmd("bzr help st")
215
    runcmd("bzr help")
216
    runcmd("bzr help commands")
352 by Martin Pool
- Show aliases in command help
217
    runcmd("bzr help slartibartfast", 1)
218
219
    out = backtick("bzr help ci")
220
    out.index('aliases: ')
350 by Martin Pool
- refactor command aliases into command classes
221
305 by Martin Pool
testbzr: test renames
222
    progress("can't rename unversioned file")
223
    runcmd("bzr rename test.txt new-test.txt", 1)
224
304 by Martin Pool
testbzr: test adding a file
225
    progress("adding a file")
226
227
    runcmd("bzr add test.txt")
228
    assert backtick("bzr unknowns") == ''
482 by Martin Pool
- more status form test fixes
229
    assert backtick("bzr status --all") == ("added:\n"
230
                                            "  test.txt\n")
300 by Martin Pool
- more tests
231
305 by Martin Pool
testbzr: test renames
232
    progress("rename newly-added file")
233
    runcmd("bzr rename test.txt hello.txt")
306 by Martin Pool
testbzr: test renames
234
    assert os.path.exists("hello.txt")
235
    assert not os.path.exists("test.txt")
305 by Martin Pool
testbzr: test renames
236
308 by Martin Pool
fix test suite
237
    assert backtick("bzr revno") == '0\n'
307 by Martin Pool
testbzr: clean up crlf handling
238
339 by Martin Pool
many more diffs
239
    progress("add first revision")
240
    runcmd(["bzr", "commit", "-m", 'add first revision'])
241
242
    progress("more complex renames")
243
    os.mkdir("sub1")
244
    runcmd("bzr rename hello.txt sub1", 1)
245
    runcmd("bzr rename hello.txt sub1/hello.txt", 1)
246
    runcmd("bzr move hello.txt sub1", 1)
247
248
    runcmd("bzr add sub1")
249
    runcmd("bzr rename sub1 sub2")
250
    runcmd("bzr move hello.txt sub2")
392 by Martin Pool
- fix relpath and add tests
251
    assert backtick("bzr relpath sub2/hello.txt") == "sub2/hello.txt\n"
339 by Martin Pool
many more diffs
252
253
    assert exists("sub2")
254
    assert exists("sub2/hello.txt")
255
    assert not exists("sub1")
256
    assert not exists("hello.txt")
257
258
    runcmd(['bzr', 'commit', '-m', 'commit with some things moved to subdirs'])
259
260
    mkdir("sub1")
261
    runcmd('bzr add sub1')
262
    runcmd('bzr move sub2/hello.txt sub1')
263
    assert not exists('sub2/hello.txt')
264
    assert exists('sub1/hello.txt')
265
    runcmd('bzr move sub2 sub1')
266
    assert not exists('sub2')
267
    assert exists('sub1/sub2')
268
269
    runcmd(['bzr', 'commit', '-m', 'rename nested subdirectories'])
270
271
    cd('sub1/sub2')
456 by Martin Pool
- tests for bzr root
272
    assert backtick('bzr root')[:-1] == os.path.join(test_root, 'branch1')
339 by Martin Pool
many more diffs
273
    runcmd('bzr move ../hello.txt .')
340 by Martin Pool
- more testcase fixes
274
    assert exists('./hello.txt')
392 by Martin Pool
- fix relpath and add tests
275
    assert backtick('bzr relpath hello.txt') == 'sub1/sub2/hello.txt\n'
276
    assert backtick('bzr relpath ../../sub1/sub2/hello.txt') == 'sub1/sub2/hello.txt\n'
339 by Martin Pool
many more diffs
277
    runcmd(['bzr', 'commit', '-m', 'move to parent directory'])
278
    cd('..')
392 by Martin Pool
- fix relpath and add tests
279
    assert backtick('bzr relpath sub2/hello.txt') == 'sub1/sub2/hello.txt\n'
340 by Martin Pool
- more testcase fixes
280
281
    runcmd('bzr move sub2/hello.txt .')
282
    assert exists('hello.txt')
389 by Martin Pool
- new commit --file option!
283
284
    f = file('hello.txt', 'wt')
285
    f.write('some nice new content\n')
286
    f.close()
287
288
    f = file('msg.tmp', 'wt')
289
    f.write('this is my new commit\n')
290
    f.close()
291
292
    runcmd('bzr commit -F msg.tmp')
394 by Martin Pool
- Fix argument handling in export command
293
294
    assert backtick('bzr revno') == '5\n'
295
    runcmd('bzr export -r 5 export-5.tmp')
296
    runcmd('bzr export export.tmp')
461 by Martin Pool
- remove compare_inventories() in favor of compare_trees()
297
298
    runcmd('bzr log')
299
    runcmd('bzr log -v')
339 by Martin Pool
many more diffs
300
    
300 by Martin Pool
- more tests
301
    cd('..')
410 by Martin Pool
- Fix ignore command and add tests
302
    cd('..')
303
304
    progress('ignore patterns')
305
    mkdir('ignorebranch')
306
    cd('ignorebranch')
307
    runcmd('bzr init')
308
    assert backtick('bzr unknowns') == ''
309
310
    file('foo.tmp', 'wt').write('tmp files are ignored')
311
    assert backtick('bzr unknowns') == ''
312
313
    file('foo.c', 'wt').write('int main() {}')
314
    assert backtick('bzr unknowns') == 'foo.c\n'
315
    runcmd('bzr add foo.c')
316
    assert backtick('bzr unknowns') == ''
317
318
    file('foo.blah', 'wt').write('blah')
319
    assert backtick('bzr unknowns') == 'foo.blah\n'
320
    runcmd('bzr ignore *.blah')
321
    assert backtick('bzr unknowns') == ''
322
    assert file('.bzrignore', 'rt').read() == '*.blah\n'
323
300 by Martin Pool
- more tests
324
296 by Martin Pool
- better reports from testbzr when it fails
325
    progress("all tests passed!")
326
except Exception, e:
327
    sys.stderr.write('*' * 50 + '\n'
328
                     + 'testbzr: tests failed\n'
335 by Martin Pool
- add new failing test for command parsing
329
                     + 'see ' + LOGFILENAME + ' for more information\n'
296 by Martin Pool
- better reports from testbzr when it fails
330
                     + '*' * 50 + '\n')
331
    logfile.write('tests failed!\n')
332
    traceback.print_exc(None, logfile)
333
    sys.exit(1)