/* * Copyright 2015 herd contributors * * 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 org.finra.herd.core; import static org.junit.Assert.assertEquals; import java.io.File; import java.io.IOException; import java.io.RandomAccessFile; import java.io.StringWriter; import java.nio.file.Path; import java.nio.file.Paths; import java.util.Collection; import java.util.Date; import java.util.HashSet; import java.util.List; import java.util.Random; import java.util.Set; import org.apache.commons.lang3.StringUtils; import org.junit.Assert; import org.junit.Before; import org.junit.runner.RunWith; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.ApplicationContext; import org.springframework.core.env.ConfigurableEnvironment; import org.springframework.core.env.Environment; import org.springframework.core.env.MutablePropertySources; import org.springframework.core.env.StandardEnvironment; import org.springframework.core.io.ResourceLoader; import org.springframework.test.context.ContextConfiguration; import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; import org.springframework.test.context.transaction.TransactionConfiguration; import org.finra.herd.core.config.CoreTestSpringModuleConfig; import org.finra.herd.core.helper.ConfigurationHelper; import org.finra.herd.core.helper.LogLevel; import org.finra.herd.core.helper.LoggingHelper; /** * Base class for all core and extending tests. We need to use a customized "loader" that stores the application context in an application context holder so * static bean creation methods don't fail. This is similar to what WarInitializer.java does for the WAR, but rather for the JUnits. */ @RunWith(SpringJUnit4ClassRunner.class) @ContextConfiguration(classes = CoreTestSpringModuleConfig.class, loader = ContextHolderContextLoader.class) @TransactionConfiguration public abstract class AbstractCoreTest { public static final String BLANK_TEXT = " \t\t "; public static final long FILE_SIZE_0_BYTE = 0L; public static final long FILE_SIZE_1_KB = 1024L; public static final long FILE_SIZE_2_KB = 2048L; public static final String INVALID_BOOLEAN_VALUE = "INVALID_BOOLEAN_VALUE"; public static final String INVALID_INTEGER_VALUE = "INVALID_INTEGER_VALUE"; public static final String RANDOM_SUFFIX = getRandomSuffix(); public static final String RANDOM_SUFFIX_2 = getRandomSuffix(); public static final long ROW_COUNT_1000 = 1000L; @Autowired protected ApplicationContext appContext; @Autowired protected ConfigurationHelper configurationHelper; @Autowired protected LoggingHelper loggingHelper; // The Spring environment. @Autowired protected Environment environment; @Autowired protected ResourceLoader resourceLoader; /** * Returns a random suffix. */ public static String getRandomSuffix() { return String.format("%.5f", Math.random()).substring(2, 7); } /** * Returns a random date. */ public static Date getRandomDate() { Random rnd = new Random(); return new Date(Math.abs(System.currentTimeMillis() - rnd.nextLong())); } @Before public void setup() throws Exception { // Remove the system environment property source so system environment variables don't affect unit tests. getMutablePropertySources().remove(StandardEnvironment.SYSTEM_ENVIRONMENT_PROPERTY_SOURCE_NAME); } /** * Same as {@link Assert#assertEquals(String, Object, Object)} but null and empty strings are considered equal. This method simply does not call assertion * if both expected and actual are null or empty. * * @param message - The message to display on assertion error * @param expected - The expected value * @param actual - The actual value * * @see StringUtils#isEmpty(CharSequence) */ public static void assertEqualsIgnoreNullOrEmpty(String message, String expected, String actual) { if (!StringUtils.isEmpty(expected) || !StringUtils.isEmpty(actual)) { assertEquals(message, expected, actual); } } /** * Asserts that the given expected collection is equal to the actual collection ignoring the order of the elements. Two collections are equal as defined by * {@link Set#equals(Object)}. This assertion is {@code null} safe. * * @param message - message as defined by {@link Assert#assertEquals(String, Object, Object)} * @param expected - expected collection * @param actual - actual collection */ public static void assertEqualsIgnoreOrder(String message, Collection<?> expected, Collection<?> actual) { if (expected != null && actual != null) { Set<?> expectedSet = new HashSet<Object>(expected); Set<?> actualSet = new HashSet<Object>(actual); assertEquals(message, expectedSet, actualSet); } else if (expected != actual) { assertEquals(message, expected, actual); } } /** * Creates a file of the specified size relative to the base directory. * * @param baseDirectory the local parent directory path, relative to which we want our file to be created * @param file the file path (including file name) relative to the base directory for the file to be created * @param size the file size in bytes * * @return the created file */ public static File createLocalFile(String baseDirectory, String file, long size) throws IOException { Path filePath = Paths.get(baseDirectory, file); // We don't check the "mkdirs" response because the directory may already exist which would return false. // But we want to create sub-directories if they don't yet exist which is why we're calling "mkdirs" in the first place. // If an actual directory couldn't be created, then the new file below will throw an exception anyway. filePath.toFile().getParentFile().mkdirs(); RandomAccessFile randomAccessFile = new RandomAccessFile(filePath.toString(), "rw"); randomAccessFile.setLength(size); randomAccessFile.close(); return filePath.toFile(); } /** * Gets the mutable property sources object from the environment. * * @return the mutable property sources. * @throws Exception if the mutable property sources couldn't be obtained. */ protected MutablePropertySources getMutablePropertySources() throws Exception { // Ensure we have a configurable environment so we can remove the property source. if (!(environment instanceof ConfigurableEnvironment)) { throw new Exception("The environment is not an instance of ConfigurableEnvironment and needs to be for this test to work."); } // Return the property sources from the configurable environment. ConfigurableEnvironment configurableEnvironment = (ConfigurableEnvironment) environment; return configurableEnvironment.getPropertySources(); } /** * Executes a command without logging. The logging will be temporarily turned off during the execution of the command and then restored once the command has * finished executing. * * @param loggingClass the logging class to turn off. If null is specified, the command will be executed with no logging changes * @param command the command to execute * * @throws Exception if any errors were encountered. */ protected void executeWithoutLogging(Class<?> loggingClass, Command command) throws Exception { loggingHelper.executeWithoutLogging(loggingClass, command); } /** * Executes a command without logging. The logging will be temporarily turned off during the execution of the command and then restored once the command has * finished executing. * * @param loggingClasses the list of logging classes to turn off * @param command the command to execute * * @throws Exception if any errors were encountered */ protected void executeWithoutLogging(List<Class<?>> loggingClasses, Command command) throws Exception { loggingHelper.executeWithoutLogging(loggingClasses, command); } /** * Adds a test appender. * * @param appenderName the appender name to add. * * @return the string writer associated with the writer appender. */ protected StringWriter addLoggingWriterAppender(String appenderName) { return loggingHelper.addLoggingWriterAppender(appenderName); } /** * Removes a logging appender. * * @param appenderName the appender name. */ protected void removeLoggingAppender(String appenderName) { loggingHelper.removeLoggingAppender(appenderName); } /** * Gets the log level for the specified logger. * * @param clazz the class for the logger. */ protected LogLevel getLogLevel(Class clazz) { return loggingHelper.getLogLevel(clazz); } /** * Gets the log level for the specified logger. * * @param loggerName the logger name to get the level for. */ protected LogLevel getLogLevel(String loggerName) { return loggingHelper.getLogLevel(loggerName); } /** * Sets the log level. * * @param clazz the class for the logger. * @param logLevel the log level to set. */ protected void setLogLevel(Class clazz, LogLevel logLevel) { loggingHelper.setLogLevel(clazz, logLevel); } /** * Sets the log level. * * @param loggerName the logger name (e.g. Myclass.class.getName()). * @param logLevel the log level to set. */ protected void setLogLevel(String loggerName, LogLevel logLevel) { loggingHelper.setLogLevel(loggerName, logLevel); } }