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);

Reply via email to