All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.finos.legend.sdlc.test.junit.JUnitTestGenerationMojo Maven / Gradle / Ivy

There is a newer version: 0.177.6
Show newest version
// Copyright 2023 Goldman Sachs
//
// 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.finos.legend.sdlc.test.junit;

import org.apache.maven.plugin.AbstractMojo;
import org.apache.maven.plugin.MojoExecutionException;
import org.apache.maven.plugins.annotations.LifecyclePhase;
import org.apache.maven.plugins.annotations.Mojo;
import org.apache.maven.plugins.annotations.Parameter;
import org.apache.maven.plugins.annotations.ResolutionScope;
import org.apache.maven.project.MavenProject;
import org.eclipse.collections.api.factory.Lists;
import org.eclipse.collections.api.list.ListIterable;
import org.eclipse.collections.impl.utility.Iterate;
import org.finos.legend.sdlc.domain.model.entity.Entity;
import org.finos.legend.sdlc.serialization.EntityLoader;
import org.finos.legend.sdlc.tools.entity.EntityPaths;

import java.io.File;
import java.net.URL;
import java.net.URLClassLoader;
import java.nio.file.Path;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;
import java.util.Set;
import java.util.function.Predicate;
import java.util.stream.Stream;
import javax.lang.model.SourceVersion;

@Mojo(name = "generate-junit-tests", defaultPhase = LifecyclePhase.GENERATE_TEST_SOURCES, threadSafe = true, requiresDependencyResolution = ResolutionScope.COMPILE)
public class JUnitTestGenerationMojo extends AbstractMojo
{
    @Parameter
    private EntityFilterSpecification inclusions;

    @Parameter
    private EntityFilterSpecification exclusions;

    @Parameter
    private String packagePrefix;

    @Parameter(defaultValue = "${project.build.directory}/generated-test-sources")
    private File outputDirectory;

    @Parameter(defaultValue = "true")
    private boolean addOutputDirectoryAsTestSource;

    @Parameter(defaultValue = "${project.build.outputDirectory}", readonly = true)
    private File entitiesDirectory;

    @Parameter(defaultValue = "${project}", readonly = true)
    private MavenProject project;

    @Parameter(defaultValue = "false")
    private boolean runDependencyTests;

    @Override
    public void execute() throws MojoExecutionException
    {
        getLog().info("entities directory: " + this.entitiesDirectory);
        getLog().info("output directory: " + this.outputDirectory);
        getLog().info("add output directory as test source: " + this.addOutputDirectoryAsTestSource);
        if (this.inclusions != null)
        {
            getLog().info("include entity paths: " + this.inclusions.paths);
            getLog().info("include entity packages: " + this.inclusions.packages);
        }
        if (this.exclusions != null)
        {
            getLog().info("exclude entity paths: " + this.exclusions.paths);
            getLog().info("exclude entity packages: " + this.exclusions.packages);
        }
        getLog().info("package prefix: " + ((this.packagePrefix == null) ? null : ('"' + this.packagePrefix + '"')));

        if ((this.packagePrefix != null) && !SourceVersion.isName(this.packagePrefix))
        {
            throw new MojoExecutionException("Invalid package prefix: " + this.packagePrefix);
        }
        if (this.runDependencyTests)
        {
            getLog().info("running dependency tests flag set");
        }

        long start = System.nanoTime();
        try
        {
            JUnitTestGenerator generator = JUnitTestGenerator.newGenerator(this.packagePrefix);
            try (EntityLoader entityLoader = this.runDependencyTests ? EntityLoader.newEntityLoader(this.getClassLoader(this.project)) : EntityLoader.newEntityLoader(this.entitiesDirectory))
            {
                Stream stream = entityLoader.getAllEntities();
                Predicate includeFilter = resolveEntityFilter(this.inclusions);
                if (includeFilter != null)
                {
                    stream = stream.filter(includeFilter);
                }
                Predicate excludeFilter = resolveEntityFilter(this.exclusions);
                if (excludeFilter != null)
                {
                    stream = stream.filter(excludeFilter.negate());
                }
                List paths = generator.writeTestClasses(this.outputDirectory.toPath(), stream);
                getLog().info("Generated " + paths.size() + " test files");
            }

            if (this.addOutputDirectoryAsTestSource)
            {
                String newTestSourceDirectory = this.outputDirectory.getAbsolutePath();
                this.project.addTestCompileSourceRoot(newTestSourceDirectory);
                getLog().info("Added test source directory: " + newTestSourceDirectory);
            }

            long end = System.nanoTime();
            getLog().info(String.format("Finished generating tests (%.9fs)", (end - start) / 1_000_000_000.0));
        }
        catch (Exception e)
        {
            long end = System.nanoTime();
            getLog().error(String.format("Error generating tess (%.9fs)", (end - start) / 1_000_000_000.0));
            throw new MojoExecutionException("Error generating tests", e);
        }
    }

    // requires requiresDependencyResolution set to compile for resolution of project to be complete
    // loads all classes from maven project see: https://maven.apache.org/guides/mini/guide-maven-classloading.html#plugin-classloaders and https://stackoverflow.com/questions/49737706/access-project-classes-from-a-maven-plugin
    private ClassLoader getClassLoader(MavenProject project) throws MojoExecutionException
    {
        try
        {
            List classpathElements = project.getCompileClasspathElements();
            classpathElements.add(project.getBuild().getOutputDirectory());
            classpathElements.add(project.getBuild().getTestOutputDirectory());
            URL[] urls = new URL[classpathElements.size()];
            for (int i = 0; i < classpathElements.size(); ++i)
            {
                urls[i] = new File(classpathElements.get(i)).toURL();
            }
            return new URLClassLoader(urls, Thread.currentThread().getContextClassLoader());
        }
        catch (Exception e)
        {
            getLog().debug("Couldn't get the classloader.");
            throw new MojoExecutionException("Error getting class loader to run dependency tests", e);
        }
    }

    private static Predicate resolveEntityFilter(EntityFilterSpecification spec)
    {
        if ((spec == null) || ((spec.paths == null) && (spec.packages == null)))
        {
            // No filter specified
            return null;
        }
        if ((spec.packages != null) && (spec.packages.contains("") || spec.packages.contains(EntityPaths.PACKAGE_SEPARATOR)))
        {
            // The packages spec includes the root package, so all entities match
            return e -> true;
        }

        Set pathSet = (spec.paths == null) ? Collections.emptySet() : spec.paths;
        ListIterable resolvedPackages = (spec.packages == null) ?
                Lists.fixedSize.empty() :
                Iterate.collect(spec.packages, p -> p.endsWith(EntityPaths.PACKAGE_SEPARATOR) ? p : (p + EntityPaths.PACKAGE_SEPARATOR), Lists.mutable.ofInitialCapacity(spec.packages.size()))
                        .sortThis(Comparator.comparingInt(String::length).thenComparing(Comparator.naturalOrder()));
        return resolvedPackages.isEmpty() ?
                (pathSet.isEmpty() ?
                        e -> false :
                        e -> pathSet.contains(e.getPath())) :
                (pathSet.isEmpty() ?
                        e -> inSomePackage(resolvedPackages, e.getPath()) :
                        e -> pathSet.contains(e.getPath()) || inSomePackage(resolvedPackages, e.getPath()));
    }

    private static boolean inSomePackage(ListIterable packages, String path)
    {
        int lastSeparator = path.lastIndexOf(EntityPaths.PACKAGE_SEPARATOR);
        int pkgLen = (lastSeparator == -1) ? 0 : lastSeparator + EntityPaths.PACKAGE_SEPARATOR.length();
        for (String pkg : packages)
        {
            if (path.startsWith(pkg))
            {
                return true;
            }
            if (pkg.length() > pkgLen)
            {
                return false;
            }
        }
        return false;
    }

    public static class EntityFilterSpecification
    {
        public Set paths;
        public Set packages;
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy