test.py 3.73 KB
Newer Older
Maxime Perrotin's avatar
Maxime Perrotin committed
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
#!/usr/bin/env python3
import subprocess
import sys
import time
import signal
import os
from functools       import partial
from multiprocessing import cpu_count
from concurrent      import futures


def colorMe(result, msg):
    if sys.stdout.isatty():
        code = "1" if result else "2"
        msg = chr(27) + "[3" + code + "m" + msg + chr(27) + "[0m"
    return msg

def main():
    ''' Run the test cases in parallel on all available CPUs '''
    start = time.time()
    results = []
    rule = sys.argv[1]
    paths = sys.argv[2:]

    with futures.ProcessPoolExecutor(max_workers=cpu_count()) as executor:
Maxime Perrotin's avatar
Maxime Perrotin committed
26
27
28
29
30
31
32
33
        fs = [executor.submit(partial(make, rule), path) for path in paths]
        for each in futures.as_completed(fs):
            result = each.result()
            errcode, stdout, stderr, path, rule = result
            name = path.replace("/", "")
            print("%40s: %s" % (name,
               colorMe (errcode, '[OK]' if errcode==0
                  else '[FAILED] ... build log in /tmp/{}.err'.format(name))))
34
            sys.stdout.flush()
Maxime Perrotin's avatar
Maxime Perrotin committed
35
36
37
38
39
40
41
42
43
44
45
46
            if errcode != 0:
                # Failure: save the log immediately
                with open("/tmp/{}.err".format(name), 'w') as f:
                    f.write("=" * 80)
                    f.write("ERROR: %s %s" % (name, rule))
                    if stdout:
                        f.write("-- stdout " + "-" * 70)
                        f.write(stdout.decode())
                    if stderr:
                        f.write("-- stderr " + "-" * 70)
                        f.write(stderr.decode())
                        f.write("-" * 80)
Maxime Perrotin's avatar
Maxime Perrotin committed
47
            results.append(result)
Maxime Perrotin's avatar
Maxime Perrotin committed
48
49
50
51
52
53
54
55
            # don't use the map function, because it keeps the order of
            # submission, meaning that even if a job finishes before the
            # previous one started, the log output will be delayed
#       for result in executor.map(partial(make, rule), paths):
#           print("%40s: %s" % (result[3].replace("/", ""), colorMe(result[0],
#                              '[OK]' if result[0]==0 else '[FAILED]')))
#           sys.stdout.flush()
#           results.append(result)
Maxime Perrotin's avatar
Maxime Perrotin committed
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
        executor.map(partial(make, 'clean'), paths)
    sys.stdout.write('\n')

    elapsed = time.time() - start
    return summarize(results, elapsed)


def make(rule, path):
    ''' Call a Makefile with the required rule (e.g. build or clean) '''
    proc = subprocess.Popen(
        ['make', '-C', path, rule],
        stdout=subprocess.PIPE,
        stderr=subprocess.PIPE
    )
    stdout, stderr = proc.communicate()
    errcode = proc.wait()
    return (errcode, stdout, stderr, path, rule)


def summarize(results, elapsed):
    ''' At the end display the errors of project that failed '''
    failed = 0
Maxime Perrotin's avatar
Maxime Perrotin committed
78
79
80
    with open("/tmp/kazoo.err", "w") as f:
        f.write("kazoo test report")
        f.write("-----------------")
Maxime Perrotin's avatar
Maxime Perrotin committed
81
82
83
84
    for errcode, stdout, stderr, path, rule in results:
        if errcode == 0:
            continue
        failed += 1
Maxime Perrotin's avatar
Maxime Perrotin committed
85
86
87
88
89
90
91
92
93
94
        with open("/tmp/kazoo.err", 'a') as f:
            f.write("=" * 80)
            f.write("ERROR: %s %s" % (path, rule))
            if stdout:
                f.write("-- stdout " + "-" * 70)
                f.write(stdout.decode())
            if stderr:
                f.write("-- stderr " + "-" * 70)
                f.write(stderr.decode())
                f.write("-" * 80)
Maxime Perrotin's avatar
Maxime Perrotin committed
95
    print("Finished in %.3fs" % elapsed)
Maxime Perrotin's avatar
Maxime Perrotin committed
96
97
    if failed:
        print("Test report in /tmp/kazoo.err")
Maxime Perrotin's avatar
Maxime Perrotin committed
98
99
100
101
102
103
104
105
106
107
108
    print("%s tests, %s errors" % (len(results), failed))
    return 0 if not failed else 1


if __name__ == '__main__':
    # Catch Ctrl-C to stop the app from the console
    signal.signal(signal.SIGINT, signal.SIG_DFL)
    ret = main()
    sys.stdout.write('\033[0m\n')
    sys.stdout.flush()
    sys.exit(ret)