Subversion Repositories Kolibri OS

Rev

Rev 9329 | Rev 9331 | Go to most recent revision | Details | Compare with Previous | Last modification | View Log | RSS feed

Rev Author Line No. Line
9249 Boppan 1
#!/usr/bin/python3
9312 Boppan 2
# Copyright 2021 Magomed Kostoev
9249 Boppan 3
# Published under MIT License
4
 
5
import os
6
import sys
9314 Boppan 7
import urllib
9249 Boppan 8
from importlib.machinery import SourceFileLoader
9310 Boppan 9
from shutil import which
9249 Boppan 10
import timeit
11
import urllib.request
12
import subprocess
9322 Boppan 13
from threading import Thread
9249 Boppan 14
 
15
sys.path.append('test')
16
import common
17
 
9326 Boppan 18
enable_umka = False
19
 
9249 Boppan 20
def log(s, end = "\n"):
21
    print(s, end = end, flush = True)
22
 
23
def execute(s, mute = False):
24
    mute = ">/dev/null" if mute else ""
25
    code = os.system(f"{s}{mute}")
26
    if code:
27
        print(f"Command returned {code}: \"{s}\"")
28
        exit(-1)
29
 
30
def stage(name, command, mute = False):
31
    print(f"{name}... ", end = "")
32
    execute(command, mute = mute)
33
    print("Done.")
34
 
9314 Boppan 35
def download(link, path):
36
    log(f"Downloading {path}... ", end = "")
9315 Boppan 37
    urllib.request.urlretrieve(link, path)
9314 Boppan 38
    log("Done.")
39
 
9310 Boppan 40
def tool_exists(name):
41
    assert(type(name) == str)
42
    return which(name) != None
43
 
44
def check_tools(tools):
45
    assert(type(tools) == tuple)
46
    for name_package_pair in tools:
47
        assert(type(name_package_pair) == tuple)
48
        assert(len(name_package_pair) == 2)
49
        assert(type(name_package_pair[0]) == str)
50
        assert(type(name_package_pair[1]) == str)
51
 
52
    not_exists = []
53
    for name, package in tools:
54
        if not tool_exists(name):
55
            not_exists.append((name, package))
56
    if len(not_exists) != 0:
57
        log("Sorry, I can't find some tools:")
9311 Boppan 58
 
59
        header_name = "Name"
60
        header_package = "Package (probably)"
61
 
62
        max_name_len = len(header_name)
63
        max_package_name_len = len(header_package)
9310 Boppan 64
        for name, package in not_exists:
65
            if len(package) > max_package_name_len:
66
                max_package_name_len = len(package)
67
            if len(name) > max_name_len:
68
                max_name_len = len(name)
69
 
70
        def draw_row(name, package):
71
            log(f" | {name.ljust(max_name_len)} | {package.ljust(max_package_name_len)} |")
72
 
73
        def draw_line():
74
            log(f" +-{'-' * max_name_len}-+-{'-' * max_package_name_len}-+")
75
 
76
        draw_line()
9311 Boppan 77
        draw_row(header_name, header_package)
9310 Boppan 78
        draw_line()
79
        for name, package in not_exists:
80
            draw_row(name, package)
81
        draw_line()
82
        exit()
83
 
9321 Boppan 84
def prepare_test_img():
85
    # TODO: Always recompile the kernel (after build system is done?)
9313 Boppan 86
    # Get IMG
87
    if not os.path.exists("kolibri_test.img"):
88
        if len(sys.argv) == 1:
9314 Boppan 89
            download("http://builds.kolibrios.org/eng/data/data/kolibri.img", "kolibri_test.img")
9313 Boppan 90
        else:
91
            builds_eng = sys.argv[1]
92
            execute(f"cp {builds_eng}/data/data/kolibri.img kolibri_test.img")
93
 
9316 Boppan 94
    # Open the IMG
95
    with open("kolibri_test.img", "rb") as img:
96
        img_data = img.read()
97
    img = common.Floppy(img_data)
9321 Boppan 98
 
9316 Boppan 99
    # Remove unuseful folders
100
    img.delete_path("GAMES")
101
    img.delete_path("DEMOS")
102
    img.delete_path("3D")
9313 Boppan 103
 
104
    # Get test kernel
105
    if not os.path.exists("kernel.mnt.pretest"):
106
        if len(sys.argv) == 1:
107
            with open("lang.inc", "w") as lang_inc:
108
                lang_inc.write("lang fix en\n")
109
            execute("fasm bootbios.asm bootbios.bin.pretest -dpretest_build=1")
110
            execute("fasm -m 65536 kernel.asm kernel.mnt.pretest -dpretest_build=1 -ddebug_com_base=0xe9")
111
        else:
112
            builds_eng = sys.argv[1]
113
            execute(f"cp {builds_eng}/data/kernel/trunk/kernel.mnt.pretest kernel.mnt.pretest", mute = True)
114
 
115
    # Put the kernel into IMG
9316 Boppan 116
    with open("kernel.mnt.pretest", "rb") as kernel_mnt_pretest:
117
        kernel_mnt_pretest_data = kernel_mnt_pretest.read()
9317 Boppan 118
    img.add_file_path("KERNEL.MNT", kernel_mnt_pretest_data)
9316 Boppan 119
    img.save("kolibri_test.img")
9321 Boppan 120
 
121
def collect_tests():
122
    tests = []
123
 
9313 Boppan 124
    # Collect tests from test folder (not recursively yet)
125
    for test_folder in os.listdir("test"):
126
        test_folder_path = f"test/{test_folder}"
127
        test_file = f"{test_folder_path}/test.py"
9321 Boppan 128
 
9313 Boppan 129
        if not os.path.isdir(test_folder_path):
130
            continue
9321 Boppan 131
 
9313 Boppan 132
        if os.path.exists(test_file):
133
            tests.append(test_folder_path)
9321 Boppan 134
    return tests
135
 
9327 Boppan 136
def collect_umka_tests():
137
    tests = []
138
 
139
    for test_file in os.listdir("umka/test"):
140
        test_file_path = f"umka/test/{test_file}"
141
        if not test_file.endswith(".t"):
142
            continue
143
        if not os.path.isfile(test_file_path):
144
            continue
9328 Boppan 145
        tests.append(test_file)
9327 Boppan 146
    return tests
147
 
9323 Boppan 148
def run_tests_serially_thread(test, root_dir):
9313 Boppan 149
    test_number = 1
150
    for test in tests:
151
        test_dir = f"{root_dir}/{test}"
152
 
153
        os.chdir(test_dir)
154
        print(f"[{test_number}/{len(tests)}] {test}... ", end = "", flush=True)
155
        start = timeit.default_timer()
156
        try:
157
            SourceFileLoader("test", "test.py").load_module().run()
158
        except common.TestTimeoutException:
159
            result = "TIMEOUT"
160
        except common.TestFailureException:
161
            result = "FAILURE"
162
        else:
163
            result = "SUCCESS"
164
        finish = timeit.default_timer()
165
        print(f"{result} ({finish - start:.2f} seconds)")
166
        os.chdir(root_dir)
167
 
168
        test_number += 1
9322 Boppan 169
 
9323 Boppan 170
def run_tests_serially(tests, root_dir):
171
    thread = Thread(target = run_tests_serially_thread, args = (tests, root_dir))
172
    thread.start()
173
    return thread
174
 
9326 Boppan 175
def gcc(fin, fout):
9329 Boppan 176
    flags = "-m32 -std=c11 -g -O0 -masm=intel -fno-pie"
177
    defines = "-D_FILE_OFFSET_BITS=64 -DNDEBUG -D_POSIX_C_SOURCE=200809L"
178
    include = "-Iumka -Iumka/linux"
179
    command = f"gcc {flags} {defines} {include} -c {fin} -o {fout}"
9326 Boppan 180
    print(command)
181
    os.system(command)
182
 
9329 Boppan 183
def build_umka_asm():
184
    include = "INCLUDE=\"../../programs/develop/libraries/libcrash/hash\""
185
    flags = "-dUEFI=1 -dextended_primary_loader=1 -dUMKA=1"
186
    files = "umka/umka.asm umka/build/umka.o -s umka/build/umka.fas"
187
    memory = "-m 2000000"
188
    os.system(f"{include} fasm {flags} {files} {memory}")
189
 
9326 Boppan 190
def build_umka():
191
    if not enable_umka:
192
        return
193
    if os.path.exists("umka_shell"):
194
        return
9330 Boppan 195
    os.makedirs("umka/build/linux", exist_ok = True)
9329 Boppan 196
    sources = [ "umka_shell.c",
197
                "shell.c",
198
                "trace.c",
199
                "trace_lbr.c",
200
                "vdisk.c",
201
                "vnet.c",
202
                "lodepng.c",
203
                "linux/pci.c",
204
                "linux/thread.c",
205
                "util.c" ]
9326 Boppan 206
    sources = [f"umka/{f}" for f in sources]
9330 Boppan 207
    objects = []
9326 Boppan 208
    for source in sources:
9330 Boppan 209
        object_path = source.replace("umka/", "umka/build/")
210
        object_path = f"{object_path}.o"
211
        gcc(source, object_path)
212
        objects.append(object_path)
9329 Boppan 213
    build_umka_asm()
9330 Boppan 214
    objects.append("umka/build/umka.o")
215
    objects = " ".join(objects)
9326 Boppan 216
    os.system(f"gcc -m32 -no-pie -o umka_shell -static -T umka/umka.ld {objects}")
217
 
9328 Boppan 218
def run_umka_test(test_file_path):
219
    ref_log = f"{test_file_path[:-2]}.ref.log"
220
    out_log = f"{test_file_path[:-2]}.out.log"
221
    os.system(f"../../umka_shell < {test_file_path} > {out_log}")
222
    if os.system(f"cmp {ref_log} {out_log}") != 0:
223
        print(f"FAILURE: {test_file_path}\n", end = "")
224
    else:
225
        print(f"SUCCESS: {test_file_path}\n", end = "")
226
 
9322 Boppan 227
if __name__ == "__main__":
228
    root_dir = os.getcwd()
229
 
230
    # Check available tools
231
    tools = (("qemu-system-i386", "qemu-system-x86"),
232
             ("fasm", "fasm"))
233
    check_tools(tools)
9313 Boppan 234
 
9322 Boppan 235
    prepare_test_img()
9326 Boppan 236
    build_umka()
9322 Boppan 237
    tests = collect_tests()
9328 Boppan 238
    umka_tests = collect_umka_tests()
9323 Boppan 239
    serial_executor_thread = run_tests_serially(tests, root_dir)
240
    serial_executor_thread.join()
9328 Boppan 241
    if enable_umka:
242
        os.chdir(f"{root_dir}/umka/test")
243
        for umka_test in umka_tests:
244
            run_umka_test(umka_test)
9323 Boppan 245