blob: 0acc77c952666e84bc75ce75cadf43f59bc283bd [file] [log] [blame]
// Copyright 2021 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 "src/sys/fuzzing/common/signal-coordinator.h"
#include <gtest/gtest.h>
#include "src/sys/fuzzing/common/testing/signal-coordinator.h"
namespace fuzzing {
namespace {
TEST(SignalCoordinatorTest, JoinAndReset) {
SignalCoordinator coordinator1, coordinator2;
auto paired = coordinator1.Create([](zx_signals_t s) { return true; });
coordinator2.Pair(std::move(paired), [](zx_signals_t s) { return true; });
// |Join| will block until the coordinator is stopped. |Reset| stops the object and its peer.
std::thread t1([&]() { coordinator1.Join(); });
coordinator2.Reset();
t1.join();
// |Join| does not block if already stopped. |Reset| is idempotent.
coordinator1.Join();
coordinator2.Reset();
coordinator2.Join();
}
TEST(SignalCoordinatorTest, AutoReset) {
SignalCoordinator coordinator1, coordinator2;
auto paired = coordinator1.Create([](zx_signals_t s) { return true; });
coordinator2.Pair(std::move(paired), [](zx_signals_t s) { return true; });
// Re-creating the coordinator will reset it, and stop its peer.
std::thread t1([&]() { coordinator1.Join(); });
auto paired1 = coordinator2.Create([](zx_signals_t s) { return true; });
t1.join();
coordinator1.Pair(std::move(paired1), [](zx_signals_t s) { return true; });
// Similarly, re-pairing also resets.
zx::eventpair paired2a, paired2b;
ASSERT_EQ(zx::eventpair::create(0, &paired2a, &paired2b), ZX_OK);
std::thread t2([&]() { coordinator2.Join(); });
coordinator1.Pair(std::move(paired2a), [](zx_signals_t s) { return true; });
t2.join();
}
TEST(SignalCoordinatorTest, WaitLoop) {
FakeSignalCoordinator coordinator1, coordinator2;
coordinator2.Pair(coordinator1.Create());
// Can send all signals, both ways.
std::vector<Signal> signals = {
kStart,
kFinish,
kStartLeakCheck,
kFinishWithLeaks,
};
std::thread t;
for (auto signal : signals) {
t = std::thread([&]() { EXPECT_EQ(coordinator2.AwaitSignal(), signal); });
EXPECT_TRUE(coordinator1.SignalPeer(signal));
t.join();
t = std::thread([&]() { EXPECT_EQ(coordinator1.AwaitSignal(), signal); });
EXPECT_TRUE(coordinator2.SignalPeer(signal));
t.join();
}
}
TEST(SignalCoordinatorTest, PeerClosed) {
FakeSignalCoordinator coordinator1, coordinator2;
coordinator2.Pair(coordinator1.Create());
std::thread t([&]() {
auto observed = coordinator2.AwaitSignal();
// Signals may arrive separately or combined.
if (observed == kStart) {
EXPECT_EQ(coordinator2.AwaitSignal(), ZX_EVENTPAIR_PEER_CLOSED);
} else {
EXPECT_NE(observed & ZX_EVENTPAIR_PEER_CLOSED, 0U);
}
});
EXPECT_TRUE(coordinator1.SignalPeer(kStart));
coordinator1.Reset();
t.join();
// After ZX_EVENTPAIR_PEER_CLOSED, the coordinator stops...
coordinator2.Join();
// Once stopped, can't send more signals.
EXPECT_FALSE(coordinator1.SignalPeer(kStart));
}
} // namespace
} // namespace fuzzing