1#! /usr/bin/env python3
2#
3# Copyright (C) 2020 Joshua Watt <JPEWhacker@gmail.com>
4#
5# SPDX-License-Identifier: MIT
6
7import argparse
8import os
9import random
10import shutil
11import signal
12import subprocess
13import sys
14import time
15
16
17def try_unlink(path):
18    try:
19        os.unlink(path)
20    except:
21        pass
22
23
24def main():
25    def cleanup():
26        shutil.rmtree("tmp/cache", ignore_errors=True)
27        try_unlink("bitbake-cookerdaemon.log")
28        try_unlink("bitbake.sock")
29        try_unlink("bitbake.lock")
30
31    parser = argparse.ArgumentParser(
32        description="Bitbake parser torture test",
33        epilog="""
34        A torture test for bitbake's parser. Repeatedly interrupts parsing until
35        bitbake decides to deadlock.
36        """,
37    )
38
39    args = parser.parse_args()
40
41    if not "BUILDDIR" in os.environ:
42        print(
43            "'BUILDDIR' not found in the environment. Did you initialize the build environment?"
44        )
45        return 1
46
47    os.chdir(os.environ["BUILDDIR"])
48
49    run_num = 0
50    while True:
51        if run_num % 100 == 0:
52            print("Calibrating wait time...")
53            cleanup()
54
55            start_time = time.monotonic()
56            r = subprocess.run(["bitbake", "-p"])
57            max_wait_time = time.monotonic() - start_time
58
59            if r.returncode != 0:
60                print("Calibration run exited with %d" % r.returncode)
61                return 1
62
63            print("Maximum wait time is %f seconds" % max_wait_time)
64
65        run_num += 1
66        wait_time = random.random() * max_wait_time
67
68        print("Run #%d" % run_num)
69        print("Will sleep for %f seconds" % wait_time)
70
71        cleanup()
72        with subprocess.Popen(["bitbake", "-p"]) as proc:
73            time.sleep(wait_time)
74            proc.send_signal(signal.SIGINT)
75            try:
76                proc.wait(45)
77            except subprocess.TimeoutExpired:
78                print("Run #%d: Waited too long. Possible deadlock!" % run_num)
79                proc.wait()
80                return 1
81
82            if proc.returncode == 0:
83                print("Exited successfully. Timeout too long?")
84            else:
85                print("Exited with %d" % proc.returncode)
86
87
88if __name__ == "__main__":
89    sys.exit(main())
90