blob: e9ffb5657d389ae07aad8d6b78193460bf399beb [file] [log] [blame]
// Copyright 2017 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 <async/wait_with_timeout.h>
#include <unittest/unittest.h>
#include "async_stub.h"
namespace {
class MockAsync : public AsyncStub {
public:
async_wait_t* last_begin_wait = nullptr;
async_wait_t* last_cancel_wait = nullptr;
async_task_t* last_post_task = nullptr;
async_task_t* last_cancel_task = nullptr;
zx_status_t next_begin_wait_status = ZX_OK;
zx_status_t next_cancel_wait_status = ZX_OK;
zx_status_t next_post_task_status = ZX_OK;
zx_status_t next_cancel_task_status = ZX_OK;
zx_status_t BeginWait(async_wait_t* wait) override {
last_begin_wait = wait;
return next_begin_wait_status;
}
zx_status_t CancelWait(async_wait_t* wait) override {
last_cancel_wait = wait;
return next_cancel_wait_status;
}
zx_status_t PostTask(async_task_t* task) override {
last_post_task = task;
return next_post_task_status;
}
zx_status_t CancelTask(async_task_t* task) override {
last_cancel_task = task;
return next_cancel_task_status;
}
};
struct Handler {
Handler(async::WaitWithTimeout* wait) {
wait->set_handler([this, wait](async_t* async, zx_status_t status,
const zx_packet_signal_t* signal) {
handler_ran = true;
last_status = status;
last_signal = signal;
wait->set_deadline(wait->deadline() + 100u);
return status == ZX_OK ? ASYNC_WAIT_AGAIN : ASYNC_WAIT_FINISHED;
});
}
bool handler_ran = false;
zx_status_t last_status = ZX_ERR_INTERNAL;
const zx_packet_signal_t* last_signal = nullptr;
};
bool timeout_test() {
const zx_handle_t dummy_handle = 1;
const zx_signals_t dummy_trigger = ZX_USER_SIGNAL_0;
const zx_packet_signal_t dummy_signal{
.trigger = dummy_trigger,
.observed = ZX_USER_SIGNAL_0 | ZX_USER_SIGNAL_1,
.count = 0u,
.reserved0 = 0u,
.reserved1 = 0u};
const zx_time_t dummy_deadline = 100u;
const uint32_t dummy_flags = ASYNC_FLAG_HANDLE_SHUTDOWN;
BEGIN_TEST;
{
async::WaitWithTimeout default_wait;
EXPECT_EQ(ZX_HANDLE_INVALID, default_wait.object(), "default object");
EXPECT_EQ(ZX_SIGNAL_NONE, default_wait.trigger(), "default trigger");
EXPECT_EQ(ZX_TIME_INFINITE, default_wait.deadline(), "default deadline");
EXPECT_EQ(0u, default_wait.flags(), "default flags");
default_wait.set_object(dummy_handle);
EXPECT_EQ(dummy_handle, default_wait.object(), "set object");
default_wait.set_trigger(dummy_trigger);
EXPECT_EQ(dummy_trigger, default_wait.trigger(), "set trigger");
default_wait.set_deadline(dummy_deadline);
EXPECT_EQ(dummy_deadline, default_wait.deadline(), "set deadline");
default_wait.set_flags(dummy_flags);
EXPECT_EQ(dummy_flags, default_wait.flags(), "set flags");
EXPECT_FALSE(!!default_wait.handler(), "handler");
// Begin waiting without timeout (will be canceled immediately).
MockAsync async;
default_wait.set_deadline(ZX_TIME_INFINITE);
EXPECT_EQ(ZX_OK, default_wait.Begin(&async), "begin, valid args");
EXPECT_NONNULL(async.last_begin_wait, "begin wait called");
EXPECT_NULL(async.last_post_task, "post task not called");
EXPECT_EQ(dummy_handle, async.last_begin_wait->object, "handle");
EXPECT_EQ(dummy_trigger, async.last_begin_wait->trigger, "trigger");
EXPECT_EQ(dummy_flags, async.last_begin_wait->flags, "flags");
async.last_begin_wait = nullptr;
// Cancel waiting without timeout.
EXPECT_EQ(ZX_OK, default_wait.Cancel(&async), "cancel, valid args");
EXPECT_NONNULL(async.last_cancel_wait, "cancel wait called");
EXPECT_NULL(async.last_cancel_task, "cancel task not called");
async.last_cancel_wait = nullptr;
}
{
async::WaitWithTimeout explicit_wait(dummy_handle, dummy_trigger, dummy_deadline, dummy_flags);
EXPECT_EQ(dummy_handle, explicit_wait.object(), "explicit object");
EXPECT_EQ(dummy_trigger, explicit_wait.trigger(), "explicit trigger");
EXPECT_EQ(dummy_deadline, explicit_wait.deadline(), "explicit deadline");
EXPECT_EQ(dummy_flags, explicit_wait.flags(), "explicit flags");
EXPECT_FALSE(!!explicit_wait.handler(), "handler");
Handler handler(&explicit_wait);
EXPECT_TRUE(!!explicit_wait.handler());
// Begin waiting without timeout.
MockAsync async;
EXPECT_EQ(ZX_OK, explicit_wait.Begin(&async), "begin, valid args");
EXPECT_NONNULL(async.last_begin_wait, "begin wait called");
EXPECT_NONNULL(async.last_post_task, "post task called");
EXPECT_EQ(dummy_handle, async.last_begin_wait->object, "handle");
EXPECT_EQ(dummy_trigger, async.last_begin_wait->trigger, "trigger");
EXPECT_EQ(dummy_flags, async.last_begin_wait->flags, "flags");
EXPECT_EQ(dummy_deadline, async.last_post_task->deadline, "deadline");
async_wait_t* wait_context = async.last_begin_wait;
async_task_t* task_context = async.last_post_task;
async.last_begin_wait = nullptr;
async.last_post_task = nullptr;
// Handle wait.
EXPECT_EQ(ASYNC_WAIT_AGAIN, wait_context->handler(&async, wait_context, ZX_OK, &dummy_signal),
"invoke wait handler");
EXPECT_TRUE(handler.handler_ran, "handler ran");
EXPECT_EQ(ZX_OK, handler.last_status, "status");
EXPECT_EQ(&dummy_signal, handler.last_signal, "signal");
EXPECT_NONNULL(async.last_cancel_task, "cancel task called");
EXPECT_NONNULL(async.last_post_task, "post task called");
EXPECT_EQ(dummy_deadline + 100u, async.last_post_task->deadline, "deadline");
handler.handler_ran = false;
async.last_cancel_task = nullptr;
async.last_post_task = nullptr;
// Handle timeout.
EXPECT_EQ(ASYNC_TASK_FINISHED, task_context->handler(&async, task_context, ZX_OK),
"invoke timeout handler");
EXPECT_TRUE(handler.handler_ran, "handler ran");
EXPECT_EQ(ZX_ERR_TIMED_OUT, handler.last_status, "status");
EXPECT_NULL(handler.last_signal, "signal");
handler.handler_ran = false;
// Cancel waiting with timeout.
EXPECT_EQ(ZX_OK, explicit_wait.Cancel(&async), "cancel, valid args");
EXPECT_NONNULL(async.last_cancel_wait, "cancel wait called");
EXPECT_NONNULL(async.last_cancel_task, "cancel task called");
}
END_TEST;
}
bool begin_wait_cleans_up() {
const zx_handle_t dummy_handle = 1;
const zx_signals_t dummy_trigger = ZX_USER_SIGNAL_0;
const zx_time_t dummy_deadline = 100u;
const uint32_t dummy_flags = ASYNC_FLAG_HANDLE_SHUTDOWN;
BEGIN_TEST;
async::WaitWithTimeout wait(dummy_handle, dummy_trigger, dummy_deadline, dummy_flags);
// If an error occurs while setting the timeout, cancel the wait.
MockAsync async;
async.next_post_task_status = ZX_ERR_BAD_STATE;
EXPECT_EQ(ZX_ERR_BAD_STATE, wait.Begin(&async), "begin, will fail to post task");
EXPECT_NONNULL(async.last_begin_wait, "begin wait called");
EXPECT_NONNULL(async.last_post_task, "post task called");
EXPECT_NONNULL(async.last_cancel_wait, "cancel wait called");
END_TEST;
}
} // namespace
BEGIN_TEST_CASE(wait_with_timeout_tests)
RUN_TEST(timeout_test)
RUN_TEST(begin_wait_cleans_up)
END_TEST_CASE(wait_with_timeout_tests)