I'm trying to run Scenario's in parallel using Trivago's Cucable Plugin. To test it before implementing it my project I download this project.
https://github.com/trivago/cucable-plugin/tree/master/example-project
I tried, mvn clean verify and it created *IT.java files in target folder, but I noticed these are not running in parallel.
How do I know? I added sleep in each statement. Largest sleep is 15 seconds, so the total build should be approx 16 seconds, but it is showing 30 (sum of all sleeps of all scenarios 2+5+15+8) seconds.
cucable.template
import cucumber.api.CucumberOptions;
import org.junit.runner.RunWith;
#RunWith(Cucumber.class)
#CucumberOptions(
glue = "steps",
features = {"target/parallel/features/[CUCABLE:FEATURE].feature"},
plugin = {"json:target/cucumber-report/[CUCABLE:RUNNER].json"}
)
public class [CUCABLE:RUNNER] {
// [CUCABLE:CUSTOM:comment]
}
pom.xml
<?xml version="1.0" encoding="UTF-8"?>
<!--suppress UnresolvedMavenProperty -->
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.trivago.rta</groupId>
<artifactId>cucable-test-project</artifactId>
<version>1.5.1</version>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
<maven.failsafe.plugin.version>3.0.0-M3</maven.failsafe.plugin.version>
<maven.build.helper.plugin.version>3.0.0</maven.build.helper.plugin.version>
<cucumber.version>4.2.6</cucumber.version>
<maven.compiler.plugin.version>3.7.0</maven.compiler.plugin.version>
<generated.runner.directory>${project.build.directory}/parallel/runners</generated.runner.directory>
<generated.feature.directory>${project.build.directory}/parallel/features</generated.feature.directory>
</properties>
<dependencies>
<dependency>
<groupId>io.cucumber</groupId>
<artifactId>cucumber-java</artifactId>
<version>${cucumber.version}</version>
</dependency>
<dependency>
<groupId>io.cucumber</groupId>
<artifactId>cucumber-junit</artifactId>
<version>${cucumber.version}</version>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>com.trivago.rta</groupId>
<artifactId>cucable-plugin</artifactId>
<version>${project.version}</version>
<executions>
<execution>
<id>generate-test-resources</id>
<phase>generate-test-resources</phase>
<goals>
<goal>parallel</goal>
</goals>
</execution>
</executions>
<configuration>
<sourceRunnerTemplateFile>src/test/java/some/template/CucableJavaTemplate.java
</sourceRunnerTemplateFile>
<sourceFeatures>src/test/resources/features</sourceFeatures>
<generatedFeatureDirectory>${generated.feature.directory}</generatedFeatureDirectory>
<generatedRunnerDirectory>${generated.runner.directory}</generatedRunnerDirectory>
</configuration>
</plugin>
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>build-helper-maven-plugin</artifactId>
<version>${maven.build.helper.plugin.version}</version>
<executions>
<execution>
<id>add-test-source</id>
<phase>generate-test-sources</phase>
<goals>
<goal>add-test-source</goal>
</goals>
<configuration>
<sources>
<source>${generated.runner.directory}</source>
</sources>
</configuration>
</execution>
</executions>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-failsafe-plugin</artifactId>
<version>${maven.failsafe.plugin.version}</version>
<executions>
<execution>
<id>Run parallel tests</id>
<phase>integration-test</phase>
<goals>
<goal>integration-test</goal>
</goals>
</execution>
</executions>
<configuration>
<forkCount>5</forkCount>
<testFailureIgnore>true</testFailureIgnore>
</configuration>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>${maven.compiler.plugin.version}</version>
<configuration>
<source>8</source>
<target>8</target>
</configuration>
</plugin>
</plugins>
</build>
</project>
Key Point :
We shall not mix direct & transitive dependencies specially their versions! Doing so can cause unpredictable outcome.
We would need to use Cucumber-JVM v4.x.x specially to implement parallel execution without using cucumber-jvm-parallel or cucable plugin
We would be considering v4.2.6 for the implementation
Cucumber Parallel Execution via JUnit
First - Update POM.xml with correct set of io.cucumber dependencies.
<dependency>
<groupId>io.cucumber</groupId>
<artifactId>cucumber-junit</artifactId>
<version>4.2.6</version>
</dependency>
<dependency>
<groupId>io.cucumber</groupId>
<artifactId>cucumber-picocontainer</artifactId>
<version>4.2.6</version>
</dependency>
Point To Note Down - There could be an issue like everything is ok but still tests do not execute in parallel and could be if your pom.xml is having direct/transitive dependency of testng. As testNG causes Surefire to ignore JUnit wrapper class. If you had testng dependency so remove the TestNG dependency or you can take a call to 2 define 2 execution - For TestNG & JUnit and disable one as per your need.
Second - Customize Runner class as per your framework need
package com.jacksparrow.automation.suite.runner;
import org.junit.runner.RunWith;
import cucumber.api.CucumberOptions;
import cucumber.api.junit.Cucumber;
#RunWith(Cucumber.class)
#CucumberOptions(features = "classpath:features/functional/",
glue = {"com.jacksparrow.automation.steps_definitions.functional" },
plugin = { "pretty","json:target/cucumber-json/cucumber.json",
"junit:target/cucumber-reports/Cucumber.xml", "html:target/cucumber-reports"},
tags = { "#BAMS_Submitted_State_Guest_User" },
junit ={ "--step-notifications"},
strict = false,
dryRun = false,
monochrome = true)
public class RunCukeTest {
}
Third - Implementing maven surefire plugin which would actually run tests in parallel
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<version>3.0.0-M3</version>
<configuration>
<parallel>methods</parallel>
<threadCount>2</threadCount>
<reuserForks>false</reuserForks>
<testFailureIgnore>true</testFailureIgnore>
<includes>
<include>**/*RunCukeTest.java</include>
</includes>
</configuration>
</plugin>
Fourth - Implement Hooks.java
import cucumber.api.Scenario;
import cucumber.api.java.Before;
import cucumber.api.java.After;
public class Hooks {
#Before
public void setUpScenario(String browser){
//BaseSteps.getInstance().getBrowserInstantiation(browser); your browser setup method
}
#After
public void afterScenario(Scenario scenario){
// more code goes here
}
}
Cucumber Parallel Execution via TestNG
Note : In below implementation, we would be reading browser parameter from TestNG.xml file
First - Update POM.xml with correct set of io.cucumber dependencies.
<dependency>
<groupId>io.cucumber</groupId>
<artifactId>cucumber-picocontainer</artifactId>
<version>4.2.6</version>
</dependency>
<dependency>
<groupId>io.cucumber</groupId>
<artifactId>cucumber-testng</artifactId>
<version>4.2.6</version>
</dependency>
Second - Customize TestNGRunner class as per your framework need
package com.jacksparrow.automation.suite.runner;
import org.testng.annotations.BeforeClass;
import org.testng.annotations.Parameters;
import com.jacksparrow.automation.steps_definitions.functional.BaseSteps;
import cucumber.api.CucumberOptions;
import cucumber.api.testng.AbstractTestNGCucumberTests;
#CucumberOptions(features = "classpath:features/functional/",
glue = {"com.jacksparrow.automation.steps_definitions.functional" },
plugin = { "pretty","json:target/cucumber-json/cucumber.json",
"junit:target/cucumber-reports/Cucumber.xml", "html:target/cucumber-reports"},
tags = { "#BAMS_Submitted_State_Guest_User" },
junit ={ "--step-notifications"},
strict = false,
dryRun = false,
monochrome = true)
public class RunCukeTest extends Hooks {
}
Third - Implement Hooks.java
import org.testng.annotations.BeforeClass;
import org.testng.annotations.Parameters;
import cucumber.api.testng.AbstractTestNGCucumberTests;
public class Hooks extends AbstractTestNGCucumberTests {
#Parameters({ "browser" })
#BeforeTest
public void setUpScenario(String browser){
//BaseSteps.getInstance().getBrowserInstantiation(browser); your browser setup method
}
}
Fourth - Update TestNG.xml under /src/test/resources/ as per your TestNGRunner Class and framework need.
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE suite SYSTEM "http://testng.org/testng-1.0.dtd">
<suite name="Testng Cucumber Suite" parallel="tests" thread-count="2">
<test name="SmokeTest">
<parameter name="browser" value="chrome" />
<classes>
<class name="com.cvs.runner.TestSuiteRunner" />
</classes>
</test>
</suite>
Fifth - You shall be all set to run automation suite using TestNG in any of the following ways
- Run TestNG.xml directly from IDE
- From CMD - mvn test -Dsurefire.suiteXmlFiles=src/test/resources/testng.xml
- From POM.xml - Using Surefire Plugin
<profiles>
<profile>
<id>selenium-tests</id>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<version>3.0.0-M3</version>
<configuration>
<suiteXmlFiles>
<suiteXmlFile>src/test/resources/testng.xml</suiteXmlFile>
</suiteXmlFiles>
</configuration>
</plugin>
</plugins>
</build>
</profile>
</profiles>
Related
I'm practicing on a very small Java/JUnit/Maven project with the Jacoco plugin to practice with the Code Coverage feature of Sonarqube.
The core code for the example is small. Here is the class under test:
package com.somebody.sonarqube;
public class Calculator {
// Method to add two numbers
public int addNumbers(int one, int two) {
return one + two;
}
// Method to subtract two numbers
public int subtractNumbers(int one, int two) {
return one - two;
}
}
And here are the unit tests:
package com.somebody.sonarqube;
import static org.junit.Assert.*;
import org.junit.Test;
public class CalculatorTest {
#Test
public void testAddNumbers() {
Calculator myCalc = new Calculator();
assertEquals(10, myCalc.addNumbers(5, 5));
}
#Test
public void testSubtractNumbers() {
Calculator myCalc = new Calculator();
assertEquals(5, myCalc.subtractNumbers(10, 5));
}
}
The two methods in the class under test are covered by the two unit tests respectively, so as far as "Code Coverage" is concerned, that Sonarqube score should be 100%.
When trying to get this score after running my "clean test sonar:sonar" Maven build targets, I'm getting 0% instead:
So the part I'm having the most trouble with is getting the various components in the pom.xml file working together. At this time there's a warning at the <systemPropertyVariables> block at the bottom that reports Invalid plugin configuration: systemPropertyVariables. Here's the full pom.xml file:
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.somebody.sonarqube</groupId>
<artifactId>HelloSonarqube</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>HelloSonarqube</name>
<description>Small example of Sonarqube and JUnit tests.</description>
<properties>
<maven.compiler.source>11</maven.compiler.source>
<maven.compiler.target>11</maven.compiler.target>
</properties>
<dependencies>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.13.2</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.sonarsource.scanner.maven</groupId>
<artifactId>sonar-maven-plugin</artifactId>
<version>3.9.1.2184</version>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<artifactId>maven-surefire-plugin</artifactId>
<version>2.22.2</version>
</plugin>
<plugin>
<artifactId>maven-failsafe-plugin</artifactId>
<version>2.22.2</version>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.9.0</version>
<configuration>
<release>11</release>
</configuration>
</plugin>
<plugin>
<groupId>org.jacoco</groupId>
<artifactId>jacoco-maven-plugin</artifactId>
<version>0.8.7</version>
<executions>
<execution>
<id>prepare-agent</id>
<goals>
<goal>prepare-agent</goal>
</goals>
</execution>
<execution>
<id>report</id>
<phase>prepare-package</phase>
<goals>
<goal>report</goal>
</goals>
</execution>
<execution>
<id>post-unit-test</id>
<phase>test</phase>
<goals>
<goal>report</goal>
</goals>
<configuration>
<dataFile>target/jacoco.exec</dataFile>
<outputDirectory>target/jacoco-ut</outputDirectory>
</configuration>
</execution>
</executions>
<configuration>
<systemPropertyVariables>
<jacoco-agent.destfile>target/jacoco.exec</jacoco-agent.destfile>
</systemPropertyVariables>
</configuration>
</plugin>
</plugins>
</build>
</project>
I've tried a lot of variations to this, including changing JUnit 4 to version 5 (I'd be interested to hear about issues on this too). From my reading I generally understand that the Eclipse/JUnit lifecycle is not fully working harmoniously with the Maven lifecycle by default, hence it's missing something. The solutions I've seen/tried are quite specific to certain project setups, and I have tried manually setting "arguments" and other changes. Would be really thrilled to see your opinions on this having spent a number of hours playing with different versions.
I was able to finally answer the question based upon a similar example I just found on this GitHub project:
https://github.com/SonarSource/sonar-scanning-examples/tree/master/sonarqube-scanner-maven/maven-basic
In short, they used "clean verify sonar:sonar" rather than "clean test sonar:sonar" Maven build targets. The change triggered the code coverage plugin that I was looking for to publish code coverage scores in the Sonarqube dashboard.
As an aside, the warning message I also shared regarding <systemPropertyVariables> was not critical to solving the problem, and I decided to go without that part of the code, and still get all the reports in the Sonarqube dashboard I was looking for.
I have created Tests and IntegrationTests (IT) defined in the POM and classNames which I run from the commandline; I now wish them to run them from Eclipse. Here is the skeleton:
test:
package org.xmlcml.it;
import org.junit.Assert;
import org.junit.Test;
public class SimpleTest {
#Test
public void simpleTest() {
Assert.assertTrue("simpleTest", true);
System.out.println("RAN simpleTest");
}
}
run with:
mvn clean test
and the integration tests:
package org.xmlcml.it;
import org.junit.Test;
import junit.framework.Assert;
public class SimpleIT {
#Test
public void integrationTest() {
Assert.assertTrue("integrationTest", true);
System.out.println("RAN integrationTest");
}
}
run with
mvn clean integration-test
My POM is:
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
<modelVersion>4.0.0</modelVersion>
<properties>
<junit.version>4.8.2</junit.version>
<!-- if this is uncommented the tests are all skipped
<skipTests>true</skipTests>
-->
<!--
<skipITs>true</skipITs>
-->
</properties>
<groupId>org.contentmine</groupId>
<artifactId>simple</artifactId>
<version>0.1-SNAPSHOT</version>
<name>Simple</name>
<description>Test integration test</description>
<dependencies>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>${junit.version}</version>
</dependency>
</dependencies>
<!-- http://maven.apache.org/surefire/maven-failsafe-plugin/usage.html -->
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-failsafe-plugin</artifactId>
<version>2.21.0</version>
<executions>
<execution>
<goals>
<goal>integration-test</goal>
<goal>verify</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>
</project>
When I run this from Eclipse (4.5.2) the IT tests are run. How can I alter the POM so they are skipped by default (and how can I switch them back on)?
NOTE: I have used
http://maven.apache.org/surefire/maven-failsafe-plugin/usage.html
for guidance but still have problems with the multiple ways of switching tests on and off (#Test, *Test.java, method public void testFoo(), ${skipTests} ...) and some of the SO answers are labelled as obsolete. I am not clear which take precedence - is there an up-to-date cheat sheet?
I have a project folder but it is not a java project. It is a maven project. I have written a junit test and it runs perfectly when running in the eclipse IDE but when I run the maven command mvn install, it seems to skip my junit tests. I have included the test file in src/test/java/ (the name of my test is AppTest.java) and the main .java file (with the main method) is in src/main/java/. I have noticed that the project I am currently working on is a maven project and not a maven java project. I have included a screen of my current folder structure:
folder structure
Maven test output <- should not build as I have a deliberate test that should fail
This is the POM. I have deleted/commented out some sensitive parts so the pom file may be syntactically wrong but the main plugins I use are there; tap4j, junit and surefire.
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<artifactId>integration-api-parent</artifactId>
<groupId>uk.gov.dwp</groupId>
<version>1.0.2</version>
</parent>
<artifactId>aa</artifactId>
<version>1.0.6</version>
<packaging>pom</packaging>
<dependencies>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.12</version>
<scope>test</scope>
</dependency>
</dependencies>
<build>
<finalName>aa</finalName>
<plugins>
<!-- plugin>
<groupId>com.github.fracpete</groupId>
<artifactId>latex-maven-plugin</artifactId>
<configuration>
<forceBuild>true</forceBuild>
</configuration>
</plugin>
<plugin>
<groupId>com.github.fracpete</groupId>
<artifactId>latex-maven-plugin</artifactId>
<configuration>
<forceBuild>true</forceBuild>
</configuration>
</plugin-->
<plugin>
<!-- Plug-in utilised for the execution of the JMeter Integration Tests -->
<!-- These tests are executed against the nominated integration server where as -->
<!-- instance of AA exists -->
<groupId>com.lazerycode.jmeter</groupId>
<artifactId>jmeter-maven-plugin</artifactId>
<version>1.9.0</version>
<executions>
<execution>
<id>jmeter-tests</id>
<phase>verify</phase>
<goals>
<goal>jmeter</goal>
</goals>
</execution>
</executions>
<configuration>
<ignoreResultErrors>false</ignoreResultErrors>
<suppressJMeterOutput>false</suppressJMeterOutput>
<overrideRootLogLevel>INFO</overrideRootLogLevel>
</configuration>
</plugin>
<plugin>
<!-- Step to copy the latest plug-ins that form this build to the integration server -->
<!-- This is done using the SCP command via the ANT plug-in thus allowing it to execute on all platforms -->
<artifactId>maven-antrun-plugin</artifactId>
<version>1.8</version>
<dependency>
<groupId>ant</groupId>
<artifactId>ant-jsch</artifactId>
<version>1.6.5</version>
</dependency>
<dependency>
<groupId>com.jcraft</groupId>
<artifactId>jsch</artifactId>
<version>0.1.42</version>
</dependency>
<!-- https://mvnrepository.com/artifact/org.tap4j/tap4j -->
<dependency>
<groupId>org.tap4j</groupId>
<artifactId>tap4j</artifactId>
<version>4.2.1</version>
</dependency>
</dependencies>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<version>2.19.1</version>
</plugin>
<!-- plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-assembly-plugin</artifactId>
<configuration>
<descriptors>
<descriptor>src/main/assembly/cassandra-assembly.xml</descriptor>
<descriptor>src/main/assembly/devenv-assembly.xml</descriptor>
<descriptor>src/main/assembly/main-assembly.xml</descriptor>
</descriptors>
</configuration>
</plugin-->
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<version>2.18.1</version>
</plugin>
<!-- plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>templating-maven-plugin</artifactId>
<configuration>
<skipPoms>false</skipPoms>
<sourceDirectory>${project.basedir}/src/main/latex-templates</sourceDirectory>
<outputDirectory>${project.build.directory}/latex</outputDirectory>
</configuration>
</plugin-->
</plugins>
</build>
</project>
AppTest:
package AccessGateway;
import static org.junit.Assert.*;
import java.io.File;
import org.junit.Test;
import org.tap4j.consumer.TapConsumer;
import org.tap4j.consumer.TapConsumerFactory;
import org.tap4j.model.TestSet;
public class AppTest {
Practise prac;
final String DIRECTORY = "C:\\Users\\Hello\\Desktop\\";
#Test
public void testHeaderProcessor() {
prac = new Practise();
assertFalse(prac.runTest(new File(DIRECTORY+"TAPHeaderProcessor.txt")));
}
#Test
public void testHeaderPortForward() {
prac = new Practise();
assertFalse(prac.runTest(new File(DIRECTORY+"TAPHeaderPortForward.txt")));
}
#Test
public void catunittest() {
prac = new Practise();
assertFalse(prac.runTest(new File(DIRECTORY+"catunittest.txt")));
}
#Test
public void catunitcrowstest() {
prac = new Practise();
assertFalse(prac.runTest(new File(DIRECTORY+"catcrowd.txt")));
}
#Test
public void testCrowd() {
prac = new Practise();
assertFalse(
prac.runTest(new File(DIRECTORY+"TAPCrowd.txt")));
}
#Test
public void testADFS() {
prac = new Practise();
assertFalse(
prac.runTest(new File(DIRECTORY+"TAPADFSformat.txt")));
}
}
The problem is the packaging of your project which is pom
You can't execute Surefire on this kind of project.
Try adding surefire plugin. When i have tests in my app i always include it (works for junit as well as testng). Based on your logs i can see that you dont have it declared.
<plugins>
[...]
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<version>2.19.1</version>
I have trying to test load time weaving in simple hello world normal Servlet based example in wildfly8.2
I have below Aspect code
package com.test.aspects;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import com.test.helloworld.HelloService;
#Aspect
public abstract class FieldAspect {
#Pointcut
public abstract void getField();
#Pointcut
public abstract void setField();
#Around("getField()")
public HelloService getFieldValue() {
System.out.println("In FieldAspect.getFieldValue() - Applying around advice - getting the value (Andy) for field annotated variable");
return new HelloService();
}
#Around("setField()")
public void setFieldValue() {
System.out
.println("In FieldAspect.setFieldValue() - Applying around advice - throw RuntimeException if field annotated variable is set");
throw new RuntimeException();
}
}
The below run time field annotation
package com.test.aspects;
import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
#Target({ ElementType.FIELD })
#Retention(RetentionPolicy.RUNTIME)
#Documented
public #interface Field {
}
Test Servlet:
package com.test.helloworld;
import java.io.IOException;
import java.io.PrintWriter;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import com.test.aspects.Field;
#SuppressWarnings("serial")
#WebServlet("/HelloWorld")
public class HelloWorldServlet extends HttpServlet {
static String PAGE_HEADER = "<html><head><title>helloworld</title></head><body>";
static String PAGE_FOOTER = "</body></html>";
#Field
public HelloService helloService;
#Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
resp.setContentType("text/html");
PrintWriter writer = resp.getWriter();
writer.println(PAGE_HEADER);
writer.println("<h1>" + helloService.createHelloMessage("World") + "</h1>");
writer.println(PAGE_FOOTER);
writer.close();
}
}
Service class:
package com.test.helloworld;
public class HelloService {
String createHelloMessage(String name) {
return "Hello " + name + "!";
}
}
Aop.xml under web-inf:
<?xml version="1.0" encoding="UTF-8"?>
<aspectj>
<aspects>
<!-- Field annotation example -->
<concrete-aspect name="com.test.aspects.MyFieldAspect"
extends="com.test.aspects.FieldAspect">
<pointcut name="getField" expression="get(#com.test.aspects.Field * *)" />
<pointcut name="setField" expression="set(#com.test.aspects.Field * *)" />
</concrete-aspect>
</aspects>
<weaver options="-verbose -showWeaveInfo" />
</aspectj>
And the POM.xml:
<?xml version="1.0"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>org.wildfly.quickstarts</groupId>
<artifactId>wildfly-helloworld</artifactId>
<version>8.0.0-SNAPSHOT</version>
<packaging>war</packaging>
<name>WildFly : Helloworld</name>
<description>WildFly : Helloworld</description>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<version.wildfly.maven.plugin>1.0.2.Final</version.wildfly.maven.plugin>
<version.jboss.spec.javaee.7.0>1.0.0.Final</version.jboss.spec.javaee.7.0>
<!-- other plugin versions -->
<version.compiler.plugin>3.1</version.compiler.plugin>
<version.war.plugin>2.1.1</version.war.plugin>
<!-- maven-compiler-plugin -->
<maven.compiler.target>1.7</maven.compiler.target>
<maven.compiler.source>1.7</maven.compiler.source>
</properties>
<dependencyManagement>
<dependencies>
<!-- Define the version of JBoss' Java EE 7 APIs we want to use -->
<!-- JBoss distributes a complete set of Java EE 7 APIs including
a Bill of Materials (BOM). A BOM specifies the versions of a "stack" (or
a collection) of artifacts. We use this here so that we always get the correct
versions of artifacts. Here we use the jboss-javaee-7.0 stack (you can
read this as the JBoss stack of the Java EE 7 APIs). You can actually
use this stack with any version of WildFly that implements Java EE 7, not
just WildFly 8! -->
<dependency>
<groupId>org.jboss.spec</groupId>
<artifactId>jboss-javaee-7.0</artifactId>
<version>1.0.2</version>
<type>pom</type>
</dependency>
</dependencies>
</dependencyManagement>
<dependencies>
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjrt</artifactId>
<version>1.8.2</version>
</dependency>
<!-- Import the CDI API, we use provided scope as the API is included in JBoss WildFly -->
<dependency>
<groupId>javax.enterprise</groupId>
<artifactId>cdi-api</artifactId>
<version>1.2</version>
</dependency>
<!-- Import the Common Annotations API (JSR-250), we use provided scope
as the API is included in JBoss WildFly -->
<dependency>
<groupId>org.jboss.spec.javax.annotation</groupId>
<artifactId>jboss-annotations-api_1.2_spec</artifactId>
<version>1.0.0.Final</version>
</dependency>
<!-- Import the Servlet API, we use provided scope as the API is included in JBoss WildFly -->
<dependency>
<groupId>org.jboss.spec.javax.servlet</groupId>
<artifactId>jboss-servlet-api_3.1_spec</artifactId>
<version>1.0.0.Final</version>
</dependency>
</dependencies>
<build>
<!-- Set the name of the war, used as the context root when the app
is deployed -->
<finalName>wildfly-helloworld</finalName>
<pluginManagement>
<plugins>
<!--This plugin's configuration is used to store Eclipse m2e settings
only. It has no influence on the Maven build itself. -->
<plugin>
<groupId>org.eclipse.m2e</groupId>
<artifactId>lifecycle-mapping</artifactId>
<version>1.0.0</version>
<configuration>
<lifecycleMappingMetadata>
<pluginExecutions>
<pluginExecution>
<pluginExecutionFilter>
<groupId>
org.apache.maven.plugins
</groupId>
<artifactId>
maven-compiler-plugin
</artifactId>
<versionRange>
[2.5.1,)
</versionRange>
<goals>
<goal>compile</goal>
</goals>
</pluginExecutionFilter>
<action>
<ignore></ignore>
</action>
</pluginExecution>
<pluginExecution>
<pluginExecutionFilter>
<groupId>
org.codehaus.mojo
</groupId>
<artifactId>
aspectj-maven-plugin
</artifactId>
<versionRange>
[1.7,)
</versionRange>
<goals>
<goal>compile</goal>
<goal>test-compile</goal>
</goals>
</pluginExecutionFilter>
<action>
<ignore></ignore>
</action>
</pluginExecution>
</pluginExecutions>
</lifecycleMappingMetadata>
</configuration>
</plugin>
</plugins>
</pluginManagement>
<plugins>
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>aspectj-maven-plugin</artifactId>
<configuration>
<complianceLevel>1.6</complianceLevel>
<source>1.6</source>
<target>1.6</target>
</configuration>
<executions>
<execution>
<goals>
<goal>compile</goal>
</goals>
</execution>
</executions>
</plugin>
<plugin>
<artifactId>maven-war-plugin</artifactId>
<version>2.6</version>
<configuration>
<!-- Java EE 7 doesn't require web.xml, Maven needs to catch up! -->
<failOnMissingWebXml>false</failOnMissingWebXml>
</configuration>
</plugin>
<!-- WildFly plugin to deploy war -->
<plugin>
<groupId>org.wildfly.plugins</groupId>
<artifactId>wildfly-maven-plugin</artifactId>
<version>1.0.2.Final</version>
<configuration>
<version>1.0.2.Final</version>
<jvmArgs>${the-whole-jvm-args}</jvmArgs>
</configuration>
</plugin>
<!-- Compiler plugin enforces Java 1.6 compatibility and activates
annotation processors -->
<plugin>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.1</version>
<configuration>
<source>1.7</source>
<target>1.7</target>
</configuration>
</plugin>
</plugins>
</build>
</project>
Used below link to configure the Load time weaving: http://wiki.eclipse.org/LTWJboss7
So after above if I start wildfly, it shows below error stack trace.
[AppClassLoader#1912a56] info AspectJ Weaver Version 1.8.5 built on Thursday Jan 29, 2015 at 01:03:58 GMT
[AppClassLoader#1912a56] info register classloader sun.misc.Launcher$AppClassLoader#1912a56
[AppClassLoader#1912a56] info using configuration file:/helloworld/target/wildfly-helloworld.war!/WEB-INF/aop.xml
[AppClassLoader#1912a56] info define aspect com.test.aspects.MyFieldAspect
[AppClassLoader#1912a56] error Cannot find parent aspect for: <concrete-aspect name='com.test.aspects.MyFieldAspect' extends='com.test.aspects.FieldAspect' perclause='null'/> in aop.xml
[AppClassLoader#1912a56] error Concrete-aspect 'com.test.aspects.MyFieldAspect' could not be registered
[AppClassLoader#1912a56] warning failure(s) registering aspects. Disabling weaver for class loader sun.misc.Launcher$AppClassLoader#1912a56
I am confused here what has been done wrong. Can someone help me to run my test program. I am learning AspectJ and LTW with wildfly and new to this all.
Thanks,
classpath was wrong.
Place the aspectjWeaver jar in WEB-INF/lib folder.
Also package aop module as create Aspects inside war module , create aspects in different module and package in jar.
I've set up a very simple "HelloWorld" service to demonstrate my problem. It uses the maven-scr-plugin to generate a service descriptor and has a pax-exam unit test. But when I try to run 'mvn clean test' it blocks for a while before giving me this error:
org.ops4j.pax.swissbox.tracker.ServiceLookupException: gave up waiting for service com.liveops.examples.osgi.helloworld.HelloWorldService
If I run 'mvn -DskipTests=true package' and then run 'mvn test' (without clean)
it works. The difference seems to be the addition of this line in my META-INF/M
ANIFEST.MF file:
Service-Component: OSGI-INF/com.liveops.examples.osgi.helloworld.internal.HelloImpl.xml
Does anyone know if there is a way to make sure this line is added earlier in the build process so that 'mvn clean test' will pass? Or is there something else I might be doing wrong?
For reference, here is the pom.xml, the service, and the unit test.
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.liveops.examples</groupId>
<artifactId>HelloWorldService</artifactId>
<version>1.0.0-SNAPSHOT</version>
<packaging>bundle</packaging>
<dependencies>
<dependency>
<groupId>org.osgi</groupId>
<artifactId>org.osgi.core</artifactId>
<version>4.3.1</version>
</dependency>
<dependency>
<groupId>javax.inject</groupId>
<artifactId>javax.inject</artifactId>
<version>1</version>
</dependency>
<dependency>
<groupId>org.ops4j.pax.exam</groupId>
<artifactId>pax-exam</artifactId>
<version>3.3.0</version>
</dependency>
<dependency>
<groupId>org.ops4j.pax.exam</groupId>
<artifactId>pax-exam-container-native</artifactId>
<version>3.3.0</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.ops4j.pax.exam</groupId>
<artifactId>pax-exam-junit4</artifactId>
<version>3.3.0</version>
</dependency>
<dependency>
<groupId>org.ops4j.pax.url</groupId>
<artifactId>pax-url-aether</artifactId>
<version>1.6.0</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.ops4j.pax.exam</groupId>
<artifactId>pax-exam-link-mvn</artifactId>
<version>3.3.0</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-simple</artifactId>
<version>1.5.8</version>
</dependency>
<dependency>
<groupId>org.apache.felix</groupId>
<artifactId>org.apache.felix.framework</artifactId>
<version>4.0.2</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.apache.felix</groupId>
<artifactId>org.apache.felix.scr.annotations</artifactId>
<version>1.9.0</version>
</dependency>
</dependencies>
<properties>
<namespace>com.liveops.examples.osgi.helloworld</namespace>
</properties>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.0</version>
<configuration>
<source>1.7</source>
<target>1.7</target>
</configuration>
</plugin>
<plugin>
<!--
| the following instructions build a simple set of public/private classes into an OSGi bundle
-->
<groupId>org.apache.felix</groupId>
<artifactId>maven-bundle-plugin</artifactId>
<version>2.3.7</version>
<extensions>true</extensions>
<configuration>
<instructions>
<Bundle-SymbolicName>${project.name}</Bundle-SymbolicName>
<Bundle-Version>${project.version}</Bundle-Version>
<!-- Bundle-Activator>${namespace}.internal.HelloActivator</Bundle-Activator -->
<!--
| assume public classes are in the top package, and private classes are under ".internal"
-->
<Export-Package>!${namespace}.internal.*,${namespace}.*;version="${project.version}"</Export-Package>
<Private-Package>${namespace}.internal.*</Private-Package>
<!--
| each module can override these defaults in their osgi.bnd file
-->
<!--_include>-osgi.bnd</_include-->
</instructions>
</configuration>
<executions>
<execution>
<id>generate-manifest</id>
<phase>process-classes</phase>
<goals>
<goal>manifest</goal>
</goals>
</execution>
</executions>
</plugin>
<plugin>
<groupId>org.apache.felix</groupId>
<artifactId>maven-scr-plugin</artifactId>
<version>1.9.0</version>
<configuration>
<supportedProjectTypes>
<supportedProjectType>jar</supportedProjectType>
<supportedProjectType>bundle</supportedProjectType>
<supportedProjectType>war</supportedProjectType>
</supportedProjectTypes>
<generateAccessors>true</generateAccessors>
<strictMode>true</strictMode>
<specVersion>1.1</specVersion>
<outputDirectory>target/classes</outputDirectory>
</configuration>
<executions>
<execution>
<id>generate-scr-scrdescriptor</id>
<goals>
<goal>scr</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>
</project>
HelloWorld Implementation class
package com.liveops.examples.osgi.helloworld.internal;
import com.liveops.examples.osgi.helloworld.HelloWorldService;
import org.apache.felix.scr.annotations.Service;
import org.apache.felix.scr.annotations.Component;
#Component
#Service(HelloWorldService.class)
public class HelloImpl implements HelloWorldService
{
public String helloWorld(String personalization)
{
return "Hello " + personalization + "!";
}
}
The unit test
package com.liveops.examples.osgi.helloworld.internal;
import com.liveops.examples.osgi.helloworld.HelloWorldService;
import junit.framework.Assert;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.ops4j.pax.exam.Option;
import org.ops4j.pax.exam.Configuration;
import org.ops4j.pax.exam.junit.PaxExam;
import org.ops4j.pax.exam.util.PathUtils;
import javax.inject.Inject;
import static org.ops4j.pax.exam.CoreOptions.*;
#RunWith(PaxExam.class)
public class HelloImplTest
{
#Inject
HelloWorldService hws;
#Configuration
public static Option[] configuration() throws Exception{
return options(
systemProperty("org.ops4j.pax.logging.DefaultServiceLog.level").value("WARN"),
mavenBundle("org.apache.felix", "org.apache.felix.scr", "1.6.2"),
bundle("reference:file:" + PathUtils.getBaseDir() + "/target/classes"),
junitBundles());
}
#Test
public void testInjection()
{
Assert.assertNotNull(hws);
}
#Test
public void testHelloWorld() throws Exception
{
Assert.assertNotNull(hws);
Assert.assertEquals("Hello UnitTest!", hws.helloWorld("UnitTest"));
}
}
Use the ProbeBuilder to enhance your tested bundle:
#ProbeBuilder
public TestProbeBuilder probeConfiguration(TestProbeBuilder probe) {
probe.setHeader("Service-Component", "OSGI-INF/com.liveops.examples.osgi.helloworld.internal.HelloImpl.xml");
return probe;
}
This most likely is all that's missing.
EDIT:
just in case you're trying to use pax-exam in the same bundle you need to take certain actions in your configuration method:
streamBundle(bundle()
.add(SomceClass.class).add("OSGI-INF/com.liveops.examples.osgi.helloworld.internal.HelloImpl.xml", new File("src/main/resources/OSGI-INF/com.liveops.examples.osgi.helloworld.internal.HelloImpl.xml")
.toURL())
.set("Service-Component", "OSGI-INF/com.liveops.examples.osgi.helloworld.internal.HelloImpl.xml")
.build()).start()
a complete sample can be found at here
I may have a fix for this, though it seems a bit in-elegant. I can explicitly add the Service-Component to the maven-bundle-plugin section of the pom file.
<plugin>
<groupId>org.apache.felix</groupId>
<artifactId>maven-bundle-plugin</artifactId>
<version>2.3.7</version>
<extensions>true</extensions>
<configuration>
<instructions>
<Bundle-SymbolicName>${project.name}</Bundle-SymbolicName>
<Bundle-Version>${project.version}</Bundle-Version>
<Export-Package>!${namespace}.internal.*,${namespace}.*;version="${project.version}"</Export-Package>
<Private-Package>${namespace}.internal.*</Private-Package>
<!--Explicitly add the components no that they can be found in the test phase -->
<Service-Component>OSGI-INF/com.liveops.examples.osgi.helloworld.internal.HelloImpl.xml</Service-Component>
</instructions>
</configuration>
<executions>
<execution>
<id>generate-manifest</id>
<phase>process-classes</phase>
<goals>
<goal>manifest</goal>
</goals>
</execution>
</executions>
</plugin>
Please let me know if anyone can think of a better way.
The Maven SCR Plugin only generates the service component descriptors but it does not include them in the manifest automatically.
So there's nothing inelegant about including a <Service-Component> instruction in the Maven Bundle Plugin configuration, that's just the documented usage.
Since the manifest header is missing, SCR does not register any services on behalf of your bundle, and that's why Pax Exam can't find the required service.