|
|
|
//
|
|
|
|
// 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/cpp/ext/gcp/observability_config.h"
|
|
|
|
|
|
|
|
#include "gmock/gmock.h"
|
|
|
|
#include "gtest/gtest.h"
|
|
|
|
|
|
|
|
#include <grpc/support/alloc.h>
|
|
|
|
|
|
|
|
#include "src/core/lib/gpr/env.h"
|
|
|
|
#include "src/core/lib/gpr/tmpfile.h"
|
|
|
|
#include "test/core/util/test_config.h"
|
|
|
|
|
|
|
|
namespace grpc {
|
|
|
|
namespace internal {
|
|
|
|
namespace {
|
|
|
|
|
|
|
|
TEST(GcpObservabilityConfigJsonParsingTest, Basic) {
|
|
|
|
const char* json_str = R"json({
|
|
|
|
"cloud_logging": {
|
|
|
|
"enabled": true
|
|
|
|
},
|
|
|
|
"cloud_monitoring": {
|
|
|
|
"enabled": true
|
|
|
|
},
|
|
|
|
"cloud_trace": {
|
|
|
|
"enabled": true,
|
|
|
|
"sampling_rate": 0.05
|
|
|
|
},
|
|
|
|
"project_id": "project"
|
|
|
|
})json";
|
|
|
|
auto json = grpc_core::Json::Parse(json_str);
|
|
|
|
ASSERT_TRUE(json.ok()) << json.status();
|
|
|
|
grpc_core::ErrorList errors;
|
|
|
|
auto config = grpc_core::LoadFromJson<GcpObservabilityConfig>(
|
|
|
|
*json, grpc_core::JsonArgs(), &errors);
|
|
|
|
ASSERT_TRUE(errors.ok()) << errors.status();
|
|
|
|
EXPECT_TRUE(config.cloud_logging.enabled);
|
|
|
|
EXPECT_TRUE(config.cloud_monitoring.enabled);
|
|
|
|
EXPECT_TRUE(config.cloud_trace.enabled);
|
|
|
|
EXPECT_FLOAT_EQ(config.cloud_trace.sampling_rate, 0.05);
|
|
|
|
EXPECT_EQ(config.project_id, "project");
|
|
|
|
}
|
|
|
|
|
|
|
|
TEST(GcpObservabilityConfigJsonParsingTest, Defaults) {
|
|
|
|
const char* json_str = R"json({
|
|
|
|
})json";
|
|
|
|
auto json = grpc_core::Json::Parse(json_str);
|
|
|
|
ASSERT_TRUE(json.ok()) << json.status();
|
|
|
|
grpc_core::ErrorList errors;
|
|
|
|
auto config = grpc_core::LoadFromJson<GcpObservabilityConfig>(
|
|
|
|
*json, grpc_core::JsonArgs(), &errors);
|
|
|
|
ASSERT_TRUE(errors.ok()) << errors.status();
|
|
|
|
EXPECT_FALSE(config.cloud_logging.enabled);
|
|
|
|
EXPECT_FALSE(config.cloud_monitoring.enabled);
|
|
|
|
EXPECT_FALSE(config.cloud_trace.enabled);
|
|
|
|
EXPECT_TRUE(config.project_id.empty());
|
|
|
|
}
|
|
|
|
|
|
|
|
TEST(GcpEnvParsingTest, NoEnvironmentVariableSet) {
|
|
|
|
auto config = GcpObservabilityConfig::ReadFromEnv();
|
|
|
|
EXPECT_EQ(config.status(),
|
|
|
|
absl::FailedPreconditionError(
|
|
|
|
"Environment variables GRPC_OBSERVABILITY_CONFIG_FILE or "
|
|
|
|
"GRPC_OBSERVABILITY_CONFIG "
|
|
|
|
"not defined"));
|
|
|
|
}
|
|
|
|
|
|
|
|
TEST(GcpEnvParsingTest, ConfigFileDoesNotExist) {
|
|
|
|
gpr_setenv("GRPC_OBSERVABILITY_CONFIG_FILE",
|
|
|
|
"/tmp/gcp_observability_config_does_not_exist");
|
|
|
|
|
|
|
|
auto config = GcpObservabilityConfig::ReadFromEnv();
|
|
|
|
|
|
|
|
EXPECT_EQ(config.status(),
|
|
|
|
absl::FailedPreconditionError("Failed to load file"));
|
|
|
|
|
|
|
|
gpr_unsetenv("GRPC_OBSERVABILITY_CONFIG_FILE");
|
|
|
|
}
|
|
|
|
|
|
|
|
class EnvParsingTestType {
|
|
|
|
public:
|
|
|
|
enum class ConfigSource {
|
|
|
|
kFile,
|
|
|
|
kEnvVar,
|
|
|
|
};
|
|
|
|
|
|
|
|
EnvParsingTestType& set_config_source(ConfigSource config_source) {
|
|
|
|
config_source_ = config_source;
|
|
|
|
return *this;
|
|
|
|
}
|
|
|
|
|
|
|
|
ConfigSource config_source() const { return config_source_; }
|
|
|
|
|
|
|
|
std::string ToString() const {
|
|
|
|
std::string ret_val;
|
|
|
|
if (config_source_ == ConfigSource::kFile) {
|
|
|
|
absl::StrAppend(&ret_val, "ConfigFromFile");
|
|
|
|
} else if (config_source_ == ConfigSource::kEnvVar) {
|
|
|
|
absl::StrAppend(&ret_val, "ConfigFromEnvVar");
|
|
|
|
}
|
|
|
|
return ret_val;
|
|
|
|
}
|
|
|
|
|
|
|
|
static std::string Name(
|
|
|
|
const ::testing::TestParamInfo<EnvParsingTestType>& info) {
|
|
|
|
return info.param.ToString();
|
|
|
|
}
|
|
|
|
|
|
|
|
private:
|
|
|
|
ConfigSource config_source_;
|
|
|
|
};
|
|
|
|
|
|
|
|
class EnvParsingTest : public ::testing::TestWithParam<EnvParsingTestType> {
|
|
|
|
protected:
|
|
|
|
~EnvParsingTest() override {
|
|
|
|
if (GetParam().config_source() == EnvParsingTestType::ConfigSource::kFile) {
|
|
|
|
if (tmp_file_name != nullptr) {
|
|
|
|
gpr_unsetenv("GRPC_OBSERVABILITY_CONFIG_FILE");
|
|
|
|
remove(tmp_file_name);
|
|
|
|
gpr_free(tmp_file_name);
|
|
|
|
}
|
|
|
|
} else if (GetParam().config_source() ==
|
|
|
|
EnvParsingTestType::ConfigSource::kEnvVar) {
|
|
|
|
gpr_unsetenv("GRPC_OBSERVABILITY_CONFIG");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void SetConfig(const char* json) {
|
|
|
|
if (GetParam().config_source() == EnvParsingTestType::ConfigSource::kFile) {
|
|
|
|
ASSERT_EQ(tmp_file_name, nullptr);
|
|
|
|
FILE* tmp_config_file =
|
|
|
|
gpr_tmpfile("gcp_observability_config", &tmp_file_name);
|
|
|
|
fputs(json, tmp_config_file);
|
|
|
|
fclose(tmp_config_file);
|
|
|
|
gpr_setenv("GRPC_OBSERVABILITY_CONFIG_FILE", tmp_file_name);
|
|
|
|
} else if (GetParam().config_source() ==
|
|
|
|
EnvParsingTestType::ConfigSource::kEnvVar) {
|
|
|
|
gpr_setenv("GRPC_OBSERVABILITY_CONFIG", json);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
private:
|
|
|
|
char* tmp_file_name = nullptr;
|
|
|
|
};
|
|
|
|
|
|
|
|
TEST_P(EnvParsingTest, Basic) {
|
|
|
|
SetConfig(R"json({
|
|
|
|
"project_id": "project"
|
|
|
|
})json");
|
|
|
|
auto config = GcpObservabilityConfig::ReadFromEnv();
|
|
|
|
|
|
|
|
ASSERT_TRUE(config.ok());
|
|
|
|
EXPECT_EQ(config->project_id, "project");
|
|
|
|
}
|
|
|
|
|
|
|
|
// Test that JSON parsing errors are propagated as expected.
|
|
|
|
TEST_P(EnvParsingTest, BadJson) {
|
|
|
|
SetConfig("{");
|
|
|
|
auto config = GcpObservabilityConfig::ReadFromEnv();
|
|
|
|
|
|
|
|
EXPECT_EQ(config.status().code(), absl::StatusCode::kInvalidArgument);
|
|
|
|
EXPECT_THAT(config.status().message(),
|
|
|
|
::testing::HasSubstr("JSON parsing failed"))
|
|
|
|
<< config.status().message();
|
|
|
|
}
|
|
|
|
|
|
|
|
// Make sure that GCP config errors are propagated as expected.
|
|
|
|
TEST_P(EnvParsingTest, BadGcpConfig) {
|
|
|
|
SetConfig(R"json({
|
|
|
|
"project_id": 123
|
|
|
|
})json");
|
|
|
|
auto config = GcpObservabilityConfig::ReadFromEnv();
|
|
|
|
|
|
|
|
EXPECT_EQ(config.status().code(), absl::StatusCode::kInvalidArgument);
|
|
|
|
EXPECT_THAT(config.status().message(),
|
|
|
|
::testing::HasSubstr("field:project_id error:is not a string"))
|
|
|
|
<< config.status().message();
|
|
|
|
}
|
|
|
|
|
|
|
|
INSTANTIATE_TEST_SUITE_P(
|
|
|
|
GcpObservabilityConfigTest, EnvParsingTest,
|
|
|
|
::testing::Values(EnvParsingTestType().set_config_source(
|
|
|
|
EnvParsingTestType::ConfigSource::kFile),
|
|
|
|
EnvParsingTestType().set_config_source(
|
|
|
|
EnvParsingTestType::ConfigSource::kEnvVar)),
|
|
|
|
&EnvParsingTestType::Name);
|
|
|
|
|
|
|
|
} // namespace
|
|
|
|
} // namespace internal
|
|
|
|
} // namespace grpc
|
|
|
|
|
|
|
|
int main(int argc, char** argv) {
|
|
|
|
grpc::testing::TestEnvironment env(&argc, argv);
|
|
|
|
::testing::InitGoogleTest(&argc, argv);
|
|
|
|
return RUN_ALL_TESTS();
|
|
|
|
}
|