Package org.easetech.easytest.loader

Source Code of org.easetech.easytest.loader.DataLoaderUtil

package org.easetech.easytest.loader;

import java.util.ArrayList;

import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import org.easetech.easytest.annotation.DataLoader;
import org.easetech.easytest.internal.SystemProperties;
import org.easetech.easytest.io.EmptyResource;
import org.easetech.easytest.io.Resource;
import org.easetech.easytest.io.ResourceLoader;
import org.easetech.easytest.io.ResourceLoaderStrategy;
import org.easetech.easytest.runner.DataDrivenTestRunner;
import org.easetech.easytest.util.DataContext;
import org.easetech.easytest.util.TestInfo;
import org.junit.Assert;
import org.junit.runners.model.FrameworkMethod;
import org.junit.runners.model.TestClass;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/**
* A Utility class for loading test data. This class has methods to identify information about loading the data
*
* @author Anuj Kumar
*
*/
public final class DataLoaderUtil {

    /**
     * An instance of logger associated with the test framework.
     */
    protected static final Logger LOG = LoggerFactory.getLogger(DataLoaderUtil.class);

    /** Pattern for runtime expression */
    private static final Pattern RUNTIME_EXPR_PATTERN = Pattern.compile("\\$\\{.*\\}");


    /**
     * Method that determines the right Loader and the right Data Files for the "write output data" functionality
     * supported by the EasyTest Framework.
     *
     * @param testData an instance of {@link DataLoader} that helps in identifying the right {@link Loader} to write the
     *            data back to the file.
     * @param testClass the class that the {@link TestInfo} object will be associated with
     *
     * @return {@link TestInfo} an instance of {@link TestInfo} containing information about the currently executing
     *         test.
     */
    public static TestInfo determineLoader(DataLoader testData, TestClass testClass) {
        TestInfo result = new TestInfo(testClass);
        // String[] dataFiles = testData.filePaths();
        String[] dataFiles = determineFilePaths(testData);
        LoaderType loaderType = determineLoaderType(testData, dataFiles);
        // Loader
        Loader dataLoader = null;
        if (LoaderType.CUSTOM.equals(loaderType) || dataFiles.length == 0) {
            dataLoader = getCustomLoaderInstance(testData);
        } else {
            // user has specified data files and the data fileType is also
            // not custom.
            if (loaderType != null) {
                dataLoader = LoaderFactory.getLoader(loaderType);
            }

        }
        result.setDataLoader(dataLoader);
        result.setFilePaths(dataFiles);
        result.setWriteData(testData.writeData());
        return result;
    }

    /**
     * Determine the Path of the test data files
     *
     * @param dataLoader the {@link DataLoader} annotation
     * @return an array of resolved file names
     */
    private static String[] determineFilePaths(DataLoader dataLoader) {
        String[] filePaths = dataLoader.filePaths();
        String[] result = new String[filePaths.length];
        result = handleSystemProperty();
        if (result == null) {
            //filePaths cannot be null as the default is an empty array
            if(filePaths.length == 0) {
                LOG.info("Neither System Property 'testDataFiles' nor the attribute 'filePaths' is specified.");
            } else {
                result = new String[filePaths.length];
                for (int i = 0; i < filePaths.length; i++) {
                    if (isVariablePath(filePaths[i])) {
                        result[i] = getTestDataFileExpression(filePaths[i]);
                    } else {
                        result[i] = filePaths[i];
                    }
                }
            }
           
        }
        return result;

    }

    /**
     * Get the test data file expression from the variable path
     *
     * @param pathExpression
     * @return
     */
    private static String getTestDataFileExpression(String pathExpression) {
        String variable = pathExpression.substring(2, pathExpression.lastIndexOf("}"));
        return System.getProperty(variable) == null ? variable : System.getProperty(variable);
    }

    private static String[] handleSystemProperty() {
        String[] result = null;
        String datafiles = System.getProperty(SystemProperties.TEST_DATA_FILES.getValue());
        if (datafiles != null && datafiles.length() > 0) {
            result = datafiles.split(",");
        }
        return result;
    }

    private static Boolean isVariablePath(String path) {
        if (path == null || "".equals(path)) {
            return false;
        }
        Matcher exprMatcher = RUNTIME_EXPR_PATTERN.matcher(path);
        if (exprMatcher.matches()) {
            return true;
        }
        return false;
    }

    /**
     * Determine the Loader Type to load the test data
     *
     * @param testData the {@link DataLoader} annotation instance
     * @param dataFiles the list of test data Files
     * @return {@link LoaderType} to use
     */
    private static final LoaderType determineLoaderType(DataLoader testData, String[] dataFiles) {
        LoaderType loaderType = testData.loaderType();
        if (LoaderType.NONE.equals(loaderType)) {
            // Identify the file extension
            if (dataFiles == null || dataFiles.length == 0) {
                // assume it is custom loader and return
                return LoaderType.CUSTOM;
            }
            // Since we currently support only a single file type in the FilePaths attribute,
            // we can safely pick one of the file, determine its extension and assume that other files have the same
            // extension
            return resolveFileExtension(dataFiles[0]);

        }
        return loaderType;

    }

    /**
     * Return the laoder type based on file extension
     *
     * @param filePath the file path
     * @return {@link LoaderType} based on file extension
     */
    private static LoaderType resolveFileExtension(String filePath) {
        if (filePath == null || filePath == "") {
            return LoaderType.CUSTOM;
        }
        if (filePath.endsWith("csv")) {
            return LoaderType.CSV;
        } else if (filePath.endsWith("xls")) {
            return LoaderType.EXCEL;
        } else if (filePath.endsWith("xml")) {
            return LoaderType.XML;
        }
        return LoaderType.CUSTOM;

    }

    private static Loader getCustomLoaderInstance(DataLoader testData) {
        Loader dataLoader = null;
        LOG.info("User specified to use custom Loader. Trying to get the custom loader.");
        if (testData.loader() == null) {
            Assert.fail("Specified the LoaderType as CUSTOM but did not specify loader"
                + " attribute. A loaderType of CUSTOM requires the loader " + "attribute specifying "
                + "the Custom Loader Class which implements Loader interface.");
        } else {
            try {
                Class<? extends Loader> loaderClass = testData.loader();
                dataLoader = loaderClass.newInstance();
            } catch (Exception e) {
                throw new RuntimeException("Exception occured while trying to instantiate a class of type :"
                    + testData.loader(), e);
            }
        }
        return dataLoader;

    }

    /**
     * Load the Data for the given class or method. This method will try to find {@link DataLoader} on either the class
     * level or the method level. In case the annotation is found, this method will load the data using the specified
     * loader class and then save it in the DataContext for further use by the system. We also create another copy of
     * the input test data that we store in the {@link DataDrivenTestRunner#writableData} field. This is done in order
     * to facilitate the writing of the data that might be returned by the test method.
     *
     * @param testClass the class object, if any.
     * @param method current executing method, if any.
     * @param currentTestClass the currently executing test class. this is used to append in front of the method name to
     *            get unique method names as there could be methods in different classes with the same name and thus we
     *            want to avoid conflicts.
     * @param writableData The writable data that is used internally for reporting purposes
     */

    public static void loadData(Class<?> testClass, FrameworkMethod method, TestClass currentTestClass,
        Map<String, List<Map<String, Object>>> writableData) {
        if (testClass == null && method == null) {
            Assert
                .fail("The framework should provide either the testClass parameter or the method parameter in order to load the test data.");
        }
        // We give priority to Class Loading and then to method loading
        DataLoader testData = null;
        if (testClass != null) {
            testData = testClass.getAnnotation(DataLoader.class);
        } else {
            testData = method.getAnnotation(DataLoader.class);
        }
        if (testData != null) {
            TestInfo testInfo = DataLoaderUtil.determineLoader(testData, currentTestClass);
            Loader dataLoader = testInfo.getDataLoader();
            if (testInfo.getDataLoader() == null) {
                Assert.fail("The framework currently does not support the specified Loader type. "
                    + "You can provide the custom Loader by choosing LoaderType.CUSTOM in TestData "
                    + "annotation and providing your custom loader using DataLoader annotation.");
            } else {
                if (testInfo.getFilePaths() == null || testInfo.getFilePaths().length == 0) {
                    // implies that there exists a CUSTOM loader that loads the data using Java classes
                    Map<String, List<Map<String, Object>>> data = dataLoader.loadData(new EmptyResource());
                    // We also maintain the copy of the actual data for our write functionality.
                    fillWritableData(writableData , data , testData.appendData());
                    DataContext.setData(DataConverter.appendClassName(data, currentTestClass.getJavaClass()), testData.appendData());
                    DataContext.setConvertedData(DataConverter.convert(data, currentTestClass.getJavaClass()) , testData.appendData());
                } else {
                    ResourceLoader resourceLoader = new ResourceLoaderStrategy(currentTestClass.getJavaClass());
                    for (String filePath : testInfo.getFilePaths()) {
                        Resource resource = resourceLoader.getResource(filePath);
                        try {
                            if (resource.exists()) {
                                Map<String, List<Map<String, Object>>> data = dataLoader.loadData(resource);
                                // We also maintain the copy of the actual data for our write functionality.
                                fillWritableData(writableData , data , testData.appendData());
                                DataContext
                                    .setData(DataConverter.appendClassName(data, currentTestClass.getJavaClass()), testData.appendData());
                                DataContext.setConvertedData(DataConverter.convert(data,
                                    currentTestClass.getJavaClass()), testData.appendData());
                            } else {
                                LOG.warn(
                                    "Resource {} does not exists in the specified path. If it is a classpath resource, use 'classpath:' "
                                        + "before the path name, else check the path.", resource);
                            }
                        } catch (Exception e) {
                            LOG.error("Exception occured while trying to load the data for resource {}", resource, e);
                            throw new RuntimeException(e);
                        }
                    }
                }
            }
        }
    }
   
    private static void fillWritableData(Map<String, List<Map<String, Object>>> writableData , Map<String, List<Map<String, Object>>> availableData, boolean appendData) {
        if(!appendData) {
            writableData.putAll(availableData);
        } else {
            for(String key : availableData.keySet()) {
                List<Map<String,Object>> newData = new ArrayList<Map<String,Object>>();
                if(writableData.get(key) != null) {
                    newData.addAll(writableData.get(key));
                }
                newData.addAll(availableData.get(key));
               
                writableData.put(key, newData);
            }
        }
    }

    /**
     * Check if the data for the given method is loaded or not.
     *
     * @param methodName the name of the method whose data needs to be checked.
     * @return true if there exists data for the given method, else false.
     */
    public static boolean isMethodDataLoaded(String methodName) {

        boolean result = false;
        if (DataContext.getData() == null || DataContext.getData().keySet() == null
            || DataContext.getData().keySet().isEmpty()) {
            result = false;
        } else {
            Iterator<String> keyIterator = DataContext.getData().keySet().iterator();
            while (keyIterator.hasNext()) {
                result = methodName.equals(keyIterator.next()) ? true : false;
                if (result) {
                    break;
                }
            }
        }

        return result;
    }

}
TOP

Related Classes of org.easetech.easytest.loader.DataLoaderUtil

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.