diff --git a/test/server/api_listener_test.cc b/test/server/api_listener_test.cc index 697cb166e2de4..4611a37fe3e36 100644 --- a/test/server/api_listener_test.cc +++ b/test/server/api_listener_test.cc @@ -240,5 +240,147 @@ name: test_api_listener EXPECT_ENVOY_BUG(connection.isHalfCloseEnabled(), "Unexpected function call"); } +// Exercise SyntheticReadCallbacks unimplemented methods and PANIC behavior for socket(). +TEST_F(ApiListenerTest, SyntheticReadCallbacksUnimplementedMethods) { + const std::string yaml = R"EOF( +name: test_api_listener +address: + socket_address: + address: 127.0.0.1 + port_value: 1234 +api_listener: + api_listener: + "@type": type.googleapis.com/envoy.extensions.filters.network.http_connection_manager.v3.HttpConnectionManager + stat_prefix: hcm + route_config: + name: api_router + virtual_hosts: + - name: api + domains: + - "*" + routes: + - match: + prefix: "/" + route: + cluster: dynamic_forward_proxy_cluster + )EOF"; + + const envoy::config::listener::v3::Listener config = parseListenerFromV3Yaml(yaml); + server_.server_factory_context_->cluster_manager_.initializeClusters( + {"dynamic_forward_proxy_cluster"}, {}); + HttpApiListenerFactory factory; + auto http_api_listener = factory.create(config, server_, config.name()).value(); + auto api_listener = http_api_listener->createHttpApiListener(server_.dispatcher()); + ASSERT_NE(api_listener, nullptr); + + // Access SyntheticReadCallbacks through the wrapper. + auto* wrapper = dynamic_cast(api_listener.get()); + ASSERT_NE(wrapper, nullptr); + auto& read_callbacks = wrapper->readCallbacks(); + + Buffer::OwnedImpl dummy_buffer("x"); + EXPECT_ENVOY_BUG(read_callbacks.continueReading(), "Unexpected call to continueReading"); + EXPECT_ENVOY_BUG(read_callbacks.injectReadDataToFilterChain(dummy_buffer, false), + "Unexpected call to injectReadDataToFilterChain"); + EXPECT_ENVOY_BUG(read_callbacks.disableClose(true), "Unexpected call to disableClose"); + EXPECT_ENVOY_BUG(read_callbacks.startUpstreamSecureTransport(), + "Unexpected call to startUpstreamSecureTransport"); + EXPECT_EQ(read_callbacks.upstreamHost(), nullptr); + EXPECT_ENVOY_BUG(read_callbacks.upstreamHost(nullptr), "Unexpected call to upstreamHost"); + EXPECT_DEATH(read_callbacks.socket(), "not implemented"); +} + +// Verify base address access and drain decision behavior. +TEST_F(ApiListenerTest, NewStreamHandleReturnsDecoderHandle) { + const std::string yaml = R"EOF( +name: test_api_listener +address: + socket_address: + address: 127.0.0.1 + port_value: 1234 +api_listener: + api_listener: + "@type": type.googleapis.com/envoy.extensions.filters.network.http_connection_manager.v3.HttpConnectionManager + stat_prefix: hcm + route_config: + name: api_router + virtual_hosts: + - name: api + domains: + - "*" + routes: + - match: + prefix: "/" + route: + cluster: dynamic_forward_proxy_cluster + )EOF"; + + const envoy::config::listener::v3::Listener config = parseListenerFromV3Yaml(yaml); + server_.server_factory_context_->cluster_manager_.initializeClusters( + {"dynamic_forward_proxy_cluster"}, {}); + + HttpApiListenerFactory factory; + auto http_api_listener = factory.create(config, server_, config.name()).value(); + auto api_listener = http_api_listener->createHttpApiListener(server_.dispatcher()); + ASSERT_NE(api_listener, nullptr); + + testing::NiceMock response_encoder; + ON_CALL(response_encoder, getStream()) + .WillByDefault(testing::ReturnRef(response_encoder.stream_)); + ON_CALL(response_encoder, setRequestDecoder(testing::_)).WillByDefault(testing::Return()); + + auto decoder_handle = api_listener->newStreamHandle(response_encoder); + ASSERT_NE(decoder_handle, nullptr); + + // Tear down in safe order. + decoder_handle.reset(); + api_listener.reset(); +} + +// Removing callbacks prevents receiving RemoteClose on ApiListenerWrapper destruction. +TEST_F(ApiListenerTest, NoEventAfterCallbackRemovalOnShutdown) { + const std::string yaml = R"EOF( +name: test_api_listener +address: + socket_address: + address: 127.0.0.1 + port_value: 1234 +api_listener: + api_listener: + "@type": type.googleapis.com/envoy.extensions.filters.network.http_connection_manager.v3.HttpConnectionManager + stat_prefix: hcm + route_config: + name: api_router + virtual_hosts: + - name: api + domains: + - "*" + routes: + - match: + prefix: "/" + route: + cluster: dynamic_forward_proxy_cluster + )EOF"; + + const envoy::config::listener::v3::Listener config = parseListenerFromV3Yaml(yaml); + server_.server_factory_context_->cluster_manager_.initializeClusters( + {"dynamic_forward_proxy_cluster"}, {}); + + HttpApiListenerFactory factory; + auto http_api_listener = factory.create(config, server_, config.name()).value(); + auto api_listener = http_api_listener->createHttpApiListener(server_.dispatcher()); + ASSERT_NE(api_listener, nullptr); + + Network::MockConnectionCallbacks network_connection_callbacks; + auto& connection = dynamic_cast(api_listener.get()) + ->readCallbacks() + .connection(); + connection.addConnectionCallbacks(network_connection_callbacks); + connection.removeConnectionCallbacks(network_connection_callbacks); + + EXPECT_CALL(network_connection_callbacks, onEvent(testing::_)).Times(0); + api_listener.reset(); +} + } // namespace Server } // namespace Envoy