Monthly Archives: January 2014

Integration Testing A Gradle Application

Separating integration tests from unit tests is a standard best practice. We can use small, fast unit tests during development, and large, slow tests periodically to detect regression bugs and integration issues. So our build system should make it easy to run integration tests, right?

Unfortunately, integration testing with maven is not so easy. In maven, integration testing is not a first-class citizen, though as mentioned in this link you can configure it to your liking with special configuration of the failsafe plugin. There are also other ways to set up integration testing with JUnit Categories, or by using the test file name. Both of these techniques require special configuration of the surefire plugin.

These techniques seem like a lot of work (and non-standardized work, at that!) for something that should be easy to do for a build system.

Fortunately for gradle users, setting up integration tests is easy!

In the build.gradle file, with just a few lines we can define a location for integration test files and define a task to run them. The code looks like this:

sourceSets {
    // Note that just declaring this sourceset creates two configurations.
    intTest {
        java {
            compileClasspath += main.output + test.output
            runtimeClasspath += main.output + test.output
        }
    }
}

configurations {
    intTestCompile.extendsFrom testCompile
    intTestRuntime.extendsFrom testRuntime
}

task intTest(type:Test){
    description = "Run integration tests (located in src/intTest/...)."
    testClassesDir = project.sourceSets.intTest.output.classesDir
    classpath = project.sourceSets.intTest.runtimeClasspath
}

Originally when we ran “gradle test”, any test files in src/test/java will be run. Now we also have the option to run “gradle intTest” so that test files in src/intTest/java will be run. Easy, right? With the configuration given above, the integration test does not depend on test, so we can run unit tests separately from integration tests, or both together with “gradle test intTest”. Finally, the build does not depend on the integration tests, so we can build the system without necessarily running the integration tests (although we could make the build depend on passing integration tests if we wanted).

Hopefully this demonstrates the ease of configuration with gradle and encourages us to write more automated tests.

Happy testing!

Advertisements

1 Comment

Filed under Software Engineering

Presentation: Unit Testing

Recently I did a presentation on unit testing. I did a lot of reading and researching to put these together. The main thing I learned is that unit testing is not necessarily for catching bugs (although it can). It’s to make you think about your code in such a way as to prevent bugs.

See the slides for the rest of the goodies! Hopefully the presentation is enjoyable and informative on its own.

Leave a comment

Filed under Software Engineering

Using RestTemplate with Basic Auth

Recently I was trying to write integration tests using Spring’s RestTemplate to make REST calls to an integration server. The server was secured using basic auth over https, and the SSL certificate was a self-signed cert created for development use only. I wanted to use RestTemplate to retrieve JSON objects and convert them to POJO’s for asserting values in the test. However it turned out that most of the examples online did not deal with this particular scenario or were out of date. So here is how to use Spring 4’s RestTemplate with the latest Apache HTTPClient (version 4.3.1 as of this writing) over HTTPS.

One complication was that the cert was self-signed. This is easily acceptable if using curl with the “-k” option, but with RestTemplate it requires a little more work to accept the cert.

Spring’s RestTemplate integrates with Apache HttpClient, it’s just the HttpClient that needs to be configured with the username, password, and to accept an insecure cert. Here is the code:

SSLContext sslContext = SSLContexts.custom().loadTrustMaterial(null, new TrustSelfSignedStrategy()).useTLS().build();
SSLConnectionSocketFactory connectionFactory = new SSLConnectionSocketFactory(sslContext, new AllowAllHostnameVerifier());
BasicCredentialsProvider credentialsProvider = new BasicCredentialsProvider();
credentialsProvider.setCredentials(AuthScope.ANY, new UsernamePasswordCredentials("username", "mypassword"));

HttpClient httpClient = HttpClientBuilder.create()
                                        .setSSLSocketFactory(connectionFactory)
                                        .setDefaultCredentialsProvider(credentialsProvider)
                                        .build();

ClientHttpRequestFactory requestFactory = new HttpComponentsClientHttpRequestFactory(httpClient);

Finally, the request factory is used to construct a new RestTemplate which can make the call to the server.

RestTemplate template = new RestTemplate(requestFactory);
ResponseEntity<User> response = template.postForEntity("https://localhost:8000/path/to/user/1", "", User.class);
User userResponse = response.getBody();

assertEquals(1L, userResponse.getId());

Fortunately the test passes… now we can run integration tests with JUnit at will! Happy Testing!

5 Comments

Filed under Software Engineering

Setting Up HTTPS For Spring Boot

[UPDATE: See an updated technique for https with spring boot here: https://thoughtfulsoftware.wordpress.com/2015/01/25/setting-up-https-for-spring-boot-2/ We now return you to your regularly scheduled blog post]

Lack of HTTPS support in any of the spring.io guides is a problem, and people are asking questions. Fortunately, there is an answer.

There is a howto for many common tasks in spring boot, including adding support for HTTPS. The main idea is that a TomcatConnectorCustomizer in a Spring Boot application will give you a callback reference to the Connector which you can then use to customize the Tomcat connectors. With that you can apply SSL to the embedded Tomcat instance.

Let’s get started. First of all, we need a keystore. Note the -alias flag which we will use for configuration later, and the -validity flag which here makes a key valid for 10 years (3650 days).

> keytool -genkey -alias tomcat -storetype PKCS12 -keyalg RSA -keysize 2048 -keystore keystore.p12 -validity 3650
Enter keystore password:  
Re-enter new password:
What is your first and last name?
  [Unknown]:  
What is the name of your organizational unit?
  [Unknown]:  
What is the name of your organization?
  [Unknown]:  
What is the name of your City or Locality?
  [Unknown]:  
What is the name of your State or Province?
  [Unknown]:  
What is the two-letter country code for this unit?
  [Unknown]:  
Is CN=Unknown, OU=Unknown, O=Unknown, L=Unknown, ST=Unknown, C=Unknown correct?
  [no]:  yes

The contents of the keystore can then be inspected. You can inspect the store to verify the keystore type, keystore provider, and review the alias name for use in configuring your code. (Note that to view a PKCS12 keystore, you need to specify the storetype)

> keytool -list -v -keystore keystore.p12 -storetype pkcs12
Enter keystore password:  

Keystore type: PKCS12
Keystore provider: SunJSSE

Your keystore contains 1 entry

Alias name: tomcat
...

With a keystore file in place and all the necessary configuration information, we can configure our server.

The first approach shown here is to create an EmbeddedServletContainerFactory and provide it as a @Bean. According to the docs, this is a heavier solution than customizing the one provided automatically, but the code for either approach is essentially the same. At the end of the day we just need a container factor and we need to add a TomcatConnectorCustomizer.

For a little extra flair, we’re also using Spring 4’s support for Java 8 lambdas, meaning we can use lambda expressions instead of anonymous inner classes.

    @Bean
    public EmbeddedServletContainerFactory servletContainer() {
        
        // keytool -genkey -alias tomcat -storetype PKCS12 -keyalg RSA -keysize 2048 -keystore keystore.p12 -validity 3650
        // keytool -list -v -keystore keystore.p12 -storetype pkcs12
        
        // curl -u user:password -k https://127.0.0.1:9000/greeting
        
        final String keystoreFile = "/absolute/path/to/keystore.p12";
        final String keystorePass = "mypassword";
        final String keystoreType = "PKCS12";
        final String keystoreProvider = "SunJSSE";
        final String keystoreAlias = "tomcat";

        TomcatEmbeddedServletContainerFactory factory = new TomcatEmbeddedServletContainerFactory();
        factory.addConnectorCustomizers((TomcatConnectorCustomizer) (Connector con) -> {
            con.setScheme("https");
            con.setSecure(true);
            Http11NioProtocol proto = (Http11NioProtocol) con.getProtocolHandler();
            proto.setSSLEnabled(true);
            proto.setKeystoreFile(keystoreFile);
            proto.setKeystorePass(keystorePass);
            proto.setKeystoreType(keystoreType);
            proto.setProperty("keystoreProvider", keystoreProvider);
            proto.setKeyAlias(keystoreAlias);
        });

        
        return factory;
    }

The second approach shown here is what Spring recommends in the howto guide. The difference here is that we are customizing the servlet container that the framework provides, instead of creating the container ourselves and customizing it. Also in this sample we are using injected properties that were defined in the application.properties file. Finally, this code does not require us to specify the keystore provider.

    @Bean
    @Inject
    public EmbeddedServletContainerCustomizer containerCustomizer(@Value("${keystore.file}") String keystoreFile,
                                                                  @Value("${keystore.password}") String keystorePassword,
                                                                  @Value("${keystore.type}") String keystoreType,
                                                                  @Value("${keystore.alias}") String keystoreAlias) throws FileNotFoundException
    {
        final String absoluteKeystoreFile = ResourceUtils.getFile(keystoreFile).getAbsolutePath();
        
        return (ConfigurableEmbeddedServletContainerFactory factory) -> {
            TomcatEmbeddedServletContainerFactory containerFactory = (TomcatEmbeddedServletContainerFactory) factory;
            containerFactory.addConnectorCustomizers((TomcatConnectorCustomizer) (Connector connector) -> {
                connector.setSecure(true);
                connector.setScheme("https");
                connector.setAttribute("keystoreFile", absoluteKeystoreFile);
                connector.setAttribute("keystorePass", keystorePassword);
                connector.setAttribute("keystoreType", keystoreType);
                connector.setAttribute("keyAlias", keystoreAlias);
                connector.setAttribute("clientAuth", "false");
                connector.setAttribute("sslProtocol", "TLS");
                connector.setAttribute("SSLEnabled", true);
            });
        };
    }

And Voila! We can now run our application on HTTPS.

6 Comments

Filed under Software Engineering