1 //
2 // Copyright 2024 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 <gmock/gmock.h>
18 #include <gtest/gtest.h>
19
20 #include <string>
21 #include <vector>
22
23 #include "absl/log/log.h"
24 #include "absl/strings/str_cat.h"
25 #include "absl/strings/str_format.h"
26 #include "envoy/config/core/v3/address.pb.h"
27 #include "envoy/extensions/transport_sockets/http_11_proxy/v3/upstream_http_11_connect.pb.h"
28 #include "src/core/client_channel/backup_poller.h"
29 #include "src/core/config/config_vars.h"
30 #include "test/core/end2end/fixtures/http_proxy_fixture.h"
31 #include "test/core/test_util/resolve_localhost_ip46.h"
32 #include "test/core/test_util/scoped_env_var.h"
33 #include "test/cpp/end2end/xds/xds_end2end_test_lib.h"
34
35 namespace grpc {
36 namespace testing {
37 namespace {
38
39 using envoy::extensions::transport_sockets::http_11_proxy::v3::
40 Http11ProxyUpstreamTransport;
41
42 class XdsHttpProxyTest : public XdsEnd2endTest {
43 protected:
SetUp()44 void SetUp() override {
45 http_proxy_ = grpc_end2end_http_proxy_create(nullptr);
46 XdsEnd2endTest::SetUp();
47 }
48
TearDown()49 void TearDown() override {
50 XdsEnd2endTest::TearDown();
51 grpc_end2end_http_proxy_destroy(http_proxy_);
52 }
53
54 grpc_end2end_http_proxy* http_proxy_;
55 };
56
57 INSTANTIATE_TEST_SUITE_P(XdsTest, XdsHttpProxyTest,
58 ::testing::Values(XdsTestType()), &XdsTestType::Name);
59
TEST_P(XdsHttpProxyTest,TransportProxyInClusterAndProxyAddressInEndpoint)60 TEST_P(XdsHttpProxyTest, TransportProxyInClusterAndProxyAddressInEndpoint) {
61 grpc_core::testing::ScopedExperimentalEnvVar env(
62 "GRPC_EXPERIMENTAL_XDS_HTTP_CONNECT");
63 CreateAndStartBackends(1);
64 // Set transport socket in CDS.
65 Cluster cluster = default_cluster_;
66 cluster.mutable_transport_socket()->mutable_typed_config()->PackFrom(
67 Http11ProxyUpstreamTransport());
68 balancer_->ads_service()->SetCdsResource(cluster);
69 // Set proxy address in EDS metadata.
70 ClusterLoadAssignment endpoints = BuildEdsResource(
71 EdsResourceArgs({{"locality0", CreateEndpointsForBackends()}}));
72 envoy::config::core::v3::Address proxy_address_proto;
73 auto* socket_address = proxy_address_proto.mutable_socket_address();
74 socket_address->set_address(grpc_core::LocalIp());
75 socket_address->set_port_value(
76 grpc_end2end_http_proxy_get_proxy_port(http_proxy_));
77 auto& metadata_map = *endpoints.mutable_endpoints(0)
78 ->mutable_lb_endpoints(0)
79 ->mutable_metadata()
80 ->mutable_typed_filter_metadata();
81 metadata_map["envoy.http11_proxy_transport_socket.proxy_address"].PackFrom(
82 proxy_address_proto);
83 balancer_->ads_service()->SetEdsResource(endpoints);
84 // Everything should work.
85 CheckRpcSendOk(DEBUG_LOCATION);
86 // Proxy should have seen one connection.
87 EXPECT_EQ(grpc_end2end_http_proxy_num_connections(http_proxy_), 1);
88 }
89
TEST_P(XdsHttpProxyTest,TransportProxyInClusterButNoProxyAddressInEndpoint)90 TEST_P(XdsHttpProxyTest, TransportProxyInClusterButNoProxyAddressInEndpoint) {
91 grpc_core::testing::ScopedExperimentalEnvVar env(
92 "GRPC_EXPERIMENTAL_XDS_HTTP_CONNECT");
93 CreateAndStartBackends(1);
94 // Set transport socket in CDS.
95 Cluster cluster = default_cluster_;
96 cluster.mutable_transport_socket()->mutable_typed_config()->PackFrom(
97 Http11ProxyUpstreamTransport());
98 balancer_->ads_service()->SetCdsResource(cluster);
99 // Set proxy address in EDS metadata.
100 ClusterLoadAssignment endpoints = BuildEdsResource(
101 EdsResourceArgs({{"locality0", CreateEndpointsForBackends()}}));
102 balancer_->ads_service()->SetEdsResource(endpoints);
103 // Everything should work.
104 CheckRpcSendOk(DEBUG_LOCATION);
105 // Proxy should not have seen any connections.
106 EXPECT_EQ(grpc_end2end_http_proxy_num_connections(http_proxy_), 0);
107 }
108
TEST_P(XdsHttpProxyTest,ProxyAddressInEndpointButNoTransportProxyInCluster)109 TEST_P(XdsHttpProxyTest, ProxyAddressInEndpointButNoTransportProxyInCluster) {
110 grpc_core::testing::ScopedExperimentalEnvVar env(
111 "GRPC_EXPERIMENTAL_XDS_HTTP_CONNECT");
112 CreateAndStartBackends(1);
113 // Set proxy address in EDS metadata.
114 ClusterLoadAssignment endpoints = BuildEdsResource(
115 EdsResourceArgs({{"locality0", CreateEndpointsForBackends()}}));
116 envoy::config::core::v3::Address proxy_address_proto;
117 auto* socket_address = proxy_address_proto.mutable_socket_address();
118 socket_address->set_address(grpc_core::LocalIp());
119 socket_address->set_port_value(
120 grpc_end2end_http_proxy_get_proxy_port(http_proxy_));
121 auto& metadata_map = *endpoints.mutable_endpoints(0)
122 ->mutable_lb_endpoints(0)
123 ->mutable_metadata()
124 ->mutable_typed_filter_metadata();
125 metadata_map["envoy.http11_proxy_transport_socket.proxy_address"].PackFrom(
126 proxy_address_proto);
127 balancer_->ads_service()->SetEdsResource(endpoints);
128 // Everything should work.
129 CheckRpcSendOk(DEBUG_LOCATION);
130 // Proxy should not have seen any connections.
131 EXPECT_EQ(grpc_end2end_http_proxy_num_connections(http_proxy_), 0);
132 }
133
TEST_P(XdsHttpProxyTest,CdsNackedWhenNotEnabled)134 TEST_P(XdsHttpProxyTest, CdsNackedWhenNotEnabled) {
135 // Set transport socket in CDS.
136 Cluster cluster = default_cluster_;
137 cluster.mutable_transport_socket()->mutable_typed_config()->PackFrom(
138 Http11ProxyUpstreamTransport());
139 balancer_->ads_service()->SetCdsResource(cluster);
140 // Wait for NACK.
141 const auto response_state = WaitForCdsNack(DEBUG_LOCATION);
142 ASSERT_TRUE(response_state.has_value()) << "timed out waiting for NACK";
143 EXPECT_EQ(response_state->error_message,
144 "xDS response validation errors: ["
145 "resource index 0: cluster_name: "
146 "INVALID_ARGUMENT: errors validating Cluster resource: ["
147 "field:transport_socket.typed_config.value["
148 "envoy.extensions.transport_sockets.http_11_proxy.v3"
149 ".Http11ProxyUpstreamTransport].type_url "
150 "error:unsupported transport socket type]]");
151 }
152
153 } // namespace
154 } // namespace testing
155 } // namespace grpc
156
main(int argc,char ** argv)157 int main(int argc, char** argv) {
158 grpc::testing::TestEnvironment env(&argc, argv);
159 ::testing::InitGoogleTest(&argc, argv);
160 // Make the backup poller poll very frequently in order to pick up
161 // updates from all the subchannels's FDs.
162 grpc_core::ConfigVars::Overrides overrides;
163 overrides.client_channel_backup_poll_interval_ms = 1;
164 grpc_core::ConfigVars::SetOverrides(overrides);
165 #if TARGET_OS_IPHONE
166 // Workaround Apple CFStream bug
167 grpc_core::SetEnv("grpc_cfstream", "0");
168 #endif
169 grpc_init();
170 const auto result = RUN_ALL_TESTS();
171 grpc_shutdown();
172 return result;
173 }
174