diff --git a/desktop/api_tests.cpp b/desktop/api_tests.cpp index 0fb5db7..55f694a 100644 --- a/desktop/api_tests.cpp +++ b/desktop/api_tests.cpp @@ -1132,26 +1132,8 @@ bool PipeTests() { #define vfork() EsPOSIXSystemCall(SYS_vfork, 0, 0, 0, 0, 0, 0) #define wait4(x, y, z, w) EsPOSIXSystemCall(SYS_wait4, (intptr_t) x, (intptr_t) y, (intptr_t) z, (intptr_t) w, 0, 0) -bool POSIXSubsystemTest() { - const char *executeEnvironment[] = { - "PATH=/Applications/POSIX/bin", - "TMPDIR=/Applications/POSIX/tmp", - NULL, - }; - - const char *executable = "/Applications/POSIX/bin/busybox"; - - const char *argv[] = { - (char *) "busybox", - (char *) "echo", - (char *) "hello", - NULL, - }; - - int _argc; - char **_argv; - EsPOSIXInitialise(&_argc, &_argv); - +bool POSIXSubsystemRunCommandAndCheckOutput(const char **executeEnvironment, const char **argv, + const char *executable, const char *expectedOutput) { int stdoutPipe[2]; pipe(stdoutPipe); @@ -1166,7 +1148,7 @@ bool POSIXSubsystemTest() { return false; } else if (pid > 0) { close(stdoutPipe[1]); - char readData[10]; + char readData[4096]; int readPosition = 0; while (true) { @@ -1179,7 +1161,8 @@ bool POSIXSubsystemTest() { } } - if (readPosition != 6 || EsMemoryCompare(readData, "hello\n", 6)) { + if (readPosition != (int) EsCStringLength(expectedOutput) + || EsMemoryCompare(readData, expectedOutput, readPosition)) { EsPrint("Incorrect output: '%s'.\n", readPosition, readData); return false; } @@ -1196,6 +1179,33 @@ bool POSIXSubsystemTest() { return false; } + close(stdoutPipe[0]); + return true; +} + +bool POSIXSubsystemTest() { + int checkIndex = 0; + + const char *executeEnvironment[] = { + "PATH=/Applications/POSIX/bin", + "TMPDIR=/Applications/POSIX/tmp", + NULL, + }; + + int _argc; + char **_argv; + EsPOSIXInitialise(&_argc, &_argv); + + const char *executable = "/Applications/POSIX/bin/busybox"; + const char *argv[] = { "busybox", "sh", "test.sh", NULL, }; + + EsFileWriteAll(EsLiteral("0:/test.sh"), EsLiteral("echo hello")); + CHECK(POSIXSubsystemRunCommandAndCheckOutput(executeEnvironment, argv, executable, "hello\n")); + EsFileWriteAll(EsLiteral("0:/test.sh"), EsLiteral("echo world")); + CHECK(POSIXSubsystemRunCommandAndCheckOutput(executeEnvironment, argv, executable, "world\n")); + EsFileWriteAll(EsLiteral("0:/test.sh"), EsLiteral("find . | grep Kernel.esx")); + CHECK(POSIXSubsystemRunCommandAndCheckOutput(executeEnvironment, argv, executable, "./Essence/Kernel.esx\n")); + return true; } diff --git a/util/build.c b/util/build.c index d78dc2e..cdafe5b 100644 --- a/util/build.c +++ b/util/build.c @@ -1263,6 +1263,56 @@ void GetSource(const char *parameters, const char *checksum) { if (CallSystemF("mv %.*s bin/source", (int) (url - folder), folder)) exit(1); } +void RunTests(int singleTest) { + // TODO Capture (and compress) emulator memory dump if a test causes a KernelPanic or EsPanic. + // TODO Using SMP/KVM if available in the optimised test runs. + + int successCount = 0, failureCount = 0; + CallSystem("mkdir -p root/Essence/Settings/API\\ Tests"); + FILE *testFailures = fopen("bin/Logs/Test Failures.txt", "wb"); + + for (int optimisations = 0; optimisations <= 1; optimisations++) { + for (uint32_t index = 0; index < sizeof(tests) / sizeof(tests[0]); index++) { + if (singleTest != -1) { + if ((int) index != singleTest || optimisations) { + continue; + } + } + + CallSystem("rm -f bin/Logs/qemu_serial1.txt"); + FILE *f = fopen("root/Essence/Settings/API Tests/test.dat", "wb"); + fwrite(&index, 1, sizeof(uint32_t), f); + uint32_t mode = 1; + fwrite(&mode, 1, sizeof(uint32_t), f); + fclose(f); + emulatorTimeout = tests[index].timeoutSeconds; + if (optimisations) BuildAndRun(OPTIMISE_FULL, true, DEBUG_LATER, EMULATOR_QEMU_NO_GUI, LOG_NORMAL); + else BuildAndRun(OPTIMISE_OFF, true, DEBUG_LATER, EMULATOR_QEMU_NO_GUI, LOG_NORMAL); + emulatorTimeout = 0; + if (emulatorDidTimeout) encounteredErrors = false; + if (encounteredErrors) { fprintf(stderr, "Compile errors, stopping tests.\n"); goto stopTests; } + char *log = (char *) LoadFile("bin/Logs/qemu_serial1.txt", NULL); + if (!log) { fprintf(stderr, "No log file, stopping tests.\n"); goto stopTests; } + bool success = strstr(log, "[APITests-Success]\n") && !emulatorDidTimeout; + bool failure = strstr(log, "[APITests-Failure]\n"); + if (emulatorDidTimeout) fprintf(stderr, "'%s' (%d/%d): " ColorError "timeout" ColorNormal ".\n", tests[index].cName, optimisations, index); + else if (success) fprintf(stderr, "'%s' (%d/%d): success.\n", tests[index].cName, optimisations, index); + else if (failure) fprintf(stderr, "'%s' (%d/%d): " ColorError "failure" ColorNormal ".\n", tests[index].cName, optimisations, index); + else fprintf(stderr, "'%s' (%d/%d): " ColorError "no response" ColorNormal ".\n", tests[index].cName, optimisations, index); + if (success) successCount++; + else failureCount++; + free(log); + if (!success) CallSystemF("mv bin/Logs/qemu_serial1.txt bin/Logs/test_%d_%d.txt", optimisations, index); + if (!success) fprintf(testFailures, "%d/%d %s\n", optimisations, index, tests[index].cName); + } + } + + stopTests:; + fprintf(stderr, ColorHighlight "%d/%d tests succeeded." ColorNormal "\n", successCount, successCount + failureCount); + fclose(testFailures); + if (failureCount && automatedBuild) exit(1); +} + void DoCommand(const char *l) { while (l && (*l == ' ' || *l == '\t')) l++; @@ -1700,47 +1750,9 @@ void DoCommand(const char *l) { strcat(cwd, "/crash-report.tar.gz"); fprintf(stderr, "Crash report made at " ColorHighlight "%s" ColorNormal ".\n", cwd); } else if (0 == strcmp(l, "run-tests")) { - // TODO Capture (and compress) emulator memory dump if a test causes a KernelPanic or EsPanic. - // TODO Using SMP/KVM if available in the optimised test runs. - - int successCount = 0, failureCount = 0; - CallSystem("mkdir -p root/Essence/Settings/API\\ Tests"); - FILE *testFailures = fopen("bin/Logs/Test Failures.txt", "wb"); - - for (int optimisations = 0; optimisations <= 1; optimisations++) { - for (uint32_t index = 0; index < sizeof(tests) / sizeof(tests[0]); index++) { - CallSystem("rm -f bin/Logs/qemu_serial1.txt"); - FILE *f = fopen("root/Essence/Settings/API Tests/test.dat", "wb"); - fwrite(&index, 1, sizeof(uint32_t), f); - uint32_t mode = 1; - fwrite(&mode, 1, sizeof(uint32_t), f); - fclose(f); - emulatorTimeout = tests[index].timeoutSeconds; - if (optimisations) BuildAndRun(OPTIMISE_FULL, true, DEBUG_LATER, EMULATOR_QEMU_NO_GUI, LOG_NORMAL); - else BuildAndRun(OPTIMISE_OFF, true, DEBUG_LATER, EMULATOR_QEMU_NO_GUI, LOG_NORMAL); - emulatorTimeout = 0; - if (emulatorDidTimeout) encounteredErrors = false; - if (encounteredErrors) { fprintf(stderr, "Compile errors, stopping tests.\n"); goto stopTests; } - char *log = (char *) LoadFile("bin/Logs/qemu_serial1.txt", NULL); - if (!log) { fprintf(stderr, "No log file, stopping tests.\n"); goto stopTests; } - bool success = strstr(log, "[APITests-Success]\n") && !emulatorDidTimeout; - bool failure = strstr(log, "[APITests-Failure]\n"); - if (emulatorDidTimeout) fprintf(stderr, "'%s' (%d/%d): " ColorError "timeout" ColorNormal ".\n", tests[index].cName, optimisations, index); - else if (success) fprintf(stderr, "'%s' (%d/%d): success.\n", tests[index].cName, optimisations, index); - else if (failure) fprintf(stderr, "'%s' (%d/%d): " ColorError "failure" ColorNormal ".\n", tests[index].cName, optimisations, index); - else fprintf(stderr, "'%s' (%d/%d): " ColorError "no response" ColorNormal ".\n", tests[index].cName, optimisations, index); - if (success) successCount++; - else failureCount++; - free(log); - if (!success) CallSystemF("mv bin/Logs/qemu_serial1.txt bin/Logs/test_%d_%d.txt", optimisations, index); - if (!success) fprintf(testFailures, "%d/%d %s\n", optimisations, index, tests[index].cName); - } - } - - stopTests:; - fprintf(stderr, ColorHighlight "%d/%d tests succeeded." ColorNormal "\n", successCount, successCount + failureCount); - fclose(testFailures); - if (failureCount && automatedBuild) exit(1); + RunTests(-1); + } else if (0 == memcmp(l, "run-test ", 9)) { + RunTests(atoi(l + 9)); } else if (0 == strcmp(l, "setup-pre-built-toolchain")) { CallSystem("mv bin/source cross"); CallSystem("mkdir -p cross/bin2");