From bba278ed1bdab731a311abfaa4fb2d362512c4a9 Mon Sep 17 00:00:00 2001 From: Houssem Nasri Date: Tue, 5 Nov 2024 04:48:54 +0100 Subject: [PATCH] Create a separate Guice module for OpenPaaS communication (#1261) --- tmail-backend/apps/distributed/pom.xml | 4 + .../app/DistributedJamesConfiguration.java | 13 ++ .../tmail/james/app/DistributedServer.java | 10 ++ ...verWithOpenPaasRabbitMqConfiguredTest.java | 44 +++++ tmail-backend/apps/memory/pom.xml | 33 +++- .../tmail/james/app/MemoryConfiguration.java | 13 ++ .../tmail/james/app/MemoryServer.java | 10 ++ ...verWithOpenPaasRabbitMqConfiguredTest.java | 39 ++++ tmail-backend/guice/distributed/pom.xml | 5 + .../tmail/james/app/TestRabbitMQModule.java | 14 ++ tmail-backend/pom.xml | 11 ++ .../tmail-third-party/openpaas/pom.xml | 1 + .../main/java/com/linagora/tmail/AmqpUri.java | 158 ++++++++++++++++ .../java/com/linagora/tmail/AmqpUserInfo.java | 16 ++ .../linagora/tmail/OpenPaasConfiguration.java | 6 - .../com/linagora/tmail/OpenPaasModule.java | 100 +++++++++++ .../OpenPaasModuleChooserConfiguration.java | 26 +++ .../tmail/api/OpenPaasRestClient.java | 11 +- .../configuration/OpenPaasConfiguration.java | 89 +++++++++ .../contact/OpenPaasContactsConsumer.java | 6 +- .../java/com/linagora/tmail/AmqpUriTest.java | 108 +++++++++++ .../OpenPaasConfigurationTest.java | 170 ++++++++++++++++++ .../contact/OpenPaasContactsConsumerTest.java | 6 +- .../tmail/api/OpenPaasRestClientTest.java | 15 +- 24 files changed, 885 insertions(+), 23 deletions(-) create mode 100644 tmail-backend/apps/distributed/src/test/java/com/linagora/tmail/james/app/DistributedServerWithOpenPaasRabbitMqConfiguredTest.java create mode 100644 tmail-backend/apps/memory/src/test/java/com/linagora/tmail/james/app/MemoryServerWithOpenPaasRabbitMqConfiguredTest.java create mode 100644 tmail-backend/tmail-third-party/openpaas/src/main/java/com/linagora/tmail/AmqpUri.java create mode 100644 tmail-backend/tmail-third-party/openpaas/src/main/java/com/linagora/tmail/AmqpUserInfo.java delete mode 100644 tmail-backend/tmail-third-party/openpaas/src/main/java/com/linagora/tmail/OpenPaasConfiguration.java create mode 100644 tmail-backend/tmail-third-party/openpaas/src/main/java/com/linagora/tmail/OpenPaasModule.java create mode 100644 tmail-backend/tmail-third-party/openpaas/src/main/java/com/linagora/tmail/OpenPaasModuleChooserConfiguration.java create mode 100644 tmail-backend/tmail-third-party/openpaas/src/main/java/com/linagora/tmail/configuration/OpenPaasConfiguration.java create mode 100644 tmail-backend/tmail-third-party/openpaas/src/test/java/com/linagora/tmail/AmqpUriTest.java create mode 100644 tmail-backend/tmail-third-party/openpaas/src/test/java/com/linagora/tmail/configuration/OpenPaasConfigurationTest.java diff --git a/tmail-backend/apps/distributed/pom.xml b/tmail-backend/apps/distributed/pom.xml index 933eb7ebf8..0c7f30c0f2 100644 --- a/tmail-backend/apps/distributed/pom.xml +++ b/tmail-backend/apps/distributed/pom.xml @@ -93,6 +93,10 @@ ${project.groupId} tmail-mailets + + ${project.groupId} + tmail-openpaas + ${project.groupId} tmail-rate-limiter-cassandra diff --git a/tmail-backend/apps/distributed/src/main/java/com/linagora/tmail/james/app/DistributedJamesConfiguration.java b/tmail-backend/apps/distributed/src/main/java/com/linagora/tmail/james/app/DistributedJamesConfiguration.java index 42da2d9e27..75ffc0d0f1 100644 --- a/tmail-backend/apps/distributed/src/main/java/com/linagora/tmail/james/app/DistributedJamesConfiguration.java +++ b/tmail-backend/apps/distributed/src/main/java/com/linagora/tmail/james/app/DistributedJamesConfiguration.java @@ -19,6 +19,7 @@ import org.apache.james.vault.VaultConfiguration; import com.github.fge.lambdas.Throwing; +import com.linagora.tmail.OpenPaasModuleChooserConfiguration; import com.linagora.tmail.blob.guice.BlobStoreConfiguration; import com.linagora.tmail.combined.identity.UsersRepositoryModuleChooser; import com.linagora.tmail.encrypted.MailboxConfiguration; @@ -33,6 +34,7 @@ public record DistributedJamesConfiguration(ConfigurationPath configurationPath, MailQueueViewChoice mailQueueViewChoice, FirebaseModuleChooserConfiguration firebaseModuleChooserConfiguration, LinagoraServicesDiscoveryModuleChooserConfiguration linagoraServicesDiscoveryModuleChooserConfiguration, + OpenPaasModuleChooserConfiguration openPaasModuleChooserConfiguration, boolean jmapEnabled, PropertiesProvider propertiesProvider, FileConfigurationProvider fileConfigurationProvider, @@ -50,6 +52,7 @@ public static class Builder { private Optional mailQueueViewChoice; private Optional firebaseModuleChooserConfiguration; private Optional linagoraServicesDiscoveryModuleChooserConfiguration; + private Optional openPaasModuleChooserConfiguration; private Optional jmapEnabled; private Optional eventBusKeysChoice; private Optional quotaCompatibilityMode; @@ -66,6 +69,7 @@ private Builder() { mailQueueViewChoice = Optional.empty(); firebaseModuleChooserConfiguration = Optional.empty(); linagoraServicesDiscoveryModuleChooserConfiguration = Optional.empty(); + openPaasModuleChooserConfiguration = Optional.empty(); jmapEnabled = Optional.empty(); quotaCompatibilityMode = Optional.empty(); eventBusKeysChoice = Optional.empty(); @@ -136,6 +140,11 @@ public Builder linagoraServicesDiscoveryModuleChooserConfiguration(LinagoraServi return this; } + public Builder openPassModuleChooserConfiguration(OpenPaasModuleChooserConfiguration openPaasModuleChooserConfiguration) { + this.openPaasModuleChooserConfiguration = Optional.of(openPaasModuleChooserConfiguration); + return this; + } + public Builder jmapEnabled(boolean enable) { this.jmapEnabled = Optional.of(enable); return this; @@ -193,6 +202,9 @@ public DistributedJamesConfiguration build() { LinagoraServicesDiscoveryModuleChooserConfiguration servicesDiscoveryModuleChooserConfiguration = this.linagoraServicesDiscoveryModuleChooserConfiguration .orElseGet(Throwing.supplier(() -> LinagoraServicesDiscoveryModuleChooserConfiguration.parse(propertiesProvider))); + OpenPaasModuleChooserConfiguration openPaasModuleChooserConfiguration = this.openPaasModuleChooserConfiguration + .orElseGet(Throwing.supplier(() -> OpenPaasModuleChooserConfiguration.parse(propertiesProvider))); + boolean jmapEnabled = this.jmapEnabled.orElseGet(() -> { try { return JMAPModule.parseConfiguration(propertiesProvider).isEnabled(); @@ -246,6 +258,7 @@ public DistributedJamesConfiguration build() { mailQueueViewChoice, firebaseModuleChooserConfiguration, servicesDiscoveryModuleChooserConfiguration, + openPaasModuleChooserConfiguration, jmapEnabled, propertiesProvider, configurationProvider, diff --git a/tmail-backend/apps/distributed/src/main/java/com/linagora/tmail/james/app/DistributedServer.java b/tmail-backend/apps/distributed/src/main/java/com/linagora/tmail/james/app/DistributedServer.java index 00ad7961de..fcbe320125 100644 --- a/tmail-backend/apps/distributed/src/main/java/com/linagora/tmail/james/app/DistributedServer.java +++ b/tmail-backend/apps/distributed/src/main/java/com/linagora/tmail/james/app/DistributedServer.java @@ -122,6 +122,8 @@ import com.google.inject.multibindings.ProvidesIntoSet; import com.google.inject.name.Names; import com.google.inject.util.Modules; +import com.linagora.tmail.OpenPaasModule; +import com.linagora.tmail.OpenPaasModuleChooserConfiguration; import com.linagora.tmail.ScheduledReconnectionHandler; import com.linagora.tmail.blob.guice.BlobStoreCacheModulesChooser; import com.linagora.tmail.blob.guice.BlobStoreConfiguration; @@ -361,6 +363,7 @@ public static GuiceJamesServer createServer(DistributedJamesConfiguration config .combineWith(UsersRepositoryModuleChooser.chooseModules(configuration.usersRepositoryImplementation())) .combineWith(chooseFirebase(configuration.firebaseModuleChooserConfiguration())) .combineWith(chooseLinagoraServicesDiscovery(configuration.linagoraServicesDiscoveryModuleChooserConfiguration())) + .combineWith(chooseOpenPaasModule(configuration.openPaasModuleChooserConfiguration())) .combineWith(chooseRedisRateLimiterModule(configuration)) .combineWith(chooseRspamdModule(configuration)) .combineWith(chooseQuotaModule(configuration)) @@ -462,6 +465,13 @@ private static List chooseLinagoraServicesDiscovery(LinagoraServicesDisc return List.of(); } + private static List chooseOpenPaasModule(OpenPaasModuleChooserConfiguration openPaasModuleChooserConfiguration) { + if (openPaasModuleChooserConfiguration.enabled()) { + return List.of(new OpenPaasModule()); + } + return List.of(); + } + private static List chooseRedisRateLimiterModule(DistributedJamesConfiguration configuration) { try { configuration.propertiesProvider().getConfiguration("redis"); diff --git a/tmail-backend/apps/distributed/src/test/java/com/linagora/tmail/james/app/DistributedServerWithOpenPaasRabbitMqConfiguredTest.java b/tmail-backend/apps/distributed/src/test/java/com/linagora/tmail/james/app/DistributedServerWithOpenPaasRabbitMqConfiguredTest.java new file mode 100644 index 0000000000..52a76a9416 --- /dev/null +++ b/tmail-backend/apps/distributed/src/test/java/com/linagora/tmail/james/app/DistributedServerWithOpenPaasRabbitMqConfiguredTest.java @@ -0,0 +1,44 @@ +package com.linagora.tmail.james.app; + +import org.apache.james.JamesServerBuilder; +import org.apache.james.JamesServerExtension; +import org.apache.james.SearchConfiguration; +import org.apache.james.backends.redis.RedisExtension; +import org.apache.james.utils.GuiceProbe; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.RegisterExtension; + +import com.google.inject.multibindings.Multibinder; + +import com.linagora.tmail.OpenPaasModuleChooserConfiguration; +import com.linagora.tmail.combined.identity.LdapExtension; +import com.linagora.tmail.combined.identity.UsersRepositoryClassProbe; +import com.linagora.tmail.combined.identity.UsersRepositoryModuleChooser; + +public class DistributedServerWithOpenPaasRabbitMqConfiguredTest { + @RegisterExtension + static JamesServerExtension + testExtension = new JamesServerBuilder(tmpDir -> + DistributedJamesConfiguration.builder() + .workingDirectory(tmpDir) + .configurationFromClasspath() + .searchConfiguration(SearchConfiguration.openSearch()) + .usersRepository(UsersRepositoryModuleChooser.Implementation.COMBINED) + .eventBusKeysChoice(EventBusKeysChoice.REDIS) + .openPassModuleChooserConfiguration(OpenPaasModuleChooserConfiguration.ENABLED) + .build()) + .server(configuration -> DistributedServer.createServer(configuration) + .overrideWith(binder -> Multibinder.newSetBinder(binder, GuiceProbe.class).addBinding().to(UsersRepositoryClassProbe.class))) + .extension(new DockerOpenSearchExtension()) + .extension(new CassandraExtension()) + .extension(new RabbitMQExtension()) + .extension(new LdapExtension()) + .extension(new RedisExtension()) + .lifeCycle(JamesServerExtension.Lifecycle.PER_CLASS) + .build(); + + @Test + void serverShouldStartWithOpenPaasRabbitMqConfigured() { + } + +} diff --git a/tmail-backend/apps/memory/pom.xml b/tmail-backend/apps/memory/pom.xml index d539e189e7..f51ee6cd60 100755 --- a/tmail-backend/apps/memory/pom.xml +++ b/tmail-backend/apps/memory/pom.xml @@ -53,6 +53,12 @@ ${project.groupId} team-mailboxes-guice + + ${project.groupId} + tmail-guice-distributed + test + test-jar + ${project.groupId} tmail-guice-jmap @@ -63,10 +69,24 @@ ${project.groupId} tmail-mailets + + ${project.groupId} + tmail-openpaas + + + ${project.groupId} + tmail-openpaas + test + test-jar + ${project.groupId} tmail-webadmin-mailbox + + ${project.groupId} + tmail-webadmin-team-mailboxes + ${project.groupId} webadmin-email-address-contact @@ -81,13 +101,15 @@ ${james.groupId} - apache-james-linshare + apache-james-backends-rabbitmq test-jar test - ${project.groupId} - tmail-webadmin-team-mailboxes + ${james.groupId} + apache-james-linshare + test-jar + test ${james.groupId} @@ -144,6 +166,11 @@ test-jar test + + ${james.groupId} + queue-rabbitmq-guice + test + com.linagora.tmail logback-json-classic diff --git a/tmail-backend/apps/memory/src/main/java/com/linagora/tmail/james/app/MemoryConfiguration.java b/tmail-backend/apps/memory/src/main/java/com/linagora/tmail/james/app/MemoryConfiguration.java index 9eb38a9abe..5752327405 100644 --- a/tmail-backend/apps/memory/src/main/java/com/linagora/tmail/james/app/MemoryConfiguration.java +++ b/tmail-backend/apps/memory/src/main/java/com/linagora/tmail/james/app/MemoryConfiguration.java @@ -17,6 +17,7 @@ import org.apache.james.utils.PropertiesProvider; import com.github.fge.lambdas.Throwing; +import com.linagora.tmail.OpenPaasModuleChooserConfiguration; import com.linagora.tmail.encrypted.MailboxConfiguration; import com.linagora.tmail.james.jmap.firebase.FirebaseModuleChooserConfiguration; import com.linagora.tmail.james.jmap.service.discovery.LinagoraServicesDiscoveryModuleChooserConfiguration; @@ -26,6 +27,7 @@ public record MemoryConfiguration(ConfigurationPath configurationPath, JamesDire UsersRepositoryModuleChooser.Implementation usersRepositoryImplementation, FirebaseModuleChooserConfiguration firebaseModuleChooserConfiguration, LinagoraServicesDiscoveryModuleChooserConfiguration linagoraServicesDiscoveryModuleChooserConfiguration, + OpenPaasModuleChooserConfiguration openPaasModuleChooserConfiguration, FileConfigurationProvider fileConfigurationProvider, boolean jmapEnabled, boolean dropListEnabled) implements Configuration { @@ -36,6 +38,7 @@ public static class Builder { private Optional usersRepositoryImplementation; private Optional firebaseModuleChooserConfiguration; private Optional linagoraServicesDiscoveryModuleChooserConfiguration; + private Optional openPaasModuleChooserConfiguration; private Optional jmapEnabled; private Optional dropListsEnabled; @@ -46,6 +49,7 @@ private Builder() { usersRepositoryImplementation = Optional.empty(); firebaseModuleChooserConfiguration = Optional.empty(); linagoraServicesDiscoveryModuleChooserConfiguration = Optional.empty(); + openPaasModuleChooserConfiguration = Optional.empty(); jmapEnabled = Optional.empty(); dropListsEnabled = Optional.empty(); } @@ -98,6 +102,11 @@ public Builder linagoraServiceDiscoveryModuleChooserConfiguration(LinagoraServic return this; } + public Builder openPaasModuleChooserConfiguration(OpenPaasModuleChooserConfiguration openPaasModuleChooserConfiguration) { + this.openPaasModuleChooserConfiguration = Optional.of(openPaasModuleChooserConfiguration); + return this; + } + public Builder jmapEnabled(boolean enable) { this.jmapEnabled = Optional.of(enable); return this; @@ -133,6 +142,9 @@ public MemoryConfiguration build() { LinagoraServicesDiscoveryModuleChooserConfiguration servicesDiscoveryModuleChooserConfiguration = this.linagoraServicesDiscoveryModuleChooserConfiguration.orElseGet(Throwing.supplier( () -> LinagoraServicesDiscoveryModuleChooserConfiguration.parse(new PropertiesProvider(fileSystem, configurationPath)))); + OpenPaasModuleChooserConfiguration openPaasModuleChooserConfiguration = this.openPaasModuleChooserConfiguration.orElseGet(Throwing.supplier( + () -> OpenPaasModuleChooserConfiguration.parse(new PropertiesProvider(fileSystem, configurationPath)))); + boolean jmapEnabled = this.jmapEnabled.orElseGet(() -> { PropertiesProvider propertiesProvider = new PropertiesProvider(fileSystem, configurationPath); try { @@ -162,6 +174,7 @@ public MemoryConfiguration build() { usersRepositoryChoice, firebaseModuleChooserConfiguration, servicesDiscoveryModuleChooserConfiguration, + openPaasModuleChooserConfiguration, configurationProvider, jmapEnabled, dropListsEnabled); diff --git a/tmail-backend/apps/memory/src/main/java/com/linagora/tmail/james/app/MemoryServer.java b/tmail-backend/apps/memory/src/main/java/com/linagora/tmail/james/app/MemoryServer.java index 5ce914631f..b75edcb7d6 100644 --- a/tmail-backend/apps/memory/src/main/java/com/linagora/tmail/james/app/MemoryServer.java +++ b/tmail-backend/apps/memory/src/main/java/com/linagora/tmail/james/app/MemoryServer.java @@ -45,6 +45,8 @@ import com.google.inject.Provides; import com.google.inject.Singleton; import com.google.inject.util.Modules; +import com.linagora.tmail.OpenPaasModule; +import com.linagora.tmail.OpenPaasModuleChooserConfiguration; import com.linagora.tmail.encrypted.ClearEmailContentFactory; import com.linagora.tmail.encrypted.EncryptedMailboxManager; import com.linagora.tmail.encrypted.InMemoryEncryptedEmailContentStore; @@ -184,6 +186,7 @@ public static GuiceJamesServer createServer(MemoryConfiguration configuration) { .chooseModules(configuration.usersRepositoryImplementation())) .combineWith(chooseFirebase(configuration.firebaseModuleChooserConfiguration())) .combineWith(chooseLinagoraServiceDiscovery(configuration.linagoraServicesDiscoveryModuleChooserConfiguration())) + .combineWith(chooseOpenPaas(configuration.openPaasModuleChooserConfiguration())) .combineWith(choosePop3ServerModule(configuration)) .overrideWith(chooseMailbox(configuration.mailboxConfiguration())) .overrideWith(chooseJmapModule(configuration)) @@ -229,6 +232,13 @@ private static List chooseLinagoraServiceDiscovery(LinagoraServicesDisco return List.of(); } + private static List chooseOpenPaas(OpenPaasModuleChooserConfiguration moduleChooserConfiguration) { + if (moduleChooserConfiguration.enabled()) { + return List.of(new OpenPaasModule()); + } + return List.of(); + } + private static Module chooseDropListsModule(MemoryConfiguration configuration) { if (configuration.dropListEnabled()) { return Modules.combine(new MemoryDropListsModule(), new DropListsRoutesModule()); diff --git a/tmail-backend/apps/memory/src/test/java/com/linagora/tmail/james/app/MemoryServerWithOpenPaasRabbitMqConfiguredTest.java b/tmail-backend/apps/memory/src/test/java/com/linagora/tmail/james/app/MemoryServerWithOpenPaasRabbitMqConfiguredTest.java new file mode 100644 index 0000000000..6f1ca489b6 --- /dev/null +++ b/tmail-backend/apps/memory/src/test/java/com/linagora/tmail/james/app/MemoryServerWithOpenPaasRabbitMqConfiguredTest.java @@ -0,0 +1,39 @@ +package com.linagora.tmail.james.app; + +import static org.apache.james.data.UsersRepositoryModuleChooser.Implementation.DEFAULT; + +import org.apache.james.JamesServerBuilder; +import org.apache.james.JamesServerExtension; +import org.apache.james.modules.queue.rabbitmq.RabbitMQModule; +import org.apache.james.utils.GuiceProbe; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.RegisterExtension; + +import com.google.inject.multibindings.Multibinder; +import com.linagora.tmail.OpenPaasModuleChooserConfiguration; +import com.linagora.tmail.encrypted.MailboxConfiguration; +import com.linagora.tmail.encrypted.MailboxManagerClassProbe; +import com.linagora.tmail.module.LinagoraTestJMAPServerModule; + +class MemoryServerWithOpenPaasRabbitMqConfiguredTest { + @RegisterExtension + static JamesServerExtension jamesServerExtension = new JamesServerBuilder(tmpDir -> + MemoryConfiguration.builder() + .workingDirectory(tmpDir) + .configurationFromClasspath() + .mailbox(new MailboxConfiguration(false)) + .usersRepository(DEFAULT) + .openPaasModuleChooserConfiguration(OpenPaasModuleChooserConfiguration.ENABLED) + .build()) + .server(configuration -> MemoryServer.createServer(configuration) + .overrideWith(new LinagoraTestJMAPServerModule()) + .overrideWith(binder -> Multibinder.newSetBinder(binder, GuiceProbe.class).addBinding().to(MailboxManagerClassProbe.class)) + .overrideWith(new RabbitMQModule())) + .extension(new RabbitMQExtension()) + .build(); + + @Test + public void serverShouldStartWithOpenPaasRabbitMqConfigured() { + + } +} \ No newline at end of file diff --git a/tmail-backend/guice/distributed/pom.xml b/tmail-backend/guice/distributed/pom.xml index 2640edad62..0e5afdf979 100644 --- a/tmail-backend/guice/distributed/pom.xml +++ b/tmail-backend/guice/distributed/pom.xml @@ -30,6 +30,11 @@ ${project.groupId} tmail-event-bus-redis + + ${project.groupId} + tmail-openpaas + test + ${james.groupId} apache-james-backends-redis diff --git a/tmail-backend/guice/distributed/src/test/java/com/linagora/tmail/james/app/TestRabbitMQModule.java b/tmail-backend/guice/distributed/src/test/java/com/linagora/tmail/james/app/TestRabbitMQModule.java index 3b72423f6d..4856c5afde 100644 --- a/tmail-backend/guice/distributed/src/test/java/com/linagora/tmail/james/app/TestRabbitMQModule.java +++ b/tmail-backend/guice/distributed/src/test/java/com/linagora/tmail/james/app/TestRabbitMQModule.java @@ -2,6 +2,7 @@ import static org.apache.james.backends.rabbitmq.RabbitMQFixture.DEFAULT_MANAGEMENT_CREDENTIAL; +import java.net.URI; import java.net.URISyntaxException; import java.time.Duration; @@ -18,6 +19,8 @@ import com.google.inject.AbstractModule; import com.google.inject.Provides; import com.google.inject.multibindings.Multibinder; +import com.linagora.tmail.AmqpUri; +import com.linagora.tmail.configuration.OpenPaasConfiguration; import com.linagora.tmail.james.jmap.RabbitMQEmailAddressContactConfiguration; public class TestRabbitMQModule extends AbstractModule { @@ -83,6 +86,17 @@ private RabbitMQMailQueueConfiguration getMailQueueSizeConfiguration() { return RabbitMQMailQueueConfiguration.sizeMetricsEnabled(); } + @Provides + @Singleton + public OpenPaasConfiguration provideOpenPaasConfiguration() throws URISyntaxException { + return new OpenPaasConfiguration( + AmqpUri.from(rabbitMQ.amqpUri()), + URI.create("http://localhost:8081"), + "user", + "password" + ); + } + public static class QueueCleanUp implements CleanupTasksPerformer.CleanupTask { private final RabbitMQMailQueueManagement api; diff --git a/tmail-backend/pom.xml b/tmail-backend/pom.xml index 5330924686..5ccfb56ced 100644 --- a/tmail-backend/pom.xml +++ b/tmail-backend/pom.xml @@ -171,6 +171,17 @@ test-jar ${project.version} + + ${project.groupId} + tmail-openpaas + ${project.version} + + + ${project.groupId} + tmail-openpaas + test-jar + ${project.version} + ${project.groupId} tmail-rate-limiter-cassandra diff --git a/tmail-backend/tmail-third-party/openpaas/pom.xml b/tmail-backend/tmail-third-party/openpaas/pom.xml index f1805f3017..af40ebfe31 100644 --- a/tmail-backend/tmail-third-party/openpaas/pom.xml +++ b/tmail-backend/tmail-third-party/openpaas/pom.xml @@ -7,6 +7,7 @@ com.linagora.tmail tmail-third-party 1.0.0-SNAPSHOT + ../../pom.xml tmail-openpaas diff --git a/tmail-backend/tmail-third-party/openpaas/src/main/java/com/linagora/tmail/AmqpUri.java b/tmail-backend/tmail-third-party/openpaas/src/main/java/com/linagora/tmail/AmqpUri.java new file mode 100644 index 0000000000..5a6e8b7da3 --- /dev/null +++ b/tmail-backend/tmail-third-party/openpaas/src/main/java/com/linagora/tmail/AmqpUri.java @@ -0,0 +1,158 @@ +package com.linagora.tmail; + +import java.net.URI; +import java.net.URISyntaxException; +import java.security.KeyManagementException; +import java.security.NoSuchAlgorithmException; +import java.util.Objects; +import java.util.Optional; + +import org.apache.james.backends.rabbitmq.RabbitMQConfiguration; + +import com.google.common.base.MoreObjects; +import com.google.common.base.Preconditions; +import com.rabbitmq.client.ConnectionFactory; + +/** + * The `AmqpUri` class represents an AMQP (Advanced Message Queuing Protocol) URI, which + * is used to configure a connection to a RabbitMQ message broker. + *

+ * This class handles the parsing and validation of the AMQP URI, and provides methods to extract + * relevant information from the URI, such as the username, password, and virtual host. + *

+ * Notes: + *

+ */ +public final class AmqpUri { + private final URI uri; + private final AmqpUserInfo userInfo; + private final Optional vhost; + private final ConnectionFactory connectionFactory; + + /** + * Constructs an `AmqpUri` object from the provided `URI`. + * + * @param uri the AMQP URI to be parsed and validated + * @throws RuntimeException if the provided URI is invalid + */ + public AmqpUri(URI uri) { + Preconditions.checkNotNull(uri); + connectionFactory = new ConnectionFactory(); + try { + connectionFactory.setUri(uri); + } catch (URISyntaxException | NoSuchAlgorithmException | KeyManagementException e) { + throw new RuntimeException(String.format("Invalid AmqpUri: '%s'", uri), e); + } + + this.uri = uri; + userInfo = new AmqpUserInfo(connectionFactory.getUsername(), connectionFactory.getPassword()); + vhost = Optional.ofNullable(connectionFactory.getVirtualHost()); + } + + /** + * Creates an `AmqpUri` object from the provided `URI`. + * + * @param uri the AMQP URI to be used + * @return an `AmqpUri` object representing the provided URI + */ + public static AmqpUri from(URI uri) { + return new AmqpUri(uri); + } + + /** + * Creates an `AmqpUri` object from the provided AMQP URI string. + * + * @param uri the AMQP URI string to be used + * @return an `AmqpUri` object representing the provided URI string + */ + public static AmqpUri from(String uri) { + return new AmqpUri(URI.create(uri)); + } + + /** + * Returns an `Optional` containing the current `AmqpUri` object. + * + * @return an `Optional` containing the `AmqpUri` object + */ + public Optional asOptional() { + return Optional.of(this); + } + + /** + * Returns the AMQP user information, including the username and password, + * extracted from the AMQP URI. + * + * @return an `AmqpUserInfo` object containing the username and password + */ + public AmqpUserInfo getUserInfo() { + return userInfo; + } + + /** + * Returns the virtual host specified in the AMQP URI, if any. + * + * @return an `Optional` containing the virtual host, or an empty `Optional` if not specified + */ + public Optional getVhost() { + return vhost; + } + + /** + * Returns the port number specified in the AMQP URI. + *

+ * If the port is not specified in the URI it falls back to RabbitMQ defaults: + * + *

  • AMQP --> 6572
  • + *
  • AMQPS --> 6571
  • + * + * + * @return the port number from the AMQP URI + */ + public int getPort() { + return connectionFactory.getPort(); + } + + /** + * Converts the `AmqpUri` object into a `RabbitMQConfiguration` object, which can be used to + * configure the RabbitMQ client. + * + * @return a `RabbitMQConfiguration` object representing the AMQP URI + */ + public RabbitMQConfiguration toRabbitMqConfiguration() { + return RabbitMQConfiguration.builder() + .amqpUri(uri) + .managementUri(uri) + .managementCredentials(userInfo.asManagementCredentials()) + .vhost(getVhost()) + .build(); + } + + @Override + public boolean equals(Object o) { + if (!(o instanceof AmqpUri amqpUri)) { + return false; + } + return Objects.equals(uri, amqpUri.uri) && + Objects.equals(userInfo, amqpUri.userInfo) && + Objects.equals(vhost, amqpUri.vhost); + } + + @Override + public int hashCode() { + return Objects.hash(uri, userInfo, vhost); + } + + @Override + public String toString() { + return MoreObjects.toStringHelper(this) + .add("amqpURI", uri) + .add("userInfo", userInfo) + .add("vhost", vhost) + .toString(); + } +} \ No newline at end of file diff --git a/tmail-backend/tmail-third-party/openpaas/src/main/java/com/linagora/tmail/AmqpUserInfo.java b/tmail-backend/tmail-third-party/openpaas/src/main/java/com/linagora/tmail/AmqpUserInfo.java new file mode 100644 index 0000000000..2aeb815d77 --- /dev/null +++ b/tmail-backend/tmail-third-party/openpaas/src/main/java/com/linagora/tmail/AmqpUserInfo.java @@ -0,0 +1,16 @@ +package com.linagora.tmail; + +import org.apache.james.backends.rabbitmq.RabbitMQConfiguration; + +import com.google.common.base.Preconditions; + +public record AmqpUserInfo(String username, String password) { + public AmqpUserInfo { + Preconditions.checkNotNull(username, "Amqp username is required."); + Preconditions.checkNotNull(password, "Amqp password is required."); + } + + public RabbitMQConfiguration.ManagementCredentials asManagementCredentials() { + return new RabbitMQConfiguration.ManagementCredentials(username, password.toCharArray()); + } +} diff --git a/tmail-backend/tmail-third-party/openpaas/src/main/java/com/linagora/tmail/OpenPaasConfiguration.java b/tmail-backend/tmail-third-party/openpaas/src/main/java/com/linagora/tmail/OpenPaasConfiguration.java deleted file mode 100644 index 65565a1f73..0000000000 --- a/tmail-backend/tmail-third-party/openpaas/src/main/java/com/linagora/tmail/OpenPaasConfiguration.java +++ /dev/null @@ -1,6 +0,0 @@ -package com.linagora.tmail; - -import java.net.URL; - -public record OpenPaasConfiguration(URL restClientUrl, String restClientUser, String restClientPassword) { -} diff --git a/tmail-backend/tmail-third-party/openpaas/src/main/java/com/linagora/tmail/OpenPaasModule.java b/tmail-backend/tmail-third-party/openpaas/src/main/java/com/linagora/tmail/OpenPaasModule.java new file mode 100644 index 0000000000..367b86289b --- /dev/null +++ b/tmail-backend/tmail-third-party/openpaas/src/main/java/com/linagora/tmail/OpenPaasModule.java @@ -0,0 +1,100 @@ +package com.linagora.tmail; + +import java.io.FileNotFoundException; + +import jakarta.inject.Named; +import jakarta.inject.Singleton; + +import org.apache.commons.configuration2.Configuration; +import org.apache.commons.configuration2.ex.ConfigurationException; +import org.apache.james.backends.rabbitmq.RabbitMQConfiguration; +import org.apache.james.backends.rabbitmq.RabbitMQConnectionFactory; +import org.apache.james.backends.rabbitmq.ReactorRabbitMQChannelPool; +import org.apache.james.backends.rabbitmq.SimpleConnectionPool; +import org.apache.james.metrics.api.GaugeRegistry; +import org.apache.james.metrics.api.MetricFactory; +import org.apache.james.utils.InitializationOperation; +import org.apache.james.utils.InitilizationOperationBuilder; +import org.apache.james.utils.PropertiesProvider; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import com.google.inject.AbstractModule; +import com.google.inject.Provides; +import com.google.inject.multibindings.ProvidesIntoSet; +import com.linagora.tmail.api.OpenPaasRestClient; +import com.linagora.tmail.configuration.OpenPaasConfiguration; +import com.linagora.tmail.contact.OpenPaasContactsConsumer; + +public class OpenPaasModule extends AbstractModule { + private static final Logger LOGGER = LoggerFactory.getLogger(OpenPaasModule.class); + public static final String OPENPAAS_INJECTION_KEY = "openpaas"; + public static final String OPENPAAS_CONFIGURATION_NAME = "openpaas"; + + @ProvidesIntoSet + public InitializationOperation initializeContactsConsumer(OpenPaasContactsConsumer instance) { + return InitilizationOperationBuilder + .forClass(OpenPaasContactsConsumer.class) + .init(instance::start); + } + + @Provides + @Named(OPENPAAS_CONFIGURATION_NAME) + @Singleton + public Configuration providePropertiesConfiguration(PropertiesProvider propertiesProvider) throws ConfigurationException { + try { + return propertiesProvider.getConfiguration(OPENPAAS_CONFIGURATION_NAME); + } catch (FileNotFoundException e) { + LOGGER.error("Could not find configuration file '{}.properties'", + OPENPAAS_CONFIGURATION_NAME); + throw new RuntimeException(e); + } + } + + @Provides + @Singleton + public OpenPaasConfiguration provideOpenPaasConfiguration(@Named(OPENPAAS_CONFIGURATION_NAME) Configuration propertiesConfiguration) { + return OpenPaasConfiguration.from(propertiesConfiguration); + } + + @Provides + public OpenPaasRestClient provideOpenPaasRestCLient(OpenPaasConfiguration openPaasConfiguration) { + return new OpenPaasRestClient(openPaasConfiguration); + } + + @Provides + @Named(OPENPAAS_INJECTION_KEY) + @Singleton + public RabbitMQConfiguration provideRabbitMQConfiguration(OpenPaasConfiguration openPaasConfiguration) { + return openPaasConfiguration.rabbitMqUri().toRabbitMqConfiguration(); + } + + @Provides + @Named(OPENPAAS_INJECTION_KEY) + @Singleton + public SimpleConnectionPool provideSimpleConnectionPool(@Named(OPENPAAS_INJECTION_KEY) RabbitMQConfiguration rabbitMQConfiguration) { + RabbitMQConnectionFactory rabbitMQConnectionFactory = new RabbitMQConnectionFactory(rabbitMQConfiguration); + try { + return new SimpleConnectionPool(rabbitMQConnectionFactory, SimpleConnectionPool.Configuration.DEFAULT); + } catch (Exception e) { + LOGGER.info("Error while retrieving SimpleConnectionPool.Configuration, falling back to defaults.", e); + return new SimpleConnectionPool(rabbitMQConnectionFactory, SimpleConnectionPool.Configuration.DEFAULT); + } + } + + @Provides + @Named(OPENPAAS_INJECTION_KEY) + @Singleton + public ReactorRabbitMQChannelPool provideReactorRabbitMQChannelPool( + @Named(OPENPAAS_INJECTION_KEY) SimpleConnectionPool simpleConnectionPool, + MetricFactory metricFactory, GaugeRegistry gaugeRegistry) { + + ReactorRabbitMQChannelPool channelPool = new ReactorRabbitMQChannelPool( + simpleConnectionPool.getResilientConnection(), + ReactorRabbitMQChannelPool.Configuration.DEFAULT, + metricFactory, + gaugeRegistry); + channelPool.start(); + return channelPool; + } +} diff --git a/tmail-backend/tmail-third-party/openpaas/src/main/java/com/linagora/tmail/OpenPaasModuleChooserConfiguration.java b/tmail-backend/tmail-third-party/openpaas/src/main/java/com/linagora/tmail/OpenPaasModuleChooserConfiguration.java new file mode 100644 index 0000000000..6dca6a4ccf --- /dev/null +++ b/tmail-backend/tmail-third-party/openpaas/src/main/java/com/linagora/tmail/OpenPaasModuleChooserConfiguration.java @@ -0,0 +1,26 @@ +package com.linagora.tmail; + +import java.io.FileNotFoundException; + +import org.apache.commons.configuration2.ex.ConfigurationException; +import org.apache.james.utils.PropertiesProvider; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public record OpenPaasModuleChooserConfiguration(boolean enabled) { + private static final Logger LOGGER = LoggerFactory.getLogger(OpenPaasModuleChooserConfiguration.class); + public static final OpenPaasModuleChooserConfiguration ENABLED = new OpenPaasModuleChooserConfiguration(true); + public static final OpenPaasModuleChooserConfiguration DISABLED = new OpenPaasModuleChooserConfiguration(false); + + public static OpenPaasModuleChooserConfiguration parse(PropertiesProvider propertiesProvider) throws + ConfigurationException { + try { + propertiesProvider.getConfiguration("openpaas"); + LOGGER.info("OpenPaas module is turned on."); + return ENABLED; + } catch (FileNotFoundException e) { + LOGGER.info("OpenPaas module is turned off."); + return DISABLED; + } + } +} diff --git a/tmail-backend/tmail-third-party/openpaas/src/main/java/com/linagora/tmail/api/OpenPaasRestClient.java b/tmail-backend/tmail-third-party/openpaas/src/main/java/com/linagora/tmail/api/OpenPaasRestClient.java index 02f70a7e61..f6eb155cf1 100644 --- a/tmail-backend/tmail-third-party/openpaas/src/main/java/com/linagora/tmail/api/OpenPaasRestClient.java +++ b/tmail-backend/tmail-third-party/openpaas/src/main/java/com/linagora/tmail/api/OpenPaasRestClient.java @@ -1,6 +1,6 @@ package com.linagora.tmail.api; -import java.net.URL; +import java.net.URI; import java.nio.charset.StandardCharsets; import java.time.Duration; @@ -13,7 +13,7 @@ import com.fasterxml.jackson.core.JsonProcessingException; import com.fasterxml.jackson.databind.ObjectMapper; import com.linagora.tmail.HttpUtils; -import com.linagora.tmail.OpenPaasConfiguration; +import com.linagora.tmail.configuration.OpenPaasConfiguration; import reactor.core.publisher.Mono; import reactor.netty.ByteBufMono; @@ -29,9 +29,10 @@ public class OpenPaasRestClient { private final ObjectMapper deserializer = new ObjectMapper(); public OpenPaasRestClient(OpenPaasConfiguration openPaasConfiguration) { - URL apiUrl = openPaasConfiguration.restClientUrl(); - String user = openPaasConfiguration.restClientUser(); - String password = openPaasConfiguration.restClientPassword(); + URI apiUrl = openPaasConfiguration.apirUri(); + String user = openPaasConfiguration.adminUsername(); + String password = openPaasConfiguration.adminPassword(); + this.client = HttpClient.create() .baseUrl(apiUrl.toString()) .headers(headers -> headers.add(AUTHORIZATION_HEADER, HttpUtils.createBasicAuthenticationToken(user, password))) diff --git a/tmail-backend/tmail-third-party/openpaas/src/main/java/com/linagora/tmail/configuration/OpenPaasConfiguration.java b/tmail-backend/tmail-third-party/openpaas/src/main/java/com/linagora/tmail/configuration/OpenPaasConfiguration.java new file mode 100644 index 0000000000..b10dd7ff70 --- /dev/null +++ b/tmail-backend/tmail-third-party/openpaas/src/main/java/com/linagora/tmail/configuration/OpenPaasConfiguration.java @@ -0,0 +1,89 @@ +package com.linagora.tmail.configuration; + +import java.net.MalformedURLException; +import java.net.URI; + +import org.apache.commons.configuration2.Configuration; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import com.linagora.tmail.AmqpUri; + +import spark.utils.StringUtils; + +public record OpenPaasConfiguration( + AmqpUri rabbitMqUri, + URI apirUri, + String adminUsername, + String adminPassword) { + private static final Logger LOGGER = LoggerFactory.getLogger(OpenPaasConfiguration.class); + private static final String RABBITMQ_URI_PROPERTY = "rabbitmq.uri"; + private static final String OPENPAAS_API_URI = "openpaas.api.uri"; + private static final String OPENPAAS_ADMIN_USER_PROPERTY = "openpaas.admin.user"; + private static final String OPENPAAS_ADMIN_PASSWORD_PROPERTY = "openpaas.admin.password"; + + public static OpenPaasConfiguration from(Configuration configuration) { + AmqpUri rabbitMqUri = readRabbitMqUri(configuration); + URI openPaasApiUri = readApiUri(configuration); + String adminUser = readAdminUsername(configuration); + String adminPassword = readAdminPassword(configuration); + + return new OpenPaasConfiguration(rabbitMqUri, openPaasApiUri, adminUser, adminPassword); + } + + private static AmqpUri readRabbitMqUri(Configuration configuration) { + String rabbitMqUri = configuration.getString(RABBITMQ_URI_PROPERTY); + if (StringUtils.isBlank(rabbitMqUri)) { + throw new IllegalStateException("RabbitMQ URI not defined in openpaas.properties."); + } + + try { + return AmqpUri.from(URI.create(rabbitMqUri)); + } catch (IllegalArgumentException e) { + throw new IllegalStateException("Invalid RabbitMQ URI in openpaas.properties."); + } + } + + private static URI readApiUri(Configuration configuration) { + String openPaasApiUri = configuration.getString(OPENPAAS_API_URI); + if (StringUtils.isBlank(openPaasApiUri)) { + throw new IllegalStateException("OpenPaas API URI not specified."); + } + + try { + return validateURI(URI.create(openPaasApiUri)); + } catch (Exception e) { + throw new IllegalStateException("Invalid OpenPaas API URI in openpaas.properties."); + } + } + + private static URI validateURI(URI uri) { + try { + // Otherwise, BAD_URI would be considered a valid URI. + uri.toURL(); + return uri; + } catch (MalformedURLException | IllegalArgumentException e) { + throw new IllegalArgumentException("Bad URI!", e); + } + } + + private static String readAdminUsername(Configuration configuration) { + String openPaasAdminUser = configuration.getString(OPENPAAS_ADMIN_USER_PROPERTY); + + if (StringUtils.isBlank(openPaasAdminUser)) { + throw new IllegalStateException("OpenPaas admin user not specified."); + } + + return openPaasAdminUser; + } + + private static String readAdminPassword(Configuration configuration) { + String openPaasAdminPassword = configuration.getString(OPENPAAS_ADMIN_PASSWORD_PROPERTY); + if (StringUtils.isBlank(openPaasAdminPassword)) { + throw new IllegalStateException("OpenPaas admin password not specified."); + } + + return openPaasAdminPassword; + } + +} diff --git a/tmail-backend/tmail-third-party/openpaas/src/main/java/com/linagora/tmail/contact/OpenPaasContactsConsumer.java b/tmail-backend/tmail-third-party/openpaas/src/main/java/com/linagora/tmail/contact/OpenPaasContactsConsumer.java index b569979703..c25b769855 100644 --- a/tmail-backend/tmail-third-party/openpaas/src/main/java/com/linagora/tmail/contact/OpenPaasContactsConsumer.java +++ b/tmail-backend/tmail-third-party/openpaas/src/main/java/com/linagora/tmail/contact/OpenPaasContactsConsumer.java @@ -1,5 +1,6 @@ package com.linagora.tmail.contact; +import static com.linagora.tmail.OpenPaasModule.OPENPAAS_INJECTION_KEY; import static org.apache.james.backends.rabbitmq.Constants.DURABLE; import static org.apache.james.backends.rabbitmq.Constants.EMPTY_ROUTING_KEY; @@ -7,6 +8,7 @@ import java.util.Optional; import jakarta.inject.Inject; +import jakarta.inject.Named; import org.apache.james.backends.rabbitmq.RabbitMQConfiguration; import org.apache.james.backends.rabbitmq.ReactorRabbitMQChannelPool; @@ -53,8 +55,8 @@ public class OpenPaasContactsConsumer implements Startable, Closeable { private Disposable consumeContactsDisposable; @Inject - public OpenPaasContactsConsumer(ReactorRabbitMQChannelPool channelPool, - RabbitMQConfiguration commonRabbitMQConfiguration, + public OpenPaasContactsConsumer(@Named(OPENPAAS_INJECTION_KEY) ReactorRabbitMQChannelPool channelPool, + @Named(OPENPAAS_INJECTION_KEY) RabbitMQConfiguration commonRabbitMQConfiguration, EmailAddressContactSearchEngine contactSearchEngine, OpenPaasRestClient openPaasRestClient) { this.receiverProvider = channelPool::createReceiver; diff --git a/tmail-backend/tmail-third-party/openpaas/src/test/java/com/linagora/tmail/AmqpUriTest.java b/tmail-backend/tmail-third-party/openpaas/src/test/java/com/linagora/tmail/AmqpUriTest.java new file mode 100644 index 0000000000..7f64e80fe0 --- /dev/null +++ b/tmail-backend/tmail-third-party/openpaas/src/test/java/com/linagora/tmail/AmqpUriTest.java @@ -0,0 +1,108 @@ +package com.linagora.tmail; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.assertThatCode; + +import java.util.stream.Stream; + +import nl.jqno.equalsverifier.EqualsVerifier; + +import org.assertj.core.api.Assertions; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.Arguments; +import org.junit.jupiter.params.provider.MethodSource; + +import com.rabbitmq.client.ConnectionFactory; + +class AmqpUriTest { + private static Stream goodAmqpURIs() { + return Stream.of( + Arguments.of("amqp://guest:guest@localhost:5672/"), + Arguments.of("amqp://user:password@host:port/vhost"), + Arguments.of("amqps://user:password@securehost:5671/securevhost"), // Using AMQPS for secure connection + Arguments.of("amqp://@localhost:5672/"), + Arguments.of("amqp://:password@host"), + Arguments.of("amqp://user@host")); + } + + private static Stream badAmqpURIs() { + return Stream.of( + Arguments.of("http://guest:guest@localhost:5672/"), // Wrong protocol + Arguments.of("amqp://user:pass@host:5672/extra/path"), // Extra path element + Arguments.of("BAD_URI")); // Just bad + } + + @ParameterizedTest + @MethodSource("goodAmqpURIs") + void testGoodAmpqUriString(String amqpUri) { + assertThatCode(() -> AmqpUri.from(amqpUri)) + .doesNotThrowAnyException(); + } + + @ParameterizedTest + @MethodSource("badAmqpURIs") + void testBadAmpqUriString(String amqpUri) { + Assertions.assertThatThrownBy(() -> AmqpUri.from(amqpUri)); + } + + @Test + void shouldRespectBeanContract() throws Exception { + ConnectionFactory red = new ConnectionFactory(); + ConnectionFactory blue = new ConnectionFactory(); + + red.setUri("amqp://username@rabbitmq.com"); + blue.setUri("amqp://rabbitmq_test.com"); + + EqualsVerifier + .forClass(AmqpUri.class) + .withIgnoredFields("connectionFactory") + .withPrefabValues(ConnectionFactory.class, red, blue) + .verify(); + } + + @Test + void shouldUseEmptyUsernameWhenUsernameIsMissing() { + AmqpUri uri = AmqpUri.from("amqp://:password@rabbitmq.com/vhost"); + + assertThat(uri.getUserInfo().username()).isEqualTo(""); + assertThat(uri.getUserInfo().password()).isEqualTo("password"); + } + + @Test + void shouldUseTheDefaultPasswordWhenPasswordIsMissing() { + AmqpUri uri = AmqpUri.from("amqp://user@rabbitmq.com/vhost"); + + assertThat(uri.getUserInfo().username()).isEqualTo("user"); + assertThat(uri.getUserInfo().password()).isEqualTo("guest"); + } + + @Test + void shouldUseTheDefaultCredentialsWhenCredentialsIsMissing() { + AmqpUri uri = AmqpUri.from("amqp://rabbitmq.com/vhost"); + + assertThat(uri.getUserInfo().username()).isEqualTo("guest"); + assertThat(uri.getUserInfo().password()).isEqualTo("guest"); + } + + @Test + void shouldUsePort5672WhenAmqpIsUsedAndPortIsMissing() { + AmqpUri uri = AmqpUri.from("amqp://user:pass@rabbitmq.com/vhost"); + + assertThat(uri.getPort()).isEqualTo(5672); + } + + @Test + void shouldUseSpecificPortWhenSpecified() { + AmqpUri uri = AmqpUri.from("amqp://user:password@rabbitmq.com:1000/vhost"); + + assertThat(uri.getPort()).isEqualTo(1000); + } + + @Test + void shouldUsePort5671WhenAmqpOverSslIsUsedAndPortIsMissing() { + AmqpUri uri = AmqpUri.from("amqps://user:pass@rabbitmq.com/vhost"); + + assertThat(uri.getPort()).isEqualTo(5671); + } +} \ No newline at end of file diff --git a/tmail-backend/tmail-third-party/openpaas/src/test/java/com/linagora/tmail/configuration/OpenPaasConfigurationTest.java b/tmail-backend/tmail-third-party/openpaas/src/test/java/com/linagora/tmail/configuration/OpenPaasConfigurationTest.java new file mode 100644 index 0000000000..ddae575a27 --- /dev/null +++ b/tmail-backend/tmail-third-party/openpaas/src/test/java/com/linagora/tmail/configuration/OpenPaasConfigurationTest.java @@ -0,0 +1,170 @@ +package com.linagora.tmail.configuration; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.assertThatThrownBy; + +import java.net.URI; + +import org.apache.commons.configuration2.PropertiesConfiguration; +import org.junit.jupiter.api.Test; + +import com.linagora.tmail.AmqpUri; + +import nl.jqno.equalsverifier.EqualsVerifier; + +class OpenPaasConfigurationTest { + + @Test + void shouldRespectBeanContract() { + AmqpUri red = AmqpUri.from("amqp://rabbitmq.com"); + AmqpUri blue = AmqpUri.from("amqp://rabbitmq_test.com"); + EqualsVerifier.forClass(OpenPaasConfiguration.class) + .withPrefabValues(AmqpUri.class, red, blue) + .verify(); + } + + @Test + void fromShouldReturnTheConfigurationWhenAllParametersAreGiven() { + PropertiesConfiguration configuration = new PropertiesConfiguration(); + configuration.addProperty("rabbitmq.uri", "amqp://james:james@rabbitmqhost:5672"); + configuration.addProperty("openpaas.api.uri", "http://localhost:8080"); + configuration.addProperty("openpaas.admin.user", "jhon_doe"); + configuration.addProperty("openpaas.admin.password", "123"); + + OpenPaasConfiguration expected = new OpenPaasConfiguration( + AmqpUri.from("amqp://james:james@rabbitmqhost:5672"), + URI.create("http://localhost:8080"), + "jhon_doe", + "123" + ); + + assertThat(OpenPaasConfiguration.from(configuration)) + .isEqualTo(expected); + } + + @Test + void fromShouldThrowWhenOpenPaasApiUriNotConfigured() { + PropertiesConfiguration configuration = new PropertiesConfiguration(); + configuration.addProperty("rabbitmq.uri", "amqp://james:james@rabbitmqhost:5672"); + configuration.addProperty("openpaas.admin.user", "jhon_doe"); + configuration.addProperty("openpaas.admin.password", "123"); + + assertThatThrownBy(() -> OpenPaasConfiguration.from(configuration)) + .isInstanceOf(IllegalStateException.class) + .hasMessage("OpenPaas API URI not specified."); + } + + @Test + void fromShouldThrowWhenOpenPaasApiUriIsBlank() { + PropertiesConfiguration configuration = new PropertiesConfiguration(); + configuration.addProperty("rabbitmq.uri", "amqp://james:james@rabbitmqhost:5672"); + configuration.addProperty("openpaas.admin.user", "jhon_doe"); + configuration.addProperty("openpaas.api.uri", " "); + configuration.addProperty("openpaas.admin.password", "123"); + + assertThatThrownBy(() -> OpenPaasConfiguration.from(configuration)) + .isInstanceOf(IllegalStateException.class) + .hasMessage("OpenPaas API URI not specified."); + } + + @Test + void fromShouldThrowWhenOpenPaasApiUriIsInvalid() { + PropertiesConfiguration configuration = new PropertiesConfiguration(); + configuration.addProperty("rabbitmq.uri", "amqp://james:james@rabbitmqhost:5672"); + configuration.addProperty("openpaas.admin.user", "jhon_doe"); + configuration.addProperty("openpaas.api.uri", "BAD_URI"); + configuration.addProperty("openpaas.admin.password", "123"); + + assertThatThrownBy(() -> OpenPaasConfiguration.from(configuration)) + .isInstanceOf(IllegalStateException.class) + .hasMessage("Invalid OpenPaas API URI in openpaas.properties."); + } + + @Test + void fromShouldThrowWhenOpenPaasAdminUserNotConfigured() { + PropertiesConfiguration configuration = new PropertiesConfiguration(); + configuration.addProperty("rabbitmq.uri", "amqp://james:james@rabbitmqhost:5672"); + configuration.addProperty("openpaas.api.uri", "http://localhost:8080"); + configuration.addProperty("openpaas.admin.password", "123"); + + assertThatThrownBy(() -> OpenPaasConfiguration.from(configuration)) + .isInstanceOf(IllegalStateException.class) + .hasMessage("OpenPaas admin user not specified."); + } + + @Test + void fromShouldThrowWhenOpenPaasAdminUserIsBlank() { + PropertiesConfiguration configuration = new PropertiesConfiguration(); + configuration.addProperty("rabbitmq.uri", "amqp://james:james@rabbitmqhost:5672"); + configuration.addProperty("openpaas.api.uri", "http://localhost:8080"); + configuration.addProperty("openpaas.admin.user", " "); + configuration.addProperty("openpaas.admin.password", "123"); + + assertThatThrownBy(() -> OpenPaasConfiguration.from(configuration)) + .isInstanceOf(IllegalStateException.class) + .hasMessage("OpenPaas admin user not specified."); + } + + @Test + void fromShouldThrowWhenOpenPaasAdminPasswordNotConfigured() { + PropertiesConfiguration configuration = new PropertiesConfiguration(); + configuration.addProperty("rabbitmq.uri", "amqp://james:james@rabbitmqhost:5672"); + configuration.addProperty("openpaas.api.uri", "http://localhost:8080"); + configuration.addProperty("openpaas.admin.user", "jhon_doe"); + + assertThatThrownBy(() -> OpenPaasConfiguration.from(configuration)) + .isInstanceOf(IllegalStateException.class) + .hasMessage("OpenPaas admin password not specified."); + } + + @Test + void fromShouldThrowWhenOpenPaasAdminPasswordIsBlank() { + PropertiesConfiguration configuration = new PropertiesConfiguration(); + configuration.addProperty("rabbitmq.uri", "amqp://james:james@rabbitmqhost:5672"); + configuration.addProperty("openpaas.api.uri", "http://localhost:8080"); + configuration.addProperty("openpaas.admin.user", "jhon_doe"); + configuration.addProperty("openpaas.admin.password", " "); + + assertThatThrownBy(() -> OpenPaasConfiguration.from(configuration)) + .isInstanceOf(IllegalStateException.class) + .hasMessage("OpenPaas admin password not specified."); + } + + @Test + void fromShouldCrashWhenRabbitMqURINotConfigured() { + PropertiesConfiguration configuration = new PropertiesConfiguration(); + configuration.addProperty("openpaas.api.uri", "http://localhost:8080"); + configuration.addProperty("openpaas.admin.user", "jhon_doe"); + configuration.addProperty("openpaas.admin.password", "123"); + + assertThatThrownBy(() -> OpenPaasConfiguration.from(configuration)) + .isInstanceOf(IllegalStateException.class) + .hasMessage("RabbitMQ URI not defined in openpaas.properties."); + } + + @Test + void fromShouldCrashWhenRabbitMqUriIsBlank() { + PropertiesConfiguration configuration = new PropertiesConfiguration(); + configuration.addProperty("rabbitmq.uri", " "); + configuration.addProperty("openpaas.api.uri", "http://localhost:8080"); + configuration.addProperty("openpaas.admin.user", "jhon_doe"); + configuration.addProperty("openpaas.admin.password", "123"); + + assertThatThrownBy(() -> OpenPaasConfiguration.from(configuration)) + .isInstanceOf(IllegalStateException.class) + .hasMessage("RabbitMQ URI not defined in openpaas.properties."); + } + + @Test + void fromShouldThrowWhenConfiguredRabbitMqURIisInvalid() { + PropertiesConfiguration configuration = new PropertiesConfiguration(); + configuration.addProperty("rabbitmq.uri", "BAD_SCHEME://james:james@rabbitmqhost:5672"); + configuration.addProperty("openpaas.api.uri", "http://localhost:8080"); + configuration.addProperty("openpaas.admin.user", "jhon_doe"); + configuration.addProperty("openpaas.admin.password", "123"); + + assertThatThrownBy(() -> OpenPaasConfiguration.from(configuration)) + .isInstanceOf(IllegalStateException.class) + .hasMessage("Invalid RabbitMQ URI in openpaas.properties."); + } +} \ No newline at end of file diff --git a/tmail-backend/tmail-third-party/openpaas/src/test/java/com/linagora/tmail/contact/OpenPaasContactsConsumerTest.java b/tmail-backend/tmail-third-party/openpaas/src/test/java/com/linagora/tmail/contact/OpenPaasContactsConsumerTest.java index 42e5971df6..134b3235f3 100644 --- a/tmail-backend/tmail-third-party/openpaas/src/test/java/com/linagora/tmail/contact/OpenPaasContactsConsumerTest.java +++ b/tmail-backend/tmail-third-party/openpaas/src/test/java/com/linagora/tmail/contact/OpenPaasContactsConsumerTest.java @@ -27,7 +27,8 @@ import jakarta.mail.internet.AddressException; import com.github.fge.lambdas.Throwing; -import com.linagora.tmail.OpenPaasConfiguration; +import com.linagora.tmail.AmqpUri; +import com.linagora.tmail.configuration.OpenPaasConfiguration; import com.linagora.tmail.api.OpenPaasRestClient; import com.linagora.tmail.api.OpenPaasServerExtension; import com.linagora.tmail.james.jmap.contact.ContactFields; @@ -51,7 +52,8 @@ class OpenPaasContactsConsumerTest { void setup() throws URISyntaxException { OpenPaasRestClient restClient = new OpenPaasRestClient( new OpenPaasConfiguration( - openPaasServerExtension.getBaseUrl(), + AmqpUri.from(rabbitMQExtension.getRabbitMQ().amqpUri()), + openPaasServerExtension.getBaseUrl().toURI(), OpenPaasServerExtension.GOOD_USER(), OpenPaasServerExtension.GOOD_PASSWORD())); searchEngine = new InMemoryEmailAddressContactSearchEngine(); diff --git a/tmail-backend/tmail-third-party/openpaas/src/test/scala/com/linagora/tmail/api/OpenPaasRestClientTest.java b/tmail-backend/tmail-third-party/openpaas/src/test/scala/com/linagora/tmail/api/OpenPaasRestClientTest.java index 68f0a91748..b8ca7c7006 100644 --- a/tmail-backend/tmail-third-party/openpaas/src/test/scala/com/linagora/tmail/api/OpenPaasRestClientTest.java +++ b/tmail-backend/tmail-third-party/openpaas/src/test/scala/com/linagora/tmail/api/OpenPaasRestClientTest.java @@ -1,5 +1,7 @@ package com.linagora.tmail.api; +import java.net.URISyntaxException; +import java.util.Optional; import static org.assertj.core.api.AssertionsForClassTypes.assertThat; import static org.assertj.core.api.AssertionsForClassTypes.assertThatThrownBy; @@ -10,7 +12,8 @@ import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.RegisterExtension; -import com.linagora.tmail.OpenPaasConfiguration; +import com.linagora.tmail.AmqpUri; +import com.linagora.tmail.configuration.OpenPaasConfiguration; public class OpenPaasRestClientTest { public static final String BAD_USER_ID = "BAD_ID"; @@ -20,9 +23,10 @@ public class OpenPaasRestClientTest { OpenPaasRestClient restClient; @BeforeEach - void setup() { + void setup() throws URISyntaxException { OpenPaasConfiguration openPaasConfig = new OpenPaasConfiguration( - openPaasServerExtension.getBaseUrl(), + AmqpUri.from("amqp://not_important.com"), + openPaasServerExtension.getBaseUrl().toURI(), OpenPaasServerExtension.GOOD_USER(), OpenPaasServerExtension.GOOD_PASSWORD()); @@ -42,9 +46,10 @@ void shouldReturnEmptyMonoWhenUserWithIdNotFound() { } @Test - void shouldThrowExceptionOnErrorStatusCode() { + void shouldThrowExceptionOnErrorStatusCode() throws URISyntaxException { OpenPaasConfiguration openPaasConfig = new OpenPaasConfiguration( - openPaasServerExtension.getBaseUrl(), + AmqpUri.from("amqp://not_important.com"), + openPaasServerExtension.getBaseUrl().toURI(), OpenPaasServerExtension.BAD_USER(), OpenPaasServerExtension.BAD_PASSWORD());