You are viewing a plain text version of this content. The canonical link for it is here.
Posted to notifications@james.apache.org by bt...@apache.org on 2022/08/20 05:54:13 UTC

[james-project] 02/02: JAMES-3775 Write webadmin route to create feeding ham messages task

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 5cce1a5f734400fcac4260ed51b6249153b9df74
Author: Quan Tran <hq...@linagora.com>
AuthorDate: Fri Jul 29 17:11:33 2022 +0700

    JAMES-3775 Write webadmin route to create feeding ham messages task
---
 third-party/rspamd/README.md                       |  46 ++++
 .../apache/james/rspamd/module/RSpamDModule.java   |  12 +
 .../james/rspamd/route/FeedMessageRoute.java       |  28 +-
 .../james/rspamd/route/FeedMessageRouteTest.java   | 286 +++++++++++++++++++--
 4 files changed, 346 insertions(+), 26 deletions(-)

diff --git a/third-party/rspamd/README.md b/third-party/rspamd/README.md
index 2f98347f0d..e508228d11 100644
--- a/third-party/rspamd/README.md
+++ b/third-party/rspamd/README.md
@@ -124,4 +124,50 @@ The scheduled task will have the following type `FeedSpamToRSpamDTask` and the f
   "timestamp": "2007-12-03T10:15:30Z",
   "type": "FeedSpamToRSpamDTask"
 }
+```
+
+### Report ham messages to RSpamD
+One can use this route to schedule a task that reports ham messages to RSpamD for its spam classify learning.
+
+```bash
+curl -XPOST 'http://ip:port/rspamd?action=reportHam
+```
+
+This endpoint has the following param:
+- `action` (required): need to be `reportHam`
+- `messagesPerSecond` (optional): Concurrent learns performed for RSpamD, default to 10
+- `period` (optional): duration (support many time units, default in seconds), only messages between `now` and `now - duration` are reported. By default,
+  all messages are reported.
+  These inputs represent the same duration: `1d`, `1day`, `86400 seconds`, `86400`...
+- `samplingProbability` (optional): float between 0 and 1, represent the chance to report each given message to RSpamD.
+  By default, all messages are reported.
+
+Will return the task id. E.g:
+```
+{
+    "taskId": "70c12761-ab86-4321-bb6f-fde99e2f74b0"
+}
+```
+
+Response codes:
+- 201: Task generation succeeded. Corresponding task id is returned.
+- 400: Invalid arguments supplied in the user request.
+
+[More details about endpoints returning a task](https://james.apache.org/server/manage-webadmin.html#Endpoints_returning_a_task).
+
+The scheduled task will have the following type `FeedHamToRSpamDTask` and the following additionalInformation:
+
+```json
+{
+  "errorCount": 1,
+  "reportedHamMessageCount": 2,
+  "runningOptions": {
+    "messagesPerSecond": 10,
+    "periodInSecond": 3600,
+    "samplingProbability": 1.0
+  },
+  "hamMessageCount": 4,
+  "timestamp": "2007-12-03T10:15:30Z",
+  "type": "FeedHamToRSpamDTask"
+}
 ```
\ No newline at end of file
diff --git a/third-party/rspamd/src/main/java/org/apache/james/rspamd/module/RSpamDModule.java b/third-party/rspamd/src/main/java/org/apache/james/rspamd/module/RSpamDModule.java
index c3865bf7a1..3d27718446 100644
--- a/third-party/rspamd/src/main/java/org/apache/james/rspamd/module/RSpamDModule.java
+++ b/third-party/rspamd/src/main/java/org/apache/james/rspamd/module/RSpamDModule.java
@@ -20,6 +20,7 @@
 package org.apache.james.rspamd.module;
 
 import org.apache.james.rspamd.route.FeedMessageRoute;
+import org.apache.james.rspamd.task.FeedHamToRSpamDTaskAdditionalInformationDTO;
 import org.apache.james.rspamd.task.FeedSpamToRSpamDTaskAdditionalInformationDTO;
 import org.apache.james.server.task.json.dto.AdditionalInformationDTO;
 import org.apache.james.server.task.json.dto.AdditionalInformationDTOModule;
@@ -49,4 +50,15 @@ public class RSpamDModule extends AbstractModule {
     public AdditionalInformationDTOModule<? extends TaskExecutionDetails.AdditionalInformation, ? extends AdditionalInformationDTO> webAdminFeedSpamAdditionalInformation() {
         return FeedSpamToRSpamDTaskAdditionalInformationDTO.SERIALIZATION_MODULE;
     }
+
+    @ProvidesIntoSet
+    public AdditionalInformationDTOModule<? extends TaskExecutionDetails.AdditionalInformation, ? extends AdditionalInformationDTO> feedHamAdditionalInformation() {
+        return FeedHamToRSpamDTaskAdditionalInformationDTO.SERIALIZATION_MODULE;
+    }
+
+    @Named(DTOModuleInjections.WEBADMIN_DTO)
+    @ProvidesIntoSet
+    public AdditionalInformationDTOModule<? extends TaskExecutionDetails.AdditionalInformation, ? extends AdditionalInformationDTO> webAdminFeedHamAdditionalInformation() {
+        return FeedHamToRSpamDTaskAdditionalInformationDTO.SERIALIZATION_MODULE;
+    }
 }
diff --git a/third-party/rspamd/src/main/java/org/apache/james/rspamd/route/FeedMessageRoute.java b/third-party/rspamd/src/main/java/org/apache/james/rspamd/route/FeedMessageRoute.java
index b1c631018b..483b7aeb92 100644
--- a/third-party/rspamd/src/main/java/org/apache/james/rspamd/route/FeedMessageRoute.java
+++ b/third-party/rspamd/src/main/java/org/apache/james/rspamd/route/FeedMessageRoute.java
@@ -19,9 +19,6 @@
 
 package org.apache.james.rspamd.route;
 
-import static org.apache.james.rspamd.task.FeedSpamToRSpamDTask.RunningOptions.DEFAULT_MESSAGES_PER_SECOND;
-import static org.apache.james.rspamd.task.FeedSpamToRSpamDTask.RunningOptions.DEFAULT_SAMPLING_PROBABILITY;
-
 import java.time.Clock;
 import java.time.temporal.ChronoUnit;
 import java.util.Optional;
@@ -33,6 +30,7 @@ import org.apache.james.mailbox.MailboxManager;
 import org.apache.james.mailbox.MessageIdManager;
 import org.apache.james.mailbox.store.MailboxSessionMapperFactory;
 import org.apache.james.rspamd.client.RSpamDHttpClient;
+import org.apache.james.rspamd.task.FeedHamToRSpamDTask;
 import org.apache.james.rspamd.task.FeedSpamToRSpamDTask;
 import org.apache.james.task.Task;
 import org.apache.james.task.TaskManager;
@@ -49,6 +47,8 @@ import spark.Service;
 
 public class FeedMessageRoute implements Routes {
     public static final String BASE_PATH = "/rspamd";
+    private static final String REPORT_SPAM_PARAM = "reportSpam";
+    private static final String REPORT_HAM_PARAM = "reportHam";
 
     private final TaskManager taskManager;
     private final MailboxManager mailboxManager;
@@ -85,21 +85,29 @@ public class FeedMessageRoute implements Routes {
 
     public Task feedMessageTaskFromRequest(Request request) {
         Preconditions.checkArgument(Optional.ofNullable(request.queryParams("action"))
-                .filter(action -> action.equals("reportSpam") || action.equals("reportHam"))
-                .isPresent(),
-            "'action' is missing or must be 'reportSpam' or 'reportHam'");
+                .filter(action -> action.equals(REPORT_SPAM_PARAM) || action.equals(REPORT_HAM_PARAM))
+                .isPresent(), String.format("'action' is missing or must be '%s' or '%s'", REPORT_SPAM_PARAM, REPORT_HAM_PARAM));
 
-        return new FeedSpamToRSpamDTask(mailboxManager, usersRepository, messageIdManager, mapperFactory, rSpamDHttpClient,
-            getFeedSpamTaskRunningOptions(request), clock);
+        return Optional.ofNullable(request.queryParams("action"))
+            .filter(action -> action.equals(REPORT_SPAM_PARAM))
+            .map(any -> (Task) new FeedSpamToRSpamDTask(mailboxManager, usersRepository, messageIdManager, mapperFactory, rSpamDHttpClient, getFeedSpamTaskRunningOptions(request), clock))
+            .orElse(new FeedHamToRSpamDTask(mailboxManager, usersRepository, messageIdManager, mapperFactory, rSpamDHttpClient, getFeedHamTaskRunningOptions(request), clock));
     }
 
     private FeedSpamToRSpamDTask.RunningOptions getFeedSpamTaskRunningOptions(Request request) {
         Optional<Long> periodInSecond = getPeriod(request);
-        int messagesPerSecond = getMessagesPerSecond(request).orElse(DEFAULT_MESSAGES_PER_SECOND);
-        double samplingProbability = getSamplingProbability(request).orElse(DEFAULT_SAMPLING_PROBABILITY);
+        int messagesPerSecond = getMessagesPerSecond(request).orElse(FeedSpamToRSpamDTask.RunningOptions.DEFAULT_MESSAGES_PER_SECOND);
+        double samplingProbability = getSamplingProbability(request).orElse(FeedSpamToRSpamDTask.RunningOptions.DEFAULT_SAMPLING_PROBABILITY);
         return new FeedSpamToRSpamDTask.RunningOptions(periodInSecond, messagesPerSecond, samplingProbability);
     }
 
+    private FeedHamToRSpamDTask.RunningOptions getFeedHamTaskRunningOptions(Request request) {
+        Optional<Long> periodInSecond = getPeriod(request);
+        int messagesPerSecond = getMessagesPerSecond(request).orElse(FeedHamToRSpamDTask.RunningOptions.DEFAULT_MESSAGES_PER_SECOND);
+        double samplingProbability = getSamplingProbability(request).orElse(FeedHamToRSpamDTask.RunningOptions.DEFAULT_SAMPLING_PROBABILITY);
+        return new FeedHamToRSpamDTask.RunningOptions(periodInSecond, messagesPerSecond, samplingProbability);
+    }
+
     private Optional<Long> getPeriod(Request req) {
         return Optional.ofNullable(req.queryParams("period"))
             .filter(Predicate.not(String::isEmpty))
diff --git a/third-party/rspamd/src/test/java/org/apache/james/rspamd/route/FeedMessageRouteTest.java b/third-party/rspamd/src/test/java/org/apache/james/rspamd/route/FeedMessageRouteTest.java
index 4af36a5406..e31d69a896 100644
--- a/third-party/rspamd/src/test/java/org/apache/james/rspamd/route/FeedMessageRouteTest.java
+++ b/third-party/rspamd/src/test/java/org/apache/james/rspamd/route/FeedMessageRouteTest.java
@@ -23,8 +23,8 @@ import static io.restassured.RestAssured.given;
 import static io.restassured.http.ContentType.JSON;
 import static org.apache.james.rspamd.DockerRSpamD.PASSWORD;
 import static org.apache.james.rspamd.route.FeedMessageRoute.BASE_PATH;
-import static org.apache.james.rspamd.task.FeedSpamToRSpamDTask.RunningOptions.DEFAULT_MESSAGES_PER_SECOND;
-import static org.apache.james.rspamd.task.FeedSpamToRSpamDTask.RunningOptions.DEFAULT_SAMPLING_PROBABILITY;
+import static org.apache.james.rspamd.task.FeedHamToRSpamDTaskTest.ALICE_INBOX_MAILBOX;
+import static org.apache.james.rspamd.task.FeedHamToRSpamDTaskTest.BOB_INBOX_MAILBOX;
 import static org.apache.james.rspamd.task.FeedSpamToRSpamDTaskTest.ALICE;
 import static org.apache.james.rspamd.task.FeedSpamToRSpamDTaskTest.ALICE_SPAM_MAILBOX;
 import static org.apache.james.rspamd.task.FeedSpamToRSpamDTaskTest.BOB;
@@ -65,6 +65,8 @@ import org.apache.james.mailbox.store.MailboxSessionMapperFactory;
 import org.apache.james.rspamd.DockerRSpamDExtension;
 import org.apache.james.rspamd.client.RSpamDClientConfiguration;
 import org.apache.james.rspamd.client.RSpamDHttpClient;
+import org.apache.james.rspamd.task.FeedHamToRSpamDTask;
+import org.apache.james.rspamd.task.FeedHamToRSpamDTaskAdditionalInformationDTO;
 import org.apache.james.rspamd.task.FeedSpamToRSpamDTask;
 import org.apache.james.rspamd.task.FeedSpamToRSpamDTaskAdditionalInformationDTO;
 import org.apache.james.task.Hostname;
@@ -111,7 +113,10 @@ public class FeedMessageRouteTest {
         usersRepository.addUser(BOB, "anyPassword");
         usersRepository.addUser(ALICE, "anyPassword");
         mailboxManager.createMailbox(BOB_SPAM_MAILBOX, mailboxManager.createSystemSession(BOB));
+        mailboxManager.createMailbox(BOB_INBOX_MAILBOX, mailboxManager.createSystemSession(BOB));
         mailboxManager.createMailbox(ALICE_SPAM_MAILBOX, mailboxManager.createSystemSession(ALICE));
+        mailboxManager.createMailbox(ALICE_INBOX_MAILBOX, mailboxManager.createSystemSession(ALICE));
+
         taskManager = new MemoryTaskManager(new Hostname("foo"));
         UpdatableTickingClock clock = new UpdatableTickingClock(NOW);
         JsonTransformer jsonTransformer = new JsonTransformer();
@@ -119,7 +124,8 @@ public class FeedMessageRouteTest {
         MessageIdManager messageIdManager = inMemoryIntegrationResources.getMessageIdManager();
         MailboxSessionMapperFactory mapperFactory = mailboxManager.getMapperFactory();
 
-        TasksRoutes tasksRoutes = new TasksRoutes(taskManager, jsonTransformer, DTOConverter.of(FeedSpamToRSpamDTaskAdditionalInformationDTO.SERIALIZATION_MODULE));
+        TasksRoutes tasksRoutes = new TasksRoutes(taskManager, jsonTransformer, DTOConverter.of(FeedSpamToRSpamDTaskAdditionalInformationDTO.SERIALIZATION_MODULE,
+            FeedHamToRSpamDTaskAdditionalInformationDTO.SERIALIZATION_MODULE));
         FeedMessageRoute feedMessageRoute = new FeedMessageRoute(taskManager, mailboxManager, usersRepository, client, jsonTransformer, clock,
             messageIdManager, mapperFactory);
 
@@ -136,7 +142,7 @@ public class FeedMessageRouteTest {
         taskManager.stop();
     }
 
-    private void appendSpamMessage(MailboxPath mailboxPath, Date internalDate) throws MailboxException {
+    private void appendMessage(MailboxPath mailboxPath, Date internalDate) throws MailboxException {
         MailboxSession session = mailboxManager.createSystemSession(mailboxPath.getUser());
         mailboxManager.getMailbox(mailboxPath, session)
             .appendMessage(new ByteArrayInputStream(String.format("random content %4.3f", Math.random()).getBytes()),
@@ -150,8 +156,8 @@ public class FeedMessageRouteTest {
     class FeedSpam {
         @Test
         void taskShouldReportAllSpamMessagesOfAllUsersByDefault() throws MailboxException {
-            appendSpamMessage(BOB_SPAM_MAILBOX, Date.from(NOW));
-            appendSpamMessage(ALICE_SPAM_MAILBOX, Date.from(NOW));
+            appendMessage(BOB_SPAM_MAILBOX, Date.from(NOW));
+            appendMessage(ALICE_SPAM_MAILBOX, Date.from(NOW));
 
             String taskId = given()
                 .queryParam("action", "reportSpam")
@@ -169,15 +175,15 @@ public class FeedMessageRouteTest {
                 .body("additionalInformation.spamMessageCount", is(2))
                 .body("additionalInformation.reportedSpamMessageCount", is(2))
                 .body("additionalInformation.errorCount", is(0))
-                .body("additionalInformation.runningOptions.messagesPerSecond", is(DEFAULT_MESSAGES_PER_SECOND))
+                .body("additionalInformation.runningOptions.messagesPerSecond", is(FeedSpamToRSpamDTask.RunningOptions.DEFAULT_MESSAGES_PER_SECOND))
                 .body("additionalInformation.runningOptions.periodInSecond", is(nullValue()))
-                .body("additionalInformation.runningOptions.samplingProbability", is((float) DEFAULT_SAMPLING_PROBABILITY));
+                .body("additionalInformation.runningOptions.samplingProbability", is((float) FeedSpamToRSpamDTask.RunningOptions.DEFAULT_SAMPLING_PROBABILITY));
         }
 
         @Test
         void taskShouldReportOnlyMailInPeriod() throws MailboxException {
-            appendSpamMessage(BOB_SPAM_MAILBOX, Date.from(NOW.minusSeconds(THREE_DAYS_IN_SECOND)));
-            appendSpamMessage(ALICE_SPAM_MAILBOX, Date.from(NOW.minusSeconds(ONE_DAY_IN_SECOND)));
+            appendMessage(BOB_SPAM_MAILBOX, Date.from(NOW.minusSeconds(THREE_DAYS_IN_SECOND)));
+            appendMessage(ALICE_SPAM_MAILBOX, Date.from(NOW.minusSeconds(ONE_DAY_IN_SECOND)));
 
             String taskId = given()
                 .queryParam("action", "reportSpam")
@@ -196,15 +202,15 @@ public class FeedMessageRouteTest {
                 .body("additionalInformation.spamMessageCount", is(2))
                 .body("additionalInformation.reportedSpamMessageCount", is(1))
                 .body("additionalInformation.errorCount", is(0))
-                .body("additionalInformation.runningOptions.messagesPerSecond", is(DEFAULT_MESSAGES_PER_SECOND))
+                .body("additionalInformation.runningOptions.messagesPerSecond", is(FeedSpamToRSpamDTask.RunningOptions.DEFAULT_MESSAGES_PER_SECOND))
                 .body("additionalInformation.runningOptions.periodInSecond", is(172800))
-                .body("additionalInformation.runningOptions.samplingProbability", is((float) DEFAULT_SAMPLING_PROBABILITY));
+                .body("additionalInformation.runningOptions.samplingProbability", is((float) FeedSpamToRSpamDTask.RunningOptions.DEFAULT_SAMPLING_PROBABILITY));
         }
 
         @Test
         void taskWithAverageSamplingProbabilityShouldNotReportAllSpamMessages() {
             IntStream.range(0, 10)
-                .forEach(Throwing.intConsumer(any -> appendSpamMessage(BOB_SPAM_MAILBOX, Date.from(NOW.minusSeconds(ONE_DAY_IN_SECOND)))));
+                .forEach(Throwing.intConsumer(any -> appendMessage(BOB_SPAM_MAILBOX, Date.from(NOW.minusSeconds(ONE_DAY_IN_SECOND)))));
 
             String taskId = given()
                 .queryParam("action", "reportSpam")
@@ -223,7 +229,7 @@ public class FeedMessageRouteTest {
                 .body("additionalInformation.spamMessageCount", is(10))
                 .body("additionalInformation.reportedSpamMessageCount", is(allOf(greaterThan(0), lessThan(10))))
                 .body("additionalInformation.errorCount", is(0))
-                .body("additionalInformation.runningOptions.messagesPerSecond", is(DEFAULT_MESSAGES_PER_SECOND))
+                .body("additionalInformation.runningOptions.messagesPerSecond", is(FeedSpamToRSpamDTask.RunningOptions.DEFAULT_MESSAGES_PER_SECOND))
                 .body("additionalInformation.runningOptions.periodInSecond", is(nullValue()))
                 .body("additionalInformation.runningOptions.samplingProbability", is(0.5F));
         }
@@ -289,9 +295,9 @@ public class FeedMessageRouteTest {
                 .body("additionalInformation.spamMessageCount", is(0))
                 .body("additionalInformation.reportedSpamMessageCount", is(0))
                 .body("additionalInformation.errorCount", is(0))
-                .body("additionalInformation.runningOptions.messagesPerSecond", is(DEFAULT_MESSAGES_PER_SECOND))
+                .body("additionalInformation.runningOptions.messagesPerSecond", is(FeedSpamToRSpamDTask.RunningOptions.DEFAULT_MESSAGES_PER_SECOND))
                 .body("additionalInformation.runningOptions.periodInSecond", is(nullValue()))
-                .body("additionalInformation.runningOptions.samplingProbability", is((float) DEFAULT_SAMPLING_PROBABILITY));
+                .body("additionalInformation.runningOptions.samplingProbability", is((float) FeedSpamToRSpamDTask.RunningOptions.DEFAULT_SAMPLING_PROBABILITY));
         }
 
         @ParameterizedTest
@@ -393,4 +399,252 @@ public class FeedMessageRouteTest {
                 .body("details", containsString("samplingProbability"));
         }
     }
+
+    @Nested
+    class FeedHam {
+        @Test
+        void taskShouldReportAllHamMessagesOfAllUsersByDefault() throws MailboxException {
+            appendMessage(BOB_INBOX_MAILBOX, Date.from(NOW));
+            appendMessage(ALICE_INBOX_MAILBOX, Date.from(NOW));
+
+            String taskId = given()
+                .queryParam("action", "reportHam")
+                .post()
+                .jsonPath()
+                .get("taskId");
+
+            given()
+                .basePath(TasksRoutes.BASE)
+            .when()
+                .get(taskId + "/await")
+            .then()
+                .body("status", is("completed"))
+                .body("additionalInformation.type", is(FeedHamToRSpamDTask.TASK_TYPE.asString()))
+                .body("additionalInformation.hamMessageCount", is(2))
+                .body("additionalInformation.reportedHamMessageCount", is(2))
+                .body("additionalInformation.errorCount", is(0))
+                .body("additionalInformation.runningOptions.messagesPerSecond", is(FeedHamToRSpamDTask.RunningOptions.DEFAULT_MESSAGES_PER_SECOND))
+                .body("additionalInformation.runningOptions.periodInSecond", is(nullValue()))
+                .body("additionalInformation.runningOptions.samplingProbability", is((float) FeedHamToRSpamDTask.RunningOptions.DEFAULT_SAMPLING_PROBABILITY));
+        }
+
+        @Test
+        void taskShouldReportOnlyMailInPeriod() throws MailboxException {
+            appendMessage(BOB_INBOX_MAILBOX, Date.from(NOW.minusSeconds(THREE_DAYS_IN_SECOND)));
+            appendMessage(ALICE_INBOX_MAILBOX, Date.from(NOW.minusSeconds(ONE_DAY_IN_SECOND)));
+
+            String taskId = given()
+                .queryParam("action", "reportHam")
+                .queryParam("period", TWO_DAYS_IN_SECOND)
+                .post()
+                .jsonPath()
+                .get("taskId");
+
+            given()
+                .basePath(TasksRoutes.BASE)
+            .when()
+                .get(taskId + "/await")
+            .then()
+                .body("status", is("completed"))
+                .body("additionalInformation.type", is(FeedHamToRSpamDTask.TASK_TYPE.asString()))
+                .body("additionalInformation.hamMessageCount", is(2))
+                .body("additionalInformation.reportedHamMessageCount", is(1))
+                .body("additionalInformation.errorCount", is(0))
+                .body("additionalInformation.runningOptions.messagesPerSecond", is(FeedHamToRSpamDTask.RunningOptions.DEFAULT_MESSAGES_PER_SECOND))
+                .body("additionalInformation.runningOptions.periodInSecond", is(172800))
+                .body("additionalInformation.runningOptions.samplingProbability", is((float) FeedHamToRSpamDTask.RunningOptions.DEFAULT_SAMPLING_PROBABILITY));
+        }
+
+        @Test
+        void taskWithAverageSamplingProbabilityShouldNotReportAllHamMessages() {
+            IntStream.range(0, 10)
+                .forEach(Throwing.intConsumer(any -> appendMessage(BOB_INBOX_MAILBOX, Date.from(NOW.minusSeconds(ONE_DAY_IN_SECOND)))));
+
+            String taskId = given()
+                .queryParam("action", "reportHam")
+                .queryParam("samplingProbability", 0.5)
+                .post()
+                .jsonPath()
+                .get("taskId");
+
+            given()
+                .basePath(TasksRoutes.BASE)
+            .when()
+                .get(taskId + "/await")
+            .then()
+                .body("status", is("completed"))
+                .body("additionalInformation.type", is(FeedHamToRSpamDTask.TASK_TYPE.asString()))
+                .body("additionalInformation.hamMessageCount", is(10))
+                .body("additionalInformation.reportedHamMessageCount", is(allOf(greaterThan(0), lessThan(10))))
+                .body("additionalInformation.errorCount", is(0))
+                .body("additionalInformation.runningOptions.messagesPerSecond", is(FeedHamToRSpamDTask.RunningOptions.DEFAULT_MESSAGES_PER_SECOND))
+                .body("additionalInformation.runningOptions.periodInSecond", is(nullValue()))
+                .body("additionalInformation.runningOptions.samplingProbability", is(0.5F));
+        }
+
+        @Test
+        void feedMessageShouldReturnErrorWhenInvalidAction() {
+            given()
+                .queryParam("action", "invalid")
+                .post()
+            .then()
+                .statusCode(BAD_REQUEST_400)
+                .contentType(JSON)
+                .body("statusCode", is(BAD_REQUEST_400))
+                .body("type", is("InvalidArgument"))
+                .body("message", is("Invalid arguments supplied in the user request"))
+                .body("details", is("'action' is missing or must be 'reportSpam' or 'reportHam'"));
+        }
+
+        @Test
+        void feedMessageTaskShouldReturnErrorWhenMissingAction() {
+            given()
+                .post()
+            .then()
+                .statusCode(BAD_REQUEST_400)
+                .contentType(JSON)
+                .body("statusCode", is(BAD_REQUEST_400))
+                .body("type", is("InvalidArgument"))
+                .body("message", is("Invalid arguments supplied in the user request"))
+                .body("details", is("'action' is missing or must be 'reportSpam' or 'reportHam'"));
+        }
+
+        @Test
+        void feedHamShouldReturnTaskId() {
+            given()
+                .queryParam("action", "reportHam")
+                .post()
+            .then()
+                .statusCode(HttpStatus.CREATED_201)
+                .body("taskId", notNullValue());
+        }
+
+        @Test
+        void feedHamShouldReturnDetail() {
+            String taskId = given()
+                .queryParam("action", "reportHam")
+                .post()
+                .jsonPath()
+                .get("taskId");
+
+            given()
+                .basePath(TasksRoutes.BASE)
+            .when()
+                .get(taskId + "/await")
+            .then()
+                .body("status", is("completed"))
+                .body("taskId", is(notNullValue()))
+                .body("type", is(FeedHamToRSpamDTask.TASK_TYPE.asString()))
+                .body("startedDate", is(notNullValue()))
+                .body("submitDate", is(notNullValue()))
+                .body("completedDate", is(notNullValue()))
+                .body("additionalInformation.type", is(FeedHamToRSpamDTask.TASK_TYPE.asString()))
+                .body("additionalInformation.timestamp", is(notNullValue()))
+                .body("additionalInformation.hamMessageCount", is(0))
+                .body("additionalInformation.reportedHamMessageCount", is(0))
+                .body("additionalInformation.errorCount", is(0))
+                .body("additionalInformation.runningOptions.messagesPerSecond", is(FeedHamToRSpamDTask.RunningOptions.DEFAULT_MESSAGES_PER_SECOND))
+                .body("additionalInformation.runningOptions.periodInSecond", is(nullValue()))
+                .body("additionalInformation.runningOptions.samplingProbability", is((float) FeedHamToRSpamDTask.RunningOptions.DEFAULT_SAMPLING_PROBABILITY));
+        }
+
+        @ParameterizedTest
+        @ValueSource(strings = {"3600", "3600 seconds", "1d", "1day"})
+        void feedHamShouldAcceptPeriodParam(String period) {
+            String taskId = given()
+                .queryParam("action", "reportHam")
+                .queryParam("period", period)
+                .post()
+                .jsonPath()
+                .get("taskId");
+
+            given()
+                .basePath(TasksRoutes.BASE)
+            .when()
+                .get(taskId + "/await")
+            .then()
+                .body("additionalInformation.runningOptions.periodInSecond", is((int) DurationParser.parse(period, ChronoUnit.SECONDS).toSeconds()));
+        }
+
+        @ParameterizedTest
+        @ValueSource(strings = {"-1", "0", "1 t"})
+        void feedHamShouldReturnErrorWhenPeriodInvalid(String period) {
+            given()
+                .queryParam("action", "reportHam")
+                .queryParam("period", period)
+                .post()
+            .then()
+                .statusCode(BAD_REQUEST_400)
+                .contentType(JSON)
+                .body("statusCode", is(BAD_REQUEST_400))
+                .body("type", is("InvalidArgument"))
+                .body("message", is("Invalid arguments supplied in the user request"));
+        }
+
+        @Test
+        void feedHamShouldAcceptMessagesPerSecondParam() {
+            String taskId = given()
+                .queryParam("action", "reportHam")
+                .queryParam("messagesPerSecond", 20)
+                .post()
+                .jsonPath()
+                .get("taskId");
+
+            given()
+                .basePath(TasksRoutes.BASE)
+            .when()
+                .get(taskId + "/await")
+                .then()
+                .body("additionalInformation.runningOptions.messagesPerSecond", is(20));
+        }
+
+        @ParameterizedTest
+        @ValueSource(doubles = {-1, -0.1, 1.1})
+        void feedHamShouldReturnErrorWhenMessagesPerSecondInvalid(double messagesPerSecond) {
+            given()
+                .queryParam("action", "reportHam")
+                .queryParam("messagesPerSecond", messagesPerSecond)
+                .post()
+            .then()
+                .statusCode(BAD_REQUEST_400)
+                .contentType(JSON)
+                .body("statusCode", is(BAD_REQUEST_400))
+                .body("type", is("InvalidArgument"))
+                .body("message", is("Invalid arguments supplied in the user request"))
+                .body("details", containsString("messagesPerSecond"));
+        }
+
+        @Test
+        void feedHamShouldAcceptSamplingProbabilityParam() {
+            String taskId = given()
+                .queryParam("action", "reportHam")
+                .queryParam("samplingProbability", 0.8)
+                .post()
+                .jsonPath()
+                .get("taskId");
+
+            given()
+                .basePath(TasksRoutes.BASE)
+            .when()
+                .get(taskId + "/await")
+            .then()
+                .body("additionalInformation.runningOptions.samplingProbability", is(0.8F));
+        }
+
+        @ParameterizedTest
+        @ValueSource(doubles = {-1, -0.1, 1.1})
+        void feedHamShouldReturnErrorWhenSamplingProbabilityInvalid(double samplingProbability) {
+            given()
+                .queryParam("action", "reportHam")
+                .queryParam("samplingProbability", samplingProbability)
+                .post()
+            .then()
+                .statusCode(BAD_REQUEST_400)
+                .contentType(JSON)
+                .body("statusCode", is(BAD_REQUEST_400))
+                .body("type", is("InvalidArgument"))
+                .body("message", is("Invalid arguments supplied in the user request"))
+                .body("details", containsString("samplingProbability"));
+        }
+    }
 }


---------------------------------------------------------------------
To unsubscribe, e-mail: notifications-unsubscribe@james.apache.org
For additional commands, e-mail: notifications-help@james.apache.org