1 //
2 //
3 // Copyright 2020 gRPC authors.
4 //
5 // Licensed under the Apache License, Version 2.0 (the "License");
6 // you may not use this file except in compliance with the License.
7 // You may obtain a copy of the License at
8 //
9 // http://www.apache.org/licenses/LICENSE-2.0
10 //
11 // Unless required by applicable law or agreed to in writing, software
12 // distributed under the License is distributed on an "AS IS" BASIS,
13 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 // See the License for the specific language governing permissions and
15 // limitations under the License.
16 //
17 //
18
19 #include "src/core/ext/xds/file_watcher_certificate_provider_factory.h"
20
21 #include <utility>
22
23 #include "absl/status/status.h"
24 #include "absl/status/statusor.h"
25 #include "absl/strings/str_format.h"
26 #include "gtest/gtest.h"
27
28 #include <grpc/grpc.h>
29
30 #include "src/core/lib/json/json_reader.h"
31 #include "test/core/util/test_config.h"
32
33 namespace grpc_core {
34 namespace testing {
35 namespace {
36
37 const char* kIdentityCertFile = "/path/to/identity_cert_file";
38 const char* kPrivateKeyFile = "/path/to/private_key_file";
39 const char* kRootCertFile = "/path/to/root_cert_file";
40 const int kRefreshInterval = 400;
41
42 absl::StatusOr<RefCountedPtr<FileWatcherCertificateProviderFactory::Config>>
ParseConfig(absl::string_view json_string)43 ParseConfig(absl::string_view json_string) {
44 auto json = JsonParse(json_string);
45 if (!json.ok()) return json.status();
46 ValidationErrors errors;
47 auto config =
48 FileWatcherCertificateProviderFactory().CreateCertificateProviderConfig(
49 *json, JsonArgs(), &errors);
50 if (!errors.ok()) {
51 return errors.status(absl::StatusCode::kInvalidArgument,
52 "validation errors");
53 }
54 return config.TakeAsSubclass<FileWatcherCertificateProviderFactory::Config>();
55 }
56
TEST(FileWatcherConfigTest,Basic)57 TEST(FileWatcherConfigTest, Basic) {
58 std::string json_str = absl::StrFormat(
59 "{"
60 " \"certificate_file\": \"%s\","
61 " \"private_key_file\": \"%s\","
62 " \"ca_certificate_file\": \"%s\","
63 " \"refresh_interval\": \"%ds\""
64 "}",
65 kIdentityCertFile, kPrivateKeyFile, kRootCertFile, kRefreshInterval);
66 auto config = ParseConfig(json_str);
67 ASSERT_TRUE(config.ok()) << config.status();
68 EXPECT_EQ((*config)->identity_cert_file(), kIdentityCertFile);
69 EXPECT_EQ((*config)->private_key_file(), kPrivateKeyFile);
70 EXPECT_EQ((*config)->root_cert_file(), kRootCertFile);
71 EXPECT_EQ((*config)->refresh_interval(), Duration::Seconds(kRefreshInterval));
72 }
73
TEST(FileWatcherConfigTest,DefaultRefreshInterval)74 TEST(FileWatcherConfigTest, DefaultRefreshInterval) {
75 std::string json_str = absl::StrFormat(
76 "{"
77 " \"certificate_file\": \"%s\","
78 " \"private_key_file\": \"%s\","
79 " \"ca_certificate_file\": \"%s\""
80 "}",
81 kIdentityCertFile, kPrivateKeyFile, kRootCertFile);
82 auto config = ParseConfig(json_str);
83 ASSERT_TRUE(config.ok()) << config.status();
84 EXPECT_EQ((*config)->identity_cert_file(), kIdentityCertFile);
85 EXPECT_EQ((*config)->private_key_file(), kPrivateKeyFile);
86 EXPECT_EQ((*config)->root_cert_file(), kRootCertFile);
87 EXPECT_EQ((*config)->refresh_interval(), Duration::Seconds(600));
88 }
89
TEST(FileWatcherConfigTest,OnlyRootCertificatesFileProvided)90 TEST(FileWatcherConfigTest, OnlyRootCertificatesFileProvided) {
91 std::string json_str = absl::StrFormat(
92 "{"
93 " \"ca_certificate_file\": \"%s\""
94 "}",
95 kRootCertFile);
96 auto config = ParseConfig(json_str);
97 ASSERT_TRUE(config.ok()) << config.status();
98 EXPECT_EQ((*config)->identity_cert_file(), "");
99 EXPECT_EQ((*config)->private_key_file(), "");
100 EXPECT_EQ((*config)->root_cert_file(), kRootCertFile);
101 EXPECT_EQ((*config)->refresh_interval(), Duration::Seconds(600));
102 }
103
TEST(FileWatcherConfigTest,OnlyIdenityCertificatesAndPrivateKeyProvided)104 TEST(FileWatcherConfigTest, OnlyIdenityCertificatesAndPrivateKeyProvided) {
105 std::string json_str = absl::StrFormat(
106 "{"
107 " \"certificate_file\": \"%s\","
108 " \"private_key_file\": \"%s\""
109 "}",
110 kIdentityCertFile, kPrivateKeyFile);
111 auto config = ParseConfig(json_str);
112 ASSERT_TRUE(config.ok()) << config.status();
113 EXPECT_EQ((*config)->identity_cert_file(), kIdentityCertFile);
114 EXPECT_EQ((*config)->private_key_file(), kPrivateKeyFile);
115 EXPECT_EQ((*config)->root_cert_file(), "");
116 EXPECT_EQ((*config)->refresh_interval(), Duration::Seconds(600));
117 }
118
TEST(FileWatcherConfigTest,WrongTypes)119 TEST(FileWatcherConfigTest, WrongTypes) {
120 const char* json_str =
121 "{"
122 " \"certificate_file\": 123,"
123 " \"private_key_file\": 123,"
124 " \"ca_certificate_file\": 123,"
125 " \"refresh_interval\": 123"
126 "}";
127 auto config = ParseConfig(json_str);
128 EXPECT_EQ(config.status().message(),
129 "validation errors: ["
130 "field:ca_certificate_file error:is not a string; "
131 "field:certificate_file error:is not a string; "
132 "field:private_key_file error:is not a string; "
133 "field:refresh_interval error:is not a string]")
134 << config.status();
135 }
136
TEST(FileWatcherConfigTest,IdentityCertProvidedButPrivateKeyMissing)137 TEST(FileWatcherConfigTest, IdentityCertProvidedButPrivateKeyMissing) {
138 std::string json_str = absl::StrFormat(
139 "{"
140 " \"certificate_file\": \"%s\""
141 "}",
142 kIdentityCertFile);
143 auto config = ParseConfig(json_str);
144 EXPECT_EQ(config.status().message(),
145 "validation errors: ["
146 "field: error:fields \"certificate_file\" and "
147 "\"private_key_file\" must be both set or both unset]")
148 << config.status();
149 }
150
TEST(FileWatcherConfigTest,PrivateKeyProvidedButIdentityCertMissing)151 TEST(FileWatcherConfigTest, PrivateKeyProvidedButIdentityCertMissing) {
152 std::string json_str = absl::StrFormat(
153 "{"
154 " \"ca_certificate_file\": \"%s\","
155 " \"private_key_file\": \"%s\""
156 "}",
157 kRootCertFile, kPrivateKeyFile);
158 auto config = ParseConfig(json_str);
159 EXPECT_EQ(config.status().message(),
160 "validation errors: ["
161 "field: error:fields \"certificate_file\" and "
162 "\"private_key_file\" must be both set or both unset]")
163 << config.status();
164 }
165
TEST(FileWatcherConfigTest,EmptyJsonObject)166 TEST(FileWatcherConfigTest, EmptyJsonObject) {
167 std::string json_str = "{}";
168 auto config = ParseConfig(json_str);
169 EXPECT_EQ(config.status().message(),
170 "validation errors: ["
171 "field: error:at least one of \"certificate_file\" and "
172 "\"ca_certificate_file\" must be specified]")
173 << config.status();
174 }
175
176 } // namespace
177 } // namespace testing
178 } // namespace grpc_core
179
main(int argc,char ** argv)180 int main(int argc, char** argv) {
181 ::testing::InitGoogleTest(&argc, argv);
182 grpc::testing::TestEnvironment env(&argc, argv);
183 grpc_init();
184 auto result = RUN_ALL_TESTS();
185 grpc_shutdown();
186 return result;
187 }
188