~bzr-pqm/bzr/bzr.dev

« back to all changes in this revision

Viewing changes to testbzr

  • Committer: Martin Pool
  • Date: 2005-06-22 03:09:57 UTC
  • Revision ID: mbp@sourcefrog.net-20050622030957-692ff24093ce2a86
- add help, try, apply options to pwk script

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
#! /usr/bin/python
 
2
# -*- coding: utf-8 -*-
 
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
print 'please use "bzr selftest" instead'
 
21
import sys
 
22
sys.exit(1)
 
23
 
 
24
 
 
25
 
 
26
 
 
27
"""External black-box test for bzr.
 
28
 
 
29
This always runs bzr as an external process to try to catch bugs
 
30
related to argument processing, startup, etc.
 
31
 
 
32
usage:
 
33
 
 
34
    testbzr [-p PYTHON] [BZR]
 
35
 
 
36
By default this tests the copy of bzr found in the same directory as
 
37
testbzr, or the first one found on the $PATH.  A copy of bzr may be
 
38
given on the command line to override this, for example when applying
 
39
a new test suite to an old copy of bzr or vice versa.
 
40
 
 
41
testbzr normally invokes bzr using the same version of python as it
 
42
would normally use to run -- that is, the system default python,
 
43
unless that is older than 2.3.  The -p option allows specification of
 
44
a different Python interpreter, such as when testing that bzr still
 
45
works on python2.3.
 
46
 
 
47
This replaces the previous test.sh which was not very portable."""
 
48
 
 
49
import sys, os, traceback
 
50
from os import mkdir
 
51
from os.path import exists
 
52
 
 
53
TESTDIR = "testbzr.tmp"
 
54
 
 
55
 
 
56
# we always invoke bzr as 'python bzr' (or e.g. 'python2.3 bzr')
 
57
# partly so as to cope if the bzr binary is not marked executable
 
58
OVERRIDE_PYTHON = 'python'
 
59
 
 
60
LOGFILENAME = 'testbzr.log'
 
61
 
 
62
try:
 
63
    import shutil
 
64
    from subprocess import call, Popen, PIPE
 
65
except ImportError, e:
 
66
    sys.stderr.write("testbzr: sorry, this test suite requires modules from python2.4\n"
 
67
                     + '    ' + str(e))
 
68
    sys.exit(1)
 
69
 
 
70
 
 
71
 
 
72
 
 
73
def formcmd(cmd):
 
74
    if isinstance(cmd, basestring):
 
75
        cmd = cmd.split()
 
76
 
 
77
    if cmd[0] == 'bzr':
 
78
        cmd[0] = BZRPATH
 
79
        if OVERRIDE_PYTHON:
 
80
            cmd.insert(0, OVERRIDE_PYTHON)
 
81
 
 
82
    logfile.write('$ %r\n' % cmd)
 
83
    
 
84
    return cmd
 
85
 
 
86
 
 
87
def runcmd(cmd, retcode=0):
 
88
    """Run one command and check the return code.
 
89
 
 
90
    Returns a tuple of (stdout,stderr) strings.
 
91
 
 
92
    If a single string is based, it is split into words.
 
93
    For commands that are not simple space-separated words, please
 
94
    pass a list instead."""
 
95
    cmd = formcmd(cmd)
 
96
    log_linenumber()
 
97
    
 
98
    actual_retcode = call(cmd, stdout=logfile, stderr=logfile)
 
99
    
 
100
    if retcode != actual_retcode:
 
101
        raise CommandFailed("test failed: %r returned %d, expected %d"
 
102
                            % (cmd, actual_retcode, retcode))
 
103
 
 
104
 
 
105
 
 
106
def backtick(cmd, retcode=0):
 
107
    cmd = formcmd(cmd)
 
108
    log_linenumber()
 
109
    child = Popen(cmd, stdout=PIPE, stderr=logfile)
 
110
    outd, errd = child.communicate()
 
111
    logfile.write(outd)
 
112
    actual_retcode = child.wait()
 
113
 
 
114
    outd = outd.replace('\r', '')
 
115
    
 
116
    if retcode != actual_retcode:
 
117
        raise CommandFailed("test failed: %r returned %d, expected %d"
 
118
                            % (cmd, actual_retcode, retcode))
 
119
 
 
120
    return outd
 
121
 
 
122
 
 
123
 
 
124
def progress(msg):
 
125
    print '* ' + msg
 
126
    logfile.write('* '+ msg + '\n')
 
127
    log_linenumber()
 
128
 
 
129
 
 
130
def cd(dirname):
 
131
    logfile.write('$ cd %s\n' % dirname)
 
132
    os.chdir(dirname)
 
133
 
 
134
 
 
135
 
 
136
def log_linenumber():
 
137
    """Log the stack frame location two things up."""
 
138
    stack = traceback.extract_stack()[-3]
 
139
    logfile.write('   at %s:%d\n' % stack[:2])
 
140
 
 
141
 
 
142
 
 
143
# prepare an empty scratch directory
 
144
if os.path.exists(TESTDIR):
 
145
    shutil.rmtree(TESTDIR)
 
146
 
 
147
start_dir = os.getcwd()
 
148
 
 
149
 
 
150
logfile = open(LOGFILENAME, 'wt', buffering=1)
 
151
 
 
152
def test_plugins():
 
153
    """Run a test involving creating a plugin to load,
 
154
    and making sure it is seen properly.
 
155
    """
 
156
    mkdir('plugin_test')
 
157
    f = open(os.path.join('plugin_test', 'myplug.py'), 'wb')
 
158
    f.write("""import bzrlib, bzrlib.commands
 
159
class cmd_myplug(bzrlib.commands.Command):
 
160
    '''Just a simple test plugin.'''
 
161
    aliases = ['mplg']
 
162
    def run(self):
 
163
        print 'Hello from my plugin'
 
164
""")
 
165
    f.close()
 
166
 
 
167
    os.environ['BZRPLUGINPATH'] = os.path.abspath('plugin_test')
 
168
    help = backtick('bzr help commands')
 
169
    assert help.find('myplug') != -1
 
170
    assert help.find('Just a simple test plugin.') != -1
 
171
 
 
172
    
 
173
    assert backtick('bzr myplug') == 'Hello from my plugin\n'
 
174
    assert backtick('bzr mplg') == 'Hello from my plugin\n'
 
175
 
 
176
    f = open(os.path.join('plugin_test', 'override.py'), 'wb')
 
177
    f.write("""import bzrlib, bzrlib.commands
 
178
class cmd_commit(bzrlib.commands.cmd_commit):
 
179
    '''Commit changes into a new revision.'''
 
180
    def run(self, *args, **kwargs):
 
181
        print "I'm sorry dave, you can't do that"
 
182
 
 
183
class cmd_help(bzrlib.commands.cmd_help):
 
184
    '''Show help on a command or other topic.'''
 
185
    def run(self, *args, **kwargs):
 
186
        print "You have been overridden"
 
187
        bzrlib.commands.cmd_help.run(self, *args, **kwargs)
 
188
 
 
189
""")
 
190
    f.close()
 
191
 
 
192
    newhelp = backtick('bzr help commands')
 
193
    assert newhelp.startswith('You have been overridden\n')
 
194
    # We added a line, but the rest should work
 
195
    assert newhelp[25:] == help
 
196
 
 
197
    assert backtick('bzr commit -m test') == "I'm sorry dave, you can't do that\n"
 
198
    
 
199
    shutil.rmtree('plugin_test')
 
200
 
 
201
try:
 
202
    from getopt import getopt
 
203
    opts, args = getopt(sys.argv[1:], 'p:')
 
204
 
 
205
    for option, value in opts:
 
206
        if option == '-p':
 
207
            OVERRIDE_PYTHON = value
 
208
            
 
209
    
 
210
    mypath = os.path.abspath(sys.argv[0])
 
211
    print '%-30s %s' % ('running tests from', mypath)
 
212
 
 
213
    global BZRPATH
 
214
 
 
215
    if args:
 
216
        BZRPATH = args[0]
 
217
    else:
 
218
        BZRPATH = os.path.join(os.path.split(mypath)[0], 'bzr')
 
219
 
 
220
    print '%-30s %s' % ('against bzr', BZRPATH)
 
221
    print '%-30s %s' % ('in directory', os.getcwd())
 
222
    print '%-30s %s' % ('with python', (OVERRIDE_PYTHON or '(default)'))
 
223
    print
 
224
    print backtick('bzr version')
 
225
    
 
226
    runcmd(['mkdir', TESTDIR])
 
227
    cd(TESTDIR)
 
228
    test_root = os.getcwd()
 
229
 
 
230
    progress("introductory commands")
 
231
    runcmd("bzr version")
 
232
    runcmd("bzr --version")
 
233
    runcmd("bzr help")
 
234
    runcmd("bzr --help")
 
235
 
 
236
    progress("internal tests")
 
237
    runcmd("bzr selftest")
 
238
 
 
239
    progress("user identity")
 
240
    # this should always identify something, if only "john@localhost"
 
241
    runcmd("bzr whoami")
 
242
    runcmd("bzr whoami --email")
 
243
    assert backtick("bzr whoami --email").count('@') == 1
 
244
 
 
245
    progress("invalid commands")
 
246
    runcmd("bzr pants", retcode=1)
 
247
    runcmd("bzr --pants off", retcode=1)
 
248
    runcmd("bzr diff --message foo", retcode=1)
 
249
 
 
250
    progress("basic branch creation")
 
251
    runcmd(['mkdir', 'branch1'])
 
252
    cd('branch1')
 
253
    runcmd('bzr init')
 
254
 
 
255
    assert backtick('bzr root')[:-1] == os.path.join(test_root, 'branch1')
 
256
 
 
257
    progress("status of new file")
 
258
    
 
259
    f = file('test.txt', 'wt')
 
260
    f.write('hello world!\n')
 
261
    f.close()
 
262
 
 
263
    out = backtick("bzr unknowns")
 
264
    assert out == 'test.txt\n'
 
265
 
 
266
    out = backtick("bzr status")
 
267
    assert out == 'unknown:\n  test.txt\n'
 
268
 
 
269
    out = backtick("bzr status --all")
 
270
    assert out == "unknown:\n  test.txt\n"
 
271
 
 
272
    out = backtick("bzr status test.txt --all")
 
273
    assert out == "unknown:\n  test.txt\n"
 
274
 
 
275
    f = file('test2.txt', 'wt')
 
276
    f.write('goodbye cruel world...\n')
 
277
    f.close()
 
278
 
 
279
    out = backtick("bzr status test.txt")
 
280
    assert out == "unknown:\n  test.txt\n"
 
281
 
 
282
    out = backtick("bzr status")
 
283
    assert out == ("unknown:\n"
 
284
                   "  test.txt\n"
 
285
                   "  test2.txt\n")
 
286
 
 
287
    os.unlink('test2.txt')
 
288
 
 
289
    progress("command aliases")
 
290
    out = backtick("bzr st --all")
 
291
    assert out == ("unknown:\n"
 
292
                   "  test.txt\n")
 
293
    
 
294
    out = backtick("bzr stat")
 
295
    assert out == ("unknown:\n"
 
296
                   "  test.txt\n")
 
297
 
 
298
    progress("command help")
 
299
    runcmd("bzr help st")
 
300
    runcmd("bzr help")
 
301
    runcmd("bzr help commands")
 
302
    runcmd("bzr help slartibartfast", 1)
 
303
 
 
304
    out = backtick("bzr help ci")
 
305
    out.index('aliases: ')
 
306
 
 
307
    progress("can't rename unversioned file")
 
308
    runcmd("bzr rename test.txt new-test.txt", 1)
 
309
 
 
310
    progress("adding a file")
 
311
 
 
312
    runcmd("bzr add test.txt")
 
313
    assert backtick("bzr unknowns") == ''
 
314
    assert backtick("bzr status --all") == ("added:\n"
 
315
                                            "  test.txt\n")
 
316
 
 
317
    progress("rename newly-added file")
 
318
    runcmd("bzr rename test.txt hello.txt")
 
319
    assert os.path.exists("hello.txt")
 
320
    assert not os.path.exists("test.txt")
 
321
 
 
322
    assert backtick("bzr revno") == '0\n'
 
323
 
 
324
    progress("add first revision")
 
325
    runcmd(["bzr", "commit", "-m", 'add first revision'])
 
326
 
 
327
    progress("more complex renames")
 
328
    os.mkdir("sub1")
 
329
    runcmd("bzr rename hello.txt sub1", 1)
 
330
    runcmd("bzr rename hello.txt sub1/hello.txt", 1)
 
331
    runcmd("bzr move hello.txt sub1", 1)
 
332
 
 
333
    runcmd("bzr add sub1")
 
334
    runcmd("bzr rename sub1 sub2")
 
335
    runcmd("bzr move hello.txt sub2")
 
336
    assert backtick("bzr relpath sub2/hello.txt") == os.path.join("sub2", "hello.txt\n")
 
337
 
 
338
    assert exists("sub2")
 
339
    assert exists("sub2/hello.txt")
 
340
    assert not exists("sub1")
 
341
    assert not exists("hello.txt")
 
342
 
 
343
    runcmd(['bzr', 'commit', '-m', 'commit with some things moved to subdirs'])
 
344
 
 
345
    mkdir("sub1")
 
346
    runcmd('bzr add sub1')
 
347
    runcmd('bzr move sub2/hello.txt sub1')
 
348
    assert not exists('sub2/hello.txt')
 
349
    assert exists('sub1/hello.txt')
 
350
    runcmd('bzr move sub2 sub1')
 
351
    assert not exists('sub2')
 
352
    assert exists('sub1/sub2')
 
353
 
 
354
    runcmd(['bzr', 'commit', '-m', 'rename nested subdirectories'])
 
355
 
 
356
    cd('sub1/sub2')
 
357
    assert backtick('bzr root')[:-1] == os.path.join(test_root, 'branch1')
 
358
    runcmd('bzr move ../hello.txt .')
 
359
    assert exists('./hello.txt')
 
360
    assert backtick('bzr relpath hello.txt') == os.path.join('sub1', 'sub2', 'hello.txt\n')
 
361
    assert backtick('bzr relpath ../../sub1/sub2/hello.txt') == os.path.join('sub1', 'sub2', 'hello.txt\n')
 
362
    runcmd(['bzr', 'commit', '-m', 'move to parent directory'])
 
363
    cd('..')
 
364
    assert backtick('bzr relpath sub2/hello.txt') == os.path.join('sub1', 'sub2', 'hello.txt\n')
 
365
 
 
366
    runcmd('bzr move sub2/hello.txt .')
 
367
    assert exists('hello.txt')
 
368
 
 
369
    f = file('hello.txt', 'wt')
 
370
    f.write('some nice new content\n')
 
371
    f.close()
 
372
 
 
373
    f = file('msg.tmp', 'wt')
 
374
    f.write('this is my new commit\n')
 
375
    f.close()
 
376
 
 
377
    runcmd('bzr commit -F msg.tmp')
 
378
 
 
379
    assert backtick('bzr revno') == '5\n'
 
380
    runcmd('bzr export -r 5 export-5.tmp')
 
381
    runcmd('bzr export export.tmp')
 
382
 
 
383
    runcmd('bzr log')
 
384
    runcmd('bzr log -v')
 
385
 
 
386
 
 
387
 
 
388
    progress("file with spaces in name")
 
389
    mkdir('sub directory')
 
390
    file('sub directory/file with spaces ', 'wt').write('see how this works\n')
 
391
    runcmd('bzr add .')
 
392
    runcmd('bzr diff')
 
393
    runcmd('bzr commit -m add-spaces')
 
394
    runcmd('bzr check')
 
395
 
 
396
    runcmd('bzr log')
 
397
    runcmd('bzr log --forward')
 
398
 
 
399
    runcmd('bzr info')
 
400
 
 
401
 
 
402
    
 
403
 
 
404
 
 
405
 
 
406
    cd('..')
 
407
    cd('..')
 
408
    progress('branch')
 
409
    # Can't create a branch if it already exists
 
410
    runcmd('bzr branch branch1', retcode=1)
 
411
    # Can't create a branch if its parent doesn't exist
 
412
    runcmd('bzr branch /unlikely/to/exist', retcode=1)
 
413
    runcmd('bzr branch branch1 branch2')
 
414
 
 
415
    progress("pull")
 
416
    cd('branch1')
 
417
    runcmd('bzr pull', retcode=1)
 
418
    runcmd('bzr pull ../branch2')
 
419
    cd('.bzr')
 
420
    runcmd('bzr pull')
 
421
    runcmd('bzr commit -m empty')
 
422
    runcmd('bzr pull')
 
423
    cd('../../branch2')
 
424
    runcmd('bzr pull')
 
425
    runcmd('bzr commit -m empty')
 
426
    cd('../branch1')
 
427
    runcmd('bzr commit -m empty')
 
428
    runcmd('bzr pull', retcode=1)
 
429
    cd ('..')
 
430
 
 
431
    progress('status after remove')
 
432
    mkdir('status-after-remove')
 
433
    # see mail from William Dodé, 2005-05-25
 
434
    # $ bzr init; touch a; bzr add a; bzr commit -m "add a"
 
435
    #     * looking for changes...
 
436
    #     added a
 
437
    #     * commited r1
 
438
    #     $ bzr remove a
 
439
    #     $ bzr status
 
440
    #     bzr: local variable 'kind' referenced before assignment
 
441
    #     at /vrac/python/bazaar-ng/bzrlib/diff.py:286 in compare_trees()
 
442
    #     see ~/.bzr.log for debug information
 
443
    cd('status-after-remove')
 
444
    runcmd('bzr init')
 
445
    file('a', 'w').write('foo')
 
446
    runcmd('bzr add a')
 
447
    runcmd(['bzr', 'commit', '-m', 'add a'])
 
448
    runcmd('bzr remove a')
 
449
    runcmd('bzr status')
 
450
 
 
451
    cd('..')
 
452
 
 
453
    progress('ignore patterns')
 
454
    mkdir('ignorebranch')
 
455
    cd('ignorebranch')
 
456
    runcmd('bzr init')
 
457
    assert backtick('bzr unknowns') == ''
 
458
 
 
459
    file('foo.tmp', 'wt').write('tmp files are ignored')
 
460
    assert backtick('bzr unknowns') == ''
 
461
 
 
462
    file('foo.c', 'wt').write('int main() {}')
 
463
    assert backtick('bzr unknowns') == 'foo.c\n'
 
464
    runcmd('bzr add foo.c')
 
465
    assert backtick('bzr unknowns') == ''
 
466
 
 
467
    # 'ignore' works when creating the .bzignore file
 
468
    file('foo.blah', 'wt').write('blah')
 
469
    assert backtick('bzr unknowns') == 'foo.blah\n'
 
470
    runcmd('bzr ignore *.blah')
 
471
    assert backtick('bzr unknowns') == ''
 
472
    assert file('.bzrignore', 'rb').read() == '*.blah\n'
 
473
 
 
474
    # 'ignore' works when then .bzrignore file already exists
 
475
    file('garh', 'wt').write('garh')
 
476
    assert backtick('bzr unknowns') == 'garh\n'
 
477
    runcmd('bzr ignore garh')
 
478
    assert backtick('bzr unknowns') == ''
 
479
    assert file('.bzrignore', 'rb').read() == '*.blah\ngarh\n'
 
480
 
 
481
    cd('..')
 
482
 
 
483
 
 
484
 
 
485
 
 
486
    progress("recursive and non-recursive add")
 
487
    mkdir('no-recurse')
 
488
    cd('no-recurse')
 
489
    runcmd('bzr init')
 
490
    mkdir('foo')
 
491
    fp = os.path.join('foo', 'test.txt')
 
492
    f = file(fp, 'w')
 
493
    f.write('hello!\n')
 
494
    f.close()
 
495
    runcmd('bzr add --no-recurse foo')
 
496
    runcmd('bzr file-id foo')
 
497
    runcmd('bzr file-id ' + fp, 1)      # not versioned yet
 
498
    runcmd('bzr commit -m add-dir-only')
 
499
 
 
500
    runcmd('bzr file-id ' + fp, 1)      # still not versioned 
 
501
 
 
502
    runcmd('bzr add foo')
 
503
    runcmd('bzr file-id ' + fp)
 
504
    runcmd('bzr commit -m add-sub-file')
 
505
    
 
506
    cd('..')
 
507
 
 
508
 
 
509
 
 
510
 
 
511
    # Run any function in this 
 
512
    g = globals()
 
513
    funcs = g.keys()
 
514
    funcs.sort()
 
515
    for k in funcs:
 
516
        if k.startswith('test_') and callable(g[k]):
 
517
            progress(k[5:].replace('_', ' '))
 
518
            g[k]()
 
519
 
 
520
    progress("all tests passed!")
 
521
except Exception, e:
 
522
    sys.stderr.write('*' * 50 + '\n'
 
523
                     + 'testbzr: tests failed\n'
 
524
                     + 'see ' + LOGFILENAME + ' for more information\n'
 
525
                     + '*' * 50 + '\n')
 
526
    logfile.write('tests failed!\n')
 
527
    traceback.print_exc(None, logfile)
 
528
    logfile.close()
 
529
 
 
530
    sys.stdout.writelines(file(os.path.join(start_dir, LOGFILENAME), 'rt').readlines()[-50:])
 
531
    
 
532
    sys.exit(1)
 
533