blob: f968c56d029fcf1987c8f4b754194899249edcb4 [file] [log] [blame]
// 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