You are viewing a plain text version of this content. The canonical link for it is here.
Posted to notifications@shardingsphere.apache.org by zh...@apache.org on 2026/03/19 04:57:20 UTC

(shardingsphere) branch master updated: Add more test cases on DataSourcePoolDestroyerTest (#38506)

This is an automated email from the ASF dual-hosted git repository.

zhangliang pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/shardingsphere.git


The following commit(s) were added to refs/heads/master by this push:
     new 62045481e64 Add more test cases on DataSourcePoolDestroyerTest (#38506)
62045481e64 is described below

commit 62045481e641665273cc53daba5cbe1e923d6d35
Author: Liang Zhang <zh...@apache.org>
AuthorDate: Thu Mar 19 12:56:32 2026 +0800

    Add more test cases on DataSourcePoolDestroyerTest (#38506)
    
    * Add more test cases on DataSourcePoolDestroyerTest
    
    * Add more test cases on DataSourcePoolDestroyerTest
---
 .../destroyer/DataSourcePoolDestroyerTest.java     | 97 +++++++++++++++++++---
 1 file changed, 85 insertions(+), 12 deletions(-)

diff --git a/infra/data-source-pool/core/src/test/java/org/apache/shardingsphere/infra/datasource/pool/destroyer/DataSourcePoolDestroyerTest.java b/infra/data-source-pool/core/src/test/java/org/apache/shardingsphere/infra/datasource/pool/destroyer/DataSourcePoolDestroyerTest.java
index 794a7a5955d..62b308ed71c 100644
--- a/infra/data-source-pool/core/src/test/java/org/apache/shardingsphere/infra/datasource/pool/destroyer/DataSourcePoolDestroyerTest.java
+++ b/infra/data-source-pool/core/src/test/java/org/apache/shardingsphere/infra/datasource/pool/destroyer/DataSourcePoolDestroyerTest.java
@@ -17,31 +17,104 @@
 
 package org.apache.shardingsphere.infra.datasource.pool.destroyer;
 
-import org.apache.shardingsphere.test.infra.fixture.jdbc.MockedDataSource;
-import org.awaitility.Awaitility;
+import org.apache.shardingsphere.infra.spi.type.typed.TypedSPILoader;
+import org.hamcrest.CoreMatchers;
+import org.hamcrest.MatcherAssert;
 import org.junit.jupiter.api.Test;
+import org.junit.jupiter.params.ParameterizedTest;
+import org.junit.jupiter.params.provider.Arguments;
+import org.junit.jupiter.params.provider.MethodSource;
+import org.mockito.MockedStatic;
 
-import java.sql.Connection;
-import java.sql.SQLException;
-import java.util.concurrent.TimeUnit;
+import javax.sql.DataSource;
+import java.util.Optional;
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.Executors;
+import java.util.stream.Stream;
 
 import static org.junit.jupiter.api.Assertions.assertDoesNotThrow;
-import static org.junit.jupiter.api.Assertions.assertTrue;
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.Mockito.doAnswer;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.mockStatic;
+import static org.mockito.Mockito.times;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.verifyNoInteractions;
+import static org.mockito.Mockito.when;
+import static org.mockito.Mockito.withSettings;
 
 class DataSourcePoolDestroyerTest {
     
     @Test
     void assertAsyncDestroyWithoutAutoCloseableDataSource() {
-        assertDoesNotThrow(() -> new DataSourcePoolDestroyer(new MockedDataSource()).asyncDestroy());
+        DataSource dataSource = mock(DataSource.class);
+        assertDoesNotThrow(() -> new DataSourcePoolDestroyer(dataSource).asyncDestroy());
+        verifyNoInteractions(dataSource);
     }
     
     @Test
-    void assertAsyncDestroyWithAutoCloseableDataSource() throws SQLException {
-        MockedDataSource dataSource = new MockedDataSource();
-        try (Connection ignored = dataSource.getConnection()) {
+    void assertAsyncDestroyWithAutoCloseableDataSourceWithoutActiveDetector() throws Exception {
+        DataSource dataSource = mock(DataSource.class, withSettings().extraInterfaces(AutoCloseable.class));
+        AutoCloseable closeable = (AutoCloseable) dataSource;
+        ExecutorService executor = mockSynchronousExecutor();
+        try (
+                MockedStatic<Executors> mockedExecutors = mockStatic(Executors.class);
+                MockedStatic<TypedSPILoader> typedSPILoader = mockStatic(TypedSPILoader.class)) {
+            mockedExecutors.when(Executors::newSingleThreadExecutor).thenReturn(executor);
+            typedSPILoader.when(() -> TypedSPILoader.findService(DataSourcePoolActiveDetector.class, dataSource.getClass().getName())).thenReturn(Optional.empty());
             new DataSourcePoolDestroyer(dataSource).asyncDestroy();
+            verify(executor).execute(any(Runnable.class));
+            verify(executor).shutdown();
+            verify(closeable).close();
         }
-        Awaitility.await().atMost(1L, TimeUnit.SECONDS).pollInterval(10L, TimeUnit.MILLISECONDS).until(dataSource::isClosed);
-        assertTrue(dataSource.isClosed());
+    }
+    
+    @ParameterizedTest(name = "{0}")
+    @MethodSource("asyncDestroyWithActiveDetectorArguments")
+    void assertAsyncDestroyWithActiveDetector(final String name, final boolean interruptedBeforeDestroy, final int expectedContainsActiveConnectionCount) throws Exception {
+        DataSource dataSource = mock(DataSource.class, withSettings().extraInterfaces(AutoCloseable.class));
+        AutoCloseable closeable = (AutoCloseable) dataSource;
+        DataSourcePoolActiveDetector activeDetector = mock(DataSourcePoolActiveDetector.class);
+        ExecutorService executor = mockSynchronousExecutor();
+        if (1 == expectedContainsActiveConnectionCount) {
+            when(activeDetector.containsActiveConnection(dataSource)).thenReturn(false);
+        } else {
+            when(activeDetector.containsActiveConnection(dataSource)).thenReturn(true, false);
+        }
+        try {
+            if (interruptedBeforeDestroy) {
+                Thread.currentThread().interrupt();
+            }
+            try (
+                    MockedStatic<Executors> mockedExecutors = mockStatic(Executors.class);
+                    MockedStatic<TypedSPILoader> typedSPILoader = mockStatic(TypedSPILoader.class)) {
+                mockedExecutors.when(Executors::newSingleThreadExecutor).thenReturn(executor);
+                typedSPILoader.when(() -> TypedSPILoader.findService(DataSourcePoolActiveDetector.class, dataSource.getClass().getName())).thenReturn(Optional.of(activeDetector));
+                new DataSourcePoolDestroyer(dataSource).asyncDestroy();
+            }
+            verify(executor).execute(any(Runnable.class));
+            verify(executor).shutdown();
+            verify(activeDetector, times(expectedContainsActiveConnectionCount)).containsActiveConnection(dataSource);
+            verify(closeable).close();
+            MatcherAssert.assertThat(Thread.currentThread().isInterrupted(), CoreMatchers.is(interruptedBeforeDestroy));
+        } finally {
+            Thread.interrupted();
+        }
+    }
+    
+    private static ExecutorService mockSynchronousExecutor() {
+        ExecutorService result = mock(ExecutorService.class);
+        doAnswer(invocation -> {
+            invocation.getArgument(0, Runnable.class).run();
+            return null;
+        }).when(result).execute(any(Runnable.class));
+        return result;
+    }
+    
+    private static Stream<Arguments> asyncDestroyWithActiveDetectorArguments() {
+        return Stream.of(
+                Arguments.of("with inactive connection detector", false, 1),
+                Arguments.of("with active connection detector", false, 2),
+                Arguments.of("with interrupted waiting thread", true, 2));
     }
 }