~bzr-pqm/bzr/bzr.dev

« back to all changes in this revision

Viewing changes to testbzr

  • Committer: Martin Pool
  • Date: 2005-06-13 12:14:52 UTC
  • Revision ID: mbp@sourcefrog.net-20050613121452-c50982a6affa3782
- draft 'meta' command by john

Show diffs side-by-side

added added

removed removed

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