software.coolstuff.springframework.owncloud.service.impl.local.OwncloudLocalFileTestExecutionListener.java Source code

Java tutorial

Introduction

Here is the source code for software.coolstuff.springframework.owncloud.service.impl.local.OwncloudLocalFileTestExecutionListener.java

Source

/*-
 * #%L
 * owncloud-spring-boot-starter
 * %%
 * Copyright (C) 2016 - 2017 by the original Authors
 * %%
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as
 * published by the Free Software Foundation, either version 3 of the
 * License, or (at your option) any later version.
 * 
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 * 
 * You should have received a copy of the GNU General Public
 * License along with this program.  If not, see
 * <http://www.gnu.org/licenses/gpl-3.0.html>.
 * #L%
 */
package software.coolstuff.springframework.owncloud.service.impl.local;

import lombok.Data;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.io.IOUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.Validate;
import org.junit.Ignore;
import org.junit.Test;
import org.springframework.beans.factory.DisposableBean;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.context.ApplicationContext;
import org.springframework.core.annotation.AnnotationUtils;
import org.springframework.core.io.Resource;
import org.springframework.core.io.ResourceLoader;
import org.springframework.core.io.UrlResource;
import org.springframework.test.context.ActiveProfiles;
import org.springframework.test.context.TestContext;
import org.springframework.test.context.support.AbstractTestExecutionListener;
import org.springframework.util.ResourceUtils;
import org.xmlunit.builder.DiffBuilder;
import org.xmlunit.builder.Input;
import org.xmlunit.diff.DefaultNodeMatcher;
import org.xmlunit.diff.Diff;
import org.xmlunit.diff.ElementSelectors;
import org.yaml.snakeyaml.Yaml;
import software.coolstuff.springframework.owncloud.config.CompareResourceAfter;
import software.coolstuff.springframework.owncloud.service.impl.OwncloudProperties;
import software.coolstuff.springframework.owncloud.service.impl.local.file.OwncloudLocalFileTest;

import java.io.*;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.Map;
import java.util.Map.Entry;

import static org.assertj.core.api.Assertions.assertThat;

/**
 * This Test-Execution Listener prepares the Tests for Resources prefixed with <code>file:</code> because these Resources will also be written on Disk just before the Bean
 * <code>OwncloudResourceService</code> will be destroyed.
 *
 * @author mufasa1976
 */
@Slf4j
@Ignore
public class OwncloudLocalFileTestExecutionListener extends AbstractTestExecutionListener {

    private final static String PROPERTY_FILE_PREFIX = "classpath:config/application-";
    private final static String PROPERTY_FILE_SUFFIX = ".yml";

    private final static String ORIGINAL_RESOURCE = "classpath:owncloud.xml";

    @Override
    public void beforeTestClass(TestContext testContext) throws Exception {
        if (isTestClassAssignableFromOwncloudLocalFileTest(testContext)) {
            Class<?> testClass = testContext.getTestClass();
            ActiveProfiles activeProfiles = AnnotationUtils.findAnnotation(testClass, ActiveProfiles.class);
            OwncloudProperties owncloudProperties = loadProperties(activeProfiles.value());
            if (StringUtils.startsWith(owncloudProperties.getLocation(), "file:")) {
                copyResource(owncloudProperties);
            }
        }
    }

    private boolean isTestClassAssignableFromOwncloudLocalFileTest(TestContext testContext) {
        Class<?> testClass = testContext.getTestClass();
        return OwncloudLocalFileTest.class.isAssignableFrom(testClass);
    }

    @SuppressWarnings("unchecked")
    private OwncloudProperties loadProperties(String[] activeProfiles) throws IOException {
        Yaml yaml = new Yaml();
        for (String activeProfile : activeProfiles) {
            String propertyFilename = PROPERTY_FILE_PREFIX + activeProfile + PROPERTY_FILE_SUFFIX;
            log.debug("Try to parse File {} with SnakeYaml", propertyFilename);
            File propertyFile = ResourceUtils.getFile(propertyFilename);
            try (InputStream input = new FileInputStream(propertyFile)) {
                Map<String, Object> properties = ((Map<String, Map<String, Object>>) yaml.load(input))
                        .get("owncloud");
                OwncloudProperties owncloudProperties = new OwncloudLocalProperties();
                for (Entry<String, Object> property : properties.entrySet()) {
                    switch (property.getKey()) {
                    case "location":
                        owncloudProperties.setLocation((String) property.getValue());
                        break;
                    case "user-service.enable-modifications":
                    case "userService.enable-modifications":
                    case "user-service.enableModifications":
                    case "userService.enableModifications":
                        if (owncloudProperties.getUserService() == null) {
                            owncloudProperties.setUserService(new OwncloudProperties.UserService());
                        }
                        owncloudProperties.getUserService().setEnableModifications((Boolean) property.getValue());
                        break;
                    }
                }
                Validate.notNull(owncloudProperties.getLocation());
                return owncloudProperties;
            }
        }
        return null;
    }

    private void copyResource(OwncloudProperties owncloudProperties) throws IOException {
        File original = ResourceUtils.getFile(ORIGINAL_RESOURCE);
        File target = ResourceUtils.getFile(owncloudProperties.getLocation());
        target.deleteOnExit();
        try (InputStream input = new BufferedInputStream(new FileInputStream(original));
                OutputStream output = new BufferedOutputStream(new FileOutputStream(target))) {
            IOUtils.copy(input, output);
        }
    }

    @Override
    public void beforeTestMethod(TestContext testContext) throws Exception {
        if (isTestClassAssignableFromOwncloudLocalFileTest(testContext)) {
            ApplicationContext applicationContext = testContext.getApplicationContext();

            ResourceLoader resourceLoader = applicationContext;
            OwncloudProperties properties = applicationContext.getBean(OwncloudProperties.class);
            copyClasspathResourceToFile(resourceLoader, properties);

            InitializingBean localDataService = applicationContext.getBean(OwncloudLocalUserDataServiceImpl.class);
            localDataService.afterPropertiesSet();
        }
    }

    private void copyClasspathResourceToFile(ResourceLoader resourceLoader, OwncloudProperties properties)
            throws IOException, FileNotFoundException {
        Resource target = resourceLoader.getResource(properties.getLocation());
        if (!(target instanceof UrlResource)) {
            throw new IllegalStateException(
                    String.format("TestClass %s implements %s but the Resource-Location %s is not of Type %s",
                            this.getClass().getName(), OwncloudLocalFileTest.class.getName(),
                            properties.getLocation(), UrlResource.class.getName()));
        }

        try (InputStream is = new BufferedInputStream(getSourceResource(resourceLoader).getInputStream());
                OutputStream os = new BufferedOutputStream(new FileOutputStream(target.getFile()))) {
            log.debug("Copy Content of Classpath-Resource {} to File {}", ORIGINAL_RESOURCE,
                    properties.getLocation());
            IOUtils.copy(is, os);
        }
    }

    public static Resource getSourceResource(ResourceLoader resourceLoader) {
        Resource resource = resourceLoader.getResource(ORIGINAL_RESOURCE);
        if (resource == null) {
            throw new IllegalStateException("Source Resource " + ORIGINAL_RESOURCE + " is not available");
        }
        return resource;
    }

    @Override
    public void afterTestMethod(TestContext testContext) throws Exception {
        if (isTestClassAssignableFromOwncloudLocalFileTest(testContext)) {
            ApplicationContext applicationContext = testContext.getApplicationContext();

            Class<?> testClass = testContext.getTestClass();
            Method testMethod = testContext.getTestMethod();

            DisposableBean localDataService = applicationContext.getBean(OwncloudLocalUserDataServiceImpl.class);
            localDataService.destroy();

            ResourceLoader resourceLoader = applicationContext;
            OwncloudProperties properties = applicationContext.getBean(OwncloudProperties.class);
            Resource target = resourceLoader.getResource(properties.getLocation());

            boolean hasSpecificResourceTest = false;
            for (Method method : testContext.getTestClass().getMethods()) {
                // is this Method annotated by @CompareResourceAfter
                CompareResourceAfter compareResourceAfter = AnnotationUtils.findAnnotation(method,
                        CompareResourceAfter.class);
                if (compareResourceAfter == null
                        || !StringUtils.equals(compareResourceAfter.value(), testMethod.getName())) {
                    continue;
                }

                // a Method annotated by @Test cannot also be annotated by
                // @CompareResourceAfter
                if (AnnotationUtils.findAnnotation(method, Test.class) != null) {
                    log.warn("Method {} of Class {} cannot be annotated by {} and {}", method.getName(),
                            testClass.getName(), CompareResourceAfter.class, Test.class);
                    continue;
                }

                // the @CompareResourceAfter annotated Method must have exactly 2
                // Parameters of Type org.springframework.core.io.Resource
                if (method.getParameterCount() != 1) {
                    log.warn("Method {} of Class {} is annotated by {} but has {} Parameters instead of 1",
                            method.getName(), testClass.getName(), CompareResourceAfter.class.getName(),
                            method.getParameterCount());
                    continue;
                }
                boolean correctParameterTypes = true;
                for (Class<?> parameterClass : method.getParameterTypes()) {
                    correctParameterTypes = correctParameterTypes
                            && Resource.class.isAssignableFrom(parameterClass);
                }
                if (!correctParameterTypes) {
                    log.warn("Method {} of Class {} (annotated by {}) must have 1 Parameter of Type {}",
                            method.getName(), testClass.getName(), CompareResourceAfter.class.getName(),
                            Resource.class.getName());
                    continue;
                }

                log.debug("Call the Resource Comparsion Method {} on Class {}", method.getName(),
                        testClass.getName());
                hasSpecificResourceTest = true;
                try {
                    method.invoke(testContext.getTestInstance(), target);
                } catch (InvocationTargetException e) {
                    if (e.getCause() instanceof Exception) {
                        throw (Exception) e.getCause();
                    }
                    throw (Error) e.getCause();
                }
            }

            if (!hasSpecificResourceTest && ((OwncloudLocalFileTest) testContext.getTestInstance())
                    .isCheckAllResourcesAgainstOriginal()) {
                compareResourcesWithOriginalSource(resourceLoader, target);
            }
        }
    }

    public static void compareResourcesWithOriginalSource(ResourceLoader resourceLoader, Resource target)
            throws Exception {
        compareResources(getSourceResource(resourceLoader), target);
    }

    public static void compareResources(Resource source, Resource target) throws Exception {
        try (InputStream inputSource = new BufferedInputStream(source.getInputStream());
                InputStream inputTarget = new BufferedInputStream(target.getInputStream())) {
            Diff diff = DiffBuilder.compare(Input.fromStream(inputSource)).withTest(Input.fromStream(inputTarget))
                    .checkForSimilar().ignoreWhitespace()
                    .withNodeMatcher(new DefaultNodeMatcher(ElementSelectors.byNameAndText)).build();
            assertThat(diff.hasDifferences()).as(diff.toString()).isFalse();
        }
    }

    @Data
    private static class YamlOwncloudProperties {

        private OwncloudProperties owncloud;
    }
}