test.java.com.cloudant.tests.CloudantClientTests Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of cloudant-client Show documentation
Show all versions of cloudant-client Show documentation
Official Cloudant client for Java
/*
* 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 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:[email protected]"));
//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());
}
}