JAMES-1968 Rework CassandraSieveRepository - Rely on denormalization instead of INDEX - Use FutureUtils - Tests DAOs - Improve APIs
Project: http://git-wip-us.apache.org/repos/asf/james-project/repo Commit: http://git-wip-us.apache.org/repos/asf/james-project/commit/f28cc423 Tree: http://git-wip-us.apache.org/repos/asf/james-project/tree/f28cc423 Diff: http://git-wip-us.apache.org/repos/asf/james-project/diff/f28cc423 Branch: refs/heads/master Commit: f28cc423e9a78e04dba25fe7fec3d2d5c42443c9 Parents: e4e1462 Author: benwa <btell...@linagora.com> Authored: Thu Mar 16 20:24:45 2017 +0700 Committer: benwa <btell...@linagora.com> Committed: Wed Mar 22 07:11:14 2017 +0700 ---------------------------------------------------------------------- .../cassandra/host/CassandraHostSystem.java | 4 +- .../cassandra/CassandraActiveScriptDAO.java | 89 +++++++++++ .../sieve/cassandra/CassandraSieveDAO.java | 157 ++++++------------- .../cassandra/CassandraSieveRepository.java | 89 +++++++---- .../CassandraSieveRepositoryModule.java | 15 +- .../sieve/cassandra/model/ActiveScriptInfo.java | 43 +++++ .../model/ScriptContentAndActivation.java | 39 ----- .../tables/CassandraSieveActiveTable.java | 30 ++++ .../cassandra/tables/CassandraSieveTable.java | 1 - .../cassandra/CassandraActiveScriptDAOTest.java | 97 ++++++++++++ .../sieve/cassandra/CassandraSieveDAOTest.java | 143 +++++++++++++++++ .../cassandra/CassandraSieveQuotaDAOTest.java | 149 ++++++++++++++++++ .../cassandra/CassandraSieveRepositoryTest.java | 48 +----- 13 files changed, 676 insertions(+), 228 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/james-project/blob/f28cc423/mpt/impl/managesieve/cassandra/src/test/java/org/apache/james/mpt/managesieve/cassandra/host/CassandraHostSystem.java ---------------------------------------------------------------------- diff --git a/mpt/impl/managesieve/cassandra/src/test/java/org/apache/james/mpt/managesieve/cassandra/host/CassandraHostSystem.java b/mpt/impl/managesieve/cassandra/src/test/java/org/apache/james/mpt/managesieve/cassandra/host/CassandraHostSystem.java index fae007c..a771517 100644 --- a/mpt/impl/managesieve/cassandra/src/test/java/org/apache/james/mpt/managesieve/cassandra/host/CassandraHostSystem.java +++ b/mpt/impl/managesieve/cassandra/src/test/java/org/apache/james/mpt/managesieve/cassandra/host/CassandraHostSystem.java @@ -21,6 +21,7 @@ package org.apache.james.mpt.managesieve.cassandra.host; import org.apache.james.backends.cassandra.init.CassandraModuleComposite; import org.apache.james.mpt.host.JamesManageSieveHostSystem; +import org.apache.james.sieve.cassandra.CassandraActiveScriptDAO; import org.apache.james.sieve.cassandra.CassandraSieveDAO; import org.apache.james.sieve.cassandra.CassandraSieveQuotaDAO; import org.apache.james.sieve.cassandra.CassandraSieveRepository; @@ -43,7 +44,8 @@ public class CassandraHostSystem extends JamesManageSieveHostSystem { protected static SieveRepository createSieveRepository() throws Exception { return new CassandraSieveRepository( new CassandraSieveDAO(CASSANDRA_CLUSTER.getConf()), - new CassandraSieveQuotaDAO(CASSANDRA_CLUSTER.getConf())); + new CassandraSieveQuotaDAO(CASSANDRA_CLUSTER.getConf()), + new CassandraActiveScriptDAO(CASSANDRA_CLUSTER.getConf())); } protected static UsersRepository createUsersRepository() { http://git-wip-us.apache.org/repos/asf/james-project/blob/f28cc423/server/data/data-cassandra/src/main/java/org/apache/james/sieve/cassandra/CassandraActiveScriptDAO.java ---------------------------------------------------------------------- diff --git a/server/data/data-cassandra/src/main/java/org/apache/james/sieve/cassandra/CassandraActiveScriptDAO.java b/server/data/data-cassandra/src/main/java/org/apache/james/sieve/cassandra/CassandraActiveScriptDAO.java new file mode 100644 index 0000000..38ca130 --- /dev/null +++ b/server/data/data-cassandra/src/main/java/org/apache/james/sieve/cassandra/CassandraActiveScriptDAO.java @@ -0,0 +1,89 @@ +/**************************************************************** + * 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; + +import static com.datastax.driver.core.querybuilder.QueryBuilder.bindMarker; +import static com.datastax.driver.core.querybuilder.QueryBuilder.delete; +import static com.datastax.driver.core.querybuilder.QueryBuilder.eq; +import static com.datastax.driver.core.querybuilder.QueryBuilder.insertInto; + +import static com.datastax.driver.core.querybuilder.QueryBuilder.now; +import static com.datastax.driver.core.querybuilder.QueryBuilder.select; +import static org.apache.james.sieve.cassandra.tables.CassandraSieveActiveTable.DATE; +import static org.apache.james.sieve.cassandra.tables.CassandraSieveActiveTable.TABLE_NAME; +import static org.apache.james.sieve.cassandra.tables.CassandraSieveActiveTable.SCRIPT_NAME; +import static org.apache.james.sieve.cassandra.tables.CassandraSieveActiveTable.USER_NAME; + +import java.util.Date; +import java.util.Optional; +import java.util.concurrent.CompletableFuture; + +import javax.inject.Inject; + +import org.apache.james.backends.cassandra.utils.CassandraAsyncExecutor; +import org.apache.james.sieve.cassandra.model.ActiveScriptInfo; + +import com.datastax.driver.core.PreparedStatement; +import com.datastax.driver.core.Session; + +public class CassandraActiveScriptDAO { + private final CassandraAsyncExecutor cassandraAsyncExecutor; + private final PreparedStatement insertActive; + private final PreparedStatement deleteActive; + private final PreparedStatement selectActiveName; + + @Inject + public CassandraActiveScriptDAO(Session session) { + this.cassandraAsyncExecutor = new CassandraAsyncExecutor(session); + this.insertActive = session.prepare(insertInto(TABLE_NAME) + .value(SCRIPT_NAME, bindMarker(SCRIPT_NAME)) + .value(USER_NAME, bindMarker(USER_NAME)) + .value(DATE, bindMarker(DATE))); + this.deleteActive = session.prepare(delete() + .from(TABLE_NAME) + .where(eq(USER_NAME, bindMarker(USER_NAME)))); + this.selectActiveName = session.prepare(select(SCRIPT_NAME, DATE) + .from(TABLE_NAME) + .where(eq(USER_NAME, bindMarker(USER_NAME)))); + } + + public CompletableFuture<Optional<ActiveScriptInfo>> getActiveSctiptInfo(String username) { + return cassandraAsyncExecutor.executeSingleRow( + selectActiveName.bind() + .setString(USER_NAME, username)) + .thenApply(rowOptional -> rowOptional.map(row -> new ActiveScriptInfo( + row.getString(SCRIPT_NAME), + row.getDate(DATE)))); + } + + public CompletableFuture<Void> unactivate(String username) { + return cassandraAsyncExecutor.executeVoid( + deleteActive.bind() + .setString(USER_NAME, username)); + } + + public CompletableFuture<Void> activate(String username, String scriptName) { + return cassandraAsyncExecutor.executeVoid( + insertActive.bind() + .setString(USER_NAME, username) + .setString(SCRIPT_NAME, scriptName) + .setDate(DATE, new Date())); + } +} http://git-wip-us.apache.org/repos/asf/james-project/blob/f28cc423/server/data/data-cassandra/src/main/java/org/apache/james/sieve/cassandra/CassandraSieveDAO.java ---------------------------------------------------------------------- diff --git a/server/data/data-cassandra/src/main/java/org/apache/james/sieve/cassandra/CassandraSieveDAO.java b/server/data/data-cassandra/src/main/java/org/apache/james/sieve/cassandra/CassandraSieveDAO.java index 31c3ee6..7dab54a 100644 --- a/server/data/data-cassandra/src/main/java/org/apache/james/sieve/cassandra/CassandraSieveDAO.java +++ b/server/data/data-cassandra/src/main/java/org/apache/james/sieve/cassandra/CassandraSieveDAO.java @@ -26,8 +26,14 @@ import static com.datastax.driver.core.querybuilder.QueryBuilder.insertInto; import static com.datastax.driver.core.querybuilder.QueryBuilder.select; import static com.datastax.driver.core.querybuilder.QueryBuilder.set; import static com.datastax.driver.core.querybuilder.QueryBuilder.update; +import static org.apache.james.sieve.cassandra.tables.CassandraSieveTable.IS_ACTIVE; +import static org.apache.james.sieve.cassandra.tables.CassandraSieveTable.SCRIPT_CONTENT; +import static org.apache.james.sieve.cassandra.tables.CassandraSieveTable.SCRIPT_NAME; +import static org.apache.james.sieve.cassandra.tables.CassandraSieveTable.SIZE; +import static org.apache.james.sieve.cassandra.tables.CassandraSieveTable.TABLE_NAME; +import static org.apache.james.sieve.cassandra.tables.CassandraSieveTable.USER_NAME; + -import java.util.Date; import java.util.List; import java.util.Optional; import java.util.concurrent.CompletableFuture; @@ -36,10 +42,8 @@ import java.util.stream.Collectors; import javax.inject.Inject; import org.apache.james.backends.cassandra.utils.CassandraAsyncExecutor; -import org.apache.james.sieve.cassandra.model.ScriptContentAndActivation; -import org.apache.james.sieve.cassandra.tables.CassandraSieveTable; +import org.apache.james.sieve.cassandra.model.Script; import org.apache.james.sieverepository.api.ScriptSummary; -import org.joda.time.DateTime; import com.datastax.driver.core.PreparedStatement; import com.datastax.driver.core.Row; @@ -50,12 +54,8 @@ public class CassandraSieveDAO { private final CassandraAsyncExecutor cassandraAsyncExecutor; private final PreparedStatement insertScriptStatement; - private final PreparedStatement selectActiveScriptStatement; - private final PreparedStatement selectActiveScriptMetadataStatement; - private final PreparedStatement selectActiveScriptNameStatement; private final PreparedStatement selectScriptsStatement; private final PreparedStatement selectScriptStatement; - private final PreparedStatement selectScriptMetadataStatement; private final PreparedStatement updateScriptActivationStatement; private final PreparedStatement deleteScriptStatement; @@ -64,145 +64,90 @@ public class CassandraSieveDAO { this.cassandraAsyncExecutor = new CassandraAsyncExecutor(session); insertScriptStatement = session.prepare( - insertInto(CassandraSieveTable.TABLE_NAME) - .value(CassandraSieveTable.USER_NAME, bindMarker(CassandraSieveTable.USER_NAME)) - .value(CassandraSieveTable.SCRIPT_NAME, bindMarker(CassandraSieveTable.SCRIPT_NAME)) - .value(CassandraSieveTable.SCRIPT_CONTENT, bindMarker(CassandraSieveTable.SCRIPT_CONTENT)) - .value(CassandraSieveTable.IS_ACTIVE, bindMarker(CassandraSieveTable.IS_ACTIVE)) - .value(CassandraSieveTable.SIZE, bindMarker(CassandraSieveTable.SIZE)) - .value(CassandraSieveTable.DATE, bindMarker(CassandraSieveTable.DATE))); - - selectActiveScriptStatement = session.prepare(getScriptQuery(CassandraSieveTable.SCRIPT_CONTENT, CassandraSieveTable.DATE) - .and(eq(CassandraSieveTable.IS_ACTIVE, bindMarker(CassandraSieveTable.IS_ACTIVE)))); - - selectActiveScriptMetadataStatement = session.prepare(getScriptQuery(CassandraSieveTable.DATE) - .and(eq(CassandraSieveTable.IS_ACTIVE, bindMarker(CassandraSieveTable.IS_ACTIVE)))); + insertInto(TABLE_NAME) + .value(USER_NAME, bindMarker(USER_NAME)) + .value(SCRIPT_NAME, bindMarker(SCRIPT_NAME)) + .value(SCRIPT_CONTENT, bindMarker(SCRIPT_CONTENT)) + .value(IS_ACTIVE, bindMarker(IS_ACTIVE)) + .value(SIZE, bindMarker(SIZE))); - selectActiveScriptNameStatement = session.prepare(getScriptQuery(CassandraSieveTable.SCRIPT_NAME) - .and(eq(CassandraSieveTable.IS_ACTIVE, bindMarker(CassandraSieveTable.IS_ACTIVE)))); + selectScriptsStatement = session.prepare(getScriptsQuery()); - selectScriptsStatement = session.prepare( - select() - .from(CassandraSieveTable.TABLE_NAME) - .where(eq(CassandraSieveTable.USER_NAME, bindMarker(CassandraSieveTable.USER_NAME)))); - - selectScriptStatement = session.prepare(getScriptQuery(CassandraSieveTable.SCRIPT_CONTENT, CassandraSieveTable.IS_ACTIVE) - .and(eq(CassandraSieveTable.SCRIPT_NAME, bindMarker(CassandraSieveTable.SCRIPT_NAME)))); - - selectScriptMetadataStatement = session.prepare(getScriptQuery(CassandraSieveTable.SIZE, CassandraSieveTable.IS_ACTIVE, CassandraSieveTable.DATE) - .and(eq(CassandraSieveTable.SCRIPT_NAME, bindMarker(CassandraSieveTable.SCRIPT_NAME)))); + selectScriptStatement = session.prepare(getScriptsQuery() + .and(eq(SCRIPT_NAME, bindMarker(SCRIPT_NAME)))); updateScriptActivationStatement = session.prepare( - update(CassandraSieveTable.TABLE_NAME) - .with(set(CassandraSieveTable.IS_ACTIVE, bindMarker(CassandraSieveTable.IS_ACTIVE))) - .where(eq(CassandraSieveTable.USER_NAME, bindMarker(CassandraSieveTable.USER_NAME))) - .and(eq(CassandraSieveTable.SCRIPT_NAME, bindMarker(CassandraSieveTable.SCRIPT_NAME))) + update(TABLE_NAME) + .with(set(IS_ACTIVE, bindMarker(IS_ACTIVE))) + .where(eq(USER_NAME, bindMarker(USER_NAME))) + .and(eq(SCRIPT_NAME, bindMarker(SCRIPT_NAME))) .ifExists()); deleteScriptStatement = session.prepare( delete() - .from(CassandraSieveTable.TABLE_NAME) - .where(eq(CassandraSieveTable.USER_NAME, bindMarker(CassandraSieveTable.USER_NAME))) - .and(eq(CassandraSieveTable.SCRIPT_NAME, bindMarker(CassandraSieveTable.SCRIPT_NAME))) + .from(TABLE_NAME) + .where(eq(USER_NAME, bindMarker(USER_NAME))) + .and(eq(SCRIPT_NAME, bindMarker(SCRIPT_NAME))) .ifExists()); } - private Select.Where getScriptQuery(String... selectedRows) { - return select(selectedRows) - .from(CassandraSieveTable.TABLE_NAME) - .where(eq(CassandraSieveTable.USER_NAME, bindMarker(CassandraSieveTable.USER_NAME))); + private Select.Where getScriptsQuery() { + return select(SCRIPT_CONTENT, IS_ACTIVE, SCRIPT_NAME, SIZE) + .from(TABLE_NAME) + .where(eq(USER_NAME, bindMarker(USER_NAME))); } - public CompletableFuture<Void> insertScript(String user, String name, String content, boolean isActive) { + public CompletableFuture<Void> insertScript(String user, Script script) { return cassandraAsyncExecutor.executeVoid( insertScriptStatement.bind() - .setString(CassandraSieveTable.USER_NAME, user) - .setString(CassandraSieveTable.SCRIPT_NAME, name) - .setString(CassandraSieveTable.SCRIPT_CONTENT, content) - .setBool(CassandraSieveTable.IS_ACTIVE, isActive) - .setLong(CassandraSieveTable.SIZE, content.getBytes().length) - .setDate(CassandraSieveTable.DATE, new Date())); + .setString(USER_NAME, user) + .setString(SCRIPT_NAME, script.getName()) + .setString(SCRIPT_CONTENT, script.getContent()) + .setBool(IS_ACTIVE, script.isActive()) + .setLong(SIZE, script.getSize())); } public CompletableFuture<List<ScriptSummary>> listScripts(String user) { return cassandraAsyncExecutor.execute( selectScriptsStatement.bind() - .setString(CassandraSieveTable.USER_NAME, user)) + .setString(USER_NAME, user)) .thenApply(resultSet -> resultSet.all() .stream() .map(row -> new ScriptSummary( - row.getString(CassandraSieveTable.SCRIPT_NAME), - row.getBool(CassandraSieveTable.IS_ACTIVE))) + row.getString(SCRIPT_NAME), + row.getBool(IS_ACTIVE))) .collect(Collectors.toList())); } public CompletableFuture<Boolean> updateScriptActivation(String user, String scriptName, boolean active) { return cassandraAsyncExecutor.executeReturnApplied( updateScriptActivationStatement.bind() - .setString(CassandraSieveTable.USER_NAME, user) - .setString(CassandraSieveTable.SCRIPT_NAME, scriptName) - .setBool(CassandraSieveTable.IS_ACTIVE, active)); - } - - public CompletableFuture<Optional<ScriptContentAndActivation>> getScriptContentAndActivation(String user, String name) { - return getScriptRow(user, name).thenApply(opt -> opt.map(row -> new ScriptContentAndActivation( - row.getString(CassandraSieveTable.SCRIPT_CONTENT), - row.getBool(CassandraSieveTable.IS_ACTIVE)))); - } - - public CompletableFuture<Optional<String>> getScriptContent(String user, String name) { - return getScriptRow(user, name).thenApply(opt -> opt.map(row -> row.getString(CassandraSieveTable.SCRIPT_CONTENT))); - } - - public CompletableFuture<Optional<Long>> getScriptSize(String user, String name) { - return cassandraAsyncExecutor.executeSingleRow( - selectScriptMetadataStatement.bind() - .setString(CassandraSieveTable.USER_NAME, user) - .setString(CassandraSieveTable.SCRIPT_NAME, name)) - .thenApply(rowOptional -> rowOptional.map(row -> row.getLong(CassandraSieveTable.SIZE))); + .setString(USER_NAME, user) + .setString(SCRIPT_NAME, scriptName) + .setBool(IS_ACTIVE, active)); } - public CompletableFuture<Optional<DateTime>> getActiveScriptActivationDate(String user) { - return cassandraAsyncExecutor.executeSingleRow( - selectActiveScriptMetadataStatement.bind() - .setString(CassandraSieveTable.USER_NAME, user) - .setBool(CassandraSieveTable.IS_ACTIVE, true)) - .thenApply(rowOptional -> rowOptional.map(row -> new DateTime(row.getDate(CassandraSieveTable.DATE).getTime()))); + public CompletableFuture<Optional<Script>> getScript(String user, String name) { + return getScriptRow(user, name).thenApply(opt -> opt.map(row -> Script.builder() + .content(row.getString(SCRIPT_CONTENT)) + .isActive(row.getBool(IS_ACTIVE)) + .name(name) + .size(row.getLong(SIZE)) + .build())); } public CompletableFuture<Boolean> deleteScriptInCassandra(String user, String name) { return cassandraAsyncExecutor.executeReturnApplied( deleteScriptStatement.bind() - .setString(CassandraSieveTable.USER_NAME, user) - .setString(CassandraSieveTable.SCRIPT_NAME, name)); - } - - public CompletableFuture<Boolean> scriptExists(String user, String name) { - return getScriptSize(user, name).thenApply(Optional::isPresent); - } - - - public CompletableFuture<Optional<String>> getActiveName(String user) { - return cassandraAsyncExecutor.executeSingleRow( - selectActiveScriptNameStatement.bind() - .setString(CassandraSieveTable.USER_NAME, user) - .setBool(CassandraSieveTable.IS_ACTIVE, true)) - .thenApply(optional -> optional.map(row -> row.getString(CassandraSieveTable.SCRIPT_NAME))); - } - - public CompletableFuture<Optional<String>> getActive(String user) { - return cassandraAsyncExecutor.executeSingleRow( - selectActiveScriptStatement.bind() - .setString(CassandraSieveTable.USER_NAME, user) - .setBool(CassandraSieveTable.IS_ACTIVE, true)) - .thenApply(rowOptional -> rowOptional.map(row -> row.getString(CassandraSieveTable.SCRIPT_CONTENT))); + .setString(USER_NAME, user) + .setString(SCRIPT_NAME, name)); } private CompletableFuture<Optional<Row>> getScriptRow(String user, String name) { return cassandraAsyncExecutor.executeSingleRow( selectScriptStatement.bind() - .setString(CassandraSieveTable.USER_NAME, user) - .setString(CassandraSieveTable.SCRIPT_NAME, name)); + .setString(USER_NAME, user) + .setString(SCRIPT_NAME, name)); } } http://git-wip-us.apache.org/repos/asf/james-project/blob/f28cc423/server/data/data-cassandra/src/main/java/org/apache/james/sieve/cassandra/CassandraSieveRepository.java ---------------------------------------------------------------------- diff --git a/server/data/data-cassandra/src/main/java/org/apache/james/sieve/cassandra/CassandraSieveRepository.java b/server/data/data-cassandra/src/main/java/org/apache/james/sieve/cassandra/CassandraSieveRepository.java index 0dd3153..1e3ad9f 100644 --- a/server/data/data-cassandra/src/main/java/org/apache/james/sieve/cassandra/CassandraSieveRepository.java +++ b/server/data/data-cassandra/src/main/java/org/apache/james/sieve/cassandra/CassandraSieveRepository.java @@ -28,9 +28,10 @@ import java.util.concurrent.CompletableFuture; import javax.inject.Inject; import org.apache.commons.io.IOUtils; -import org.apache.james.sieve.cassandra.model.ScriptContentAndActivation; -import org.apache.james.sieverepository.api.ScriptSummary; +import org.apache.james.sieve.cassandra.model.ActiveScriptInfo; +import org.apache.james.sieve.cassandra.model.Script; import org.apache.james.sieve.cassandra.model.SieveQuota; +import org.apache.james.sieverepository.api.ScriptSummary; import org.apache.james.sieverepository.api.SieveRepository; import org.apache.james.sieverepository.api.exception.DuplicateException; import org.apache.james.sieverepository.api.exception.IsActiveException; @@ -38,24 +39,28 @@ import org.apache.james.sieverepository.api.exception.QuotaExceededException; import org.apache.james.sieverepository.api.exception.QuotaNotFoundException; import org.apache.james.sieverepository.api.exception.ScriptNotFoundException; import org.apache.james.sieverepository.api.exception.StorageException; +import org.apache.james.util.CompletableFutureUtil; +import org.apache.james.util.FluentFutureStream; import org.joda.time.DateTime; public class CassandraSieveRepository implements SieveRepository { private final CassandraSieveDAO cassandraSieveDAO; private final CassandraSieveQuotaDAO cassandraSieveQuotaDAO; + private final CassandraActiveScriptDAO cassandraActiveScriptDAO; @Inject - public CassandraSieveRepository(CassandraSieveDAO cassandraSieveDAO, CassandraSieveQuotaDAO cassandraSieveQuotaDAO) { + public CassandraSieveRepository(CassandraSieveDAO cassandraSieveDAO, CassandraSieveQuotaDAO cassandraSieveQuotaDAO, CassandraActiveScriptDAO cassandraActiveScriptDAO) { this.cassandraSieveDAO = cassandraSieveDAO; this.cassandraSieveQuotaDAO = cassandraSieveQuotaDAO; + this.cassandraActiveScriptDAO = cassandraActiveScriptDAO; } @Override public DateTime getActivationDateForActiveScript(String user) throws StorageException, ScriptNotFoundException { - return cassandraSieveDAO.getActiveScriptActivationDate(user) - .join() - .orElseThrow(ScriptNotFoundException::new); + return cassandraActiveScriptDAO.getActiveSctiptInfo(user).join() + .orElseThrow(ScriptNotFoundException::new) + .getActivationDate(); } @Override @@ -72,8 +77,9 @@ public class CassandraSieveRepository implements SieveRepository { } public CompletableFuture<Long> spaceThatWillBeUsedByNewScript(String user, String name, long scriptSize) { - return cassandraSieveDAO.getScriptSize(user, name) - .thenApply(sizeOfStoredScript -> scriptSize - sizeOfStoredScript.orElse(0L)); + return cassandraSieveDAO.getScript(user, name) + .thenApply(optional -> optional.map(Script::getSize).orElse(0L)) + .thenApply(sizeOfStoredScript -> scriptSize - sizeOfStoredScript); } private Optional<Long> limitToUse(CompletableFuture<Optional<Long>> userQuota, CompletableFuture<Optional<Long>> globalQuota) { @@ -90,7 +96,12 @@ public class CassandraSieveRepository implements SieveRepository { CompletableFuture.allOf( updateSpaceUsed(user, spaceUsed.join()), - cassandraSieveDAO.insertScript(user, name, content, false)) + cassandraSieveDAO.insertScript(user, + Script.builder() + .name(name) + .content(content) + .isActive(false) + .build())) .join(); } @@ -109,15 +120,21 @@ public class CassandraSieveRepository implements SieveRepository { @Override public InputStream getActive(String user) throws ScriptNotFoundException { return IOUtils.toInputStream( - cassandraSieveDAO.getActive(user) + cassandraActiveScriptDAO.getActiveSctiptInfo(user) + .thenCompose(optionalActiveName -> optionalActiveName + .map(activeScriptInfo -> cassandraSieveDAO.getScript(user, activeScriptInfo.getName())) + .orElse(CompletableFuture.completedFuture(Optional.empty()))) .join() - .orElseThrow(ScriptNotFoundException::new), StandardCharsets.UTF_8); + .orElseThrow(ScriptNotFoundException::new) + .getContent(), StandardCharsets.UTF_8); } @Override public void setActive(String user, String name) throws ScriptNotFoundException { CompletableFuture<Void> unactivateOldScriptFuture = unactivateOldScript(user); - CompletableFuture<Boolean> activateNewScript = updateScriptActivation(user, name, true); + CompletableFuture<Boolean> activateNewScript = updateScriptActivation(user, name, true) + .thenCompose(CompletableFutureUtil.composeIfTrue( + () -> cassandraActiveScriptDAO.activate(user, name))); unactivateOldScriptFuture.join(); if (!activateNewScript.join()) { @@ -126,9 +143,9 @@ public class CassandraSieveRepository implements SieveRepository { } private CompletableFuture<Void> unactivateOldScript(String user) { - return cassandraSieveDAO.getActiveName(user) + return cassandraActiveScriptDAO.getActiveSctiptInfo(user) .thenCompose(scriptNameOptional -> scriptNameOptional - .map(scriptName -> updateScriptActivation(user, scriptName, false) + .map(activeScriptInfo -> updateScriptActivation(user, activeScriptInfo.getName(), false) .<Void>thenApply(any -> null)) .orElse(CompletableFuture.completedFuture(null))); } @@ -137,14 +154,14 @@ public class CassandraSieveRepository implements SieveRepository { if (!scriptName.equals(SieveRepository.NO_SCRIPT_NAME)) { return cassandraSieveDAO.updateScriptActivation(user, scriptName, active); } - return CompletableFuture.completedFuture(true); + return cassandraActiveScriptDAO.unactivate(user).thenApply(any -> true); } @Override public InputStream getScript(String user, String name) throws ScriptNotFoundException { - return cassandraSieveDAO.getScriptContent(user, name) + return cassandraSieveDAO.getScript(user, name) .join() - .map(script -> IOUtils.toInputStream(script, StandardCharsets.UTF_8)) + .map(script -> IOUtils.toInputStream(script.getContent(), StandardCharsets.UTF_8)) .orElseThrow(ScriptNotFoundException::new); } @@ -157,7 +174,7 @@ public class CassandraSieveRepository implements SieveRepository { } private void ensureIsNotActive(String user, String name) throws IsActiveException { - Optional<String> activeName = cassandraSieveDAO.getActiveName(user).join(); + Optional<String> activeName = cassandraActiveScriptDAO.getActiveSctiptInfo(user).join().map(ActiveScriptInfo::getName); if (activeName.isPresent() && name.equals(activeName.get())) { throw new IsActiveException(); } @@ -165,8 +182,9 @@ public class CassandraSieveRepository implements SieveRepository { @Override public void renameScript(String user, String oldName, String newName) throws ScriptNotFoundException, DuplicateException { - CompletableFuture<Boolean> scriptExistsFuture = cassandraSieveDAO.scriptExists(user, newName); - CompletableFuture<Optional<ScriptContentAndActivation>> oldScriptFuture = cassandraSieveDAO.getScriptContentAndActivation(user, oldName); + CompletableFuture<Boolean> scriptExistsFuture = cassandraSieveDAO.getScript(user, newName) + .thenApply(Optional::isPresent); + CompletableFuture<Optional<Script>> oldScriptFuture = cassandraSieveDAO.getScript(user, oldName); oldScriptFuture.join(); if (scriptExistsFuture.join()) { @@ -174,18 +192,30 @@ public class CassandraSieveRepository implements SieveRepository { } performScriptRename(user, - oldName, newName, oldScriptFuture.join().orElseThrow(ScriptNotFoundException::new)); } - private void performScriptRename(String user, String oldName, String newName, ScriptContentAndActivation oldScript) { + private void performScriptRename(String user, String newName, Script oldScript) { CompletableFuture.allOf( - cassandraSieveDAO.insertScript(user, newName, oldScript.getContent(), oldScript.isActive()), - cassandraSieveDAO.deleteScriptInCassandra(user, oldName)) + cassandraSieveDAO.insertScript(user, + Script.builder() + .copyOf(oldScript) + .name(newName) + .build()), + cassandraSieveDAO.deleteScriptInCassandra(user, oldScript.getName()), + performActiveScriptRename(user, oldScript.getName(), newName)) .join(); } + private CompletableFuture<Void> performActiveScriptRename(String user, String oldName, String newName) { + return cassandraActiveScriptDAO.getActiveSctiptInfo(user) + .thenCompose(optionalActivationInfo -> optionalActivationInfo + .filter(activeScriptInfo -> activeScriptInfo.getName().equals(oldName)) + .map(name -> cassandraActiveScriptDAO.activate(user, newName)) + .orElse(CompletableFuture.completedFuture(null))); + } + @Override public boolean hasQuota() { return cassandraSieveQuotaDAO.getQuota() @@ -214,11 +244,12 @@ public class CassandraSieveRepository implements SieveRepository { @Override public boolean hasQuota(String user) { - CompletableFuture<Boolean> userQuotaIsPresent = cassandraSieveQuotaDAO.getQuota(user).thenApply(Optional::isPresent); - CompletableFuture<Boolean> globalQuotaIsPresent = cassandraSieveQuotaDAO.getQuota().thenApply(Optional::isPresent); - CompletableFuture.allOf(userQuotaIsPresent, globalQuotaIsPresent).join(); - - return userQuotaIsPresent.join() || globalQuotaIsPresent.join(); + return FluentFutureStream.ofFutures( + cassandraSieveQuotaDAO.getQuota(user).thenApply(Optional::isPresent), + cassandraSieveQuotaDAO.getQuota().thenApply(Optional::isPresent)) + .reduce((b1, b2) -> b1 || b2) + .thenApply(Optional::get) + .join(); } @Override http://git-wip-us.apache.org/repos/asf/james-project/blob/f28cc423/server/data/data-cassandra/src/main/java/org/apache/james/sieve/cassandra/CassandraSieveRepositoryModule.java ---------------------------------------------------------------------- diff --git a/server/data/data-cassandra/src/main/java/org/apache/james/sieve/cassandra/CassandraSieveRepositoryModule.java b/server/data/data-cassandra/src/main/java/org/apache/james/sieve/cassandra/CassandraSieveRepositoryModule.java index c59053d..b837030 100644 --- a/server/data/data-cassandra/src/main/java/org/apache/james/sieve/cassandra/CassandraSieveRepositoryModule.java +++ b/server/data/data-cassandra/src/main/java/org/apache/james/sieve/cassandra/CassandraSieveRepositoryModule.java @@ -31,6 +31,7 @@ import org.apache.james.backends.cassandra.components.CassandraIndex; import org.apache.james.backends.cassandra.components.CassandraModule; import org.apache.james.backends.cassandra.components.CassandraTable; import org.apache.james.backends.cassandra.components.CassandraType; +import org.apache.james.sieve.cassandra.tables.CassandraSieveActiveTable; import org.apache.james.sieve.cassandra.tables.CassandraSieveClusterQuotaTable; import org.apache.james.sieve.cassandra.tables.CassandraSieveQuotaTable; import org.apache.james.sieve.cassandra.tables.CassandraSieveSpaceTable; @@ -54,7 +55,6 @@ public class CassandraSieveRepositoryModule implements CassandraModule { .addClusteringColumn(CassandraSieveTable.SCRIPT_NAME, text()) .addColumn(CassandraSieveTable.SCRIPT_CONTENT, text()) .addColumn(CassandraSieveTable.IS_ACTIVE, cboolean()) - .addColumn(CassandraSieveTable.DATE, timestamp()) .addColumn(CassandraSieveTable.SIZE, bigint())), new CassandraTable(CassandraSieveSpaceTable.TABLE_NAME, SchemaBuilder.createTable(CassandraSieveSpaceTable.TABLE_NAME) @@ -70,13 +70,14 @@ public class CassandraSieveRepositoryModule implements CassandraModule { SchemaBuilder.createTable(CassandraSieveClusterQuotaTable.TABLE_NAME) .ifNotExists() .addPartitionKey(CassandraSieveClusterQuotaTable.NAME, text()) - .addColumn(CassandraSieveClusterQuotaTable.VALUE, bigint()))); - index = ImmutableList.of( - new CassandraIndex( - SchemaBuilder.createIndex(CassandraIndex.INDEX_PREFIX + CassandraSieveTable.TABLE_NAME + CassandraSieveTable.IS_ACTIVE) + .addColumn(CassandraSieveClusterQuotaTable.VALUE, bigint())), + new CassandraTable(CassandraSieveActiveTable.TABLE_NAME, + SchemaBuilder.createTable(CassandraSieveActiveTable.TABLE_NAME) .ifNotExists() - .onTable(CassandraSieveTable.TABLE_NAME) - .andColumn(CassandraSieveTable.IS_ACTIVE))); + .addPartitionKey(CassandraSieveActiveTable.USER_NAME, text()) + .addColumn(CassandraSieveActiveTable.SCRIPT_NAME, text()) + .addColumn(CassandraSieveActiveTable.DATE, timestamp()))); + index = ImmutableList.of(); types = ImmutableList.of(); } http://git-wip-us.apache.org/repos/asf/james-project/blob/f28cc423/server/data/data-cassandra/src/main/java/org/apache/james/sieve/cassandra/model/ActiveScriptInfo.java ---------------------------------------------------------------------- diff --git a/server/data/data-cassandra/src/main/java/org/apache/james/sieve/cassandra/model/ActiveScriptInfo.java b/server/data/data-cassandra/src/main/java/org/apache/james/sieve/cassandra/model/ActiveScriptInfo.java new file mode 100644 index 0000000..b3377be --- /dev/null +++ b/server/data/data-cassandra/src/main/java/org/apache/james/sieve/cassandra/model/ActiveScriptInfo.java @@ -0,0 +1,43 @@ +/**************************************************************** + * 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.model; + +import java.util.Date; + +import org.joda.time.DateTime; + +public class ActiveScriptInfo { + + private final String name; + private final DateTime activationDate; + + public ActiveScriptInfo(String content, Date date) { + this.name = content; + this.activationDate = new DateTime(date); + } + + public String getName() { + return name; + } + + public DateTime getActivationDate() { + return activationDate; + } +} http://git-wip-us.apache.org/repos/asf/james-project/blob/f28cc423/server/data/data-cassandra/src/main/java/org/apache/james/sieve/cassandra/model/ScriptContentAndActivation.java ---------------------------------------------------------------------- diff --git a/server/data/data-cassandra/src/main/java/org/apache/james/sieve/cassandra/model/ScriptContentAndActivation.java b/server/data/data-cassandra/src/main/java/org/apache/james/sieve/cassandra/model/ScriptContentAndActivation.java deleted file mode 100644 index 0e26b7b..0000000 --- a/server/data/data-cassandra/src/main/java/org/apache/james/sieve/cassandra/model/ScriptContentAndActivation.java +++ /dev/null @@ -1,39 +0,0 @@ -/**************************************************************** - * 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.model; - -public class ScriptContentAndActivation { - - private final String content; - private final boolean activation; - - public ScriptContentAndActivation(String content, boolean activation) { - this.content = content; - this.activation = activation; - } - - public String getContent() { - return content; - } - - public boolean isActive() { - return activation; - } -} http://git-wip-us.apache.org/repos/asf/james-project/blob/f28cc423/server/data/data-cassandra/src/main/java/org/apache/james/sieve/cassandra/tables/CassandraSieveActiveTable.java ---------------------------------------------------------------------- diff --git a/server/data/data-cassandra/src/main/java/org/apache/james/sieve/cassandra/tables/CassandraSieveActiveTable.java b/server/data/data-cassandra/src/main/java/org/apache/james/sieve/cassandra/tables/CassandraSieveActiveTable.java new file mode 100644 index 0000000..efc64d0 --- /dev/null +++ b/server/data/data-cassandra/src/main/java/org/apache/james/sieve/cassandra/tables/CassandraSieveActiveTable.java @@ -0,0 +1,30 @@ +/**************************************************************** + * 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.tables; + +public interface CassandraSieveActiveTable { + + String TABLE_NAME = "sieve_active"; + + String USER_NAME = "user_name"; + String SCRIPT_NAME = "script_name"; + String DATE = "date"; + +} http://git-wip-us.apache.org/repos/asf/james-project/blob/f28cc423/server/data/data-cassandra/src/main/java/org/apache/james/sieve/cassandra/tables/CassandraSieveTable.java ---------------------------------------------------------------------- diff --git a/server/data/data-cassandra/src/main/java/org/apache/james/sieve/cassandra/tables/CassandraSieveTable.java b/server/data/data-cassandra/src/main/java/org/apache/james/sieve/cassandra/tables/CassandraSieveTable.java index 9479ea3..c247352 100644 --- a/server/data/data-cassandra/src/main/java/org/apache/james/sieve/cassandra/tables/CassandraSieveTable.java +++ b/server/data/data-cassandra/src/main/java/org/apache/james/sieve/cassandra/tables/CassandraSieveTable.java @@ -26,6 +26,5 @@ public interface CassandraSieveTable { String SCRIPT_NAME = "script_name"; String SCRIPT_CONTENT = "script_content"; String IS_ACTIVE = "is_active"; - String DATE = "date"; String SIZE = "size"; } http://git-wip-us.apache.org/repos/asf/james-project/blob/f28cc423/server/data/data-cassandra/src/test/java/org/apache/james/sieve/cassandra/CassandraActiveScriptDAOTest.java ---------------------------------------------------------------------- diff --git a/server/data/data-cassandra/src/test/java/org/apache/james/sieve/cassandra/CassandraActiveScriptDAOTest.java b/server/data/data-cassandra/src/test/java/org/apache/james/sieve/cassandra/CassandraActiveScriptDAOTest.java new file mode 100644 index 0000000..efdfa14 --- /dev/null +++ b/server/data/data-cassandra/src/test/java/org/apache/james/sieve/cassandra/CassandraActiveScriptDAOTest.java @@ -0,0 +1,97 @@ +/**************************************************************** + * 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; + +import static org.assertj.core.api.Assertions.assertThat; + +import java.util.Optional; + +import org.apache.james.backends.cassandra.CassandraCluster; +import org.apache.james.sieve.cassandra.model.ActiveScriptInfo; +import org.junit.After; +import org.junit.Before; +import org.junit.Test; + +public class CassandraActiveScriptDAOTest { + + public static final String USER = "user"; + public static final String SCRIPT_NAME = "sciptName"; + public static final String NEW_SCRIPT_NAME = "newScriptName"; + private static CassandraCluster cassandra = CassandraCluster.create(new CassandraSieveRepositoryModule()); + private CassandraActiveScriptDAO activeScriptDAO; + + @Before + public void setUp() { + cassandra.ensureAllTables(); + activeScriptDAO = new CassandraActiveScriptDAO(cassandra.getConf()); + } + + @After + public void tearDown() { + cassandra.clearAllTables(); + } + + @Test + public void getActiveSctiptInfoShouldReturnEmptyByDefault() { + assertThat(activeScriptDAO.getActiveSctiptInfo(USER).join().isPresent()) + .isFalse(); + } + + @Test + public void getActiveSctiptInfoShouldReturnStoredName() { + activeScriptDAO.activate(USER, SCRIPT_NAME).join(); + + Optional<ActiveScriptInfo> actual = activeScriptDAO.getActiveSctiptInfo(USER).join(); + + assertThat(actual.isPresent()).isTrue(); + assertThat(actual.get().getName()).isEqualTo(SCRIPT_NAME); + } + + @Test + public void activateShouldAllowRename() { + activeScriptDAO.activate(USER, SCRIPT_NAME).join(); + + activeScriptDAO.activate(USER, NEW_SCRIPT_NAME).join(); + + Optional<ActiveScriptInfo> actual = activeScriptDAO.getActiveSctiptInfo(USER).join(); + assertThat(actual.isPresent()).isTrue(); + assertThat(actual.get().getName()).isEqualTo(NEW_SCRIPT_NAME); + } + + @Test + public void unactivateShouldAllowRemovingActiveScript() { + activeScriptDAO.activate(USER, SCRIPT_NAME).join(); + + activeScriptDAO.unactivate(USER).join(); + + Optional<ActiveScriptInfo> actual = activeScriptDAO.getActiveSctiptInfo(USER).join(); + assertThat(actual.isPresent()).isFalse(); + } + + + @Test + public void unactivateShouldWorkWhenNoneStore() { + activeScriptDAO.unactivate(USER).join(); + + Optional<ActiveScriptInfo> actual = activeScriptDAO.getActiveSctiptInfo(USER).join(); + assertThat(actual.isPresent()).isFalse(); + } + +} http://git-wip-us.apache.org/repos/asf/james-project/blob/f28cc423/server/data/data-cassandra/src/test/java/org/apache/james/sieve/cassandra/CassandraSieveDAOTest.java ---------------------------------------------------------------------- diff --git a/server/data/data-cassandra/src/test/java/org/apache/james/sieve/cassandra/CassandraSieveDAOTest.java b/server/data/data-cassandra/src/test/java/org/apache/james/sieve/cassandra/CassandraSieveDAOTest.java new file mode 100644 index 0000000..243279b --- /dev/null +++ b/server/data/data-cassandra/src/test/java/org/apache/james/sieve/cassandra/CassandraSieveDAOTest.java @@ -0,0 +1,143 @@ +/**************************************************************** + * 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; + +import static org.assertj.core.api.Assertions.assertThat; + +import java.util.List; +import java.util.Optional; + +import org.apache.james.backends.cassandra.CassandraCluster; +import org.apache.james.sieve.cassandra.model.Script; +import org.apache.james.sieverepository.api.ScriptSummary; +import org.junit.After; +import org.junit.Before; +import org.junit.Test; + +public class CassandraSieveDAOTest { + + public static final String USER = "user"; + public static final String SCRIPT_NAME = "scriptName"; + public static final String SCRIPT_NAME2 = "scriptName2"; + public static final Script SCRIPT = Script.builder() + .name(SCRIPT_NAME) + .content("content") + .isActive(false) + .build(); + public static final Script SCRIPT2 = Script.builder() + .name(SCRIPT_NAME2) + .content("alternative content") + .isActive(true) + .build(); + public static final Script ACTIVE_SCRIPT = Script.builder() + .copyOf(SCRIPT) + .isActive(true) + .build(); + public static final Script SCRIPT_NEW_CONTENT = Script.builder() + .copyOf(SCRIPT) + .content("newContent") + .build(); + private static CassandraCluster cassandra = CassandraCluster.create(new CassandraSieveRepositoryModule()); + private CassandraSieveDAO sieveDAO; + + @Before + public void setUp() { + cassandra.ensureAllTables(); + sieveDAO = new CassandraSieveDAO(cassandra.getConf()); + } + + @After + public void tearDown() { + cassandra.clearAllTables(); + } + + @Test + public void getScriptShouldReturnEmptyByDefault() { + assertThat(sieveDAO.getScript(USER, SCRIPT_NAME).join().isPresent()) + .isFalse(); + } + + @Test + public void getScriptShouldReturnStoredScript() { + sieveDAO.insertScript(USER, SCRIPT).join(); + + Optional<Script> actual = sieveDAO.getScript(USER, SCRIPT_NAME).join(); + + assertThat(actual.isPresent()).isTrue(); + assertThat(actual.get()).isEqualTo(SCRIPT); + } + + @Test + public void insertScriptShouldUpdateContent() { + sieveDAO.insertScript(USER, SCRIPT).join(); + + sieveDAO.insertScript(USER, SCRIPT_NEW_CONTENT).join(); + + Optional<Script> actual = sieveDAO.getScript(USER, SCRIPT_NAME).join(); + assertThat(actual.isPresent()).isTrue(); + assertThat(actual.get()).isEqualTo(SCRIPT_NEW_CONTENT); + } + + @Test + public void insertScriptShouldUpdateActivate() { + sieveDAO.insertScript(USER, SCRIPT).join(); + + sieveDAO.insertScript(USER, ACTIVE_SCRIPT).join(); + + Optional<Script> actual = sieveDAO.getScript(USER, SCRIPT_NAME).join(); + assertThat(actual.isPresent()).isTrue(); + assertThat(actual.get()).isEqualTo(ACTIVE_SCRIPT); + } + + @Test + public void deleteScriptInCassandraShouldWork() { + sieveDAO.insertScript(USER, SCRIPT).join(); + + sieveDAO.deleteScriptInCassandra(USER, SCRIPT_NAME).join(); + + Optional<Script> actual = sieveDAO.getScript(USER, SCRIPT_NAME).join(); + assertThat(actual.isPresent()).isFalse(); + } + + @Test + public void deleteScriptInCassandraShouldWorkWhenNoneStore() { + sieveDAO.deleteScriptInCassandra(USER, SCRIPT_NAME).join(); + + Optional<Script> actual = sieveDAO.getScript(USER, SCRIPT_NAME).join(); + assertThat(actual.isPresent()).isFalse(); + } + + @Test + public void listScriptsShouldReturnEmpty() { + List<ScriptSummary> scriptSummaryList = sieveDAO.listScripts(USER).join(); + + assertThat(scriptSummaryList).isEmpty(); + } + + @Test + public void listScriptsShouldReturnSingleStoredValue() { + sieveDAO.insertScript(USER, SCRIPT).join(); + sieveDAO.insertScript(USER, SCRIPT2).join(); + + List<ScriptSummary> scriptSummaryList = sieveDAO.listScripts(USER).join(); + + assertThat(scriptSummaryList).containsOnly(SCRIPT.toSummary(), SCRIPT2.toSummary()); + } +} http://git-wip-us.apache.org/repos/asf/james-project/blob/f28cc423/server/data/data-cassandra/src/test/java/org/apache/james/sieve/cassandra/CassandraSieveQuotaDAOTest.java ---------------------------------------------------------------------- diff --git a/server/data/data-cassandra/src/test/java/org/apache/james/sieve/cassandra/CassandraSieveQuotaDAOTest.java b/server/data/data-cassandra/src/test/java/org/apache/james/sieve/cassandra/CassandraSieveQuotaDAOTest.java new file mode 100644 index 0000000..51ae3ed --- /dev/null +++ b/server/data/data-cassandra/src/test/java/org/apache/james/sieve/cassandra/CassandraSieveQuotaDAOTest.java @@ -0,0 +1,149 @@ +/**************************************************************** + * 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; + +import static org.assertj.core.api.Assertions.assertThat; + +import java.util.Optional; + +import org.apache.james.backends.cassandra.CassandraCluster; +import org.junit.After; +import org.junit.Before; +import org.junit.Test; + +public class CassandraSieveQuotaDAOTest { + + public static final String USER = "user"; + private static CassandraCluster cassandra = CassandraCluster.create(new CassandraSieveRepositoryModule()); + private CassandraSieveQuotaDAO sieveQuotaDAO; + + @Before + public void setUp() { + cassandra.ensureAllTables(); + sieveQuotaDAO = new CassandraSieveQuotaDAO(cassandra.getConf()); + } + + @After + public void tearDown() { + cassandra.clearAllTables(); + } + + @Test + public void getQuotaShouldReturnEmptyByDefault() { + assertThat(sieveQuotaDAO.getQuota().join().isPresent()) + .isFalse(); + } + + @Test + public void getQuotaUserShouldReturnEmptyByDefault() { + assertThat(sieveQuotaDAO.getQuota(USER).join().isPresent()) + .isFalse(); + } + + @Test + public void getQuotaShouldReturnStoredValue() { + long quota = 15L; + sieveQuotaDAO.setQuota(quota).join(); + + Optional<Long> actual = sieveQuotaDAO.getQuota().join(); + assertThat(actual.isPresent()).isTrue(); + assertThat(actual.get()).isEqualTo(quota); + } + + @Test + public void getQuotaUserShouldReturnStoredValue() { + long quota = 15L; + sieveQuotaDAO.setQuota(USER, quota).join(); + + Optional<Long> actual = sieveQuotaDAO.getQuota(USER).join(); + assertThat(actual.isPresent()).isTrue(); + assertThat(actual.get()).isEqualTo(quota); + } + + @Test + public void removeQuotaShouldDeleteQuota() { + sieveQuotaDAO.setQuota(15L).join(); + + sieveQuotaDAO.removeQuota().join(); + + Optional<Long> actual = sieveQuotaDAO.getQuota().join(); + assertThat(actual.isPresent()).isFalse(); + } + + @Test + public void removeQuotaUserShouldDeleteQuotaUser() { + sieveQuotaDAO.setQuota(USER, 15L).join(); + + sieveQuotaDAO.removeQuota(USER).join(); + + Optional<Long> actual = sieveQuotaDAO.getQuota(USER).join(); + assertThat(actual.isPresent()).isFalse(); + } + + @Test + public void removeQuotaShouldWorkWhenNoneStore() { + sieveQuotaDAO.removeQuota().join(); + + Optional<Long> actual = sieveQuotaDAO.getQuota().join(); + assertThat(actual.isPresent()).isFalse(); + } + + @Test + public void removeQuotaUserShouldWorkWhenNoneStore() { + sieveQuotaDAO.removeQuota(USER).join(); + + Optional<Long> actual = sieveQuotaDAO.getQuota(USER).join(); + assertThat(actual.isPresent()).isFalse(); + } + + @Test + public void spaceUsedByShouldReturnZeroByDefault() { + assertThat(sieveQuotaDAO.spaceUsedBy(USER).join()).isEqualTo(0); + } + + @Test + public void spaceUsedByShouldReturnStoredValue() { + long spaceUsed = 18L; + + sieveQuotaDAO.updateSpaceUsed(USER, spaceUsed).join(); + + assertThat(sieveQuotaDAO.spaceUsedBy(USER).join()).isEqualTo(spaceUsed); + } + + @Test + public void updateSpaceUsedShouldBeAdditive() { + long spaceUsed = 18L; + + sieveQuotaDAO.updateSpaceUsed(USER, spaceUsed).join(); + sieveQuotaDAO.updateSpaceUsed(USER, spaceUsed).join(); + + assertThat(sieveQuotaDAO.spaceUsedBy(USER).join()).isEqualTo(2 * spaceUsed); + } + + @Test + public void updateSpaceUsedShouldWorkWithNegativeValues() { + long spaceUsed = 18L; + + sieveQuotaDAO.updateSpaceUsed(USER, spaceUsed).join(); + sieveQuotaDAO.updateSpaceUsed(USER, -1 * spaceUsed).join(); + + assertThat(sieveQuotaDAO.spaceUsedBy(USER).join()).isEqualTo(0L); + } +} http://git-wip-us.apache.org/repos/asf/james-project/blob/f28cc423/server/data/data-cassandra/src/test/java/org/apache/james/sieve/cassandra/CassandraSieveRepositoryTest.java ---------------------------------------------------------------------- diff --git a/server/data/data-cassandra/src/test/java/org/apache/james/sieve/cassandra/CassandraSieveRepositoryTest.java b/server/data/data-cassandra/src/test/java/org/apache/james/sieve/cassandra/CassandraSieveRepositoryTest.java index bf1fd34..8451207 100644 --- a/server/data/data-cassandra/src/test/java/org/apache/james/sieve/cassandra/CassandraSieveRepositoryTest.java +++ b/server/data/data-cassandra/src/test/java/org/apache/james/sieve/cassandra/CassandraSieveRepositoryTest.java @@ -19,65 +19,23 @@ package org.apache.james.sieve.cassandra; -import static com.datastax.driver.core.querybuilder.QueryBuilder.insertInto; -import static org.assertj.core.api.Assertions.assertThat; - -import java.util.Date; - import org.apache.james.backends.cassandra.CassandraCluster; -import org.apache.james.sieve.cassandra.tables.CassandraSieveTable; import org.apache.james.sieverepository.api.SieveRepository; -import org.apache.james.sieverepository.api.exception.ScriptNotFoundException; import org.apache.james.sieverepository.lib.AbstractSieveRepositoryTest; -import org.joda.time.DateTime; -import org.junit.Test; public class CassandraSieveRepositoryTest extends AbstractSieveRepositoryTest { - public static final int DATE_TIMESTAMP = 123456141; - private CassandraCluster cassandra; - - public CassandraSieveRepositoryTest() { - cassandra = CassandraCluster.create(new CassandraSieveRepositoryModule()); - } + private CassandraCluster cassandra = CassandraCluster.create(new CassandraSieveRepositoryModule()); @Override protected SieveRepository createSieveRepository() throws Exception { return new CassandraSieveRepository( new CassandraSieveDAO(cassandra.getConf()), - new CassandraSieveQuotaDAO(cassandra.getConf())); + new CassandraSieveQuotaDAO(cassandra.getConf()), + new CassandraActiveScriptDAO(cassandra.getConf())); } @Override protected void cleanUp() throws Exception { cassandra.clearAllTables(); } - - @Test - public void getActivationDateForActiveScriptShouldWork() throws Exception { - cassandra.getConf().execute( - insertInto(CassandraSieveTable.TABLE_NAME) - .value(CassandraSieveTable.USER_NAME, USER) - .value(CassandraSieveTable.SCRIPT_NAME, SCRIPT_NAME) - .value(CassandraSieveTable.SCRIPT_CONTENT, SCRIPT_CONTENT) - .value(CassandraSieveTable.IS_ACTIVE, true) - .value(CassandraSieveTable.SIZE, SCRIPT_CONTENT.length()) - .value(CassandraSieveTable.DATE, new Date(DATE_TIMESTAMP)) - ); - assertThat(sieveRepository.getActivationDateForActiveScript(USER)).isEqualTo(new DateTime(DATE_TIMESTAMP)); - } - - - @Test(expected = ScriptNotFoundException.class) - public void getActivationDateForActiveScriptShouldThrowOnMissingActiveScript() throws Exception { - cassandra.getConf().execute( - insertInto(CassandraSieveTable.TABLE_NAME) - .value(CassandraSieveTable.USER_NAME, USER) - .value(CassandraSieveTable.SCRIPT_NAME, SCRIPT_NAME) - .value(CassandraSieveTable.SCRIPT_CONTENT, SCRIPT_CONTENT) - .value(CassandraSieveTable.IS_ACTIVE, false) - .value(CassandraSieveTable.SIZE, SCRIPT_CONTENT.length()) - .value(CassandraSieveTable.DATE, DATE_TIMESTAMP) - ); - sieveRepository.getActivationDateForActiveScript(USER); - } } \ No newline at end of file --------------------------------------------------------------------- To unsubscribe, e-mail: server-dev-unsubscr...@james.apache.org For additional commands, e-mail: server-dev-h...@james.apache.org