blob: ae301e0eb6cd4f578ae9b3ef607622b10e693b85 [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 <fidl/fidl.test.compatibility/cpp/fidl.h>
#include <lib/component/incoming/cpp/protocol.h>
#include <utility>
#include <src/tests/fidl/compatibility/helpers.h>
using namespace component_testing;
namespace fidl_test_compatibility_helpers {
AllowImplPair Exclude(std::initializer_list<const char*> substrings) {
return [substrings](const std::string& proxy_url, const std::string& server_url) {
return std::all_of(std::begin(substrings), std::end(substrings), [&](const char* substring) {
if (proxy_url.find(substring) != std::string::npos) {
return false;
}
if (server_url.find(substring) != std::string::npos) {
return false;
}
return true;
});
};
}
std::string ExtractShortName(const std::string& pkg_url) {
std::string short_name;
re2::RE2::PartialMatch(pkg_url, "(fidl-compatibility-test-)(.*)(#meta/impl\\.cm)", nullptr,
&short_name);
return short_name;
}
void ForAllImpls(const Impls& impls, const TestBody& body) {
ForSomeImpls(
impls, [](const std::string& p, const std::string& s) { return true; }, body);
}
void ForSomeImpls(const Impls& impls, const AllowImplPair& allow, const TestBody& body) {
for (auto const& proxy_url : impls) {
for (auto const& server_url : impls) {
if (!allow(proxy_url, server_url)) {
continue;
}
bool test_completed = false;
const std::string& proxy_short = ExtractShortName(proxy_url);
const std::string& server_short = ExtractShortName(server_url);
const std::string proxy_component = proxy_short + "_proxy";
const std::string server_component = server_short + "_server";
std::cerr << "Executing test for: " << proxy_short << " <-> " << server_short << std::endl;
auto builder = RealmBuilder::Create();
builder.AddChild(proxy_component, proxy_url,
ChildOptions{.startup_mode = StartupMode::EAGER});
builder.AddChild(server_component, server_url,
ChildOptions{.startup_mode = StartupMode::EAGER});
builder.AddRoute(Route{.capabilities = {Protocol{"fidl.test.compatibility.Echo"}},
.source = ChildRef{server_component},
.targets = {ChildRef{proxy_component}}});
builder.AddRoute(Route{.capabilities = {Protocol{"fidl.test.compatibility.Echo"}},
.source = ChildRef{proxy_component},
.targets = {ParentRef()}});
builder.AddRoute(Route{.capabilities = {Protocol{"fuchsia.logger.LogSink"}},
.source = ParentRef(),
.targets = {ChildRef{server_component}, ChildRef{proxy_component}}});
async::Loop loop(&kAsyncLoopConfigAttachToCurrentThread);
auto realm = builder.Build(loop.dispatcher());
auto echo = realm.component().Connect<fidl::test::compatibility::Echo>();
echo.set_error_handler([&proxy_url, &loop, &test_completed](zx_status_t status) {
if (!test_completed) {
loop.Quit();
FAIL() << "Connection to " << proxy_url
<< " failed unexpectedly: " << zx_status_get_string(status);
}
});
body(loop, echo, server_url, proxy_url);
test_completed = true;
}
}
}
bool GetImplsUnderTest(Impls* out_impls) {
// TODO(https://fxbug.dev/42077626): this should come from structured config.
zx::result client_end = component::Connect<fidl_test_compatibility::Config>();
FX_CHECK(client_end.is_ok());
fidl::SyncClient config(std::move(*client_end));
auto result = config->GetImpls();
FX_CHECK(result.is_ok()) << "Failed to get impls: " << result.error_value().status_string();
auto impls = result->impls();
for (size_t i = 0; i < impls.size(); i++) {
out_impls->push_back(impls[i]);
}
if (!out_impls->empty()) {
return true;
}
FX_CHECK(!out_impls->empty());
return false;
}
zx::handle Handle() {
zx_handle_t raw_event;
const zx_status_t status = zx_event_create(0u, &raw_event);
ZX_ASSERT_MSG(status == ZX_OK, "status = %s", zx_status_get_string(status));
return zx::handle(raw_event);
}
::testing::AssertionResult HandlesEq(const zx::object_base& a, const zx::object_base& b) {
if (a.is_valid() != b.is_valid()) {
return ::testing::AssertionFailure()
<< "Handles are not equally valid :" << a.is_valid() << " vs " << b.is_valid();
}
if (!a.is_valid()) {
return ::testing::AssertionSuccess() << "Both handles invalid";
}
zx_info_handle_basic_t a_info, b_info;
if (zx_status_t status = zx_object_get_info(a.get(), ZX_INFO_HANDLE_BASIC, &a_info,
sizeof(a_info), nullptr, nullptr);
ZX_OK != status) {
return ::testing::AssertionFailure()
<< "zx_object_get_info(a) returned " << zx_status_get_string(status);
}
if (zx_status_t status = zx_object_get_info(b.get(), ZX_INFO_HANDLE_BASIC, &b_info,
sizeof(b_info), nullptr, nullptr);
ZX_OK != status) {
return ::testing::AssertionFailure()
<< "zx_object_get_info(b) returned " << zx_status_get_string(status);
}
if (a_info.koid != b_info.koid) {
return ::testing::AssertionFailure() << std::endl
<< "a_info.koid is: " << a_info.koid << std::endl
<< "b_info.koid is: " << b_info.koid;
}
return ::testing::AssertionSuccess();
}
void PrintSummary(const Summary& summary) {
std::cout << std::endl;
std::cout << "========================= Interop Summary ======================" << std::endl;
for (std::pair<std::string, bool> element : summary) {
if (element.second) {
std::cout << "[PASS]";
} else {
std::cout << "[FAIL]";
}
std::cout << " " << element.first << std::endl;
}
std::cout << std::endl;
std::cout << std::endl;
}
std::string RandomUTF8(size_t count, std::default_random_engine& rand_engine) {
std::uniform_int_distribution<uint32_t> uint32_distribution;
std::string random_string;
random_string.reserve(count);
do {
// Generate a random 32 bit unsigned int to use a the code point.
uint32_t code_point = uint32_distribution(rand_engine);
// Mask the random number so that it can be encoded into the number of bytes
// remaining.
size_t remaining = count - random_string.size();
if (remaining == 1) {
code_point &= 0x7F;
} else if (remaining == 2) {
code_point &= 0x7FF;
} else if (remaining == 3) {
code_point &= 0xFFFF;
} else {
// Mask to fall within the general range of code points.
code_point &= 0x1FFFFF;
}
// Check that it's really a valid code point, otherwise try again.
if (!fxl::IsValidCodepoint(code_point)) {
continue;
}
// Add the character to the random string.
fxl::WriteUnicodeCharacter(code_point, &random_string);
FX_CHECK(random_string.size() <= count);
} while (random_string.size() < count);
return random_string;
}
} // namespace fidl_test_compatibility_helpers