blob: e8bc1f884cf21da1faecefbf345388fe5266aad8 [file] [log] [blame]
// Copyright 2021 gRPC authors.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#include <gtest/gtest.h>
#include "src/core/lib/config/core_configuration.h"
#include "src/core/lib/iomgr/port.h"
#include "test/core/util/test_config.h"
#ifdef GRPC_HAVE_UNIX_SOCKET
#include <sys/un.h>
#include <cstring>
#include <grpc/grpc.h>
#include <grpc/support/alloc.h>
#include <grpc/support/log.h>
#include <grpc/support/string_util.h>
#include "src/core/lib/channel/channel_args.h"
#include "src/core/lib/iomgr/exec_ctx.h"
#include "src/core/lib/resolver/resolver_registry.h"
// Registers the factory with `grpc_core::ResolverRegistry`. Defined in
// binder_resolver.cc
namespace grpc_core {
void RegisterBinderResolver(CoreConfiguration::Builder* builder);
}
namespace {
class BinderResolverTest : public ::testing::Test {
public:
BinderResolverTest() {
factory_ = grpc_core::CoreConfiguration::Get()
.resolver_registry()
.LookupResolverFactory("binder");
}
~BinderResolverTest() override {}
static void SetUpTestSuite() {
grpc_core::CoreConfiguration::Reset();
grpc_core::CoreConfiguration::BuildSpecialConfiguration(
[](grpc_core::CoreConfiguration::Builder* builder) {
BuildCoreConfiguration(builder);
if (!builder->resolver_registry()->HasResolverFactory("binder")) {
// Binder resolver will only be registered on platforms that support
// binder transport. If it is not registered on current platform, we
// manually register it here for testing purpose.
RegisterBinderResolver(builder);
ASSERT_TRUE(
builder->resolver_registry()->HasResolverFactory("binder"));
}
});
grpc_init();
if (grpc_core::CoreConfiguration::Get()
.resolver_registry()
.LookupResolverFactory("binder") == nullptr) {
}
}
static void TearDownTestSuite() { grpc_shutdown(); }
void SetUp() override { ASSERT_TRUE(factory_); }
class ResultHandler : public grpc_core::Resolver::ResultHandler {
public:
ResultHandler() = default;
explicit ResultHandler(const std::string& expected_binder_id)
: expect_result_(true), expected_binder_id_(expected_binder_id) {}
void ReportResult(grpc_core::Resolver::Result result) override {
EXPECT_TRUE(expect_result_);
ASSERT_TRUE(result.addresses.ok());
ASSERT_EQ(result.addresses->size(), 1);
grpc_core::ServerAddress addr = (*result.addresses)[0];
const struct sockaddr_un* un =
reinterpret_cast<const struct sockaddr_un*>(addr.address().addr);
EXPECT_EQ(addr.address().len,
sizeof(un->sun_family) + expected_binder_id_.length() + 1);
EXPECT_EQ(un->sun_family, AF_MAX);
EXPECT_EQ(un->sun_path, expected_binder_id_);
}
private:
// Whether we expect ReportResult function to be invoked
bool expect_result_ = false;
std::string expected_binder_id_;
};
void TestSucceeds(const char* string, const std::string& expected_path) {
gpr_log(GPR_DEBUG, "test: '%s' should be valid for '%s'", string,
std::string(factory_->scheme()).c_str());
grpc_core::ExecCtx exec_ctx;
absl::StatusOr<grpc_core::URI> uri = grpc_core::URI::Parse(string);
ASSERT_TRUE(uri.ok()) << uri.status().ToString();
grpc_core::ResolverArgs args;
args.uri = std::move(*uri);
args.result_handler =
absl::make_unique<BinderResolverTest::ResultHandler>(expected_path);
grpc_core::OrphanablePtr<grpc_core::Resolver> resolver =
factory_->CreateResolver(std::move(args));
ASSERT_TRUE(resolver != nullptr);
resolver->StartLocked();
}
void TestFails(const char* string) {
gpr_log(GPR_DEBUG, "test: '%s' should be invalid for '%s'", string,
std::string(factory_->scheme()).c_str());
grpc_core::ExecCtx exec_ctx;
absl::StatusOr<grpc_core::URI> uri = grpc_core::URI::Parse(string);
ASSERT_TRUE(uri.ok()) << uri.status().ToString();
grpc_core::ResolverArgs args;
args.uri = std::move(*uri);
args.result_handler =
absl::make_unique<BinderResolverTest::ResultHandler>();
grpc_core::OrphanablePtr<grpc_core::Resolver> resolver =
factory_->CreateResolver(std::move(args));
EXPECT_TRUE(resolver == nullptr);
}
private:
grpc_core::ResolverFactory* factory_;
};
} // namespace
// Authority is not allowed
TEST_F(BinderResolverTest, AuthorityPresents) {
TestFails("binder://example");
TestFails("binder://google.com");
TestFails("binder://google.com/test");
}
// Path cannot be empty
TEST_F(BinderResolverTest, EmptyPath) {
TestFails("binder:");
TestFails("binder:/");
TestFails("binder://");
}
TEST_F(BinderResolverTest, PathLength) {
// Note that we have a static assert in binder_resolver.cc that checks
// sizeof(sockaddr_un::sun_path) is greater than 100
// 100 character path should be fine
TestSucceeds(("binder:l" + std::string(98, 'o') + "g").c_str(),
"l" + std::string(98, 'o') + "g");
// 200 character path most likely will fail
TestFails(("binder:l" + std::string(198, 'o') + "g").c_str());
}
TEST_F(BinderResolverTest, SlashPrefixes) {
TestSucceeds("binder:///test", "test");
TestSucceeds("binder:////test", "/test");
}
TEST_F(BinderResolverTest, ValidCases) {
TestSucceeds("binder:[[", "[[");
TestSucceeds("binder:google!com", "google!com");
TestSucceeds("binder:test/", "test/");
TestSucceeds("binder:test:", "test:");
TestSucceeds("binder:e", "e");
TestSucceeds("binder:example", "example");
TestSucceeds("binder:google.com", "google.com");
TestSucceeds("binder:~", "~");
TestSucceeds("binder:12345", "12345");
TestSucceeds(
"binder:abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789-._"
"~",
"abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789-._~");
}
#endif
int main(int argc, char** argv) {
::testing::InitGoogleTest(&argc, argv);
grpc::testing::TestEnvironment env(argc, argv);
return RUN_ALL_TESTS();
}