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

btellier pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/james-project.git

commit de092eab6774da5bae1e731875a91bd0866f16dc
Author: Benoit Tellier <btell...@linagora.com>
AuthorDate: Mon Sep 9 09:30:19 2019 +0700

    JAMES-2813 Enhance Duration parser negative number parsing
    
    This enables a nicer error message upon negative numbers, avoiding hacks
    on the caller side.
---
 .../QuotaMailingListenerConfigurationTest.java        |  3 ++-
 .../java/org/apache/james/util/DurationParser.java    | 19 ++++++++++++++-----
 .../org/apache/james/util/DurationParserTest.java     | 13 +++++++------
 .../transport/mailets/remote/delivery/DelayTest.java  |  8 +++++---
 .../org/apache/james/webadmin/routes/TasksRoutes.java | 19 +++++++++----------
 .../apache/james/webadmin/routes/TasksRoutesTest.java |  7 ++++---
 6 files changed, 41 insertions(+), 28 deletions(-)

diff --git 
a/mailbox/plugin/quota-mailing/src/test/java/org/apache/james/mailbox/quota/mailing/QuotaMailingListenerConfigurationTest.java
 
b/mailbox/plugin/quota-mailing/src/test/java/org/apache/james/mailbox/quota/mailing/QuotaMailingListenerConfigurationTest.java
index cff7d75..919c2c7 100644
--- 
a/mailbox/plugin/quota-mailing/src/test/java/org/apache/james/mailbox/quota/mailing/QuotaMailingListenerConfigurationTest.java
+++ 
b/mailbox/plugin/quota-mailing/src/test/java/org/apache/james/mailbox/quota/mailing/QuotaMailingListenerConfigurationTest.java
@@ -174,7 +174,8 @@ public class QuotaMailingListenerConfigurationTest {
             "<configuration><gracePeriod>-12 
ms</gracePeriod></configuration>"));
 
         assertThatThrownBy(() -> 
QuotaMailingListenerConfiguration.from(xmlConfiguration))
-            .isInstanceOf(NumberFormatException.class);
+            .isInstanceOf(IllegalArgumentException.class)
+            .hasMessage("Duration amount should be positive");
     }
 
     @Test
diff --git 
a/server/container/util/src/main/java/org/apache/james/util/DurationParser.java 
b/server/container/util/src/main/java/org/apache/james/util/DurationParser.java
index b78fd6e..a0d61a6 100644
--- 
a/server/container/util/src/main/java/org/apache/james/util/DurationParser.java
+++ 
b/server/container/util/src/main/java/org/apache/james/util/DurationParser.java
@@ -27,12 +27,13 @@ import java.util.Optional;
 import java.util.regex.Matcher;
 import java.util.regex.Pattern;
 
+import com.google.common.base.Preconditions;
 import com.google.common.base.Strings;
 import com.google.common.collect.ImmutableList;
 
 public class DurationParser {
 
-    private static final String PATTERN_STRING = 
"\\s*([0-9]+)\\s*([a-z,A-Z]*)\\s*";
+    private static final String PATTERN_STRING = 
"\\s*(-?[0-9]+)\\s*([a-z,A-Z]*)\\s*";
     private static final int AMOUNT = 1;
     private static final int UNIT = 2;
 
@@ -87,16 +88,24 @@ public class DurationParser {
     public static Duration parse(String rawString, ChronoUnit defaultUnit) 
throws NumberFormatException {
         Matcher res = PATTERN.matcher(rawString);
         if (res.matches()) {
-            if (res.group(AMOUNT) != null && res.group(UNIT) != null) {
+            String unitAsString = res.group(UNIT);
+            String amountAsString = res.group(AMOUNT);
+            if (amountAsString != null && unitAsString != null) {
                 long time = Integer.parseInt(res.group(AMOUNT).trim());
-                return parseUnitAsDuration(res.group(UNIT))
-                    .orElse(defaultUnit.getDuration())
-                    .multipliedBy(time);
+                Duration unitAsDuration = 
parseUnitAsDuration(unitAsString).orElse(defaultUnit.getDuration());
+
+                return computeDuration(unitAsDuration, time);
             }
         }
         throw new NumberFormatException("The supplied String is not a 
supported format " + rawString);
     }
 
+    private static Duration computeDuration(Duration unitAsDuration, long 
time) {
+        Preconditions.checkArgument(time >= 0, "Duration amount should be 
positive");
+
+        return unitAsDuration.multipliedBy(time);
+    }
+
     private static Optional<Duration> parseUnitAsDuration(String unit) {
         if (Strings.isNullOrEmpty(unit)) {
             return Optional.empty();
diff --git 
a/server/container/util/src/test/java/org/apache/james/util/DurationParserTest.java
 
b/server/container/util/src/test/java/org/apache/james/util/DurationParserTest.java
index e0b573c..37a5550 100644
--- 
a/server/container/util/src/test/java/org/apache/james/util/DurationParserTest.java
+++ 
b/server/container/util/src/test/java/org/apache/james/util/DurationParserTest.java
@@ -59,6 +59,13 @@ class DurationParserTest {
             .isEqualTo(Duration.ofMinutes(2));
     }
 
+    @Test
+    void parseShouldThrowOnNegativeValue() {
+        assertThatThrownBy(() -> DurationParser.parse("-2 minutes"))
+            .isInstanceOf(IllegalArgumentException.class)
+            .hasMessage("Duration amount should be positive");
+    }
+
     @ParameterizedTest
     @ValueSource(strings = {"2ms", "2", "2 ms", "2 msec", "2 msecs", "2 Ms"})
     void parseShouldHandleMilliseconds(String input) {
@@ -140,12 +147,6 @@ class DurationParserTest {
     }
 
     @Test
-    void parseShouldThrowWhenNegativeAmount() {
-        assertThatThrownBy(() -> DurationParser.parse("-1 s"))
-            .isInstanceOf(NumberFormatException.class);
-    }
-
-    @Test
     void parseShouldThrowWhenZero() {
         assertThat(DurationParser.parse("0 s"))
             .isEqualTo(Duration.ofSeconds(0));
diff --git 
a/server/mailet/mailets/src/test/java/org/apache/james/transport/mailets/remote/delivery/DelayTest.java
 
b/server/mailet/mailets/src/test/java/org/apache/james/transport/mailets/remote/delivery/DelayTest.java
index f619d28..dafaf83 100644
--- 
a/server/mailet/mailets/src/test/java/org/apache/james/transport/mailets/remote/delivery/DelayTest.java
+++ 
b/server/mailet/mailets/src/test/java/org/apache/james/transport/mailets/remote/delivery/DelayTest.java
@@ -20,6 +20,7 @@
 package org.apache.james.transport.mailets.remote.delivery;
 
 import static org.assertj.core.api.Assertions.assertThat;
+import static org.assertj.core.api.Assertions.assertThatThrownBy;
 
 import java.time.Duration;
 
@@ -51,9 +52,10 @@ public class DelayTest {
     }
 
     @Test
-    public void stringConstructorShouldThrowOnNegativeNumbers() throws 
Exception {
-        expectedException.expect(NumberFormatException.class);
-        assertThat(Delay.from("-1s")).isEqualTo(new 
Delay(Delay.DEFAULT_ATTEMPTS, Duration.ofMillis(0)));
+    public void stringConstructorShouldThrowOnNegativeNumbers() {
+        assertThatThrownBy(() -> Delay.from("-1s"))
+            .isInstanceOf(IllegalArgumentException.class)
+            .hasMessage("Duration amount should be positive");
     }
 
     @Test
diff --git 
a/server/protocols/webadmin/webadmin-core/src/main/java/org/apache/james/webadmin/routes/TasksRoutes.java
 
b/server/protocols/webadmin/webadmin-core/src/main/java/org/apache/james/webadmin/routes/TasksRoutes.java
index 35db8b8..a01fc99 100644
--- 
a/server/protocols/webadmin/webadmin-core/src/main/java/org/apache/james/webadmin/routes/TasksRoutes.java
+++ 
b/server/protocols/webadmin/webadmin-core/src/main/java/org/apache/james/webadmin/routes/TasksRoutes.java
@@ -41,10 +41,10 @@ import org.apache.james.webadmin.dto.ExecutionDetailsDto;
 import org.apache.james.webadmin.utils.ErrorResponder;
 import org.apache.james.webadmin.utils.JsonTransformer;
 import org.apache.james.webadmin.utils.Responses;
-
 import org.eclipse.jetty.http.HttpStatus;
 
 import com.google.common.base.Preconditions;
+
 import io.swagger.annotations.Api;
 import io.swagger.annotations.ApiImplicitParam;
 import io.swagger.annotations.ApiImplicitParams;
@@ -192,28 +192,27 @@ public class TasksRoutes implements Routes {
 
     private Duration getTimeout(Request req) {
         try {
-            Optional<String> requestTimeout = 
Optional.ofNullable(req.queryParams("timeout"))
-                .filter(parameter -> !parameter.isEmpty());
-
-            requestTimeout.ifPresent(timeout ->
-                Preconditions.checkState(!timeout.replaceAll(" ", 
"").startsWith("-"), "Timeout should be positive"));
-
-            Duration timeout = requestTimeout
+            Duration timeout =  Optional.ofNullable(req.queryParams("timeout"))
+                .filter(parameter -> !parameter.isEmpty())
                 .map(rawString -> DurationParser.parse(rawString, 
ChronoUnit.SECONDS))
                 .orElse(MAXIMUM_AWAIT_TIMEOUT);
 
-            Preconditions.checkState(timeout.compareTo(MAXIMUM_AWAIT_TIMEOUT) 
<= 0, "Timeout should not exceed one year");
+            assertDoesNotExceedMaximumTimeout(timeout);
             return timeout;
         } catch (Exception e) {
             throw ErrorResponder.builder()
                 .statusCode(HttpStatus.BAD_REQUEST_400)
                 .cause(e)
                 .type(ErrorResponder.ErrorType.INVALID_ARGUMENT)
-                .message("Invalid timeout " + e.getMessage())
+                .message("Invalid timeout")
                 .haltError();
         }
     }
 
+    private void assertDoesNotExceedMaximumTimeout(Duration timeout) {
+        Preconditions.checkState(timeout.compareTo(MAXIMUM_AWAIT_TIMEOUT) <= 
0, "Timeout should not exceed 365 days");
+    }
+
     private TaskExecutionDetails awaitTask(TaskId taskId, Duration timeout) {
         try {
             return taskManager.await(taskId, timeout);
diff --git 
a/server/protocols/webadmin/webadmin-core/src/test/java/org/apache/james/webadmin/routes/TasksRoutesTest.java
 
b/server/protocols/webadmin/webadmin-core/src/test/java/org/apache/james/webadmin/routes/TasksRoutesTest.java
index f31ec43..ad77c96 100644
--- 
a/server/protocols/webadmin/webadmin-core/src/test/java/org/apache/james/webadmin/routes/TasksRoutesTest.java
+++ 
b/server/protocols/webadmin/webadmin-core/src/test/java/org/apache/james/webadmin/routes/TasksRoutesTest.java
@@ -22,7 +22,6 @@ package org.apache.james.webadmin.routes;
 import static io.restassured.RestAssured.given;
 import static io.restassured.RestAssured.when;
 import static io.restassured.RestAssured.with;
-import static org.hamcrest.Matchers.allOf;
 import static org.hamcrest.Matchers.containsString;
 import static org.hamcrest.Matchers.empty;
 import static org.hamcrest.Matchers.hasSize;
@@ -230,7 +229,8 @@ class TasksRoutesTest {
             .get("/" + taskId.getValue() + "/await")
         .then()
             .statusCode(HttpStatus.BAD_REQUEST_400)
-            .body("message", allOf(containsString("Invalid timeout"), 
containsString("Timeout should be positive")));
+            .body("message", containsString("Invalid timeout"))
+            .body("details", containsString("Duration amount should be 
positive"));
     }
 
     @Test
@@ -243,7 +243,8 @@ class TasksRoutesTest {
             .get("/" + taskId.getValue() + "/await")
         .then()
             .statusCode(HttpStatus.BAD_REQUEST_400)
-            .body("message", allOf(containsString("Invalid timeout"), 
containsString("Timeout should not exceed one year")));
+            .body("message", containsString("Invalid timeout"))
+            .body("details", containsString("Timeout should not exceed 365 
days"));
     }
 
     @Test


---------------------------------------------------------------------
To unsubscribe, e-mail: server-dev-unsubscr...@james.apache.org
For additional commands, e-mail: server-dev-h...@james.apache.org

Reply via email to