Archive for the ‘maven 2’ Category
« Older EntriesTesting SSL (HTTPS) clients with Junit and Jetty
Wednesday, July 14th, 2010
Posted in: https, junit, ssl, unit test J2EE, java, maven 2, open source.
I recently ran into a situation where a web service client had issues when invoking a webservice via HTTPS. To reproduce, I needed a lightweight, JUnit-based test to reproduce the problem and write a regression test. Here is how I got it to work:
First, I used the basic HTTP test setup. Now however, I needed Jetty to provide a HTTPS connector. For this to work, Jetty – just like any other webserver, such as apache – needs a server certificate and a private key in a keystore. To create the keystore, I simply followed the excellent Jetty SSL guide. Namingly, I did this (using Ubuntu, see the above link for alternatives):
openssl genrsa -des3 -out jetty.key openssl req -new -x509 -key jetty.key -out jetty.crt openssl pkcs12 -inkey jetty.key -in jetty.crt -export -out jetty.pkcs12 $JAVA_HOME/bin/keytool -importkeystore -srckeystore jetty.pkcs12 -srcstoretype PKCS12 -destkeystore keystore
Once I had the keystore set up, I placed it in the src/main/resources folder (the root of the classpath, in case you’re not a maven user) and extended the HttpTestServer like so:
import java.net.URL;
import org.junit.Ignore;
import org.mortbay.jetty.Connector;
import org.mortbay.jetty.security.SslSocketConnector;
/**
* A test server for testing SSL requests.
*
* @author Olaf Otto
*/
@Ignore
public class SslTestServer extends HttpTestServer {
private static final int HTTPS_PORT = 50443;
public SslTestServer() {
}
public SslTestServer(String mockData) {
super(mockData);
}
@Override
protected void configureServer() {
super.configureServer();
Connector secureConnector = createSecureConnector();
getServer().addConnector(secureConnector);
}
private Connector createSecureConnector() {
SslSocketConnector connector = new SslSocketConnector();
connector.setPort(HTTPS_PORT);
URL keystoreUrl = getClass().getClassLoader().getResource("keystore");
connector.setKeystore(keystoreUrl.getFile());
connector.setKeyPassword("test");
return connector;
}
public static void main(String[] args) {
SslTestServer server = new SslTestServer();
try {
server.start();
} catch (Exception e) {
throw new RuntimeException(e);
}
}
}
(I added the @Ignore annotation as I placed the class in the test sources folder, though it’s not a test…)
You might use it in your JUnit-based test like so:
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
/**
* @author Olaf Otto
*/
public class MySslTest {
private SslTestServer _server;
@Before
public void startServer() throws Exception {
_server = new SslTestServer();
_server.start();
}
@After
public void stopServer() throws Exception {
_server.stop();
}
@Test
public void mySsltest() {
_server.setMockResponseData("<xml>My client expects this response</xml>");
// Perform tests on port 50443...
}
}
Here is the whole package as a maven 2 project (including the keystore with a self-signed certificate). Download, unzip, and give it a try (mvn test).
Lightweight testing of (webservice) HTTP clients with JUnit and Jetty
Wednesday, July 14th, 2010
Posted in: http clients, junit, test, webservices J2EE, java, maven 2, open source.
If you’re working with webservice clients you will certainly have noticed the complexity of integration-testing your webservice clients. Building webservice clients can already be quite a complex task, but providing a mock-up webservice backend delivering useful test responses is quite often just to much work, if not impossible, since many web service backends are very complex constructs. Furthermore, setting up a backend for each integration test consumes valuable build time.
As an alternative, one may simply replace the backend with a mock HTTP server that does one thing: deliver the expected webserver response – i.e. XML data – when called by the client. All you need to set this up is a HTTP server and a pre-recorded service response (quite often this comes with WS client specifications). If you don’t have this data, you can record it, for example using a proxy server in between your WS client and a real WS backend, or a tool such as wireshark.
The recorded XML response thus represents your assumptions against which you test the client. This makes your tests fast, lightweight and a lot better to understand.
Here is my Jetty-based test HTTP server:
package de.sysbsb.test;
import static javax.servlet.http.HttpServletResponse.SC_OK;
import static org.apache.commons.io.IOUtils.write;
import java.io.IOException;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.apache.commons.io.IOUtils;
import org.junit.Ignore;
import org.mortbay.jetty.Handler;
import org.mortbay.jetty.HttpConnection;
import org.mortbay.jetty.Request;
import org.mortbay.jetty.Server;
import org.mortbay.jetty.handler.AbstractHandler;
/**
* A server for answering HTTP requests with test response data.
*
* @author Olaf Otto
*/
@Ignore
public class HttpTestServer {
public static final int HTTP_PORT = 50036;
private Server _server;
private String _responseBody;
private String _requestBody;
private String _mockResponseData;
public HttpTestServer() {
}
public HttpTestServer(String mockData) {
setMockResponseData(mockData);
}
public void start() throws Exception {
configureServer();
startServer();
}
private void startServer() throws Exception {
_server.start();
}
protected void configureServer() {
_server = new Server(HTTP_PORT);
_server.setHandler(getMockHandler());
}
/**
* Creates an {@link AbstractHandler handler} returning an arbitrary String as a response.
*
* @return never <code>null</code>.
*/
public Handler getMockHandler() {
Handler handler = new AbstractHandler() {
public void handle(String target, HttpServletRequest request, HttpServletResponse response, int dispatch) throws IOException, ServletException {
Request baseRequest = request instanceof Request ? (Request) request : HttpConnection.getCurrentConnection().getRequest();
setResponseBody(getMockResponseData());
setRequestBody(IOUtils.toString(baseRequest.getInputStream()));
response.setStatus(SC_OK);
response.setContentType("text/xml;charset=utf-8");
write(getResponseBody(), response.getOutputStream());
baseRequest.setHandled(true);
}
};
return handler;
}
public void stop() throws Exception {
_server.stop();
}
public void setResponseBody(String responseBody) {
_responseBody = responseBody;
}
public String getResponseBody() {
return _responseBody;
}
public void setRequestBody(String requestBody) {
_requestBody = requestBody;
}
public String getRequestBody() {
return _requestBody;
}
public static void main(String[] args) {
HttpTestServer server = new HttpTestServer();
try {
server.start();
} catch (Exception e) {
throw new RuntimeException(e);
}
}
public void setMockResponseData(String mockResponseData) {
_mockResponseData = mockResponseData;
}
public String getMockResponseData() {
return _mockResponseData;
}
protected Server getServer() {
return _server;
}
}
You can use it in a JUnit test like so:
package de.sysbsb.test;
import java.io.IOException;
import java.io.InputStream;
import org.apache.commons.io.IOUtils;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
/**
* @author Olaf Otto
*/
public class MyClientTest {
private HttpTestServer _server;
@Before
public void startTestServer() throws Exception {
_server = new HttpTestServer();
_server.start();
}
@After
public void stopTestServer() throws Exception {
_server.stop();
}
@Test
public void someClientTest() throws IOException {
_server.setMockResponseData("<xml><testdata>hello, world</testdata></xml>");
// or as a much more elegant alternative:
_server.setMockResponseData(getRecordedResponse("testdata.xml"));
// run your client tests, using the HttpTestServer.HTTP_PORT
}
private String getRecordedResponse(String recordedResponseFile) throws IOException {
InputStream testDataStream = getClass().getClassLoader().getResourceAsStream(recordedResponseFile);
return IOUtils.toString(testDataStream);
}
}
Here are is the HTTP test server and a JUnit test example as a maven 2 project.
No CommentsPer-assembly filtering with the maven-assembly-plugin
Monday, January 18th, 2010
Posted in: maven 2, open source.
The maven assembly plugin is an extremely powerful tool when it comes to creating custom distributions (aka assemblies) of your artifacts for individual platforms etc. However, the ability to create multiple variants of an artifact within a single build conflicts with the standard maven approach of using multiple build profiles and executing a single build for each profile to generate artifact variants.
This also means that mavens resource filtering is not very useful for individual assemblies, since you can only replace placeholders such as ${someValue} with the same value for all assemblies (since resources are only filtered once, using the active profile(s), for all assemblies).
You can, however, configure the maven assembly plugin to use individual filter property files for each assembly using the <execution> section of the plugin configuration, like so:
<plugin>
<artifactId>maven-assembly-plugin</artifactId>
<version>2.2-beta-5</version>
<executions>
<execution>
<id>production</id>
<goals>
<goal>single</goal>
</goals>
<configuration>
<filters>
<filter>${project.basedir}/src/main/assembly/production.properties</filter>
</filters>
<finalName>${artifactId}-production-${version}</finalName>
<ignoreDirFormatExtensions>true</ignoreDirFormatExtensions>
<descriptors>
<descriptor>src/main/assembly/assembly.xml</descriptor>
</descriptors>
</configuration>
<phase>package</phase>
</execution>
<execution>
<id>integration</id>
<goals>
<goal>single</goal>
</goals>
<configuration>
<filters>
<filter>${project.basedir}/src/main/assembly/integration.properties</filter>
</filters>
<finalName>${artifactId}-integration-${version}</finalName>
<ignoreDirFormatExtensions>true</ignoreDirFormatExtensions>
<descriptors>
<descriptor>src/main/assembly/assembly.xml</descriptor>
</descriptors>
</configuration>
<phase>package</phase>
</execution>
</executions>
</plugin>
This snippet uses the same assembly descriptor (you can use any assembly descriptor, actually) to build individual artifacts for production and integration. Note that the ${project.basedir}/ prefix is a workaround for MASSEMBLY-150 and is nedded to avoid a nasty Failed to create assembly: Error filtering file ... Error loading property file 'src/main/...' error when executing the mojo from outside the module directory (say, for instance, in a mvn release:prepare…).
Filtering must be enabled in the assembly descriptor, like so:
<?xml version="1.0" encoding="UTF-8"?>
<assembly xmlns="http://maven.apache.org/xsd/assembly"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/xsd/assembly http://maven.apache.org/xsd/assembly-1.1.1.xsd">
...
<fileSets>
<fileSet>
<filtered>true</filtered>
...
</fileSet>
</fileSets>
</assembly>
Thanks to John Casey for suggesting this in MASSEMBLY-430!
No CommentsRunning mvn:release with Subversion 1.5.x
Monday, March 23rd, 2009
Posted in: J2EE, SCM, System engineering, java, maven 2, open source, subversion.
When attempting to prepare a release using maven and the maven-release-plugin, you are currently very likely to see your build fail with a message such as:
[INFO] Executing: svn --non-interactive copy --file /tmp/...commit . https://subversion..../tags/...
[INFO] Working directory: ...
[INFO] ------------------------------------------------------------------------
[ERROR] BUILD FAILURE
[INFO] ------------------------------------------------------------------------
[INFO] Unable to tag SCM
Provider message:
The svn tag command failed.
Command output:
svn: Commit failed (details follow):
svn: File '...' already exists
If you do, you are using subversion 1.5.x which no longer supports tagging from a local working copy, thus causing the unfortunately very misleading error message.
This is a known issue of the subversion sourcecode management (SCM) and there is a simple workaround:
Read the rest of “Running mvn:release with Subversion 1.5.x”
Maven, Surefire, remote debugging and the -javaagent switch
Monday, February 2nd, 2009
Posted in: J2EE, java, maven 2, spring.
When using maven surefire in conjunction with remote debugging (mvnDebug, for instance)
it seems necessary to disable forking of the test executions into separate processes, as the remote debugging works process wise. This is usually done by setting the the fork mode to never, e.g. by specifying -DforkMode=never on the command line.
This is, however, a misunderstanding. mvnDebug is there to enable debugging of the maven process and not of the surefire execution – and disabling forking may have various side effects. One of those is the use of Java agents. When using agents, e.g. for loadtime-weaving in the Spring Framework, one often specifies a -javaagent: as a JVM argument for surefire:
Read the rest of “Maven, Surefire, remote debugging and the -javaagent switch”
Repository search for maven artifacts
Monday, November 10th, 2008
Posted in: java, maven 2, open source.
Most of the maven users know the site www.mvnrepository.com which provides a nice lookup of maven artefacts.
Now there is also a newer site, www.mvnbrowser.com which currently performs better than mvnrepository. In addition, you can lookup repositories actually containing your desired artifact – now that’s sweet!
OutOfMemoryError using findbugs & continuum – and how to fix it.
Monday, April 21st, 2008
Posted in: continuum, java, maven 2.
When using findbugs through the findbugs maven plugin, one is very likely to see the maven build in continuum fail with an OutOfMemory-Exception like this:
Read the rest of “OutOfMemoryError using findbugs & continuum – and how to fix it.”
ContinuumBuildCancelledException in continuum
Monday, April 21st, 2008
Posted in: continuum, java, maven 2.
Users of continuum might see their builds fail with the following exception when running a little more voluminous build:
org.apache.maven.continuum.execution.ContinuumBuildCancelledException: The build was cancelled
Read the rest of "ContinuumBuildCancelledException in continuum"
Configuring custom username for maven’s scm with subversion and ssh
Monday, April 21st, 2008
Posted in: System engineering, continuum, java, maven 2, subversion.
I just stumbled over a nice little problem: When using the maven 2 changelog plugin, it automatically uses the configured <scm> settings and attempts to fetch the change history with them.
Unfortunately, such a setting usually does not contain a username, since this has to be provided by the actual team member connecting to version control.
Neither did i have any intention to configure a placeholder into the scm section, forcing the developers to mess with the maven settings.xml in order to provide their own username.
Luckily, after searching a while, i found a proper solution.
SSH allows an optional per-host specific username setting to be placed in a file called “config” located in the user’s .ssh directory, for example
File: ~/.ssh/config
Host my.host.name
User myusername
Thanks to Chad Humphries for posting the Solution on programming is hard.
It really wasn’t…
maven autocompletion für die shell (und windows)
Wednesday, March 26th, 2008
Posted in: System engineering, java, maven 2, ubuntu.
Beim Arbeiten mit maven stört die fehlende automatische Vervollständigung auf der Kommadozeile, insbesondere wenn man den Komfort einer ordentlichen unix-shell gewähnt ist. Doch dem kann abgeholfen werden. Aktuelle Linux-Distributionen (und unter Windows CYGWIN) besitzen mit bash-completion eine einfache Schnittstelle zum Erweitern der Autocompletion.
Read the rest of “maven autocompletion für die shell (und windows)”
