Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

SDK-358 - Add integration test framework for helper classes #308

Closed
wants to merge 7 commits into from
Closed
Show file tree
Hide file tree
Changes from 5 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 0 additions & 12 deletions integration-tests/.gitignore

This file was deleted.

50 changes: 0 additions & 50 deletions integration-tests/pom.xml

This file was deleted.

34 changes: 34 additions & 0 deletions maven-plugin/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -159,6 +159,12 @@
<artifactId>dom4j</artifactId>
</dependency>

<!-- lombok -->
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
</dependency>

<!--zip-->
<dependency>
<groupId>net.lingala.zip4j</groupId>
Expand Down Expand Up @@ -226,7 +232,35 @@
</excludes>
</resource>
</resources>
<testResources>
<testResource>
<directory>src/test/resources</directory>
<filtering>true</filtering>
<includes>
<include>integration-test/invokeIT/pom.xml</include>
</includes>
</testResource>
<testResource>
<directory>src/test/resources</directory>
<filtering>false</filtering>
<excludes>
<exclude>integration-test/invokeIT/pom.xml</exclude>
</excludes>
</testResource>
</testResources>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-jar-plugin</artifactId>
<version>3.4.2</version>
<executions>
<execution>
<goals>
<goal>test-jar</goal>
</goals>
</execution>
</executions>
</plugin>
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This adds all of the test classes to their own library, so this library can be added to the classpath of the pom used by the Maven verifier during the integration tests, which runs outside of this project

<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-plugin-plugin</artifactId>
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
package org.openmrs.maven.plugins;

import lombok.Getter;
import org.apache.commons.lang.StringUtils;
import org.apache.maven.artifact.factory.ArtifactFactory;
import org.apache.maven.artifact.metadata.ArtifactMetadataSource;
Expand All @@ -12,14 +13,15 @@
import org.apache.maven.plugins.annotations.Parameter;
import org.apache.maven.project.MavenProject;
import org.apache.maven.settings.Settings;
import org.openmrs.maven.plugins.git.DefaultGitHelper;
import org.openmrs.maven.plugins.git.GitHelper;
import org.openmrs.maven.plugins.model.Server;
import org.openmrs.maven.plugins.utility.ConfigurationInstaller;
import org.openmrs.maven.plugins.utility.DefaultJira;
import org.openmrs.maven.plugins.utility.DistroHelper;
import org.openmrs.maven.plugins.git.DefaultGitHelper;
import org.openmrs.maven.plugins.git.GitHelper;
import org.openmrs.maven.plugins.utility.DockerHelper;
import org.openmrs.maven.plugins.utility.Jira;
import org.openmrs.maven.plugins.utility.MavenEnvironment;
import org.openmrs.maven.plugins.utility.ModuleInstaller;
import org.openmrs.maven.plugins.utility.NodeHelper;
import org.openmrs.maven.plugins.utility.OwaHelper;
Expand Down Expand Up @@ -140,10 +142,17 @@ public abstract class AbstractTask extends AbstractMojo {
*/
DockerHelper dockerHelper;

/**
* provides access to the current Maven environment
*/
@Getter
private MavenEnvironment mavenEnvironment;

public AbstractTask() {
}

public AbstractTask(AbstractTask other) {
this.mavenEnvironment = other.mavenEnvironment;
this.mavenProject = other.mavenProject;
this.mavenSession = other.mavenSession;
this.wizard = other.wizard;
Expand All @@ -155,6 +164,7 @@ public AbstractTask(AbstractTask other) {
this.distroHelper = other.distroHelper;
this.owaHelper = other.owaHelper;
this.spaInstaller = other.spaInstaller;
this.configurationInstaller = other.configurationInstaller;
this.gitHelper = other.gitHelper;
this.dockerHelper = other.dockerHelper;
this.settings = other.settings;
Expand All @@ -166,6 +176,16 @@ public AbstractTask(AbstractTask other) {
}

public void initTask() {
if (mavenEnvironment == null) {
mavenEnvironment = new MavenEnvironment();
mavenEnvironment.setMavenProject(mavenProject);
mavenEnvironment.setMavenSession(mavenSession);
mavenEnvironment.setSettings(settings);
mavenEnvironment.setArtifactMetadataSource(artifactMetadataSource);
mavenEnvironment.setArtifactFactory(artifactFactory);
mavenEnvironment.setPluginManager(pluginManager);
mavenEnvironment.setWizard(wizard);
}
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

See the new MavenEnvironment class below - basically this just allows us to encapsulate everything provided by the Maven process during plugin execution in a single object that can be passed around and depended upon.

if (jira == null) {
jira = new DefaultJira();
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,93 @@
package org.openmrs.maven.plugins;

import lombok.Getter;
import lombok.Setter;
import org.apache.commons.lang.StringUtils;
import org.apache.maven.plugin.MojoExecutionException;
import org.apache.maven.plugins.annotations.Mojo;
import org.apache.maven.plugins.annotations.Parameter;
import org.openmrs.maven.plugins.utility.MavenEnvironment;
import org.openmrs.maven.plugins.utility.Wizard;

import java.lang.reflect.Method;

/**
* The purpose is this Mojo is to support testing of helper utilities that are used by the various goals. This will:
* instantiate a new object of type className
* if this class has a setter property for a MavenExecution, this will be set
* it will then invoke the given testMethod on the testClass
*/
@Mojo(name = InvokeMethod.NAME)
@Getter @Setter
public class InvokeMethod extends AbstractTask {

public static final String NAME = "invoke-method";

@Parameter(property = "className")
String className;

@Parameter(property = "methodName")
String methodName;

public void executeTask() throws MojoExecutionException {

if (StringUtils.isBlank(className) || StringUtils.isBlank(methodName)) {
throw new MojoExecutionException("You must supply both a className and methodName parameter");
}

Wizard wizard = getMavenEnvironment().getWizard();

wizard.showMessage("Invoking: " + className + ":" + methodName);

Class<?> clazz;
try {
clazz = getClass().getClassLoader().loadClass(className);
}
catch (ClassNotFoundException e) {
throw new MojoExecutionException("Unable to load class", e);
}
wizard.showMessage("Class " + clazz.getName() + " loaded successfully");

Object instance;
try {
instance = clazz.getConstructor().newInstance();
} catch (Exception e) {
throw new MojoExecutionException("Unable to instantiate class with " + getClass(), e);
}
wizard.showMessage("New instance of " + clazz.getName() + " instantiated");

Method setterMethod = null;
try {
setterMethod = clazz.getMethod("set" + MavenEnvironment.class.getSimpleName(), MavenEnvironment.class);
}
catch (NoSuchMethodException ignored) {
}

if (setterMethod != null) {
try {
setterMethod.invoke(instance, getMavenEnvironment());
wizard.showMessage("Instance populated with maven environment");
}
catch (Exception e) {
throw new MojoExecutionException("Error executing method: " + methodName, e);
}
}
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This code is admittedly ugly. I probably should have just found a library to do this all more elegantly. In any event, this plugin will instantiate the given class, set the mavenEnvironment property on it if available, and the call the given method. This is what allows us to test functionality that requires a Maven Environment outside of individual plugins that consume that functionality (aside from this one, which is necessary).


Method method;
try {
method = clazz.getMethod(methodName);
}
catch (NoSuchMethodException e) {
throw new MojoExecutionException("Unable to find method: " + methodName, e);
}
wizard.showMessage("Got test method: " + method.getName());

try {
method.invoke(instance);
}
catch (Exception e) {
throw new MojoExecutionException("Error executing method: " + methodName, e);
}
wizard.showMessage("Method: " + method.getName() + " invoked successfully");
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
package org.openmrs.maven.plugins;


import lombok.Getter;
import lombok.Setter;
import org.junit.Before;
import org.openmrs.maven.plugins.utility.MavenEnvironment;

import java.io.File;

@Getter @Setter
public abstract class AbstractMavenIT extends AbstractSdkIT {

MavenEnvironment mavenEnvironment = null;

@Override
@Before
public void setup() throws Exception {
super.setup();
mavenEnvironment = null;
}

@Override
void addTestResources() throws Exception {
includePomFile("invokeIT", "pom.xml");
}

protected void executeTest(MavenTestFunction testFunction) throws Exception {
StackTraceElement invoker = Thread.currentThread().getStackTrace()[2];
String className = invoker.getClassName();
String testMethod = invoker.getMethodName();
if (mavenEnvironment == null) {
addTaskParam("className", className);
addTaskParam("methodName", testMethod);
addTaskParam(BATCH_ANSWERS, getAnswers());
addTaskParam("testMode", "true");
String plugin = resolveSdkArtifact();
verifier.executeGoal(plugin + ":" + InvokeMethod.NAME);
}
else {
testFunction.executeTest();
}
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

So the general idea here, is that a particular integration test will wrap it's test functionality in this executeTest method. When this is run, the mavenEnvironment will be null, and this will trigger the new "InvokeMethod" plugin to run it, by creating a new instance of this same test class, and executing this same method, but this time with the mavenEnvironment populated from the InvokeMethod plugin.

}

protected File getMavenTestDirectory() {
return new File(mavenEnvironment.getMavenProject().getBuild().getDirectory());
}

/**
* Simple interface that encapsulates a test that should be evaluated by tests that use this Mojo
*/
public interface MavenTestFunction {
void executeTest() throws Exception;
}
}
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
package org.openmrs.maven.plugins;

import org.apache.commons.io.FileUtils;
import org.apache.commons.io.IOUtils;
import org.apache.commons.lang.StringUtils;
import org.apache.maven.it.VerificationException;
import org.apache.maven.it.Verifier;
Expand Down Expand Up @@ -48,7 +47,7 @@


@RunWith(BlockJUnit4ClassRunner.class)
public abstract class AbstractSdkIntegrationTest {
public abstract class AbstractSdkIT {

/**
* contains name of directory in project's target dir, where integration tests are conducted
Expand Down Expand Up @@ -84,25 +83,26 @@ public String resolveSdkArtifact() throws MojoExecutionException {
return sdk.get("groupId")+":"+sdk.get("artifactId")+":"+sdk.get("version");
}

void includeTestResource(String fileName) throws Exception {
File source = getTestFile(TEST_DIRECTORY, fileName);
File target = new File(testDirectory, fileName);
if (source.isDirectory()) {
FileUtils.copyDirectory(source, testDirectory);
}
else {
FileUtils.copyFile(source, target);
void includeDistroPropertiesFile(String... paths) throws Exception {
Path sourcePath = testDirectoryPath.resolve(TEST_DIRECTORY);
for (String path : paths) {
sourcePath = sourcePath.resolve(path);
}
Path targetPath = testDirectoryPath.resolve(DistroProperties.DISTRO_FILE_NAME);
FileUtils.copyFile(sourcePath.toFile(), targetPath.toFile());
}

void includeDistroPropertiesFile(String fileName) throws Exception {
File source = getTestFile(TEST_DIRECTORY, fileName);
File target = new File(testDirectory, DistroProperties.DISTRO_FILE_NAME);
FileUtils.copyFile(source, target);
void includePomFile(String... paths) throws Exception {
Path sourcePath = testDirectoryPath.resolve(TEST_DIRECTORY);
for (String path : paths) {
sourcePath = sourcePath.resolve(path);
}
Path targetPath = testDirectoryPath.resolve("pom.xml");
FileUtils.copyFile(sourcePath.toFile(), targetPath.toFile());
}

void addTestResources() throws Exception {
includeTestResource("pom.xml");
includePomFile("pom.xml");
includeDistroPropertiesFile(DistroProperties.DISTRO_FILE_NAME);
}

Expand Down
Loading