JAMES-4025 VacationRelayIntegrationTest for JMAP RFC-8621
diff --git a/server/protocols/jmap-rfc-8621-integration-tests/distributed-jmap-rfc-8621-integration-tests/src/test/java/org/apache/james/jmap/rfc8621/distributed/DistributedVacationRelayIntegrationTest.java b/server/protocols/jmap-rfc-8621-integration-tests/distributed-jmap-rfc-8621-integration-tests/src/test/java/org/apache/james/jmap/rfc8621/distributed/DistributedVacationRelayIntegrationTest.java
new file mode 100644
index 0000000..5faa711
--- /dev/null
+++ b/server/protocols/jmap-rfc-8621-integration-tests/distributed-jmap-rfc-8621-integration-tests/src/test/java/org/apache/james/jmap/rfc8621/distributed/DistributedVacationRelayIntegrationTest.java
@@ -0,0 +1,78 @@
+/****************************************************************
+ * 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.james.jmap.rfc8621.distributed;
+
+import org.apache.james.CassandraExtension;
+import org.apache.james.CassandraRabbitMQJamesConfiguration;
+import org.apache.james.CassandraRabbitMQJamesServerMain;
+import org.apache.james.DockerOpenSearchExtension;
+import org.apache.james.JamesServerBuilder;
+import org.apache.james.JamesServerExtension;
+import org.apache.james.SearchConfiguration;
+import org.apache.james.dnsservice.api.DNSService;
+import org.apache.james.dnsservice.api.InMemoryDNSService;
+import org.apache.james.jmap.rfc8621.contract.IdentityProbeModule;
+import org.apache.james.jmap.rfc8621.contract.VacationRelayIntegrationTest;
+import org.apache.james.jmap.rfc8621.contract.probe.DelegationProbeModule;
+import org.apache.james.mock.smtp.server.testing.MockSmtpServerExtension;
+import org.apache.james.modules.AwsS3BlobStoreExtension;
+import org.apache.james.modules.RabbitMQExtension;
+import org.apache.james.modules.TestJMAPServerModule;
+import org.apache.james.modules.blobstore.BlobStoreConfiguration;
+import org.junit.jupiter.api.extension.RegisterExtension;
+
+public class DistributedVacationRelayIntegrationTest implements VacationRelayIntegrationTest {
+    private static final InMemoryDNSService inMemoryDNSService = new InMemoryDNSService();
+
+    @RegisterExtension
+    static MockSmtpServerExtension fakeSmtp = new MockSmtpServerExtension();
+
+    @RegisterExtension
+    static JamesServerExtension testExtension = new JamesServerBuilder<CassandraRabbitMQJamesConfiguration>(tmpDir ->
+        CassandraRabbitMQJamesConfiguration.builder()
+            .workingDirectory(tmpDir)
+            .configurationFromClasspath()
+            .enableJMAP()
+            .blobStore(BlobStoreConfiguration.builder()
+                .s3()
+                .disableCache()
+                .deduplication()
+                .noCryptoConfig())
+            .searchConfiguration(SearchConfiguration.openSearch())
+            .build())
+        .extension(new DockerOpenSearchExtension())
+        .extension(new CassandraExtension())
+        .extension(new RabbitMQExtension())
+        .extension(new AwsS3BlobStoreExtension())
+        .server(configuration -> CassandraRabbitMQJamesServerMain.createServer(configuration)
+            .overrideWith(new TestJMAPServerModule(), new DelegationProbeModule(), new IdentityProbeModule())
+            .overrideWith((binder -> binder.bind(DNSService.class).toInstance(inMemoryDNSService))))
+        .build();
+
+    @Override
+    public MockSmtpServerExtension getFakeSmtp() {
+        return fakeSmtp;
+    }
+
+    @Override
+    public InMemoryDNSService getInMemoryDns() {
+        return inMemoryDNSService;
+    }
+}
diff --git a/server/protocols/jmap-rfc-8621-integration-tests/jmap-rfc-8621-integration-tests-common/pom.xml b/server/protocols/jmap-rfc-8621-integration-tests/jmap-rfc-8621-integration-tests-common/pom.xml
index fea8604..173ede4 100644
--- a/server/protocols/jmap-rfc-8621-integration-tests/jmap-rfc-8621-integration-tests-common/pom.xml
+++ b/server/protocols/jmap-rfc-8621-integration-tests/jmap-rfc-8621-integration-tests-common/pom.xml
@@ -40,6 +40,10 @@
         </dependency>
         <dependency>
             <groupId>${james.groupId}</groupId>
+            <artifactId>james-server-dnsservice-test</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>${james.groupId}</groupId>
             <artifactId>james-server-guice-common</artifactId>
         </dependency>
         <dependency>
@@ -56,6 +60,10 @@
         </dependency>
         <dependency>
             <groupId>${james.groupId}</groupId>
+            <artifactId>mock-smtp-server</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>${james.groupId}</groupId>
             <artifactId>testing-base</artifactId>
         </dependency>
         <dependency>
diff --git a/server/protocols/jmap-rfc-8621-integration-tests/jmap-rfc-8621-integration-tests-common/src/main/scala/org/apache/james/jmap/rfc8621/contract/VacationRelayIntegrationTest.scala b/server/protocols/jmap-rfc-8621-integration-tests/jmap-rfc-8621-integration-tests-common/src/main/scala/org/apache/james/jmap/rfc8621/contract/VacationRelayIntegrationTest.scala
new file mode 100644
index 0000000..2a588fb
--- /dev/null
+++ b/server/protocols/jmap-rfc-8621-integration-tests/jmap-rfc-8621-integration-tests-common/src/main/scala/org/apache/james/jmap/rfc8621/contract/VacationRelayIntegrationTest.scala
@@ -0,0 +1,103 @@
+/****************************************************************
+ * 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.james.jmap.rfc8621.contract
+
+import java.util.concurrent.TimeUnit
+
+import com.github.fge.lambdas.Throwing
+import org.apache.commons.net.smtp.SMTPClient
+import org.apache.james.GuiceJamesServer
+import org.apache.james.core.MailAddress
+import org.apache.james.dnsservice.api.InMemoryDNSService
+import org.apache.james.jmap.JMAPTestingConstants.{DOMAIN, LOCALHOST_IP, calmlyAwait}
+import org.apache.james.jmap.JmapGuiceProbe
+import org.apache.james.jmap.api.model.AccountId
+import org.apache.james.jmap.rfc8621.contract.VacationRelayIntegrationTest.{PASSWORD, REASON, USER_WITH_DOMAIN}
+import org.apache.james.junit.categories.BasicFeature
+import org.apache.james.mailbox.DefaultMailboxes
+import org.apache.james.mailbox.model.MailboxConstants
+import org.apache.james.mock.smtp.server.model.Mail
+import org.apache.james.mock.smtp.server.testing.MockSmtpServerExtension
+import org.apache.james.modules.MailboxProbeImpl
+import org.apache.james.modules.protocols.SmtpGuiceProbe
+import org.apache.james.utils.DataProbeImpl
+import org.apache.james.vacation.api.VacationPatch
+import org.assertj.core.api.Assertions.assertThat
+import org.assertj.core.api.SoftAssertions
+import org.junit.experimental.categories.Category
+import org.junit.jupiter.api.{AfterEach, BeforeEach, Test}
+
+object VacationRelayIntegrationTest {
+  private val USER = "benwa"
+  private val USER_WITH_DOMAIN = USER + '@' + DOMAIN
+  private val PASSWORD = "secret"
+  private val REASON = "Message explaining my wonderful vacations"
+}
+
+trait VacationRelayIntegrationTest {
+  def getFakeSmtp: MockSmtpServerExtension
+  def getInMemoryDns: InMemoryDNSService
+
+  @BeforeEach
+  def setUp(server: GuiceJamesServer): Unit = {
+    getInMemoryDns.registerMxRecord("yopmail.com", getFakeSmtp.getMockSmtp.getIPAddress)
+
+    server.getProbe(classOf[DataProbeImpl])
+      .fluent
+      .addDomain(DOMAIN)
+      .addUser(USER_WITH_DOMAIN, PASSWORD)
+
+    val mailboxProbe = server.getProbe(classOf[MailboxProbeImpl])
+    mailboxProbe.createMailbox(MailboxConstants.USER_NAMESPACE, USER_WITH_DOMAIN, DefaultMailboxes.SENT)
+    mailboxProbe.createMailbox(MailboxConstants.USER_NAMESPACE, USER_WITH_DOMAIN, DefaultMailboxes.INBOX)
+  }
+
+  @AfterEach
+  def teardown(server: GuiceJamesServer): Unit = {
+    getFakeSmtp.getMockSmtp.getConfigurationClient.clearMails()
+    getFakeSmtp.getMockSmtp.getConfigurationClient.clearBehaviors()
+  }
+
+  @Category(Array(classOf[BasicFeature]))
+  @Test
+  def forwardingAnEmailShouldWork(server: GuiceJamesServer): Unit = {
+    server.getProbe(classOf[JmapGuiceProbe])
+      .modifyVacation(AccountId.fromString(USER_WITH_DOMAIN), VacationPatch.builder.isEnabled(true).textBody(REASON).build)
+
+    val externalMail = "ray@yopmail.com"
+
+    val smtpClient = new SMTPClient
+
+    smtpClient.connect(LOCALHOST_IP, server.getProbe(classOf[SmtpGuiceProbe]).getSmtpPort.getValue)
+    smtpClient.helo(DOMAIN)
+    smtpClient.setSender(externalMail)
+    smtpClient.rcpt("<" + USER_WITH_DOMAIN + ">")
+    smtpClient.sendShortMessageData("Reply-To: <" + externalMail + ">\r\n\r\ncontent")
+    calmlyAwait.atMost(1, TimeUnit.MINUTES).untilAsserted(() => {
+      val mails = getFakeSmtp.getMockSmtp.getConfigurationClient.listMails
+      assertThat(mails).hasSize(1)
+      SoftAssertions.assertSoftly(Throwing.consumer((softly: SoftAssertions) => {
+        softly.assertThat(mails.get(0).getEnvelope.getFrom).isEqualTo(MailAddress.nullSender)
+        softly.assertThat(mails.get(0).getEnvelope.getRecipients).containsOnly(Mail.Recipient.builder.address(new MailAddress(externalMail)).build)
+        softly.assertThat(mails.get(0).getMessage).contains(REASON)
+      }))
+    })
+  }
+}
diff --git a/server/protocols/jmap-rfc-8621-integration-tests/memory-jmap-rfc-8621-integration-tests/src/test/java/org/apache/james/jmap/rfc8621/memory/MemoryVacationRelayIntegrationTest.java b/server/protocols/jmap-rfc-8621-integration-tests/memory-jmap-rfc-8621-integration-tests/src/test/java/org/apache/james/jmap/rfc8621/memory/MemoryVacationRelayIntegrationTest.java
new file mode 100644
index 0000000..4035d34
--- /dev/null
+++ b/server/protocols/jmap-rfc-8621-integration-tests/memory-jmap-rfc-8621-integration-tests/src/test/java/org/apache/james/jmap/rfc8621/memory/MemoryVacationRelayIntegrationTest.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.james.jmap.rfc8621.memory;
+
+import static org.apache.james.data.UsersRepositoryModuleChooser.Implementation.DEFAULT;
+
+import org.apache.james.JamesServerBuilder;
+import org.apache.james.JamesServerExtension;
+import org.apache.james.MemoryJamesConfiguration;
+import org.apache.james.MemoryJamesServerMain;
+import org.apache.james.dnsservice.api.DNSService;
+import org.apache.james.dnsservice.api.InMemoryDNSService;
+import org.apache.james.jmap.rfc8621.contract.IdentityProbeModule;
+import org.apache.james.jmap.rfc8621.contract.VacationRelayIntegrationTest;
+import org.apache.james.jmap.rfc8621.contract.probe.DelegationProbeModule;
+import org.apache.james.mock.smtp.server.testing.MockSmtpServerExtension;
+import org.apache.james.modules.TestJMAPServerModule;
+import org.junit.jupiter.api.extension.RegisterExtension;
+
+public class MemoryVacationRelayIntegrationTest implements VacationRelayIntegrationTest {
+    private static final InMemoryDNSService inMemoryDNSService = new InMemoryDNSService();
+
+    @RegisterExtension
+    static MockSmtpServerExtension fakeSmtp = new MockSmtpServerExtension();
+
+    @RegisterExtension
+    static JamesServerExtension testExtension = new JamesServerBuilder<MemoryJamesConfiguration>(tmpDir ->
+        MemoryJamesConfiguration.builder()
+            .workingDirectory(tmpDir)
+            .configurationFromClasspath()
+            .usersRepository(DEFAULT)
+            .enableJMAP()
+            .build())
+        .server(configuration -> MemoryJamesServerMain.createServer(configuration)
+            .overrideWith(new TestJMAPServerModule(), new DelegationProbeModule(), new IdentityProbeModule())
+            .overrideWith((binder -> binder.bind(DNSService.class).toInstance(inMemoryDNSService))))
+        .build();
+
+    @Override
+    public MockSmtpServerExtension getFakeSmtp() {
+        return fakeSmtp;
+    }
+
+    @Override
+    public InMemoryDNSService getInMemoryDns() {
+        return inMemoryDNSService;
+    }
+}