This is an automated email from the ASF dual-hosted git repository.
xxubai pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/amoro.git
The following commit(s) were added to refs/heads/master by this push:
new 13364ef2f fix(ams): reject non-positive optimizer parallelism (#4398)
13364ef2f is described below
commit 13364ef2f2aab6e2b897ce848bdaeca0ee5b0de4
Author: Sivakumar Mahalingam
<[email protected]>
AuthorDate: Thu Oct 8 09:36:52 2026 +0300
fix(ams): reject non-positive optimizer parallelism (#4398)
Co-authored-by: Xu Bai <[email protected]>
---
.../dashboard/controller/OptimizerController.java | 4 ++
.../controller/OptimizerGroupController.java | 4 ++
.../amoro/server/TestOptimizerController.java | 65 ++++++++++++++++++++++
.../amoro/server/TestOptimizerGroupController.java | 19 +++++++
4 files changed, 92 insertions(+)
diff --git
a/amoro-ams/src/main/java/org/apache/amoro/server/dashboard/controller/OptimizerController.java
b/amoro-ams/src/main/java/org/apache/amoro/server/dashboard/controller/OptimizerController.java
index 071f7c58b..4476fe175 100644
---
a/amoro-ams/src/main/java/org/apache/amoro/server/dashboard/controller/OptimizerController.java
+++
b/amoro-ams/src/main/java/org/apache/amoro/server/dashboard/controller/OptimizerController.java
@@ -18,6 +18,7 @@
package org.apache.amoro.server.dashboard.controller;
+import io.javalin.http.BadRequestResponse;
import io.javalin.http.Context;
import org.apache.amoro.resource.Resource;
import org.apache.amoro.resource.ResourceContainer;
@@ -78,6 +79,9 @@ public class OptimizerController {
public void createOptimizer(Context ctx) {
Map<String, Object> map = ctx.bodyAsClass(Map.class);
int parallelism = Integer.parseInt(map.get("parallelism").toString());
+ if (parallelism <= 0) {
+ throw new BadRequestResponse("Parallelism must be greater than 0.");
+ }
String optimizerGroup = map.get("optimizerGroup").toString();
ResourceGroup resourceGroup =
optimizerManager.getResourceGroup(optimizerGroup);
Resource resource =
diff --git
a/amoro-ams/src/main/java/org/apache/amoro/server/dashboard/controller/OptimizerGroupController.java
b/amoro-ams/src/main/java/org/apache/amoro/server/dashboard/controller/OptimizerGroupController.java
index 586891d27..4e005f86c 100644
---
a/amoro-ams/src/main/java/org/apache/amoro/server/dashboard/controller/OptimizerGroupController.java
+++
b/amoro-ams/src/main/java/org/apache/amoro/server/dashboard/controller/OptimizerGroupController.java
@@ -18,6 +18,7 @@
package org.apache.amoro.server.dashboard.controller;
+import io.javalin.http.BadRequestResponse;
import io.javalin.http.Context;
import org.apache.amoro.resource.Resource;
import org.apache.amoro.resource.ResourceContainer;
@@ -208,6 +209,9 @@ public class OptimizerGroupController {
String optimizerGroup = ctx.pathParam("optimizerGroup");
Map<String, Integer> map = ctx.bodyAsClass(Map.class);
int parallelism = map.get("parallelism");
+ if (parallelism <= 0) {
+ throw new BadRequestResponse("Parallelism must be greater than 0.");
+ }
ResourceGroup resourceGroup =
optimizerManager.getResourceGroup(optimizerGroup);
Resource resource =
diff --git
a/amoro-ams/src/test/java/org/apache/amoro/server/TestOptimizerController.java
b/amoro-ams/src/test/java/org/apache/amoro/server/TestOptimizerController.java
new file mode 100644
index 000000000..81f9a504c
--- /dev/null
+++
b/amoro-ams/src/test/java/org/apache/amoro/server/TestOptimizerController.java
@@ -0,0 +1,65 @@
+/*
+ * 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.amoro.server;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertThrows;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.verifyNoInteractions;
+import static org.mockito.Mockito.when;
+
+import io.javalin.http.BadRequestResponse;
+import io.javalin.http.Context;
+import org.apache.amoro.server.dashboard.controller.OptimizerController;
+import org.apache.amoro.server.resource.OptimizerManager;
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.params.ParameterizedTest;
+import org.junit.jupiter.params.provider.ValueSource;
+
+import java.util.HashMap;
+import java.util.Map;
+
+public class TestOptimizerController {
+
+ private OptimizerManager optimizerManager;
+ private OptimizerController controller;
+ private Context ctx;
+
+ @BeforeEach
+ void setUp() {
+ optimizerManager = mock(OptimizerManager.class);
+ controller = new OptimizerController(optimizerManager);
+ ctx = mock(Context.class);
+ }
+
+ @ParameterizedTest
+ @ValueSource(ints = {0, -1})
+ void createOptimizerWithInvalidParallelism(int parallelism) {
+ Map<String, Object> requestBody = new HashMap<>();
+ requestBody.put("parallelism", parallelism);
+ requestBody.put("optimizerGroup", "group1");
+
+ when(ctx.bodyAsClass(Map.class)).thenReturn(requestBody);
+
+ BadRequestResponse exception =
+ assertThrows(BadRequestResponse.class, () ->
controller.createOptimizer(ctx));
+ assertEquals(400, exception.getStatus());
+ verifyNoInteractions(optimizerManager);
+ }
+}
diff --git
a/amoro-ams/src/test/java/org/apache/amoro/server/TestOptimizerGroupController.java
b/amoro-ams/src/test/java/org/apache/amoro/server/TestOptimizerGroupController.java
index a4dfa4290..7fddb1ea2 100644
---
a/amoro-ams/src/test/java/org/apache/amoro/server/TestOptimizerGroupController.java
+++
b/amoro-ams/src/test/java/org/apache/amoro/server/TestOptimizerGroupController.java
@@ -18,12 +18,15 @@
package org.apache.amoro.server;
+import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertThrows;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.verifyNoInteractions;
import static org.mockito.Mockito.when;
+import io.javalin.http.BadRequestResponse;
import io.javalin.http.Context;
import org.apache.amoro.OptimizerProperties;
import org.apache.amoro.resource.ResourceGroup;
@@ -34,6 +37,7 @@ import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.MethodSource;
+import org.junit.jupiter.params.provider.ValueSource;
import javax.ws.rs.BadRequestException;
@@ -83,6 +87,21 @@ public class TestOptimizerGroupController {
assertThrows(BadRequestException.class, () ->
controller.createResourceGroup(ctx));
}
+ @ParameterizedTest
+ @ValueSource(ints = {0, -1})
+ void scaleOutOptimizerWithInvalidParallelism(int parallelism) {
+ Map<String, Integer> requestBody = new HashMap<>();
+ requestBody.put("parallelism", parallelism);
+
+ when(ctx.pathParam("optimizerGroup")).thenReturn("group1");
+ when(ctx.bodyAsClass(Map.class)).thenReturn(requestBody);
+
+ BadRequestResponse exception =
+ assertThrows(BadRequestResponse.class, () ->
controller.scaleOutOptimizer(ctx));
+ assertEquals(400, exception.getStatus());
+ verifyNoInteractions(optimizerManager);
+ }
+
private Map<String, Object> groupRequest(String name, Map<String, String>
properties) {
Map<String, Object> requestBody = new HashMap<>();
requestBody.put("name", name);