@@ -240,5 +240,147 @@ name: test_api_listener
240240 EXPECT_ENVOY_BUG (connection.isHalfCloseEnabled (), " Unexpected function call" );
241241}
242242
243+ // Exercise SyntheticReadCallbacks unimplemented methods and PANIC behavior for socket().
244+ TEST_F (ApiListenerTest, SyntheticReadCallbacksUnimplementedMethods) {
245+ const std::string yaml = R"EOF(
246+ name: test_api_listener
247+ address:
248+ socket_address:
249+ address: 127.0.0.1
250+ port_value: 1234
251+ api_listener:
252+ api_listener:
253+ "@type": type.googleapis.com/envoy.extensions.filters.network.http_connection_manager.v3.HttpConnectionManager
254+ stat_prefix: hcm
255+ route_config:
256+ name: api_router
257+ virtual_hosts:
258+ - name: api
259+ domains:
260+ - "*"
261+ routes:
262+ - match:
263+ prefix: "/"
264+ route:
265+ cluster: dynamic_forward_proxy_cluster
266+ )EOF" ;
267+
268+ const envoy::config::listener::v3::Listener config = parseListenerFromV3Yaml (yaml);
269+ server_.server_factory_context_ ->cluster_manager_ .initializeClusters (
270+ {" dynamic_forward_proxy_cluster" }, {});
271+ HttpApiListenerFactory factory;
272+ auto http_api_listener = factory.create (config, server_, config.name ()).value ();
273+ auto api_listener = http_api_listener->createHttpApiListener (server_.dispatcher ());
274+ ASSERT_NE (api_listener, nullptr );
275+
276+ // Access SyntheticReadCallbacks through the wrapper.
277+ auto * wrapper = dynamic_cast <HttpApiListener::ApiListenerWrapper*>(api_listener.get ());
278+ ASSERT_NE (wrapper, nullptr );
279+ auto & read_callbacks = wrapper->readCallbacks ();
280+
281+ Buffer::OwnedImpl dummy_buffer (" x" );
282+ EXPECT_ENVOY_BUG (read_callbacks.continueReading (), " Unexpected call to continueReading" );
283+ EXPECT_ENVOY_BUG (read_callbacks.injectReadDataToFilterChain (dummy_buffer, false ),
284+ " Unexpected call to injectReadDataToFilterChain" );
285+ EXPECT_ENVOY_BUG (read_callbacks.disableClose (true ), " Unexpected call to disableClose" );
286+ EXPECT_ENVOY_BUG (read_callbacks.startUpstreamSecureTransport (),
287+ " Unexpected call to startUpstreamSecureTransport" );
288+ EXPECT_EQ (read_callbacks.upstreamHost (), nullptr );
289+ EXPECT_ENVOY_BUG (read_callbacks.upstreamHost (nullptr ), " Unexpected call to upstreamHost" );
290+ EXPECT_DEATH (read_callbacks.socket (), " not implemented" );
291+ }
292+
293+ // Verify base address access and drain decision behavior.
294+ TEST_F (ApiListenerTest, NewStreamHandleReturnsDecoderHandle) {
295+ const std::string yaml = R"EOF(
296+ name: test_api_listener
297+ address:
298+ socket_address:
299+ address: 127.0.0.1
300+ port_value: 1234
301+ api_listener:
302+ api_listener:
303+ "@type": type.googleapis.com/envoy.extensions.filters.network.http_connection_manager.v3.HttpConnectionManager
304+ stat_prefix: hcm
305+ route_config:
306+ name: api_router
307+ virtual_hosts:
308+ - name: api
309+ domains:
310+ - "*"
311+ routes:
312+ - match:
313+ prefix: "/"
314+ route:
315+ cluster: dynamic_forward_proxy_cluster
316+ )EOF" ;
317+
318+ const envoy::config::listener::v3::Listener config = parseListenerFromV3Yaml (yaml);
319+ server_.server_factory_context_ ->cluster_manager_ .initializeClusters (
320+ {" dynamic_forward_proxy_cluster" }, {});
321+
322+ HttpApiListenerFactory factory;
323+ auto http_api_listener = factory.create (config, server_, config.name ()).value ();
324+ auto api_listener = http_api_listener->createHttpApiListener (server_.dispatcher ());
325+ ASSERT_NE (api_listener, nullptr );
326+
327+ testing::NiceMock<Envoy::Http::MockResponseEncoder> response_encoder;
328+ ON_CALL (response_encoder, getStream ())
329+ .WillByDefault (testing::ReturnRef (response_encoder.stream_ ));
330+ ON_CALL (response_encoder, setRequestDecoder (testing::_)).WillByDefault (testing::Return ());
331+
332+ auto decoder_handle = api_listener->newStreamHandle (response_encoder);
333+ ASSERT_NE (decoder_handle, nullptr );
334+
335+ // Tear down in safe order.
336+ decoder_handle.reset ();
337+ api_listener.reset ();
338+ }
339+
340+ // Removing callbacks prevents receiving RemoteClose on ApiListenerWrapper destruction.
341+ TEST_F (ApiListenerTest, NoEventAfterCallbackRemovalOnShutdown) {
342+ const std::string yaml = R"EOF(
343+ name: test_api_listener
344+ address:
345+ socket_address:
346+ address: 127.0.0.1
347+ port_value: 1234
348+ api_listener:
349+ api_listener:
350+ "@type": type.googleapis.com/envoy.extensions.filters.network.http_connection_manager.v3.HttpConnectionManager
351+ stat_prefix: hcm
352+ route_config:
353+ name: api_router
354+ virtual_hosts:
355+ - name: api
356+ domains:
357+ - "*"
358+ routes:
359+ - match:
360+ prefix: "/"
361+ route:
362+ cluster: dynamic_forward_proxy_cluster
363+ )EOF" ;
364+
365+ const envoy::config::listener::v3::Listener config = parseListenerFromV3Yaml (yaml);
366+ server_.server_factory_context_ ->cluster_manager_ .initializeClusters (
367+ {" dynamic_forward_proxy_cluster" }, {});
368+
369+ HttpApiListenerFactory factory;
370+ auto http_api_listener = factory.create (config, server_, config.name ()).value ();
371+ auto api_listener = http_api_listener->createHttpApiListener (server_.dispatcher ());
372+ ASSERT_NE (api_listener, nullptr );
373+
374+ Network::MockConnectionCallbacks network_connection_callbacks;
375+ auto & connection = dynamic_cast <HttpApiListener::ApiListenerWrapper*>(api_listener.get ())
376+ ->readCallbacks ()
377+ .connection ();
378+ connection.addConnectionCallbacks (network_connection_callbacks);
379+ connection.removeConnectionCallbacks (network_connection_callbacks);
380+
381+ EXPECT_CALL (network_connection_callbacks, onEvent (testing::_)).Times (0 );
382+ api_listener.reset ();
383+ }
384+
243385} // namespace Server
244386} // namespace Envoy
0 commit comments