Add tests for new service config mechanism

reviewable/pr18586/r5
Yash Tibrewal 6 years ago
parent fbe3b3575f
commit 390078b7a8
  1. 40
      CMakeLists.txt
  2. 48
      Makefile
  3. 13
      build.yaml
  4. 4
      src/core/ext/filters/client_channel/service_config.cc
  5. 6
      src/core/ext/filters/client_channel/service_config.h
  6. 14
      test/core/client_channel/BUILD
  7. 221
      test/core/client_channel/service_config_test.cc
  8. 18
      tools/run_tests/generated/sources_and_headers.json
  9. 24
      tools/run_tests/generated/tests.json

@ -698,6 +698,7 @@ add_dependencies(buildtests_cxx server_crash_test_client)
add_dependencies(buildtests_cxx server_early_return_test)
add_dependencies(buildtests_cxx server_interceptors_end2end_test)
add_dependencies(buildtests_cxx server_request_call_test)
add_dependencies(buildtests_cxx service_config_test)
add_dependencies(buildtests_cxx shutdown_test)
add_dependencies(buildtests_cxx slice_hash_table_test)
add_dependencies(buildtests_cxx slice_weak_hash_table_test)
@ -15679,6 +15680,45 @@ target_link_libraries(server_request_call_test
)
endif (gRPC_BUILD_TESTS)
if (gRPC_BUILD_TESTS)
add_executable(service_config_test
test/core/client_channel/service_config_test.cc
third_party/googletest/googletest/src/gtest-all.cc
third_party/googletest/googlemock/src/gmock-all.cc
)
target_include_directories(service_config_test
PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}
PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/include
PRIVATE ${_gRPC_SSL_INCLUDE_DIR}
PRIVATE ${_gRPC_PROTOBUF_INCLUDE_DIR}
PRIVATE ${_gRPC_ZLIB_INCLUDE_DIR}
PRIVATE ${_gRPC_BENCHMARK_INCLUDE_DIR}
PRIVATE ${_gRPC_CARES_INCLUDE_DIR}
PRIVATE ${_gRPC_GFLAGS_INCLUDE_DIR}
PRIVATE ${_gRPC_ADDRESS_SORTING_INCLUDE_DIR}
PRIVATE ${_gRPC_NANOPB_INCLUDE_DIR}
PRIVATE third_party/googletest/googletest/include
PRIVATE third_party/googletest/googletest
PRIVATE third_party/googletest/googlemock/include
PRIVATE third_party/googletest/googlemock
PRIVATE ${_gRPC_PROTO_GENS_DIR}
)
target_link_libraries(service_config_test
${_gRPC_PROTOBUF_LIBRARIES}
${_gRPC_ALLTARGETS_LIBRARIES}
grpc_test_util
grpc++
grpc
gpr
${_gRPC_GFLAGS_LIBRARIES}
)
endif (gRPC_BUILD_TESTS)
if (gRPC_BUILD_TESTS)

@ -1261,6 +1261,7 @@ server_crash_test_client: $(BINDIR)/$(CONFIG)/server_crash_test_client
server_early_return_test: $(BINDIR)/$(CONFIG)/server_early_return_test
server_interceptors_end2end_test: $(BINDIR)/$(CONFIG)/server_interceptors_end2end_test
server_request_call_test: $(BINDIR)/$(CONFIG)/server_request_call_test
service_config_test: $(BINDIR)/$(CONFIG)/service_config_test
shutdown_test: $(BINDIR)/$(CONFIG)/shutdown_test
slice_hash_table_test: $(BINDIR)/$(CONFIG)/slice_hash_table_test
slice_weak_hash_table_test: $(BINDIR)/$(CONFIG)/slice_weak_hash_table_test
@ -1725,6 +1726,7 @@ buildtests_cxx: privatelibs_cxx \
$(BINDIR)/$(CONFIG)/server_early_return_test \
$(BINDIR)/$(CONFIG)/server_interceptors_end2end_test \
$(BINDIR)/$(CONFIG)/server_request_call_test \
$(BINDIR)/$(CONFIG)/service_config_test \
$(BINDIR)/$(CONFIG)/shutdown_test \
$(BINDIR)/$(CONFIG)/slice_hash_table_test \
$(BINDIR)/$(CONFIG)/slice_weak_hash_table_test \
@ -1866,6 +1868,7 @@ buildtests_cxx: privatelibs_cxx \
$(BINDIR)/$(CONFIG)/server_early_return_test \
$(BINDIR)/$(CONFIG)/server_interceptors_end2end_test \
$(BINDIR)/$(CONFIG)/server_request_call_test \
$(BINDIR)/$(CONFIG)/service_config_test \
$(BINDIR)/$(CONFIG)/shutdown_test \
$(BINDIR)/$(CONFIG)/slice_hash_table_test \
$(BINDIR)/$(CONFIG)/slice_weak_hash_table_test \
@ -2377,6 +2380,8 @@ test_cxx: buildtests_cxx
$(Q) $(BINDIR)/$(CONFIG)/server_interceptors_end2end_test || ( echo test server_interceptors_end2end_test failed ; exit 1 )
$(E) "[RUN] Testing server_request_call_test"
$(Q) $(BINDIR)/$(CONFIG)/server_request_call_test || ( echo test server_request_call_test failed ; exit 1 )
$(E) "[RUN] Testing service_config_test"
$(Q) $(BINDIR)/$(CONFIG)/service_config_test || ( echo test service_config_test failed ; exit 1 )
$(E) "[RUN] Testing shutdown_test"
$(Q) $(BINDIR)/$(CONFIG)/shutdown_test || ( echo test shutdown_test failed ; exit 1 )
$(E) "[RUN] Testing slice_hash_table_test"
@ -18601,6 +18606,49 @@ endif
$(OBJDIR)/$(CONFIG)/test/cpp/server/server_request_call_test.o: $(GENDIR)/src/proto/grpc/testing/echo_messages.pb.cc $(GENDIR)/src/proto/grpc/testing/echo_messages.grpc.pb.cc $(GENDIR)/src/proto/grpc/testing/echo.pb.cc $(GENDIR)/src/proto/grpc/testing/echo.grpc.pb.cc
SERVICE_CONFIG_TEST_SRC = \
test/core/client_channel/service_config_test.cc \
SERVICE_CONFIG_TEST_OBJS = $(addprefix $(OBJDIR)/$(CONFIG)/, $(addsuffix .o, $(basename $(SERVICE_CONFIG_TEST_SRC))))
ifeq ($(NO_SECURE),true)
# You can't build secure targets if you don't have OpenSSL.
$(BINDIR)/$(CONFIG)/service_config_test: openssl_dep_error
else
ifeq ($(NO_PROTOBUF),true)
# You can't build the protoc plugins or protobuf-enabled targets if you don't have protobuf 3.5.0+.
$(BINDIR)/$(CONFIG)/service_config_test: protobuf_dep_error
else
$(BINDIR)/$(CONFIG)/service_config_test: $(PROTOBUF_DEP) $(SERVICE_CONFIG_TEST_OBJS) $(LIBDIR)/$(CONFIG)/libgrpc_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc++.a $(LIBDIR)/$(CONFIG)/libgrpc.a $(LIBDIR)/$(CONFIG)/libgpr.a
$(E) "[LD] Linking $@"
$(Q) mkdir -p `dirname $@`
$(Q) $(LDXX) $(LDFLAGS) $(SERVICE_CONFIG_TEST_OBJS) $(LIBDIR)/$(CONFIG)/libgrpc_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc++.a $(LIBDIR)/$(CONFIG)/libgrpc.a $(LIBDIR)/$(CONFIG)/libgpr.a $(LDLIBSXX) $(LDLIBS_PROTOBUF) $(LDLIBS) $(LDLIBS_SECURE) $(GTEST_LIB) -o $(BINDIR)/$(CONFIG)/service_config_test
endif
endif
$(OBJDIR)/$(CONFIG)/test/core/client_channel/service_config_test.o: $(LIBDIR)/$(CONFIG)/libgrpc_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc++.a $(LIBDIR)/$(CONFIG)/libgrpc.a $(LIBDIR)/$(CONFIG)/libgpr.a
deps_service_config_test: $(SERVICE_CONFIG_TEST_OBJS:.o=.dep)
ifneq ($(NO_SECURE),true)
ifneq ($(NO_DEPS),true)
-include $(SERVICE_CONFIG_TEST_OBJS:.o=.dep)
endif
endif
SHUTDOWN_TEST_SRC = \
test/cpp/end2end/shutdown_test.cc \

@ -5441,6 +5441,19 @@ targets:
- grpc++_unsecure
- grpc_unsecure
- gpr
- name: service_config_test
gtest: true
build: test
language: c++
src:
- test/core/client_channel/service_config_test.cc
deps:
- grpc_test_util
- grpc++
- grpc
- gpr
uses:
- grpc++_test
- name: shutdown_test
gtest: true
build: test

@ -87,7 +87,7 @@ grpc_error* ServiceConfig::ParseGlobalParams(const grpc_json* json_tree) {
for (size_t i = 0; i < registered_parsers_->size(); i++) {
grpc_error* parser_error = GRPC_ERROR_NONE;
auto parsed_obj =
(*registered_parsers_)[i].ParseGlobalParams(json_tree, &parser_error);
(*registered_parsers_)[i]->ParseGlobalParams(json_tree, &parser_error);
error = grpc_error_add_child(error, parser_error);
parsed_global_service_config_objects_.push_back(std::move(parsed_obj));
}
@ -103,7 +103,7 @@ grpc_error* ServiceConfig::ParseJsonMethodConfigToServiceConfigObjectsTable(
for (size_t i = 0; i < registered_parsers_->size(); i++) {
grpc_error* parser_error = GRPC_ERROR_NONE;
auto parsed_obj =
(*registered_parsers_)[i].ParsePerMethodParams(json, &error);
(*registered_parsers_)[i]->ParsePerMethodParams(json, &error);
error = grpc_error_add_child(error, parser_error);
objs_vector->push_back(std::move(parsed_obj));
}

@ -72,14 +72,12 @@ class ServiceConfigParser {
virtual UniquePtr<ServiceConfigParsedObject> ParseGlobalParams(
const grpc_json* json, grpc_error** error) {
GPR_DEBUG_ASSERT(error != nullptr);
*error = GRPC_ERROR_NONE;
return nullptr;
}
virtual UniquePtr<ServiceConfigParsedObject> ParsePerMethodParams(
const grpc_json* json, grpc_error** error) {
GPR_DEBUG_ASSERT(error != nullptr);
*error = GRPC_ERROR_NONE;
return nullptr;
}
@ -152,7 +150,7 @@ class ServiceConfig : public RefCounted<ServiceConfig> {
/// registered parser. Each parser is responsible for reading the service
/// config json and returning a parsed object. This parsed object can later be
/// retrieved using the same index that was returned at registration time.
static int RegisterParser(ServiceConfigParser parser) {
static int RegisterParser(UniquePtr<ServiceConfigParser> parser) {
registered_parsers_->push_back(std::move(parser));
return registered_parsers_->size() - 1;
}
@ -168,7 +166,7 @@ class ServiceConfig : public RefCounted<ServiceConfig> {
}
private:
typedef InlinedVector<ServiceConfigParser, kNumPreallocatedParsers>
typedef InlinedVector<UniquePtr<ServiceConfigParser>, kNumPreallocatedParsers>
ServiceConfigParserList;
// So New() can call our private ctor.
template <typename T, typename... Args>

@ -78,3 +78,17 @@ grpc_cc_test(
"//test/core/util:grpc_test_util",
],
)
grpc_cc_test(
name = "service_config_test",
srcs = ["service_config_test.cc"],
external_deps = [
"gtest",
],
language = "C++",
deps = [
"//:gpr",
"//:grpc",
"//test/core/util:grpc_test_util",
],
)

@ -0,0 +1,221 @@
/*
*
* Copyright 2019 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 <grpc/grpc.h>
#include "src/core/ext/filters/client_channel/service_config.h"
#include "src/core/lib/gpr/string.h"
#include "test/core/util/port.h"
#include "test/core/util/test_config.h"
namespace grpc_core {
namespace testing {
class TestParsedObject1 : public ServiceConfigParsedObject {
public:
TestParsedObject1(int value) : value_(value) {}
int value() const { return value_; }
private:
int value_;
};
class TestParser1 : public ServiceConfigParser {
public:
UniquePtr<ServiceConfigParsedObject> ParseGlobalParams(
const grpc_json* json, grpc_error** error) override {
GPR_DEBUG_ASSERT(error != nullptr);
for (grpc_json* field = json->child; field != nullptr;
field = field->next) {
if (strcmp(field->key, "global_param") == 0) {
if (field->type != GRPC_JSON_NUMBER) {
*error = GRPC_ERROR_CREATE_FROM_STATIC_STRING(
"global_param value type should be a number");
return nullptr;
}
int value = gpr_parse_nonnegative_int(field->value);
if (value == -1) {
*error = GRPC_ERROR_CREATE_FROM_STATIC_STRING(
"global_param value type should be non-negative");
return nullptr;
}
return UniquePtr<ServiceConfigParsedObject>(
New<TestParsedObject1>(value));
}
}
return nullptr;
}
};
class TestParser2 : public ServiceConfigParser {
public:
UniquePtr<ServiceConfigParsedObject> ParsePerMethodParams(
const grpc_json* json, grpc_error** error) override {
GPR_DEBUG_ASSERT(error != nullptr);
for (grpc_json* field = json->child; field != nullptr;
field = field->next) {
if (field->key == nullptr || strcmp(field->key, "name") == 0) {
continue;
}
if (strcmp(field->key, "method_param") == 0) {
if (field->type != GRPC_JSON_NUMBER) {
*error = GRPC_ERROR_CREATE_FROM_STATIC_STRING(
"method_param value type should be a number");
return nullptr;
}
int value = gpr_parse_nonnegative_int(field->value);
if (value == -1) {
*error = GRPC_ERROR_CREATE_FROM_STATIC_STRING(
"method_param value type should be non-negative");
return nullptr;
}
return UniquePtr<ServiceConfigParsedObject>(
New<TestParsedObject1>(value));
}
}
return nullptr;
}
};
class ServiceConfigTest : public ::testing::Test {
protected:
void SetUp() override {
ServiceConfig::Shutdown();
ServiceConfig::Init();
EXPECT_TRUE(ServiceConfig::RegisterParser(
UniquePtr<ServiceConfigParser>(New<TestParser1>())) == 0);
EXPECT_TRUE(ServiceConfig::RegisterParser(
UniquePtr<ServiceConfigParser>(New<TestParser2>())) == 1);
}
};
TEST_F(ServiceConfigTest, ErrorCheck1) {
const char* test_json = "";
grpc_error* error = GRPC_ERROR_NONE;
auto svc_cfg = ServiceConfig::Create(test_json, &error);
EXPECT_TRUE(error != GRPC_ERROR_NONE);
}
TEST_F(ServiceConfigTest, BasicTest1) {
const char* test_json = "{}";
grpc_error* error = GRPC_ERROR_NONE;
auto svc_cfg = ServiceConfig::Create(test_json, &error);
EXPECT_TRUE(error == GRPC_ERROR_NONE);
}
TEST_F(ServiceConfigTest, ErrorNoNames) {
const char* test_json = "{\"methodConfig\": [{\"blah\":1}]}";
grpc_error* error = GRPC_ERROR_NONE;
auto svc_cfg = ServiceConfig::Create(test_json, &error);
gpr_log(GPR_ERROR, "%s", grpc_error_string(error));
EXPECT_TRUE(error != GRPC_ERROR_NONE);
}
TEST_F(ServiceConfigTest, ErrorNoNamesWithMultipleMethodConfigs) {
const char* test_json =
"{\"methodConfig\": [{}, {\"name\":[{\"service\":\"TestServ\"}]}]}";
grpc_error* error = GRPC_ERROR_NONE;
auto svc_cfg = ServiceConfig::Create(test_json, &error);
gpr_log(GPR_ERROR, "%s", grpc_error_string(error));
EXPECT_TRUE(error != GRPC_ERROR_NONE);
}
TEST_F(ServiceConfigTest, ValidMethodConfig) {
const char* test_json =
"{\"methodConfig\": [{\"name\":[{\"service\":\"TestServ\"}]}]}";
grpc_error* error = GRPC_ERROR_NONE;
auto svc_cfg = ServiceConfig::Create(test_json, &error);
EXPECT_TRUE(error == GRPC_ERROR_NONE);
}
TEST_F(ServiceConfigTest, Parser1BasicTest1) {
const char* test_json = "{\"global_param\":5}";
grpc_error* error = GRPC_ERROR_NONE;
auto svc_cfg = ServiceConfig::Create(test_json, &error);
EXPECT_TRUE(error == GRPC_ERROR_NONE);
EXPECT_TRUE((static_cast<TestParsedObject1*>(
svc_cfg->GetParsedGlobalServiceConfigObject(0)))
->value() == 5);
}
TEST_F(ServiceConfigTest, Parser1BasicTest2) {
const char* test_json = "{\"global_param\":1000}";
grpc_error* error = GRPC_ERROR_NONE;
auto svc_cfg = ServiceConfig::Create(test_json, &error);
EXPECT_TRUE(error == GRPC_ERROR_NONE);
EXPECT_TRUE((static_cast<TestParsedObject1*>(
svc_cfg->GetParsedGlobalServiceConfigObject(0)))
->value() == 1000);
}
TEST_F(ServiceConfigTest, Parser1ErrorInvalidType) {
const char* test_json = "{\"global_param\":\"5\"}";
grpc_error* error = GRPC_ERROR_NONE;
auto svc_cfg = ServiceConfig::Create(test_json, &error);
gpr_log(GPR_ERROR, "%s", grpc_error_string(error));
EXPECT_TRUE(error != GRPC_ERROR_NONE);
}
TEST_F(ServiceConfigTest, Parser1ErrorInvalidValue) {
const char* test_json = "{\"global_param\":-5}";
grpc_error* error = GRPC_ERROR_NONE;
auto svc_cfg = ServiceConfig::Create(test_json, &error);
gpr_log(GPR_ERROR, "%s", grpc_error_string(error));
EXPECT_TRUE(error != GRPC_ERROR_NONE);
}
TEST_F(ServiceConfigTest, Parser2BasicTest) {
const char* test_json =
"{\"methodConfig\": [{\"name\":[{\"service\":\"TestServ\"}], "
"\"method_param\":5}]}";
grpc_error* error = GRPC_ERROR_NONE;
auto svc_cfg = ServiceConfig::Create(test_json, &error);
EXPECT_TRUE(error == GRPC_ERROR_NONE);
}
TEST_F(ServiceConfigTest, Parser2ErrorInvalidType) {
const char* test_json =
"{\"methodConfig\": [{\"name\":[{\"service\":\"TestServ\"}], "
"\"method_param\":\"5\"}]}";
grpc_error* error = GRPC_ERROR_NONE;
auto svc_cfg = ServiceConfig::Create(test_json, &error);
EXPECT_TRUE(error != GRPC_ERROR_NONE);
}
TEST_F(ServiceConfigTest, Parser2ErrorInvalidValue) {
const char* test_json =
"{\"methodConfig\": [{\"name\":[{\"service\":\"TestServ\"}], "
"\"method_param\":-5}]}";
grpc_error* error = GRPC_ERROR_NONE;
auto svc_cfg = ServiceConfig::Create(test_json, &error);
EXPECT_TRUE(error != GRPC_ERROR_NONE);
}
} // namespace testing
} // namespace grpc_core
int main(int argc, char** argv) {
grpc::testing::TestEnvironment env(argc, argv);
grpc_init();
::testing::InitGoogleTest(&argc, argv);
int ret = RUN_ALL_TESTS();
grpc_shutdown();
return ret;
}

@ -4723,6 +4723,24 @@
"third_party": false,
"type": "target"
},
{
"deps": [
"gpr",
"grpc",
"grpc++",
"grpc++_test",
"grpc_test_util"
],
"headers": [],
"is_filegroup": false,
"language": "c++",
"name": "service_config_test",
"src": [
"test/core/client_channel/service_config_test.cc"
],
"third_party": false,
"type": "target"
},
{
"deps": [
"gpr",

@ -5349,6 +5349,30 @@
],
"uses_polling": true
},
{
"args": [],
"benchmark": false,
"ci_platforms": [
"linux",
"mac",
"posix",
"windows"
],
"cpu_cost": 1.0,
"exclude_configs": [],
"exclude_iomgrs": [],
"flaky": false,
"gtest": true,
"language": "c++",
"name": "service_config_test",
"platforms": [
"linux",
"mac",
"posix",
"windows"
],
"uses_polling": true
},
{
"args": [],
"benchmark": false,

Loading…
Cancel
Save