I have a runnable jar that I want to run in a new process before my integration test start (on pre-integration-test
) and get it terminated after my integration tests finish (on post-integration-test
).
One of the things I could use is maven-antrun-plugin or exec-maven-plugin to start new process on pre-integration-test
but how do I terminate it?
Maybe there is a better solution for what I am trying to achieve?
PS: I build my project both on Windows and Linux, so portability matters for me.
You can use maven-process-plugin open sourced by BV to start and stop any process in pre and post-integration phase respectively. There is an example in the readme that does exactly what you want (start a runnable jar). Hope that helps.
The main idea is to write a maven plugin with two goals - start, and stop. Start runs in your pre-integration-phase and runs any process you would like to run. Java's process builder can be used to start processes like running jars, etc. Store the started Process in a datastructure such as a Map or a Stack. 'Stop' will stop all the processes it has started. Since this is such a generic problem, I would recommend the above plugin for starting and stopping any processes easily for your integration tests. Simply add the following plugin:
<plugin>
<groupId>com.bazaarvoice.maven.plugins</groupId>
<artifactId>process-exec-maven-plugin</artifactId>
<version>0.4</version>
<executions>
<!--Start process-->
<execution>
<id>start-jar</id>
<phase>pre-integration-test</phase>
<goals><goal>start</goal></goals>
<configuration>
<workingDir>app</workingDir>
<arguments>
<argument>java</argument>
<argument>-jar</argument>
<argument>app.jar</argument>
</arguments>
</configuration>
</execution>
<!--Stop Process-->
<execution>
<id>stop-jar-process</id>
<phase>post-integration-test</phase>
<goals><goal>stop-all</goal></goals>
</execution>
</executions>
</plugin>
I have solved this using maven-antrun-plugin.
If your background process is java process you can use the java ant target and give it a stop timeout. If you know that your integration tests will get over say after N seconds, fork & spawn the process and stop the process after a timeout (N)
<plugin>
<artifactId>maven-antrun-plugin</artifactId>
<version>1.6</version>
<executions>
<execution>
<id>start-my-Application</id>
<phase>pre-integration-test</phase>
<goals>
<goal>run</goal>
</goals>
<configuration>
<target>
<java jar="target/myapp-${project.version}.jar"
spawn="true"
fork="true"
timeout="120">
<sysproperty key="env" value="test" />
<arg value="--xyz" /> <arg value="123" />
</java>
</target>
</configuration>
</execution>
</executions>
</plugin>
If this was Linux only, I'd write the PID to a file and then just kill the process using this PID later.
My guess is that you can achieve something similar on Windows but you'd need a couple of non-standard tools.
The alternative is to open a socket in the new process and listen for a kill command on this socket. That works on all platforms but you need to modify the JAR.
Note: If you need to run several the integration tests in parallel, this will also cause problems.
The easiest way is to include some kind of stop mechanism in your external jar (compare to the stop port of tomcat).
That way you would not need to handle PIDs or anything.
The easiest, and most resource saving way would be to simply open a server socket on a predefined (overridable) port.
Kill it by using call bash
<!--Kill the started process.-->
<target>
<exec executable="bash"
dir="${project.build.directory}"
spawn="false">
<arg value="-c"/>
<arg value="ps ax | grep -i '${project.artifactId}' | awk 'NR==1{print $1}' | xargs kill -SIGTERM"/>
</exec>
</target>