/* * 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; import com.google.gson.Gson; import com.google.gson.JsonElement; import com.google.gson.JsonObject; import net.spy.memcached.internal.OperationFuture; import org.couchbase.mock.Bucket; import org.couchbase.mock.memcached.MemcachedServer; import org.couchbase.mock.memcached.client.ClientResponse; import org.couchbase.mock.memcached.client.CommandBuilder; import org.couchbase.mock.memcached.client.MemcachedClient; import org.couchbase.mock.memcached.protocol.CommandCode; import org.couchbase.mock.memcached.protocol.ErrorCode; import java.io.IOException; import java.net.InetSocketAddress; import java.net.Socket; import java.util.ArrayList; /** * Tests for the "extended" Mock API. * * @author Mark Nunberg <mnunberg@haskalah.org> */ public class MockAPITest extends ClientBaseTest { MockHttpClient mockHttpClient; @Override protected void setUp() throws Exception { super.setUp(); mockHttpClient = new MockHttpClient(new InetSocketAddress("localhost", mockClient.getRestPort())); } 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()); assertTrue(mockClient.request(new EndureRequest("key", "value", true, 2, "default")).isOk()); assertTrue(mockHttpClient.request(new EndureRequest("key", "value", true, 2, "default")).isOk()); ArrayList<Integer> replicaId = new ArrayList<Integer>(); for (int ii = 0; ii < bucketConfiguration.numReplicas; ++ii) { replicaId.add(ii); } assertTrue(mockClient.request(new EndureRequest("key", "value", true, replicaId)).isOk()); assertTrue(mockHttpClient.request(new EndureRequest("key", "value", true, replicaId)).isOk()); assertTrue(mockClient.request(new EndureRequest("key", "value", true, replicaId, "default")).isOk()); assertTrue(mockHttpClient.request(new EndureRequest("key", "value", true, replicaId, "default")).isOk()); // Now verify that we can't endure over the max number.. replicaId.add(bucketConfiguration.numReplicas); assertFalse(mockClient.request(new EndureRequest("key", "value", true, replicaId)).isOk()); assertFalse(mockClient.request(new EndureRequest("key", "value", true, replicaId, "default")).isOk()); } public void testTimeTravel() throws IOException { assertTrue(mockClient.request(new TimeTravelRequest(1)).isOk()); assertTrue(mockClient.request(new TimeTravelRequest(-1)).isOk()); MockResponse res = mockHttpClient.request(new TimeTravelRequest(1)); if (!res.isOk()) { System.err.println(res.getErrorMessage()); } assertTrue(mockHttpClient.request(new TimeTravelRequest(1)).isOk()); assertTrue(mockHttpClient.request(new TimeTravelRequest(-1)).isOk()); } 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 testHiccup() throws IOException { assertTrue(mockClient.request(new HiccupRequest(100, 10)).isOk()); assertTrue(mockHttpClient.request(new HiccupRequest(1000, 10)).isOk()); } public void testTruncate() throws IOException { assertTrue(mockClient.request(new TruncateRequest(1000)).isOk()); assertTrue(mockHttpClient.request(new TruncateRequest(10)).isOk()); } public void testPersist() throws IOException { assertTrue(mockClient.request(new PersistRequest("key", "value", 0, true, 0)).isOk()); assertTrue(mockHttpClient.request(new PersistRequest("key", "value", 0, true, 1)).isOk()); assertTrue(mockClient.request(new PersistRequest("key", "value", 0, true, 2, "default")).isOk()); assertTrue(mockHttpClient.request(new PersistRequest("key", "value", 0, true, 2, "default")).isOk()); ArrayList<Integer> replicaId = new ArrayList<Integer>(); for (int ii = 0; ii < bucketConfiguration.numReplicas; ++ii) { replicaId.add(ii); } assertTrue(mockClient.request(new PersistRequest("key", "value", 0, true, replicaId)).isOk()); assertTrue(mockHttpClient.request(new PersistRequest("key", "value", 0, true, replicaId)).isOk()); assertTrue(mockClient.request(new PersistRequest("key", "value", 0, true, replicaId, "default")).isOk()); assertTrue(mockHttpClient.request(new PersistRequest("key", "value", 0, true, replicaId, "default")).isOk()); // Now verify that we can't persist over the max number.. replicaId.add(bucketConfiguration.numReplicas); assertFalse(mockClient.request(new PersistRequest("key", "value", 0, true, replicaId)).isOk()); assertFalse(mockClient.request(new PersistRequest("key", "value", 0, true, replicaId, "default")).isOk()); // try to set with random cas assertTrue(mockClient.request(new PersistRequest("key", "value", 123, true, 0)).isOk()); assertTrue(mockHttpClient.request(new PersistRequest("key", "value", 456, true, 1)).isOk()); assertTrue(mockClient.request(new PersistRequest("key", "value", 789, true, 2, "default")).isOk()); assertTrue(mockHttpClient.request(new PersistRequest("key", "value", 123, true, 2, "default")).isOk()); } public void testUnpersist() throws IOException { assertTrue(mockClient.request(new UnpersistRequest("key", true, 0)).isOk()); assertTrue(mockHttpClient.request(new UnpersistRequest("key", true, 1)).isOk()); assertTrue(mockClient.request(new UnpersistRequest("key", true, 2, "default")).isOk()); assertTrue(mockHttpClient.request(new UnpersistRequest("key", true, 2, "default")).isOk()); ArrayList<Integer> replicaId = new ArrayList<Integer>(); for (int ii = 0; ii < bucketConfiguration.numReplicas; ++ii) { replicaId.add(ii); } assertTrue(mockClient.request(new UnpersistRequest("key", true, replicaId)).isOk()); assertTrue(mockHttpClient.request(new UnpersistRequest("key", true, replicaId)).isOk()); assertTrue(mockClient.request(new UnpersistRequest("key", true, replicaId, "default")).isOk()); assertTrue(mockHttpClient.request(new UnpersistRequest("key", true, replicaId, "default")).isOk()); // Now verify that we can't unpersist over the max number.. replicaId.add(bucketConfiguration.numReplicas); assertFalse(mockClient.request(new UnpersistRequest("key", true, replicaId)).isOk()); assertFalse(mockClient.request(new UnpersistRequest("key", true, replicaId, "default")).isOk()); } public void testCache() throws IOException { assertTrue(mockClient.request(new CacheRequest("key", "value", 0, true, 0)).isOk()); assertTrue(mockHttpClient.request(new CacheRequest("key", "value", 0, true, 1)).isOk()); assertTrue(mockClient.request(new CacheRequest("key", "value", 0, true, 2, "default")).isOk()); assertTrue(mockHttpClient.request(new CacheRequest("key", "value", 0, true, 2, "default")).isOk()); ArrayList<Integer> replicaId = new ArrayList<Integer>(); for (int ii = 0; ii < bucketConfiguration.numReplicas; ++ii) { replicaId.add(ii); } assertTrue(mockClient.request(new CacheRequest("key", "value", 0, true, replicaId)).isOk()); assertTrue(mockHttpClient.request(new CacheRequest("key", "value", 0, true, replicaId)).isOk()); assertTrue(mockClient.request(new CacheRequest("key", "value", 0, true, replicaId, "default")).isOk()); assertTrue(mockHttpClient.request(new CacheRequest("key", "value", 0, true, replicaId, "default")).isOk()); // Now verify that we can't cache over the max number.. replicaId.add(bucketConfiguration.numReplicas); assertFalse(mockClient.request(new CacheRequest("key", "value", 0, true, replicaId)).isOk()); assertFalse(mockClient.request(new CacheRequest("key", "value", 0, true, replicaId, "default")).isOk()); // try to set with random cas assertTrue(mockClient.request(new CacheRequest("key", "value", 123, true, 0)).isOk()); assertTrue(mockHttpClient.request(new CacheRequest("key", "value", 456, true, 1)).isOk()); assertTrue(mockClient.request(new CacheRequest("key", "value", 789, true, 2, "default")).isOk()); assertTrue(mockHttpClient.request(new CacheRequest("key", "value", 123, true, 2, "default")).isOk()); } public void testUncache() throws IOException { assertTrue(mockClient.request(new UncacheRequest("key", true, 0)).isOk()); assertTrue(mockHttpClient.request(new UncacheRequest("key", true, 1)).isOk()); assertTrue(mockClient.request(new UncacheRequest("key", true, 2, "default")).isOk()); assertTrue(mockHttpClient.request(new UncacheRequest("key", true, 2, "default")).isOk()); ArrayList<Integer> replicaId = new ArrayList<Integer>(); for (int ii = 0; ii < bucketConfiguration.numReplicas; ++ii) { replicaId.add(ii); } assertTrue(mockClient.request(new UncacheRequest("key", true, replicaId)).isOk()); assertTrue(mockHttpClient.request(new UncacheRequest("key", true, replicaId)).isOk()); assertTrue(mockClient.request(new UncacheRequest("key", true, replicaId, "default")).isOk()); assertTrue(mockHttpClient.request(new UncacheRequest("key", true, replicaId, "default")).isOk()); // Now verify that we can't uncache over the max number.. replicaId.add(bucketConfiguration.numReplicas); assertFalse(mockClient.request(new UncacheRequest("key", true, replicaId)).isOk()); assertFalse(mockClient.request(new UncacheRequest("key", true, replicaId, "default")).isOk()); } public void testPurge() throws IOException { assertTrue(mockClient.request(new PurgeRequest("key", true, 0)).isOk()); assertTrue(mockHttpClient.request(new PurgeRequest("key", true, 1)).isOk()); assertTrue(mockClient.request(new PurgeRequest("key", true, 2, "default")).isOk()); assertTrue(mockHttpClient.request(new PurgeRequest("key", true, 2, "default")).isOk()); ArrayList<Integer> replicaId = new ArrayList<Integer>(); for (int ii = 0; ii < bucketConfiguration.numReplicas; ++ii) { replicaId.add(ii); } assertTrue(mockClient.request(new PurgeRequest("key", true, replicaId)).isOk()); assertTrue(mockHttpClient.request(new PurgeRequest("key", true, replicaId)).isOk()); assertTrue(mockClient.request(new PurgeRequest("key", true, replicaId, "default")).isOk()); assertTrue(mockHttpClient.request(new PurgeRequest("key", true, replicaId, "default")).isOk()); // Now verify that we can't purge over the max number.. replicaId.add(bucketConfiguration.numReplicas); assertFalse(mockClient.request(new PurgeRequest("key", true, replicaId)).isOk()); assertFalse(mockClient.request(new PurgeRequest("key", true, replicaId, "default")).isOk()); } public void testKeyInfo() throws IOException { assertTrue(mockClient.request(new CacheRequest("key", "value", 123, true, 2)).isOk()); assertTrue(mockClient.request(new KeyInfoRequest("key")).isOk()); assertTrue(mockHttpClient.request(new KeyInfoRequest("key")).isOk()); assertTrue(mockClient.request(new KeyInfoRequest("key", "default")).isOk()); assertTrue(mockHttpClient.request(new KeyInfoRequest("key", "default")).isOk()); } public void testHelp() throws IOException { assertTrue(mockClient.request(new HelpRequest()).isOk()); } public void testOpfail() throws Exception { OperationFuture ft = client.set("foo", "bar"); ft.get(); assertTrue(ft.getStatus().isSuccess()); assertTrue(mockClient.request(new OpfailRequest(ErrorCode.KEY_ENOENT, 100)).isOk()); ft = client.asyncGets("foo"); ft.get(); assertFalse(ft.getStatus().isSuccess()); assertTrue(mockClient.request(new OpfailRequest(ErrorCode.SUCCESS, 0)).isOk()); ft = client.asyncGets("foo"); ft.get(); assertTrue(ft.getStatus().isSuccess()); assertTrue(mockHttpClient.request(new OpfailRequest(ErrorCode.KEY_ENOENT, 100)).isOk()); assertTrue(mockHttpClient.request(new OpfailRequest(ErrorCode.SUCCESS, 0)).isOk()); } private void checkCCCPEnabled(int index, boolean enabledExpected) throws Exception { MemcachedClient mcClient = getBinClient(index); try { CommandBuilder cBuilder; ClientResponse resp; cBuilder = new CommandBuilder(CommandCode.GET_CLUSTER_CONFIG); resp = mcClient.sendRequest(cBuilder.build()); if (enabledExpected) { assertEquals(ErrorCode.SUCCESS, resp.getStatus()); assertTrue(resp.getValue().length() > 0); new Gson().fromJson(resp.getValue(), JsonObject.class); } else { assertEquals(ErrorCode.NOT_SUPPORTED, resp.getStatus()); assertEquals(0, resp.getValue().length()); } cBuilder = new CommandBuilder(CommandCode.GET); cBuilder.key("foo", Short.MAX_VALUE); resp = mcClient.sendRequest(cBuilder.build()); assertEquals(ErrorCode.NOT_MY_VBUCKET, resp.getStatus()); if (enabledExpected) { assertTrue(resp.getValue().length() > 0); new Gson().fromJson(resp.getValue(), JsonObject.class); } else { assertEquals(0, resp.getValue().length()); } } finally { mcClient.close(); } } public void testBasicCCCP() throws Exception { // Open a connection to a mock server // CCCP is disabled by default checkCCCPEnabled(0, false); // Enable CCCP SetCCCPRequest req = new SetCCCPRequest(true); assertTrue(mockClient.request(req).isOk()); checkCCCPEnabled(0, true); } public void testDetailedCCCP() throws Exception { ArrayList<Integer> enabledServers = new ArrayList<Integer>(); enabledServers.add(0); enabledServers.add(3); for (int index : enabledServers) { checkCCCPEnabled(index, false); } SetCCCPRequest req = new SetCCCPRequest(true, bucketConfiguration.name, enabledServers); assertTrue(mockClient.request(req).isOk()); for (int index : enabledServers) { checkCCCPEnabled(index, true); } Bucket deflBucket = couchbaseMock.getBuckets().get(bucketConfiguration.name); MemcachedServer[] servers = deflBucket.getServers(); for (int index = 0; index < servers.length; index++) { if (enabledServers.contains(index)) { continue; } checkCCCPEnabled(index, false); } } public void testMCPorts() throws Exception { GetMCPortsRequest mreq = new GetMCPortsRequest(bucketConfiguration.name); MockResponse mres = mockClient.request(mreq); assertTrue(mres.isOk()); assertTrue(mres.getPayload().isJsonArray()); for (JsonElement elem : mres.getPayload().getAsJsonArray()) { int port = elem.getAsInt(); Socket socket = new Socket(); socket.connect(new InetSocketAddress("localhost", port)); socket.close(); } } }