blob: 4c1cd8e4219faf7d36bad35fc1a271c4bcddd0e7 [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 <threads.h>
#include <mx/handle.h>
#include <async/async.h>
#include <unittest/unittest.h>
#include "async_stub.h"
namespace {
class MockAsync : public AsyncStub {
public:
enum class Op {
NONE,
BEGIN_WAIT,
CANCEL_WAIT,
POST_TASK,
CANCEL_TASK,
QUEUE_PACKET
};
Op last_op = Op::NONE;
async_wait_t* last_wait = nullptr;
async_task_t* last_task = nullptr;
async_receiver_t* last_receiver = nullptr;
const mx_packet_user_t* last_data = nullptr;
mx_status_t BeginWait(async_wait_t* wait) override {
last_op = Op::BEGIN_WAIT;
last_wait = wait;
return MX_OK;
}
mx_status_t CancelWait(async_wait_t* wait) override {
last_op = Op::CANCEL_WAIT;
last_wait = wait;
return MX_OK;
}
mx_status_t PostTask(async_task_t* task) override {
last_op = Op::POST_TASK;
last_task = task;
return MX_OK;
}
mx_status_t CancelTask(async_task_t* task) override {
last_op = Op::CANCEL_TASK;
last_task = task;
return MX_OK;
}
mx_status_t QueuePacket(async_receiver_t* receiver,
const mx_packet_user_t* data) override {
last_op = Op::QUEUE_PACKET;
last_receiver = receiver;
last_data = data;
return MX_OK;
}
};
class MockWait : public async::Wait {
public:
MockWait() {}
MockWait(mx_handle_t object, mx_signals_t trigger, uint32_t flags)
: async::Wait(object, trigger, flags) {}
bool handler_ran = false;
mx_status_t last_status = MX_ERR_INTERNAL;
const mx_packet_signal_t* last_signal = nullptr;
protected:
async_wait_result_t Handle(async_t* async, mx_status_t status,
const mx_packet_signal_t* signal) override {
handler_ran = true;
last_status = status;
last_signal = signal;
return ASYNC_WAIT_AGAIN;
}
};
bool wait_test() {
const mx_handle_t dummy_handle = 1;
const mx_signals_t dummy_trigger = MX_USER_SIGNAL_0;
const mx_packet_signal_t dummy_signal{
.trigger = dummy_trigger,
.observed = MX_USER_SIGNAL_0 | MX_USER_SIGNAL_1,
.count = 0u};
const uint32_t dummy_flags = ASYNC_HANDLE_SHUTDOWN;
BEGIN_TEST;
MockWait default_wait;
EXPECT_EQ(MX_HANDLE_INVALID, default_wait.object(), "default object");
EXPECT_EQ(MX_SIGNAL_NONE, default_wait.trigger(), "default trigger");
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_flags(dummy_flags);
EXPECT_EQ(dummy_flags, default_wait.flags(), "set flags");
MockWait explicit_wait(dummy_handle, dummy_trigger, dummy_flags);
EXPECT_EQ(dummy_handle, explicit_wait.object(), "explicit object");
EXPECT_EQ(dummy_trigger, explicit_wait.trigger(), "explicit trigger");
EXPECT_EQ(dummy_flags, explicit_wait.flags(), "explicit flags");
MockAsync async;
EXPECT_EQ(MX_OK, explicit_wait.Begin(&async), "begin, valid args");
EXPECT_EQ(MockAsync::Op::BEGIN_WAIT, async.last_op, "op");
EXPECT_EQ(dummy_handle, async.last_wait->object, "handle");
EXPECT_EQ(dummy_trigger, async.last_wait->trigger, "trigger");
EXPECT_EQ(dummy_flags, async.last_wait->flags, "flags");
EXPECT_EQ(ASYNC_WAIT_AGAIN, async.last_wait->handler(&async, async.last_wait, MX_OK, &dummy_signal),
"invoke handler");
EXPECT_TRUE(explicit_wait.handler_ran, "handler ran");
EXPECT_EQ(MX_OK, explicit_wait.last_status, "status");
EXPECT_EQ(&dummy_signal, explicit_wait.last_signal, "signal");
EXPECT_EQ(MX_OK, explicit_wait.Cancel(&async), "cancel, valid args");
EXPECT_EQ(MockAsync::Op::CANCEL_WAIT, async.last_op, "op");
END_TEST;
}
class MockTask : public async::Task {
public:
MockTask() {}
MockTask(mx_time_t deadline, uint32_t flags)
: async::Task(deadline, flags) {}
bool handler_ran = false;
mx_status_t last_status = MX_ERR_INTERNAL;
protected:
async_task_result_t Handle(async_t* async, mx_status_t status) override {
handler_ran = true;
last_status = status;
return ASYNC_TASK_REPEAT;
}
};
bool task_test() {
const mx_time_t dummy_deadline = 1;
const uint32_t dummy_flags = ASYNC_HANDLE_SHUTDOWN;
BEGIN_TEST;
MockTask default_task;
EXPECT_EQ(MX_TIME_INFINITE, default_task.deadline(), "default deadline");
EXPECT_EQ(0u, default_task.flags(), "default flags");
default_task.set_deadline(dummy_deadline);
EXPECT_EQ(dummy_deadline, default_task.deadline(), "set deadline");
default_task.set_flags(dummy_flags);
EXPECT_EQ(dummy_flags, default_task.flags(), "set flags");
MockTask explicit_task(dummy_deadline, dummy_flags);
EXPECT_EQ(dummy_deadline, default_task.deadline(), "explicit deadline");
EXPECT_EQ(dummy_flags, explicit_task.flags(), "explicit flags");
MockAsync async;
EXPECT_EQ(MX_OK, explicit_task.Post(&async), "post, valid args");
EXPECT_EQ(MockAsync::Op::POST_TASK, async.last_op, "op");
EXPECT_EQ(dummy_deadline, async.last_task->deadline, "deadline");
EXPECT_EQ(dummy_flags, async.last_task->flags, "flags");
EXPECT_EQ(ASYNC_TASK_REPEAT, async.last_task->handler(&async, async.last_task, MX_OK),
"invoke handler");
EXPECT_TRUE(explicit_task.handler_ran, "handler ran");
EXPECT_EQ(MX_OK, explicit_task.last_status, "status");
EXPECT_EQ(MX_OK, explicit_task.Cancel(&async), "cancel, valid args");
EXPECT_EQ(MockAsync::Op::CANCEL_TASK, async.last_op, "op");
END_TEST;
}
class MockReceiver : public async::Receiver {
public:
MockReceiver() {}
MockReceiver(uint32_t flags)
: async::Receiver(flags) {}
bool handler_ran = false;
mx_status_t last_status = MX_ERR_INTERNAL;
const mx_packet_user_t* last_data = nullptr;
protected:
void Handle(async_t* async, mx_status_t status, const mx_packet_user_t* data) override {
handler_ran = true;
last_status = status;
last_data = data;
}
};
bool receiver_test() {
const uint32_t dummy_flags = ASYNC_HANDLE_SHUTDOWN;
const mx_packet_user_t dummy_data{};
BEGIN_TEST;
MockReceiver default_receiver;
EXPECT_EQ(0u, default_receiver.flags(), "default flags");
default_receiver.set_flags(dummy_flags);
EXPECT_EQ(dummy_flags, default_receiver.flags(), "set flags");
MockReceiver explicit_receiver(dummy_flags);
EXPECT_EQ(dummy_flags, explicit_receiver.flags(), "explicit flags");
MockAsync async;
EXPECT_EQ(MX_OK, explicit_receiver.Queue(&async, nullptr), "queue, null data");
EXPECT_EQ(MockAsync::Op::QUEUE_PACKET, async.last_op, "op");
EXPECT_EQ(dummy_flags, async.last_receiver->flags, "flags");
EXPECT_NULL(async.last_data, "data");
EXPECT_EQ(MX_OK, explicit_receiver.Queue(&async, &dummy_data), "queue, non-null data");
EXPECT_EQ(MockAsync::Op::QUEUE_PACKET, async.last_op, "op");
EXPECT_EQ(dummy_flags, async.last_receiver->flags, "flags");
EXPECT_EQ(&dummy_data, async.last_data, "data");
async.last_receiver->handler(&async, async.last_receiver, MX_OK, nullptr);
EXPECT_TRUE(explicit_receiver.handler_ran, "handler ran");
EXPECT_EQ(MX_OK, explicit_receiver.last_status, "status");
EXPECT_NULL(explicit_receiver.last_data, "data");
async.last_receiver->handler(&async, async.last_receiver, MX_OK, &dummy_data);
EXPECT_TRUE(explicit_receiver.handler_ran, "handler ran");
EXPECT_EQ(MX_OK, explicit_receiver.last_status, "status");
EXPECT_EQ(&dummy_data, explicit_receiver.last_data, "data");
END_TEST;
}
} // namespace
BEGIN_TEST_CASE(async_wrapper_tests)
RUN_TEST(wait_test)
RUN_TEST(task_test)
RUN_TEST(receiver_test)
END_TEST_CASE(async_wrapper_tests)