blob: 63e05f5830039a9eae0a7fd4decaf1ea2eec81d0 [file] [log] [blame]
// Copyright 2019 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 <lib/async/cpp/task.h>
#include <lib/sys/cpp/testing/test_with_environment.h>
#include "sync_manager.h"
#define ASSERT_OK(st) ASSERT_EQ(ZX_OK, (st))
#define ASSERT_NOK(st) ASSERT_NE(ZX_OK, (st))
#define WAIT_FOR_OK(ok) \
ASSERT_TRUE(RunLoopWithTimeoutOrUntil([&ok]() { return ok; }, zx::sec(2)))
#define WAIT_FOR_OK_AND_RESET(ok) \
WAIT_FOR_OK(ok); \
ok = false
namespace netemul {
namespace testing {
using sys::testing::EnclosingEnvironment;
using sys::testing::EnvironmentServices;
using sys::testing::TestWithEnvironment;
static const char* kMainTestBarrier = "test-barrier";
static const char* kAltTestBarrier = "alt-barrier";
class BarrierTest : public TestWithEnvironment {
public:
using SyncManagerPtr = fidl::InterfacePtr<SyncManager::FSyncManager>;
protected:
void SetUp() override {
fuchsia::sys::EnvironmentPtr parent_env;
real_services()->Connect(parent_env.NewRequest());
svc_loop_ =
std::make_unique<async::Loop>(&kAsyncLoopConfigNoAttachToThread);
ASSERT_OK(svc_loop_->StartThread("testloop"));
svc_ = std::make_unique<SyncManager>(svc_loop_->dispatcher());
auto services =
EnvironmentServices::Create(parent_env, svc_loop_->dispatcher());
services->AddService(svc_->GetHandler());
test_env_ = CreateNewEnclosingEnvironment("env", std::move(services));
WaitForEnclosingEnvToStart(test_env_.get());
}
void TearDown() override {
async::PostTask(svc_loop_->dispatcher(), [this]() {
svc_.reset();
svc_loop_->Quit();
});
svc_loop_->JoinThreads();
}
void GetSyncManager(
fidl::InterfaceRequest<SyncManager::FSyncManager> manager) {
test_env_->ConnectToService(std::move(manager));
}
std::unique_ptr<EnclosingEnvironment> test_env_;
std::unique_ptr<async::Loop> svc_loop_;
std::unique_ptr<SyncManager> svc_;
};
TEST_F(BarrierTest, FulfillBarrier) {
SyncManagerPtr sm;
GetSyncManager(sm.NewRequest());
bool got_callback = false;
// waiting on a count of 1 will always fullfill immediately:
sm->WaitForBarrierThreshold(kMainTestBarrier, 1, zx::msec(0).to_nsecs(),
[&got_callback](bool result) {
EXPECT_TRUE(result);
got_callback = true;
});
WAIT_FOR_OK_AND_RESET(got_callback);
}
TEST_F(BarrierTest, TimeoutBarrier) {
SyncManagerPtr sm;
GetSyncManager(sm.NewRequest());
bool got_callback = false;
// wait and timeout:
sm->WaitForBarrierThreshold(kMainTestBarrier, 2, zx::msec(15).to_nsecs(),
[&got_callback](bool result) {
EXPECT_FALSE(result);
got_callback = true;
});
WAIT_FOR_OK_AND_RESET(got_callback);
}
TEST_F(BarrierTest, DestroyWithPending) {
SyncManagerPtr sm;
GetSyncManager(sm.NewRequest());
// wait and timeout:
sm->WaitForBarrierThreshold(
kMainTestBarrier, 2, zx::msec(0).to_nsecs(),
[](bool result) { FAIL() << "Shouldn't call callback"; });
}
TEST_F(BarrierTest, ManyWaits) {
SyncManagerPtr sm;
GetSyncManager(sm.NewRequest());
bool got_callback1 = false;
bool got_callback2 = false;
bool got_callback3 = false;
bool got_callback4 = false;
sm->WaitForBarrierThreshold(kMainTestBarrier, 4, zx::msec(0).to_nsecs(),
[&got_callback1](bool result) {
EXPECT_TRUE(result);
got_callback1 = true;
});
sm->WaitForBarrierThreshold(kMainTestBarrier, 4, zx::msec(0).to_nsecs(),
[&got_callback2](bool result) {
EXPECT_TRUE(result);
got_callback2 = true;
});
sm->WaitForBarrierThreshold(kMainTestBarrier, 4, zx::msec(0).to_nsecs(),
[&got_callback3](bool result) {
EXPECT_TRUE(result);
got_callback3 = true;
});
// Wait for 5. Will trigger the others, but will timeout on itself.
sm->WaitForBarrierThreshold(kMainTestBarrier, 5, zx::msec(15).to_nsecs(),
[&got_callback4](bool result) {
EXPECT_FALSE(result);
got_callback4 = true;
});
ASSERT_TRUE(RunLoopWithTimeoutOrUntil(
[&]() {
return got_callback1 && got_callback2 && got_callback3 && got_callback4;
},
zx::sec(2)));
}
TEST_F(BarrierTest, DifferentBarriers) {
SyncManagerPtr sm;
GetSyncManager(sm.NewRequest());
bool got_callback1 = false;
bool got_callback2 = false;
bool got_callback3 = false;
sm->WaitForBarrierThreshold(kMainTestBarrier, 2, zx::msec(0).to_nsecs(),
[&got_callback1](bool result) {
EXPECT_TRUE(result);
got_callback1 = true;
});
sm->WaitForBarrierThreshold(kMainTestBarrier, 2, zx::msec(0).to_nsecs(),
[&got_callback2](bool result) {
EXPECT_TRUE(result);
got_callback2 = true;
});
// wait on different barrier. Should timeout.
sm->WaitForBarrierThreshold(kAltTestBarrier, 2, zx::msec(10).to_nsecs(),
[&got_callback3](bool result) {
EXPECT_FALSE(result);
got_callback3 = true;
});
ASSERT_TRUE(RunLoopWithTimeoutOrUntil(
[&]() { return got_callback1 && got_callback2 && got_callback3; },
zx::sec(2)));
}
} // namespace testing
} // namespace netemul