Skip to content

Commit

Permalink
Move more tests over to the MockClient
Browse files Browse the repository at this point in the history
And add a basic test of some of the MockRequests (just to
verify that they are detected and executed). Fixup a bug
in the HTTP mock request that wouldn't properly fixup
commands with space in them.

Change-Id: Ib10fb283051daf4e9794b9c7d2a86d482266944a
Reviewed-on: http://review.couchbase.org/27909
Reviewed-by: Mark Nunberg <mnunberg@haskalah.org>
Tested-by: Trond Norbye <trond.norbye@gmail.com>
  • Loading branch information
trondn committed Aug 3, 2013
1 parent 9ec1bfc commit 8dc7b2d
Show file tree
Hide file tree
Showing 7 changed files with 93 additions and 201 deletions.
40 changes: 40 additions & 0 deletions src/main/java/org/couchbase/mock/client/EndureRequest.java
@@ -0,0 +1,40 @@
/*
* Copyright 2013 Couchbase, Inc.
*
* 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 org.couchbase.mock.client;

public class EndureRequest extends MockRequest {
/**
* EndureRequest is used to fake the persistence of a key-value pair
* on a number of nodes.
*
* @param key The key to endure
* @param value An optional value
* @param onMaster Should it be persisted on the master?
* @param numReplicas THe number of replicas to persist it
*/
public EndureRequest(String key, String value, boolean onMaster, int numReplicas) {
super();
command.put("command", "endure");

payload.put("Key", key);
if (value != null && !value.isEmpty()) {
payload.put("Value", value);
}
payload.put("OnMaster", onMaster);
payload.put("OnReplicas", numReplicas);
command.put("payload", payload);
}
}
Expand Up @@ -49,7 +49,7 @@ private URL buildRequestUri(MockRequest request) throws IOException {
.append(":")
.append(this.restAddress.getPort())
.append("/mock/")
.append(request.getName())
.append(URLEncoder.encode(request.getName(), "UTF-8"))
.append("?");
appendPayload(sb, request.getPayload());
return new URL(sb.toString());
Expand Down
Expand Up @@ -65,21 +65,23 @@ private static void registerClass(MockCommand.Command cmd, Class cls) {
// Instance members
private final CouchbaseMock mock;

public MockCommand getCommand(String commandString, JsonObject payload) {
public MockCommand getCommand(String command, JsonObject payload) {
MockCommand obj;

if (!commandMap.containsKey(commandString.toUpperCase())) {
throw new CommandNotFoundException("Unknown command: " + commandString);
command = command.replaceAll(" ", "_").toUpperCase();

if (!commandMap.containsKey(command)) {
throw new CommandNotFoundException("Unknown command: " + command);
}

MockCommand.Command cmd;
Class cls;

try {
cmd = MockCommand.Command.valueOf(commandString.toUpperCase());
cmd = MockCommand.Command.valueOf(command.toUpperCase());

} catch (IllegalArgumentException e) {
throw new CommandNotFoundException("No such command: " + commandString, e);
throw new CommandNotFoundException("No such command: " + command, e);
}

cls = classMap.get(cmd);
Expand Down Expand Up @@ -128,7 +130,7 @@ public String processInput(String input) {
return "{ \"status\" : \"fail\", \"error\" : \"Failed to parse input\" }";
}

String command = object.get("command").getAsString().replaceAll(" ", "_");
String command = object.get("command").getAsString();
JsonObject payload;
if (!object.has("payload")) {
payload = new JsonObject();
Expand Down
6 changes: 2 additions & 4 deletions src/main/java/org/couchbase/mock/http/ControlHandler.java
Expand Up @@ -120,10 +120,8 @@ private void _handle(HttpExchange exchange) throws IOException {
}

JsonObject payload = parseQueryParams(exchange);
String cmdStr = components[1];

MockCommand cmd = dispatcher.getCommand(
cmdStr, payload);
String cmdStr = URLDecoder.decode(components[1], "UTF-8");
MockCommand cmd = dispatcher.getCommand(cmdStr, payload);

byte[] response = cmd.getResponse().getBytes();

Expand Down
78 changes: 14 additions & 64 deletions src/test/java/org/couchbase/mock/client/ClientBaseTest.java
Expand Up @@ -41,72 +41,20 @@
*/
public abstract class ClientBaseTest extends TestCase {
protected final BucketConfiguration bucketConfiguration = new BucketConfiguration();
protected BufferedReader harakiriInput;
protected OutputStream harakiriOutput;

public ClientBaseTest() {}
protected MockClient mockClient;
protected CouchbaseMock couchbaseMock;

protected final CouchbaseConnectionFactoryBuilder cfb = new CouchbaseConnectionFactoryBuilder();
protected CouchbaseClient client;
protected CouchbaseConnectionFactory connectionFactory;
protected CouchbaseMock mock;

public ClientBaseTest() {}

protected MemcachedNode getMasterForKey(String key) {
VBucketNodeLocator locator = (VBucketNodeLocator) client.getNodeLocator();
return locator.getPrimary(key);
}


private interface Listener extends Runnable {
public Socket getClientSocket();
}

private void setupHarakiri() throws Exception {
final ServerSocket sock = new ServerSocket(0);
final int port = sock.getLocalPort();

Listener listener = new Listener() {
public Socket clientSocket = null;

@Override public Socket getClientSocket() {
return clientSocket;
}

@Override public void run() {
try {
clientSocket = sock.accept();
} catch (IOException e) {
e.printStackTrace();
}
}
};

Thread listenThread = new Thread(listener);
String hostString = sock.getInetAddress().getHostAddress() + ":" + port;

mock.setupHarakiriMonitor(hostString, false);
listenThread.start();
listenThread.join();
Socket harakiriConnection = listener.getClientSocket();
if (harakiriConnection == null) {
throw new IOException("Couldn't get client socket");
}

harakiriInput = new BufferedReader(
new InputStreamReader(harakiriConnection.getInputStream()));
harakiriOutput = harakiriConnection.getOutputStream();

/**
* We need to negotiate the port now.
*/
StringBuilder sb = new StringBuilder();
char c;
while ( (c = (char)harakiriInput.read()) != '\0' ) {
sb.append(c);
}
assertEquals(Integer.parseInt(sb.toString()), mock.getHttpPort());
}

// Don't make the client flood the screen with log messages..
static {
System.setProperty("net.spy.log.LoggerImpl", "net.spy.memcached.compat.log.SunLogger");
Expand All @@ -124,23 +72,25 @@ protected void setUp() throws Exception {
bucketConfiguration.type = BucketType.COUCHBASE;
ArrayList configList = new ArrayList<BucketConfiguration>();
configList.add(bucketConfiguration);
mock = new CouchbaseMock(0, configList);
mock.start();
mock.waitForStartup();
setupHarakiri();
couchbaseMock = new CouchbaseMock(0, configList);
couchbaseMock.start();
couchbaseMock.waitForStartup();

mockClient = new MockClient(new InetSocketAddress("localhost", 0));
couchbaseMock.setupHarakiriMonitor("localhost:" + mockClient.getPort(), false);
mockClient.negotiate();

List<URI> uriList = new ArrayList<URI>();
uriList.add(new URI("http", null, "localhost", mock.getHttpPort(), "/pools", "", ""));
uriList.add(new URI("http", null, "localhost", couchbaseMock.getHttpPort(), "/pools", "", ""));
connectionFactory = cfb.buildCouchbaseConnection(uriList, bucketConfiguration.name, bucketConfiguration.password);
client = new CouchbaseClient(connectionFactory);
}

@Override
protected void tearDown() throws Exception {
client.shutdown();
mock.stop();
try { harakiriInput.close();} catch (IOException e) {}
try { harakiriOutput.close(); } catch (IOException e) {}
couchbaseMock.stop();
mockClient.shutdown();
super.tearDown();
}
}
4 changes: 1 addition & 3 deletions src/test/java/org/couchbase/mock/client/ClientTest.java
Expand Up @@ -111,9 +111,7 @@ public void testTTL() throws Exception {
String key = "ttl_key";
OperationFuture ft = client.set(key, 1, key);
ft.get();
harakiriOutput.write("{ \"command\" : \"time travel\", \"payload\" : { \"Offset\" : 2 }}\n".getBytes());
String response = harakiriInput.readLine();
assertEquals("{\"status\":\"ok\"}", response);
assertTrue(mockClient.request(new TimeTravelRequest(2)).isOk());
assertNull(client.get(key));
ft = client.set(key, 10, key);
ft.get();
Expand Down
150 changes: 27 additions & 123 deletions src/test/java/org/couchbase/mock/client/MockAPITest.java
Expand Up @@ -15,146 +15,50 @@
*/
package org.couchbase.mock.client;

import com.google.gson.Gson;
import com.google.gson.JsonElement;
import com.google.gson.JsonObject;
import java.net.HttpURLConnection;
import java.net.URL;
import java.net.URLEncoder;
import java.util.HashMap;
import java.util.Map;
import java.io.IOException;
import java.net.InetSocketAddress;

/**
* Tests for the "extended" Mock API.
*
* @author Mark Nunberg <mnunberg@haskalah.org>
*/
public class MockAPITest extends ClientBaseTest {
MockHttpClient mockHttpClient;

protected class Command {
Map<String,Object> commandMap = new HashMap<String, Object>();
Map<String,Object> payload = new HashMap<String, Object>();

void setName(String name) {
commandMap.put("command", name);
}

String getName() {
return (String)commandMap.get("command");
}

void set(String param, Object value) {
payload.put(param, value);
}

void clear() {
commandMap.clear();
payload.clear();
commandMap.put("payload", payload);
}

public Command() {
commandMap.put("payload", payload);
}
}

private interface CommandSender {
JsonObject transact(Command cmd) throws Exception;
@Override
protected void setUp() throws Exception {
super.setUp();
mockHttpClient = new MockHttpClient(new InetSocketAddress("localhost", mockClient.getRestPort()));
}


private static Gson gs = new Gson();

protected JsonObject jsonLineTxn(Command command) throws Exception {
harakiriOutput.write(gs.toJson(command.commandMap).getBytes());
harakiriOutput.write('\n');

String line = harakiriInput.readLine();
assertNotNull(line);

JsonObject ret = gs.fromJson(line, JsonObject.class);
assertNotNull(ret);

return ret;
public void testEndure() throws IOException {
assertTrue(mockClient.request(new EndureRequest("key", "value", true, 2)).isOk());
assertTrue(mockHttpClient.request(new EndureRequest("key", "value", true, 2)).isOk());
}

protected JsonObject jsonHttpTxn(Command command) throws Exception {
StringBuilder sb = new StringBuilder();
sb.append("http://localhost:")
.append(mock.getHttpPort())
.append("/mock/")
.append(command.getName())
.append("?");

for (Map.Entry<String,Object> kv : command.payload.entrySet()) {
String jStr = gs.toJson(kv.getValue());
jStr = URLEncoder.encode(jStr, "UTF-8");
sb.append(kv.getKey()).append('=').append(jStr).append('&');
}
public void testTimeTravel() throws IOException {
assertTrue(mockClient.request(new TimeTravelRequest(1)).isOk());
assertTrue(mockClient.request(new TimeTravelRequest(-1)).isOk());

int index = sb.lastIndexOf("&");
if (index > 0) {
sb.deleteCharAt(index);
MockResponse res = mockHttpClient.request(new TimeTravelRequest(1));
if (!res.isOk()) {
System.err.println(res.getErrorMessage());
}

URL url = new URL(sb.toString());
HttpURLConnection uc = (HttpURLConnection)url.openConnection();
uc.connect();

sb = new StringBuilder();
byte[] buf = new byte[4096];
int nr;
while ( (nr = uc.getInputStream().read(buf)) != -1) {
sb.append(new String(buf, 0, nr));
}


return gs.fromJson(sb.toString(), JsonElement.class).getAsJsonObject();
assertTrue(mockHttpClient.request(new TimeTravelRequest(1)).isOk());
assertTrue(mockHttpClient.request(new TimeTravelRequest(-1)).isOk());
}

private void doTestSimpleEndure(CommandSender sender) throws Exception {
Command cmd = new Command();
cmd.setName("help");
JsonObject response = sender.transact(cmd);
assertTrue(response.has("status"));

// Try something more complicated
cmd.clear();
cmd.setName("endure");
cmd.set("Key", "hello world");
cmd.set("Value", "new value");
cmd.set("OnMaster", true);
cmd.set("OnReplicas", 2);

response = sender.transact(cmd);
assertTrue(response.has("status"));
Object result = client.get("hello world");
assertNotNull(result);
assertEquals("new value", (String)result);
public void testFailoverRespawn() throws IOException {
assertTrue(mockClient.request(new FailoverRequest(1)).isOk());
assertTrue(mockClient.request(new RespawnRequest(1)).isOk());
assertTrue(mockHttpClient.request(new FailoverRequest(1)).isOk());
assertTrue(mockHttpClient.request(new RespawnRequest(1)).isOk());
}

public void testLineProtocol() throws Exception {
CommandSender sender = new CommandSender() {

@Override
public JsonObject transact(Command cmd) throws Exception {
return jsonLineTxn(cmd);
}
};

doTestSimpleEndure(sender);
}


public void testHttpProtocol() throws Exception {
CommandSender sender = new CommandSender() {

@Override
public JsonObject transact(Command cmd) throws Exception {
return jsonHttpTxn(cmd);
}
};

doTestSimpleEndure(sender);
public void testHiccup() throws IOException {
assertTrue(mockClient.request(new HiccupRequest(100, 10)).isOk());
assertTrue(mockHttpClient.request(new HiccupRequest(1000, 10)).isOk());
}

}

0 comments on commit 8dc7b2d

Please sign in to comment.