You are viewing a plain text version of this content. The canonical link for it is here.
Posted to notifications@james.apache.org by rc...@apache.org on 2023/08/30 07:50:52 UTC
[james-project] 03/10: JAMES-3926 Implement CassandraCurrentQuotaManagerMigration
This is an automated email from the ASF dual-hosted git repository.
rcordier pushed a commit to branch james-3926-mailbox-current-quotas
in repository https://gitbox.apache.org/repos/asf/james-project.git
commit a2e1b0f0a0fe36d798d7e30ad3c84bd9696f4f5a
Author: Rene Cordier <rc...@linagora.com>
AuthorDate: Fri Aug 25 17:27:42 2023 +0700
JAMES-3926 Implement CassandraCurrentQuotaManagerMigration
---
mailbox/cassandra/pom.xml | 10 ++
.../CassandraCurrentQuotaManagerMigration.java | 67 +++++++++++
.../CassandraCurrentQuotaManagerMigrationTest.java | 124 +++++++++++++++++++++
3 files changed, 201 insertions(+)
diff --git a/mailbox/cassandra/pom.xml b/mailbox/cassandra/pom.xml
index 22255438ea..101c1c92aa 100644
--- a/mailbox/cassandra/pom.xml
+++ b/mailbox/cassandra/pom.xml
@@ -111,11 +111,21 @@
<type>test-jar</type>
<scope>test</scope>
</dependency>
+ <dependency>
+ <groupId>${james.groupId}</groupId>
+ <artifactId>james-server-data-api</artifactId>
+ </dependency>
<dependency>
<groupId>${james.groupId}</groupId>
<artifactId>james-server-data-cassandra</artifactId>
<scope>test</scope>
</dependency>
+ <dependency>
+ <groupId>${james.groupId}</groupId>
+ <artifactId>james-server-data-library</artifactId>
+ <type>test-jar</type>
+ <scope>test</scope>
+ </dependency>
<dependency>
<groupId>${james.groupId}</groupId>
<artifactId>james-server-task-api</artifactId>
diff --git a/mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/quota/migration/CassandraCurrentQuotaManagerMigration.java b/mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/quota/migration/CassandraCurrentQuotaManagerMigration.java
new file mode 100644
index 0000000000..b22e2aec63
--- /dev/null
+++ b/mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/quota/migration/CassandraCurrentQuotaManagerMigration.java
@@ -0,0 +1,67 @@
+/****************************************************************
+ * 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.mailbox.cassandra.quota.migration;
+
+import javax.inject.Inject;
+import javax.inject.Named;
+
+import org.apache.james.backends.cassandra.migration.Migration;
+import org.apache.james.core.Username;
+import org.apache.james.mailbox.model.QuotaOperation;
+import org.apache.james.mailbox.model.QuotaRoot;
+import org.apache.james.mailbox.quota.CurrentQuotaManager;
+import org.apache.james.mailbox.quota.UserQuotaRootResolver;
+import org.apache.james.user.api.UsersRepository;
+
+import reactor.core.publisher.Flux;
+import reactor.core.publisher.Mono;
+
+public class CassandraCurrentQuotaManagerMigration implements Migration {
+ private final UsersRepository usersRepository;
+ private final UserQuotaRootResolver userQuotaRootResolver;
+ private final CurrentQuotaManager oldCurrentQuotaManager;
+ private final CurrentQuotaManager newCurrentQuotaManager;
+
+ @Inject
+ public CassandraCurrentQuotaManagerMigration(UsersRepository usersRepository,
+ UserQuotaRootResolver userQuotaRootResolver,
+ @Named("old") CurrentQuotaManager oldCurrentQuotaManager,
+ CurrentQuotaManager newCurrentQuotaManager) {
+ this.usersRepository = usersRepository;
+ this.userQuotaRootResolver = userQuotaRootResolver;
+ this.oldCurrentQuotaManager = oldCurrentQuotaManager;
+ this.newCurrentQuotaManager = newCurrentQuotaManager;
+ }
+
+ @Override
+ public void apply() throws InterruptedException {
+ Flux.from(usersRepository.listReactive())
+ .flatMap(this::migrateCurrentValue)
+ .then()
+ .block();
+ }
+
+ private Mono<Void> migrateCurrentValue(Username username) {
+ QuotaRoot quotaRoot = userQuotaRootResolver.forUser(username);
+
+ return Mono.from(oldCurrentQuotaManager.getCurrentQuotas(quotaRoot))
+ .flatMap(currentQuotas -> Mono.from(newCurrentQuotaManager.setCurrentQuotas(QuotaOperation.from(quotaRoot, currentQuotas))));
+ }
+}
diff --git a/mailbox/cassandra/src/test/java/org/apache/james/mailbox/cassandra/quota/migration/CassandraCurrentQuotaManagerMigrationTest.java b/mailbox/cassandra/src/test/java/org/apache/james/mailbox/cassandra/quota/migration/CassandraCurrentQuotaManagerMigrationTest.java
new file mode 100644
index 0000000000..cb33b72735
--- /dev/null
+++ b/mailbox/cassandra/src/test/java/org/apache/james/mailbox/cassandra/quota/migration/CassandraCurrentQuotaManagerMigrationTest.java
@@ -0,0 +1,124 @@
+/****************************************************************
+ * 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.mailbox.cassandra.quota.migration;
+
+import static org.apache.james.mailbox.store.quota.DefaultUserQuotaRootResolver.SEPARATOR;
+import static org.assertj.core.api.Assertions.assertThat;
+import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.when;
+
+import org.apache.commons.configuration2.BaseHierarchicalConfiguration;
+import org.apache.james.backends.cassandra.CassandraCluster;
+import org.apache.james.backends.cassandra.CassandraClusterExtension;
+import org.apache.james.backends.cassandra.components.CassandraModule;
+import org.apache.james.backends.cassandra.components.CassandraMutualizedQuotaModule;
+import org.apache.james.backends.cassandra.components.CassandraQuotaCurrentValueDao;
+import org.apache.james.core.Domain;
+import org.apache.james.core.Username;
+import org.apache.james.core.quota.QuotaCountUsage;
+import org.apache.james.core.quota.QuotaSizeUsage;
+import org.apache.james.domainlist.api.DomainList;
+import org.apache.james.domainlist.api.mock.SimpleDomainList;
+import org.apache.james.domainlist.cassandra.CassandraDomainListModule;
+import org.apache.james.mailbox.cassandra.modules.CassandraQuotaModule;
+import org.apache.james.mailbox.cassandra.quota.CassandraCurrentQuotaManagerV1;
+import org.apache.james.mailbox.cassandra.quota.CassandraCurrentQuotaManagerV2;
+import org.apache.james.mailbox.model.CurrentQuotas;
+import org.apache.james.mailbox.model.MailboxConstants;
+import org.apache.james.mailbox.model.QuotaOperation;
+import org.apache.james.mailbox.model.QuotaRoot;
+import org.apache.james.mailbox.quota.UserQuotaRootResolver;
+import org.apache.james.user.api.UsersRepository;
+import org.apache.james.user.cassandra.CassandraUsersDAO;
+import org.apache.james.user.cassandra.CassandraUsersRepositoryModule;
+import org.apache.james.user.lib.UsersRepositoryImpl;
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.api.extension.RegisterExtension;
+
+public class CassandraCurrentQuotaManagerMigrationTest {
+ private static final Username BOB = Username.of("bob");
+ private static final QuotaRoot QUOTA_ROOT = QuotaRoot.quotaRoot(MailboxConstants.USER_NAMESPACE + SEPARATOR + BOB.asString(), BOB.getDomainPart());
+
+ @RegisterExtension
+ static CassandraClusterExtension cassandraCluster = new CassandraClusterExtension(CassandraModule.aggregateModules(
+ CassandraQuotaModule.MODULE,
+ CassandraUsersRepositoryModule.MODULE,
+ CassandraDomainListModule.MODULE,
+ CassandraMutualizedQuotaModule.MODULE));
+
+ private UsersRepositoryImpl<CassandraUsersDAO> getUsersRepository() throws Exception {
+ boolean enableVirtualHosting = false;
+ DomainList domainList = new SimpleDomainList();
+ domainList.addDomain(Domain.of("domain.tld"));
+ CassandraUsersDAO usersDAO = new CassandraUsersDAO(cassandraCluster.getCassandraCluster().getConf());
+ BaseHierarchicalConfiguration configuration = new BaseHierarchicalConfiguration();
+ configuration.addProperty("enableVirtualHosting", String.valueOf(enableVirtualHosting));
+
+ UsersRepositoryImpl<CassandraUsersDAO> usersRepository = new UsersRepositoryImpl<>(domainList, usersDAO);
+ usersRepository.configure(configuration);
+ return usersRepository;
+ }
+
+ private CassandraCurrentQuotaManagerV1 oldCurrentQuotaManager;
+ private CassandraCurrentQuotaManagerV2 newCurrentQuotaManager;
+ private UserQuotaRootResolver userQuotaRootResolver;
+ private CassandraCurrentQuotaManagerMigration testee;
+
+ @BeforeEach
+ void setUp() throws Exception {
+ CassandraCluster cassandra = cassandraCluster.getCassandraCluster();
+
+ oldCurrentQuotaManager = new CassandraCurrentQuotaManagerV1(cassandra.getConf());
+ newCurrentQuotaManager = new CassandraCurrentQuotaManagerV2(new CassandraQuotaCurrentValueDao(cassandra.getConf()));
+ UsersRepository usersRepository = getUsersRepository();
+
+ usersRepository.addUser(BOB, "passBob");
+
+ userQuotaRootResolver = mock(UserQuotaRootResolver.class);
+ when(userQuotaRootResolver.forUser(eq(BOB))).thenReturn(QUOTA_ROOT);
+
+ testee = new CassandraCurrentQuotaManagerMigration(usersRepository, userQuotaRootResolver, oldCurrentQuotaManager, newCurrentQuotaManager);
+ }
+
+ @Test
+ void shouldMigrateQuotaUsage() throws Exception {
+ CurrentQuotas currentQuotas = new CurrentQuotas(QuotaCountUsage.count(42L), QuotaSizeUsage.size(172L));
+ QuotaOperation quotaOperation = QuotaOperation.from(QUOTA_ROOT, currentQuotas);
+
+ oldCurrentQuotaManager.setCurrentQuotas(quotaOperation).block();
+
+ testee.apply();
+
+ assertThat(newCurrentQuotaManager.getCurrentQuotas(QUOTA_ROOT).block())
+ .isEqualTo(currentQuotas);
+ }
+
+ @Test
+ void shouldNotFailWhenNoQuota() throws Exception {
+ CurrentQuotas defaultQuota = new CurrentQuotas(QuotaCountUsage.count(0L), QuotaSizeUsage.size(0L));
+
+ testee.apply();
+
+ assertThat(newCurrentQuotaManager.getCurrentQuotas(QUOTA_ROOT).block())
+ .isEqualTo(defaultQuota);
+ }
+}
---------------------------------------------------------------------
To unsubscribe, e-mail: notifications-unsubscribe@james.apache.org
For additional commands, e-mail: notifications-help@james.apache.org