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 ece9245833c183668371a06ae8ac5934efd03deb Author: Benoit TELLIER <btell...@linagora.com> AuthorDate: Thu Aug 24 17:12:03 2023 +0700 JAMES-3926 Implement SieveQuotaMigration --- .../cassandra/migration/SieveQuotaMigration.java | 67 ++++++++++ .../migration/SieveQuotaMigrationTest.java | 141 +++++++++++++++++++++ 2 files changed, 208 insertions(+) diff --git a/server/data/data-cassandra/src/main/java/org/apache/james/sieve/cassandra/migration/SieveQuotaMigration.java b/server/data/data-cassandra/src/main/java/org/apache/james/sieve/cassandra/migration/SieveQuotaMigration.java new file mode 100644 index 0000000000..287bd01c52 --- /dev/null +++ b/server/data/data-cassandra/src/main/java/org/apache/james/sieve/cassandra/migration/SieveQuotaMigration.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.sieve.cassandra.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.sieve.cassandra.CassandraSieveQuotaDAO; +import org.apache.james.user.api.UsersRepository; + +import reactor.core.publisher.Flux; +import reactor.core.publisher.Mono; + +public class SieveQuotaMigration implements Migration { + private final UsersRepository usersRepository; + private final CassandraSieveQuotaDAO oldDAO; + private final CassandraSieveQuotaDAO newDAO; + + @Inject + public SieveQuotaMigration(UsersRepository usersRepository, @Named("old") CassandraSieveQuotaDAO oldDAO, CassandraSieveQuotaDAO newDAO) { + this.usersRepository = usersRepository; + this.oldDAO = oldDAO; + this.newDAO = newDAO; + } + + @Override + public void apply() throws InterruptedException { + oldDAO.getQuota() + .flatMap(maybeLimit -> maybeLimit.map(newDAO::setQuota).orElse(Mono.empty())) + .block(); + + Flux.from(usersRepository.listReactive()) + .flatMap(username -> migrateLimit(username) + .then(migrateCurrentValue(username))) + .then() + .block(); + } + + private Mono<Void> migrateCurrentValue(Username username) { + return oldDAO.spaceUsedBy(username) + .flatMap(currentValue -> newDAO.updateSpaceUsed(username, currentValue)); + } + + private Mono<Void> migrateLimit(Username username) { + return oldDAO.getQuota(username) + .flatMap(maybeLimit -> maybeLimit.map(limit -> newDAO.setQuota(username, limit)).orElse(Mono.empty())); + } +} diff --git a/server/data/data-cassandra/src/test/java/org/apache/james/sieve/cassandra/migration/SieveQuotaMigrationTest.java b/server/data/data-cassandra/src/test/java/org/apache/james/sieve/cassandra/migration/SieveQuotaMigrationTest.java new file mode 100644 index 0000000000..f7006148c5 --- /dev/null +++ b/server/data/data-cassandra/src/test/java/org/apache/james/sieve/cassandra/migration/SieveQuotaMigrationTest.java @@ -0,0 +1,141 @@ +/**************************************************************** + * 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.sieve.cassandra.migration; + +import static org.assertj.core.api.Assertions.assertThat; + +import org.apache.commons.configuration2.BaseHierarchicalConfiguration; +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.backends.cassandra.components.CassandraQuotaLimitDao; +import org.apache.james.core.Domain; +import org.apache.james.core.Username; +import org.apache.james.core.quota.QuotaSizeLimit; +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.sieve.cassandra.CassandraSieveQuotaDAO; +import org.apache.james.sieve.cassandra.CassandraSieveQuotaDAOV1; +import org.apache.james.sieve.cassandra.CassandraSieveQuotaDAOV2; +import org.apache.james.sieve.cassandra.CassandraSieveRepositoryModule; +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; + +class SieveQuotaMigrationTest { + public static final Username BOB = Username.of("bob"); + + 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; + } + + @RegisterExtension + static CassandraClusterExtension cassandraCluster = new CassandraClusterExtension(CassandraModule.aggregateModules( + CassandraSieveRepositoryModule.MODULE, + CassandraUsersRepositoryModule.MODULE, + CassandraDomainListModule.MODULE, + CassandraMutualizedQuotaModule.MODULE)); + + private CassandraSieveQuotaDAOV1 oldDAO; + private CassandraSieveQuotaDAOV2 newDAO; + private SieveQuotaMigration testee; + + @BeforeEach + void setUp() throws Exception { + oldDAO = new CassandraSieveQuotaDAOV1(cassandraCluster.getCassandraCluster().getConf()); + newDAO = new CassandraSieveQuotaDAOV2(new CassandraQuotaCurrentValueDao(cassandraCluster.getCassandraCluster().getConf()), + new CassandraQuotaLimitDao(cassandraCluster.getCassandraCluster().getConf())); + UsersRepository usersRepository = getUsersRepository(); + + usersRepository.addUser(BOB, "passBob"); + + testee = new SieveQuotaMigration(usersRepository, oldDAO, newDAO); + } + + @Test + void shouldMigrateGlobalLimit() throws Exception { + oldDAO.setQuota(QuotaSizeLimit.size(32)).block(); + + testee.apply(); + + assertThat(newDAO.getQuota().block()) + .contains(QuotaSizeLimit.size(32)); + } + + @Test + void shouldNotFailWhenNoGlobalLimit() throws Exception { + testee.apply(); + + assertThat(newDAO.getQuota().block()) + .isEmpty(); + } + + @Test + void shouldNotFailWhenNoUserLimit() throws Exception { + testee.apply(); + + assertThat(newDAO.getQuota(BOB).block()) + .isEmpty(); + } + + @Test + void shouldNotFailWhenNoSpaceUsed() throws Exception { + testee.apply(); + + assertThat(newDAO.spaceUsedBy(BOB).block()) + .isEqualTo(0L); + } + + @Test + void shouldMigrateUserSpace() throws Exception { + oldDAO.updateSpaceUsed(BOB, 42).block(); + + testee.apply(); + + assertThat(newDAO.spaceUsedBy(BOB).block()) + .isEqualTo(42L); + } + + + @Test + void shouldMigrateUserLimit() throws Exception { + oldDAO.setQuota(BOB, QuotaSizeLimit.size(90)).block(); + + testee.apply(); + + assertThat(newDAO.getQuota(BOB).block()) + .contains(QuotaSizeLimit.size(90)); + } +} \ No newline at end of file --------------------------------------------------------------------- To unsubscribe, e-mail: notifications-unsubscr...@james.apache.org For additional commands, e-mail: notifications-h...@james.apache.org