| // Copyright 2018 The Fuchsia Authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| #include <runtests-utils/runtests-utils.h> |
| |
| #include <errno.h> |
| #include <stdlib.h> |
| #include <stdio.h> |
| #include <string.h> |
| #include <unistd.h> |
| |
| #include <fbl/auto_call.h> |
| #include <fbl/vector.h> |
| #include <launchpad/launchpad.h> |
| #include <lib/zx/job.h> |
| #include <lib/zx/process.h> |
| #include <lib/zx/time.h> |
| #include <zircon/listnode.h> |
| #include <zircon/process.h> |
| #include <zircon/syscalls.h> |
| #include <zircon/syscalls/object.h> |
| |
| |
| namespace runtests { |
| |
| Result RunTest(const char* argv[], int argc, FILE* out) { |
| int fds[2]; |
| const char* path = argv[0]; |
| |
| launchpad_t* lp = nullptr; |
| zx_status_t status = ZX_OK; |
| |
| zx::job test_job; |
| status = zx::job::create(zx_job_default(), 0, &test_job); |
| if (status != ZX_OK) { |
| printf("FAILURE: zx::job::create() returned %d\n", status); |
| return Result(path, FAILED_TO_LAUNCH, 0); |
| } |
| auto auto_call_kill_job = fbl::MakeAutoCall([&test_job]() { |
| test_job.kill(); |
| }); |
| auto auto_call_launchpad_destroy = fbl::MakeAutoCall([&lp]() { |
| if (lp) { |
| launchpad_destroy(lp); |
| } |
| }); |
| status = test_job.set_property(ZX_PROP_NAME, "run-test", sizeof("run-test")); |
| if (status != ZX_OK) { |
| printf("FAILURE: set_property() returned %d\n", status); |
| return Result(path, FAILED_TO_LAUNCH, 0); |
| } |
| status = launchpad_create(test_job.get(), path, &lp); |
| if (status != ZX_OK) { |
| printf("FAILURE: launchpad_create() returned %d\n", status); |
| return Result(path, FAILED_TO_LAUNCH, 0); |
| } |
| status = launchpad_load_from_file(lp, path); |
| if (status != ZX_OK) { |
| printf("FAILURE: launchpad_load_from_file() returned %d\n", status); |
| return Result(path, FAILED_TO_LAUNCH, 0); |
| } |
| status = launchpad_clone(lp, LP_CLONE_FDIO_ALL | LP_CLONE_ENVIRON); |
| if (status != ZX_OK) { |
| printf("FAILURE: launchpad_clone() returned %d\n", status); |
| return Result(path, FAILED_TO_LAUNCH, 0); |
| } |
| if (out != nullptr) { |
| if (pipe(fds)) { |
| printf("FAILURE: Failed to create pipe: %s\n", strerror(errno)); |
| return Result(path, FAILED_TO_LAUNCH, 0); |
| } |
| status = launchpad_clone_fd(lp, fds[1], STDOUT_FILENO); |
| if (status != ZX_OK) { |
| printf("FAILURE: launchpad_clone_fd() returned %d\n", status); |
| return Result(path, FAILED_TO_LAUNCH, 0); |
| } |
| status = launchpad_transfer_fd(lp, fds[1], STDERR_FILENO); |
| if (status != ZX_OK) { |
| printf("FAILURE: launchpad_transfer_fd() returned %d\n", status); |
| return Result(path, FAILED_TO_LAUNCH, 0); |
| } |
| } |
| launchpad_set_args(lp, argc, argv); |
| const char* errmsg; |
| zx::process process; |
| status = launchpad_go(lp, process.reset_and_get_address(), &errmsg); |
| lp = nullptr; // launchpad_go destroys lp, null it so we don't try to destroy again. |
| if (status != ZX_OK) { |
| printf("FAILURE: Failed to launch %s: %d: %s\n", path, status, errmsg); |
| return Result(path, FAILED_TO_LAUNCH, 0); |
| } |
| // Tee output. |
| if (out != nullptr) { |
| char buf[1024]; |
| ssize_t bytes_read = 0; |
| while ((bytes_read = read(fds[0], buf, sizeof(buf))) > 0) { |
| fwrite(buf, 1, bytes_read, out); |
| fwrite(buf, 1, bytes_read, stdout); |
| } |
| } |
| status = process.wait_one(ZX_PROCESS_TERMINATED, zx::time::infinite(), nullptr); |
| if (status != ZX_OK) { |
| printf("FAILURE: Failed to wait for process exiting %s: %d\n", path, status); |
| return Result(path, FAILED_TO_WAIT, 0); |
| } |
| |
| // read the return code |
| zx_info_process_t proc_info; |
| status = process.get_info(ZX_INFO_PROCESS, &proc_info, sizeof(proc_info), nullptr, nullptr); |
| |
| if (status != ZX_OK) { |
| printf("FAILURE: Failed to get process return code %s: %d\n", path, status); |
| return Result(path, FAILED_TO_RETURN_CODE, 0); |
| } |
| |
| if (proc_info.return_code != 0) { |
| printf("FAILURE: %s exited with nonzero status: %d\n", path, proc_info.return_code); |
| return Result(path, FAILED_NONZERO_RETURN_CODE, proc_info.return_code); |
| } |
| |
| printf("PASSED: %s passed\n", path); |
| return Result(path, SUCCESS, 0); |
| } |
| |
| |
| } // namespace runtests |