Java tutorial
package org.raistlic.spring.test.flyway; /* * Copyright 2015 Lei CHEN (raistlic@gmail.com) * * 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. */ import org.flywaydb.core.Flyway; import org.raistlic.common.precondition.Precondition; import org.raistlic.common.precondition.PreconditionException; import org.raistlic.spring.test.DataReset; import org.springframework.context.ApplicationContext; import org.springframework.core.annotation.AnnotationUtils; import org.springframework.test.context.TestContext; import org.springframework.test.context.TestExecutionListener; import java.util.Arrays; import java.util.Collections; import java.util.HashSet; import java.util.Set; /** * @author Lei CHEN (2015-08-30) * @since 1.2 */ public class FlywayTestExecutionListener implements TestExecutionListener { private static final Set<String> FIRST_RESET_DONE_SET = Collections.synchronizedSet(new HashSet<String>()); @Override public void beforeTestClass(TestContext testContext) throws Exception { // do nothing } @Override public void prepareTestInstance(TestContext testContext) throws Exception { // do nothing } /** * The method checks whether a database reset needs to be done for the test method, based on the * annotations on the test method and test class, and calls flyway to do the database reset if * needed. * * @param testContext the test context, cannot be {@code null}. * @throws PreconditionException when the {@code testContext} is {@code null} or not valid. * @throws FlywayTestExecutionException when anything goes wrong when trying to do the check or * database reset. */ @Override public void beforeTestMethod(TestContext testContext) throws PreconditionException, FlywayTestExecutionException { Precondition.param(testContext, "testContext").notNull(); Precondition.param(testContext.getApplicationContext(), "testContext.applicationContext").notNull(); Precondition.param(testContext.getTestClass(), "testContext.testClass").notNull(); Precondition.param(testContext.getTestMethod(), "testContext.testMethod").notNull(); DataReset annotation = getDataResetAnnotation(testContext); if (annotation == null) { return; } String name = annotation.value(); synchronized (FIRST_RESET_DONE_SET) { if (FIRST_RESET_DONE_SET.contains(name)) { return; } ApplicationContext applicationContext = testContext.getApplicationContext(); Flyway flyway = getFlywayBean(applicationContext, name); doReset(flyway, name); FIRST_RESET_DONE_SET.add(name); } } @Override public void afterTestMethod(TestContext testContext) throws Exception { DataReset annotation = getDataResetAnnotation(testContext); if (annotation == null) { return; } if (annotation.readOnly()) { return; } String name = annotation.value(); ApplicationContext applicationContext = testContext.getApplicationContext(); Flyway flyway = getFlywayBean(applicationContext, name); doReset(flyway, name); } @Override public void afterTestClass(TestContext testContext) throws Exception { // do nothing } /** * The method gets and returns the {@link DataReset} annotation from the {@code testContext}, or * {@code null} if none found. * * @param testContext the test context to get {@link DataReset} annotation from, cannot be * {@code null} and must be valid. * @return the {@link DataReset} found, or {@code null} if none found. * * @throws PreconditionException when {@code testContext} is {@code null} or invalid. */ static DataReset getDataResetAnnotation(TestContext testContext) { Precondition.param(testContext, "testContext").notNull(); Precondition.param(testContext.getTestMethod(), "testContext.testMethod").notNull(); Precondition.param(testContext.getTestClass(), "testContext.testClass").notNull(); DataReset annotation = AnnotationUtils.getAnnotation(testContext.getTestMethod(), DataReset.class); if (annotation == null) { annotation = AnnotationUtils.getAnnotation(testContext.getTestClass(), DataReset.class); } return annotation; } /** * * * @param flyway * @param name */ static void doReset(Flyway flyway, String name) { try { flyway.clean(); flyway.migrate(); } catch (Exception ex) { if (ex instanceof FlywayTestExecutionException) { throw (FlywayTestExecutionException) ex; } else { throw new FlywayTestExecutionException(ex); } } } /** * The method gets the {@link Flyway} bean from the {@code applicationContext}, using the given * {@code name} if its not empty and there are multiple instances of beans of type {@link Flyway}. * * @param applicationContext the application context to find the bean from, cannot be {@code null}. * @param name the name to help identify the bean if multiple instances exist, {@code null} or * empty if not specified. * @return the required {@link Flyway} bean. * * @throws PreconditionException when {@code applicationContext} is {@code null}. * @throws FlywayTestExecutionException when any other error occur in the process of finding the * {@link Flyway} bean. */ static Flyway getFlywayBean(ApplicationContext applicationContext, String name) { Precondition.param(applicationContext, "applicationContext").notNull(); try { String[] names = applicationContext.getBeanNamesForType(Flyway.class); if (names.length == 0) { throw new FlywayTestExecutionException("Flyway bean definition not found in applicationContext."); } if (names.length == 1) { return applicationContext.getBean(Flyway.class); } if (name == null || name.isEmpty()) { throw new FlywayTestExecutionException( "Name not specified while multiple Flyway beans found in applicationContext: " + Arrays.asList(names)); } return applicationContext.getBean(name, Flyway.class); } catch (Exception ex) { if (ex instanceof FlywayTestExecutionException) { throw (FlywayTestExecutionException) ex; } else { throw new FlywayTestExecutionException(ex); } } } }