Search in sources :

Example 1 with CloudantClient

use of com.cloudant.client.api.CloudantClient in project java-cloudant by cloudant.

the class HttpIamTest method iamTokenAndCookieSuccessful.

/**
 * Test IAM token and cookie flow:
 * - GET a resource on the cloudant server
 * - Cookie jar empty, so get IAM token followed by session cookie
 * - GET now proceeds as normal, expected cookie value is sent in header
 *
 * @throws Exception
 */
@Test
public void iamTokenAndCookieSuccessful() throws Exception {
    // Request sequence
    // _iam_session request to get Cookie
    // GET request -> 200 with a Set-Cookie
    mockWebServer.enqueue(OK_IAM_COOKIE);
    mockWebServer.enqueue(new MockResponse().setResponseCode(200).setBody(hello));
    mockIamServer.enqueue(new MockResponse().setResponseCode(200).setBody(IAM_TOKEN));
    CloudantClient c = CloudantClientHelper.newMockWebServerClientBuilder(mockWebServer).iamApiKey(iamApiKey).build();
    String response = c.executeRequest(Http.GET(c.getBaseUri())).responseAsString();
    assertEquals(hello, response, "The expected response should be received");
    // cloudant mock server
    // assert that there were 2 calls
    RecordedRequest[] recordedRequests = takeN(mockWebServer, 2);
    assertEquals("/_iam_session", recordedRequests[0].getPath(), "The request should have been for /_iam_session");
    assertThat("The request body should contain the IAM token", recordedRequests[0].getBody().readString(Charset.forName("UTF-8")), containsString(IAM_TOKEN));
    // the request should have the cookie header
    assertEquals("/", recordedRequests[1].getPath(), "The request should have been for /");
    // The cookie may or may not have the session id quoted, so check both
    assertThat("The Cookie header should contain the expected session value", recordedRequests[1].getHeader("Cookie"), anyOf(containsString(iamSession(EXPECTED_OK_COOKIE)), containsString(iamSessionUnquoted(EXPECTED_OK_COOKIE))));
    // asserts on the IAM server
    // assert that there was 1 call
    RecordedRequest[] recordedIamRequests = takeN(mockIamServer, 1);
    assertEquals(iamTokenEndpoint, recordedIamRequests[0].getPath(), "The request should have been for " + "/identity/token");
    assertThat("The request body should contain the IAM API key", recordedIamRequests[0].getBody().readString(Charset.forName("UTF-8")), containsString("apikey=" + iamApiKey));
}
Also used : RecordedRequest(okhttp3.mockwebserver.RecordedRequest) MockResponse(okhttp3.mockwebserver.MockResponse) CloudantClient(com.cloudant.client.api.CloudantClient) CoreMatchers.containsString(org.hamcrest.CoreMatchers.containsString) Test(org.junit.jupiter.api.Test)

Example 2 with CloudantClient

use of com.cloudant.client.api.CloudantClient in project java-cloudant by cloudant.

the class HttpIamTest method iamRenewalFailureOnSessionCookie.

/**
 * Test IAM token and cookie flow, where session expires and subsequent session cookie fails:
 * - GET a resource on the cloudant server
 * - Cookie jar empty, so get IAM token followed by session cookie
 * - GET now proceeds as normal, expected cookie value is sent in header
 * - second GET on cloudant server, re-using session cookie
 * - third GET on cloudant server, cookie expired, get IAM token, subsequent session cookie
 * request fails, no more requests are made
 *
 * @throws Exception
 */
@Test
public void iamRenewalFailureOnSessionCookie() throws Exception {
    // Request sequence
    mockWebServer.enqueue(OK_IAM_COOKIE);
    mockWebServer.enqueue(new MockResponse().setResponseCode(200).setBody(hello));
    mockWebServer.enqueue(new MockResponse().setResponseCode(200).setBody(hello));
    // cookie expired
    mockWebServer.enqueue(new MockResponse().setResponseCode(401).setBody("{\"error\":\"credentials_expired\"}"));
    // mock 500 on cookie renewal
    mockWebServer.enqueue(new MockResponse().setResponseCode(500));
    mockIamServer.enqueue(new MockResponse().setResponseCode(200).setBody(IAM_TOKEN));
    mockIamServer.enqueue(new MockResponse().setResponseCode(200).setBody(IAM_TOKEN_2));
    CloudantClient c = CloudantClientHelper.newMockWebServerClientBuilder(mockWebServer).iamApiKey(iamApiKey).build();
    String response = c.executeRequest(Http.GET(c.getBaseUri())).responseAsString();
    assertEquals(hello, response, "The expected response should be received");
    String response2 = c.executeRequest(Http.GET(c.getBaseUri())).responseAsString();
    assertEquals(hello, response2, "The expected response should be received");
    // unhelpful
    try {
        c.executeRequest(Http.GET(c.getBaseUri())).responseAsString();
        fail("Should get CouchDbException when trying to get response");
    } catch (CouchDbException cdbe) {
        ;
    }
    // cloudant mock server
    // assert that there were 5 calls
    RecordedRequest[] recordedRequests = takeN(mockWebServer, 5);
    assertEquals("/_iam_session", recordedRequests[0].getPath(), "The request should have been for /_iam_session");
    assertThat("The request body should contain the IAM token", recordedRequests[0].getBody().readString(Charset.forName("UTF-8")), containsString(IAM_TOKEN));
    // first request
    assertEquals("/", recordedRequests[1].getPath(), "The request should have been for /");
    // The cookie may or may not have the session id quoted, so check both
    assertThat("The Cookie header should contain the expected session value", recordedRequests[1].getHeader("Cookie"), anyOf(containsString(iamSession(EXPECTED_OK_COOKIE)), containsString(iamSessionUnquoted(EXPECTED_OK_COOKIE))));
    // second request
    assertEquals("/", recordedRequests[2].getPath(), "The request should have been for /");
    // third request, will be rejected due to cookie expiry
    assertEquals("/", recordedRequests[3].getPath(), "The request should have been for /");
    // try to renew cookie but get 500
    assertEquals("/_iam_session", recordedRequests[4].getPath(), "The request should have been for /_iam_session");
    assertThat("The request body should contain the IAM token", recordedRequests[4].getBody().readString(Charset.forName("UTF-8")), containsString(IAM_TOKEN_2));
    // iam mock server
    // assert that there were 2 calls
    RecordedRequest[] recordedIamRequests = takeN(mockIamServer, 2);
    // first time, automatically fetch because cookie jar is empty
    assertEquals(iamTokenEndpoint, recordedIamRequests[0].getPath(), "The request should have been for " + "/identity/token");
    assertThat("The request body should contain the IAM API key", recordedIamRequests[0].getBody().readString(Charset.forName("UTF-8")), containsString("apikey=" + iamApiKey));
    // second time, refresh because the cloudant session cookie has expired
    assertEquals(iamTokenEndpoint, recordedIamRequests[1].getPath(), "The request should have been for " + "/identity/token");
}
Also used : RecordedRequest(okhttp3.mockwebserver.RecordedRequest) MockResponse(okhttp3.mockwebserver.MockResponse) CouchDbException(com.cloudant.client.org.lightcouch.CouchDbException) CloudantClient(com.cloudant.client.api.CloudantClient) CoreMatchers.containsString(org.hamcrest.CoreMatchers.containsString) Test(org.junit.jupiter.api.Test)

Example 3 with CloudantClient

use of com.cloudant.client.api.CloudantClient in project java-cloudant by cloudant.

the class HttpProxyTest method proxiedRequest.

/**
 * This test validates that a request can successfully traverse a proxy to our mock server.
 */
@TestTemplate
public void proxiedRequest(final boolean okUsable, final boolean useSecureProxy, final boolean useHttpsServer, final boolean useProxyAuth) throws Exception {
    // mock a 200 OK
    server.setDispatcher(new Dispatcher() {

        @Override
        public MockResponse dispatch(RecordedRequest request) throws InterruptedException {
            return new MockResponse();
        }
    });
    InetSocketAddress address = proxy.getListenAddress();
    URL proxyUrl = new URL((useSecureProxy) ? "https" : "http", address.getHostName(), address.getPort(), "/");
    ClientBuilder builder = CloudantClientHelper.newMockWebServerClientBuilder(server).proxyURL(proxyUrl);
    if (useProxyAuth) {
        builder.proxyUser(mockProxyUser).proxyPassword(mockProxyPass);
    }
    // We don't use SSL authentication for this test
    CloudantClient client = builder.disableSSLAuthentication().build();
    String response = client.executeRequest(Http.GET(client.getBaseUri())).responseAsString();
    assertTrue(response.isEmpty(), "There should be no response body on the mock response");
    // if it wasn't a 20x then an exception should have been thrown by now
    RecordedRequest request = server.takeRequest(10, TimeUnit.SECONDS);
    assertNotNull(request);
}
Also used : RecordedRequest(okhttp3.mockwebserver.RecordedRequest) MockResponse(okhttp3.mockwebserver.MockResponse) CloudantClient(com.cloudant.client.api.CloudantClient) InetSocketAddress(java.net.InetSocketAddress) Dispatcher(okhttp3.mockwebserver.Dispatcher) URL(java.net.URL) ClientBuilder(com.cloudant.client.api.ClientBuilder) TestTemplate(org.junit.jupiter.api.TestTemplate)

Example 4 with CloudantClient

use of com.cloudant.client.api.CloudantClient in project java-cloudant by cloudant.

the class HttpTest method badCredsDisablesCookie.

/**
 * Test that cookie authentication is stopped if the credentials were bad.
 *
 * @throws Exception
 */
@TestTemplate
public void badCredsDisablesCookie() throws Exception {
    mockWebServer.setDispatcher(new Dispatcher() {

        private int counter = 0;

        @Override
        public MockResponse dispatch(RecordedRequest request) throws InterruptedException {
            counter++;
            // Return a 401 for the first _session request, after that return 200 OKs
            if (counter == 1) {
                return new MockResponse().setResponseCode(401);
            } else {
                return new MockResponse().setBody("TEST");
            }
        }
    });
    CloudantClient c = CloudantClientHelper.newMockWebServerClientBuilder(mockWebServer).username("bad").password("worse").build();
    String response = c.executeRequest(Http.GET(c.getBaseUri())).responseAsString();
    assertEquals("TEST", response, "The expected response body should be received");
    // There should only be two requests: an initial auth failure followed by an ok response.
    // If the cookie interceptor keeps trying then there will be more _session requests.
    assertEquals(2, mockWebServer.getRequestCount(), "There should be 2 requests");
    assertEquals("/_session", MockWebServerResources.takeRequestWithTimeout(mockWebServer).getPath(), "The " + "first request should have been for a cookie");
    assertEquals("/", MockWebServerResources.takeRequestWithTimeout(mockWebServer).getPath(), "The " + "second request should have been for /");
    response = c.executeRequest(Http.GET(c.getBaseUri())).responseAsString();
    assertEquals("TEST", response, "The expected response body should be received");
    // Make another request, the cookie interceptor should not try again so there should only be
    // one more request.
    assertEquals(3, mockWebServer.getRequestCount(), "There should be 3 requests");
    assertEquals("/", MockWebServerResources.takeRequestWithTimeout(mockWebServer).getPath(), "The third request should have been for /");
}
Also used : RecordedRequest(okhttp3.mockwebserver.RecordedRequest) MockResponse(okhttp3.mockwebserver.MockResponse) CloudantClient(com.cloudant.client.api.CloudantClient) CoreMatchers.containsString(org.hamcrest.CoreMatchers.containsString) Dispatcher(okhttp3.mockwebserver.Dispatcher) TestTemplate(org.junit.jupiter.api.TestTemplate)

Example 5 with CloudantClient

use of com.cloudant.client.api.CloudantClient in project java-cloudant by cloudant.

the class HttpTest method testChunking.

/**
 * Test that chunking is used when input stream length is not known.
 *
 * @throws Exception
 */
@TestTemplate
public void testChunking() throws Exception {
    mockWebServer.enqueue(new MockResponse());
    final int chunkSize = 1024 * 8;
    final int chunks = 50 * 4;
    CloudantClient client = CloudantClientHelper.newMockWebServerClientBuilder(mockWebServer).build();
    // POST some large random data
    String response = client.executeRequest(Http.POST(mockWebServer.url("/").url(), "text/plain").setRequestBody(new RandomInputStreamGenerator(chunks * chunkSize))).responseAsString();
    assertTrue(response.isEmpty(), "There should be no response body on the mock response");
    assertEquals(1, mockWebServer.getRequestCount(), "There should have been 1 request");
    RecordedRequest request = MockWebServerResources.takeRequestWithTimeout(mockWebServer);
    assertNotNull(request, "The recorded request should not be null");
    assertNull(request.getHeader("Content-Length"), "There should be no Content-Length header");
    assertEquals("chunked", request.getHeader("Transfer-Encoding"), "The Transfer-Encoding should be chunked");
    // It would be nice to assert that we got the chunk sizes we were expecting, but sadly the
    // HttpURLConnection and ChunkedOutputStream only use the chunkSize as a suggestion and seem
    // to use the buffer size instead. The best assertion we can make is that we did receive
    // multiple chunks.
    assertTrue(request.getChunkSizes().size() > 1, "There should have been at least 2 chunks");
}
Also used : RecordedRequest(okhttp3.mockwebserver.RecordedRequest) MockResponse(okhttp3.mockwebserver.MockResponse) CloudantClient(com.cloudant.client.api.CloudantClient) CoreMatchers.containsString(org.hamcrest.CoreMatchers.containsString) TestTemplate(org.junit.jupiter.api.TestTemplate)

Aggregations

CloudantClient (com.cloudant.client.api.CloudantClient)47 MockResponse (okhttp3.mockwebserver.MockResponse)32 TestTemplate (org.junit.jupiter.api.TestTemplate)23 CoreMatchers.containsString (org.hamcrest.CoreMatchers.containsString)21 Test (org.junit.jupiter.api.Test)20 RecordedRequest (okhttp3.mockwebserver.RecordedRequest)19 Database (com.cloudant.client.api.Database)8 CouchDbException (com.cloudant.client.org.lightcouch.CouchDbException)7 TestTimer (com.cloudant.tests.util.TestTimer)4 URL (java.net.URL)4 TooManyRequestsException (com.cloudant.client.org.lightcouch.TooManyRequestsException)3 HttpConnection (com.cloudant.http.HttpConnection)3 HttpConnectionInterceptorContext (com.cloudant.http.HttpConnectionInterceptorContext)3 Replay429Interceptor (com.cloudant.http.interceptors.Replay429Interceptor)3 Dispatcher (okhttp3.mockwebserver.Dispatcher)3 HttpConnectionRequestInterceptor (com.cloudant.http.HttpConnectionRequestInterceptor)2 BasicAuthInterceptor (com.cloudant.http.interceptors.BasicAuthInterceptor)2 RequiresCloudant (com.cloudant.test.main.RequiresCloudant)2 RequiresCloudantService (com.cloudant.test.main.RequiresCloudantService)2 TestWithDbPerTest (com.cloudant.tests.base.TestWithDbPerTest)2