You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@maven.apache.org by gn...@apache.org on 2023/10/18 14:30:23 UTC

[maven-plugin-testing] branch master updated: [MPLUGINTESTING-84] Support Junit 5 + Maven 3 (#31)

This is an automated email from the ASF dual-hosted git repository.

gnodet pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/maven-plugin-testing.git


The following commit(s) were added to refs/heads/master by this push:
     new c7c07ad  [MPLUGINTESTING-84] Support Junit 5 + Maven 3 (#31)
c7c07ad is described below

commit c7c07ad079686bb219354f4d8708f6c62eaeff61
Author: Guillaume Nodet <gn...@apache.org>
AuthorDate: Wed Oct 18 16:30:18 2023 +0200

    [MPLUGINTESTING-84] Support Junit 5 + Maven 3 (#31)
---
 maven-plugin-testing-harness/pom.xml               |  11 +-
 .../maven/api/plugin/testing/MojoExtension.java    |  39 ++----
 .../maven/plugin/testing/AbstractMojoTestCase.java |   2 +-
 .../maven/plugin/testing/junit5/InjectMojo.java    |  35 ++++++
 .../testing/junit5}/MojoExtension.java             | 131 +++++++++------------
 .../maven/plugin/testing/junit5/MojoParameter.java |  34 ++++++
 .../plugin/testing/junit5/MojoParameters.java      |  30 +++++
 .../maven/plugin/testing/junit5/MojoTest.java      |  34 ++++++
 8 files changed, 206 insertions(+), 110 deletions(-)

diff --git a/maven-plugin-testing-harness/pom.xml b/maven-plugin-testing-harness/pom.xml
index 186330e..b6a5a4b 100644
--- a/maven-plugin-testing-harness/pom.xml
+++ b/maven-plugin-testing-harness/pom.xml
@@ -48,7 +48,7 @@ under the License.
       <groupId>org.apache.maven</groupId>
       <artifactId>maven-compat</artifactId>
       <version>${mavenVersion}</version>
-      <scope>test</scope>
+      <scope>provided</scope>
     </dependency>
     <dependency>
       <groupId>org.apache.maven</groupId>
@@ -71,9 +71,14 @@ under the License.
 
     <!-- plexus -->
     <dependency>
-      <groupId>org.apache.maven</groupId>
+      <groupId>org.codehaus.plexus</groupId>
       <artifactId>plexus-utils</artifactId>
-      <version>${mavenVersion}</version>
+      <version>4.0.0</version>
+    </dependency>
+    <dependency>
+      <groupId>org.codehaus.plexus</groupId>
+      <artifactId>plexus-xml</artifactId>
+      <version>4.0.0</version>
     </dependency>
     <dependency>
       <groupId>commons-io</groupId>
diff --git a/maven-plugin-testing-harness/src/main/java/org/apache/maven/api/plugin/testing/MojoExtension.java b/maven-plugin-testing-harness/src/main/java/org/apache/maven/api/plugin/testing/MojoExtension.java
index 4a32690..f0a4f09 100644
--- a/maven-plugin-testing-harness/src/main/java/org/apache/maven/api/plugin/testing/MojoExtension.java
+++ b/maven-plugin-testing-harness/src/main/java/org/apache/maven/api/plugin/testing/MojoExtension.java
@@ -77,7 +77,12 @@ import org.junit.jupiter.api.extension.ParameterResolver;
 import org.slf4j.LoggerFactory;
 
 /**
+ * JUnit extension to help testing Mojos. The extension should be automatically registered
+ * by adding the {@link MojoTest} annotation on the test class.
  *
+ * @see MojoTest
+ * @see InjectMojo
+ * @see MojoParameter
  */
 public class MojoExtension extends PlexusExtension implements ParameterResolver {
 
@@ -134,15 +139,6 @@ public class MojoExtension extends PlexusExtension implements ParameterResolver
 
             PluginDescriptor pluginDescriptor = new PluginDescriptorBuilder().build(interpolationReader);
 
-            //            Artifact artifact =
-            //                    lookup( RepositorySystem.class ).createArtifact( pluginDescriptor.getGroupId(),
-            //                            pluginDescriptor.getArtifactId(),
-            //                            pluginDescriptor.getVersion(), ".jar" );
-            //
-            //            artifact.setFile( getPluginArtifactFile() );
-            //            pluginDescriptor.setPluginArtifact( artifact );
-            //            pluginDescriptor.setArtifacts( Collections.singletonList( artifact ) );
-
             context.getStore(ExtensionContext.Namespace.GLOBAL).put(PluginDescriptor.class, pluginDescriptor);
 
             for (ComponentDescriptor<?> desc : pluginDescriptor.getComponents()) {
@@ -203,7 +199,7 @@ public class MojoExtension extends PlexusExtension implements ParameterResolver
     }
 
     /**
-     * lookup the mojo while we have all of the relavent information
+     * lookup the mojo while we have all the relevent information
      */
     protected Mojo lookupMojo(String[] coord, XmlNode pluginConfiguration, PluginDescriptor descriptor)
             throws Exception {
@@ -319,13 +315,8 @@ public class MojoExtension extends PlexusExtension implements ParameterResolver
 
     /**
      * Convenience method to obtain the value of a variable on a mojo that might not have a getter.
-     *
-     * NOTE: the caller is responsible for casting to to what the desired type is.
-     *
-     * @param object
-     * @param variable
-     * @return object value of variable
-     * @throws IllegalArgumentException
+     * <br>
+     * NOTE: the caller is responsible for casting to what the desired type is.
      */
     public static Object getVariableValueFromObject(Object object, String variable) throws IllegalAccessException {
         Field field = ReflectionUtils.getFieldByNameIncludingSuperclasses(variable, object.getClass());
@@ -335,11 +326,8 @@ public class MojoExtension extends PlexusExtension implements ParameterResolver
 
     /**
      * Convenience method to obtain all variables and values from the mojo (including its superclasses)
-     *
+     * <br>
      * Note: the values in the map are of type Object so the caller is responsible for casting to desired types.
-     *
-     * @param object
-     * @return map of variable names and values
      */
     public static Map<String, Object> getVariablesAndValuesFromObject(Object object) throws IllegalAccessException {
         return getVariablesAndValuesFromObject(object.getClass(), object);
@@ -347,11 +335,9 @@ public class MojoExtension extends PlexusExtension implements ParameterResolver
 
     /**
      * Convenience method to obtain all variables and values from the mojo (including its superclasses)
-     *
+     * <br>
      * Note: the values in the map are of type Object so the caller is responsible for casting to desired types.
      *
-     * @param clazz
-     * @param object
      * @return map of variable names and values
      */
     public static Map<String, Object> getVariablesAndValuesFromObject(Class<?> clazz, Object object)
@@ -371,11 +357,6 @@ public class MojoExtension extends PlexusExtension implements ParameterResolver
 
     /**
      * Convenience method to set values to variables in objects that don't have setters
-     *
-     * @param object
-     * @param variable
-     * @param value
-     * @throws IllegalAccessException
      */
     public static void setVariableValueToObject(Object object, String variable, Object value)
             throws IllegalAccessException {
diff --git a/maven-plugin-testing-harness/src/main/java/org/apache/maven/plugin/testing/AbstractMojoTestCase.java b/maven-plugin-testing-harness/src/main/java/org/apache/maven/plugin/testing/AbstractMojoTestCase.java
index 8c46573..a163e5d 100644
--- a/maven-plugin-testing-harness/src/main/java/org/apache/maven/plugin/testing/AbstractMojoTestCase.java
+++ b/maven-plugin-testing-harness/src/main/java/org/apache/maven/plugin/testing/AbstractMojoTestCase.java
@@ -36,7 +36,6 @@ import java.util.Map;
 import java.util.Properties;
 
 import com.google.inject.Module;
-import org.apache.commons.io.input.XmlStreamReader;
 import org.apache.maven.artifact.Artifact;
 import org.apache.maven.artifact.versioning.DefaultArtifactVersion;
 import org.apache.maven.execution.DefaultMavenExecutionRequest;
@@ -75,6 +74,7 @@ import org.codehaus.plexus.util.InterpolationFilterReader;
 import org.codehaus.plexus.util.ReaderFactory;
 import org.codehaus.plexus.util.ReflectionUtils;
 import org.codehaus.plexus.util.StringUtils;
+import org.codehaus.plexus.util.xml.XmlStreamReader;
 import org.codehaus.plexus.util.xml.Xpp3Dom;
 import org.codehaus.plexus.util.xml.Xpp3DomBuilder;
 
diff --git a/maven-plugin-testing-harness/src/main/java/org/apache/maven/plugin/testing/junit5/InjectMojo.java b/maven-plugin-testing-harness/src/main/java/org/apache/maven/plugin/testing/junit5/InjectMojo.java
new file mode 100644
index 0000000..7b2fbdc
--- /dev/null
+++ b/maven-plugin-testing-harness/src/main/java/org/apache/maven/plugin/testing/junit5/InjectMojo.java
@@ -0,0 +1,35 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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.apache.maven.plugin.testing.junit5;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+
+/**
+ *
+ */
+@Retention(RetentionPolicy.RUNTIME)
+public @interface InjectMojo {
+
+    String goal();
+
+    String pom();
+
+    boolean empty() default false;
+}
diff --git a/maven-plugin-testing-harness/src/main/java/org/apache/maven/api/plugin/testing/MojoExtension.java b/maven-plugin-testing-harness/src/main/java/org/apache/maven/plugin/testing/junit5/MojoExtension.java
similarity index 79%
copy from maven-plugin-testing-harness/src/main/java/org/apache/maven/api/plugin/testing/MojoExtension.java
copy to maven-plugin-testing-harness/src/main/java/org/apache/maven/plugin/testing/junit5/MojoExtension.java
index 4a32690..f5d2d21 100644
--- a/maven-plugin-testing-harness/src/main/java/org/apache/maven/api/plugin/testing/MojoExtension.java
+++ b/maven-plugin-testing-harness/src/main/java/org/apache/maven/plugin/testing/junit5/MojoExtension.java
@@ -16,7 +16,7 @@
  * specific language governing permissions and limitations
  * under the License.
  */
-package org.apache.maven.api.plugin.testing;
+package org.apache.maven.plugin.testing.junit5;
 
 import java.io.BufferedReader;
 import java.io.File;
@@ -39,23 +39,23 @@ import java.util.stream.Collectors;
 import java.util.stream.Stream;
 
 import com.google.inject.internal.ProviderMethodsModule;
-import org.apache.maven.api.MojoExecution;
-import org.apache.maven.api.Project;
-import org.apache.maven.api.Session;
-import org.apache.maven.api.plugin.Log;
-import org.apache.maven.api.plugin.Mojo;
-import org.apache.maven.api.xml.XmlNode;
-import org.apache.maven.configuration.internal.EnhancedComponentConfigurator;
-import org.apache.maven.internal.impl.DefaultLog;
-import org.apache.maven.internal.xml.XmlNodeImpl;
+import org.apache.maven.api.plugin.testing.MojoTest;
+import org.apache.maven.execution.MavenSession;
 import org.apache.maven.lifecycle.internal.MojoDescriptorCreator;
-import org.apache.maven.plugin.PluginParameterExpressionEvaluatorV4;
+import org.apache.maven.plugin.Mojo;
+import org.apache.maven.plugin.MojoExecution;
+import org.apache.maven.plugin.PluginParameterExpressionEvaluator;
 import org.apache.maven.plugin.descriptor.MojoDescriptor;
 import org.apache.maven.plugin.descriptor.Parameter;
 import org.apache.maven.plugin.descriptor.PluginDescriptor;
 import org.apache.maven.plugin.descriptor.PluginDescriptorBuilder;
+import org.apache.maven.plugin.logging.Log;
+import org.apache.maven.plugin.testing.ConfigurationException;
+import org.apache.maven.plugin.testing.MojoLogWrapper;
+import org.apache.maven.project.MavenProject;
 import org.codehaus.plexus.DefaultPlexusContainer;
 import org.codehaus.plexus.PlexusContainer;
+import org.codehaus.plexus.component.configurator.BasicComponentConfigurator;
 import org.codehaus.plexus.component.configurator.ComponentConfigurator;
 import org.codehaus.plexus.component.configurator.expression.ExpressionEvaluationException;
 import org.codehaus.plexus.component.configurator.expression.ExpressionEvaluator;
@@ -77,7 +77,12 @@ import org.junit.jupiter.api.extension.ParameterResolver;
 import org.slf4j.LoggerFactory;
 
 /**
+ * JUnit extension to help testing Mojos. The extension should be automatically registered
+ * by adding the {@link org.apache.maven.api.plugin.testing.MojoTest} annotation on the test class.
  *
+ * @see MojoTest
+ * @see org.apache.maven.api.plugin.testing.InjectMojo
+ * @see org.apache.maven.api.plugin.testing.MojoParameter
  */
 public class MojoExtension extends PlexusExtension implements ParameterResolver {
 
@@ -120,7 +125,7 @@ public class MojoExtension extends PlexusExtension implements ParameterResolver
         ((DefaultPlexusContainer) getContainer()).addPlexusInjector(Collections.emptyList(), binder -> {
             binder.install(ProviderMethodsModule.forObject(context.getRequiredTestInstance()));
             binder.requestInjection(context.getRequiredTestInstance());
-            binder.bind(Log.class).toInstance(new DefaultLog(LoggerFactory.getLogger("anonymous")));
+            binder.bind(Log.class).toInstance(new MojoLogWrapper(LoggerFactory.getLogger("anonymous")));
         });
 
         Map<Object, Object> map = getContainer().getContext().getContextData();
@@ -134,15 +139,6 @@ public class MojoExtension extends PlexusExtension implements ParameterResolver
 
             PluginDescriptor pluginDescriptor = new PluginDescriptorBuilder().build(interpolationReader);
 
-            //            Artifact artifact =
-            //                    lookup( RepositorySystem.class ).createArtifact( pluginDescriptor.getGroupId(),
-            //                            pluginDescriptor.getArtifactId(),
-            //                            pluginDescriptor.getVersion(), ".jar" );
-            //
-            //            artifact.setFile( getPluginArtifactFile() );
-            //            pluginDescriptor.setPluginArtifact( artifact );
-            //            pluginDescriptor.setArtifacts( Collections.singletonList( artifact ) );
-
             context.getStore(ExtensionContext.Namespace.GLOBAL).put(PluginDescriptor.class, pluginDescriptor);
 
             for (ComponentDescriptor<?> desc : pluginDescriptor.getComponents()) {
@@ -177,13 +173,18 @@ public class MojoExtension extends PlexusExtension implements ParameterResolver
             Path path = Paths.get(getBasedir()).resolve(pom);
             pomDom = Xpp3DomBuilder.build(ReaderFactory.newXmlReader(path.toFile()));
         }
-        XmlNode pluginConfiguration = extractPluginConfiguration(coord[1], pomDom);
+        Xpp3Dom pluginConfiguration = extractPluginConfiguration(coord[1], pomDom);
         if (!mojoParameters.isEmpty()) {
-            List<XmlNode> children = mojoParameters.stream()
-                    .map(mp -> new XmlNodeImpl(mp.name(), mp.value()))
+            List<Xpp3Dom> children = mojoParameters.stream()
+                    .map(mp -> {
+                        Xpp3Dom c = new Xpp3Dom(mp.name());
+                        c.setValue(mp.value());
+                        return c;
+                    })
                     .collect(Collectors.toList());
-            XmlNode config = new XmlNodeImpl("configuration", null, null, children, null);
-            pluginConfiguration = XmlNode.merge(config, pluginConfiguration);
+            Xpp3Dom config = new Xpp3Dom("configuration");
+            children.forEach(config::addChild);
+            pluginConfiguration = Xpp3Dom.mergeXpp3Dom(config, pluginConfiguration);
         }
         Mojo mojo = lookupMojo(coord, pluginConfiguration, descriptor);
         return mojo;
@@ -203,9 +204,9 @@ public class MojoExtension extends PlexusExtension implements ParameterResolver
     }
 
     /**
-     * lookup the mojo while we have all of the relavent information
+     * lookup the mojo while we have all the relevent information
      */
-    protected Mojo lookupMojo(String[] coord, XmlNode pluginConfiguration, PluginDescriptor descriptor)
+    protected Mojo lookupMojo(String[] coord, Xpp3Dom pluginConfiguration, PluginDescriptor descriptor)
             throws Exception {
         // pluginkey = groupId : artifactId : version : goal
         Mojo mojo = lookup(Mojo.class, coord[0] + ":" + coord[1] + ":" + coord[2] + ":" + coord[3]);
@@ -218,27 +219,25 @@ public class MojoExtension extends PlexusExtension implements ParameterResolver
             }
         }
         if (pluginConfiguration != null) {
-            Session session = getContainer().lookup(Session.class);
-            Project project;
+            MavenSession session = getContainer().lookup(MavenSession.class);
+            MavenProject project;
             try {
-                project = getContainer().lookup(Project.class);
+                project = getContainer().lookup(MavenProject.class);
             } catch (ComponentLookupException e) {
                 project = null;
             }
-            org.apache.maven.plugin.MojoExecution mojoExecution;
+            MojoExecution mojoExecution;
             try {
-                MojoExecution me = getContainer().lookup(MojoExecution.class);
-                mojoExecution = new org.apache.maven.plugin.MojoExecution(
-                        new org.apache.maven.model.Plugin(me.getPlugin()), me.getGoal(), me.getExecutionId());
+                mojoExecution = getContainer().lookup(MojoExecution.class);
             } catch (ComponentLookupException e) {
                 mojoExecution = null;
             }
-            ExpressionEvaluator evaluator = new WrapEvaluator(
-                    getContainer(), new PluginParameterExpressionEvaluatorV4(session, project, mojoExecution));
-            ComponentConfigurator configurator = new EnhancedComponentConfigurator();
+            ExpressionEvaluator evaluator =
+                    new WrapEvaluator(getContainer(), new PluginParameterExpressionEvaluator(session, mojoExecution));
+            ComponentConfigurator configurator = new BasicComponentConfigurator();
             configurator.configureComponent(
                     mojo,
-                    new XmlPlexusConfiguration(new Xpp3Dom(pluginConfiguration)),
+                    new XmlPlexusConfiguration(pluginConfiguration),
                     evaluator,
                     getContainer().getContainerRealm());
         }
@@ -246,36 +245,29 @@ public class MojoExtension extends PlexusExtension implements ParameterResolver
         return mojo;
     }
 
-    private XmlNode finalizeConfig(XmlNode config, MojoDescriptor mojoDescriptor) {
-        List<XmlNode> children = new ArrayList<>();
+    private Xpp3Dom finalizeConfig(Xpp3Dom config, MojoDescriptor mojoDescriptor) {
+        List<Xpp3Dom> children = new ArrayList<>();
         if (mojoDescriptor != null && mojoDescriptor.getParameters() != null) {
-            XmlNode defaultConfiguration =
-                    MojoDescriptorCreator.convert(mojoDescriptor).getDom();
+            Xpp3Dom defaultConfiguration = MojoDescriptorCreator.convert(mojoDescriptor);
             for (Parameter parameter : mojoDescriptor.getParameters()) {
-                XmlNode parameterConfiguration = config.getChild(parameter.getName());
+                Xpp3Dom parameterConfiguration = config.getChild(parameter.getName());
                 if (parameterConfiguration == null) {
                     parameterConfiguration = config.getChild(parameter.getAlias());
                 }
-                XmlNode parameterDefaults = defaultConfiguration.getChild(parameter.getName());
-                parameterConfiguration = XmlNode.merge(parameterConfiguration, parameterDefaults, Boolean.TRUE);
+                Xpp3Dom parameterDefaults = defaultConfiguration.getChild(parameter.getName());
+                parameterConfiguration = Xpp3Dom.mergeXpp3Dom(parameterConfiguration, parameterDefaults, Boolean.TRUE);
                 if (parameterConfiguration != null) {
-                    Map<String, String> attributes = new HashMap<>(parameterConfiguration.getAttributes());
                     if (isEmpty(parameterConfiguration.getAttribute("implementation"))
                             && !isEmpty(parameter.getImplementation())) {
-                        attributes.put("implementation", parameter.getImplementation());
+                        parameterConfiguration.setAttribute("implementation", parameter.getImplementation());
                     }
-                    parameterConfiguration = new XmlNodeImpl(
-                            parameter.getName(),
-                            parameterConfiguration.getValue(),
-                            attributes,
-                            parameterConfiguration.getChildren(),
-                            parameterConfiguration.getInputLocation());
-
                     children.add(parameterConfiguration);
                 }
             }
         }
-        return new XmlNodeImpl("configuration", null, null, children, null);
+        Xpp3Dom c = new Xpp3Dom("configuration");
+        children.forEach(c::addChild);
+        return c;
     }
 
     private boolean isEmpty(String str) {
@@ -290,7 +282,7 @@ public class MojoExtension extends PlexusExtension implements ParameterResolver
         return Stream.of(element.getChildren());
     }
 
-    public static XmlNode extractPluginConfiguration(String artifactId, Xpp3Dom pomDom) throws Exception {
+    public static Xpp3Dom extractPluginConfiguration(String artifactId, Xpp3Dom pomDom) throws Exception {
         Xpp3Dom pluginConfigurationElement = child(pomDom, "build")
                 .flatMap(buildElement -> child(buildElement, "plugins"))
                 .map(MojoExtension::children)
@@ -301,7 +293,7 @@ public class MojoExtension extends PlexusExtension implements ParameterResolver
                 .orElseThrow(
                         () -> new ConfigurationException("Cannot find a configuration element for a plugin with an "
                                 + "artifactId of " + artifactId + "."));
-        return pluginConfigurationElement.getDom();
+        return pluginConfigurationElement;
     }
 
     /**
@@ -319,13 +311,8 @@ public class MojoExtension extends PlexusExtension implements ParameterResolver
 
     /**
      * Convenience method to obtain the value of a variable on a mojo that might not have a getter.
-     *
-     * NOTE: the caller is responsible for casting to to what the desired type is.
-     *
-     * @param object
-     * @param variable
-     * @return object value of variable
-     * @throws IllegalArgumentException
+     * <br>
+     * Note: the caller is responsible for casting to what the desired type is.
      */
     public static Object getVariableValueFromObject(Object object, String variable) throws IllegalAccessException {
         Field field = ReflectionUtils.getFieldByNameIncludingSuperclasses(variable, object.getClass());
@@ -335,11 +322,8 @@ public class MojoExtension extends PlexusExtension implements ParameterResolver
 
     /**
      * Convenience method to obtain all variables and values from the mojo (including its superclasses)
-     *
+     * <br>
      * Note: the values in the map are of type Object so the caller is responsible for casting to desired types.
-     *
-     * @param object
-     * @return map of variable names and values
      */
     public static Map<String, Object> getVariablesAndValuesFromObject(Object object) throws IllegalAccessException {
         return getVariablesAndValuesFromObject(object.getClass(), object);
@@ -347,11 +331,9 @@ public class MojoExtension extends PlexusExtension implements ParameterResolver
 
     /**
      * Convenience method to obtain all variables and values from the mojo (including its superclasses)
-     *
+     * <br>
      * Note: the values in the map are of type Object so the caller is responsible for casting to desired types.
      *
-     * @param clazz
-     * @param object
      * @return map of variable names and values
      */
     public static Map<String, Object> getVariablesAndValuesFromObject(Class<?> clazz, Object object)
@@ -371,11 +353,6 @@ public class MojoExtension extends PlexusExtension implements ParameterResolver
 
     /**
      * Convenience method to set values to variables in objects that don't have setters
-     *
-     * @param object
-     * @param variable
-     * @param value
-     * @throws IllegalAccessException
      */
     public static void setVariableValueToObject(Object object, String variable, Object value)
             throws IllegalAccessException {
diff --git a/maven-plugin-testing-harness/src/main/java/org/apache/maven/plugin/testing/junit5/MojoParameter.java b/maven-plugin-testing-harness/src/main/java/org/apache/maven/plugin/testing/junit5/MojoParameter.java
new file mode 100644
index 0000000..a3a8294
--- /dev/null
+++ b/maven-plugin-testing-harness/src/main/java/org/apache/maven/plugin/testing/junit5/MojoParameter.java
@@ -0,0 +1,34 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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.apache.maven.plugin.testing.junit5;
+
+import java.lang.annotation.Repeatable;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+
+/**
+ * Mojo parameter
+ */
+@Retention(RetentionPolicy.RUNTIME)
+@Repeatable(MojoParameters.class)
+public @interface MojoParameter {
+    String name();
+
+    String value();
+}
diff --git a/maven-plugin-testing-harness/src/main/java/org/apache/maven/plugin/testing/junit5/MojoParameters.java b/maven-plugin-testing-harness/src/main/java/org/apache/maven/plugin/testing/junit5/MojoParameters.java
new file mode 100644
index 0000000..33c0a23
--- /dev/null
+++ b/maven-plugin-testing-harness/src/main/java/org/apache/maven/plugin/testing/junit5/MojoParameters.java
@@ -0,0 +1,30 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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.apache.maven.plugin.testing.junit5;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+
+/**
+ * Mojo parameters container
+ */
+@Retention(RetentionPolicy.RUNTIME)
+public @interface MojoParameters {
+    MojoParameter[] value();
+}
diff --git a/maven-plugin-testing-harness/src/main/java/org/apache/maven/plugin/testing/junit5/MojoTest.java b/maven-plugin-testing-harness/src/main/java/org/apache/maven/plugin/testing/junit5/MojoTest.java
new file mode 100644
index 0000000..09461bd
--- /dev/null
+++ b/maven-plugin-testing-harness/src/main/java/org/apache/maven/plugin/testing/junit5/MojoTest.java
@@ -0,0 +1,34 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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.apache.maven.plugin.testing.junit5;
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+import org.junit.jupiter.api.extension.ExtendWith;
+
+/**
+ *
+ */
+@Retention(RetentionPolicy.RUNTIME)
+@ExtendWith(MojoExtension.class)
+@Target(ElementType.TYPE)
+public @interface MojoTest {}