Subversion Repositories Kolibri OS

Rev

Rev 9338 | Rev 9340 | 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
 
9337 Boppan 18
enable_umka = True
9326 Boppan 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
9333 Boppan 145
        tests.append(test_file_path)
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
        print(f"[{test_number}/{len(tests)}] {test}... ", end = "", flush=True)
154
        start = timeit.default_timer()
155
        try:
9331 Boppan 156
            SourceFileLoader("test", f"{test_dir}/test.py").load_module().run(root_dir, test_dir)
9313 Boppan 157
        except common.TestTimeoutException:
158
            result = "TIMEOUT"
159
        except common.TestFailureException:
160
            result = "FAILURE"
161
        else:
162
            result = "SUCCESS"
163
        finish = timeit.default_timer()
164
        print(f"{result} ({finish - start:.2f} seconds)")
165
 
166
        test_number += 1
9322 Boppan 167
 
9323 Boppan 168
def run_tests_serially(tests, root_dir):
169
    thread = Thread(target = run_tests_serially_thread, args = (tests, root_dir))
170
    thread.start()
171
    return thread
172
 
9326 Boppan 173
def gcc(fin, fout):
9338 Boppan 174
    flags = "-m32 -std=c11 -g -O0 -fno-pie -w" # -masm-intel
9329 Boppan 175
    defines = "-D_FILE_OFFSET_BITS=64 -DNDEBUG -D_POSIX_C_SOURCE=200809L"
176
    include = "-Iumka -Iumka/linux"
9338 Boppan 177
    command = f"clang {flags} {defines} {include} -c {fin} -o {fout}"
9326 Boppan 178
    print(command)
179
    os.system(command)
180
 
9329 Boppan 181
def build_umka_asm():
182
    include = "INCLUDE=\"../../programs/develop/libraries/libcrash/hash\""
183
    flags = "-dUEFI=1 -dextended_primary_loader=1 -dUMKA=1"
184
    files = "umka/umka.asm umka/build/umka.o -s umka/build/umka.fas"
185
    memory = "-m 2000000"
9337 Boppan 186
    command = f"{include} fasm {flags} {files} {memory}"
187
    print(command)
188
    os.system(command)
9329 Boppan 189
 
9326 Boppan 190
def build_umka():
191
    if not enable_umka:
192
        return
9339 Boppan 193
    if os.path.exists("umka_shell.exe"):
9326 Boppan 194
        return
9330 Boppan 195
    os.makedirs("umka/build/linux", exist_ok = True)
9329 Boppan 196
    sources = [ "umka_shell.c",
197
                "shell.c",
198
                "vdisk.c",
199
                "lodepng.c",
200
                "linux/pci.c",
9337 Boppan 201
                "linux/thread.c" ]
9326 Boppan 202
    sources = [f"umka/{f}" for f in sources]
9330 Boppan 203
    objects = []
9326 Boppan 204
    for source in sources:
9330 Boppan 205
        object_path = source.replace("umka/", "umka/build/")
206
        object_path = f"{object_path}.o"
207
        gcc(source, object_path)
208
        objects.append(object_path)
9329 Boppan 209
    build_umka_asm()
9330 Boppan 210
    objects.append("umka/build/umka.o")
211
    objects = " ".join(objects)
9339 Boppan 212
    command = f"gcc -m32 -no-pie -o umka_shell.exe -static -T umka/umka.ld {objects}"
9337 Boppan 213
    print(command)
214
    os.system(command)
9326 Boppan 215
 
9333 Boppan 216
def create_relocated(root_dir, fname):
217
    with open(fname, "rb") as f:
218
        contents = f.read()
219
    new_contents = contents.replace(b"../img", bytes(f"{root_dir}/umka/img", "ascii"))
220
    new_contents = new_contents.replace(b"chess_image.rgb", bytes(f"{root_dir}/umka/test/chess_image.rgb", "ascii"))
221
    outname = f"{fname}.o" # .o extension just to avoid indexing of the file
222
    with open(outname, "wb") as f:
223
        f.write(new_contents)
224
    return outname
225
 
226
def run_umka_test(root_dir, test_file_path):
227
    test = create_relocated(root_dir, test_file_path)
228
    ref_log = create_relocated(root_dir, f"{test_file_path[:-2]}.ref.log")
9337 Boppan 229
    out_log = f"{test_file_path[:-2]}.out.log.o"
9339 Boppan 230
    os.system(f"./umka_shell.exe < {test} > {out_log}")
9328 Boppan 231
    if os.system(f"cmp {ref_log} {out_log}") != 0:
232
        print(f"FAILURE: {test_file_path}\n", end = "")
233
    else:
234
        print(f"SUCCESS: {test_file_path}\n", end = "")
235
 
9322 Boppan 236
if __name__ == "__main__":
237
    root_dir = os.getcwd()
238
 
239
    # Check available tools
240
    tools = (("qemu-system-i386", "qemu-system-x86"),
241
             ("fasm", "fasm"))
242
    check_tools(tools)
9313 Boppan 243
 
9322 Boppan 244
    prepare_test_img()
9326 Boppan 245
    build_umka()
9322 Boppan 246
    tests = collect_tests()
9328 Boppan 247
    umka_tests = collect_umka_tests()
9323 Boppan 248
    serial_executor_thread = run_tests_serially(tests, root_dir)
9328 Boppan 249
    if enable_umka:
250
        for umka_test in umka_tests:
9333 Boppan 251
            run_umka_test(root_dir, umka_test)
9335 Boppan 252
    serial_executor_thread.join()
9323 Boppan 253