Earlier this week, I was tasked with getting automated integration tests working in my project at Overstock.com. By automated, I mean that ability to run "mvn install" and have the following process cycled through:
Start a container
Deploy the application
Run all integration tests
Stop the container
Since it makes sense for integration tests to run in Maven's integration-test phase, I first configured the maven-surefire-plugin to skip tests in the test phase and execute them in the integration-test phase. I used the <id>default-phase</id> syntax to override the plugins' usual behavior.
<plugin>
<artifactId>maven-surefire-plugin</artifactId>
<executions>
<execution>
<id>default-test</id>
<configuration>
<excludes>
<exclude>**/*Test*.java</exclude>
</excludes>
</configuration>
</execution>
<execution>
<id>default-integration-test</id>
<phase>integration-test</phase>
<goals>
<goal>test</goal>
</goals>
<configuration>
<includes>
<include>**/*Test.java</include>
</includes>
<excludes>
<exclude>none</exclude>
<exclude>**/TestCase.java</exclude>
</excludes>
</configuration>
</execution>
</executions>
</plugin>
After I had this working, I moved onto getting the container started and stopped properly. In the past, I've done this using Cargo and it's always worked well for me. Apart from the usual setup I use in AppFuse archetypes (example pom.xml), I added a couple additional items:
Added <timeout>180000</timeout> so the container would wait up to 3 minutes for the WAR to deploy.
In configuration/properties, specified <context.path>ROOT</context.path> so the app would deploy at the / context path.
In configuration/properties, specified <cargo.protocol>https</cargo.protocol> since many existing unit tests made requests to secure resources.
I started by using Cargo with Tomcat and had to create certificate keystore in order to get Tomcat to start with SSL enabled. After getting it to start, I found the tests failed with the following errors in the logs:
javax.net.ssl.SSLHandshakeException: sun.security.validator.ValidatorException:
PKIX path building failed: sun.security.provider.certpath.SunCertPathBuilderException:
unable to find valid certification path to requested target
at com.sun.net.ssl.internal.ssl.Alerts.getSSLException(Alerts.java:174)
at com.sun.net.ssl.internal.ssl.SSLSocketImpl.fatal(SSLSocketImpl.java:1649)
Co-workers told me this was easily solved by adding my 'untrusted' cert to my JVM keystore. Once all this was working, I thought I was good to go, but found that some tests were still failing. The failures turned out to be because they were talking to http and https was the only protocol enabled. After doing some research, I discovered that Cargo doesn't support starting on both http and https ports.
So back to the drawing board I went. I ended up turning to the maven-jetty-plugin and the tomcat-maven-plugin to get the functionality I was looking for. I also automated the certificate keystore generation using the keytool-maven-plugin. Below is the extremely-verbose 95-line profiles section of my pom.xml that allows either container to be used.
Sidenote: I wonder how this same setup would look using Gradle?
<profiles>
<profile>
<id>jetty</id>
<activation>
<activeByDefault>true</activeByDefault>
</activation>
<build>
<plugins>
<plugin>
<groupId>org.mortbay.jetty</groupId>
<artifactId>maven-jetty-plugin</artifactId>
<version>6.1.26</version>
<configuration>
<contextPath>/</contextPath>
<connectors>
<connector implementation="org.mortbay.jetty.nio.SelectChannelConnector">
<!-- forwarded == true interprets x-forwarded-* headers -->
<!-- http://docs.codehaus.org/display/JETTY/Configuring+mod_proxy -->
<forwarded>true</forwarded>
<port>8080</port>
<maxIdleTime>60000</maxIdleTime>
</connector>
<connector implementation="org.mortbay.jetty.security.SslSocketConnector">
<forwarded>true</forwarded>
<port>8443</port>
<maxIdleTime>60000</maxIdleTime>
<keystore>${project.build.directory}/ssl.keystore</keystore>
<password>overstock</password>
<keyPassword>overstock</keyPassword>
</connector>
</connectors>
<stopKey>overstock</stopKey>
<stopPort>9999</stopPort>
</configuration>
<executions>
<execution>
<id>start-jetty</id>
<phase>pre-integration-test</phase>
<goals>
<goal>run-war</goal>
</goals>
<configuration>
<daemon>true</daemon>
</configuration>
</execution>
<execution>
<id>stop-jetty</id>
<phase>post-integration-test</phase>
<goals>
<goal>stop</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>
</profile>
<profile>
<id>tomcat</id>
<build>
<plugins>
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>tomcat-maven-plugin</artifactId>
<version>1.1</version>
<configuration>
<addContextWarDependencies>true</addContextWarDependencies>
<fork>true</fork>
<path>/</path>
<port>8080</port>
<httpsPort>8443</httpsPort>
<keystoreFile>${project.build.directory}/ssl.keystore</keystoreFile>
<keystorePass>overstock</keystorePass>
</configuration>
<executions>
<execution>
<id>start-tomcat</id>
<phase>pre-integration-test</phase>
<goals>
<goal>run-war</goal>
</goals>
</execution>
<execution>
<id>stop-tomcat</id>
<phase>post-integration-test</phase>
<goals>
<goal>shutdown</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>
</profile>
</profiles>
With this setup in place, I was able to automate running our integration tests by simply typing "mvn install" (for Jetty) or "mvn install -Ptomcat" (for Tomcat). For running in Hudson, it's possible I'll have to further enhance things to randomize the port and pass that into tests as a system property. The build-helper-maven-plugin and its reserve-network-port goal is a nice way to do this. Note: if you want to run more than one instance of Tomcat at a time, you might have to randomize the ajp and rmi ports to avoid collisions.
The final thing I encountered was our app didn't shutdown gracefully. Luckily, this was fixed in a newer version of our core framework and upgrading fixed the problem. Here's the explanation from an architect on the core framework team.
The hanging problem was caused by the way the framework internally aggregated statistics related to database connection usage and page response times. The aggregation runs on a separate thread but not as a daemon thread. Previously, the aggregation threads weren't being terminated on shutdown so the JVM would hang waiting for them to finish. In the new frameworks, the aggregation threads are terminated on shutdown.
Hopefully this post helps you test your secure and unsecure applications at the same time. At the same time, I'm hoping it motivates the Cargo developers to add simultaneous http and https support.
Update: In the comments, Ron Piterman recommended I use the Maven Failsafe Plugin because its designed to run integration tests while Surefire Plugin is for unit tests. I changed my configuration to the following and everything still passes. Thanks Ron!
<plugin>
<artifactId>maven-surefire-plugin</artifactId>
<version>2.7.2</version>
<configuration>
<skipTests>true</skipTests>
</configuration>
</plugin>
<plugin>
<artifactId>maven-failsafe-plugin</artifactId>
<version>2.7.2</version>
<configuration>
<includes>
<include>**/*Test.java</include>
</includes>
<excludes>
<exclude>**/TestCase.java</exclude>
</excludes>
</configuration>
<executions>
<execution>
<id>integration-test</id>
<phase>integration-test</phase>
<goals>
<goal>integration-test</goal>
</goals>
</execution>
<execution>
<id>verify</id>
<phase>verify</phase>
<goals>
<goal>verify</goal>
</goals>
</execution>
</executions>
</plugin>
Update 2: In addition to application changes to solve hanging issues, I also had to change my Jetty Plugin configuration to use a different SSL connector implementation. This also required adding the jetty-sslengine dependency, which has been renamed to jetty-ssl for Jetty 7.
<connector implementation="org.mortbay.jetty.security.SslSelectChannelConnector">
...
<dependencies>
<dependency>
<groupId>org.mortbay.jetty</groupId>
<artifactId>jetty-sslengine</artifactId>
<version>6.1.26</version>
</dependency>
</dependencies
转载:http://raibledesigns.com/rd/entry/integration_testing_with_http_https
相关推荐
Title: Android Application Development with Maven Author: Patroklos Papapetrou Length: 175 pages Edition: 1 Language: English Publisher: Packt Publishing Publication Date: 2015-02-27 ISBN-10: ...
In terms of capabilities, Maven is an improvement to Apache Ant-thanks to numerous plug-ins and built-in integration with unit testing frameworks such as JUnit. Tired of writing the same build logic ...
Build your Xtext DSLs easily with Maven/Tycho and Gradle; Write a code generator and an interpreter for a DSL; Explore the Xtext scoping mechanism for symbol resolution; Test most aspects of the DSL ...
《Testing with Junit》这本书是Java开发者们进行单元测试的重要参考资料。Junit是Java编程语言中最广泛使用的单元测试框架,它允许程序员对代码进行自动化测试,确保代码的正确性和稳定性。下面将详细介绍Junit及其...
Testing in Scala starts with an introduction of the Scala programming language, explains why project infrastructure is critical, and provides compelling reasons to use Scala testing frameworks to not ...
They then explain how to automate the testing process using JUnit, Cactus, and other tools, and to enhance project management and continuous integration through Maven and AntHill. Finally, they show ...
They then explain how to automate the testing process using JUnit, Cactus, and other tools, and to enhance project management and continuous integration through Maven and AntHill. Finally, they show ...
They then explain how to automate the testing process using JUnit, Cactus, and other tools, and to enhance project management and continuous integration through Maven and AntHill. Finally, they show ...
They then explain how to automate the testing process using JUnit, Cactus, and other tools, and to enhance project management and continuous integration through Maven and AntHill. Finally, they show ...
You will then explore the relationship between Jenkins builds and Maven pom.xml. Then, you will learn how to use plugins to display code metrics and fail builds to improve quality, followed by how to...
Implement build automation and continuous integration with Gradle, Maven, and Jenkins Perform static code reviews with SonarQube and repositories to store build artifacts Establish automated GUI and ...
In terms of capabilities, Maven is an improvement to Apache Ant-thanks to numerous plug-ins and built-in integration with unit testing frameworks such as JUnit. Tired of writing the same build logic ...
Along the way, it touches on advanced topics like testing, continuous integration, and monitoring code quality. You’ll also explore tasks like setting up your target environment and deploying your ...
- **Integration Testing**: Discussion on integrating TDD with continuous integration (CI) systems to automate testing and deployment processes. **12. Build and Continuous Integration** - **Overview...
with service discovery and create simple and more advanced routing and filtering rules. Chapter 9, Distributed Logging and Tracing, will introduce some popular tools for collecting and analizing ...