This is an automated email from the ASF dual-hosted git repository.
sumitagrawal pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/ozone.git
The following commit(s) were added to refs/heads/master by this push:
new 20dca25d393 HDDS-13648. Update NSSummary rebuilding implementation to
queue based approach. (#9009)
20dca25d393 is described below
commit 20dca25d393d4257aaff41ed872aca4b4e02d761
Author: Devesh Kumar Singh <[email protected]>
AuthorDate: Tue Sep 9 20:49:19 2025 +0530
HDDS-13648. Update NSSummary rebuilding implementation to queue based
approach. (#9009)
---
.../org/apache/hadoop/ozone/recon/ReconUtils.java | 45 ------
.../recon/spi/ReconNamespaceSummaryManager.java | 3 -
.../spi/impl/ReconNamespaceSummaryManagerImpl.java | 8 --
.../hadoop/ozone/recon/tasks/NSSummaryTask.java | 36 ++++-
.../recon/tasks/NSSummaryTaskDbEventHandler.java | 2 +-
.../upgrade/NSSummaryAggregatedTotalsUpgrade.java | 19 +--
.../recon/api/TestNSSummaryEndpointWithFSO.java | 38 -----
.../recon/tasks/TestNSSummaryUnifiedControl.java | 48 -------
.../TestNSSummaryAggregatedTotalsUpgrade.java | 160 +++++++++++++++++++++
9 files changed, 201 insertions(+), 158 deletions(-)
diff --git
a/hadoop-ozone/recon/src/main/java/org/apache/hadoop/ozone/recon/ReconUtils.java
b/hadoop-ozone/recon/src/main/java/org/apache/hadoop/ozone/recon/ReconUtils.java
index 5a367a8baad..2758dfb34cc 100644
---
a/hadoop-ozone/recon/src/main/java/org/apache/hadoop/ozone/recon/ReconUtils.java
+++
b/hadoop-ozone/recon/src/main/java/org/apache/hadoop/ozone/recon/ReconUtils.java
@@ -49,8 +49,6 @@
import java.util.Set;
import java.util.TimeZone;
import java.util.concurrent.BlockingQueue;
-import java.util.concurrent.ExecutorService;
-import java.util.concurrent.Executors;
import java.util.stream.Collectors;
import javax.ws.rs.core.Response;
import org.apache.commons.io.FileUtils;
@@ -97,15 +95,6 @@ public class ReconUtils {
private static Logger log = LoggerFactory.getLogger(
ReconUtils.class);
- // Use NSSummaryTask's unified rebuild control instead of separate tracking
- private static final ExecutorService NSSUMMARY_REBUILD_EXECUTOR =
- Executors.newSingleThreadExecutor(r -> {
- Thread t = new Thread(r);
- t.setName("RebuildNSSummaryThread");
- t.setDaemon(true); // Optional: allows JVM to exit without waiting
- return t;
- });
-
public ReconUtils() {
}
@@ -119,33 +108,6 @@ public static
org.apache.hadoop.ozone.recon.tasks.NSSummaryTask.RebuildState get
return org.apache.hadoop.ozone.recon.tasks.NSSummaryTask.getRebuildState();
}
- /**
- * Convenience method to trigger asynchronous NSSummary tree rebuild.
- * Uses the unified control mechanism in NSSummaryTask.
- *
- * @param reconNamespaceSummaryManager The namespace summary manager
- * @param omMetadataManager The OM metadata manager
- * @return true if rebuild was triggered successfully, false otherwise
- */
- public static boolean triggerAsyncNSSummaryRebuild(
- ReconNamespaceSummaryManager reconNamespaceSummaryManager,
- ReconOMMetadataManager omMetadataManager) {
-
- // Submit rebuild task to single thread executor for async execution
- NSSUMMARY_REBUILD_EXECUTOR.submit(() -> {
- try {
-
- // This will go through NSSummaryTask's unified control mechanism
- reconNamespaceSummaryManager.rebuildNSSummaryTree(omMetadataManager);
- log.info("Async NSSummary tree rebuild completed successfully.");
- } catch (Exception e) {
- log.error("Async NSSummary tree rebuild failed.", e);
- }
- });
-
- return true;
- }
-
public static File getReconScmDbDir(ConfigurationSource conf) {
return new ReconUtils().getReconDbDir(conf, OZONE_RECON_SCM_DB_DIR);
}
@@ -299,13 +261,6 @@ public static StringBuilder constructFullPathPrefix(long
initialParentId, String
"deletion, returning empty string for path construction.");
throw new ServiceNotReadyException("Service is initializing. Please
try again later.");
}
- if (nsSummary.getParentId() == -1) {
- // Trigger async rebuild using unified control mechanism
- triggerAsyncNSSummaryRebuild(reconNamespaceSummaryManager,
omMetadataManager);
- log.warn(
- "NSSummary tree corruption detected, rebuild triggered. Returning
empty string for path construction.");
- throw new ServiceNotReadyException("Service is initializing. Please
try again later.");
- }
// On the last pass, dir-name will be empty and parent will be zero,
indicating the loop should end.
if (!nsSummary.getDirName().isEmpty()) {
pathSegments.add(nsSummary.getDirName());
diff --git
a/hadoop-ozone/recon/src/main/java/org/apache/hadoop/ozone/recon/spi/ReconNamespaceSummaryManager.java
b/hadoop-ozone/recon/src/main/java/org/apache/hadoop/ozone/recon/spi/ReconNamespaceSummaryManager.java
index e166466cd56..0c59f0921b4 100644
---
a/hadoop-ozone/recon/src/main/java/org/apache/hadoop/ozone/recon/spi/ReconNamespaceSummaryManager.java
+++
b/hadoop-ozone/recon/src/main/java/org/apache/hadoop/ozone/recon/spi/ReconNamespaceSummaryManager.java
@@ -22,7 +22,6 @@
import org.apache.hadoop.hdds.utils.db.BatchOperation;
import org.apache.hadoop.hdds.utils.db.DBStore;
import org.apache.hadoop.hdds.utils.db.RDBBatchOperation;
-import org.apache.hadoop.ozone.om.OMMetadataManager;
import org.apache.hadoop.ozone.recon.api.types.NSSummary;
import org.apache.hadoop.ozone.recon.spi.impl.ReconDBProvider;
@@ -52,6 +51,4 @@ void batchStoreNSSummaries(BatchOperation batch, long
objectId,
void commitBatchOperation(RDBBatchOperation rdbBatchOperation)
throws IOException;
-
- void rebuildNSSummaryTree(OMMetadataManager omMetadataManager);
}
diff --git
a/hadoop-ozone/recon/src/main/java/org/apache/hadoop/ozone/recon/spi/impl/ReconNamespaceSummaryManagerImpl.java
b/hadoop-ozone/recon/src/main/java/org/apache/hadoop/ozone/recon/spi/impl/ReconNamespaceSummaryManagerImpl.java
index 536fce1e8fe..1d0a7a0d617 100644
---
a/hadoop-ozone/recon/src/main/java/org/apache/hadoop/ozone/recon/spi/impl/ReconNamespaceSummaryManagerImpl.java
+++
b/hadoop-ozone/recon/src/main/java/org/apache/hadoop/ozone/recon/spi/impl/ReconNamespaceSummaryManagerImpl.java
@@ -26,7 +26,6 @@
import org.apache.hadoop.hdds.utils.db.DBStore;
import org.apache.hadoop.hdds.utils.db.RDBBatchOperation;
import org.apache.hadoop.hdds.utils.db.Table;
-import org.apache.hadoop.ozone.om.OMMetadataManager;
import org.apache.hadoop.ozone.recon.api.types.NSSummary;
import org.apache.hadoop.ozone.recon.spi.ReconNamespaceSummaryManager;
import org.apache.hadoop.ozone.recon.tasks.NSSummaryTask;
@@ -105,13 +104,6 @@ public void commitBatchOperation(RDBBatchOperation
rdbBatchOperation)
this.namespaceDbStore.commitBatchOperation(rdbBatchOperation);
}
- @Override
- public void rebuildNSSummaryTree(OMMetadataManager omMetadataManager) {
- // This method is called by the unified ReconUtils.triggerNSSummaryRebuild
- // It should only handle the actual rebuild logic without state management
- nsSummaryTask.reprocess(omMetadataManager);
- }
-
public Table getNSSummaryTable() {
return nsSummaryTable;
}
diff --git
a/hadoop-ozone/recon/src/main/java/org/apache/hadoop/ozone/recon/tasks/NSSummaryTask.java
b/hadoop-ozone/recon/src/main/java/org/apache/hadoop/ozone/recon/tasks/NSSummaryTask.java
index 1291a6cc9e7..6b4a5cce0e7 100644
---
a/hadoop-ozone/recon/src/main/java/org/apache/hadoop/ozone/recon/tasks/NSSummaryTask.java
+++
b/hadoop-ozone/recon/src/main/java/org/apache/hadoop/ozone/recon/tasks/NSSummaryTask.java
@@ -205,9 +205,14 @@ public TaskResult reprocess(OMMetadataManager
omMetadataManager) {
LOG.info("NSSummary tree rebuild is already in progress, skipping
duplicate request.");
return buildTaskResult(false);
}
-
+
if (!REBUILD_STATE.compareAndSet(currentState, RebuildState.RUNNING)) {
- LOG.info("Failed to acquire rebuild lock, another thread may have
started rebuild.");
+ // Check if another thread successfully started the rebuild
+ if (REBUILD_STATE.get() == RebuildState.RUNNING) {
+ LOG.info("Rebuild already in progress by another thread, returning
success");
+ return buildTaskResult(true);
+ }
+ LOG.info("Failed to acquire rebuild lock, unknown state");
return buildTaskResult(false);
}
@@ -250,7 +255,7 @@ protected TaskResult executeReprocess(OMMetadataManager
omMetadataManager, long
ThreadFactory threadFactory = new ThreadFactoryBuilder()
.setNameFormat("Recon-NSSummaryTask-%d")
.build();
- ExecutorService executorService = Executors.newFixedThreadPool(2,
+ ExecutorService executorService = Executors.newFixedThreadPool(3,
threadFactory);
boolean success = false;
try {
@@ -263,14 +268,31 @@ protected TaskResult executeReprocess(OMMetadataManager
omMetadataManager, long
}
}
success = true;
-
- } catch (InterruptedException | ExecutionException ex) {
- LOG.error("Error while reprocessing NSSummary table in Recon DB.", ex);
+
+ } catch (InterruptedException ex) {
+ Thread.currentThread().interrupt();
+ LOG.error("NSSummaryTask was interrupted.", ex);
+ REBUILD_STATE.set(RebuildState.FAILED);
+ return buildTaskResult(false);
+ } catch (ExecutionException ex) {
+ LOG.error("Error while reprocessing NSSummary table in Recon DB.",
ex.getCause());
REBUILD_STATE.set(RebuildState.FAILED);
return buildTaskResult(false);
-
} finally {
executorService.shutdown();
+ // Deterministic resource cleanup with timeout
+ try {
+ // get() ensures the work is done. awaitTermination ensures the
workers are also verifiably gone.
+ // It turns an asynchronous shutdown into a synchronous, deterministic
one
+ if (!executorService.awaitTermination(5, TimeUnit.MINUTES)) {
+ LOG.warn("Executor service for NSSummaryTask did not terminate in
the specified time.");
+ executorService.shutdownNow();
+ }
+ } catch (InterruptedException ex) {
+ LOG.error("NSSummaryTask executor service termination was
interrupted.", ex);
+ executorService.shutdownNow();
+ Thread.currentThread().interrupt();
+ }
long endTime = System.nanoTime();
// Convert to milliseconds
diff --git
a/hadoop-ozone/recon/src/main/java/org/apache/hadoop/ozone/recon/tasks/NSSummaryTaskDbEventHandler.java
b/hadoop-ozone/recon/src/main/java/org/apache/hadoop/ozone/recon/tasks/NSSummaryTaskDbEventHandler.java
index a45930f5bb2..5d2f747f940 100644
---
a/hadoop-ozone/recon/src/main/java/org/apache/hadoop/ozone/recon/tasks/NSSummaryTaskDbEventHandler.java
+++
b/hadoop-ozone/recon/src/main/java/org/apache/hadoop/ozone/recon/tasks/NSSummaryTaskDbEventHandler.java
@@ -261,7 +261,7 @@ protected boolean flushAndCommitUpdatedNSToDB(Map<Long,
NSSummary> nsSummaryMap,
try {
updateNSSummariesToDB(nsSummaryMap, objectIdsToBeDeleted);
} catch (IOException e) {
- LOG.error("Unable to write Namespace Summary data in Recon DB.", e);
+ LOG.error("Unable to write Namespace Summary data in Recon DB.
batchSize={}", nsSummaryMap.size(), e);
return false;
} finally {
nsSummaryMap.clear();
diff --git
a/hadoop-ozone/recon/src/main/java/org/apache/hadoop/ozone/recon/upgrade/NSSummaryAggregatedTotalsUpgrade.java
b/hadoop-ozone/recon/src/main/java/org/apache/hadoop/ozone/recon/upgrade/NSSummaryAggregatedTotalsUpgrade.java
index 5f3817a2fd3..af69ea8b88c 100644
---
a/hadoop-ozone/recon/src/main/java/org/apache/hadoop/ozone/recon/upgrade/NSSummaryAggregatedTotalsUpgrade.java
+++
b/hadoop-ozone/recon/src/main/java/org/apache/hadoop/ozone/recon/upgrade/NSSummaryAggregatedTotalsUpgrade.java
@@ -22,9 +22,8 @@
import com.google.inject.Injector;
import javax.sql.DataSource;
import org.apache.hadoop.ozone.recon.ReconGuiceServletContextListener;
-import org.apache.hadoop.ozone.recon.ReconUtils;
-import org.apache.hadoop.ozone.recon.recovery.ReconOMMetadataManager;
-import org.apache.hadoop.ozone.recon.spi.ReconNamespaceSummaryManager;
+import org.apache.hadoop.ozone.recon.tasks.ReconTaskController;
+import org.apache.hadoop.ozone.recon.tasks.ReconTaskReInitializationEvent;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@@ -50,12 +49,16 @@ public void execute(DataSource source) throws Exception {
"Guice injector not initialized. NSSummary rebuild cannot proceed
during upgrade.");
}
- ReconNamespaceSummaryManager nsMgr =
injector.getInstance(ReconNamespaceSummaryManager.class);
- ReconOMMetadataManager omMgr =
injector.getInstance(ReconOMMetadataManager.class);
-
- // Fire and forget: unified control using ReconUtils -> NSSummaryTask
+ ReconTaskController reconTaskController =
injector.getInstance(ReconTaskController.class);
LOG.info("Triggering asynchronous NSSummary tree rebuild for materialized
totals (upgrade action).");
- ReconUtils.triggerAsyncNSSummaryRebuild(nsMgr, omMgr);
+ ReconTaskController.ReInitializationResult result =
reconTaskController.queueReInitializationEvent(
+ ReconTaskReInitializationEvent.ReInitializationReason.MANUAL_TRIGGER);
+ if (result != ReconTaskController.ReInitializationResult.SUCCESS) {
+ LOG.error(
+ "Failed to queue reinitialization event for manual trigger (result:
{}), failing the reinitialization " +
+ "during NSSummaryAggregatedTotalsUpgrade action, will be retried
as part of syncDataFromOM " +
+ "scheduler task.", result);
+ }
}
@Override
diff --git
a/hadoop-ozone/recon/src/test/java/org/apache/hadoop/ozone/recon/api/TestNSSummaryEndpointWithFSO.java
b/hadoop-ozone/recon/src/test/java/org/apache/hadoop/ozone/recon/api/TestNSSummaryEndpointWithFSO.java
index b496f2225d1..227330c83f6 100644
---
a/hadoop-ozone/recon/src/test/java/org/apache/hadoop/ozone/recon/api/TestNSSummaryEndpointWithFSO.java
+++
b/hadoop-ozone/recon/src/test/java/org/apache/hadoop/ozone/recon/api/TestNSSummaryEndpointWithFSO.java
@@ -29,9 +29,7 @@
import static org.junit.jupiter.api.Assertions.assertArrayEquals;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertThrows;
-import static org.mockito.Mockito.anyLong;
import static org.mockito.Mockito.mock;
-import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
import java.io.File;
@@ -88,8 +86,6 @@
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.io.TempDir;
-import org.mockito.ArgumentCaptor;
-import org.slf4j.Logger;
/**
* Test for NSSummary REST APIs with FSO.
@@ -813,40 +809,6 @@ public void
testConstructFullPathWithNegativeParentIdTriggersRebuild() throws IO
ReconUtils.constructFullPath(keyInfo, mockSummaryManager,
mockMetadataManager));
}
- @Test
- public void testLoggingWhenParentIdIsNegative() throws IOException {
- ReconNamespaceSummaryManager mockManager =
- mock(ReconNamespaceSummaryManager.class);
- Logger mockLogger = mock(Logger.class);
- ReconUtils.setLogger(mockLogger);
-
- NSSummary mockSummary = new NSSummary();
- mockSummary.setParentId(-1);
- when(mockManager.getNSSummary(anyLong())).thenReturn(mockSummary);
-
- OmKeyInfo keyInfo = new OmKeyInfo.Builder()
- .setKeyName("testKey")
- .setVolumeName("vol")
- .setBucketName("bucket")
- .setObjectID(1L)
- .setParentObjectID(1L)
- .build();
-
- assertThrows(ServiceNotReadyException.class, () ->
- ReconUtils.constructFullPath(keyInfo, mockManager, null));
-
- // Assert
- ArgumentCaptor<String> logCaptor = ArgumentCaptor.forClass(String.class);
- verify(mockLogger).warn(logCaptor.capture());
- String loggedMessage = logCaptor.getValue();
-
- // Here we can assert the exact message we expect to see in the logs.
- // Since we set parentId = -1, this triggers the corruption detection path
- assertEquals(
- "NSSummary tree corruption detected, rebuild triggered. Returning
empty string " +
- "for path construction.", loggedMessage);
- }
-
/**
* Write directories and keys info into OM DB.
* @throws Exception
diff --git
a/hadoop-ozone/recon/src/test/java/org/apache/hadoop/ozone/recon/tasks/TestNSSummaryUnifiedControl.java
b/hadoop-ozone/recon/src/test/java/org/apache/hadoop/ozone/recon/tasks/TestNSSummaryUnifiedControl.java
index d6016e3d2df..c1d0a49ee99 100644
---
a/hadoop-ozone/recon/src/test/java/org/apache/hadoop/ozone/recon/tasks/TestNSSummaryUnifiedControl.java
+++
b/hadoop-ozone/recon/src/test/java/org/apache/hadoop/ozone/recon/tasks/TestNSSummaryUnifiedControl.java
@@ -434,54 +434,6 @@ void testReconUtilsIntegration() throws Exception {
"State should return to IDLE after completion");
}
- /**
- * Test that ReconUtils async trigger respects unified control.
- */
- @Test
- void testReconUtilsRespectsUnifiedControl() throws Exception {
- CountDownLatch firstRebuildStarted = new CountDownLatch(1);
- CountDownLatch firstRebuildCanFinish = new CountDownLatch(1);
-
- // Setup first rebuild to block
- doAnswer(invocation -> {
- firstRebuildStarted.countDown();
- boolean awaitSuccess = firstRebuildCanFinish.await(5, TimeUnit.SECONDS);
- if (!awaitSuccess) {
- LOG.warn("firstRebuildCanFinish.await() timed out");
- }
- return null;
- }).when(mockNamespaceSummaryManager).clearNSSummaryTable();
-
- // Start first rebuild via NSSummaryTask directly
- CompletableFuture<TaskResult> directRebuild =
CompletableFuture.supplyAsync(() ->
- nsSummaryTask.reprocess(mockOMMetadataManager));
-
- // Wait for first rebuild to start
- assertTrue(firstRebuildStarted.await(5, TimeUnit.SECONDS),
- "First rebuild should start");
- assertEquals(RebuildState.RUNNING, NSSummaryTask.getRebuildState(),
- "State should be RUNNING");
-
- // Try to trigger via ReconUtils - should still respect the running state
- // (The async execution will be queued but the actual rebuild will be
rejected)
- boolean triggered = ReconUtils.triggerAsyncNSSummaryRebuild(
- mockNamespaceSummaryManager, mockReconOMMetadataManager);
- assertTrue(triggered, "ReconUtils should queue the async request");
-
- // State should still be RUNNING from the first rebuild
- assertEquals(RebuildState.RUNNING, NSSummaryTask.getRebuildState(),
- "State should still be RUNNING from first rebuild");
-
- // Complete first rebuild
- firstRebuildCanFinish.countDown();
- TaskResult result = directRebuild.get(5, TimeUnit.SECONDS);
- assertTrue(result.isTaskSuccess(), "First rebuild should succeed");
-
- // Final state should be IDLE
- assertEquals(RebuildState.IDLE, NSSummaryTask.getRebuildState(),
- "Final state should be IDLE");
- }
-
/**
* Test state transitions during exception scenarios.
*/
diff --git
a/hadoop-ozone/recon/src/test/java/org/apache/hadoop/ozone/recon/upgrade/TestNSSummaryAggregatedTotalsUpgrade.java
b/hadoop-ozone/recon/src/test/java/org/apache/hadoop/ozone/recon/upgrade/TestNSSummaryAggregatedTotalsUpgrade.java
new file mode 100644
index 00000000000..87b5d2b2f71
--- /dev/null
+++
b/hadoop-ozone/recon/src/test/java/org/apache/hadoop/ozone/recon/upgrade/TestNSSummaryAggregatedTotalsUpgrade.java
@@ -0,0 +1,160 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.hadoop.ozone.recon.upgrade;
+
+import static org.junit.jupiter.api.Assertions.assertDoesNotThrow;
+import static org.junit.jupiter.api.Assertions.assertThrows;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+import com.google.inject.Injector;
+import javax.sql.DataSource;
+import org.apache.hadoop.ozone.recon.ReconGuiceServletContextListener;
+import org.apache.hadoop.ozone.recon.tasks.ReconTaskController;
+import org.apache.hadoop.ozone.recon.tasks.ReconTaskReInitializationEvent;
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
+import org.mockito.MockedStatic;
+import org.mockito.Mockito;
+
+/**
+ * Test class for NSSummaryAggregatedTotalsUpgrade.
+ */
+public class TestNSSummaryAggregatedTotalsUpgrade {
+
+ private NSSummaryAggregatedTotalsUpgrade upgradeAction;
+ private DataSource mockDataSource;
+ private Injector mockInjector;
+ private ReconTaskController mockReconTaskController;
+
+ @BeforeEach
+ public void setUp() {
+ upgradeAction = new NSSummaryAggregatedTotalsUpgrade();
+ mockDataSource = mock(DataSource.class);
+ mockInjector = mock(Injector.class);
+ mockReconTaskController = mock(ReconTaskController.class);
+ }
+
+ @Test
+ public void testExecuteSuccessfulReinitialization() throws Exception {
+ try (MockedStatic<ReconGuiceServletContextListener> mockedListener =
+ Mockito.mockStatic(ReconGuiceServletContextListener.class)) {
+
+ mockedListener.when(ReconGuiceServletContextListener::getGlobalInjector)
+ .thenReturn(mockInjector);
+
+ when(mockInjector.getInstance(ReconTaskController.class))
+ .thenReturn(mockReconTaskController);
+
+ when(mockReconTaskController.queueReInitializationEvent(
+
ReconTaskReInitializationEvent.ReInitializationReason.MANUAL_TRIGGER))
+ .thenReturn(ReconTaskController.ReInitializationResult.SUCCESS);
+
+ assertDoesNotThrow(() -> upgradeAction.execute(mockDataSource));
+
+ verify(mockInjector).getInstance(ReconTaskController.class);
+ verify(mockReconTaskController).queueReInitializationEvent(
+
ReconTaskReInitializationEvent.ReInitializationReason.MANUAL_TRIGGER);
+ }
+ }
+
+ @Test
+ public void testExecuteFailedReinitializationRetryLater() throws Exception {
+ try (MockedStatic<ReconGuiceServletContextListener> mockedListener =
+ Mockito.mockStatic(ReconGuiceServletContextListener.class)) {
+
+ mockedListener.when(ReconGuiceServletContextListener::getGlobalInjector)
+ .thenReturn(mockInjector);
+
+ when(mockInjector.getInstance(ReconTaskController.class))
+ .thenReturn(mockReconTaskController);
+
+ when(mockReconTaskController.queueReInitializationEvent(
+
ReconTaskReInitializationEvent.ReInitializationReason.MANUAL_TRIGGER))
+ .thenReturn(ReconTaskController.ReInitializationResult.RETRY_LATER);
+
+ assertDoesNotThrow(() -> upgradeAction.execute(mockDataSource));
+
+ verify(mockInjector).getInstance(ReconTaskController.class);
+ verify(mockReconTaskController).queueReInitializationEvent(
+
ReconTaskReInitializationEvent.ReInitializationReason.MANUAL_TRIGGER);
+ }
+ }
+
+ @Test
+ public void testExecuteFailedReinitializationMaxRetriesExceeded() throws
Exception {
+ try (MockedStatic<ReconGuiceServletContextListener> mockedListener =
+ Mockito.mockStatic(ReconGuiceServletContextListener.class)) {
+
+ mockedListener.when(ReconGuiceServletContextListener::getGlobalInjector)
+ .thenReturn(mockInjector);
+
+ when(mockInjector.getInstance(ReconTaskController.class))
+ .thenReturn(mockReconTaskController);
+
+ when(mockReconTaskController.queueReInitializationEvent(
+
ReconTaskReInitializationEvent.ReInitializationReason.MANUAL_TRIGGER))
+
.thenReturn(ReconTaskController.ReInitializationResult.MAX_RETRIES_EXCEEDED);
+
+ assertDoesNotThrow(() -> upgradeAction.execute(mockDataSource));
+
+ verify(mockInjector).getInstance(ReconTaskController.class);
+ verify(mockReconTaskController).queueReInitializationEvent(
+
ReconTaskReInitializationEvent.ReInitializationReason.MANUAL_TRIGGER);
+ }
+ }
+
+ @Test
+ public void testExecuteWithNullInjector() {
+ try (MockedStatic<ReconGuiceServletContextListener> mockedListener =
+ Mockito.mockStatic(ReconGuiceServletContextListener.class)) {
+
+ mockedListener.when(ReconGuiceServletContextListener::getGlobalInjector)
+ .thenReturn(null);
+
+ IllegalStateException exception =
assertThrows(IllegalStateException.class,
+ () -> upgradeAction.execute(mockDataSource));
+
+ assert exception.getMessage().contains(
+ "Guice injector not initialized. NSSummary rebuild cannot proceed
during upgrade.");
+ }
+ }
+
+ @Test
+ public void testExecuteWithInjectorException() throws Exception {
+ try (MockedStatic<ReconGuiceServletContextListener> mockedListener =
+ Mockito.mockStatic(ReconGuiceServletContextListener.class)) {
+
+ mockedListener.when(ReconGuiceServletContextListener::getGlobalInjector)
+ .thenReturn(mockInjector);
+
+ when(mockInjector.getInstance(ReconTaskController.class))
+ .thenThrow(new RuntimeException("Injector failed to provide
instance"));
+
+ assertThrows(RuntimeException.class, () ->
upgradeAction.execute(mockDataSource));
+
+ verify(mockInjector).getInstance(ReconTaskController.class);
+ }
+ }
+
+ @Test
+ public void testGetType() {
+ assert upgradeAction.getType() ==
ReconUpgradeAction.UpgradeActionType.FINALIZE;
+ }
+}
---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]