2
# -*- coding: utf-8 -*-
 
 
4
# Copyright (C) 2005 Canonical Ltd
 
 
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.
 
 
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.
 
 
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
 
 
21
"""External black-box test for bzr.
 
 
23
This always runs bzr as an external process to try to catch bugs
 
 
24
related to argument processing, startup, etc.
 
 
28
    testbzr [-p PYTHON] [BZR]
 
 
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.
 
 
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
 
 
41
This replaces the previous test.sh which was not very portable."""
 
 
43
import sys, os, traceback
 
 
45
from os.path import exists
 
 
47
TESTDIR = "testbzr.tmp"
 
 
49
OVERRIDE_PYTHON = None
 
 
51
LOGFILENAME = 'testbzr.log'
 
 
55
    from subprocess import call, Popen, PIPE
 
 
56
except ImportError, e:
 
 
57
    sys.stderr.write("testbzr: sorry, this test suite requires modules from python2.4\n"
 
 
62
class CommandFailed(Exception):
 
 
67
    if isinstance(cmd, basestring):
 
 
73
            cmd.insert(0, OVERRIDE_PYTHON)
 
 
75
    logfile.write('$ %r\n' % cmd)
 
 
80
def runcmd(cmd, retcode=0):
 
 
81
    """Run one command and check the return code.
 
 
83
    Returns a tuple of (stdout,stderr) strings.
 
 
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."""
 
 
91
    actual_retcode = call(cmd, stdout=logfile, stderr=logfile)
 
 
93
    if retcode != actual_retcode:
 
 
94
        raise CommandFailed("test failed: %r returned %d, expected %d"
 
 
95
                            % (cmd, actual_retcode, retcode))
 
 
99
def backtick(cmd, retcode=0):
 
 
102
    child = Popen(cmd, stdout=PIPE, stderr=logfile)
 
 
103
    outd, errd = child.communicate()
 
 
105
    actual_retcode = child.wait()
 
 
107
    outd = outd.replace('\r', '')
 
 
109
    if retcode != actual_retcode:
 
 
110
        raise CommandFailed("test failed: %r returned %d, expected %d"
 
 
111
                            % (cmd, actual_retcode, retcode))
 
 
119
    logfile.write('* '+ msg + '\n')
 
 
124
    logfile.write('$ cd %s\n' % dirname)
 
 
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])
 
 
136
# prepare an empty scratch directory
 
 
137
if os.path.exists(TESTDIR):
 
 
138
    shutil.rmtree(TESTDIR)
 
 
140
start_dir = os.getcwd()
 
 
143
logfile = open(LOGFILENAME, 'wt', buffering=1)
 
 
147
    from getopt import getopt
 
 
148
    opts, args = getopt(sys.argv[1:], 'p:')
 
 
150
    for option, value in opts:
 
 
152
            OVERRIDE_PYTHON = value
 
 
155
    mypath = os.path.abspath(sys.argv[0])
 
 
156
    print '%-30s %s' % ('running tests from', mypath)
 
 
163
        BZRPATH = os.path.join(os.path.split(mypath)[0], 'bzr')
 
 
165
    print '%-30s %s' % ('against bzr', BZRPATH)
 
 
166
    print '%-30s %s' % ('in directory', os.getcwd())
 
 
167
    print '%-30s %s' % ('with python', (OVERRIDE_PYTHON or '(default)'))
 
 
169
    print backtick([BZRPATH, 'version'])
 
 
171
    runcmd(['mkdir', TESTDIR])
 
 
173
    test_root = os.getcwd()
 
 
175
    progress("introductory commands")
 
 
176
    runcmd("bzr version")
 
 
177
    runcmd("bzr --version")
 
 
181
    progress("internal tests")
 
 
182
    runcmd("bzr selftest")
 
 
184
    progress("user identity")
 
 
185
    # this should always identify something, if only "john@localhost"
 
 
187
    runcmd("bzr whoami --email")
 
 
188
    assert backtick("bzr whoami --email").count('@') == 1
 
 
190
    progress("invalid commands")
 
 
191
    runcmd("bzr pants", retcode=1)
 
 
192
    runcmd("bzr --pants off", retcode=1)
 
 
193
    runcmd("bzr diff --message foo", retcode=1)
 
 
195
    progress("basic branch creation")
 
 
196
    runcmd(['mkdir', 'branch1'])
 
 
200
    assert backtick('bzr root')[:-1] == os.path.join(test_root, 'branch1')
 
 
202
    progress("status of new file")
 
 
204
    f = file('test.txt', 'wt')
 
 
205
    f.write('hello world!\n')
 
 
208
    out = backtick("bzr unknowns")
 
 
209
    assert out == 'test.txt\n'
 
 
211
    out = backtick("bzr status")
 
 
212
    assert out == 'unknown:\n  test.txt\n'
 
 
214
    out = backtick("bzr status --all")
 
 
215
    assert out == "unknown:\n  test.txt\n"
 
 
217
    out = backtick("bzr status test.txt --all")
 
 
218
    assert out == "unknown:\n  test.txt\n"
 
 
220
    f = file('test2.txt', 'wt')
 
 
221
    f.write('goodbye cruel world...\n')
 
 
224
    out = backtick("bzr status test.txt")
 
 
225
    assert out == "unknown:\n  test.txt\n"
 
 
227
    out = backtick("bzr status")
 
 
228
    assert out == ("unknown:\n"
 
 
232
    os.unlink('test2.txt')
 
 
234
    progress("command aliases")
 
 
235
    out = backtick("bzr st --all")
 
 
236
    assert out == ("unknown:\n"
 
 
239
    out = backtick("bzr stat")
 
 
240
    assert out == ("unknown:\n"
 
 
243
    progress("command help")
 
 
244
    runcmd("bzr help st")
 
 
246
    runcmd("bzr help commands")
 
 
247
    runcmd("bzr help slartibartfast", 1)
 
 
249
    out = backtick("bzr help ci")
 
 
250
    out.index('aliases: ')
 
 
252
    progress("can't rename unversioned file")
 
 
253
    runcmd("bzr rename test.txt new-test.txt", 1)
 
 
255
    progress("adding a file")
 
 
257
    runcmd("bzr add test.txt")
 
 
258
    assert backtick("bzr unknowns") == ''
 
 
259
    assert backtick("bzr status --all") == ("added:\n"
 
 
262
    progress("rename newly-added file")
 
 
263
    runcmd("bzr rename test.txt hello.txt")
 
 
264
    assert os.path.exists("hello.txt")
 
 
265
    assert not os.path.exists("test.txt")
 
 
267
    assert backtick("bzr revno") == '0\n'
 
 
269
    progress("add first revision")
 
 
270
    runcmd(["bzr", "commit", "-m", 'add first revision'])
 
 
272
    progress("more complex renames")
 
 
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)
 
 
278
    runcmd("bzr add sub1")
 
 
279
    runcmd("bzr rename sub1 sub2")
 
 
280
    runcmd("bzr move hello.txt sub2")
 
 
281
    assert backtick("bzr relpath sub2/hello.txt") == os.path.join("sub2", "hello.txt\n")
 
 
283
    assert exists("sub2")
 
 
284
    assert exists("sub2/hello.txt")
 
 
285
    assert not exists("sub1")
 
 
286
    assert not exists("hello.txt")
 
 
288
    runcmd(['bzr', 'commit', '-m', 'commit with some things moved to subdirs'])
 
 
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')
 
 
299
    runcmd(['bzr', 'commit', '-m', 'rename nested subdirectories'])
 
 
302
    assert backtick('bzr root')[:-1] == os.path.join(test_root, 'branch1')
 
 
303
    runcmd('bzr move ../hello.txt .')
 
 
304
    assert exists('./hello.txt')
 
 
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')
 
 
307
    runcmd(['bzr', 'commit', '-m', 'move to parent directory'])
 
 
309
    assert backtick('bzr relpath sub2/hello.txt') == os.path.join('sub1', 'sub2', 'hello.txt\n')
 
 
311
    runcmd('bzr move sub2/hello.txt .')
 
 
312
    assert exists('hello.txt')
 
 
314
    f = file('hello.txt', 'wt')
 
 
315
    f.write('some nice new content\n')
 
 
318
    f = file('msg.tmp', 'wt')
 
 
319
    f.write('this is my new commit\n')
 
 
322
    runcmd('bzr commit -F msg.tmp')
 
 
324
    assert backtick('bzr revno') == '5\n'
 
 
325
    runcmd('bzr export -r 5 export-5.tmp')
 
 
326
    runcmd('bzr export export.tmp')
 
 
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')
 
 
338
    runcmd('bzr commit -m add-spaces')
 
 
342
    runcmd('bzr log --forward')
 
 
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...
 
 
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')
 
 
365
    file('a', 'w').write('foo')
 
 
367
    runcmd(['bzr', 'commit', '-m', 'add a'])
 
 
368
    runcmd('bzr remove a')
 
 
373
    progress('ignore patterns')
 
 
374
    mkdir('ignorebranch')
 
 
377
    assert backtick('bzr unknowns') == ''
 
 
379
    file('foo.tmp', 'wt').write('tmp files are ignored')
 
 
380
    assert backtick('bzr unknowns') == ''
 
 
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') == ''
 
 
387
    # 'ignore' works when creating the .bzignore file
 
 
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') == ''
 
 
392
    assert file('.bzrignore', 'rb').read() == '*.blah\n'
 
 
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'
 
 
403
    progress("all tests passed!")
 
 
405
    sys.stderr.write('*' * 50 + '\n'
 
 
406
                     + 'testbzr: tests failed\n'
 
 
407
                     + 'see ' + LOGFILENAME + ' for more information\n'
 
 
409
    logfile.write('tests failed!\n')
 
 
410
    traceback.print_exc(None, logfile)
 
 
413
    sys.stdout.writelines(file(os.path.join(start_dir, LOGFILENAME), 'rt').readlines()[-50:])