xref: /5.5.2/couchdb/test/etap/runtest.py (revision aae1433b)
1#!/usr/bin/env python
2# Description: Wrapper script for running CouchDB unit tests
3
4import sys
5import getopt
6import os
7import subprocess
8import re
9import platform
10import shlex
11
12TEST_COUNT_RE = r"^1\.\.(\d+)"
13TEST_OK_RE = r"(^ok)\b"
14TEST_NOT_OK_RE = r"(^not ok)\b"
15
16MODULES = ["../test/etap"]
17
18def usage():
19    print "Usage: %s -p builddir -l erl_libs_dir -m module_dir_paths" \
20    " -f erl_flags -t testfile [ -v ] [ -c couchstore_install_path ]" \
21    " [-e escript_path]" \
22    % sys.argv[0]
23    print
24
25def setup():
26    """Configure LD_LIBRARY_PATH"""
27    if platform.system() == "Linux":
28        dname, fname = os.path.split(os.path.abspath(__file__))
29        cpath = dname.split('couchdb')[0]
30        nspath = os.path.join(cpath, 'ns_server')
31
32        def read_configuration():
33            cfig = os.path.join(nspath, 'build', 'cluster_run.configuration')
34            with open(cfig) as f:
35                def fn(line):
36                    k, v = line.strip().split('=')
37                    return k, shlex.split(v)[0]
38                return dict(fn(line) for line in f.readlines())
39
40        config = read_configuration()
41        PREFIX = config['prefix']
42
43        LIBS = os.path.join(PREFIX, 'lib')
44        MEMCACHED = os.path.join(LIBS, 'memcached')
45        LD_LIBRARY_PATH = LIBS + os.pathsep + MEMCACHED
46        env = os.environ.copy()
47        if 'LD_LIBRARY_PATH' in env:
48            LD_LIBRARY_PATH += os.pathsep + env['LD_LIBRARY_PATH']
49        os.environ['LD_LIBRARY_PATH'] = LD_LIBRARY_PATH
50
51def run_test(testfile,eescript_path, verbose = False):
52    test_total = -1
53    test_passed = 0
54    exit_status = 0
55    count_re = re.compile(TEST_COUNT_RE)
56    ok_re = re.compile(TEST_OK_RE)
57    not_ok_re = re.compile(TEST_NOT_OK_RE)
58    s = subprocess.Popen([escript_path, testfile], stdout=subprocess.PIPE,
59            stderr=subprocess.PIPE)
60    while True:
61        line = s.stdout.readline()
62        if line:
63            if ok_re.match(line):
64                test_passed += 1
65                print line,
66            elif not_ok_re.match(line):
67                print line,
68            else:
69                if verbose:
70                    print line,
71
72                count = count_re.match(line)
73                if count:
74                    test_total = int(count.group(1))
75        else:
76            break
77
78    if test_total == test_passed:
79        exit_status = 0
80    else:
81        exit_status = 1
82        err = s.stderr.read()
83        if err:
84            print err
85
86    if test_total > 0:
87        print "%d/%d tests passed" %(test_passed, test_total)
88
89    return exit_status
90
91if __name__ == '__main__':
92    try:
93        opts, args = getopt.getopt(sys.argv[1:], "p:l:m:f:t:hvc:e:", \
94                    ["path=", "libsdir=", "modules=", "flags=", "test=",
95                     "help", "verbose", "couchstore-installdir=", "escript="])
96    except getopt.GetoptError, err:
97        print err
98        usage()
99        sys.exit(2)
100
101    if not opts:
102        usage()
103        sys.exit(2)
104
105    path = None
106    libsdir = None
107    test = None
108    modules = None
109    flags = None
110    verbose = False
111    couchstore_path = None
112    escript_path = 'escript'
113
114    for opt, arg in opts:
115        if opt in ("-p", "--path"):
116            path = arg
117        elif opt in ("-l", "--libsdir"):
118            libsdir = arg
119        elif opt in ("-m", "--modules"):
120            modules = arg
121        elif opt in ("-f", "--flags"):
122            flags = arg
123        elif opt in ("-t", "--test"):
124            test = arg
125        elif opt in ("-v", "--verbose"):
126            verbose = True
127        elif opt in ("-c", "--couchstore-installdir"):
128            couchstore_path = arg
129        elif opt in ("-e", "--escript"):
130            escript_path = arg
131        elif opt in ("-h", "--help"):
132            usage()
133            sys.exit(0)
134
135    if modules:
136        MODULES += modules.split(",")
137
138    erl_libs = []
139    env = os.getenv("ERL_LIBS")
140    if env:
141        erl_libs.append(env)
142    if libsdir:
143        erl_libs.append(libsdir)
144
145    erl_flags = []
146    env = os.getenv("ERL_FLAGS")
147    if env:
148        erl_flags.append(env)
149    if flags:
150        erl_flags.append(flags)
151
152    if path:
153        erl_libs.append(path)
154
155        # As some modules are not proper OTP apps, just add all dirs as
156        # ERL_FLAGS paths as well
157        MODULES += [d for d in os.listdir(path)
158                   if os.path.isdir(os.path.join(path, d))]
159
160        paths = map(lambda x: " %s" %os.path.join(path, x), MODULES)
161        erl_flags.append("-pa" + " ".join(paths))
162
163
164    # Erlang modules expect posix path format
165    # which is respected by all platforms
166    # including Windows. So replace '\' by '/'
167    # Ensure spaces escaped by '\' are intact,
168    # since directory names might contain space
169    pattern = re.compile(r'\\(\S)')
170
171    erl_flags = " ".join(erl_flags)
172    erl_flags = pattern.sub(r'/\1', erl_flags)
173    os.putenv("ERL_FLAGS", erl_flags)
174
175    erl_libs = os.pathsep.join(erl_libs)
176    erl_libs = pattern.sub(r'/\1', erl_libs)
177    os.putenv("ERL_LIBS", erl_libs)
178
179    if verbose:
180        print('ERL_LIBS="{}"'.format(erl_libs))
181        print('ERL_FLAGS="{}"'.format(erl_flags))
182
183    if couchstore_path:
184        env = os.getenv("PATH")
185        if env:
186            env += ":"
187        else:
188            env = ""
189
190        env += couchstore_path
191        os.putenv("PATH", env)
192
193    if test:
194        setup()
195        sys.exit(run_test(test, escript_path, verbose))
196    else:
197        sys.exit("ERROR: No test specified")
198