com.digi.wva.internal.HttpClientTest.java Source code

Java tutorial

Introduction

Here is the source code for com.digi.wva.internal.HttpClientTest.java

Source

/*
 * This Source Code Form is subject to the terms of the Mozilla Public License, v. 2.0. If a copy of
 * the MPL was not distributed with this file, You can obtain one at http://mozilla.org/MPL/2.0/.
 *
 * Copyright (c) 2014 Digi International Inc., All Rights Reserved.
 */

package com.digi.wva.internal;

import com.digi.wva.exc.WvaHttpException;
import com.digi.wva.test_auxiliary.PassFailHttpCallback;
import com.squareup.okhttp.Authenticator;
import com.squareup.okhttp.OkHttpClient;
import com.squareup.okhttp.Request;
import com.squareup.okhttp.Response;
import com.squareup.okhttp.mockwebserver.MockResponse;
import com.squareup.okhttp.mockwebserver.MockWebServer;
import com.squareup.okhttp.mockwebserver.RecordedRequest;

import junit.framework.TestCase;

import org.json.JSONObject;

import java.io.IOException;
import java.net.Proxy;
import java.net.URL;

import javax.net.ssl.HostnameVerifier;

/**
 * Test the behavior of the WVALib HttpClient.
 */
public class HttpClientTest extends TestCase {
    public static final String TAG = "HttpClientTest";
    PassFailHttpCallback callback;
    MockWebServer server;
    HttpClient dut;

    @Override
    protected void setUp() throws Exception {
        super.setUp();

        server = new MockWebServer();
        server.start();

        callback = new PassFailHttpCallback();

        // Configure HTTP client to point to mock server
        dut = new HttpClient(server.getHostName());
        dut.useSecureHttp(false);
        dut.setHttpPort(server.getPort());
    }

    @Override
    protected void tearDown() throws Exception {
        server.shutdown();
    }

    private void verifyRequest(String requestLine, String body) {
        // Add HTTP/1.1 to request line
        requestLine += " HTTP/1.1";

        try {
            RecordedRequest request = server.takeRequest();

            assertEquals(requestLine, request.getRequestLine());

            // Test that the Accept header has json in it
            String accept = request.getHeader("Accept");
            assertTrue("No application/json in header: " + accept, accept.contains("application/json"));

            if (body != null) {
                assertEquals(body, request.getUtf8Body());
            }
        } catch (InterruptedException e) {
            e.printStackTrace();
            fail(e.getMessage());
        }
    }

    public void testHttpClient() {
        HttpClient constructorTest = new HttpClient("HOSTNAME");
        assertNotNull(constructorTest);
    }

    public void testGet() {
        server.enqueue(new MockResponse().setBody("{}"));

        dut.get("url", callback);

        PassFailHttpCallback.RecordedResponse r = callback.await();
        assertTrue(r.success);
        assertNotNull(r.response);

        verifyRequest("GET /ws/url", null);
    }

    public void testPut() {
        server.enqueue(new MockResponse().setBody("{}"));

        dut.put("url", new JSONObject(), callback);

        PassFailHttpCallback.RecordedResponse r = callback.await();
        assertTrue(r.success);
        assertNotNull(r.response);

        verifyRequest("PUT /ws/url", "{}");
    }

    /*
    public void testPutNull() {
    server.enqueue(new MockResponse().setBody("{}"));
        
    dut.put("url", null, callback);
        
    PassFailHttpCallback.RecordedResponse r = callback.await();
    assertTrue(r.success);
    assertNotNull(r.response);
        
    verifyRequest("PUT /ws/url", "");
    }
    */
    public void testDelete() {
        server.enqueue(new MockResponse().setBody("{}"));

        dut.delete("url", callback);

        PassFailHttpCallback.RecordedResponse r = callback.await();
        assertTrue(r.success);
        assertNotNull(r.response);

        verifyRequest("DELETE /ws/url", null);
    }

    public void testPost() {
        server.enqueue(new MockResponse().setBody("{}"));

        dut.post("url", new JSONObject(), callback);

        PassFailHttpCallback.RecordedResponse r = callback.await();
        assertTrue(r.success);
        assertNotNull(r.response);

        verifyRequest("POST /ws/url", "{}");
    }

    /*
    public void testPostNull() {
    server.enqueue(new MockResponse().setBody("{}"));
    dut.post("url", null, callback);
        
    PassFailHttpCallback.RecordedResponse r = callback.await();
    assertTrue(r.success);
    assertNotNull(r.response);
        
    verifyRequest("POST /ws/url", "");
    }
    */
    public void testGetAbsoluteUrl() {
        dut.setHttpPort(5001);
        dut.setHttpsPort(5002);

        String host = server.getHostName();

        // Test HTTP, HTTP port setting
        dut.useSecureHttp(false); // Use HTTP port
        String absUrl = dut.getAbsoluteUrl("xyz").toString();
        assertEquals("http://" + host + ":5001/ws/xyz", absUrl);

        dut.setHttpPort(80);
        absUrl = dut.getAbsoluteUrl("xyz").toString();
        assertEquals("http://" + host + ":80/ws/xyz", absUrl);

        // Test HTTPS, HTTPS port setting
        dut.useSecureHttp(true);
        absUrl = dut.getAbsoluteUrl("xyz").toString();
        assertEquals("https://" + host + ":5002/ws/xyz", absUrl);

        dut.setHttpsPort(443);
        absUrl = dut.getAbsoluteUrl("xyz").toString();
        assertEquals("https://" + host + ":443/ws/xyz", absUrl);

        // Malformed URL handling
        dut.setHttpsPort(-99);
        try {
            URL result = dut.getAbsoluteUrl("xyz");
            fail("Expected getAbsoluteUrl to throw when port == -99. Got: " + result.toString());
        } catch (AssertionError e) {
            assertEquals("Malformed URL: https://localhost:-99/ws/xyz", e.getMessage());
        }
    }

    public void testUnderlyingClient() {
        OkHttpClient okhttp = dut.getUnderlyingClient();

        // Hostname verifier should return true for everything
        HostnameVerifier v = okhttp.getHostnameVerifier();
        assertTrue(v.verify("foo", null));
        assertTrue(v.verify("bar", null));
        assertTrue(v.verify("https://google.c", null));
    }

    public void test400BadRequest() {
        server.enqueue(new MockResponse().setResponseCode(400));

        dut.get("some_url", callback);
        PassFailHttpCallback.RecordedResponse r = callback.await();
        assertFalse(r.success);
        assertNotNull(r.error);
        assertEquals(WvaHttpException.WvaHttpBadRequest.class, r.error.getClass());
    }

    public void test403Forbidden() {
        server.enqueue(new MockResponse().setResponseCode(403));

        dut.get("some_url", callback);
        PassFailHttpCallback.RecordedResponse r = callback.await();
        assertFalse(r.success);
        assertNotNull(r.error);
        assertEquals(WvaHttpException.WvaHttpForbidden.class, r.error.getClass());
    }

    public void test404NotFound() {
        server.enqueue(new MockResponse().setResponseCode(404));

        dut.get("some_url", callback);
        PassFailHttpCallback.RecordedResponse r = callback.await();
        assertFalse(r.success);
        assertNotNull(r.error);
        assertEquals(WvaHttpException.WvaHttpNotFound.class, r.error.getClass());
    }

    public void test414TooLong() {
        server.enqueue(new MockResponse().setResponseCode(414));

        dut.get("some_url", callback);
        PassFailHttpCallback.RecordedResponse r = callback.await();
        assertFalse(r.success);
        assertNotNull(r.error);
        assertEquals(WvaHttpException.WvaHttpRequestUriTooLong.class, r.error.getClass());
    }

    public void test500InternalServerError() {
        server.enqueue(new MockResponse().setResponseCode(500));

        dut.get("some_url", callback);
        PassFailHttpCallback.RecordedResponse r = callback.await();
        assertFalse(r.success);
        assertNotNull(r.error);
        assertEquals(WvaHttpException.WvaHttpInternalServerError.class, r.error.getClass());
    }

    public void test403ServiceUnavailable() {
        server.enqueue(new MockResponse().setResponseCode(503));

        dut.get("some_url", callback);
        PassFailHttpCallback.RecordedResponse r = callback.await();
        assertFalse(r.success);
        assertNotNull(r.error);
        assertEquals(WvaHttpException.WvaHttpServiceUnavailable.class, r.error.getClass());
    }

    public void testOtherResponseCode() {
        // Enable logging to get code coverage of request/response logging in the cases of no
        // prior responses.
        dut.setLoggingEnabled(true);
        server.enqueue(new MockResponse().setResponseCode(418)); // I'm a teapot

        dut.get("some_url", callback);
        PassFailHttpCallback.RecordedResponse r = callback.await();
        assertFalse(r.success);
        assertNotNull(r.error);
        assertEquals(WvaHttpException.class, r.error.getClass());
    }

    /*
    public void testFailure() {
    dut.get("this is an invalid url", callback);
        
    PassFailHttpCallback.RecordedResponse r = callback.await();
    assertFalse(r.success);
    assertNotNull(r.error);
    assertEquals(IOException.class, r.error.getClass());
    }
    */
    /**
     * Just for code coverage over the request/response logging and basic "is it working" test.
     * A redirect will trigger additional response logging logic.
     */
    public void testRedirect() {
        dut.setLoggingEnabled(true);

        String redirectLocation = "http://" + server.getHostName() + ":" + server.getPort() + "/some_other_url";
        // First redirect to "some_other_url"
        server.enqueue(new MockResponse().addHeader("Location", redirectLocation).setResponseCode(301));
        // Then redirect to "some_other_url2" (covers the branching on do/while over prior requests)
        server.enqueue(new MockResponse().addHeader("Location", redirectLocation + "2").setResponseCode(301));
        server.enqueue(new MockResponse().setResponseCode(200).setBody("{}"));

        dut.get("some_url", callback);

        PassFailHttpCallback.RecordedResponse r = callback.await();
        assertTrue(r.success);
        assertNull(r.error);
    }

    /**
     * Just for code coverage over the request/response logging and basic "is it working" test.
     * This will cover the code branches where the prior request was NOT a redirect.
     */
    public void testAuthChallenge() {
        dut.setLoggingEnabled(true);

        // First send an auth challenge
        server.enqueue(
                new MockResponse().addHeader("WWW-Authenticate", "Basic realm=\"foo\"").setResponseCode(401));
        // Then send an OK response
        server.enqueue(new MockResponse().setResponseCode(200).setBody("{}"));

        // Need to set up an Authenticator to handle the challenge though. But as was mentioned above,
        // this test is purely to exercise the code for a) coverage and b) assurance that it doesn't
        // error out in this case.
        dut.getUnderlyingClient().setAuthenticator(new Authenticator() {
            @Override
            public Request authenticate(Proxy proxy, Response response) throws IOException {
                // See https://github.com/square/okhttp/wiki/Recipes, "Handling authentication"
                String credentials = com.squareup.okhttp.Credentials.basic("user", "pass");
                return response.request().newBuilder().header("Authorization", credentials).build();
            }

            @Override
            public Request authenticateProxy(Proxy proxy, Response response) throws IOException {
                return null;
            }
        });
        dut.get("some_url", callback);

        PassFailHttpCallback.RecordedResponse r = callback.await();
        assertTrue(r.success);
        assertNull(r.error);
    }

    /**
     * Test the ability to set logging enabled/disabled on the HttpClient.
     * (Does not test the effect of setting this value, just verifies external API.)
     */
    public void testGetSetLoggingEnabled() {
        // Logging should default to disabled.
        assertFalse(dut.getLoggingEnabled());

        dut.setLoggingEnabled(true);
        assertTrue(dut.getLoggingEnabled());

        dut.setLoggingEnabled(false);
        assertFalse(dut.getLoggingEnabled());
    }
}