Skip to content

Commit 52d12f6

Browse files
author
karenx
committed
code cov
Signed-off-by: karenx <karenx@uber.com>
1 parent aa9d758 commit 52d12f6

File tree

1 file changed

+204
-0
lines changed

1 file changed

+204
-0
lines changed

modules/transport-grpc/src/test/java/org/opensearch/transport/grpc/Netty4GrpcServerTransportTests.java

Lines changed: 204 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212
import org.opensearch.common.network.NetworkService;
1313
import org.opensearch.common.settings.Settings;
1414
import org.opensearch.common.util.concurrent.OpenSearchExecutors;
15+
import org.opensearch.core.common.transport.BoundTransportAddress;
1516
import org.opensearch.core.common.transport.TransportAddress;
1617
import org.opensearch.test.OpenSearchTestCase;
1718
import org.opensearch.transport.grpc.ssl.NettyGrpcClient;
@@ -324,6 +325,209 @@ public void testExecutorCountSettingsValidation() {
324325
expectThrows(IllegalArgumentException.class, () -> { new Netty4GrpcServerTransport(invalidSettings, services, networkService); });
325326
}
326327

328+
public void testStartFailureTriggersCleanup() {
329+
// Create a transport that will fail to start
330+
Settings settingsWithInvalidPort = Settings.builder()
331+
.put(Netty4GrpcServerTransport.SETTING_GRPC_PORT.getKey(), "999999") // Invalid port
332+
.build();
333+
334+
Netty4GrpcServerTransport transport = new Netty4GrpcServerTransport(settingsWithInvalidPort, services, networkService);
335+
336+
// Start should fail
337+
expectThrows(Exception.class, transport::start);
338+
339+
// Resources should be cleaned up after failure - the implementation calls doStop() in the finally block
340+
ExecutorService executor = transport.getGrpcExecutorForTesting();
341+
EventLoopGroup bossGroup = transport.getBossEventLoopGroupForTesting();
342+
EventLoopGroup workerGroup = transport.getWorkerEventLoopGroupForTesting();
343+
344+
// Resources may still exist but should be shutdown
345+
if (executor != null) {
346+
assertTrue("Executor should be shutdown after failed start", executor.isShutdown());
347+
}
348+
if (bossGroup != null) {
349+
assertTrue("Boss group should be shutdown after failed start", bossGroup.isShutdown());
350+
}
351+
if (workerGroup != null) {
352+
assertTrue("Worker group should be shutdown after failed start", workerGroup.isShutdown());
353+
}
354+
355+
// Close should still be safe to call
356+
transport.close();
357+
}
358+
359+
public void testInterruptedShutdownHandling() throws InterruptedException {
360+
Settings settings = createSettings();
361+
Netty4GrpcServerTransport transport = new Netty4GrpcServerTransport(settings, services, networkService);
362+
363+
transport.start();
364+
365+
// Interrupt the current thread to test interrupt handling
366+
Thread.currentThread().interrupt();
367+
368+
// Stop should handle the interrupt gracefully
369+
transport.stop();
370+
371+
// Clear interrupt status
372+
Thread.interrupted();
373+
374+
transport.close();
375+
}
376+
377+
public void testInvalidHostBinding() {
378+
// Test with invalid bind host to trigger host resolution error
379+
Settings settings = Settings.builder()
380+
.put(Netty4GrpcServerTransport.SETTING_GRPC_PORT.getKey(), OpenSearchTestCase.getPortRange())
381+
.put(Netty4GrpcServerTransport.SETTING_GRPC_BIND_HOST.getKey(), "invalid.host.that.does.not.exist")
382+
.build();
383+
384+
Netty4GrpcServerTransport transport = new Netty4GrpcServerTransport(settings, services, networkService);
385+
386+
// Start should fail due to host resolution failure
387+
expectThrows(Exception.class, transport::start);
388+
389+
transport.close();
390+
}
391+
392+
public void testPublishPortResolutionFailure() {
393+
// Create settings that will cause publish port resolution to fail
394+
Settings settings = Settings.builder()
395+
.put(Netty4GrpcServerTransport.SETTING_GRPC_PORT.getKey(), "0") // Dynamic port
396+
.put(Netty4GrpcServerTransport.SETTING_GRPC_PUBLISH_PORT.getKey(), "65536") // Invalid publish port
397+
.build();
398+
399+
Netty4GrpcServerTransport transport = new Netty4GrpcServerTransport(settings, services, networkService);
400+
401+
// Start should fail due to publish port resolution
402+
expectThrows(Exception.class, transport::start);
403+
404+
transport.close();
405+
}
406+
407+
public void testMultipleBindAddresses() {
408+
// Test binding to multiple localhost addresses
409+
Settings settings = Settings.builder()
410+
.put(Netty4GrpcServerTransport.SETTING_GRPC_PORT.getKey(), OpenSearchTestCase.getPortRange())
411+
.putList(Netty4GrpcServerTransport.SETTING_GRPC_BIND_HOST.getKey(), "127.0.0.1", "localhost")
412+
.build();
413+
414+
try (Netty4GrpcServerTransport transport = new Netty4GrpcServerTransport(settings, services, networkService)) {
415+
transport.start();
416+
417+
BoundTransportAddress boundAddress = transport.getBoundAddress();
418+
assertNotNull("Bound address should not be null", boundAddress);
419+
assertTrue("Should have at least one bound address", boundAddress.boundAddresses().length > 0);
420+
421+
transport.stop();
422+
}
423+
}
424+
425+
public void testShutdownTimeoutHandling() throws InterruptedException {
426+
Settings settings = createSettings();
427+
Netty4GrpcServerTransport transport = new Netty4GrpcServerTransport(settings, services, networkService);
428+
429+
transport.start();
430+
431+
// Get references to the thread pools
432+
ExecutorService executor = transport.getGrpcExecutorForTesting();
433+
EventLoopGroup bossGroup = transport.getBossEventLoopGroupForTesting();
434+
EventLoopGroup workerGroup = transport.getWorkerEventLoopGroupForTesting();
435+
436+
assertNotNull("Executor should be created", executor);
437+
assertNotNull("Boss group should be created", bossGroup);
438+
assertNotNull("Worker group should be created", workerGroup);
439+
440+
// Normal shutdown should work
441+
transport.stop();
442+
443+
// Verify everything is shutdown
444+
assertTrue("Executor should be shutdown", executor.isShutdown());
445+
assertTrue("Boss group should be shutdown", bossGroup.isShutdown());
446+
assertTrue("Worker group should be shutdown", workerGroup.isShutdown());
447+
448+
transport.close();
449+
}
450+
451+
public void testResourceCleanupOnClose() {
452+
Settings settings = createSettings();
453+
Netty4GrpcServerTransport transport = new Netty4GrpcServerTransport(settings, services, networkService);
454+
455+
transport.start();
456+
transport.stop();
457+
458+
// doClose should handle cleanup gracefully even if resources are already shutdown
459+
transport.close();
460+
461+
// Multiple closes should be safe
462+
transport.close();
463+
}
464+
465+
public void testPortRangeHandling() {
466+
// Test with a port range
467+
Settings settings = Settings.builder().put(Netty4GrpcServerTransport.SETTING_GRPC_PORT.getKey(), "9300-9400").build();
468+
469+
try (Netty4GrpcServerTransport transport = new Netty4GrpcServerTransport(settings, services, networkService)) {
470+
transport.start();
471+
472+
BoundTransportAddress boundAddress = transport.getBoundAddress();
473+
assertNotNull("Bound address should not be null", boundAddress);
474+
475+
int actualPort = boundAddress.publishAddress().getPort();
476+
assertTrue("Port should be in range 9300-9400", actualPort >= 9300 && actualPort <= 9400);
477+
478+
transport.stop();
479+
}
480+
}
481+
482+
public void testGracefulShutdownWithException() {
483+
// Test that exceptions during shutdown don't prevent cleanup
484+
Settings settings = createSettings();
485+
Netty4GrpcServerTransport transport = new Netty4GrpcServerTransport(settings, services, networkService);
486+
487+
transport.start();
488+
489+
// Simulate an interruption during shutdown to test exception handling paths
490+
ExecutorService executor = transport.getGrpcExecutorForTesting();
491+
EventLoopGroup bossGroup = transport.getBossEventLoopGroupForTesting();
492+
EventLoopGroup workerGroup = transport.getWorkerEventLoopGroupForTesting();
493+
494+
assertNotNull("Executor should be created", executor);
495+
assertNotNull("Boss group should be created", bossGroup);
496+
assertNotNull("Worker group should be created", workerGroup);
497+
498+
// Force shutdown to test the interrupt handling code paths
499+
executor.shutdownNow();
500+
bossGroup.shutdownGracefully(0, 0, java.util.concurrent.TimeUnit.MILLISECONDS);
501+
workerGroup.shutdownGracefully(0, 0, java.util.concurrent.TimeUnit.MILLISECONDS);
502+
503+
// Now call stop - it should handle the already shutdown resources gracefully
504+
transport.stop();
505+
transport.close();
506+
507+
// Verify everything is still properly shutdown
508+
assertTrue("Executor should be shutdown", executor.isShutdown());
509+
assertTrue("Boss group should be shutdown", bossGroup.isShutdown());
510+
assertTrue("Worker group should be shutdown", workerGroup.isShutdown());
511+
}
512+
513+
public void testCloseWithNullResources() {
514+
// Test that close() handles null resources gracefully
515+
Settings settings = createSettings();
516+
Netty4GrpcServerTransport transport = new Netty4GrpcServerTransport(settings, services, networkService);
517+
518+
// Don't start the transport, so resources should be null
519+
assertNull("Boss group should be null before start", transport.getBossEventLoopGroupForTesting());
520+
assertNull("Worker group should be null before start", transport.getWorkerEventLoopGroupForTesting());
521+
assertNull("Executor should be null before start", transport.getGrpcExecutorForTesting());
522+
523+
// Close should handle null resources gracefully
524+
transport.close();
525+
526+
// Multiple closes should be safe
527+
transport.close();
528+
transport.close();
529+
}
530+
327531
private static Settings createSettings() {
328532
return Settings.builder().put(Netty4GrpcServerTransport.SETTING_GRPC_PORT.getKey(), OpenSearchTestCase.getPortRange()).build();
329533
}

0 commit comments

Comments
 (0)