You are viewing a plain text version of this content. The canonical link for it is here.
Posted to server-dev@james.apache.org by ro...@apache.org on 2018/12/19 08:24:38 UTC
[1/8] james-project git commit: JAMES-2618 Write SchemaVersion after
Types and Tables creation
Repository: james-project
Updated Branches:
refs/heads/master c739d3aec -> 3b223d537
JAMES-2618 Write SchemaVersion after Types and Tables creation
Project: http://git-wip-us.apache.org/repos/asf/james-project/repo
Commit: http://git-wip-us.apache.org/repos/asf/james-project/commit/d796a1d3
Tree: http://git-wip-us.apache.org/repos/asf/james-project/tree/d796a1d3
Diff: http://git-wip-us.apache.org/repos/asf/james-project/diff/d796a1d3
Branch: refs/heads/master
Commit: d796a1d3c103683c2096313805745c78f6d5ef64
Parents: c739d3a
Author: Gautier DI FOLCO <gd...@linagora.com>
Authored: Tue Dec 4 18:46:46 2018 +0100
Committer: Raphael Ouazana <ra...@linagora.com>
Committed: Wed Dec 19 09:23:43 2018 +0100
----------------------------------------------------------------------
backends-common/cassandra/pom.xml | 5 +
.../cassandra/components/CassandraTable.java | 55 ++++++-
.../cassandra/components/CassandraType.java | 50 +++++-
.../cassandra/init/CassandraTableManager.java | 15 +-
.../cassandra/init/CassandraTypesCreator.java | 14 +-
.../SessionWithInitializedTablesFactory.java | 29 +++-
.../components/CassandraTableTest.java | 103 ++++++++++++
.../cassandra/components/CassandraTypeTest.java | 104 +++++++++++++
.../init/CassandraTableManagerTest.java | 104 +++++++++++++
.../init/CassandraTypeProviderTest.java | 5 +-
.../init/CassandraTypesCreatorTest.java | 112 +++++++++++++
...SessionWithInitializedTablesFactoryTest.java | 156 +++++++++++++++++++
.../cassandra/mail/MailboxAggregateModule.java | 2 +
.../CassandraVacationRepositoryTest.java | 6 +-
.../cassandra/CassandraMailRepositoryTest.java | 2 +
...abbitMQMailQueueConfigurationChangeTest.java | 2 +
16 files changed, 741 insertions(+), 23 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/james-project/blob/d796a1d3/backends-common/cassandra/pom.xml
----------------------------------------------------------------------
diff --git a/backends-common/cassandra/pom.xml b/backends-common/cassandra/pom.xml
index 6b35ab1..bcac1fc 100644
--- a/backends-common/cassandra/pom.xml
+++ b/backends-common/cassandra/pom.xml
@@ -122,6 +122,11 @@
<scope>test</scope>
</dependency>
<dependency>
+ <groupId>org.junit.jupiter</groupId>
+ <artifactId>junit-jupiter-params</artifactId>
+ <scope>test</scope>
+ </dependency>
+ <dependency>
<groupId>org.junit.platform</groupId>
<artifactId>junit-platform-launcher</artifactId>
<scope>test</scope>
http://git-wip-us.apache.org/repos/asf/james-project/blob/d796a1d3/backends-common/cassandra/src/main/java/org/apache/james/backends/cassandra/components/CassandraTable.java
----------------------------------------------------------------------
diff --git a/backends-common/cassandra/src/main/java/org/apache/james/backends/cassandra/components/CassandraTable.java b/backends-common/cassandra/src/main/java/org/apache/james/backends/cassandra/components/CassandraTable.java
index cb9100a..ed2d53b 100644
--- a/backends-common/cassandra/src/main/java/org/apache/james/backends/cassandra/components/CassandraTable.java
+++ b/backends-common/cassandra/src/main/java/org/apache/james/backends/cassandra/components/CassandraTable.java
@@ -19,9 +19,27 @@
package org.apache.james.backends.cassandra.components;
+import java.util.Objects;
+
+import com.datastax.driver.core.KeyspaceMetadata;
+import com.datastax.driver.core.Session;
import com.datastax.driver.core.Statement;
+import com.google.common.base.MoreObjects;
public class CassandraTable {
+ public enum InitializationStatus {
+ ALREADY_DONE,
+ PARTIAL,
+ FULL;
+
+ public InitializationStatus reduce(InitializationStatus other) {
+ if (this == other) {
+ return this;
+ }
+
+ return PARTIAL;
+ }
+ }
private final Statement createStatement;
private final String name;
@@ -31,11 +49,40 @@ public class CassandraTable {
this.name = name;
}
- public Statement getCreateStatement() {
- return createStatement;
- }
-
public String getName() {
return name;
}
+
+ public InitializationStatus initialize(KeyspaceMetadata keyspaceMetadata, Session session) {
+ if (keyspaceMetadata.getTable(name) != null) {
+ return InitializationStatus.ALREADY_DONE;
+ }
+
+ session.execute(createStatement);
+ return InitializationStatus.FULL;
+ }
+
+ @Override
+ public final boolean equals(Object o) {
+ if (o instanceof CassandraTable) {
+ CassandraTable that = (CassandraTable) o;
+
+ return Objects.equals(this.name, that.name)
+ && Objects.equals(this.createStatement, that.createStatement);
+ }
+ return false;
+ }
+
+ @Override
+ public final int hashCode() {
+ return Objects.hash(name, createStatement);
+ }
+
+ @Override
+ public String toString() {
+ return MoreObjects.toStringHelper(this)
+ .add("name", name)
+ .add("createStatement", createStatement)
+ .toString();
+ }
}
http://git-wip-us.apache.org/repos/asf/james-project/blob/d796a1d3/backends-common/cassandra/src/main/java/org/apache/james/backends/cassandra/components/CassandraType.java
----------------------------------------------------------------------
diff --git a/backends-common/cassandra/src/main/java/org/apache/james/backends/cassandra/components/CassandraType.java b/backends-common/cassandra/src/main/java/org/apache/james/backends/cassandra/components/CassandraType.java
index 2b41d72..082eff2 100644
--- a/backends-common/cassandra/src/main/java/org/apache/james/backends/cassandra/components/CassandraType.java
+++ b/backends-common/cassandra/src/main/java/org/apache/james/backends/cassandra/components/CassandraType.java
@@ -19,9 +19,27 @@
package org.apache.james.backends.cassandra.components;
+import java.util.Objects;
+
+import com.datastax.driver.core.KeyspaceMetadata;
+import com.datastax.driver.core.Session;
import com.datastax.driver.core.schemabuilder.CreateType;
+import com.google.common.base.MoreObjects;
public class CassandraType {
+ public enum InitializationStatus {
+ ALREADY_DONE,
+ PARTIAL,
+ FULL;
+
+ public InitializationStatus reduce(InitializationStatus other) {
+ if (this == other) {
+ return this;
+ }
+
+ return PARTIAL;
+ }
+ }
private final String name;
private final CreateType createStatement;
@@ -35,8 +53,36 @@ public class CassandraType {
return name;
}
- public CreateType getCreateStatement() {
- return createStatement;
+ public InitializationStatus initialize(KeyspaceMetadata keyspaceMetadata, Session session) {
+ if (keyspaceMetadata.getUserType(name) != null) {
+ return InitializationStatus.ALREADY_DONE;
+ }
+
+ session.execute(createStatement);
+ return InitializationStatus.FULL;
}
+ @Override
+ public final boolean equals(Object o) {
+ if (o instanceof CassandraType) {
+ CassandraType that = (CassandraType) o;
+
+ return Objects.equals(this.name, that.name)
+ && Objects.equals(this.createStatement, that.createStatement);
+ }
+ return false;
+ }
+
+ @Override
+ public final int hashCode() {
+ return Objects.hash(name, createStatement);
+ }
+
+ @Override
+ public String toString() {
+ return MoreObjects.toStringHelper(this)
+ .add("name", name)
+ .add("createStatement", createStatement)
+ .toString();
+ }
}
http://git-wip-us.apache.org/repos/asf/james-project/blob/d796a1d3/backends-common/cassandra/src/main/java/org/apache/james/backends/cassandra/init/CassandraTableManager.java
----------------------------------------------------------------------
diff --git a/backends-common/cassandra/src/main/java/org/apache/james/backends/cassandra/init/CassandraTableManager.java b/backends-common/cassandra/src/main/java/org/apache/james/backends/cassandra/init/CassandraTableManager.java
index f406b5c..3317138 100644
--- a/backends-common/cassandra/src/main/java/org/apache/james/backends/cassandra/init/CassandraTableManager.java
+++ b/backends-common/cassandra/src/main/java/org/apache/james/backends/cassandra/init/CassandraTableManager.java
@@ -23,6 +23,7 @@ import javax.inject.Inject;
import org.apache.james.backends.cassandra.components.CassandraModule;
import org.apache.james.backends.cassandra.components.CassandraTable;
+import org.apache.james.backends.cassandra.components.CassandraTable.InitializationStatus;
import org.apache.james.backends.cassandra.utils.CassandraAsyncExecutor;
import com.datastax.driver.core.KeyspaceMetadata;
@@ -43,17 +44,16 @@ public class CassandraTableManager {
this.module = module;
}
- public CassandraTableManager ensureAllTables() {
+ public InitializationStatus initializeTables() {
KeyspaceMetadata keyspaceMetadata = session.getCluster()
.getMetadata()
.getKeyspace(session.getLoggedKeyspace());
- module.moduleTables()
- .stream()
- .filter(table -> keyspaceMetadata.getTable(table.getName()) == null)
- .forEach(table -> session.execute(table.getCreateStatement()));
-
- return this;
+ return module.moduleTables()
+ .stream()
+ .map(table -> table.initialize(keyspaceMetadata, session))
+ .reduce((left, right) -> left.reduce(right))
+ .orElse(InitializationStatus.ALREADY_DONE);
}
public void clearAllTables() {
@@ -75,5 +75,4 @@ public class CassandraTableManager {
.filter(resultSet -> !resultSet.isExhausted())
.flatMap(ignored -> Mono.fromFuture(executor.execute(QueryBuilder.truncate(name))));
}
-
}
http://git-wip-us.apache.org/repos/asf/james-project/blob/d796a1d3/backends-common/cassandra/src/main/java/org/apache/james/backends/cassandra/init/CassandraTypesCreator.java
----------------------------------------------------------------------
diff --git a/backends-common/cassandra/src/main/java/org/apache/james/backends/cassandra/init/CassandraTypesCreator.java b/backends-common/cassandra/src/main/java/org/apache/james/backends/cassandra/init/CassandraTypesCreator.java
index 27179bc..8c9a0aa 100644
--- a/backends-common/cassandra/src/main/java/org/apache/james/backends/cassandra/init/CassandraTypesCreator.java
+++ b/backends-common/cassandra/src/main/java/org/apache/james/backends/cassandra/init/CassandraTypesCreator.java
@@ -21,7 +21,9 @@ package org.apache.james.backends.cassandra.init;
import org.apache.james.backends.cassandra.components.CassandraModule;
import org.apache.james.backends.cassandra.components.CassandraType;
+import org.apache.james.backends.cassandra.components.CassandraType.InitializationStatus;
+import com.datastax.driver.core.KeyspaceMetadata;
import com.datastax.driver.core.Session;
import com.google.common.collect.ImmutableList;
@@ -34,8 +36,14 @@ public class CassandraTypesCreator {
this.session = session;
}
- public void initializeTypes() {
- types.forEach((type) -> session.execute(type.getCreateStatement()));
- }
+ public InitializationStatus initializeTypes() {
+ KeyspaceMetadata keyspaceMetadata = session.getCluster()
+ .getMetadata()
+ .getKeyspace(session.getLoggedKeyspace());
+ return types.stream()
+ .map(type -> type.initialize(keyspaceMetadata, session))
+ .reduce((left, right) -> left.reduce(right))
+ .orElse(InitializationStatus.ALREADY_DONE);
+ }
}
http://git-wip-us.apache.org/repos/asf/james-project/blob/d796a1d3/backends-common/cassandra/src/main/java/org/apache/james/backends/cassandra/init/SessionWithInitializedTablesFactory.java
----------------------------------------------------------------------
diff --git a/backends-common/cassandra/src/main/java/org/apache/james/backends/cassandra/init/SessionWithInitializedTablesFactory.java b/backends-common/cassandra/src/main/java/org/apache/james/backends/cassandra/init/SessionWithInitializedTablesFactory.java
index d87b41b..b5213d7 100644
--- a/backends-common/cassandra/src/main/java/org/apache/james/backends/cassandra/init/SessionWithInitializedTablesFactory.java
+++ b/backends-common/cassandra/src/main/java/org/apache/james/backends/cassandra/init/SessionWithInitializedTablesFactory.java
@@ -19,13 +19,19 @@
package org.apache.james.backends.cassandra.init;
+import java.util.stream.Stream;
import javax.annotation.PreDestroy;
import javax.inject.Inject;
import javax.inject.Provider;
import javax.inject.Singleton;
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.backends.cassandra.init.configuration.ClusterConfiguration;
+import org.apache.james.backends.cassandra.utils.CassandraUtils;
+import org.apache.james.backends.cassandra.versions.CassandraSchemaVersionDAO;
+import org.apache.james.backends.cassandra.versions.CassandraSchemaVersionManager;
import com.datastax.driver.core.Cluster;
import com.datastax.driver.core.Session;
@@ -44,10 +50,10 @@ public class SessionWithInitializedTablesFactory implements Provider<Session> {
private Session createSession(Cluster cluster, String keyspace) {
Session session = cluster.connect(keyspace);
try {
- new CassandraTypesCreator(module, session)
- .initializeTypes();
- new CassandraTableManager(module, session)
- .ensureAllTables();
+ if (allOperationsAreFullyPerformed(session)) {
+ new CassandraSchemaVersionDAO(session, CassandraUtils.WITH_DEFAULT_CONFIGURATION)
+ .updateVersion(CassandraSchemaVersionManager.MAX_VERSION);
+ }
return session;
} catch (Exception e) {
session.close();
@@ -55,6 +61,21 @@ public class SessionWithInitializedTablesFactory implements Provider<Session> {
}
}
+ private boolean allOperationsAreFullyPerformed(Session session) {
+ Stream<Boolean> operations = Stream.of(createTypes(session), createTables(session));
+ return operations.allMatch(updated -> updated);
+ }
+
+ private boolean createTypes(Session session) {
+ return new CassandraTypesCreator(module, session)
+ .initializeTypes() == CassandraType.InitializationStatus.FULL;
+ }
+
+ private boolean createTables(Session session) {
+ return new CassandraTableManager(module, session)
+ .initializeTables() == CassandraTable.InitializationStatus.FULL;
+ }
+
@Override
public Session get() {
return session;
http://git-wip-us.apache.org/repos/asf/james-project/blob/d796a1d3/backends-common/cassandra/src/test/java/org/apache/james/backends/cassandra/components/CassandraTableTest.java
----------------------------------------------------------------------
diff --git a/backends-common/cassandra/src/test/java/org/apache/james/backends/cassandra/components/CassandraTableTest.java b/backends-common/cassandra/src/test/java/org/apache/james/backends/cassandra/components/CassandraTableTest.java
new file mode 100644
index 0000000..a0d264f
--- /dev/null
+++ b/backends-common/cassandra/src/test/java/org/apache/james/backends/cassandra/components/CassandraTableTest.java
@@ -0,0 +1,103 @@
+/****************************************************************
+ * Licensed to the Apache Software Foundation (ASF) under one *
+ * or more contributor license agreements. See the NOTICE file *
+ * distributed with this work for additional information *
+ * regarding copyright ownership. The ASF licenses this file *
+ * to you under the Apache License, Version 2.0 (the *
+ * "License"); you may not use this file except in compliance *
+ * with the License. You may obtain a copy of the License at *
+ * *
+ * http://www.apache.org/licenses/LICENSE-2.0 *
+ * *
+ * Unless required by applicable law or agreed to in writing, *
+ * software distributed under the License is distributed on an *
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY *
+ * KIND, either express or implied. See the License for the *
+ * specific language governing permissions and limitations *
+ * under the License. *
+ ****************************************************************/
+package org.apache.james.backends.cassandra.components;
+
+import static org.apache.james.backends.cassandra.components.CassandraTable.InitializationStatus.ALREADY_DONE;
+import static org.apache.james.backends.cassandra.components.CassandraTable.InitializationStatus.FULL;
+import static org.apache.james.backends.cassandra.components.CassandraTable.InitializationStatus.PARTIAL;
+import static org.assertj.core.api.Assertions.assertThat;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+import java.util.stream.Stream;
+
+import org.apache.james.backends.cassandra.components.CassandraTable.InitializationStatus;
+import org.junit.jupiter.api.Nested;
+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.datastax.driver.core.KeyspaceMetadata;
+import com.datastax.driver.core.Session;
+import com.datastax.driver.core.Statement;
+import com.datastax.driver.core.TableMetadata;
+import com.datastax.driver.core.schemabuilder.SchemaBuilder;
+
+import nl.jqno.equalsverifier.EqualsVerifier;
+
+class CassandraTableTest {
+ private static final String NAME = "tableName";
+ private static final Statement STATEMENT = SchemaBuilder.createTable(NAME);
+ private static final CassandraTable TABLE = new CassandraTable(NAME, STATEMENT);
+
+ @Test
+ void shouldRespectBeanContract() {
+ EqualsVerifier.forClass(CassandraTable.class)
+ .verify();
+ }
+
+ @Test
+ void initializeShouldExecuteCreateStatementAndReturnFullWhenTableDoesNotExist() {
+ KeyspaceMetadata keyspace = mock(KeyspaceMetadata.class);
+ when(keyspace.getTable(NAME)).thenReturn(null);
+ Session session = mock(Session.class);
+
+ assertThat(TABLE.initialize(keyspace, session))
+ .isEqualByComparingTo(FULL);
+
+ verify(keyspace).getTable(NAME);
+ verify(session).execute(STATEMENT);
+ }
+
+ @Test
+ void initializeShouldExecuteReturnAlreadyDoneWhenTableExists() {
+ KeyspaceMetadata keyspace = mock(KeyspaceMetadata.class);
+ when(keyspace.getTable(NAME)).thenReturn(mock(TableMetadata.class));
+ Session session = mock(Session.class);
+
+ assertThat(TABLE.initialize(keyspace, session))
+ .isEqualByComparingTo(ALREADY_DONE);
+
+ verify(keyspace).getTable(NAME);
+ verify(session, never()).execute(STATEMENT);
+ }
+
+ @ParameterizedTest
+ @MethodSource
+ void initializationStatusReduceShouldFallIntoTheRightState(InitializationStatus left, InitializationStatus right, InitializationStatus expectedResult) {
+ assertThat(left.reduce(right)).isEqualByComparingTo(expectedResult);
+ }
+
+ private static Stream<Arguments> initializationStatusReduceShouldFallIntoTheRightState() {
+ return Stream.of(
+ Arguments.of(ALREADY_DONE, ALREADY_DONE, ALREADY_DONE),
+ Arguments.of(ALREADY_DONE, PARTIAL, PARTIAL),
+ Arguments.of(ALREADY_DONE, FULL, PARTIAL),
+ Arguments.of(PARTIAL, PARTIAL, PARTIAL),
+ Arguments.of(PARTIAL, PARTIAL, PARTIAL),
+ Arguments.of(PARTIAL, FULL, PARTIAL),
+ Arguments.of(FULL, ALREADY_DONE, PARTIAL),
+ Arguments.of(FULL, PARTIAL, PARTIAL),
+ Arguments.of(FULL, FULL, FULL)
+ );
+ }
+}
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/james-project/blob/d796a1d3/backends-common/cassandra/src/test/java/org/apache/james/backends/cassandra/components/CassandraTypeTest.java
----------------------------------------------------------------------
diff --git a/backends-common/cassandra/src/test/java/org/apache/james/backends/cassandra/components/CassandraTypeTest.java b/backends-common/cassandra/src/test/java/org/apache/james/backends/cassandra/components/CassandraTypeTest.java
new file mode 100644
index 0000000..7973c83
--- /dev/null
+++ b/backends-common/cassandra/src/test/java/org/apache/james/backends/cassandra/components/CassandraTypeTest.java
@@ -0,0 +1,104 @@
+/****************************************************************
+ * 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.backends.cassandra.components;
+
+import static org.apache.james.backends.cassandra.components.CassandraType.InitializationStatus.ALREADY_DONE;
+import static org.apache.james.backends.cassandra.components.CassandraType.InitializationStatus.FULL;
+import static org.apache.james.backends.cassandra.components.CassandraType.InitializationStatus.PARTIAL;
+import static org.assertj.core.api.Assertions.assertThat;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+import java.util.stream.Stream;
+
+import org.apache.james.backends.cassandra.components.CassandraType.InitializationStatus;
+import org.junit.jupiter.api.Nested;
+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.datastax.driver.core.KeyspaceMetadata;
+import com.datastax.driver.core.Session;
+import com.datastax.driver.core.UserType;
+import com.datastax.driver.core.schemabuilder.CreateType;
+import com.datastax.driver.core.schemabuilder.SchemaBuilder;
+
+import nl.jqno.equalsverifier.EqualsVerifier;
+
+class CassandraTypeTest {
+ private static final String NAME = "typeName";
+ private static final CreateType STATEMENT = SchemaBuilder.createType(NAME);
+ private static final CassandraType TYPE = new CassandraType(NAME, STATEMENT);
+
+ @Test
+ void shouldRespectBeanContract() {
+ EqualsVerifier.forClass(CassandraType.class)
+ .withPrefabValues(CreateType.class, SchemaBuilder.createType("name1"), SchemaBuilder.createType("name2"))
+ .verify();
+ }
+
+ @Test
+ void initializeShouldExecuteCreateStatementAndReturnFullWhenTypeDoesNotExist() {
+ KeyspaceMetadata keyspace = mock(KeyspaceMetadata.class);
+ when(keyspace.getUserType(NAME)).thenReturn(null);
+ Session session = mock(Session.class);
+
+ assertThat(TYPE.initialize(keyspace, session))
+ .isEqualByComparingTo(FULL);
+
+ verify(keyspace).getUserType(NAME);
+ verify(session).execute(STATEMENT);
+ }
+
+ @Test
+ void initializeShouldReturnAlreadyDoneWhenTypeExists() {
+ KeyspaceMetadata keyspace = mock(KeyspaceMetadata.class);
+ when(keyspace.getUserType(NAME)).thenReturn(mock(UserType.class));
+ Session session = mock(Session.class);
+
+ assertThat(TYPE.initialize(keyspace, session))
+ .isEqualByComparingTo(ALREADY_DONE);
+
+ verify(keyspace).getUserType(NAME);
+ verify(session, never()).execute(STATEMENT);
+ }
+
+ @ParameterizedTest
+ @MethodSource
+ void initializationStatusReduceShouldFallIntoTheRightState(InitializationStatus left, InitializationStatus right, InitializationStatus expectedResult) {
+ assertThat(left.reduce(right)).isEqualByComparingTo(expectedResult);
+ }
+
+ static Stream<Arguments> initializationStatusReduceShouldFallIntoTheRightState() {
+ return Stream.of(
+ Arguments.of(ALREADY_DONE, ALREADY_DONE, ALREADY_DONE),
+ Arguments.of(ALREADY_DONE, PARTIAL, PARTIAL),
+ Arguments.of(ALREADY_DONE, FULL, PARTIAL),
+ Arguments.of(PARTIAL, PARTIAL, PARTIAL),
+ Arguments.of(PARTIAL, PARTIAL, PARTIAL),
+ Arguments.of(PARTIAL, FULL, PARTIAL),
+ Arguments.of(FULL, ALREADY_DONE, PARTIAL),
+ Arguments.of(FULL, PARTIAL, PARTIAL),
+ Arguments.of(FULL, FULL, FULL)
+ );
+ }
+}
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/james-project/blob/d796a1d3/backends-common/cassandra/src/test/java/org/apache/james/backends/cassandra/init/CassandraTableManagerTest.java
----------------------------------------------------------------------
diff --git a/backends-common/cassandra/src/test/java/org/apache/james/backends/cassandra/init/CassandraTableManagerTest.java b/backends-common/cassandra/src/test/java/org/apache/james/backends/cassandra/init/CassandraTableManagerTest.java
new file mode 100644
index 0000000..2b5206b
--- /dev/null
+++ b/backends-common/cassandra/src/test/java/org/apache/james/backends/cassandra/init/CassandraTableManagerTest.java
@@ -0,0 +1,104 @@
+/****************************************************************
+ * 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.backends.cassandra.init;
+
+import static org.assertj.core.api.Assertions.assertThat;
+import static org.assertj.core.api.Assertions.assertThatCode;
+
+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.CassandraTable;
+import org.apache.james.backends.cassandra.versions.CassandraSchemaVersionModule;
+import org.apache.james.backends.cassandra.versions.table.CassandraSchemaVersionTable;
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.api.extension.RegisterExtension;
+
+import com.datastax.driver.core.DataType;
+import com.datastax.driver.core.querybuilder.QueryBuilder;
+import com.datastax.driver.core.schemabuilder.SchemaBuilder;
+
+class CassandraTableManagerTest {
+ private static final String TABLE_NAME = "tablename";
+
+ public static final CassandraModule MODULE = CassandraModule.aggregateModules(
+ CassandraSchemaVersionModule.MODULE,
+ CassandraModule.table(TABLE_NAME)
+ .comment("Testing table")
+ .statement(statement -> statement
+ .addPartitionKey("id", DataType.timeuuid())
+ .addClusteringColumn("clustering", DataType.bigint()))
+ .build());
+
+ @RegisterExtension
+ static CassandraClusterExtension cassandraCluster = new CassandraClusterExtension(MODULE);
+
+ private CassandraCluster cassandra;
+
+ @BeforeEach
+ void setUp(CassandraCluster cassandra) {
+ this.cassandra = cassandra;
+ }
+
+ @Test
+ void describeShouldNotReturnNullNorFailWhenTableIsDefined() {
+ ensureTableExistence(TABLE_NAME);
+ }
+
+ @Test
+ void initializeTableShouldCreateAllTheTables() {
+ cassandra.getConf().execute(SchemaBuilder.dropTable(TABLE_NAME));
+ cassandra.getConf().execute(SchemaBuilder.dropTable(CassandraSchemaVersionTable.TABLE_NAME));
+
+ assertThat(new CassandraTableManager(MODULE, cassandra.getConf()).initializeTables())
+ .isEqualByComparingTo(CassandraTable.InitializationStatus.FULL);
+
+ ensureTableExistence(TABLE_NAME);
+ }
+
+ @Test
+ void initializeTableShouldCreateAllTheMissingTable() {
+ cassandra.getConf().execute(SchemaBuilder.dropTable(TABLE_NAME));
+
+ assertThat(new CassandraTableManager(MODULE, cassandra.getConf()).initializeTables())
+ .isEqualByComparingTo(CassandraTable.InitializationStatus.PARTIAL);
+
+ ensureTableExistence(TABLE_NAME);
+ }
+
+ @Test
+ void initializeTableShouldNotPerformIfCalledASecondTime() {
+ assertThat(new CassandraTableManager(MODULE, cassandra.getConf()).initializeTables())
+ .isEqualByComparingTo(CassandraTable.InitializationStatus.ALREADY_DONE);
+ }
+
+ @Test
+ void initializeTableShouldNotFailIfCalledASecondTime() {
+ new CassandraTableManager(MODULE, cassandra.getConf()).initializeTables();
+
+ ensureTableExistence(TABLE_NAME);
+ }
+
+ private void ensureTableExistence(String tableName) {
+ assertThatCode(() -> cassandra.getConf().execute(QueryBuilder.select().from(tableName).limit(1)))
+ .doesNotThrowAnyException();
+ }
+}
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/james-project/blob/d796a1d3/backends-common/cassandra/src/test/java/org/apache/james/backends/cassandra/init/CassandraTypeProviderTest.java
----------------------------------------------------------------------
diff --git a/backends-common/cassandra/src/test/java/org/apache/james/backends/cassandra/init/CassandraTypeProviderTest.java b/backends-common/cassandra/src/test/java/org/apache/james/backends/cassandra/init/CassandraTypeProviderTest.java
index 1bf149c..e2e6f21 100644
--- a/backends-common/cassandra/src/test/java/org/apache/james/backends/cassandra/init/CassandraTypeProviderTest.java
+++ b/backends-common/cassandra/src/test/java/org/apache/james/backends/cassandra/init/CassandraTypeProviderTest.java
@@ -25,6 +25,7 @@ import static org.assertj.core.api.Assertions.assertThat;
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.CassandraType;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.RegisterExtension;
@@ -59,7 +60,9 @@ class CassandraTypeProviderTest {
void initializeTypesShouldCreateTheTypes() {
cassandra.getConf().execute(SchemaBuilder.dropType(TYPE_NAME));
- new CassandraTypesCreator(MODULE, cassandra.getConf()).initializeTypes();
+ assertThat(new CassandraTypesCreator(MODULE, cassandra.getConf()).initializeTypes())
+ .isEqualByComparingTo(CassandraType.InitializationStatus.FULL);
+
CassandraTypesProvider cassandraTypesProviderTest = new CassandraTypesProvider(MODULE, cassandra.getConf());
assertThat(cassandraTypesProviderTest.getDefinedUserType(TYPE_NAME))
.isNotNull();
http://git-wip-us.apache.org/repos/asf/james-project/blob/d796a1d3/backends-common/cassandra/src/test/java/org/apache/james/backends/cassandra/init/CassandraTypesCreatorTest.java
----------------------------------------------------------------------
diff --git a/backends-common/cassandra/src/test/java/org/apache/james/backends/cassandra/init/CassandraTypesCreatorTest.java b/backends-common/cassandra/src/test/java/org/apache/james/backends/cassandra/init/CassandraTypesCreatorTest.java
new file mode 100644
index 0000000..9db2f8c
--- /dev/null
+++ b/backends-common/cassandra/src/test/java/org/apache/james/backends/cassandra/init/CassandraTypesCreatorTest.java
@@ -0,0 +1,112 @@
+/****************************************************************
+ * 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.backends.cassandra.init;
+
+import static com.datastax.driver.core.DataType.text;
+import static org.assertj.core.api.Assertions.assertThat;
+
+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.CassandraType;
+import org.apache.james.backends.cassandra.versions.CassandraSchemaVersionModule;
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.api.extension.RegisterExtension;
+
+import com.datastax.driver.core.schemabuilder.SchemaBuilder;
+
+class CassandraTypesCreatorTest {
+ private static final String TYPE_NAME_1 = "typename1";
+ private static final String PROPERTY_1 = "property1";
+ private static final String TYPE_NAME_2 = "typename2";
+ private static final String PROPERTY_2 = "property2";
+
+ public static final CassandraModule MODULE = CassandraModule.aggregateModules(
+ CassandraSchemaVersionModule.MODULE,
+ CassandraModule.type(TYPE_NAME_1)
+ .statement(statement -> statement.addColumn(PROPERTY_1, text()))
+ .build(),
+ CassandraModule.type(TYPE_NAME_2)
+ .statement(statement -> statement.addColumn(PROPERTY_2, text()))
+ .build());
+
+ @RegisterExtension
+ static CassandraClusterExtension cassandraCluster = new CassandraClusterExtension(MODULE);
+
+ private CassandraCluster cassandra;
+
+ @BeforeEach
+ void setUp(CassandraCluster cassandra) {
+ this.cassandra = cassandra;
+ cassandra.getTypesProvider();
+ }
+
+ @Test
+ void getDefinedUserTypeShouldNotReturnNullNorFailWhenTypeIsDefined() {
+ assertThat(cassandra.getTypesProvider().getDefinedUserType(TYPE_NAME_1))
+ .isNotNull();
+ assertThat(cassandra.getTypesProvider().getDefinedUserType(TYPE_NAME_2))
+ .isNotNull();
+ }
+
+ @Test
+ void initializeTypesShouldCreateTheAllTypes() {
+ cassandra.getConf().execute(SchemaBuilder.dropType(TYPE_NAME_1));
+ cassandra.getConf().execute(SchemaBuilder.dropType(TYPE_NAME_2));
+
+ assertThat(new CassandraTypesCreator(MODULE, cassandra.getConf()).initializeTypes())
+ .isEqualByComparingTo(CassandraType.InitializationStatus.FULL);
+
+ CassandraTypesProvider cassandraTypesProviderTest = new CassandraTypesProvider(MODULE, cassandra.getConf());
+ assertThat(cassandraTypesProviderTest.getDefinedUserType(TYPE_NAME_1))
+ .isNotNull();
+ assertThat(cassandraTypesProviderTest.getDefinedUserType(TYPE_NAME_2))
+ .isNotNull();
+ }
+
+ @Test
+ void initializeTypesShouldCreateTheMissingType() {
+ cassandra.getConf().execute(SchemaBuilder.dropType(TYPE_NAME_1));
+
+ assertThat(new CassandraTypesCreator(MODULE, cassandra.getConf()).initializeTypes())
+ .isEqualByComparingTo(CassandraType.InitializationStatus.PARTIAL);
+
+ CassandraTypesProvider cassandraTypesProviderTest = new CassandraTypesProvider(MODULE, cassandra.getConf());
+ assertThat(cassandraTypesProviderTest.getDefinedUserType(TYPE_NAME_1))
+ .isNotNull();
+ }
+
+ @Test
+ void initializeTypesShouldNotPerformIfCalledASecondTime() {
+ assertThat(new CassandraTypesCreator(MODULE, cassandra.getConf()).initializeTypes())
+ .isEqualByComparingTo(CassandraType.InitializationStatus.ALREADY_DONE);
+ }
+
+ @Test
+ void initializeTypesShouldNotFailIfCalledASecondTime() {
+ new CassandraTypesCreator(MODULE, cassandra.getConf()).initializeTypes();
+
+ assertThat(cassandra.getTypesProvider().getDefinedUserType(TYPE_NAME_1))
+ .isNotNull();
+ assertThat(cassandra.getTypesProvider().getDefinedUserType(TYPE_NAME_2))
+ .isNotNull();
+ }
+}
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/james-project/blob/d796a1d3/backends-common/cassandra/src/test/java/org/apache/james/backends/cassandra/init/SessionWithInitializedTablesFactoryTest.java
----------------------------------------------------------------------
diff --git a/backends-common/cassandra/src/test/java/org/apache/james/backends/cassandra/init/SessionWithInitializedTablesFactoryTest.java b/backends-common/cassandra/src/test/java/org/apache/james/backends/cassandra/init/SessionWithInitializedTablesFactoryTest.java
new file mode 100644
index 0000000..631a027
--- /dev/null
+++ b/backends-common/cassandra/src/test/java/org/apache/james/backends/cassandra/init/SessionWithInitializedTablesFactoryTest.java
@@ -0,0 +1,156 @@
+/****************************************************************
+ * 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.backends.cassandra.init;
+
+import static com.datastax.driver.core.DataType.text;
+import static org.apache.james.backends.cassandra.CassandraCluster.KEYSPACE;
+import static org.apache.james.backends.cassandra.versions.CassandraSchemaVersionManager.MAX_VERSION;
+import static org.apache.james.backends.cassandra.versions.CassandraSchemaVersionManager.MIN_VERSION;
+import static org.assertj.core.api.Assertions.assertThat;
+
+import java.util.function.Supplier;
+
+import org.apache.james.backends.cassandra.DockerCassandraExtension;
+import org.apache.james.backends.cassandra.components.CassandraModule;
+import org.apache.james.backends.cassandra.init.configuration.ClusterConfiguration;
+import org.apache.james.backends.cassandra.utils.CassandraUtils;
+import org.apache.james.backends.cassandra.versions.CassandraSchemaVersionDAO;
+import org.apache.james.backends.cassandra.versions.CassandraSchemaVersionManager;
+import org.apache.james.backends.cassandra.versions.CassandraSchemaVersionModule;
+import org.apache.james.util.Host;
+import org.junit.jupiter.api.AfterAll;
+import org.junit.jupiter.api.AfterEach;
+import org.junit.jupiter.api.BeforeAll;
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.api.extension.ExtendWith;
+
+import com.datastax.driver.core.Cluster;
+import com.datastax.driver.core.DataType;
+import com.datastax.driver.core.Session;
+import com.datastax.driver.core.schemabuilder.SchemaBuilder;
+
+@ExtendWith(DockerCassandraExtension.class)
+class SessionWithInitializedTablesFactoryTest {
+ private static final String TABLE_NAME = "tablename";
+ private static final String TYPE_NAME = "typename";
+ private static final String PROPERTY = "property";
+
+ public static final CassandraModule MODULE = CassandraModule.aggregateModules(
+ CassandraSchemaVersionModule.MODULE,
+ CassandraModule.table(TABLE_NAME)
+ .comment("Testing table")
+ .statement(statement -> statement
+ .addPartitionKey("id", DataType.timeuuid())
+ .addClusteringColumn("clustering", DataType.bigint()))
+ .build(),
+ CassandraModule.type(TYPE_NAME)
+ .statement(statement -> statement.addColumn(PROPERTY, text()))
+ .build());
+
+ private Supplier<Session> testee;
+
+ @BeforeEach
+ void setUp(DockerCassandraExtension.DockerCassandra cassandraServer) {
+ this.testee = createSession(cassandraServer);
+ }
+
+ @AfterEach
+ void tearDown() {
+ cleanCassandra(testee.get());
+ }
+
+ @BeforeAll
+ @AfterAll
+ static void stabilizeCassandra(DockerCassandraExtension.DockerCassandra cassandraServer) {
+ cleanCassandra(createSession(cassandraServer).get());
+ }
+
+ @Test
+ void createSessionShouldSetTheLatestSchemaVersionWhenCreatingTypesAndTables() {
+ assertThat(versionManager(testee.get()).computeVersion())
+ .isEqualTo(MAX_VERSION);
+ }
+
+ @Test
+ void createSessionShouldKeepTheSetSchemaVersionWhenTypesAndTablesHaveNotChanged() {
+ Session session = testee.get();
+ assertThat(versionManager(session).computeVersion())
+ .isEqualTo(MAX_VERSION);
+
+ new CassandraTableManager(MODULE, session).clearAllTables();
+ versionManagerDAO(session).updateVersion(MIN_VERSION);
+ assertThat(versionManager(session).computeVersion())
+ .isEqualTo(MIN_VERSION);
+
+ assertThat(versionManager(testee.get()).computeVersion())
+ .isEqualTo(MIN_VERSION);
+ }
+
+ @Test
+ void createSessionShouldKeepTheSetSchemaVersionWhenTypesAndTablesHavePartiallyChanged() {
+ Session session = testee.get();
+ assertThat(versionManager(session).computeVersion())
+ .isEqualTo(MAX_VERSION);
+
+ new CassandraTableManager(MODULE, session).clearAllTables();
+ versionManagerDAO(session).updateVersion(MIN_VERSION);
+ assertThat(versionManager(session).computeVersion())
+ .isEqualTo(MIN_VERSION);
+ session.execute(SchemaBuilder.dropTable(TABLE_NAME));
+ session.execute(SchemaBuilder.dropType(TYPE_NAME));
+
+ assertThat(versionManager(testee.get()).computeVersion())
+ .isEqualTo(MIN_VERSION);
+ }
+
+ private static Supplier<Session> createSession(DockerCassandraExtension.DockerCassandra cassandraServer) {
+ Host host = cassandraServer.getHost();
+ Cluster cluster = ClusterBuilder.builder()
+ .host(host.getHostName())
+ .port(host.getPort())
+ .build();
+ return () -> new SessionWithInitializedTablesFactory(
+ ClusterConfiguration.builder()
+ .host(host)
+ .keyspace(KEYSPACE)
+ .replicationFactor(1)
+ .build(),
+ ClusterWithKeyspaceCreatedFactory
+ .config(cluster, KEYSPACE)
+ .replicationFactor(1)
+ .disableDurableWrites()
+ .clusterWithInitializedKeyspace(),
+ MODULE).get();
+ }
+
+ private static void cleanCassandra(Session session) {
+ MODULE.moduleTables().forEach(table -> session.execute(SchemaBuilder.dropTable(table.getName())));
+ MODULE.moduleTypes().forEach(type -> session.execute(SchemaBuilder.dropType(type.getName())));
+ }
+
+ private CassandraSchemaVersionManager versionManager(Session session) {
+ return new CassandraSchemaVersionManager(versionManagerDAO(session));
+ }
+
+ private CassandraSchemaVersionDAO versionManagerDAO(Session session) {
+ return new CassandraSchemaVersionDAO(session, CassandraUtils.WITH_DEFAULT_CONFIGURATION);
+ }
+}
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/james-project/blob/d796a1d3/mailbox/cassandra/src/test/java/org/apache/james/mailbox/cassandra/mail/MailboxAggregateModule.java
----------------------------------------------------------------------
diff --git a/mailbox/cassandra/src/test/java/org/apache/james/mailbox/cassandra/mail/MailboxAggregateModule.java b/mailbox/cassandra/src/test/java/org/apache/james/mailbox/cassandra/mail/MailboxAggregateModule.java
index 841a785..dd1fd57 100644
--- a/mailbox/cassandra/src/test/java/org/apache/james/mailbox/cassandra/mail/MailboxAggregateModule.java
+++ b/mailbox/cassandra/src/test/java/org/apache/james/mailbox/cassandra/mail/MailboxAggregateModule.java
@@ -20,6 +20,7 @@
package org.apache.james.mailbox.cassandra.mail;
import org.apache.james.backends.cassandra.components.CassandraModule;
+import org.apache.james.backends.cassandra.versions.CassandraSchemaVersionModule;
import org.apache.james.blob.cassandra.CassandraBlobModule;
import org.apache.james.mailbox.cassandra.modules.CassandraAclModule;
import org.apache.james.mailbox.cassandra.modules.CassandraAnnotationModule;
@@ -38,6 +39,7 @@ import org.apache.james.mailbox.cassandra.modules.CassandraUidModule;
public interface MailboxAggregateModule {
CassandraModule MODULE = CassandraModule.aggregateModules(
+ CassandraSchemaVersionModule.MODULE,
CassandraAclModule.MODULE,
CassandraMailboxModule.MODULE,
CassandraMessageModule.MODULE,
http://git-wip-us.apache.org/repos/asf/james-project/blob/d796a1d3/server/data/data-jmap-cassandra/src/test/java/org/apache/james/jmap/cassandra/vacation/CassandraVacationRepositoryTest.java
----------------------------------------------------------------------
diff --git a/server/data/data-jmap-cassandra/src/test/java/org/apache/james/jmap/cassandra/vacation/CassandraVacationRepositoryTest.java b/server/data/data-jmap-cassandra/src/test/java/org/apache/james/jmap/cassandra/vacation/CassandraVacationRepositoryTest.java
index 7db419b..caf644e 100644
--- a/server/data/data-jmap-cassandra/src/test/java/org/apache/james/jmap/cassandra/vacation/CassandraVacationRepositoryTest.java
+++ b/server/data/data-jmap-cassandra/src/test/java/org/apache/james/jmap/cassandra/vacation/CassandraVacationRepositoryTest.java
@@ -23,6 +23,7 @@ import org.apache.james.backends.cassandra.CassandraCluster;
import org.apache.james.backends.cassandra.DockerCassandraRule;
import org.apache.james.backends.cassandra.components.CassandraModule;
import org.apache.james.backends.cassandra.init.CassandraZonedDateTimeModule;
+import org.apache.james.backends.cassandra.versions.CassandraSchemaVersionModule;
import org.apache.james.jmap.api.vacation.AbstractVacationRepositoryTest;
import org.apache.james.jmap.api.vacation.VacationRepository;
import org.junit.After;
@@ -39,7 +40,10 @@ public class CassandraVacationRepositoryTest extends AbstractVacationRepositoryT
@BeforeClass
public static void setUpClass() {
- CassandraModule module = CassandraModule.aggregateModules(CassandraVacationModule.MODULE, CassandraZonedDateTimeModule.MODULE);
+ CassandraModule module = CassandraModule.aggregateModules(
+ CassandraSchemaVersionModule.MODULE,
+ CassandraVacationModule.MODULE,
+ CassandraZonedDateTimeModule.MODULE);
cassandra = CassandraCluster.create(module, cassandraServer.getHost());
}
http://git-wip-us.apache.org/repos/asf/james-project/blob/d796a1d3/server/mailrepository/mailrepository-cassandra/src/test/java/org/apache/james/mailrepository/cassandra/CassandraMailRepositoryTest.java
----------------------------------------------------------------------
diff --git a/server/mailrepository/mailrepository-cassandra/src/test/java/org/apache/james/mailrepository/cassandra/CassandraMailRepositoryTest.java b/server/mailrepository/mailrepository-cassandra/src/test/java/org/apache/james/mailrepository/cassandra/CassandraMailRepositoryTest.java
index d83677e..b0c059e 100644
--- a/server/mailrepository/mailrepository-cassandra/src/test/java/org/apache/james/mailrepository/cassandra/CassandraMailRepositoryTest.java
+++ b/server/mailrepository/mailrepository-cassandra/src/test/java/org/apache/james/mailrepository/cassandra/CassandraMailRepositoryTest.java
@@ -23,6 +23,7 @@ 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.utils.CassandraUtils;
+import org.apache.james.backends.cassandra.versions.CassandraSchemaVersionModule;
import org.apache.james.blob.api.HashBlobId;
import org.apache.james.blob.cassandra.CassandraBlobModule;
import org.apache.james.blob.cassandra.CassandraBlobsDAO;
@@ -42,6 +43,7 @@ class CassandraMailRepositoryTest implements MailRepositoryContract {
@RegisterExtension
static CassandraClusterExtension cassandraCluster = new CassandraClusterExtension(
CassandraModule.aggregateModules(
+ CassandraSchemaVersionModule.MODULE,
CassandraMailRepositoryModule.MODULE,
CassandraBlobModule.MODULE));
http://git-wip-us.apache.org/repos/asf/james-project/blob/d796a1d3/server/queue/queue-rabbitmq/src/test/java/org/apache/james/queue/rabbitmq/RabbitMQMailQueueConfigurationChangeTest.java
----------------------------------------------------------------------
diff --git a/server/queue/queue-rabbitmq/src/test/java/org/apache/james/queue/rabbitmq/RabbitMQMailQueueConfigurationChangeTest.java b/server/queue/queue-rabbitmq/src/test/java/org/apache/james/queue/rabbitmq/RabbitMQMailQueueConfigurationChangeTest.java
index d0acd5d..4ae8328 100644
--- a/server/queue/queue-rabbitmq/src/test/java/org/apache/james/queue/rabbitmq/RabbitMQMailQueueConfigurationChangeTest.java
+++ b/server/queue/queue-rabbitmq/src/test/java/org/apache/james/queue/rabbitmq/RabbitMQMailQueueConfigurationChangeTest.java
@@ -39,6 +39,7 @@ 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.init.configuration.CassandraConfiguration;
+import org.apache.james.backends.cassandra.versions.CassandraSchemaVersionModule;
import org.apache.james.blob.api.HashBlobId;
import org.apache.james.blob.cassandra.CassandraBlobModule;
import org.apache.james.blob.cassandra.CassandraBlobsDAO;
@@ -79,6 +80,7 @@ class RabbitMQMailQueueConfigurationChangeTest {
@RegisterExtension
static CassandraClusterExtension cassandraCluster = new CassandraClusterExtension(CassandraModule.aggregateModules(
+ CassandraSchemaVersionModule.MODULE,
CassandraBlobModule.MODULE,
CassandraMailQueueViewModule.MODULE,
CassandraEventStoreModule.MODULE));
---------------------------------------------------------------------
To unsubscribe, e-mail: server-dev-unsubscribe@james.apache.org
For additional commands, e-mail: server-dev-help@james.apache.org
[3/8] james-project git commit: JAMES-2608 Cassandra doesn't support
multiple values in PerRecipientHeaders for a given recipient
Posted by ro...@apache.org.
JAMES-2608 Cassandra doesn't support multiple values in PerRecipientHeaders for a given recipient
Project: http://git-wip-us.apache.org/repos/asf/james-project/repo
Commit: http://git-wip-us.apache.org/repos/asf/james-project/commit/d9118f6d
Tree: http://git-wip-us.apache.org/repos/asf/james-project/tree/d9118f6d
Diff: http://git-wip-us.apache.org/repos/asf/james-project/diff/d9118f6d
Branch: refs/heads/master
Commit: d9118f6d7d648121d1ac0e99527f0519562d197b
Parents: d796a1d
Author: Matthieu Baechler <ma...@apache.org>
Authored: Mon Nov 26 16:53:54 2018 +0100
Committer: Raphael Ouazana <ra...@linagora.com>
Committed: Wed Dec 19 09:24:12 2018 +0100
----------------------------------------------------------------------
.../mailrepository/MailRepositoryContract.java | 17 +++++++++++++++++
1 file changed, 17 insertions(+)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/james-project/blob/d9118f6d/server/mailrepository/mailrepository-api/src/test/java/org/apache/james/mailrepository/MailRepositoryContract.java
----------------------------------------------------------------------
diff --git a/server/mailrepository/mailrepository-api/src/test/java/org/apache/james/mailrepository/MailRepositoryContract.java b/server/mailrepository/mailrepository-api/src/test/java/org/apache/james/mailrepository/MailRepositoryContract.java
index d923050..e106015 100644
--- a/server/mailrepository/mailrepository-api/src/test/java/org/apache/james/mailrepository/MailRepositoryContract.java
+++ b/server/mailrepository/mailrepository-api/src/test/java/org/apache/james/mailrepository/MailRepositoryContract.java
@@ -46,6 +46,7 @@ import org.apache.mailet.Mail;
import org.apache.mailet.PerRecipientHeaders;
import org.apache.mailet.base.MailAddressFixture;
import org.apache.mailet.base.test.FakeMail;
+import org.junit.jupiter.api.Disabled;
import org.junit.jupiter.api.RepeatedTest;
import org.junit.jupiter.api.Test;
@@ -419,6 +420,22 @@ public interface MailRepositoryContract {
assertThat(testee.retrieve(MAIL_1)).satisfies(actual -> checkMailEquality(actual, mail));
}
+
+ @Disabled("JAMES-2608")
+ @Test
+ default void storingMessageWithPerRecipientHeadersShouldAllowMultipleHeadersPerUser() throws Exception {
+
+ MailRepository testee = retrieveRepository();
+ Mail mail = createMail(MAIL_1);
+ MailAddress recipient1 = new MailAddress("rec1@domain.com");
+ mail.addSpecificHeaderForRecipient(PerRecipientHeaders.Header.builder().name("foo").value("bar").build(), recipient1);
+ mail.addSpecificHeaderForRecipient(PerRecipientHeaders.Header.builder().name("fizz").value("buzz").build(), recipient1);
+ testee.store(mail);
+
+ assertThat(testee.list()).hasSize(1).containsOnly(MAIL_1);
+ assertThat(testee.retrieve(MAIL_1)).satisfies(actual -> checkMailEquality(actual, mail));
+ }
+
@RepeatedTest(100)
default void storingAndRemovingMessagesConcurrentlyShouldLeadToConsistentResult() throws Exception {
MailRepository testee = retrieveRepository();
---------------------------------------------------------------------
To unsubscribe, e-mail: server-dev-unsubscribe@james.apache.org
For additional commands, e-mail: server-dev-help@james.apache.org
[6/8] james-project git commit: JAMES-2608 implement
CassandraMailRepositoryMailDaoV2 to handle several headers for each user
Posted by ro...@apache.org.
JAMES-2608 implement CassandraMailRepositoryMailDaoV2 to handle several headers for each user
Project: http://git-wip-us.apache.org/repos/asf/james-project/repo
Commit: http://git-wip-us.apache.org/repos/asf/james-project/commit/d0f973b1
Tree: http://git-wip-us.apache.org/repos/asf/james-project/tree/d0f973b1
Diff: http://git-wip-us.apache.org/repos/asf/james-project/diff/d0f973b1
Branch: refs/heads/master
Commit: d0f973b1071bf4ae43a71dd5b61444ba0904be89
Parents: 7a2e552
Author: Matthieu Baechler <ma...@apache.org>
Authored: Wed Nov 28 18:41:07 2018 +0100
Committer: Raphael Ouazana <ra...@linagora.com>
Committed: Wed Dec 19 09:24:12 2018 +0100
----------------------------------------------------------------------
.../CassandraMailRepositoryMailDaoV2.java | 277 +++++++++++++++++++
.../CassandraMailRepositoryModule.java | 23 ++
.../cassandra/MailRepositoryTableV2.java | 49 ++++
.../CassandraMailRepositoryMailDAOTest.java | 16 ++
4 files changed, 365 insertions(+)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/james-project/blob/d0f973b1/server/mailrepository/mailrepository-cassandra/src/main/java/org/apache/james/mailrepository/cassandra/CassandraMailRepositoryMailDaoV2.java
----------------------------------------------------------------------
diff --git a/server/mailrepository/mailrepository-cassandra/src/main/java/org/apache/james/mailrepository/cassandra/CassandraMailRepositoryMailDaoV2.java b/server/mailrepository/mailrepository-cassandra/src/main/java/org/apache/james/mailrepository/cassandra/CassandraMailRepositoryMailDaoV2.java
new file mode 100644
index 0000000..10b44b1
--- /dev/null
+++ b/server/mailrepository/mailrepository-cassandra/src/main/java/org/apache/james/mailrepository/cassandra/CassandraMailRepositoryMailDaoV2.java
@@ -0,0 +1,277 @@
+/****************************************************************
+ * 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.mailrepository.cassandra;
+
+import static com.datastax.driver.core.DataType.text;
+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.select;
+import static org.apache.james.mailrepository.cassandra.MailRepositoryTableV2.ATTRIBUTES;
+import static org.apache.james.mailrepository.cassandra.MailRepositoryTableV2.BODY_BLOB_ID;
+import static org.apache.james.mailrepository.cassandra.MailRepositoryTableV2.CONTENT_TABLE_NAME;
+import static org.apache.james.mailrepository.cassandra.MailRepositoryTableV2.ERROR_MESSAGE;
+import static org.apache.james.mailrepository.cassandra.MailRepositoryTableV2.HEADER_BLOB_ID;
+import static org.apache.james.mailrepository.cassandra.MailRepositoryTableV2.HeaderEntrty.HEADER_NAME_INDEX;
+import static org.apache.james.mailrepository.cassandra.MailRepositoryTableV2.HeaderEntrty.HEADER_VALUE_INDEX;
+import static org.apache.james.mailrepository.cassandra.MailRepositoryTableV2.HeaderEntrty.USER_INDEX;
+import static org.apache.james.mailrepository.cassandra.MailRepositoryTableV2.LAST_UPDATED;
+import static org.apache.james.mailrepository.cassandra.MailRepositoryTableV2.MAIL_KEY;
+import static org.apache.james.mailrepository.cassandra.MailRepositoryTableV2.MAIL_PROPERTIES;
+import static org.apache.james.mailrepository.cassandra.MailRepositoryTableV2.MESSAGE_SIZE;
+import static org.apache.james.mailrepository.cassandra.MailRepositoryTableV2.PER_RECIPIENT_SPECIFIC_HEADERS;
+import static org.apache.james.mailrepository.cassandra.MailRepositoryTableV2.RECIPIENTS;
+import static org.apache.james.mailrepository.cassandra.MailRepositoryTableV2.REMOTE_ADDR;
+import static org.apache.james.mailrepository.cassandra.MailRepositoryTableV2.REMOTE_HOST;
+import static org.apache.james.mailrepository.cassandra.MailRepositoryTableV2.REPOSITORY_NAME;
+import static org.apache.james.mailrepository.cassandra.MailRepositoryTableV2.SENDER;
+import static org.apache.james.mailrepository.cassandra.MailRepositoryTableV2.STATE;
+
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.io.ObjectInputStream;
+import java.io.ObjectOutputStream;
+import java.io.Serializable;
+import java.nio.ByteBuffer;
+import java.util.Collection;
+import java.util.Date;
+import java.util.List;
+import java.util.Map;
+import java.util.Optional;
+import java.util.concurrent.CompletableFuture;
+
+import javax.inject.Inject;
+import javax.mail.MessagingException;
+import javax.mail.internet.AddressException;
+
+import org.apache.commons.lang3.tuple.Pair;
+import org.apache.james.backends.cassandra.utils.CassandraAsyncExecutor;
+import org.apache.james.blob.api.BlobId;
+import org.apache.james.core.MailAddress;
+import org.apache.james.mailrepository.api.MailKey;
+import org.apache.james.mailrepository.api.MailRepositoryUrl;
+import org.apache.james.server.core.MailImpl;
+import org.apache.james.util.streams.Iterators;
+import org.apache.mailet.Mail;
+import org.apache.mailet.PerRecipientHeaders;
+import org.apache.mailet.PerRecipientHeaders.Header;
+
+import com.datastax.driver.core.PreparedStatement;
+import com.datastax.driver.core.Row;
+import com.datastax.driver.core.Session;
+import com.datastax.driver.core.TupleType;
+import com.datastax.driver.core.TupleValue;
+import com.github.fge.lambdas.Throwing;
+import com.github.steveash.guavate.Guavate;
+import com.google.common.annotations.VisibleForTesting;
+import com.google.common.collect.ImmutableList;
+import com.google.common.collect.ImmutableMap;
+
+public class CassandraMailRepositoryMailDaoV2 implements CassandraMailRepositoryMailDaoAPI {
+
+ private final CassandraAsyncExecutor executor;
+ private final PreparedStatement insertMail;
+ private final PreparedStatement deleteMail;
+ private final PreparedStatement selectMail;
+ private final BlobId.Factory blobIdFactory;
+ private final TupleType userHeaderNameHeaderValueTriple;
+
+ @Inject
+ @VisibleForTesting
+ CassandraMailRepositoryMailDaoV2(Session session, BlobId.Factory blobIdFactory) {
+ this.executor = new CassandraAsyncExecutor(session);
+
+ this.insertMail = prepareInsert(session);
+ this.deleteMail = prepareDelete(session);
+ this.selectMail = prepareSelect(session);
+ this.blobIdFactory = blobIdFactory;
+ this.userHeaderNameHeaderValueTriple = session.getCluster().getMetadata().newTupleType(text(), text(), text());
+ }
+
+ private PreparedStatement prepareDelete(Session session) {
+ return session.prepare(delete()
+ .from(CONTENT_TABLE_NAME)
+ .where(eq(REPOSITORY_NAME, bindMarker(REPOSITORY_NAME)))
+ .and(eq(MAIL_KEY, bindMarker(MAIL_KEY))));
+ }
+
+ private PreparedStatement prepareInsert(Session session) {
+ return session.prepare(insertInto(CONTENT_TABLE_NAME)
+ .value(REPOSITORY_NAME, bindMarker(REPOSITORY_NAME))
+ .value(MAIL_KEY, bindMarker(MAIL_KEY))
+ .value(MESSAGE_SIZE, bindMarker(MESSAGE_SIZE))
+ .value(STATE, bindMarker(STATE))
+ .value(SENDER, bindMarker(SENDER))
+ .value(RECIPIENTS, bindMarker(RECIPIENTS))
+ .value(ATTRIBUTES, bindMarker(ATTRIBUTES))
+ .value(ERROR_MESSAGE, bindMarker(ERROR_MESSAGE))
+ .value(REMOTE_ADDR, bindMarker(REMOTE_ADDR))
+ .value(REMOTE_HOST, bindMarker(REMOTE_HOST))
+ .value(LAST_UPDATED, bindMarker(LAST_UPDATED))
+ .value(HEADER_BLOB_ID, bindMarker(HEADER_BLOB_ID))
+ .value(BODY_BLOB_ID, bindMarker(BODY_BLOB_ID))
+ .value(PER_RECIPIENT_SPECIFIC_HEADERS, bindMarker(PER_RECIPIENT_SPECIFIC_HEADERS)));
+ }
+
+ private PreparedStatement prepareSelect(Session session) {
+ return session.prepare(
+ select(MAIL_PROPERTIES)
+ .from(CONTENT_TABLE_NAME)
+ .where(eq(REPOSITORY_NAME, bindMarker(REPOSITORY_NAME)))
+ .and(eq(MAIL_KEY, bindMarker(MAIL_KEY))));
+ }
+
+ public CompletableFuture<Void> store(MailRepositoryUrl url, Mail mail, BlobId headerId, BlobId bodyId) throws MessagingException {
+ return executor.executeVoid(insertMail.bind()
+ .setString(REPOSITORY_NAME, url.asString())
+ .setString(MAIL_KEY, mail.getName())
+ .setString(HEADER_BLOB_ID, headerId.asString())
+ .setString(BODY_BLOB_ID, bodyId.asString())
+ .setString(STATE, mail.getState())
+ .setString(SENDER, mail.getMaybeSender().asString(null))
+ .setList(RECIPIENTS, asStringList(mail.getRecipients()))
+ .setString(ERROR_MESSAGE, mail.getErrorMessage())
+ .setString(REMOTE_ADDR, mail.getRemoteAddr())
+ .setString(REMOTE_HOST, mail.getRemoteHost())
+ .setLong(MESSAGE_SIZE, mail.getMessageSize())
+ .setTimestamp(LAST_UPDATED, mail.getLastUpdated())
+ .setMap(ATTRIBUTES, toRawAttributeMap(mail))
+ .setList(PER_RECIPIENT_SPECIFIC_HEADERS, toTupleList(mail.getPerRecipientSpecificHeaders()))
+ );
+ }
+
+ public CompletableFuture<Void> remove(MailRepositoryUrl url, MailKey key) {
+ return executor.executeVoid(deleteMail.bind()
+ .setString(REPOSITORY_NAME, url.asString())
+ .setString(MAIL_KEY, key.asString()));
+ }
+
+ public CompletableFuture<Optional<MailDTO>> read(MailRepositoryUrl url, MailKey key) {
+ return executor.executeSingleRow(selectMail.bind()
+ .setString(REPOSITORY_NAME, url.asString())
+ .setString(MAIL_KEY, key.asString()))
+ .thenApply(rowOptional -> rowOptional.map(this::toMail));
+ }
+
+ private MailDTO toMail(Row row) {
+ MailAddress sender = Optional.ofNullable(row.getString(SENDER))
+ .map(MailAddress::getMailSender)
+ .orElse(null);
+ List<MailAddress> recipients = row.getList(RECIPIENTS, String.class)
+ .stream()
+ .map(Throwing.function(MailAddress::new))
+ .collect(Guavate.toImmutableList());
+ String state = row.getString(STATE);
+ String remoteAddr = row.getString(REMOTE_ADDR);
+ String remoteHost = row.getString(REMOTE_HOST);
+ String errorMessage = row.getString(ERROR_MESSAGE);
+ String name = row.getString(MAIL_KEY);
+ Date lastUpdated = row.getTimestamp(LAST_UPDATED);
+ Map<String, ByteBuffer> rawAttributes = row.getMap(ATTRIBUTES, String.class, ByteBuffer.class);
+ PerRecipientHeaders perRecipientHeaders = fromList(row.getList(PER_RECIPIENT_SPECIFIC_HEADERS, TupleValue.class));
+
+ MailImpl.Builder mailBuilder = MailImpl.builder()
+ .name(name)
+ .sender(sender)
+ .recipients(recipients)
+ .lastUpdated(lastUpdated)
+ .errorMessage(errorMessage)
+ .remoteHost(remoteHost)
+ .remoteAddr(remoteAddr)
+ .state(state)
+ .addAllHeadersForRecipients(perRecipientHeaders)
+ .attributes(toAttributes(rawAttributes));
+
+ return new MailDTO(mailBuilder,
+ blobIdFactory.from(row.getString(HEADER_BLOB_ID)),
+ blobIdFactory.from(row.getString(BODY_BLOB_ID)));
+ }
+
+ private Map<String, Serializable> toAttributes(Map<String, ByteBuffer> rowAttributes) {
+ return rowAttributes.entrySet()
+ .stream()
+ .map(entry -> Pair.of(entry.getKey(), fromByteBuffer(entry.getValue())))
+ .collect(Guavate.toImmutableMap(Pair::getLeft, Pair::getRight));
+ }
+
+ private ImmutableList<String> asStringList(Collection<MailAddress> mailAddresses) {
+ return mailAddresses.stream().map(MailAddress::asString).collect(Guavate.toImmutableList());
+ }
+
+ private ImmutableMap<String, ByteBuffer> toRawAttributeMap(Mail mail) {
+ return Iterators.toStream(mail.getAttributeNames())
+ .map(name -> Pair.of(name, mail.getAttribute(name)))
+ .map(pair -> Pair.of(pair.getLeft(), toByteBuffer(pair.getRight())))
+ .collect(Guavate.toImmutableMap(Pair::getLeft, Pair::getRight));
+ }
+
+ private ImmutableList<TupleValue> toTupleList(PerRecipientHeaders perRecipientHeaders) {
+ return perRecipientHeaders.getHeadersByRecipient()
+ .entries()
+ .stream()
+ .map(entry -> userHeaderNameHeaderValueTriple.newValue(entry.getKey().asString(), entry.getValue().getName(), entry.getValue().getValue()))
+ .collect(Guavate.toImmutableList());
+ }
+
+ private PerRecipientHeaders fromList(List<TupleValue> list) {
+ PerRecipientHeaders result = new PerRecipientHeaders();
+
+ list.forEach(tuple ->
+ result.addHeaderForRecipient(
+ Header.builder()
+ .name(tuple.getString(HEADER_NAME_INDEX))
+ .value(tuple.getString(HEADER_VALUE_INDEX))
+ .build(),
+ toMailAddress(tuple.getString(USER_INDEX))));
+ return result;
+ }
+
+ private ByteBuffer toByteBuffer(Serializable serializable) {
+ try {
+ ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
+ new ObjectOutputStream(outputStream).writeObject(serializable);
+ return ByteBuffer.wrap(outputStream.toByteArray());
+ } catch (IOException e) {
+ throw new RuntimeException(e);
+ }
+ }
+
+ private Serializable fromByteBuffer(ByteBuffer byteBuffer) {
+ try {
+ byte[] data = new byte[byteBuffer.remaining()];
+ byteBuffer.get(data);
+ ObjectInputStream objectInputStream = new ObjectInputStream(new ByteArrayInputStream(data));
+ return (Serializable) objectInputStream.readObject();
+ } catch (IOException | ClassNotFoundException e) {
+ throw new RuntimeException(e);
+ }
+ }
+
+ private MailAddress toMailAddress(String rawValue) {
+ try {
+ return new MailAddress(rawValue);
+ } catch (AddressException e) {
+ throw new RuntimeException(e);
+ }
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/james-project/blob/d0f973b1/server/mailrepository/mailrepository-cassandra/src/main/java/org/apache/james/mailrepository/cassandra/CassandraMailRepositoryModule.java
----------------------------------------------------------------------
diff --git a/server/mailrepository/mailrepository-cassandra/src/main/java/org/apache/james/mailrepository/cassandra/CassandraMailRepositoryModule.java b/server/mailrepository/mailrepository-cassandra/src/main/java/org/apache/james/mailrepository/cassandra/CassandraMailRepositoryModule.java
index cfbcdf4..f2c44f4 100644
--- a/server/mailrepository/mailrepository-cassandra/src/main/java/org/apache/james/mailrepository/cassandra/CassandraMailRepositoryModule.java
+++ b/server/mailrepository/mailrepository-cassandra/src/main/java/org/apache/james/mailrepository/cassandra/CassandraMailRepositoryModule.java
@@ -30,6 +30,10 @@ import static com.datastax.driver.core.schemabuilder.SchemaBuilder.frozen;
import org.apache.james.backends.cassandra.components.CassandraModule;
+import com.datastax.driver.core.CodecRegistry;
+import com.datastax.driver.core.ProtocolVersion;
+import com.datastax.driver.core.TupleType;
+
public interface CassandraMailRepositoryModule {
CassandraModule MODULE = CassandraModule.builder()
.type(MailRepositoryTable.HEADER_TYPE)
@@ -64,5 +68,24 @@ public interface CassandraMailRepositoryModule {
.addColumn(MailRepositoryTable.REMOTE_ADDR, text())
.addColumn(MailRepositoryTable.LAST_UPDATED, timestamp())
.addUDTMapColumn(MailRepositoryTable.PER_RECIPIENT_SPECIFIC_HEADERS, text(), frozen(MailRepositoryTable.HEADER_TYPE)))
+ .table(MailRepositoryTableV2.CONTENT_TABLE_NAME)
+ .comment("Stores the mails for a given repository. " +
+ "Content is stored with other blobs. " +
+ "This v2 version was introduced to support multiple headers for each user")
+ .statement(statement -> statement
+ .addPartitionKey(MailRepositoryTable.REPOSITORY_NAME, text())
+ .addPartitionKey(MailRepositoryTable.MAIL_KEY, text())
+ .addColumn(MailRepositoryTable.MESSAGE_SIZE, bigint())
+ .addColumn(MailRepositoryTable.STATE, text())
+ .addColumn(MailRepositoryTable.HEADER_BLOB_ID, text())
+ .addColumn(MailRepositoryTable.BODY_BLOB_ID, text())
+ .addColumn(MailRepositoryTable.ATTRIBUTES, map(text(), blob()))
+ .addColumn(MailRepositoryTable.ERROR_MESSAGE, text())
+ .addColumn(MailRepositoryTable.SENDER, text())
+ .addColumn(MailRepositoryTable.RECIPIENTS, list(text()))
+ .addColumn(MailRepositoryTable.REMOTE_HOST, text())
+ .addColumn(MailRepositoryTable.REMOTE_ADDR, text())
+ .addColumn(MailRepositoryTable.LAST_UPDATED, timestamp())
+ .addColumn(MailRepositoryTable.PER_RECIPIENT_SPECIFIC_HEADERS, list(TupleType.of(ProtocolVersion.NEWEST_SUPPORTED, CodecRegistry.DEFAULT_INSTANCE, text(), text(), text()))))
.build();
}
http://git-wip-us.apache.org/repos/asf/james-project/blob/d0f973b1/server/mailrepository/mailrepository-cassandra/src/main/java/org/apache/james/mailrepository/cassandra/MailRepositoryTableV2.java
----------------------------------------------------------------------
diff --git a/server/mailrepository/mailrepository-cassandra/src/main/java/org/apache/james/mailrepository/cassandra/MailRepositoryTableV2.java b/server/mailrepository/mailrepository-cassandra/src/main/java/org/apache/james/mailrepository/cassandra/MailRepositoryTableV2.java
new file mode 100644
index 0000000..54e2e45
--- /dev/null
+++ b/server/mailrepository/mailrepository-cassandra/src/main/java/org/apache/james/mailrepository/cassandra/MailRepositoryTableV2.java
@@ -0,0 +1,49 @@
+/****************************************************************
+ * 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.mailrepository.cassandra;
+
+public interface MailRepositoryTableV2 {
+ String CONTENT_TABLE_NAME = "mailRepositoryContentV2";
+
+ String REPOSITORY_NAME = "name";
+
+ String MAIL_KEY = "mailKey";
+ String MESSAGE_SIZE = "messageSize";
+ String HEADER_BLOB_ID = "headerBlobId";
+ String BODY_BLOB_ID = "bodyBlobId";
+ String STATE = "state";
+ String SENDER = "sender";
+ String RECIPIENTS = "recipients";
+ String ATTRIBUTES = "attributes";
+ String ERROR_MESSAGE = "errorMessage";
+ String REMOTE_HOST = "remoteHost";
+ String REMOTE_ADDR = "remoteAddr";
+ String LAST_UPDATED = "lastUpdated";
+ String PER_RECIPIENT_SPECIFIC_HEADERS = "perRecipientSpecificHeaders";
+
+ interface HeaderEntrty {
+ int USER_INDEX = 0;
+ int HEADER_NAME_INDEX = 1;
+ int HEADER_VALUE_INDEX = 2;
+ }
+
+ String[] MAIL_PROPERTIES = { MAIL_KEY, MESSAGE_SIZE, STATE, SENDER, RECIPIENTS, ATTRIBUTES, ERROR_MESSAGE, REMOTE_ADDR,
+ REMOTE_HOST, LAST_UPDATED, PER_RECIPIENT_SPECIFIC_HEADERS, HEADER_BLOB_ID, BODY_BLOB_ID };
+}
http://git-wip-us.apache.org/repos/asf/james-project/blob/d0f973b1/server/mailrepository/mailrepository-cassandra/src/test/java/org/apache/james/mailrepository/cassandra/CassandraMailRepositoryMailDAOTest.java
----------------------------------------------------------------------
diff --git a/server/mailrepository/mailrepository-cassandra/src/test/java/org/apache/james/mailrepository/cassandra/CassandraMailRepositoryMailDAOTest.java b/server/mailrepository/mailrepository-cassandra/src/test/java/org/apache/james/mailrepository/cassandra/CassandraMailRepositoryMailDAOTest.java
index 582a7ba..c02966a 100644
--- a/server/mailrepository/mailrepository-cassandra/src/test/java/org/apache/james/mailrepository/cassandra/CassandraMailRepositoryMailDAOTest.java
+++ b/server/mailrepository/mailrepository-cassandra/src/test/java/org/apache/james/mailrepository/cassandra/CassandraMailRepositoryMailDAOTest.java
@@ -171,4 +171,20 @@ class CassandraMailRepositoryMailDAOTest {
return testee;
}
}
+
+ @Nested
+ class v2 extends TestSuite {
+
+ private CassandraMailRepositoryMailDaoV2 testee;
+
+ @BeforeEach
+ void setUp(CassandraCluster cassandra) {
+ testee = new CassandraMailRepositoryMailDaoV2(cassandra.getConf(), BLOB_ID_FACTORY);
+ }
+
+ @Override
+ CassandraMailRepositoryMailDaoAPI testee() {
+ return testee;
+ }
+ }
}
\ No newline at end of file
---------------------------------------------------------------------
To unsubscribe, e-mail: server-dev-unsubscribe@james.apache.org
For additional commands, e-mail: server-dev-help@james.apache.org
[7/8] james-project git commit: JAMES-2608 Store attributes as Json
Posted by ro...@apache.org.
JAMES-2608 Store attributes as Json
Project: http://git-wip-us.apache.org/repos/asf/james-project/repo
Commit: http://git-wip-us.apache.org/repos/asf/james-project/commit/3b223d53
Tree: http://git-wip-us.apache.org/repos/asf/james-project/tree/3b223d53
Diff: http://git-wip-us.apache.org/repos/asf/james-project/diff/3b223d53
Branch: refs/heads/master
Commit: 3b223d537508d9a79aa50640cc23d87726508c29
Parents: 1ebe3fd
Author: Antoine Duprat <ad...@linagora.com>
Authored: Mon Dec 17 11:34:23 2018 +0100
Committer: Raphael Ouazana <ra...@linagora.com>
Committed: Wed Dec 19 09:24:12 2018 +0100
----------------------------------------------------------------------
.../CassandraMailRepositoryMailDaoV2.java | 47 ++----
.../CassandraMailRepositoryModule.java | 5 +-
.../CassandraMailRepositoryMailDAOTest.java | 163 +++++++++++++------
3 files changed, 126 insertions(+), 89 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/james-project/blob/3b223d53/server/mailrepository/mailrepository-cassandra/src/main/java/org/apache/james/mailrepository/cassandra/CassandraMailRepositoryMailDaoV2.java
----------------------------------------------------------------------
diff --git a/server/mailrepository/mailrepository-cassandra/src/main/java/org/apache/james/mailrepository/cassandra/CassandraMailRepositoryMailDaoV2.java b/server/mailrepository/mailrepository-cassandra/src/main/java/org/apache/james/mailrepository/cassandra/CassandraMailRepositoryMailDaoV2.java
index 156fa85..36e8e28 100644
--- a/server/mailrepository/mailrepository-cassandra/src/main/java/org/apache/james/mailrepository/cassandra/CassandraMailRepositoryMailDaoV2.java
+++ b/server/mailrepository/mailrepository-cassandra/src/main/java/org/apache/james/mailrepository/cassandra/CassandraMailRepositoryMailDaoV2.java
@@ -44,13 +44,6 @@ import static org.apache.james.mailrepository.cassandra.MailRepositoryTableV2.RE
import static org.apache.james.mailrepository.cassandra.MailRepositoryTableV2.SENDER;
import static org.apache.james.mailrepository.cassandra.MailRepositoryTableV2.STATE;
-import java.io.ByteArrayInputStream;
-import java.io.ByteArrayOutputStream;
-import java.io.IOException;
-import java.io.ObjectInputStream;
-import java.io.ObjectOutputStream;
-import java.io.Serializable;
-import java.nio.ByteBuffer;
import java.util.Collection;
import java.util.Date;
import java.util.List;
@@ -69,7 +62,9 @@ import org.apache.james.core.MailAddress;
import org.apache.james.mailrepository.api.MailKey;
import org.apache.james.mailrepository.api.MailRepositoryUrl;
import org.apache.james.server.core.MailImpl;
-import org.apache.james.util.streams.Iterators;
+import org.apache.mailet.Attribute;
+import org.apache.mailet.AttributeName;
+import org.apache.mailet.AttributeValue;
import org.apache.mailet.Mail;
import org.apache.mailet.PerRecipientHeaders;
import org.apache.mailet.PerRecipientHeaders.Header;
@@ -183,7 +178,7 @@ public class CassandraMailRepositoryMailDaoV2 implements CassandraMailRepository
String errorMessage = row.getString(ERROR_MESSAGE);
String name = row.getString(MAIL_KEY);
Date lastUpdated = row.getTimestamp(LAST_UPDATED);
- Map<String, ByteBuffer> rawAttributes = row.getMap(ATTRIBUTES, String.class, ByteBuffer.class);
+ Map<String, String> rawAttributes = row.getMap(ATTRIBUTES, String.class, String.class);
PerRecipientHeaders perRecipientHeaders = fromList(row.getList(PER_RECIPIENT_SPECIFIC_HEADERS, TupleValue.class));
MailImpl.Builder mailBuilder = MailImpl.builder()
@@ -203,21 +198,20 @@ public class CassandraMailRepositoryMailDaoV2 implements CassandraMailRepository
blobIdFactory.from(row.getString(BODY_BLOB_ID)));
}
- private Map<String, Serializable> toAttributes(Map<String, ByteBuffer> rowAttributes) {
+ private List<Attribute> toAttributes(Map<String, String> rowAttributes) {
return rowAttributes.entrySet()
.stream()
- .map(entry -> Pair.of(entry.getKey(), fromByteBuffer(entry.getValue())))
- .collect(Guavate.toImmutableMap(Pair::getLeft, Pair::getRight));
+ .map(Throwing.function(entry -> new Attribute(AttributeName.of(entry.getKey()), AttributeValue.fromJsonString(entry.getValue()))))
+ .collect(Guavate.toImmutableList());
}
private ImmutableList<String> asStringList(Collection<MailAddress> mailAddresses) {
return mailAddresses.stream().map(MailAddress::asString).collect(Guavate.toImmutableList());
}
- private ImmutableMap<String, ByteBuffer> toRawAttributeMap(Mail mail) {
- return Iterators.toStream(mail.getAttributeNames())
- .map(name -> Pair.of(name, mail.getAttribute(name)))
- .map(pair -> Pair.of(pair.getLeft(), toByteBuffer(pair.getRight())))
+ private ImmutableMap<String, String> toRawAttributeMap(Mail mail) {
+ return mail.attributes()
+ .map(attribute -> Pair.of(attribute.getName().asString(), toJson(attribute.getValue())))
.collect(Guavate.toImmutableMap(Pair::getLeft, Pair::getRight));
}
@@ -242,25 +236,8 @@ public class CassandraMailRepositoryMailDaoV2 implements CassandraMailRepository
return result;
}
- private ByteBuffer toByteBuffer(Serializable serializable) {
- try {
- ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
- new ObjectOutputStream(outputStream).writeObject(serializable);
- return ByteBuffer.wrap(outputStream.toByteArray());
- } catch (IOException e) {
- throw new RuntimeException(e);
- }
- }
-
- private Serializable fromByteBuffer(ByteBuffer byteBuffer) {
- try {
- byte[] data = new byte[byteBuffer.remaining()];
- byteBuffer.get(data);
- ObjectInputStream objectInputStream = new ObjectInputStream(new ByteArrayInputStream(data));
- return (Serializable) objectInputStream.readObject();
- } catch (IOException | ClassNotFoundException e) {
- throw new RuntimeException(e);
- }
+ private String toJson(AttributeValue<?> attributeValue) {
+ return attributeValue.toJson().toString();
}
private MailAddress toMailAddress(String rawValue) {
http://git-wip-us.apache.org/repos/asf/james-project/blob/3b223d53/server/mailrepository/mailrepository-cassandra/src/main/java/org/apache/james/mailrepository/cassandra/CassandraMailRepositoryModule.java
----------------------------------------------------------------------
diff --git a/server/mailrepository/mailrepository-cassandra/src/main/java/org/apache/james/mailrepository/cassandra/CassandraMailRepositoryModule.java b/server/mailrepository/mailrepository-cassandra/src/main/java/org/apache/james/mailrepository/cassandra/CassandraMailRepositoryModule.java
index f2c44f4..6e6c3cd 100644
--- a/server/mailrepository/mailrepository-cassandra/src/main/java/org/apache/james/mailrepository/cassandra/CassandraMailRepositoryModule.java
+++ b/server/mailrepository/mailrepository-cassandra/src/main/java/org/apache/james/mailrepository/cassandra/CassandraMailRepositoryModule.java
@@ -71,7 +71,8 @@ public interface CassandraMailRepositoryModule {
.table(MailRepositoryTableV2.CONTENT_TABLE_NAME)
.comment("Stores the mails for a given repository. " +
"Content is stored with other blobs. " +
- "This v2 version was introduced to support multiple headers for each user")
+ "This v2 version was introduced to support multiple headers for each user. " +
+ "The attributes are store as Json introduced in Mailet API v3.2.")
.statement(statement -> statement
.addPartitionKey(MailRepositoryTable.REPOSITORY_NAME, text())
.addPartitionKey(MailRepositoryTable.MAIL_KEY, text())
@@ -79,7 +80,7 @@ public interface CassandraMailRepositoryModule {
.addColumn(MailRepositoryTable.STATE, text())
.addColumn(MailRepositoryTable.HEADER_BLOB_ID, text())
.addColumn(MailRepositoryTable.BODY_BLOB_ID, text())
- .addColumn(MailRepositoryTable.ATTRIBUTES, map(text(), blob()))
+ .addColumn(MailRepositoryTable.ATTRIBUTES, map(text(), text()))
.addColumn(MailRepositoryTable.ERROR_MESSAGE, text())
.addColumn(MailRepositoryTable.SENDER, text())
.addColumn(MailRepositoryTable.RECIPIENTS, list(text()))
http://git-wip-us.apache.org/repos/asf/james-project/blob/3b223d53/server/mailrepository/mailrepository-cassandra/src/test/java/org/apache/james/mailrepository/cassandra/CassandraMailRepositoryMailDAOTest.java
----------------------------------------------------------------------
diff --git a/server/mailrepository/mailrepository-cassandra/src/test/java/org/apache/james/mailrepository/cassandra/CassandraMailRepositoryMailDAOTest.java b/server/mailrepository/mailrepository-cassandra/src/test/java/org/apache/james/mailrepository/cassandra/CassandraMailRepositoryMailDAOTest.java
index a50c69e..a04b8ed 100644
--- a/server/mailrepository/mailrepository-cassandra/src/test/java/org/apache/james/mailrepository/cassandra/CassandraMailRepositoryMailDAOTest.java
+++ b/server/mailrepository/mailrepository-cassandra/src/test/java/org/apache/james/mailrepository/cassandra/CassandraMailRepositoryMailDAOTest.java
@@ -22,6 +22,8 @@ package org.apache.james.mailrepository.cassandra;
import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.api.SoftAssertions.assertSoftly;
+import java.util.Collection;
+import java.util.List;
import java.util.Optional;
import javax.mail.MessagingException;
@@ -32,6 +34,9 @@ import org.apache.james.blob.api.BlobId;
import org.apache.james.blob.api.TestBlobId;
import org.apache.james.mailrepository.api.MailKey;
import org.apache.james.mailrepository.api.MailRepositoryUrl;
+import org.apache.mailet.Attribute;
+import org.apache.mailet.AttributeName;
+import org.apache.mailet.AttributeValue;
import org.apache.mailet.Mail;
import org.apache.mailet.PerRecipientHeaders;
import org.apache.mailet.base.MailAddressFixture;
@@ -57,58 +62,6 @@ class CassandraMailRepositoryMailDAOTest {
abstract CassandraMailRepositoryMailDaoAPI testee();
@Test
- void readShouldReturnAllMailMetadata() throws Exception {
- CassandraMailRepositoryMailDaoAPI testee = testee();
-
- BlobId blobIdBody = BLOB_ID_FACTORY.from("blobHeader");
- BlobId blobIdHeader = BLOB_ID_FACTORY.from("blobBody");
- String errorMessage = "error message";
- String state = "state";
- String remoteAddr = "remoteAddr";
- String remoteHost = "remoteHost";
- PerRecipientHeaders.Header header = PerRecipientHeaders.Header.builder().name("headerName").value("headerValue").build();
- String attributeName = "att1";
- ImmutableList<String> attributeValue = ImmutableList.of("value1", "value2");
-
- testee.store(URL,
- FakeMail.builder()
- .name(KEY_1.asString())
- .sender(MailAddressFixture.SENDER)
- .recipients(MailAddressFixture.RECIPIENT1, MailAddressFixture.RECIPIENT2)
- .errorMessage(errorMessage)
- .state(state)
- .remoteAddr(remoteAddr)
- .remoteHost(remoteHost)
- .addHeaderForRecipient(header, MailAddressFixture.RECIPIENT1)
- .attribute(attributeName, attributeValue)
- .build(),
- blobIdHeader,
- blobIdBody)
- .join();
-
- CassandraMailRepositoryMailDAO.MailDTO mailDTO = testee.read(URL, KEY_1).join().get();
-
- Mail partialMail = mailDTO.getMailBuilder().build();
- assertSoftly(softly -> {
- softly.assertThat(mailDTO.getBodyBlobId()).isEqualTo(blobIdBody);
- softly.assertThat(mailDTO.getHeaderBlobId()).isEqualTo(blobIdHeader);
- softly.assertThat(partialMail.getName()).isEqualTo(KEY_1.asString());
- softly.assertThat(partialMail.getErrorMessage()).isEqualTo(errorMessage);
- softly.assertThat(partialMail.getState()).isEqualTo(state);
- softly.assertThat(partialMail.getRemoteAddr()).isEqualTo(remoteAddr);
- softly.assertThat(partialMail.getRemoteHost()).isEqualTo(remoteHost);
- softly.assertThat(partialMail.getAttributeNames()).containsOnly(attributeName);
- softly.assertThat(partialMail.getAttribute(attributeName)).isEqualTo(attributeValue);
- softly.assertThat(partialMail.getPerRecipientSpecificHeaders().getRecipientsWithSpecificHeaders())
- .containsOnly(MailAddressFixture.RECIPIENT1);
- softly.assertThat(partialMail.getPerRecipientSpecificHeaders().getHeadersForRecipient(MailAddressFixture.RECIPIENT1))
- .containsOnly(header);
- softly.assertThat(partialMail.getMaybeSender().asOptional()).contains(MailAddressFixture.SENDER);
- softly.assertThat(partialMail.getRecipients()).containsOnly(MailAddressFixture.RECIPIENT1, MailAddressFixture.RECIPIENT2);
- });
- }
-
- @Test
void storeShouldAcceptMailWithOnlyName() throws Exception {
CassandraMailRepositoryMailDaoAPI testee = testee();
BlobId blobIdBody = BLOB_ID_FACTORY.from("blobHeader");
@@ -174,6 +127,58 @@ class CassandraMailRepositoryMailDAOTest {
CassandraMailRepositoryMailDaoAPI testee() {
return testee;
}
+
+ @Test
+ void readShouldReturnAllMailMetadata() throws Exception {
+ CassandraMailRepositoryMailDaoAPI testee = testee();
+
+ BlobId blobIdBody = BLOB_ID_FACTORY.from("blobHeader");
+ BlobId blobIdHeader = BLOB_ID_FACTORY.from("blobBody");
+ String errorMessage = "error message";
+ String state = "state";
+ String remoteAddr = "remoteAddr";
+ String remoteHost = "remoteHost";
+ PerRecipientHeaders.Header header = PerRecipientHeaders.Header.builder().name("headerName").value("headerValue").build();
+ String attributeName = "att1";
+ ImmutableList<String> attributeValue = ImmutableList.of("value1", "value2");
+
+ testee.store(URL,
+ FakeMail.builder()
+ .name(KEY_1.asString())
+ .sender(MailAddressFixture.SENDER)
+ .recipients(MailAddressFixture.RECIPIENT1, MailAddressFixture.RECIPIENT2)
+ .errorMessage(errorMessage)
+ .state(state)
+ .remoteAddr(remoteAddr)
+ .remoteHost(remoteHost)
+ .addHeaderForRecipient(header, MailAddressFixture.RECIPIENT1)
+ .attribute(attributeName, attributeValue)
+ .build(),
+ blobIdHeader,
+ blobIdBody)
+ .join();
+
+ CassandraMailRepositoryMailDAO.MailDTO mailDTO = testee.read(URL, KEY_1).join().get();
+
+ Mail partialMail = mailDTO.getMailBuilder().build();
+ assertSoftly(softly -> {
+ softly.assertThat(mailDTO.getBodyBlobId()).isEqualTo(blobIdBody);
+ softly.assertThat(mailDTO.getHeaderBlobId()).isEqualTo(blobIdHeader);
+ softly.assertThat(partialMail.getName()).isEqualTo(KEY_1.asString());
+ softly.assertThat(partialMail.getErrorMessage()).isEqualTo(errorMessage);
+ softly.assertThat(partialMail.getState()).isEqualTo(state);
+ softly.assertThat(partialMail.getRemoteAddr()).isEqualTo(remoteAddr);
+ softly.assertThat(partialMail.getRemoteHost()).isEqualTo(remoteHost);
+ softly.assertThat(partialMail.getAttributeNames()).containsOnly(attributeName);
+ softly.assertThat(partialMail.getAttribute(attributeName)).isEqualTo(attributeValue);
+ softly.assertThat(partialMail.getPerRecipientSpecificHeaders().getRecipientsWithSpecificHeaders())
+ .containsOnly(MailAddressFixture.RECIPIENT1);
+ softly.assertThat(partialMail.getPerRecipientSpecificHeaders().getHeadersForRecipient(MailAddressFixture.RECIPIENT1))
+ .containsOnly(header);
+ softly.assertThat(partialMail.getMaybeSender().asOptional()).contains(MailAddressFixture.SENDER);
+ softly.assertThat(partialMail.getRecipients()).containsOnly(MailAddressFixture.RECIPIENT1, MailAddressFixture.RECIPIENT2);
+ });
+ }
}
@Nested
@@ -190,6 +195,60 @@ class CassandraMailRepositoryMailDAOTest {
CassandraMailRepositoryMailDaoAPI testee() {
return testee;
}
+
+ @Test
+ void readShouldReturnAllMailMetadata() throws Exception {
+ CassandraMailRepositoryMailDaoAPI testee = testee();
+
+ BlobId blobIdBody = BLOB_ID_FACTORY.from("blobHeader");
+ BlobId blobIdHeader = BLOB_ID_FACTORY.from("blobBody");
+ String errorMessage = "error message";
+ String state = "state";
+ String remoteAddr = "remoteAddr";
+ String remoteHost = "remoteHost";
+ PerRecipientHeaders.Header header = PerRecipientHeaders.Header.builder().name("headerName").value("headerValue").build();
+ String attributeName = "att1";
+ List<AttributeValue<?>> attributeValue = ImmutableList.of(AttributeValue.of("value1"), AttributeValue.of("value2"));
+ Attribute attribute = new Attribute(AttributeName.of(attributeName), AttributeValue.of(attributeValue));
+ List<Attribute> attributes = ImmutableList.of(attribute);
+
+ testee.store(URL,
+ FakeMail.builder()
+ .name(KEY_1.asString())
+ .sender(MailAddressFixture.SENDER)
+ .recipients(MailAddressFixture.RECIPIENT1, MailAddressFixture.RECIPIENT2)
+ .errorMessage(errorMessage)
+ .state(state)
+ .remoteAddr(remoteAddr)
+ .remoteHost(remoteHost)
+ .addHeaderForRecipient(header, MailAddressFixture.RECIPIENT1)
+ .attributes(attributes)
+ .build(),
+ blobIdHeader,
+ blobIdBody)
+ .join();
+
+ CassandraMailRepositoryMailDAO.MailDTO mailDTO = testee.read(URL, KEY_1).join().get();
+
+ Mail partialMail = mailDTO.getMailBuilder().build();
+ assertSoftly(softly -> {
+ softly.assertThat(mailDTO.getBodyBlobId()).isEqualTo(blobIdBody);
+ softly.assertThat(mailDTO.getHeaderBlobId()).isEqualTo(blobIdHeader);
+ softly.assertThat(partialMail.getName()).isEqualTo(KEY_1.asString());
+ softly.assertThat(partialMail.getErrorMessage()).isEqualTo(errorMessage);
+ softly.assertThat(partialMail.getState()).isEqualTo(state);
+ softly.assertThat(partialMail.getRemoteAddr()).isEqualTo(remoteAddr);
+ softly.assertThat(partialMail.getRemoteHost()).isEqualTo(remoteHost);
+ softly.assertThat(partialMail.getAttributeNames()).containsOnly(attributeName);
+ softly.assertThat(partialMail.getAttribute(AttributeName.of(attributeName))).contains(attribute);
+ softly.assertThat(partialMail.getPerRecipientSpecificHeaders().getRecipientsWithSpecificHeaders())
+ .containsOnly(MailAddressFixture.RECIPIENT1);
+ softly.assertThat(partialMail.getPerRecipientSpecificHeaders().getHeadersForRecipient(MailAddressFixture.RECIPIENT1))
+ .containsOnly(header);
+ softly.assertThat(partialMail.getMaybeSender().asOptional()).contains(MailAddressFixture.SENDER);
+ softly.assertThat(partialMail.getRecipients()).containsOnly(MailAddressFixture.RECIPIENT1, MailAddressFixture.RECIPIENT2);
+ });
+ }
}
@Nested
---------------------------------------------------------------------
To unsubscribe, e-mail: server-dev-unsubscribe@james.apache.org
For additional commands, e-mail: server-dev-help@james.apache.org
[4/8] james-project git commit: JAMES-2608 introduce
CassandraMailRepositoryMailDaoAPI to introduce a v2 implementation later
Posted by ro...@apache.org.
JAMES-2608 introduce CassandraMailRepositoryMailDaoAPI to introduce a v2 implementation later
Project: http://git-wip-us.apache.org/repos/asf/james-project/repo
Commit: http://git-wip-us.apache.org/repos/asf/james-project/commit/7a2e552f
Tree: http://git-wip-us.apache.org/repos/asf/james-project/tree/7a2e552f
Diff: http://git-wip-us.apache.org/repos/asf/james-project/diff/7a2e552f
Branch: refs/heads/master
Commit: 7a2e552f3575ad56def379850c1e38637c320771
Parents: d9118f6
Author: Matthieu Baechler <ma...@apache.org>
Authored: Wed Nov 28 18:37:59 2018 +0100
Committer: Raphael Ouazana <ra...@linagora.com>
Committed: Wed Dec 19 09:24:12 2018 +0100
----------------------------------------------------------------------
.../cassandra/CassandraMailRepository.java | 4 +-
.../CassandraMailRepositoryMailDAO.java | 52 +----
.../CassandraMailRepositoryMailDaoAPI.java | 81 +++++++
.../CassandraMailRepositoryProvider.java | 4 +-
.../CassandraMailRepositoryMailDAOTest.java | 212 ++++++++++---------
...ilRepositoryWithFakeImplementationsTest.java | 33 ++-
6 files changed, 232 insertions(+), 154 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/james-project/blob/7a2e552f/server/mailrepository/mailrepository-cassandra/src/main/java/org/apache/james/mailrepository/cassandra/CassandraMailRepository.java
----------------------------------------------------------------------
diff --git a/server/mailrepository/mailrepository-cassandra/src/main/java/org/apache/james/mailrepository/cassandra/CassandraMailRepository.java b/server/mailrepository/mailrepository-cassandra/src/main/java/org/apache/james/mailrepository/cassandra/CassandraMailRepository.java
index c62feba..6655798 100644
--- a/server/mailrepository/mailrepository-cassandra/src/main/java/org/apache/james/mailrepository/cassandra/CassandraMailRepository.java
+++ b/server/mailrepository/mailrepository-cassandra/src/main/java/org/apache/james/mailrepository/cassandra/CassandraMailRepository.java
@@ -43,11 +43,11 @@ public class CassandraMailRepository implements MailRepository {
private final MailRepositoryUrl url;
private final CassandraMailRepositoryKeysDAO keysDAO;
private final CassandraMailRepositoryCountDAO countDAO;
- private final CassandraMailRepositoryMailDAO mailDAO;
+ private final CassandraMailRepositoryMailDaoAPI mailDAO;
private final Store<MimeMessage, MimeMessagePartsId> mimeMessageStore;
public CassandraMailRepository(MailRepositoryUrl url, CassandraMailRepositoryKeysDAO keysDAO,
- CassandraMailRepositoryCountDAO countDAO, CassandraMailRepositoryMailDAO mailDAO,
+ CassandraMailRepositoryCountDAO countDAO, CassandraMailRepositoryMailDaoAPI mailDAO,
Store<MimeMessage, MimeMessagePartsId> mimeMessageStore) {
this.url = url;
this.keysDAO = keysDAO;
http://git-wip-us.apache.org/repos/asf/james-project/blob/7a2e552f/server/mailrepository/mailrepository-cassandra/src/main/java/org/apache/james/mailrepository/cassandra/CassandraMailRepositoryMailDAO.java
----------------------------------------------------------------------
diff --git a/server/mailrepository/mailrepository-cassandra/src/main/java/org/apache/james/mailrepository/cassandra/CassandraMailRepositoryMailDAO.java b/server/mailrepository/mailrepository-cassandra/src/main/java/org/apache/james/mailrepository/cassandra/CassandraMailRepositoryMailDAO.java
index 51bbe30..7c3596b 100644
--- a/server/mailrepository/mailrepository-cassandra/src/main/java/org/apache/james/mailrepository/cassandra/CassandraMailRepositoryMailDAO.java
+++ b/server/mailrepository/mailrepository-cassandra/src/main/java/org/apache/james/mailrepository/cassandra/CassandraMailRepositoryMailDAO.java
@@ -55,7 +55,6 @@ import java.util.Collection;
import java.util.Date;
import java.util.List;
import java.util.Map;
-import java.util.Objects;
import java.util.Optional;
import java.util.concurrent.CompletableFuture;
@@ -82,10 +81,11 @@ import com.datastax.driver.core.Session;
import com.datastax.driver.core.UDTValue;
import com.github.fge.lambdas.Throwing;
import com.github.steveash.guavate.Guavate;
+import com.google.common.annotations.VisibleForTesting;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableMap;
-public class CassandraMailRepositoryMailDAO {
+public class CassandraMailRepositoryMailDAO implements CassandraMailRepositoryMailDaoAPI {
private final CassandraAsyncExecutor executor;
private final PreparedStatement insertMail;
@@ -95,8 +95,9 @@ public class CassandraMailRepositoryMailDAO {
private final CassandraTypesProvider cassandraTypesProvider;
@Inject
- public CassandraMailRepositoryMailDAO(Session session, BlobId.Factory blobIdFactory,
- CassandraTypesProvider cassandraTypesProvider) {
+ @VisibleForTesting
+ CassandraMailRepositoryMailDAO(Session session, BlobId.Factory blobIdFactory,
+ CassandraTypesProvider cassandraTypesProvider) {
this.executor = new CassandraAsyncExecutor(session);
this.insertMail = prepareInsert(session);
@@ -139,6 +140,7 @@ public class CassandraMailRepositoryMailDAO {
.and(eq(MAIL_KEY, bindMarker(MAIL_KEY))));
}
+ @Override
public CompletableFuture<Void> store(MailRepositoryUrl url, Mail mail, BlobId headerId, BlobId bodyId) throws MessagingException {
return executor.executeVoid(insertMail.bind()
.setString(REPOSITORY_NAME, url.asString())
@@ -158,12 +160,14 @@ public class CassandraMailRepositoryMailDAO {
);
}
+ @Override
public CompletableFuture<Void> remove(MailRepositoryUrl url, MailKey key) {
return executor.executeVoid(deleteMail.bind()
.setString(REPOSITORY_NAME, url.asString())
.setString(MAIL_KEY, key.asString()));
}
+ @Override
public CompletableFuture<Optional<MailDTO>> read(MailRepositoryUrl url, MailKey key) {
return executor.executeSingleRow(selectMail.bind()
.setString(REPOSITORY_NAME, url.asString())
@@ -277,44 +281,4 @@ public class CassandraMailRepositoryMailDAO {
}
}
- public class MailDTO {
- private final MailImpl.Builder mailBuilder;
- private final BlobId headerBlobId;
- private final BlobId bodyBlobId;
-
- public MailDTO(MailImpl.Builder mailBuilder, BlobId headerBlobId, BlobId bodyBlobId) {
- this.mailBuilder = mailBuilder;
- this.headerBlobId = headerBlobId;
- this.bodyBlobId = bodyBlobId;
- }
-
- public MailImpl.Builder getMailBuilder() {
- return mailBuilder;
- }
-
- public BlobId getHeaderBlobId() {
- return headerBlobId;
- }
-
- public BlobId getBodyBlobId() {
- return bodyBlobId;
- }
-
- @Override
- public final boolean equals(Object o) {
- if (o instanceof MailDTO) {
- MailDTO mailDTO = (MailDTO) o;
-
- return Objects.equals(this.mailBuilder.build(), mailDTO.mailBuilder.build())
- && Objects.equals(this.headerBlobId, mailDTO.headerBlobId)
- && Objects.equals(this.bodyBlobId, mailDTO.bodyBlobId);
- }
- return false;
- }
-
- @Override
- public final int hashCode() {
- return Objects.hash(mailBuilder.build(), headerBlobId, bodyBlobId);
- }
- }
}
http://git-wip-us.apache.org/repos/asf/james-project/blob/7a2e552f/server/mailrepository/mailrepository-cassandra/src/main/java/org/apache/james/mailrepository/cassandra/CassandraMailRepositoryMailDaoAPI.java
----------------------------------------------------------------------
diff --git a/server/mailrepository/mailrepository-cassandra/src/main/java/org/apache/james/mailrepository/cassandra/CassandraMailRepositoryMailDaoAPI.java b/server/mailrepository/mailrepository-cassandra/src/main/java/org/apache/james/mailrepository/cassandra/CassandraMailRepositoryMailDaoAPI.java
new file mode 100644
index 0000000..435bcf1
--- /dev/null
+++ b/server/mailrepository/mailrepository-cassandra/src/main/java/org/apache/james/mailrepository/cassandra/CassandraMailRepositoryMailDaoAPI.java
@@ -0,0 +1,81 @@
+/****************************************************************
+ * 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.mailrepository.cassandra;
+
+import java.util.Objects;
+import java.util.Optional;
+import java.util.concurrent.CompletableFuture;
+
+import javax.mail.MessagingException;
+
+import org.apache.james.blob.api.BlobId;
+import org.apache.james.mailrepository.api.MailKey;
+import org.apache.james.mailrepository.api.MailRepositoryUrl;
+import org.apache.james.server.core.MailImpl;
+import org.apache.mailet.Mail;
+
+public interface CassandraMailRepositoryMailDaoAPI {
+ CompletableFuture<Void> store(MailRepositoryUrl url, Mail mail, BlobId headerId, BlobId bodyId) throws MessagingException;
+
+ CompletableFuture<Void> remove(MailRepositoryUrl url, MailKey key);
+
+ CompletableFuture<Optional<MailDTO>> read(MailRepositoryUrl url, MailKey key);
+
+ class MailDTO {
+ private final MailImpl.Builder mailBuilder;
+ private final BlobId headerBlobId;
+ private final BlobId bodyBlobId;
+
+ public MailDTO(MailImpl.Builder mailBuilder, BlobId headerBlobId, BlobId bodyBlobId) {
+ this.mailBuilder = mailBuilder;
+ this.headerBlobId = headerBlobId;
+ this.bodyBlobId = bodyBlobId;
+ }
+
+ public MailImpl.Builder getMailBuilder() {
+ return mailBuilder;
+ }
+
+ public BlobId getHeaderBlobId() {
+ return headerBlobId;
+ }
+
+ public BlobId getBodyBlobId() {
+ return bodyBlobId;
+ }
+
+ @Override
+ public final boolean equals(Object o) {
+ if (o instanceof MailDTO) {
+ MailDTO mailDTO = (MailDTO) o;
+
+ return Objects.equals(this.mailBuilder.build(), mailDTO.mailBuilder.build())
+ && Objects.equals(this.headerBlobId, mailDTO.headerBlobId)
+ && Objects.equals(this.bodyBlobId, mailDTO.bodyBlobId);
+ }
+ return false;
+ }
+
+ @Override
+ public final int hashCode() {
+ return Objects.hash(mailBuilder.build(), headerBlobId, bodyBlobId);
+ }
+ }
+}
http://git-wip-us.apache.org/repos/asf/james-project/blob/7a2e552f/server/mailrepository/mailrepository-cassandra/src/main/java/org/apache/james/mailrepository/cassandra/CassandraMailRepositoryProvider.java
----------------------------------------------------------------------
diff --git a/server/mailrepository/mailrepository-cassandra/src/main/java/org/apache/james/mailrepository/cassandra/CassandraMailRepositoryProvider.java b/server/mailrepository/mailrepository-cassandra/src/main/java/org/apache/james/mailrepository/cassandra/CassandraMailRepositoryProvider.java
index d5c1077..410c46b 100644
--- a/server/mailrepository/mailrepository-cassandra/src/main/java/org/apache/james/mailrepository/cassandra/CassandraMailRepositoryProvider.java
+++ b/server/mailrepository/mailrepository-cassandra/src/main/java/org/apache/james/mailrepository/cassandra/CassandraMailRepositoryProvider.java
@@ -29,12 +29,12 @@ import org.apache.james.mailrepository.api.MailRepositoryUrl;
public class CassandraMailRepositoryProvider implements MailRepositoryProvider {
private final CassandraMailRepositoryKeysDAO keysDAO;
private final CassandraMailRepositoryCountDAO countDAO;
- private final CassandraMailRepositoryMailDAO mailDAO;
+ private final CassandraMailRepositoryMailDaoAPI mailDAO;
private final MimeMessageStore.Factory mimeMessageStoreFactory;
@Inject
public CassandraMailRepositoryProvider(CassandraMailRepositoryKeysDAO keysDAO, CassandraMailRepositoryCountDAO countDAO,
- CassandraMailRepositoryMailDAO mailDAO, MimeMessageStore.Factory mimeMessageStoreFactory) {
+ CassandraMailRepositoryMailDaoAPI mailDAO, MimeMessageStore.Factory mimeMessageStoreFactory) {
this.keysDAO = keysDAO;
this.countDAO = countDAO;
this.mailDAO = mailDAO;
http://git-wip-us.apache.org/repos/asf/james-project/blob/7a2e552f/server/mailrepository/mailrepository-cassandra/src/test/java/org/apache/james/mailrepository/cassandra/CassandraMailRepositoryMailDAOTest.java
----------------------------------------------------------------------
diff --git a/server/mailrepository/mailrepository-cassandra/src/test/java/org/apache/james/mailrepository/cassandra/CassandraMailRepositoryMailDAOTest.java b/server/mailrepository/mailrepository-cassandra/src/test/java/org/apache/james/mailrepository/cassandra/CassandraMailRepositoryMailDAOTest.java
index de19dee..582a7ba 100644
--- a/server/mailrepository/mailrepository-cassandra/src/test/java/org/apache/james/mailrepository/cassandra/CassandraMailRepositoryMailDAOTest.java
+++ b/server/mailrepository/mailrepository-cassandra/src/test/java/org/apache/james/mailrepository/cassandra/CassandraMailRepositoryMailDAOTest.java
@@ -33,6 +33,7 @@ import org.apache.mailet.PerRecipientHeaders;
import org.apache.mailet.base.MailAddressFixture;
import org.apache.mailet.base.test.FakeMail;
import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Nested;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.RegisterExtension;
@@ -46,109 +47,128 @@ class CassandraMailRepositoryMailDAOTest {
@RegisterExtension
static CassandraClusterExtension cassandraCluster = new CassandraClusterExtension(CassandraMailRepositoryModule.MODULE);
- CassandraMailRepositoryMailDAO testee;
- @BeforeEach
- void setUp(CassandraCluster cassandra) {
- testee = new CassandraMailRepositoryMailDAO(cassandra.getConf(), BLOB_ID_FACTORY, cassandra.getTypesProvider());
- }
-
- @Test
- void readShouldReturnEmptyWhenAbsent() {
- assertThat(testee.read(URL, KEY_1).join())
- .isEmpty();
- }
-
- @Test
- void readShouldReturnAllMailMetadata() throws Exception {
- BlobId blobIdBody = BLOB_ID_FACTORY.from("blobHeader");
- BlobId blobIdHeader = BLOB_ID_FACTORY.from("blobBody");
- String errorMessage = "error message";
- String state = "state";
- String remoteAddr = "remoteAddr";
- String remoteHost = "remoteHost";
- PerRecipientHeaders.Header header = PerRecipientHeaders.Header.builder().name("headerName").value("headerValue").build();
- String attributeName = "att1";
- ImmutableList<String> attributeValue = ImmutableList.of("value1", "value2");
-
- testee.store(URL,
- FakeMail.builder()
- .name(KEY_1.asString())
- .sender(MailAddressFixture.SENDER)
- .recipients(MailAddressFixture.RECIPIENT1, MailAddressFixture.RECIPIENT2)
- .errorMessage(errorMessage)
- .state(state)
- .remoteAddr(remoteAddr)
- .remoteHost(remoteHost)
- .addHeaderForRecipient(header, MailAddressFixture.RECIPIENT1)
- .attribute(attributeName, attributeValue)
- .build(),
- blobIdHeader,
- blobIdBody)
- .join();
-
- CassandraMailRepositoryMailDAO.MailDTO mailDTO = testee.read(URL, KEY_1).join().get();
-
- Mail partialMail = mailDTO.getMailBuilder().build();
- assertSoftly(softly -> {
- softly.assertThat(mailDTO.getBodyBlobId()).isEqualTo(blobIdBody);
- softly.assertThat(mailDTO.getHeaderBlobId()).isEqualTo(blobIdHeader);
- softly.assertThat(partialMail.getName()).isEqualTo(KEY_1.asString());
- softly.assertThat(partialMail.getErrorMessage()).isEqualTo(errorMessage);
- softly.assertThat(partialMail.getState()).isEqualTo(state);
- softly.assertThat(partialMail.getRemoteAddr()).isEqualTo(remoteAddr);
- softly.assertThat(partialMail.getRemoteHost()).isEqualTo(remoteHost);
- softly.assertThat(partialMail.getAttributeNames()).containsOnly(attributeName);
- softly.assertThat(partialMail.getAttribute(attributeName)).isEqualTo(attributeValue);
- softly.assertThat(partialMail.getPerRecipientSpecificHeaders().getRecipientsWithSpecificHeaders())
+ abstract class TestSuite {
+
+ abstract CassandraMailRepositoryMailDaoAPI testee();
+
+ @Test
+ void readShouldReturnAllMailMetadata() throws Exception {
+ CassandraMailRepositoryMailDaoAPI testee = testee();
+
+ BlobId blobIdBody = BLOB_ID_FACTORY.from("blobHeader");
+ BlobId blobIdHeader = BLOB_ID_FACTORY.from("blobBody");
+ String errorMessage = "error message";
+ String state = "state";
+ String remoteAddr = "remoteAddr";
+ String remoteHost = "remoteHost";
+ PerRecipientHeaders.Header header = PerRecipientHeaders.Header.builder().name("headerName").value("headerValue").build();
+ String attributeName = "att1";
+ ImmutableList<String> attributeValue = ImmutableList.of("value1", "value2");
+
+ testee.store(URL,
+ FakeMail.builder()
+ .name(KEY_1.asString())
+ .sender(MailAddressFixture.SENDER)
+ .recipients(MailAddressFixture.RECIPIENT1, MailAddressFixture.RECIPIENT2)
+ .errorMessage(errorMessage)
+ .state(state)
+ .remoteAddr(remoteAddr)
+ .remoteHost(remoteHost)
+ .addHeaderForRecipient(header, MailAddressFixture.RECIPIENT1)
+ .attribute(attributeName, attributeValue)
+ .build(),
+ blobIdHeader,
+ blobIdBody)
+ .join();
+
+ CassandraMailRepositoryMailDAO.MailDTO mailDTO = testee.read(URL, KEY_1).join().get();
+
+ Mail partialMail = mailDTO.getMailBuilder().build();
+ assertSoftly(softly -> {
+ softly.assertThat(mailDTO.getBodyBlobId()).isEqualTo(blobIdBody);
+ softly.assertThat(mailDTO.getHeaderBlobId()).isEqualTo(blobIdHeader);
+ softly.assertThat(partialMail.getName()).isEqualTo(KEY_1.asString());
+ softly.assertThat(partialMail.getErrorMessage()).isEqualTo(errorMessage);
+ softly.assertThat(partialMail.getState()).isEqualTo(state);
+ softly.assertThat(partialMail.getRemoteAddr()).isEqualTo(remoteAddr);
+ softly.assertThat(partialMail.getRemoteHost()).isEqualTo(remoteHost);
+ softly.assertThat(partialMail.getAttributeNames()).containsOnly(attributeName);
+ softly.assertThat(partialMail.getAttribute(attributeName)).isEqualTo(attributeValue);
+ softly.assertThat(partialMail.getPerRecipientSpecificHeaders().getRecipientsWithSpecificHeaders())
.containsOnly(MailAddressFixture.RECIPIENT1);
- softly.assertThat(partialMail.getPerRecipientSpecificHeaders().getHeadersForRecipient(MailAddressFixture.RECIPIENT1))
+ softly.assertThat(partialMail.getPerRecipientSpecificHeaders().getHeadersForRecipient(MailAddressFixture.RECIPIENT1))
.containsOnly(header);
- softly.assertThat(partialMail.getMaybeSender().asOptional()).contains(MailAddressFixture.SENDER);
- softly.assertThat(partialMail.getRecipients()).containsOnly(MailAddressFixture.RECIPIENT1, MailAddressFixture.RECIPIENT2);
- });
+ softly.assertThat(partialMail.getMaybeSender().asOptional()).contains(MailAddressFixture.SENDER);
+ softly.assertThat(partialMail.getRecipients()).containsOnly(MailAddressFixture.RECIPIENT1, MailAddressFixture.RECIPIENT2);
+ });
+ }
+
+ @Test
+ void storeShouldAcceptMailWithOnlyName() throws Exception {
+ CassandraMailRepositoryMailDaoAPI testee = testee();
+ BlobId blobIdBody = BLOB_ID_FACTORY.from("blobHeader");
+ BlobId blobIdHeader = BLOB_ID_FACTORY.from("blobBody");
+
+ testee.store(URL,
+ FakeMail.builder()
+ .name(KEY_1.asString())
+ .build(),
+ blobIdHeader,
+ blobIdBody)
+ .join();
+
+ CassandraMailRepositoryMailDAO.MailDTO mailDTO = testee.read(URL, KEY_1).join().get();
+
+ Mail partialMail = mailDTO.getMailBuilder().build();
+ assertSoftly(softly -> {
+ softly.assertThat(mailDTO.getBodyBlobId()).isEqualTo(blobIdBody);
+ softly.assertThat(mailDTO.getHeaderBlobId()).isEqualTo(blobIdHeader);
+ softly.assertThat(partialMail.getName()).isEqualTo(KEY_1.asString());
+ });
+ }
+
+ @Test
+ void removeShouldDeleteMailMetaData() throws Exception {
+ CassandraMailRepositoryMailDaoAPI testee = testee();
+ BlobId blobIdBody = BLOB_ID_FACTORY.from("blobHeader");
+ BlobId blobIdHeader = BLOB_ID_FACTORY.from("blobBody");
+
+ testee.store(URL,
+ FakeMail.builder()
+ .name(KEY_1.asString())
+ .build(),
+ blobIdHeader,
+ blobIdBody)
+ .join();
+
+ testee.remove(URL, KEY_1).join();
+
+ assertThat(testee.read(URL, KEY_1).join())
+ .isEmpty();
+ }
+
+
+ @Test
+ void readShouldReturnEmptyWhenAbsent() {
+ assertThat(testee().read(URL, KEY_1).join())
+ .isEmpty();
+ }
}
- @Test
- void storeShouldAcceptMailWithOnlyName() throws Exception {
- BlobId blobIdBody = BLOB_ID_FACTORY.from("blobHeader");
- BlobId blobIdHeader = BLOB_ID_FACTORY.from("blobBody");
-
- testee.store(URL,
- FakeMail.builder()
- .name(KEY_1.asString())
- .build(),
- blobIdHeader,
- blobIdBody)
- .join();
-
- CassandraMailRepositoryMailDAO.MailDTO mailDTO = testee.read(URL, KEY_1).join().get();
-
- Mail partialMail = mailDTO.getMailBuilder().build();
- assertSoftly(softly -> {
- softly.assertThat(mailDTO.getBodyBlobId()).isEqualTo(blobIdBody);
- softly.assertThat(mailDTO.getHeaderBlobId()).isEqualTo(blobIdHeader);
- softly.assertThat(partialMail.getName()).isEqualTo(KEY_1.asString());
- });
- }
-
- @Test
- void removeShouldDeleteMailMetaData() throws Exception {
- BlobId blobIdBody = BLOB_ID_FACTORY.from("blobHeader");
- BlobId blobIdHeader = BLOB_ID_FACTORY.from("blobBody");
+ @Nested
+ class v1 extends TestSuite {
- testee.store(URL,
- FakeMail.builder()
- .name(KEY_1.asString())
- .build(),
- blobIdHeader,
- blobIdBody)
- .join();
+ private CassandraMailRepositoryMailDAO testee;
- testee.remove(URL, KEY_1).join();
+ @BeforeEach
+ void setUp(CassandraCluster cassandra) {
+ testee = new CassandraMailRepositoryMailDAO(cassandra.getConf(), BLOB_ID_FACTORY, cassandra.getTypesProvider());
+ }
- assertThat(testee.read(URL, KEY_1).join())
- .isEmpty();
+ @Override
+ CassandraMailRepositoryMailDaoAPI testee() {
+ return testee;
+ }
}
-
}
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/james-project/blob/7a2e552f/server/mailrepository/mailrepository-cassandra/src/test/java/org/apache/james/mailrepository/cassandra/CassandraMailRepositoryWithFakeImplementationsTest.java
----------------------------------------------------------------------
diff --git a/server/mailrepository/mailrepository-cassandra/src/test/java/org/apache/james/mailrepository/cassandra/CassandraMailRepositoryWithFakeImplementationsTest.java b/server/mailrepository/mailrepository-cassandra/src/test/java/org/apache/james/mailrepository/cassandra/CassandraMailRepositoryWithFakeImplementationsTest.java
index ce56641..ca2eb2c 100644
--- a/server/mailrepository/mailrepository-cassandra/src/test/java/org/apache/james/mailrepository/cassandra/CassandraMailRepositoryWithFakeImplementationsTest.java
+++ b/server/mailrepository/mailrepository-cassandra/src/test/java/org/apache/james/mailrepository/cassandra/CassandraMailRepositoryWithFakeImplementationsTest.java
@@ -24,15 +24,14 @@ import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.api.Assertions.assertThatThrownBy;
import java.util.List;
+import java.util.Optional;
import java.util.concurrent.CompletableFuture;
-import javax.mail.MessagingException;
import javax.mail.internet.MimeMessage;
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.init.CassandraTypesProvider;
import org.apache.james.backends.cassandra.utils.CassandraUtils;
import org.apache.james.blob.api.BlobId;
import org.apache.james.blob.api.HashBlobId;
@@ -82,7 +81,7 @@ class CassandraMailRepositoryWithFakeImplementationsTest {
@BeforeEach
void setup(CassandraCluster cassandra) {
- CassandraMailRepositoryMailDAO mailDAO = new CassandraMailRepositoryMailDAO(cassandra.getConf(), BLOB_ID_FACTORY, cassandra.getTypesProvider());
+ CassandraMailRepositoryMailDaoAPI mailDAO = new CassandraMailRepositoryMailDAO(cassandra.getConf(), BLOB_ID_FACTORY, cassandra.getTypesProvider());
keysDAO = new CassandraMailRepositoryKeysDAO(cassandra.getConf(), CassandraUtils.WITH_DEFAULT_CONFIGURATION);
CassandraMailRepositoryCountDAO countDAO = new CassandraMailRepositoryCountDAO(cassandra.getConf());
@@ -134,7 +133,7 @@ class CassandraMailRepositoryWithFakeImplementationsTest {
@BeforeEach
void setup(CassandraCluster cassandra) {
- FailingMailDAO mailDAO = new FailingMailDAO(cassandra.getConf(), BLOB_ID_FACTORY, cassandra.getTypesProvider());
+ FailingMailDAO mailDAO = new FailingMailDAO();
keysDAO = new CassandraMailRepositoryKeysDAO(cassandra.getConf(), CassandraUtils.WITH_DEFAULT_CONFIGURATION);
CassandraMailRepositoryCountDAO countDAO = new CassandraMailRepositoryCountDAO(cassandra.getConf());
CassandraBlobsDAO blobsDAO = new CassandraBlobsDAO(cassandra.getConf());
@@ -143,18 +142,32 @@ class CassandraMailRepositoryWithFakeImplementationsTest {
keysDAO, countDAO, mailDAO, MimeMessageStore.factory(blobsDAO).mimeMessageStore());
}
- class FailingMailDAO extends CassandraMailRepositoryMailDAO {
+ class FailingMailDAO implements CassandraMailRepositoryMailDaoAPI {
- public FailingMailDAO(Session session, BlobId.Factory blobIdFactory, CassandraTypesProvider cassandraTypesProvider) {
- super(session, blobIdFactory, cassandraTypesProvider);
+ FailingMailDAO() {
}
@Override
- public CompletableFuture<Void> store(MailRepositoryUrl url, Mail mail, BlobId headerId, BlobId bodyId) throws MessagingException {
+ public CompletableFuture<Void> store(MailRepositoryUrl url, Mail mail, BlobId headerId, BlobId bodyId) {
return CompletableFuture.supplyAsync(() -> {
throw new RuntimeException("Expected failure while storing mail parts");
});
}
+
+ @Override
+ public CompletableFuture<Void> remove(MailRepositoryUrl url, MailKey key) {
+ return CompletableFuture.supplyAsync(() -> {
+ throw new RuntimeException("Expected failure while remeving mail parts");
+ });
+
+ }
+
+ @Override
+ public CompletableFuture<Optional<CassandraMailRepositoryMailDAO.MailDTO>> read(MailRepositoryUrl url, MailKey key) {
+ return CompletableFuture.supplyAsync(() -> {
+ throw new RuntimeException("Expected failure while reading mail parts");
+ });
+ }
}
@Test
@@ -205,7 +218,7 @@ class CassandraMailRepositoryWithFakeImplementationsTest {
@BeforeEach
void setup(CassandraCluster cassandra) {
- CassandraMailRepositoryMailDAO mailDAO = new CassandraMailRepositoryMailDAO(cassandra.getConf(), BLOB_ID_FACTORY, cassandra.getTypesProvider());
+ CassandraMailRepositoryMailDaoAPI mailDAO = new CassandraMailRepositoryMailDAO(cassandra.getConf(), BLOB_ID_FACTORY, cassandra.getTypesProvider());
FailingKeysDAO keysDAO = new FailingKeysDAO(cassandra.getConf(), CassandraUtils.WITH_DEFAULT_CONFIGURATION);
countDAO = new CassandraMailRepositoryCountDAO(cassandra.getConf());
CassandraBlobsDAO blobsDAO = new CassandraBlobsDAO(cassandra.getConf());
@@ -216,7 +229,7 @@ class CassandraMailRepositoryWithFakeImplementationsTest {
class FailingKeysDAO extends CassandraMailRepositoryKeysDAO {
- public FailingKeysDAO(Session session, CassandraUtils cassandraUtils) {
+ FailingKeysDAO(Session session, CassandraUtils cassandraUtils) {
super(session, cassandraUtils);
}
---------------------------------------------------------------------
To unsubscribe, e-mail: server-dev-unsubscribe@james.apache.org
For additional commands, e-mail: server-dev-help@james.apache.org
[8/8] james-project git commit: JAMES-2608 Remove MESSAGE_SIZE from
MailRepositoryTableV2
Posted by ro...@apache.org.
JAMES-2608 Remove MESSAGE_SIZE from MailRepositoryTableV2
Project: http://git-wip-us.apache.org/repos/asf/james-project/repo
Commit: http://git-wip-us.apache.org/repos/asf/james-project/commit/1ebe3fde
Tree: http://git-wip-us.apache.org/repos/asf/james-project/tree/1ebe3fde
Diff: http://git-wip-us.apache.org/repos/asf/james-project/diff/1ebe3fde
Branch: refs/heads/master
Commit: 1ebe3fde75d170129c5d5e90a68f2174c3d464df
Parents: 31dd1b2
Author: Antoine Duprat <ad...@linagora.com>
Authored: Thu Dec 13 14:26:18 2018 +0100
Committer: Raphael Ouazana <ra...@linagora.com>
Committed: Wed Dec 19 09:24:12 2018 +0100
----------------------------------------------------------------------
.../cassandra/CassandraMailRepositoryMailDaoV2.java | 3 ---
.../james/mailrepository/cassandra/MailRepositoryTableV2.java | 3 +--
2 files changed, 1 insertion(+), 5 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/james-project/blob/1ebe3fde/server/mailrepository/mailrepository-cassandra/src/main/java/org/apache/james/mailrepository/cassandra/CassandraMailRepositoryMailDaoV2.java
----------------------------------------------------------------------
diff --git a/server/mailrepository/mailrepository-cassandra/src/main/java/org/apache/james/mailrepository/cassandra/CassandraMailRepositoryMailDaoV2.java b/server/mailrepository/mailrepository-cassandra/src/main/java/org/apache/james/mailrepository/cassandra/CassandraMailRepositoryMailDaoV2.java
index 10b44b1..156fa85 100644
--- a/server/mailrepository/mailrepository-cassandra/src/main/java/org/apache/james/mailrepository/cassandra/CassandraMailRepositoryMailDaoV2.java
+++ b/server/mailrepository/mailrepository-cassandra/src/main/java/org/apache/james/mailrepository/cassandra/CassandraMailRepositoryMailDaoV2.java
@@ -36,7 +36,6 @@ import static org.apache.james.mailrepository.cassandra.MailRepositoryTableV2.He
import static org.apache.james.mailrepository.cassandra.MailRepositoryTableV2.LAST_UPDATED;
import static org.apache.james.mailrepository.cassandra.MailRepositoryTableV2.MAIL_KEY;
import static org.apache.james.mailrepository.cassandra.MailRepositoryTableV2.MAIL_PROPERTIES;
-import static org.apache.james.mailrepository.cassandra.MailRepositoryTableV2.MESSAGE_SIZE;
import static org.apache.james.mailrepository.cassandra.MailRepositoryTableV2.PER_RECIPIENT_SPECIFIC_HEADERS;
import static org.apache.james.mailrepository.cassandra.MailRepositoryTableV2.RECIPIENTS;
import static org.apache.james.mailrepository.cassandra.MailRepositoryTableV2.REMOTE_ADDR;
@@ -118,7 +117,6 @@ public class CassandraMailRepositoryMailDaoV2 implements CassandraMailRepository
return session.prepare(insertInto(CONTENT_TABLE_NAME)
.value(REPOSITORY_NAME, bindMarker(REPOSITORY_NAME))
.value(MAIL_KEY, bindMarker(MAIL_KEY))
- .value(MESSAGE_SIZE, bindMarker(MESSAGE_SIZE))
.value(STATE, bindMarker(STATE))
.value(SENDER, bindMarker(SENDER))
.value(RECIPIENTS, bindMarker(RECIPIENTS))
@@ -152,7 +150,6 @@ public class CassandraMailRepositoryMailDaoV2 implements CassandraMailRepository
.setString(ERROR_MESSAGE, mail.getErrorMessage())
.setString(REMOTE_ADDR, mail.getRemoteAddr())
.setString(REMOTE_HOST, mail.getRemoteHost())
- .setLong(MESSAGE_SIZE, mail.getMessageSize())
.setTimestamp(LAST_UPDATED, mail.getLastUpdated())
.setMap(ATTRIBUTES, toRawAttributeMap(mail))
.setList(PER_RECIPIENT_SPECIFIC_HEADERS, toTupleList(mail.getPerRecipientSpecificHeaders()))
http://git-wip-us.apache.org/repos/asf/james-project/blob/1ebe3fde/server/mailrepository/mailrepository-cassandra/src/main/java/org/apache/james/mailrepository/cassandra/MailRepositoryTableV2.java
----------------------------------------------------------------------
diff --git a/server/mailrepository/mailrepository-cassandra/src/main/java/org/apache/james/mailrepository/cassandra/MailRepositoryTableV2.java b/server/mailrepository/mailrepository-cassandra/src/main/java/org/apache/james/mailrepository/cassandra/MailRepositoryTableV2.java
index 54e2e45..30b9ea5 100644
--- a/server/mailrepository/mailrepository-cassandra/src/main/java/org/apache/james/mailrepository/cassandra/MailRepositoryTableV2.java
+++ b/server/mailrepository/mailrepository-cassandra/src/main/java/org/apache/james/mailrepository/cassandra/MailRepositoryTableV2.java
@@ -25,7 +25,6 @@ public interface MailRepositoryTableV2 {
String REPOSITORY_NAME = "name";
String MAIL_KEY = "mailKey";
- String MESSAGE_SIZE = "messageSize";
String HEADER_BLOB_ID = "headerBlobId";
String BODY_BLOB_ID = "bodyBlobId";
String STATE = "state";
@@ -44,6 +43,6 @@ public interface MailRepositoryTableV2 {
int HEADER_VALUE_INDEX = 2;
}
- String[] MAIL_PROPERTIES = { MAIL_KEY, MESSAGE_SIZE, STATE, SENDER, RECIPIENTS, ATTRIBUTES, ERROR_MESSAGE, REMOTE_ADDR,
+ String[] MAIL_PROPERTIES = { MAIL_KEY, STATE, SENDER, RECIPIENTS, ATTRIBUTES, ERROR_MESSAGE, REMOTE_ADDR,
REMOTE_HOST, LAST_UPDATED, PER_RECIPIENT_SPECIFIC_HEADERS, HEADER_BLOB_ID, BODY_BLOB_ID };
}
---------------------------------------------------------------------
To unsubscribe, e-mail: server-dev-unsubscribe@james.apache.org
For additional commands, e-mail: server-dev-help@james.apache.org
[2/8] james-project git commit: JAMES-2608 finally bind
MergingCassandraMailRepositoryMailDao and enable the broken test
Posted by ro...@apache.org.
JAMES-2608 finally bind MergingCassandraMailRepositoryMailDao and enable the broken test
Project: http://git-wip-us.apache.org/repos/asf/james-project/repo
Commit: http://git-wip-us.apache.org/repos/asf/james-project/commit/31dd1b25
Tree: http://git-wip-us.apache.org/repos/asf/james-project/tree/31dd1b25
Diff: http://git-wip-us.apache.org/repos/asf/james-project/diff/31dd1b25
Branch: refs/heads/master
Commit: 31dd1b251d2e98deb8758318aef8027f784473ef
Parents: 48b99bf
Author: Matthieu Baechler <ma...@apache.org>
Authored: Wed Nov 28 19:17:12 2018 +0100
Committer: Raphael Ouazana <ra...@linagora.com>
Committed: Wed Dec 19 09:24:12 2018 +0100
----------------------------------------------------------------------
.../james/modules/data/CassandraMailRepositoryModule.java | 6 ++++++
.../apache/james/mailrepository/MailRepositoryContract.java | 2 --
.../mailrepository/cassandra/CassandraMailRepositoryTest.java | 4 +++-
3 files changed, 9 insertions(+), 3 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/james-project/blob/31dd1b25/server/container/guice/cassandra-guice/src/main/java/org/apache/james/modules/data/CassandraMailRepositoryModule.java
----------------------------------------------------------------------
diff --git a/server/container/guice/cassandra-guice/src/main/java/org/apache/james/modules/data/CassandraMailRepositoryModule.java b/server/container/guice/cassandra-guice/src/main/java/org/apache/james/modules/data/CassandraMailRepositoryModule.java
index 176c39b..60fa72f 100644
--- a/server/container/guice/cassandra-guice/src/main/java/org/apache/james/modules/data/CassandraMailRepositoryModule.java
+++ b/server/container/guice/cassandra-guice/src/main/java/org/apache/james/modules/data/CassandraMailRepositoryModule.java
@@ -25,9 +25,12 @@ import org.apache.james.mailrepository.api.MailRepositoryUrlStore;
import org.apache.james.mailrepository.cassandra.CassandraMailRepositoryCountDAO;
import org.apache.james.mailrepository.cassandra.CassandraMailRepositoryKeysDAO;
import org.apache.james.mailrepository.cassandra.CassandraMailRepositoryMailDAO;
+import org.apache.james.mailrepository.cassandra.CassandraMailRepositoryMailDaoAPI;
+import org.apache.james.mailrepository.cassandra.CassandraMailRepositoryMailDaoV2;
import org.apache.james.mailrepository.cassandra.CassandraMailRepositoryProvider;
import org.apache.james.mailrepository.cassandra.CassandraMailRepositoryUrlModule;
import org.apache.james.mailrepository.cassandra.CassandraMailRepositoryUrlStore;
+import org.apache.james.mailrepository.cassandra.MergingCassandraMailRepositoryMailDao;
import com.google.inject.AbstractModule;
import com.google.inject.Scopes;
@@ -40,7 +43,10 @@ public class CassandraMailRepositoryModule extends AbstractModule {
bind(CassandraMailRepositoryKeysDAO.class).in(Scopes.SINGLETON);
bind(CassandraMailRepositoryCountDAO.class).in(Scopes.SINGLETON);
bind(CassandraMailRepositoryMailDAO.class).in(Scopes.SINGLETON);
+ bind(CassandraMailRepositoryMailDaoV2.class).in(Scopes.SINGLETON);
+ bind(MergingCassandraMailRepositoryMailDao.class).in(Scopes.SINGLETON);
+ bind(CassandraMailRepositoryMailDaoAPI.class).to(MergingCassandraMailRepositoryMailDao.class);
bind(MailRepositoryUrlStore.class).to(CassandraMailRepositoryUrlStore.class);
Multibinder<MailRepositoryProvider> multibinder = Multibinder.newSetBinder(binder(), MailRepositoryProvider.class);
http://git-wip-us.apache.org/repos/asf/james-project/blob/31dd1b25/server/mailrepository/mailrepository-api/src/test/java/org/apache/james/mailrepository/MailRepositoryContract.java
----------------------------------------------------------------------
diff --git a/server/mailrepository/mailrepository-api/src/test/java/org/apache/james/mailrepository/MailRepositoryContract.java b/server/mailrepository/mailrepository-api/src/test/java/org/apache/james/mailrepository/MailRepositoryContract.java
index e106015..ee74d10 100644
--- a/server/mailrepository/mailrepository-api/src/test/java/org/apache/james/mailrepository/MailRepositoryContract.java
+++ b/server/mailrepository/mailrepository-api/src/test/java/org/apache/james/mailrepository/MailRepositoryContract.java
@@ -46,7 +46,6 @@ import org.apache.mailet.Mail;
import org.apache.mailet.PerRecipientHeaders;
import org.apache.mailet.base.MailAddressFixture;
import org.apache.mailet.base.test.FakeMail;
-import org.junit.jupiter.api.Disabled;
import org.junit.jupiter.api.RepeatedTest;
import org.junit.jupiter.api.Test;
@@ -421,7 +420,6 @@ public interface MailRepositoryContract {
}
- @Disabled("JAMES-2608")
@Test
default void storingMessageWithPerRecipientHeadersShouldAllowMultipleHeadersPerUser() throws Exception {
http://git-wip-us.apache.org/repos/asf/james-project/blob/31dd1b25/server/mailrepository/mailrepository-cassandra/src/test/java/org/apache/james/mailrepository/cassandra/CassandraMailRepositoryTest.java
----------------------------------------------------------------------
diff --git a/server/mailrepository/mailrepository-cassandra/src/test/java/org/apache/james/mailrepository/cassandra/CassandraMailRepositoryTest.java b/server/mailrepository/mailrepository-cassandra/src/test/java/org/apache/james/mailrepository/cassandra/CassandraMailRepositoryTest.java
index b0c059e..dbd39a3 100644
--- a/server/mailrepository/mailrepository-cassandra/src/test/java/org/apache/james/mailrepository/cassandra/CassandraMailRepositoryTest.java
+++ b/server/mailrepository/mailrepository-cassandra/src/test/java/org/apache/james/mailrepository/cassandra/CassandraMailRepositoryTest.java
@@ -52,7 +52,9 @@ class CassandraMailRepositoryTest implements MailRepositoryContract {
@BeforeEach
void setup(CassandraCluster cassandra) {
- CassandraMailRepositoryMailDAO mailDAO = new CassandraMailRepositoryMailDAO(cassandra.getConf(), BLOB_ID_FACTORY, cassandra.getTypesProvider());
+ CassandraMailRepositoryMailDAO v1 = new CassandraMailRepositoryMailDAO(cassandra.getConf(), BLOB_ID_FACTORY, cassandra.getTypesProvider());
+ CassandraMailRepositoryMailDaoV2 v2 = new CassandraMailRepositoryMailDaoV2(cassandra.getConf(), BLOB_ID_FACTORY);
+ CassandraMailRepositoryMailDaoAPI mailDAO = new MergingCassandraMailRepositoryMailDao(v1, v2);
CassandraMailRepositoryKeysDAO keysDAO = new CassandraMailRepositoryKeysDAO(cassandra.getConf(), CassandraUtils.WITH_DEFAULT_CONFIGURATION);
CassandraMailRepositoryCountDAO countDAO = new CassandraMailRepositoryCountDAO(cassandra.getConf());
CassandraBlobsDAO blobsDAO = new CassandraBlobsDAO(cassandra.getConf());
---------------------------------------------------------------------
To unsubscribe, e-mail: server-dev-unsubscribe@james.apache.org
For additional commands, e-mail: server-dev-help@james.apache.org
[5/8] james-project git commit: JAMES-2608 implement
MergingCassandraMailRepositoryMailDao to handle on-the-fly data migration
Posted by ro...@apache.org.
JAMES-2608 implement MergingCassandraMailRepositoryMailDao to handle on-the-fly data migration
Project: http://git-wip-us.apache.org/repos/asf/james-project/repo
Commit: http://git-wip-us.apache.org/repos/asf/james-project/commit/48b99bf7
Tree: http://git-wip-us.apache.org/repos/asf/james-project/tree/48b99bf7
Diff: http://git-wip-us.apache.org/repos/asf/james-project/diff/48b99bf7
Branch: refs/heads/master
Commit: 48b99bf7b00862ee4e7fcef7b08b44c61fdcbc57
Parents: d0f973b
Author: Matthieu Baechler <ma...@apache.org>
Authored: Wed Nov 28 19:11:44 2018 +0100
Committer: Raphael Ouazana <ra...@linagora.com>
Committed: Wed Dec 19 09:24:12 2018 +0100
----------------------------------------------------------------------
.../MergingCassandraMailRepositoryMailDao.java | 64 +++++++++
.../CassandraMailRepositoryMailDAOTest.java | 135 ++++++++++++++++++-
2 files changed, 197 insertions(+), 2 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/james-project/blob/48b99bf7/server/mailrepository/mailrepository-cassandra/src/main/java/org/apache/james/mailrepository/cassandra/MergingCassandraMailRepositoryMailDao.java
----------------------------------------------------------------------
diff --git a/server/mailrepository/mailrepository-cassandra/src/main/java/org/apache/james/mailrepository/cassandra/MergingCassandraMailRepositoryMailDao.java b/server/mailrepository/mailrepository-cassandra/src/main/java/org/apache/james/mailrepository/cassandra/MergingCassandraMailRepositoryMailDao.java
new file mode 100644
index 0000000..8b01a38
--- /dev/null
+++ b/server/mailrepository/mailrepository-cassandra/src/main/java/org/apache/james/mailrepository/cassandra/MergingCassandraMailRepositoryMailDao.java
@@ -0,0 +1,64 @@
+/****************************************************************
+ * 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.mailrepository.cassandra;
+
+import java.util.Optional;
+import java.util.concurrent.CompletableFuture;
+
+import javax.inject.Inject;
+import javax.mail.MessagingException;
+
+import org.apache.james.blob.api.BlobId;
+import org.apache.james.mailrepository.api.MailKey;
+import org.apache.james.mailrepository.api.MailRepositoryUrl;
+import org.apache.james.util.OptionalUtils;
+import org.apache.mailet.Mail;
+
+import com.google.common.annotations.VisibleForTesting;
+
+public class MergingCassandraMailRepositoryMailDao implements CassandraMailRepositoryMailDaoAPI {
+
+ private final CassandraMailRepositoryMailDAO v1;
+ private final CassandraMailRepositoryMailDaoV2 v2;
+
+ @Inject
+ @VisibleForTesting
+ MergingCassandraMailRepositoryMailDao(CassandraMailRepositoryMailDAO v1, CassandraMailRepositoryMailDaoV2 v2) {
+ this.v1 = v1;
+ this.v2 = v2;
+ }
+
+ @Override
+ public CompletableFuture<Void> store(MailRepositoryUrl url, Mail mail, BlobId headerId, BlobId bodyId) throws MessagingException {
+ return v2.store(url, mail, headerId, bodyId);
+ }
+
+ @Override
+ public CompletableFuture<Void> remove(MailRepositoryUrl url, MailKey key) {
+ return CompletableFuture.allOf(v1.remove(url, key), v2.remove(url, key));
+ }
+
+ @Override
+ public CompletableFuture<Optional<MailDTO>> read(MailRepositoryUrl url, MailKey key) {
+ return v2.read(url, key)
+ .thenCombine(v1.read(url, key),
+ (maybeV2Value, maybeV1Value) -> OptionalUtils.or(maybeV2Value, maybeV1Value));
+ }
+}
http://git-wip-us.apache.org/repos/asf/james-project/blob/48b99bf7/server/mailrepository/mailrepository-cassandra/src/test/java/org/apache/james/mailrepository/cassandra/CassandraMailRepositoryMailDAOTest.java
----------------------------------------------------------------------
diff --git a/server/mailrepository/mailrepository-cassandra/src/test/java/org/apache/james/mailrepository/cassandra/CassandraMailRepositoryMailDAOTest.java b/server/mailrepository/mailrepository-cassandra/src/test/java/org/apache/james/mailrepository/cassandra/CassandraMailRepositoryMailDAOTest.java
index c02966a..a50c69e 100644
--- a/server/mailrepository/mailrepository-cassandra/src/test/java/org/apache/james/mailrepository/cassandra/CassandraMailRepositoryMailDAOTest.java
+++ b/server/mailrepository/mailrepository-cassandra/src/test/java/org/apache/james/mailrepository/cassandra/CassandraMailRepositoryMailDAOTest.java
@@ -22,6 +22,10 @@ package org.apache.james.mailrepository.cassandra;
import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.api.SoftAssertions.assertSoftly;
+import java.util.Optional;
+
+import javax.mail.MessagingException;
+
import org.apache.james.backends.cassandra.CassandraCluster;
import org.apache.james.backends.cassandra.CassandraClusterExtension;
import org.apache.james.blob.api.BlobId;
@@ -157,7 +161,7 @@ class CassandraMailRepositoryMailDAOTest {
}
@Nested
- class v1 extends TestSuite {
+ class V1 extends TestSuite {
private CassandraMailRepositoryMailDAO testee;
@@ -173,7 +177,7 @@ class CassandraMailRepositoryMailDAOTest {
}
@Nested
- class v2 extends TestSuite {
+ class V2 extends TestSuite {
private CassandraMailRepositoryMailDaoV2 testee;
@@ -187,4 +191,131 @@ class CassandraMailRepositoryMailDAOTest {
return testee;
}
}
+
+ @Nested
+ class Merging extends TestSuite {
+
+ private MergingCassandraMailRepositoryMailDao testee;
+ private CassandraMailRepositoryMailDAO v1;
+ private CassandraMailRepositoryMailDaoV2 v2;
+
+ @BeforeEach
+ void setUp(CassandraCluster cassandra) {
+ v1 = new CassandraMailRepositoryMailDAO(cassandra.getConf(), BLOB_ID_FACTORY, cassandra.getTypesProvider());
+ v2 = new CassandraMailRepositoryMailDaoV2(cassandra.getConf(), BLOB_ID_FACTORY);
+ testee = new MergingCassandraMailRepositoryMailDao(v1, v2);
+ }
+
+ @Override
+ CassandraMailRepositoryMailDaoAPI testee() {
+ return testee;
+ }
+
+ @Test
+ void readShouldReturnV1Value() throws MessagingException {
+ BlobId blobIdBody = BLOB_ID_FACTORY.from("blobHeader");
+ BlobId blobIdHeader = BLOB_ID_FACTORY.from("blobBody");
+
+ v1.store(URL,
+ FakeMail.builder()
+ .name(KEY_1.asString())
+ .build(),
+ blobIdHeader,
+ blobIdBody)
+ .join();
+
+ CassandraMailRepositoryMailDaoAPI.MailDTO actual = testee.read(URL, KEY_1).join().get();
+ Mail partialMail = actual.getMailBuilder().build();
+ assertSoftly(softly -> {
+ softly.assertThat(actual.getBodyBlobId()).isEqualTo(blobIdBody);
+ softly.assertThat(actual.getHeaderBlobId()).isEqualTo(blobIdHeader);
+ softly.assertThat(partialMail.getName()).isEqualTo(KEY_1.asString());
+ });
+ }
+
+ @Test
+ void readShouldReturnV2Value() throws MessagingException {
+ BlobId blobIdBody = BLOB_ID_FACTORY.from("blobHeader");
+ BlobId blobIdHeader = BLOB_ID_FACTORY.from("blobBody");
+
+ v2.store(URL,
+ FakeMail.builder()
+ .name(KEY_1.asString())
+ .build(),
+ blobIdHeader,
+ blobIdBody)
+ .join();
+
+ CassandraMailRepositoryMailDaoAPI.MailDTO actual = testee.read(URL, KEY_1).join().get();
+ Mail partialMail = actual.getMailBuilder().build();
+ assertSoftly(softly -> {
+ softly.assertThat(actual.getBodyBlobId()).isEqualTo(blobIdBody);
+ softly.assertThat(actual.getHeaderBlobId()).isEqualTo(blobIdHeader);
+ softly.assertThat(partialMail.getName()).isEqualTo(KEY_1.asString());
+ });
+ }
+
+ @Test
+ void readShouldReturnV2ValueIfPresentInBoth() throws MessagingException {
+ BlobId blobIdBody1 = BLOB_ID_FACTORY.from("blobHeader");
+ BlobId blobIdBody2 = BLOB_ID_FACTORY.from("blobHeader2");
+ BlobId blobIdHeader1 = BLOB_ID_FACTORY.from("blobBody");
+ BlobId blobIdHeader2 = BLOB_ID_FACTORY.from("blobBody2");
+
+ v1.store(URL,
+ FakeMail.builder()
+ .name(KEY_1.asString())
+ .build(),
+ blobIdHeader1,
+ blobIdBody1)
+ .join();
+
+ v2.store(URL,
+ FakeMail.builder()
+ .name(KEY_1.asString())
+ .build(),
+ blobIdHeader2,
+ blobIdBody2)
+ .join();
+
+ CassandraMailRepositoryMailDaoAPI.MailDTO actual = testee.read(URL, KEY_1).join().get();
+ Mail partialMail = actual.getMailBuilder().build();
+ assertSoftly(softly -> {
+ softly.assertThat(actual.getBodyBlobId()).isEqualTo(blobIdBody2);
+ softly.assertThat(actual.getHeaderBlobId()).isEqualTo(blobIdHeader2);
+ softly.assertThat(partialMail.getName()).isEqualTo(KEY_1.asString());
+ });
+ }
+
+ @Test
+ void removeShouldRemoveInBOth() throws MessagingException {
+ BlobId blobIdBody1 = BLOB_ID_FACTORY.from("blobHeader");
+ BlobId blobIdBody2 = BLOB_ID_FACTORY.from("blobHeader2");
+ BlobId blobIdHeader1 = BLOB_ID_FACTORY.from("blobBody");
+ BlobId blobIdHeader2 = BLOB_ID_FACTORY.from("blobBody2");
+
+ v1.store(URL,
+ FakeMail.builder()
+ .name(KEY_1.asString())
+ .build(),
+ blobIdHeader1,
+ blobIdBody1)
+ .join();
+
+ v2.store(URL,
+ FakeMail.builder()
+ .name(KEY_1.asString())
+ .build(),
+ blobIdHeader2,
+ blobIdBody2)
+ .join();
+
+ testee.remove(URL, KEY_1).join();
+
+ Optional<CassandraMailRepositoryMailDaoAPI.MailDTO> v1Entry = v1.read(URL, KEY_1).join();
+ Optional<CassandraMailRepositoryMailDaoAPI.MailDTO> v2Entry = v2.read(URL, KEY_1).join();
+ assertThat(v1Entry).isEmpty();
+ assertThat(v2Entry).isEmpty();
+ }
+ }
}
\ No newline at end of file
---------------------------------------------------------------------
To unsubscribe, e-mail: server-dev-unsubscribe@james.apache.org
For additional commands, e-mail: server-dev-help@james.apache.org