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

gerlowskija pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/solr.git


The following commit(s) were added to refs/heads/main by this push:
     new 8a88b745b4e SOLR-16397: Create v2 (JAX-RS) endpoint for unload-core 
(#1933)
8a88b745b4e is described below

commit 8a88b745b4eda9b8840f45a0dea714b3c295a14f
Author: Sanjay Dutt <[email protected]>
AuthorDate: Sun Oct 8 23:48:15 2023 +0530

    SOLR-16397: Create v2 (JAX-RS) endpoint for unload-core (#1933)
    
    No v2 equivalent existed prior to this commit.  The new V2 API is
    `POST /api/cores/cName/unload {...}`.
    
    ---------
    
    Co-authored-by: iamsanjay <[email protected]>
    Co-authored-by: Jason Gerlowski <[email protected]>
---
 solr/CHANGES.txt                                   |  3 +
 .../solr/client/api/endpoint/UnloadCoreApi.java    | 39 ++++++++++
 .../client/api/model/UnloadCoreRequestBody.java    | 40 ++++++++++
 .../src/java/org/apache/solr/api/V2HttpCall.java   |  4 +
 .../solr/handler/admin/CoreAdminHandler.java       |  6 +-
 .../solr/handler/admin/CoreAdminOperation.java     | 21 ++++--
 .../apache/solr/handler/admin/api/UnloadCore.java  | 79 ++++++++++++++++++++
 .../solr/handler/admin/api/UnloadCoreAPI.java      | 76 -------------------
 .../solr/handler/admin/TestCoreAdminApis.java      |  6 --
 .../solr/handler/admin/api/UnloadCoreAPITest.java  | 86 ++++++++++++++++++++++
 .../handler/admin/api/V2CoreAPIMappingTest.java    | 25 -------
 .../configuration-guide/pages/coreadmin-api.adoc   | 26 ++++++-
 12 files changed, 292 insertions(+), 119 deletions(-)

diff --git a/solr/CHANGES.txt b/solr/CHANGES.txt
index 0e6ec525018..ae63ebfd9ed 100644
--- a/solr/CHANGES.txt
+++ b/solr/CHANGES.txt
@@ -455,6 +455,9 @@ Improvements
 * SOLR-16397: Reload core v2 endpoints have been updated to be more REST-ful.
   RELOAD is now available at `POST /api/cores/coreName/reload` (Sanjay Dutt 
via Jason Gerlowski)
 
+* SOLR-16397: Unload core v2 endpoints have been updated to be more REST-ful.
+  UNLOAD is now available at `POST /api/cores/coreName/unload` (Sanjay Dutt 
via Jason Gerlowski)
+
 Optimizations
 ---------------------
 
diff --git 
a/solr/api/src/java/org/apache/solr/client/api/endpoint/UnloadCoreApi.java 
b/solr/api/src/java/org/apache/solr/client/api/endpoint/UnloadCoreApi.java
new file mode 100644
index 00000000000..c8239ac3d84
--- /dev/null
+++ b/solr/api/src/java/org/apache/solr/client/api/endpoint/UnloadCoreApi.java
@@ -0,0 +1,39 @@
+/*
+ * 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.solr.client.api.endpoint;
+
+import io.swagger.v3.oas.annotations.Operation;
+import io.swagger.v3.oas.annotations.parameters.RequestBody;
+import javax.ws.rs.POST;
+import javax.ws.rs.Path;
+import javax.ws.rs.PathParam;
+import org.apache.solr.client.api.model.SolrJerseyResponse;
+import org.apache.solr.client.api.model.UnloadCoreRequestBody;
+
+/** V2 API definition for unloading a Solr core. */
+@Path("/cores/{coreName}/unload")
+public interface UnloadCoreApi {
+  @POST
+  @Operation(
+      summary = "Unloads a single core specified by name",
+      tags = {"cores"})
+  SolrJerseyResponse unloadCore(
+      @PathParam("coreName") String coreName,
+      @RequestBody(description = "Additional properties related to the core 
unloading")
+          UnloadCoreRequestBody requestBody)
+      throws Exception;
+}
diff --git 
a/solr/api/src/java/org/apache/solr/client/api/model/UnloadCoreRequestBody.java 
b/solr/api/src/java/org/apache/solr/client/api/model/UnloadCoreRequestBody.java
new file mode 100644
index 00000000000..de290c51827
--- /dev/null
+++ 
b/solr/api/src/java/org/apache/solr/client/api/model/UnloadCoreRequestBody.java
@@ -0,0 +1,40 @@
+/*
+ * 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.solr.client.api.model;
+
+import com.fasterxml.jackson.annotation.JsonProperty;
+import io.swagger.v3.oas.annotations.media.Schema;
+
+public class UnloadCoreRequestBody {
+  @Schema(description = "If true, will remove the index when unloading the 
core.")
+  @JsonProperty
+  public Boolean deleteIndex;
+
+  @Schema(description = "If true, removes the data directory and all 
sub-directories.")
+  @JsonProperty
+  public Boolean deleteDataDir;
+
+  @Schema(
+      description =
+          "If true, removes everything related to the core, including the 
index directory, configuration files and other related files.")
+  @JsonProperty
+  public Boolean deleteInstanceDir;
+
+  @Schema(description = "Request ID to track this action which will be 
processed asynchronously.")
+  @JsonProperty
+  public String async;
+}
diff --git a/solr/core/src/java/org/apache/solr/api/V2HttpCall.java 
b/solr/core/src/java/org/apache/solr/api/V2HttpCall.java
index a57b286a9a3..4f17f3ea800 100644
--- a/solr/core/src/java/org/apache/solr/api/V2HttpCall.java
+++ b/solr/core/src/java/org/apache/solr/api/V2HttpCall.java
@@ -471,6 +471,10 @@ public class V2HttpCall extends HttpSolrCall {
               rsp,
               suppressNotFoundProp);
       if (!resourceFound) {
+        // Whatever this API call is, it's not a core-level request so make 
sure we free our
+        // SolrCore counter
+        core.close();
+        core = null;
         response.getHeaderNames().stream().forEach(name -> 
response.setHeader(name, null));
         invokeJerseyRequest(
             cores, null, cores.getJerseyApplicationHandler(), 
cores.getRequestHandlers(), rsp);
diff --git 
a/solr/core/src/java/org/apache/solr/handler/admin/CoreAdminHandler.java 
b/solr/core/src/java/org/apache/solr/handler/admin/CoreAdminHandler.java
index 25af745db5b..c0759543da9 100644
--- a/solr/core/src/java/org/apache/solr/handler/admin/CoreAdminHandler.java
+++ b/solr/core/src/java/org/apache/solr/handler/admin/CoreAdminHandler.java
@@ -74,7 +74,7 @@ import org.apache.solr.handler.admin.api.RestoreCore;
 import org.apache.solr.handler.admin.api.SingleCoreStatusAPI;
 import org.apache.solr.handler.admin.api.SplitCoreAPI;
 import org.apache.solr.handler.admin.api.SwapCoresAPI;
-import org.apache.solr.handler.admin.api.UnloadCoreAPI;
+import org.apache.solr.handler.admin.api.UnloadCore;
 import org.apache.solr.logging.MDCLoggingContext;
 import org.apache.solr.metrics.SolrMetricManager;
 import org.apache.solr.metrics.SolrMetricsContext;
@@ -385,7 +385,6 @@ public class CoreAdminHandler extends RequestHandlerBase 
implements PermissionNa
     apis.addAll(AnnotatedApi.getApis(new OverseerOperationAPI(this)));
     apis.addAll(AnnotatedApi.getApis(new SwapCoresAPI(this)));
     apis.addAll(AnnotatedApi.getApis(new RenameCoreAPI(this)));
-    apis.addAll(AnnotatedApi.getApis(new UnloadCoreAPI(this)));
     apis.addAll(AnnotatedApi.getApis(new MergeIndexesAPI(this)));
     apis.addAll(AnnotatedApi.getApis(new SplitCoreAPI(this)));
     apis.addAll(AnnotatedApi.getApis(new RequestCoreCommandStatusAPI(this)));
@@ -406,7 +405,8 @@ public class CoreAdminHandler extends RequestHandlerBase 
implements PermissionNa
         InstallCoreData.class,
         BackupCoreAPI.class,
         RestoreCore.class,
-        ReloadCore.class);
+        ReloadCore.class,
+        UnloadCore.class);
   }
 
   public interface CoreAdminOp {
diff --git 
a/solr/core/src/java/org/apache/solr/handler/admin/CoreAdminOperation.java 
b/solr/core/src/java/org/apache/solr/handler/admin/CoreAdminOperation.java
index 5c95a20a36f..c1580cdc5bb 100644
--- a/solr/core/src/java/org/apache/solr/handler/admin/CoreAdminOperation.java
+++ b/solr/core/src/java/org/apache/solr/handler/admin/CoreAdminOperation.java
@@ -61,6 +61,7 @@ import java.util.Map;
 import org.apache.solr.client.api.model.ListCoreSnapshotsResponse;
 import org.apache.solr.client.api.model.ReloadCoreRequestBody;
 import org.apache.solr.client.api.model.SolrJerseyResponse;
+import org.apache.solr.client.api.model.UnloadCoreRequestBody;
 import org.apache.solr.cloud.ZkController;
 import org.apache.solr.common.SolrException;
 import org.apache.solr.common.SolrException.ErrorCode;
@@ -76,6 +77,7 @@ import org.apache.solr.core.SolrCore;
 import org.apache.solr.handler.admin.CoreAdminHandler.CoreAdminOp;
 import org.apache.solr.handler.admin.api.CoreSnapshot;
 import org.apache.solr.handler.admin.api.ReloadCore;
+import org.apache.solr.handler.admin.api.UnloadCore;
 import org.apache.solr.handler.api.V2ApiUtils;
 import org.apache.solr.search.SolrIndexSearcher;
 import org.apache.solr.update.UpdateLog;
@@ -122,14 +124,17 @@ public enum CoreAdminOperation implements CoreAdminOp {
       it -> {
         SolrParams params = it.req.getParams();
         String cname = params.required().get(CoreAdminParams.CORE);
-
-        boolean deleteIndexDir = params.getBool(CoreAdminParams.DELETE_INDEX, 
false);
-        boolean deleteDataDir = 
params.getBool(CoreAdminParams.DELETE_DATA_DIR, false);
-        boolean deleteInstanceDir = 
params.getBool(CoreAdminParams.DELETE_INSTANCE_DIR, false);
-        CoreDescriptor cdescr = 
it.handler.coreContainer.getCoreDescriptor(cname);
-        it.handler.coreContainer.unload(cname, deleteIndexDir, deleteDataDir, 
deleteInstanceDir);
-
-        assert TestInjection.injectNonExistentCoreExceptionAfterUnload(cname);
+        final var unloadCoreRequestBody = new UnloadCoreRequestBody();
+        unloadCoreRequestBody.deleteIndex = 
params.getBool(CoreAdminParams.DELETE_INDEX, false);
+        unloadCoreRequestBody.deleteDataDir =
+            params.getBool(CoreAdminParams.DELETE_DATA_DIR, false);
+        unloadCoreRequestBody.deleteInstanceDir =
+            params.getBool(CoreAdminParams.DELETE_INSTANCE_DIR, false);
+        UnloadCore unloadCoreAPI =
+            new UnloadCore(
+                it.handler.coreContainer, 
it.handler.getCoreAdminAsyncTracker(), it.req, it.rsp);
+        SolrJerseyResponse response = unloadCoreAPI.unloadCore(cname, 
unloadCoreRequestBody);
+        V2ApiUtils.squashIntoSolrResponseWithoutHeader(it.rsp, response);
       }),
   RELOAD_OP(
       RELOAD,
diff --git 
a/solr/core/src/java/org/apache/solr/handler/admin/api/UnloadCore.java 
b/solr/core/src/java/org/apache/solr/handler/admin/api/UnloadCore.java
new file mode 100644
index 00000000000..63fd49a21d3
--- /dev/null
+++ b/solr/core/src/java/org/apache/solr/handler/admin/api/UnloadCore.java
@@ -0,0 +1,79 @@
+/*
+ * 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.solr.handler.admin.api;
+
+import static 
org.apache.solr.security.PermissionNameProvider.Name.CORE_EDIT_PERM;
+
+import javax.inject.Inject;
+import org.apache.solr.client.api.endpoint.UnloadCoreApi;
+import org.apache.solr.client.api.model.SolrJerseyResponse;
+import org.apache.solr.client.api.model.UnloadCoreRequestBody;
+import org.apache.solr.core.CoreContainer;
+import org.apache.solr.core.CoreDescriptor;
+import org.apache.solr.handler.admin.CoreAdminHandler;
+import org.apache.solr.jersey.PermissionName;
+import org.apache.solr.request.SolrQueryRequest;
+import org.apache.solr.response.SolrQueryResponse;
+import org.apache.solr.util.TestInjection;
+
+/**
+ * V2 API implementation for unloading a Solr core.
+ *
+ * <p>The API (POST /v2/cores/coreName/unload is equivalent to the v1 
/admin/cores?action=unload
+ * command.
+ */
+public class UnloadCore extends CoreAdminAPIBase implements UnloadCoreApi {
+
+  @Inject
+  public UnloadCore(
+      CoreContainer coreContainer,
+      CoreAdminHandler.CoreAdminAsyncTracker coreAdminAsyncTracker,
+      SolrQueryRequest solrQueryRequest,
+      SolrQueryResponse solrQueryResponse) {
+    super(coreContainer, coreAdminAsyncTracker, solrQueryRequest, 
solrQueryResponse);
+  }
+
+  @PermissionName(CORE_EDIT_PERM)
+  @Override
+  public SolrJerseyResponse unloadCore(String coreName, UnloadCoreRequestBody 
requestBody)
+      throws Exception {
+    ensureRequiredParameterProvided("coreName", coreName);
+    SolrJerseyResponse solrJerseyResponse = 
instantiateJerseyResponse(SolrJerseyResponse.class);
+    if (requestBody == null) {
+      requestBody = new UnloadCoreRequestBody();
+    }
+    final var requestBodyFinal = requestBody; // Lambda below requires a 
'final' variable
+    return handlePotentiallyAsynchronousTask(
+        solrJerseyResponse,
+        coreName,
+        requestBody.async,
+        "unload",
+        () -> {
+          CoreDescriptor cdescr = coreContainer.getCoreDescriptor(coreName);
+          coreContainer.unload(
+              coreName,
+              requestBodyFinal.deleteIndex == null ? false : 
requestBodyFinal.deleteIndex,
+              requestBodyFinal.deleteDataDir == null ? false : 
requestBodyFinal.deleteDataDir,
+              requestBodyFinal.deleteInstanceDir == null
+                  ? false
+                  : requestBodyFinal.deleteInstanceDir);
+          assert 
TestInjection.injectNonExistentCoreExceptionAfterUnload(coreName);
+          return solrJerseyResponse;
+        });
+  }
+}
diff --git 
a/solr/core/src/java/org/apache/solr/handler/admin/api/UnloadCoreAPI.java 
b/solr/core/src/java/org/apache/solr/handler/admin/api/UnloadCoreAPI.java
deleted file mode 100644
index 0fa50a9aa4d..00000000000
--- a/solr/core/src/java/org/apache/solr/handler/admin/api/UnloadCoreAPI.java
+++ /dev/null
@@ -1,76 +0,0 @@
-/*
- * 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.solr.handler.admin.api;
-
-import static org.apache.solr.client.solrj.SolrRequest.METHOD.POST;
-import static org.apache.solr.handler.ClusterAPI.wrapParams;
-import static 
org.apache.solr.security.PermissionNameProvider.Name.CORE_EDIT_PERM;
-
-import java.util.HashMap;
-import java.util.Locale;
-import java.util.Map;
-import org.apache.solr.api.Command;
-import org.apache.solr.api.EndPoint;
-import org.apache.solr.api.PayloadObj;
-import org.apache.solr.common.annotation.JsonProperty;
-import org.apache.solr.common.params.CoreAdminParams;
-import org.apache.solr.common.util.ReflectMapWriter;
-import org.apache.solr.handler.admin.CoreAdminHandler;
-
-/**
- * V2 API for renaming an existing Solr core.
- *
- * <p>The new API (POST /v2/cores/coreName {'unload': {...}}) is equivalent to 
the v1
- * /admin/cores?action=unload command.
- */
-@EndPoint(
-    path = {"/cores/{core}"},
-    method = POST,
-    permission = CORE_EDIT_PERM)
-public class UnloadCoreAPI {
-  private static final String V2_UNLOAD_CORE_CMD = "unload";
-
-  private final CoreAdminHandler coreHandler;
-
-  public UnloadCoreAPI(CoreAdminHandler coreHandler) {
-    this.coreHandler = coreHandler;
-  }
-
-  @Command(name = V2_UNLOAD_CORE_CMD)
-  public void unloadCore(PayloadObj<UnloadCorePayload> obj) throws Exception {
-    final UnloadCorePayload v2Body = obj.get();
-    final Map<String, Object> v1Params = v2Body.toMap(new HashMap<>());
-    v1Params.put(
-        CoreAdminParams.ACTION,
-        
CoreAdminParams.CoreAdminAction.UNLOAD.name().toLowerCase(Locale.ROOT));
-    v1Params.put(
-        CoreAdminParams.CORE, 
obj.getRequest().getPathTemplateValues().get(CoreAdminParams.CORE));
-
-    coreHandler.handleRequestBody(wrapParams(obj.getRequest(), v1Params), 
obj.getResponse());
-  }
-
-  public static class UnloadCorePayload implements ReflectMapWriter {
-    @JsonProperty public Boolean deleteIndex;
-
-    @JsonProperty public Boolean deleteDataDir;
-
-    @JsonProperty public Boolean deleteInstanceDir;
-
-    @JsonProperty public String async;
-  }
-}
diff --git 
a/solr/core/src/test/org/apache/solr/handler/admin/TestCoreAdminApis.java 
b/solr/core/src/test/org/apache/solr/handler/admin/TestCoreAdminApis.java
index 1e3ff94b749..3cf5b06261d 100644
--- a/solr/core/src/test/org/apache/solr/handler/admin/TestCoreAdminApis.java
+++ b/solr/core/src/test/org/apache/solr/handler/admin/TestCoreAdminApis.java
@@ -69,12 +69,6 @@ public class TestCoreAdminApis extends SolrTestCaseJ4 {
     params = calls.get("rename");
     assertEquals("core1", params[0]);
     assertEquals("core2", params[1]);
-
-    TestCollectionAPIs.makeCall(
-        apiBag, "/cores/core1", SolrRequest.METHOD.POST, "{unload:{deleteIndex 
: true}}");
-    params = calls.get("unload");
-    assertEquals("core1", params[0]);
-    assertEquals(Boolean.TRUE, params[1]);
   }
 
   @SuppressWarnings({"unchecked"})
diff --git 
a/solr/core/src/test/org/apache/solr/handler/admin/api/UnloadCoreAPITest.java 
b/solr/core/src/test/org/apache/solr/handler/admin/api/UnloadCoreAPITest.java
new file mode 100644
index 00000000000..d2dcc732b2c
--- /dev/null
+++ 
b/solr/core/src/test/org/apache/solr/handler/admin/api/UnloadCoreAPITest.java
@@ -0,0 +1,86 @@
+/*
+ * 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.solr.handler.admin.api;
+
+import org.apache.solr.SolrTestCaseJ4;
+import org.apache.solr.client.api.model.SolrJerseyResponse;
+import org.apache.solr.client.api.model.UnloadCoreRequestBody;
+import org.apache.solr.common.SolrException;
+import org.apache.solr.core.CoreContainer;
+import org.apache.solr.handler.admin.CoreAdminHandler;
+import org.apache.solr.request.SolrQueryRequest;
+import org.apache.solr.response.SolrQueryResponse;
+import org.junit.AfterClass;
+import org.junit.Before;
+import org.junit.BeforeClass;
+import org.junit.Test;
+
+public class UnloadCoreAPITest extends SolrTestCaseJ4 {
+  private UnloadCore unloadCoreAPI;
+  private static final String NON_EXISTENT_CORE = "non_existent_core";
+
+  @BeforeClass
+  public static void initializeCoreAndRequestFactory() throws Exception {
+    initCore("solrconfig.xml", "schema.xml");
+    lrf = h.getRequestFactory("/api", 0, 10);
+  }
+
+  @Before
+  @Override
+  public void setUp() throws Exception {
+    super.setUp();
+    SolrQueryRequest solrQueryRequest = req();
+    SolrQueryResponse solrQueryResponse = new SolrQueryResponse();
+    CoreContainer coreContainer = h.getCoreContainer();
+    CoreAdminHandler.CoreAdminAsyncTracker coreAdminAsyncTracker =
+        new CoreAdminHandler.CoreAdminAsyncTracker();
+    unloadCoreAPI =
+        new UnloadCore(coreContainer, coreAdminAsyncTracker, solrQueryRequest, 
solrQueryResponse);
+  }
+
+  @Test
+  public void testValidUnloadCoreAPIResponse() throws Exception {
+    SolrJerseyResponse response = unloadCoreAPI.unloadCore(coreName, 
getUnloadCoreRequestBodyObj());
+    assertEquals(0, response.responseHeader.status);
+    assertNotNull(response.responseHeader.qTime);
+  }
+
+  @Test
+  public void testNonExistentCoreExceptionResponse() {
+    final SolrException solrException =
+        expectThrows(
+            SolrException.class,
+            () -> {
+              unloadCoreAPI.unloadCore(NON_EXISTENT_CORE, 
getUnloadCoreRequestBodyObj());
+            });
+    assertEquals(400, solrException.code());
+    assertTrue(solrException.getMessage().contains("Cannot unload non-existent 
core"));
+  }
+
+  @AfterClass // unique core per test
+  public static void coreDestroy() {
+    deleteCore();
+  }
+
+  private UnloadCoreRequestBody getUnloadCoreRequestBodyObj() {
+    UnloadCoreRequestBody unloadCoreRequestBody = new UnloadCoreRequestBody();
+    unloadCoreRequestBody.deleteIndex = false;
+    unloadCoreRequestBody.deleteDataDir = false;
+    unloadCoreRequestBody.deleteInstanceDir = false;
+    return unloadCoreRequestBody;
+  }
+}
diff --git 
a/solr/core/src/test/org/apache/solr/handler/admin/api/V2CoreAPIMappingTest.java
 
b/solr/core/src/test/org/apache/solr/handler/admin/api/V2CoreAPIMappingTest.java
index a2a36af2c4f..ed2ea3079ee 100644
--- 
a/solr/core/src/test/org/apache/solr/handler/admin/api/V2CoreAPIMappingTest.java
+++ 
b/solr/core/src/test/org/apache/solr/handler/admin/api/V2CoreAPIMappingTest.java
@@ -23,9 +23,6 @@ import static 
org.apache.solr.common.params.CommonParams.ACTION;
 import static org.apache.solr.common.params.CommonParams.PATH;
 import static org.apache.solr.common.params.CoreAdminParams.CORE;
 import static org.apache.solr.common.params.CoreAdminParams.CORE_NODE_NAME;
-import static org.apache.solr.common.params.CoreAdminParams.DELETE_DATA_DIR;
-import static org.apache.solr.common.params.CoreAdminParams.DELETE_INDEX;
-import static 
org.apache.solr.common.params.CoreAdminParams.DELETE_INSTANCE_DIR;
 import static org.apache.solr.common.params.CoreAdminParams.NAME;
 import static org.apache.solr.common.params.CoreAdminParams.OTHER;
 import static org.apache.solr.common.params.CoreAdminParams.RANGES;
@@ -69,7 +66,6 @@ public class V2CoreAPIMappingTest extends 
V2ApiMappingTest<CoreAdminHandler> {
     final CoreAdminHandler handler = getRequestHandler();
     apiBag.registerObject(new SwapCoresAPI(handler));
     apiBag.registerObject(new RenameCoreAPI(handler));
-    apiBag.registerObject(new UnloadCoreAPI(handler));
     apiBag.registerObject(new MergeIndexesAPI(handler));
     apiBag.registerObject(new SplitCoreAPI(handler));
     apiBag.registerObject(new RequestCoreRecoveryAPI(handler));
@@ -102,27 +98,6 @@ public class V2CoreAPIMappingTest extends 
V2ApiMappingTest<CoreAdminHandler> {
     assertEquals("otherCore", v1Params.get(OTHER));
   }
 
-  @Test
-  public void testUnloadCoreAllParams() throws Exception {
-    final SolrParams v1Params =
-        captureConvertedV1Params(
-            "/cores/coreName",
-            "POST",
-            "{"
-                + "\"unload\": {"
-                + "\"deleteIndex\": true, "
-                + "\"deleteDataDir\": true, "
-                + "\"deleteInstanceDir\": true, "
-                + "\"async\": \"someRequestId\"}}");
-
-    assertEquals("unload", v1Params.get(ACTION));
-    assertEquals("coreName", v1Params.get(CORE));
-    assertEquals(true, v1Params.getBool(DELETE_INDEX));
-    assertEquals(true, v1Params.getBool(DELETE_DATA_DIR));
-    assertEquals(true, v1Params.getBool(DELETE_INSTANCE_DIR));
-    assertEquals("someRequestId", v1Params.get(ASYNC));
-  }
-
   @Test
   public void testMergeIndexesAllParams() throws Exception {
     final SolrParams v1Params =
diff --git 
a/solr/solr-ref-guide/modules/configuration-guide/pages/coreadmin-api.adoc 
b/solr/solr-ref-guide/modules/configuration-guide/pages/coreadmin-api.adoc
index a62e4288199..aa4cc2f76a8 100644
--- a/solr/solr-ref-guide/modules/configuration-guide/pages/coreadmin-api.adoc
+++ b/solr/solr-ref-guide/modules/configuration-guide/pages/coreadmin-api.adoc
@@ -435,7 +435,31 @@ The `UNLOAD` action removes a core from Solr.
 Active requests will continue to be processed, but no new requests will be 
sent to the named core.
 If a core is registered under more than one name, only the given name is 
removed.
 
-`admin/cores?action=UNLOAD&core=_core-name_`
+[.dynamic-tabs]
+--
+[example.tab-pane#v1coreadmin-unload]
+====
+[.tab-label]*V1 API*
+
+[source,bash]
+----
+http://localhost:8983/solr/admin/cores?actionUNLOAD&core=techproducts
+
+----
+====
+
+[example.tab-pane#v2coreadmin-unload]
+====
+[.tab-label]*V2 API*
+
+[source,bash]
+----
+curl -X POST http://localhost:8983/api/cores/techproducts/unload -H 
'Content-Type: application/json' -d '
+  {}
+'
+----
+====
+--
 
 The `UNLOAD` action requires a parameter (`core`) identifying the core to be 
removed.
 If the persistent attribute of `<solr>` is set to `true`, the `<core>` element 
with this `name` attribute will be removed from `solr.xml`.

Reply via email to