blob: 4ffb9453fc1bc234d912932fe02ec5a72f2154d1 [file] [log] [blame]
// Copyright 2022 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 "harness.h"
#include <fidl/fidl.serversuite/cpp/common_types.h>
#include <fidl/fidl.serversuite/cpp/markers.h>
#include <fidl/fidl.serversuite/cpp/natural_ostream.h>
#include <fidl/fidl.serversuite/cpp/natural_types.h>
#include <lib/component/incoming/cpp/protocol.h>
#include <lib/zx/object_traits.h>
#include <lib/zx/time.h>
#include <zircon/types.h>
#include <gtest/gtest.h>
#include "src/lib/testing/predicates/status.h"
#include "src/tests/fidl/dynsuite/channel_util/channel.h"
namespace server_suite {
namespace {
const char* RunnerEventName(RunnerEvent event) {
switch (event) {
#define X(name) \
case RunnerEvent::k##name: \
return #name;
X_RUNNER_EVENT_NAMES
#undef X
}
}
} // namespace
void ServerTest::SetUp() {
// Connect to the Runner.
{
auto client_end = component::Connect<fidl_serversuite::Runner>();
ASSERT_OK(client_end.status_value());
runner_ = fidl::SyncClient<fidl_serversuite::Runner>(std::move(*client_end));
}
// Get the version.
{
auto result = runner_->GetVersion();
ASSERT_TRUE(result.is_ok()) << "Runner.GetVersion() failed: " << result.error_value();
runner_version_ = result->version();
}
// TODO(https://fxbug.dev/42082237): Remove after updating Dart.
SKIP_IF_VERSION_OLDER_THAN(1);
// Start the Target server.
{
zx::channel client_end, server_end;
ASSERT_OK(zx::channel::create(0, &client_end, &server_end));
auto any_target = [&]() {
switch (target_kind_) {
case fidl_serversuite::AnyTarget::Tag::kClosed:
return fidl_serversuite::AnyTarget::WithClosed(
fidl::ServerEnd<fidl_serversuite::ClosedTarget>(std::move(server_end)));
case fidl_serversuite::AnyTarget::Tag::kAjar:
return fidl_serversuite::AnyTarget::WithAjar(
fidl::ServerEnd<fidl_serversuite::AjarTarget>(std::move(server_end)));
case fidl_serversuite::AnyTarget::Tag::kOpen:
return fidl_serversuite::AnyTarget::WithOpen(
fidl::ServerEnd<fidl_serversuite::OpenTarget>(std::move(server_end)));
}
}();
auto result = runner_->Start({test_, std::move(any_target)});
if (result.is_error() && result.error_value().is_domain_error() &&
result.error_value().domain_error() == fidl_serversuite::StartError::kTestDisabled) {
GTEST_SKIP() << "Skipping because Runner.Start() returned TEST_DISABLED";
}
ASSERT_TRUE(result.is_ok()) << "Runner.Start() failed: " << result.error_value();
client_end_ = channel_util::Channel(std::move(client_end));
}
}
void ServerTest::TearDown() {
if (HasFailure() || IsSkipped()) {
return;
}
if (!asserted_teardown_) {
ASSERT_FALSE(client_end_.is_signal_present(ZX_CHANNEL_PEER_CLOSED))
<< "Target channel is unexpectedly closed at the end of the test";
ASSERT_FALSE(client_end_.is_signal_present(ZX_CHANNEL_READABLE))
<< "Target channel is unexpectedly readable at the end of the test";
client_end_.reset();
ASSERT_SERVER_TEARDOWN(fidl_serversuite::TeardownReason::kPeerClosed);
}
auto result = runner_->CheckAlive();
ASSERT_TRUE(result.is_ok()) << "Runner.CheckAlive() failed! The Runner may have crashed. Error: "
<< result.error_value();
}
class RunnerEventHandler : public fidl::SyncEventHandler<fidl_serversuite::Runner> {
public:
void OnTeardown(fidl_serversuite::RunnerOnTeardownRequest& request) override {
event_ = RunnerEvent::kOnTeardown;
payload_ = request.reason();
}
void OnReceivedUnknownMethod(fidl_serversuite::UnknownMethodInfo& info) override {
event_ = RunnerEvent::kOnReceivedUnknownMethod;
payload_ = info;
}
void OnReceivedClosedTargetOneWayNoPayload() override {
event_ = RunnerEvent::kOnReceivedClosedTargetOneWayNoPayload;
}
void OnReceivedOpenTargetStrictOneWay() override {
event_ = RunnerEvent::kOnReceivedOpenTargetStrictOneWay;
}
void OnReceivedOpenTargetFlexibleOneWay() override {
event_ = RunnerEvent::kOnReceivedOpenTargetFlexibleOneWay;
}
RunnerEventPayload payload_;
std::optional<RunnerEvent> event_;
};
void ServerTest::AssertRunnerEventImpl(RunnerEvent expected_event) {
auto deadline = zx::deadline_after(channel_util::kWaitTimeout);
zx_status_t status = runner_.client_end().channel().wait_one(
ZX_CHANNEL_READABLE | ZX_CHANNEL_PEER_CLOSED, deadline, nullptr);
ASSERT_OK(status) << "ASSERT_RUNNER_EVENT: Failed waiting for a Runner event";
RunnerEventHandler handler;
auto result = runner_.HandleOneEvent(handler);
ASSERT_TRUE(result.ok()) << "ASSERT_RUNNER_EVENT: HandleOneEvent failed: " << result;
// Assert on strings instead of integer values to make failure messages more useful.
auto actual_event_name = RunnerEventName(handler.event_.value());
auto expected_event_name = RunnerEventName(expected_event);
ASSERT_STREQ(actual_event_name, expected_event_name);
runner_event_payload_ = handler.payload_;
}
void ServerTest::AssertServerTeardownImpl(fidl_serversuite::TeardownReason expected_reason) {
ASSERT_EQ(__builtin_popcount(static_cast<uint32_t>(expected_reason)), 1)
<< "ASSERT_SERVER_TEARDOWN: expected_reason must only have 1 bit set";
ASSERT_FALSE(asserted_teardown_) << "Called ASSERT_SERVER_TEARDOWN more than once?";
asserted_teardown_ = true;
bool we_closed = !client_end_.get().is_valid();
bool they_should_close = expected_reason != fidl_serversuite::TeardownReason::kPeerClosed;
ASSERT_NE(we_closed, they_should_close)
<< "ASSERT_SERVER_TEARDOWN: Test's teardown expectation does not make sense";
if (they_should_close) {
ASSERT_OK(client_end_.wait_for_signal(ZX_CHANNEL_PEER_CLOSED))
<< "ASSERT_SERVER_TEARDOWN: Failed waiting for the target channel to close";
ASSERT_FALSE(client_end_.is_signal_present(ZX_CHANNEL_READABLE))
<< "ASSERT_SERVER_TEARDOWN: Target channel is unexpectedly readable at the end of the test";
}
ASSERT_RUNNER_EVENT(RunnerEvent::kOnTeardown);
auto actual_reason = std::get<fidl_serversuite::TeardownReason>(runner_event_payload_);
if (!(actual_reason & expected_reason)) {
FAIL() << "ASSERT_SERVER_TEARDOWN:\n Expected teardown reason: "
<< fidl::ostream::Formatted(expected_reason)
<< "\n Actual teardown reason: " << fidl::ostream::Formatted(actual_reason);
}
}
} // namespace server_suite