/* * Copyright (C) 2012-2016 DuyHai DOAN * * Licensed 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 info.archinnov.achilles.junit; import static info.archinnov.achilles.embedded.CassandraEmbeddedConfigParameters.*; import static java.util.Arrays.asList; import static java.util.Optional.ofNullable; import java.util.*; import java.util.function.BiFunction; import com.datastax.driver.core.Cluster; import info.archinnov.achilles.internals.cache.StatementsCache; import info.archinnov.achilles.internals.runtime.AbstractManagerFactory; import info.archinnov.achilles.junit.AchillesTestResource.Steps; import info.archinnov.achilles.type.TypedMap; import info.archinnov.achilles.validation.Validator; /** * <strong>WARNING: this AchillesTestResource will use an unsafe Cassandra daemon, it is not suitable for production</strong> * <br/><br/> * Builder class to create an instance of {@link AchillesTestResource} * <pre class="code"><code class="java"> * AchillesTestResourceBuilder * .forJunit() * .withScript("script1.cql") * .withScript("script2.cql") * .tablesToTruncate("user", "account") // entityClassesToTruncate(UserEntity.class, AccountEntity.class) * .createAndUseKeyspace("unit_test") * . * ... * .build((cluster, statementsCache) -> ManagerFactoryBuilder * .builder(cluster) * .doForceSchemaCreation(true) * .withStatementCache(statementsCache) * .withDefaultKeyspaceName(DEFAULT_CASSANDRA_EMBEDDED_KEYSPACE_NAME) * .build() * ); * </code></pre> * */ public class AchillesTestResourceBuilder { private Steps cleanupSteps = Steps.BOTH; private List<Class<?>> entityClassesToCleanUp = new ArrayList<>(); private Optional<String> keyspace = Optional.empty(); private TypedMap cassandraParams = new TypedMap(); private List<String> scriptLocations = new ArrayList<>(); private Map<String, Map<String, Object>> scriptTemplates = new HashMap<>(); private List<String> tablesToTruncate = new ArrayList<>(); private AchillesTestResourceBuilder() { } public static AchillesTestResourceBuilder forJunit() { return new AchillesTestResourceBuilder(); } /** * /** * Load an CQL script in the class path and execute it upon initialization * of the embedded Cassandra server * <br/> * Call this method as many times as there are CQL scripts to be executed. * <br/> * Example: * <br/> * <pre class="code"><code class="java"> * AchillesTestResourceBuilder * .forJunit() * .withScript("script1.cql") * .withScript("script2.cql") * ... * .build(cluster -> ManagerFactoryBuilder * .builder(cluster) * .doForceSchemaCreation(true) * .withDefaultKeyspaceName(DEFAULT_CASSANDRA_EMBEDDED_KEYSPACE_NAME) * .build()); * </code></pre> * * @param scriptLocation location of the CQL script in the <strong>class path</strong> * @return AchillesTestResourceBuilder */ public AchillesTestResourceBuilder withScript(String scriptLocation) { scriptLocations.add(scriptLocation); return this; } /** * Load an CQL script template in the class path, inject the values into the template * to produce the final script and execute it upon initialization * of the embedded Cassandra server * <br/> * Call this method as many times as there are CQL templates to be executed. * <br/> * Example: * <br/> * <pre class="code"><code class="java"> * Map<String, Object> map1 = new HashMap<>(); * map1.put("id", 100L); * map1.put("date", new Date()); * ... * AchillesTestResourceBuilder * .forJunit() * .withScriptTemplate("script1.cql", map1) * .withScriptTemplate("script2.cql", map2) * ... * .build(); * </code></pre> * * @param scriptTemplateLocation location of the CQL script in the <strong>class path</strong> * @param values values to inject into the template. * @return AchillesTestResourceBuilder */ public AchillesTestResourceBuilder withScriptTemplate(String scriptTemplateLocation, Map<String, Object> values) { Validator.validateNotBlank(scriptTemplateLocation, "The script template should not be blank while executing AchillesTestResourceBuilder.withScriptTemplate()"); Validator.validateNotEmpty(values, "The template values should not be empty while executing AchillesTestResourceBuilder.withScriptTemplate()"); scriptTemplates.put(scriptTemplateLocation.trim(), values); return this; } /** * Keyspace name to create * * @param keyspaceName keyspace name * @return AchillesTestResourceBuilder */ public AchillesTestResourceBuilder createAndUseKeyspace(String keyspaceName) { this.keyspace = ofNullable(keyspaceName); this.keyspace.ifPresent(ks -> this.cassandraParams.put(DEFAULT_KEYSPACE_NAME, ks)); return this; } /** * Entity classes whose table should be truncated during unit tests * * @param entityClassesToTruncate list of entity classes whose table should be truncated before and/or after tests * @return AchillesTestResourceBuilder */ public AchillesTestResourceBuilder entityClassesToTruncate(Class<?>... entityClassesToTruncate) { this.entityClassesToCleanUp.addAll(asList(ofNullable(entityClassesToTruncate).orElse(new Class<?>[]{}))); return this; } /** * Tables to be truncated during unit tests * * @param tablesToTruncate list of tables to truncate * @return AchillesTestResourceBuilder */ public AchillesTestResourceBuilder tablesToTruncate(String... tablesToTruncate) { this.tablesToTruncate.addAll(asList(ofNullable(tablesToTruncate).orElse(new String[]{}))); return this; } /** * Truncate tables BEFORE each test * * @return AchillesTestResourceBuilder */ public AchillesTestResourceBuilder truncateBeforeTest() { this.cleanupSteps = Steps.BEFORE_TEST; return this; } /** * Truncate tables AFTER each test * * @return AchillesTestResourceBuilder */ public AchillesTestResourceBuilder truncateAfterTest() { this.cleanupSteps = Steps.AFTER_TEST; return this; } /** * Truncate tables BEFORE and AFTER each test * * @return AchillesTestResourceBuilder */ public AchillesTestResourceBuilder truncateBeforeAndAfterTest() { this.cleanupSteps = Steps.BOTH; return this; } /** * Provide a lambda function to build the ManagerFactory instance with the given Cluster object * * @param managerFactoryBuilder lambda function * @return ManagerFactory */ public <T extends AbstractManagerFactory> AchillesTestResource<T> build(BiFunction<Cluster, StatementsCache, T> managerFactoryBuilder) { final TypedMap cassandraParams = buildCassandraParams(); return new AchillesTestResource<>(managerFactoryBuilder, cassandraParams, keyspace, cleanupSteps, tablesToTruncate, entityClassesToCleanUp); } private TypedMap buildCassandraParams() { cassandraParams.put(SCRIPT_LOCATIONS, scriptLocations); cassandraParams.put(SCRIPT_TEMPLATES, scriptTemplates); cassandraParams.put(USE_UNSAFE_CASSANDRA_DAEMON, false); return cassandraParams; } }