Java tutorial
/* * Copyright (c) 2015 IBM Corp. All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file * except in compliance with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software distributed under the * License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, * either express or implied. See the License for the specific language governing permissions * and limitations under the License. */ package com.cloudant.tests; import static com.cloudant.client.org.lightcouch.internal.CouchDbUtil.createPost; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertTrue; import com.cloudant.client.api.ClientBuilder; import com.cloudant.client.api.CloudantClient; import com.cloudant.client.api.Database; import com.cloudant.client.api.model.ApiKey; import com.cloudant.client.api.model.Membership; import com.cloudant.client.api.model.Task; import com.cloudant.client.org.lightcouch.CouchDbException; import com.cloudant.client.org.lightcouch.NoDocumentException; import com.cloudant.http.internal.AgentHelper; import com.cloudant.test.main.RequiresCloudant; import com.cloudant.test.main.RequiresCloudantService; import com.cloudant.test.main.RequiresDB; import com.cloudant.tests.util.CloudantClientResource; import com.cloudant.tests.util.TestLog; import com.cloudant.tests.util.Utils; import com.squareup.okhttp.mockwebserver.Dispatcher; import com.squareup.okhttp.mockwebserver.MockResponse; import com.squareup.okhttp.mockwebserver.MockWebServer; import com.squareup.okhttp.mockwebserver.RecordedRequest; import org.apache.commons.io.IOUtils; import org.junit.ClassRule; import org.junit.Test; import org.junit.experimental.categories.Category; import java.lang.reflect.Field; import java.net.ServerSocket; import java.net.Socket; import java.net.SocketTimeoutException; import java.net.URL; import java.util.List; import java.util.concurrent.TimeUnit; import javax.net.ServerSocketFactory; public class CloudantClientTests { @ClassRule public static final TestLog TEST_LOG = new TestLog(); @ClassRule public static CloudantClientResource clientResource = new CloudantClientResource(); private CloudantClient account = clientResource.get(); @Test @Category(RequiresCloudantService.class) public void apiKey() { ApiKey key = account.generateApiKey(); assertNotNull(key); assertNotNull(key.getKey()); assertNotNull(key.getPassword()); } @Test @Category(RequiresCloudant.class) public void activeTasks() { List<Task> tasks = account.getActiveTasks(); assertNotNull(tasks); } @Test @Category(RequiresCloudant.class) public void membership() { Membership mship = account.getMembership(); assertNotNull(mship); assertNotNull(mship.getClusterNodes()); assertNotNull(mship.getClusterNodes().hasNext()); assertNotNull(mship.getAllNodes()); assertNotNull(mship.getAllNodes().hasNext()); } @Test @Category(RequiresCloudant.class) public void cookieTest() { Membership membership = account.getMembership(); assertNotNull(membership); } private final String userAgentRegex = "java-cloudant/[^\\s]+ " + "\\[Java \\([^;]*;[^;]*;[^;]*\\) [^;]*;[^;]*;" + "[^;]*\\]"; /** * Assert that the User-Agent header is of the expected form. */ @Test public void testUserAgentHeaderString() { assertTrue("The value of the User-Agent header should match the format " + "\"java-cloudant/version [Java (os.arch; os.name; os.version) jvm.vendor; jvm" + ".version; jvm.runtime.version]\"", AgentHelper.USER_AGENT.matches(userAgentRegex)); } /** * Assert that requests have the User-Agent header added. This test runs a local HTTP server * process that can handle a single request to receive the request and validate the header. */ @Test public void testUserAgentHeaderIsAddedToRequest() throws Exception { MockWebServer server = new MockWebServer(); server.start(); //send back an OK 200 server.enqueue(new MockResponse()); try { //instantiating the client performs a single post request CloudantClient client = CloudantClientHelper.newMockWebServerClientBuilder(server).build(); client.executeRequest(createPost(client.getBaseUri(), null, "application/json")); //assert that the request had the expected header String userAgentHeader = server.takeRequest(10, TimeUnit.SECONDS).getHeader("User-Agent"); assertNotNull("The User-Agent header should be present on the request", userAgentHeader); assertTrue("The value of the User-Agent header value on the request should match the " + "format " + "\"java-cloudant/version [Java (os.arch; os.name; os.version) jvm" + ".vendor; jvm" + ".version; jvm.runtime.version]\"", userAgentHeader.matches(userAgentRegex)); } finally { server.shutdown(); } } /** * Test a NoDocumentException is thrown when trying an operation on a DB that doesn't exist */ @Test(expected = NoDocumentException.class) @Category(RequiresDB.class) public void nonExistentDatabaseException() { //try and get a DB that doesn't exist Database db = account.database("not_really_there", false); //try an operation against the non-existant DB db.info(); } /** * Validate that no exception bubbles up when trying to create a DB that already exists */ @Test @Category(RequiresDB.class) public void existingDatabaseCreateException() { String id = Utils.generateUUID(); String dbName = "existing" + id; try { //create a DB for this test account.createDB(dbName); //do a get with create true for the already existing DB account.database(dbName, true); } finally { //clean up the DB created by this test account.deleteDB(dbName); } } @Test public void testDefaultPorts() throws Exception { CloudantClient c = null; c = CloudantClientHelper.newTestAddressClient().build(); assertEquals("The http port should be 80", 80, c.getBaseUri().getPort()); c = CloudantClientHelper.newHttpsTestAddressClient().build(); assertEquals("The http port should be 443", 443, c.getBaseUri().getPort()); } /** * Check that the connection timeout throws a SocketTimeoutException when it can't connect * within the timeout. */ @Test(expected = SocketTimeoutException.class) public void connectionTimeout() throws Throwable { ServerSocket serverSocket = ServerSocketFactory.getDefault().createServerSocket(0, 1); //block the single connection to our server Socket socket = new Socket(); socket.connect(serverSocket.getLocalSocketAddress()); //now try to connect, but should timeout because there is no connection available try { CloudantClient c = ClientBuilder.url(new URL("http://127.0.0.1:" + serverSocket.getLocalPort())) .connectTimeout(100, TimeUnit.MILLISECONDS).build(); // Make a request c.getAllDbs(); } catch (CouchDbException e) { //unwrap the CouchDbException if (e.getCause() != null) { //whilst it would be really nice to actually assert that this was a connect //exception and not some other SocketTimeoutException there are JVM differences in //this respect (i.e. OpenJDK does not appear to distinguish between read/connect) //in its exception messages throw e.getCause(); } else { throw e; } } finally { //make sure we close the sockets IOUtils.closeQuietly(serverSocket); IOUtils.closeQuietly(socket); } } /** * Checks that the read timeout works. The test sets a read timeout of 0.25 s and the mock * server thread sleeps for twice the duration of the read timeout. If things are working * correctly then the client should see a SocketTimeoutException for the read. */ @Test(expected = SocketTimeoutException.class) public void readTimeout() throws Throwable { final Long READ_TIMEOUT = 250l; //start a simple http server MockWebServer server = new MockWebServer(); server.setDispatcher(new Dispatcher() { @Override public MockResponse dispatch(RecordedRequest request) throws InterruptedException { Thread.sleep(READ_TIMEOUT * 2); return new MockResponse(); } }); try { server.start(); try { CloudantClient c = CloudantClientHelper.newMockWebServerClientBuilder(server) .readTimeout(READ_TIMEOUT, TimeUnit.MILLISECONDS).build(); //do a call that expects a response c.getAllDbs(); } catch (CouchDbException e) { //unwrap the CouchDbException if (e.getCause() != null) { throw e.getCause(); } else { throw e; } } } finally { server.shutdown(); } } /** * This tests that a CouchDbException is thrown if the user is null, but the password is * supplied. */ @Test(expected = CouchDbException.class) public void nullUser() throws Exception { CloudantClientHelper.newTestAddressClient().password(":0-myPassword").build(); } /** * This tests that a CouchDbException is thrown if the user is supplied, but the password is * null. */ @Test(expected = CouchDbException.class) public void nullPassword() throws Exception { CloudantClientHelper.newTestAddressClient().username("user").build(); } /** * Test that user info provided in a url is correctly removed and made into user name and * password fields. */ @Test public void testUserInfoInUrl() throws Exception { ClientBuilder b = ClientBuilder.url(new URL("https://user:password@192.0.2.0")); //reflectively check (not nice, but better than having a bug) Field user = b.getClass().getDeclaredField("username"); user.setAccessible(true); assertEquals("The username should match the one provided in the URL", "user", user.get(b)); Field pass = b.getClass().getDeclaredField("password"); pass.setAccessible(true); assertEquals("The password should match the one provided in the URL", "password", pass.get(b)); CloudantClient c = b.build(); assertFalse("The URL should not contain the username", c.getBaseUri().toString().contains("user")); assertFalse("The URL should not contain the password", c.getBaseUri().toString().contains("password")); //ensure that building a URL from it does not throw any exceptions new URL(c.getBaseUri().toString()); } @Test public void sessionDeleteOnShutdown() throws Exception { MockWebServer server = new MockWebServer(); // Mock a 200 OK for the _session DELETE request server.enqueue(new MockResponse().setResponseCode(200).setBody("{\"ok\":\"true\"}")); CloudantClient c = CloudantClientHelper.newMockWebServerClientBuilder(server).build(); c.shutdown(); RecordedRequest request = server.takeRequest(10, TimeUnit.SECONDS); assertEquals("The request method should be DELETE", "DELETE", request.getMethod()); assertEquals("The request should be to the _session path", "/_session", request.getPath()); } }