Smoke testing is the verification of functionality in a live system, be that development, test or production. Many of us are familiar with deploying an application, and clicking around to be sure nothing is obviously broken. Is the application running? Am I connecting to the database correctly? But there are many more holes that form as an application grows, and integration testing becomes critical to catching them.
Automating these smoke tests make our lives easier by allowing you to run all of the tests on every deployment. My Dropwizard application has a RESTful API, which I then write a Client API adapter in Java to call those endpoints.
The Client API is useful both for smoke testing, and for providing to client applications of an API to ease their integration. It should bundle into its own jar, as slim as possible, referencing another shared repository for the data model as the main application.
Example
REST Controller
The controller sets up the GET for a User by ID.
@Path("/api/user") @Produces(MediaType.APPLICATION_JSON) public class UserController { @GET @Path("{id}") public User get(@PathParam("id") int id) { // ...
Client API
The API class will call an endpoint in a specified environment using a Jersey Client.
public class UserAPI { private final String baseUrl; // set in constructor private ObjectMapper mapper = new ObjectMapper(); public User get(int id) { // create the Client Client client = getClient(host); // create a Builder Builder builder = client.resource(baseUrl + "/api/user/" + id).accept(MediaType.APPLICATION_JSON); // execute the GET ClientResponse response = builder.get(ClientResponse.class); // process for error/success, parse value
Smoke Test
The smoke test is a simple unit test, designed to use the API to call the running application. The baseUrl in this case should be configured, or set at runtime with a System property (-DtargetEnv=https://test:8473
with Maven)
public class UserAPITest { // make API, host should be configurable UserAPI userAPI = new UserAPI("https://localhost:8473"); @Test public void testGetUser() { User user = userAPI.get(1); assertNotNull(user); } }
Seems pretty straightforward right? Well there is one critical function you will need to have your smoke test work for http and https environments (see Dropwizard Configuration), and it will be used by all API classes — getClient
:
protected Client getClient() { ClientConfig config = new DefaultClientConfig(); try { // TrustManager will accept any certificate TrustManager[] trustAllCerts = { new X509TrustManager() { @Override public X509Certificate[] getAcceptedIssuers() { return null; } @Override public void checkClientTrusted(X509Certificate[] certs, String authType) {} @Override public void checkServerTrusted(X509Certificate[] certs, String authType) {} }}; // context will use the trust manager SSLContext ctx = SSLContext.getInstance("SSL"); ctx.init(null, trustAllCerts, new SecureRandom()); // uses the context configured for the ClientConfig config.getProperties().put(HTTPSProperties.PROPERTY_HTTPS_PROPERTIES, new HTTPSProperties(new HostnameVerifier() { @Override public boolean verify(String s, SSLSession sslSession) { // whatever your matching policy states return true; } }, ctx)); } catch (Exception e) { log.error("Failed to setup the SSL handler", e); } Client client = Client.create(config); }
Now you have a Client capable of calling an SSL application and accept a locally signed certificate.
Errors Overcome
Automated smoke testing with SSL environments can create a couple common problems:
javax.net.ssl.SSLHandshakeException: java.security.cert.CertificateException: No name matching localhost
This occurs when the certificate sent from the REST endpoint is not accepted by the API
java.lang.IllegalStateException: SSLContextImpl is not initialized
This occurs when the SSLContext init
function is not called before the Client is used.
Happy testing!