From 036f6bc836442a35e5f1cab47345e3209e04d085 Mon Sep 17 00:00:00 2001
From: Ashish Singh <ssashish@amazon.com>
Date: Sat, 21 Sep 2024 09:43:27 +0530
Subject: [PATCH] Add disallow settings update during repository in use ITs
 (#16001)

Signed-off-by: Ashish Singh <ssashish@amazon.com>
---
 .../snapshots/ConcurrentSnapshotsIT.java      | 55 +++++++++++++++++++
 .../AbstractSnapshotIntegTestCase.java        | 10 ++++
 2 files changed, 65 insertions(+)

diff --git a/server/src/internalClusterTest/java/org/opensearch/snapshots/ConcurrentSnapshotsIT.java b/server/src/internalClusterTest/java/org/opensearch/snapshots/ConcurrentSnapshotsIT.java
index 15e92f6f7204b..26f8ab5dd8d09 100644
--- a/server/src/internalClusterTest/java/org/opensearch/snapshots/ConcurrentSnapshotsIT.java
+++ b/server/src/internalClusterTest/java/org/opensearch/snapshots/ConcurrentSnapshotsIT.java
@@ -50,6 +50,7 @@
 import org.opensearch.common.util.concurrent.UncategorizedExecutionException;
 import org.opensearch.core.action.ActionListener;
 import org.opensearch.core.common.Strings;
+import org.opensearch.core.rest.RestStatus;
 import org.opensearch.discovery.AbstractDisruptionTestCase;
 import org.opensearch.plugins.Plugin;
 import org.opensearch.repositories.RepositoryData;
@@ -135,6 +136,60 @@ public void testLongRunningSnapshotAllowsConcurrentSnapshot() throws Exception {
         assertSuccessful(createSlowFuture);
     }
 
+    public void testSettingsUpdateFailWhenCreateSnapshotInProgress() throws Exception {
+        // Start a cluster with a cluster manager node and a data node
+        internalCluster().startClusterManagerOnlyNode();
+        final String dataNode = internalCluster().startDataOnlyNode();
+        final String repoName = "test-repo";
+        // Create a repository with random settings
+        Settings.Builder settings = randomRepositorySettings();
+        createRepository(repoName, "mock", settings);
+        createIndexWithContent("index");
+        // Start a full snapshot and block it on the data node
+        final ActionFuture<CreateSnapshotResponse> createSlowFuture = startFullSnapshotBlockedOnDataNode(
+            "slow-snapshot",
+            repoName,
+            dataNode
+        );
+        Thread.sleep(1000); // Wait for the snapshot to start
+        assertFalse(createSlowFuture.isDone()); // Ensure the snapshot is still in progress
+        // Attempt to update the repository settings while the snapshot is in progress
+        IllegalStateException ex = assertThrows(IllegalStateException.class, () -> updateRepository(repoName, "mock", settings));
+        // Verify that the update fails with an appropriate exception
+        assertEquals("trying to modify or unregister repository that is currently used", ex.getMessage());
+        unblockNode(repoName, dataNode); // Unblock the snapshot
+        assertSuccessful(createSlowFuture); // Ensure the snapshot completes successfully
+    }
+
+    public void testSettingsUpdateFailWhenDeleteSnapshotInProgress() throws InterruptedException {
+        // Start a cluster with a cluster manager node and a data node
+        String clusterManagerName = internalCluster().startClusterManagerOnlyNode();
+        internalCluster().startDataOnlyNode();
+        final String repoName = "test-repo";
+        // Create a repository with random settings
+        Settings.Builder settings = randomRepositorySettings();
+        createRepository(repoName, "mock", settings);
+        createIndexWithContent("index");
+        final String snapshotName = "snapshot-1";
+        // Create a full snapshot
+        SnapshotInfo snapshotInfo = createFullSnapshot(repoName, snapshotName);
+        assertEquals(SnapshotState.SUCCESS, snapshotInfo.state()); // Ensure the snapshot was successful
+        assertEquals(RestStatus.OK, snapshotInfo.status()); // Ensure the snapshot status is OK
+        // Start deleting the snapshot and block it on the cluster manager node
+        ActionFuture<AcknowledgedResponse> future = deleteSnapshotBlockedOnClusterManager(repoName, snapshotName);
+        Thread.sleep(1000); // Wait for the delete operation to start
+        assertFalse(future.isDone()); // Ensure the delete operation is still in progress
+        // Attempt to update the repository settings while the delete operation is in progress
+        IllegalStateException ex = assertThrows(
+            IllegalStateException.class,
+            () -> updateRepository(repoName, "mock", randomRepositorySettings())
+        );
+        // Verify that the update fails with an appropriate exception
+        assertEquals("trying to modify or unregister repository that is currently used", ex.getMessage());
+        unblockNode(repoName, clusterManagerName); // Unblock the delete operation
+        assertAcked(future.actionGet()); // Wait for the delete operation to complete
+    }
+
     public void testDeletesAreBatched() throws Exception {
         internalCluster().startClusterManagerOnlyNode();
         final String dataNode = internalCluster().startDataOnlyNode();
diff --git a/test/framework/src/main/java/org/opensearch/snapshots/AbstractSnapshotIntegTestCase.java b/test/framework/src/main/java/org/opensearch/snapshots/AbstractSnapshotIntegTestCase.java
index a8bb10fe20752..0bfa70a771f65 100644
--- a/test/framework/src/main/java/org/opensearch/snapshots/AbstractSnapshotIntegTestCase.java
+++ b/test/framework/src/main/java/org/opensearch/snapshots/AbstractSnapshotIntegTestCase.java
@@ -665,6 +665,16 @@ public void onTimeout(TimeValue timeout) {
         }
     }
 
+    protected ActionFuture<AcknowledgedResponse> deleteSnapshotBlockedOnClusterManager(String repoName, String snapshotName) {
+        blockClusterManagerFromDeletingIndexNFile(repoName);
+        return deleteSnapshot(repoName, snapshotName);
+    }
+
+    protected ActionFuture<AcknowledgedResponse> deleteSnapshot(String repoName, String snapshotName) {
+        logger.info("--> Deleting snapshot [{}] to repo [{}]", snapshotName, repoName);
+        return clusterAdmin().prepareDeleteSnapshot(repoName, snapshotName).execute();
+    }
+
     protected ActionFuture<CreateSnapshotResponse> startFullSnapshotBlockedOnDataNode(String snapshotName, String repoName, String dataNode)
         throws InterruptedException {
         blockDataNode(repoName, dataNode);