mirror of https://github.com/grpc/grpc.git
security and subchannel: implement UniqueTypeName and use it in these interfaces (#29709)
* implement UniqueTypeName API * convert security code to use UniqueTypeName * change subchannel data producer API to use UniqueTypeName * sanitize * add missing build dep * fix credentials_test * fix certificate_provider_store_test * fix tls_security_connector_test * attempt to fix windows build * avoid unnecessary allocation * work around MSVC 2017 bug * sanity * change factory to not be templated * fix sanity * fix bug in chttp2 connector that used server creds instead of channel creds * add missing build dep * simplify APIpull/29764/head
parent
9a46171833
commit
709dff9ca8
59 changed files with 566 additions and 119 deletions
@ -0,0 +1,104 @@ |
||||
//
|
||||
// Copyright 2022 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.
|
||||
//
|
||||
|
||||
#ifndef GRPC_CORE_LIB_GPRPP_UNIQUE_TYPE_NAME_H |
||||
#define GRPC_CORE_LIB_GPRPP_UNIQUE_TYPE_NAME_H |
||||
|
||||
#include <grpc/support/port_platform.h> |
||||
|
||||
#include <string> |
||||
|
||||
#include "absl/strings/string_view.h" |
||||
|
||||
#include "src/core/lib/gpr/useful.h" |
||||
|
||||
// Provides a type name that is unique by instance rather than by
|
||||
// string content. This is useful in cases where there are different
|
||||
// implementations of a given interface that need to be differentiated from
|
||||
// each other for down-casting purposes, where it is undesirable to provide
|
||||
// a registry to avoid name collisions.
|
||||
//
|
||||
// Expected usage:
|
||||
/*
|
||||
// Interface has a virtual method that returns a UniqueTypeName.
|
||||
class Interface { |
||||
public: |
||||
virtual ~Interface() = default; |
||||
virtual UniqueTypeName type() const = 0; |
||||
}; |
||||
|
||||
// Implementation uses a static factory instance to return the same
|
||||
// UniqueTypeName for every instance.
|
||||
class FooImplementation : public Interface { |
||||
public: |
||||
UniqueTypeName type() const override { |
||||
static UniqueTypeName::Factory kFactory("Foo"); |
||||
return kFactory.Create(); |
||||
} |
||||
}; |
||||
*/ |
||||
|
||||
namespace grpc_core { |
||||
|
||||
class UniqueTypeName { |
||||
public: |
||||
// Factory class. There should be a single static instance of this
|
||||
// for each unique type name.
|
||||
class Factory { |
||||
public: |
||||
explicit Factory(absl::string_view name) : name_(new std::string(name)) {} |
||||
|
||||
Factory(const Factory&) = delete; |
||||
Factory& operator=(const Factory&) = delete; |
||||
|
||||
UniqueTypeName Create() { return UniqueTypeName(*name_); } |
||||
|
||||
private: |
||||
std::string* name_; |
||||
}; |
||||
|
||||
// Copyable.
|
||||
UniqueTypeName(const UniqueTypeName& other) : name_(other.name_) {} |
||||
UniqueTypeName& operator=(const UniqueTypeName& other) { |
||||
name_ = other.name_; |
||||
return *this; |
||||
} |
||||
|
||||
bool operator==(const UniqueTypeName& other) const { |
||||
return name_.data() == other.name_.data(); |
||||
} |
||||
bool operator!=(const UniqueTypeName& other) const { |
||||
return name_.data() != other.name_.data(); |
||||
} |
||||
bool operator<(const UniqueTypeName& other) const { |
||||
return name_.data() < other.name_.data(); |
||||
} |
||||
|
||||
int Compare(const UniqueTypeName& other) const { |
||||
return QsortCompare(name_.data(), other.name_.data()); |
||||
} |
||||
|
||||
absl::string_view name() const { return name_; } |
||||
|
||||
private: |
||||
explicit UniqueTypeName(absl::string_view name) : name_(name) {} |
||||
|
||||
absl::string_view name_; |
||||
}; |
||||
|
||||
} // namespace grpc_core
|
||||
|
||||
#endif // GRPC_CORE_LIB_GPRPP_UNIQUE_TYPE_NAME_H
|
@ -0,0 +1,100 @@ |
||||
// Copyright 2022 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 "src/core/lib/gprpp/unique_type_name.h" |
||||
|
||||
#include <gmock/gmock.h> |
||||
#include <gtest/gtest.h> |
||||
|
||||
#include "absl/strings/str_format.h" |
||||
|
||||
namespace grpc_core { |
||||
|
||||
// Teach gtest to print names usefully.
|
||||
std::ostream& operator<<(std::ostream& os, const UniqueTypeName& name) { |
||||
return os << absl::StrFormat("%s (%p)", name.name(), name.name().data()); |
||||
} |
||||
|
||||
namespace { |
||||
|
||||
class Interface { |
||||
public: |
||||
virtual ~Interface() = default; |
||||
virtual UniqueTypeName type() const = 0; |
||||
}; |
||||
|
||||
class Foo : public Interface { |
||||
public: |
||||
UniqueTypeName type() const override { |
||||
static UniqueTypeName::Factory kFactory("Foo"); |
||||
return kFactory.Create(); |
||||
} |
||||
}; |
||||
|
||||
class Bar : public Interface { |
||||
public: |
||||
UniqueTypeName type() const override { |
||||
static UniqueTypeName::Factory kFactory("Bar"); |
||||
return kFactory.Create(); |
||||
} |
||||
}; |
||||
|
||||
// Uses the same string as Foo.
|
||||
class Foo2 : public Interface { |
||||
public: |
||||
UniqueTypeName type() const override { |
||||
static UniqueTypeName::Factory kFactory("Foo"); |
||||
return kFactory.Create(); |
||||
} |
||||
}; |
||||
|
||||
TEST(UniqueTypeNameTest, MultipleInstancesShareName) { |
||||
Foo foo1; |
||||
Foo foo2; |
||||
EXPECT_EQ(foo1.type(), foo2.type()); |
||||
EXPECT_EQ(0, foo1.type().Compare(foo2.type())); |
||||
} |
||||
|
||||
TEST(UniqueTypeNameTest, DifferentImplsDoNotShareName) { |
||||
Foo foo; |
||||
Bar bar; |
||||
EXPECT_NE(foo.type(), bar.type()); |
||||
EXPECT_NE(0, foo.type().Compare(bar.type())); |
||||
} |
||||
|
||||
TEST(UniqueTypeNameTest, MultipleInstancesOfSameStringAreNotEqual) { |
||||
Foo foo1; |
||||
Foo2 foo2; |
||||
EXPECT_NE(foo1.type(), foo2.type()); |
||||
EXPECT_NE(0, foo1.type().Compare(foo2.type())); |
||||
} |
||||
|
||||
TEST(UniqueTypeNameTest, CanUseAsMapKey) { |
||||
Foo foo; |
||||
Bar bar; |
||||
std::map<UniqueTypeName, int> m; |
||||
m[foo.type()] = 1; |
||||
m[bar.type()] = 2; |
||||
EXPECT_THAT(m, |
||||
::testing::UnorderedElementsAre(::testing::Pair(foo.type(), 1), |
||||
::testing::Pair(bar.type(), 2))); |
||||
} |
||||
|
||||
} // namespace
|
||||
} // namespace grpc_core
|
||||
|
||||
int main(int argc, char** argv) { |
||||
::testing::InitGoogleTest(&argc, argv); |
||||
return RUN_ALL_TESTS(); |
||||
} |
Loading…
Reference in new issue