• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 //
2 // Copyright 2023 gRPC authors.
3 //
4 // Licensed under the Apache License, Version 2.0 (the "License");
5 // you may not use this file except in compliance with the License.
6 // You may obtain a copy of the License at
7 //
8 //     http://www.apache.org/licenses/LICENSE-2.0
9 //
10 // Unless required by applicable law or agreed to in writing, software
11 // distributed under the License is distributed on an "AS IS" BASIS,
12 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 // See the License for the specific language governing permissions and
14 // limitations under the License.
15 //
16 
17 #include "test/cpp/interop/xds_stats_watcher.h"
18 
19 #include <gmock/gmock.h>
20 #include <grpc/grpc.h>
21 #include <gtest/gtest.h>
22 
23 #include <map>
24 #include <memory>
25 
26 #include "test/core/test_util/test_config.h"
27 
28 namespace grpc {
29 namespace testing {
30 namespace {
31 
BuildCallResult(int saved_request_id)32 AsyncClientCallResult BuildCallResult(int saved_request_id) {
33   AsyncClientCallResult result;
34   result.saved_request_id = saved_request_id;
35   result.rpc_type = ClientConfigureRequest::UNARY_CALL;
36   return result;
37 }
38 
39 struct MetadataEntryInit {
40   absl::string_view key;
41   absl::string_view value;
42   bool is_trailing;
43 };
44 
BuildMetadatas(const std::initializer_list<std::initializer_list<MetadataEntryInit>> & values)45 LoadBalancerStatsResponse::MetadataByPeer BuildMetadatas(
46     const std::initializer_list<std::initializer_list<MetadataEntryInit>>&
47         values) {
48   LoadBalancerStatsResponse::MetadataByPeer metadata_by_peer;
49   for (const auto& per_rpc : values) {
50     auto rpc_metadata = metadata_by_peer.add_rpc_metadata();
51     for (const auto& key_value : per_rpc) {
52       auto entry = rpc_metadata->add_metadata();
53       entry->set_key(key_value.key);
54       entry->set_value(key_value.value);
55       entry->set_type(key_value.is_trailing
56                           ? LoadBalancerStatsResponse::TRAILING
57                           : LoadBalancerStatsResponse::INITIAL);
58     }
59   }
60   return metadata_by_peer;
61 }
62 
TEST(XdsStatsWatcherTest,WaitForRpcStatsResponse)63 TEST(XdsStatsWatcherTest, WaitForRpcStatsResponse) {
64   // "k3" will be ignored
65   XdsStatsWatcher watcher(0, 4, {"k1", "k2"});
66   watcher.RpcCompleted(BuildCallResult(0), "peer1",
67                        {{"k1", "v1"}, {"k2", "v2"}, {"k3", "v3"}},
68                        {{"k1", "t1"}, {"k3", "t3"}});
69   watcher.RpcCompleted(BuildCallResult(1), "peer1", {{"k1", "v4"}}, {});
70   watcher.RpcCompleted(BuildCallResult(2), "peer1", {}, {});
71   watcher.RpcCompleted(BuildCallResult(3), "peer2",
72                        {{"k1", "v5"}, {"k2", "v6"}, {"k3", "v7"}},
73                        {{"k1", "t5"}, {"k3", "t7"}});
74   LoadBalancerStatsResponse expected;
75   expected.mutable_rpcs_by_peer()->insert({{"peer1", 3}, {"peer2", 1}});
76   expected.mutable_metadatas_by_peer()->insert({
77       {"peer1",
78        BuildMetadatas({
79            {{"k1", "v1", false}, {"k2", "v2", false}, {"k1", "t1", true}},
80            {{"k1", "v4", false}},
81            {},
82        })},
83       {"peer2",
84        BuildMetadatas({
85            {{"k1", "v5", false}, {"k2", "v6", false}, {"k1", "t5", true}},
86        })},
87   });
88   (*expected.mutable_rpcs_by_method())["UnaryCall"]
89       .mutable_rpcs_by_peer()
90       ->insert({{"peer1", 3}, {"peer2", 1}});
91   EXPECT_EQ(expected.DebugString(),
92             watcher.WaitForRpcStatsResponse(0).DebugString());
93 }
94 
TEST(XdsStatsWatcherTest,WaitForRpcStatsResponseIgnoresCase)95 TEST(XdsStatsWatcherTest, WaitForRpcStatsResponseIgnoresCase) {
96   // "k3" will be ignored
97   XdsStatsWatcher watcher(0, 3, {"k1", "K2"});
98   watcher.RpcCompleted(BuildCallResult(0), "peer1",
99                        {{"K1", "v1"}, {"k2", "v2"}, {"k3", "v3"}},
100                        {{"K1", "t1"}, {"k2", "t2"}});
101   watcher.RpcCompleted(BuildCallResult(1), "peer1", {}, {});
102   watcher.RpcCompleted(BuildCallResult(2), "peer2", {},
103                        {{"k1", "v5"}, {"K2", "v6"}, {"k3", "v7"}});
104   LoadBalancerStatsResponse expected;
105   expected.mutable_rpcs_by_peer()->insert({{"peer1", 2}, {"peer2", 1}});
106   expected.mutable_metadatas_by_peer()->insert({
107       {"peer1", BuildMetadatas({
108                     {{"K1", "v1", false},
109                      {"k2", "v2", false},
110                      {"K1", "t1", true},
111                      {"k2", "t2", true}},
112                     {},
113                 })},
114       {"peer2", BuildMetadatas({{{"K2", "v6", true}, {"k1", "v5", true}}})},
115   });
116   (*expected.mutable_rpcs_by_method())["UnaryCall"]
117       .mutable_rpcs_by_peer()
118       ->insert({{"peer1", 2}, {"peer2", 1}});
119   EXPECT_EQ(expected.DebugString(),
120             watcher.WaitForRpcStatsResponse(0).DebugString());
121 }
122 
TEST(XdsStatsWatcherTest,WaitForRpcStatsResponseReturnsAll)123 TEST(XdsStatsWatcherTest, WaitForRpcStatsResponseReturnsAll) {
124   // "k3" will be ignored
125   XdsStatsWatcher watcher(0, 3, {"*"});
126   watcher.RpcCompleted(BuildCallResult(0), "peer1",
127                        {{"K1", "v1"}, {"k2", "v2"}, {"k3", "v3"}},
128                        {{"K1", "t1"}, {"k2", "t2"}});
129   watcher.RpcCompleted(BuildCallResult(1), "peer1", {}, {});
130   watcher.RpcCompleted(BuildCallResult(2), "peer2", {},
131                        {{"k1", "v5"}, {"K2", "v6"}, {"k3", "v7"}});
132   LoadBalancerStatsResponse expected;
133   expected.mutable_rpcs_by_peer()->insert({{"peer1", 2}, {"peer2", 1}});
134   expected.mutable_metadatas_by_peer()->insert({
135       {"peer1", BuildMetadatas({
136                     {{"K1", "v1", false},
137                      {"k2", "v2", false},
138                      {"k3", "v3", false},
139                      {"K1", "t1", true},
140                      {"k2", "t2", true}},
141                     {},
142                 })},
143       {"peer2",
144        BuildMetadatas(
145            {{{"K2", "v6", true}, {"k1", "v5", true}, {"k3", "v7", true}}})},
146   });
147   (*expected.mutable_rpcs_by_method())["UnaryCall"]
148       .mutable_rpcs_by_peer()
149       ->insert({{"peer1", 2}, {"peer2", 1}});
150   EXPECT_EQ(expected.DebugString(),
151             watcher.WaitForRpcStatsResponse(0).DebugString());
152 }
153 
TEST(XdsStatsWatcherTest,WaitForRpcStatsResponseExcludesMetadata)154 TEST(XdsStatsWatcherTest, WaitForRpcStatsResponseExcludesMetadata) {
155   XdsStatsWatcher watcher(0, 3, {});
156   // RPC had metadata - but watcher should ignore it
157   watcher.RpcCompleted(BuildCallResult(0), "peer1",
158                        {{"K1", "v1"}, {"k2", "v2"}, {"k3", "v3"}},
159                        {{"K1", "t1"}, {"k2", "t2"}});
160   watcher.RpcCompleted(BuildCallResult(1), "peer1", {{"k1", "v4"}}, {});
161   watcher.RpcCompleted(BuildCallResult(2), "peer2", {},
162                        {{"k1", "v5"}, {"k2", "v6"}, {"k3", "v7"}});
163   LoadBalancerStatsResponse expected;
164   expected.mutable_rpcs_by_peer()->insert({{"peer1", 2}, {"peer2", 1}});
165   (*expected.mutable_rpcs_by_method())["UnaryCall"]
166       .mutable_rpcs_by_peer()
167       ->insert({{"peer1", 2}, {"peer2", 1}});
168   EXPECT_EQ(watcher.WaitForRpcStatsResponse(0).DebugString(),
169             expected.DebugString());
170 }
171 
172 }  // namespace
173 }  // namespace testing
174 }  // namespace grpc
175 
main(int argc,char ** argv)176 int main(int argc, char** argv) {
177   ::testing::InitGoogleTest(&argc, argv);
178   grpc::testing::TestEnvironment env(&argc, argv);
179   grpc_init();
180   auto result = RUN_ALL_TESTS();
181   grpc_shutdown();
182   return result;
183 }
184