package voldemort.client;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;
import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.Properties;
import org.apache.commons.io.FileUtils;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import voldemort.ServerTestUtils;
import voldemort.TestUtils;
import voldemort.cluster.Cluster;
import voldemort.rest.coordinator.CoordinatorProxyService;
import voldemort.rest.coordinator.config.CoordinatorConfig;
import voldemort.rest.coordinator.config.FileBasedStoreClientConfigService;
import voldemort.rest.coordinator.config.StoreClientConfigService;
import voldemort.restclient.RESTClientFactory;
import voldemort.restclient.RESTClientFactoryConfig;
import voldemort.server.VoldemortServer;
import voldemort.store.socket.SocketStoreFactory;
import voldemort.store.socket.clientrequest.ClientRequestExecutorPool;
import voldemort.utils.SystemTime;
import voldemort.versioning.ObsoleteVersionException;
import voldemort.versioning.VectorClock;
import voldemort.versioning.Versioned;
public class RestClientTest extends DefaultStoreClientTest {
private static final String STORE_NAME = "test";
private static final String FAT_CLIENT_CONFIG_PATH_ORIGINAL = "test/common/coordinator/config/clientConfigs.avro";
private static File COPY_OF_FAT_CLIENT_CONFIG_FILE;
private static String storesXmlfile = "test/common/voldemort/config/two-stores.xml";
String[] bootStrapUrls = null;
private VoldemortServer[] servers;
private CoordinatorProxyService coordinator;
private Cluster cluster;
public static String socketUrl = "";
private SocketStoreFactory socketStoreFactory = new ClientRequestExecutorPool(2,
10000,
100000,
32 * 1024);
@Override
@Before
public void setUp() throws IOException {
final int numServers = 1;
this.nodeId = 0;
this.time = SystemTime.INSTANCE;
servers = new VoldemortServer[numServers];
int partitionMap[][] = { { 0, 1, 2, 3, 4, 5, 6, 7 } };
try {
// Setup the cluster
cluster = ServerTestUtils.startVoldemortCluster(numServers,
servers,
partitionMap,
socketStoreFactory,
true,
null,
storesXmlfile,
new Properties());
} catch(IOException e) {
fail("Failure to setup the cluster");
}
socketUrl = servers[0].getIdentityNode().getSocketUrl().toString();
List<String> bootstrapUrls = new ArrayList<String>();
bootstrapUrls.add(socketUrl);
// create a copy of the config file in a temp directory and work on that
File src = new File(FAT_CLIENT_CONFIG_PATH_ORIGINAL);
COPY_OF_FAT_CLIENT_CONFIG_FILE = new File(TestUtils.createTempDir(),
"clientConfigs" + System.currentTimeMillis()
+ ".avro");
FileUtils.copyFile(src, COPY_OF_FAT_CLIENT_CONFIG_FILE);
// Setup the Coordinator
CoordinatorConfig coordinatorConfig = new CoordinatorConfig();
coordinatorConfig.setBootstrapURLs(bootstrapUrls)
.setCoordinatorCoreThreads(100)
.setCoordinatorMaxThreads(100)
.setFatClientConfigPath(COPY_OF_FAT_CLIENT_CONFIG_FILE.getAbsolutePath())
.setServerPort(9999);
try {
StoreClientConfigService storeClientConfigs = null;
switch(coordinatorConfig.getFatClientConfigSource()) {
case FILE:
storeClientConfigs = new FileBasedStoreClientConfigService(coordinatorConfig);
break;
case ZOOKEEPER:
throw new UnsupportedOperationException("Zookeeper-based configs are not implemented yet!");
default:
storeClientConfigs = null;
}
coordinator = new CoordinatorProxyService(coordinatorConfig, storeClientConfigs);
coordinator.start();
} catch(Exception e) {
e.printStackTrace();
fail("Failure to start the Coordinator");
}
Properties props = new Properties();
props.setProperty(ClientConfig.BOOTSTRAP_URLS_PROPERTY, "http://localhost:9999");
props.setProperty(ClientConfig.ROUTING_TIMEOUT_MS_PROPERTY, "1500");
RESTClientFactoryConfig mainConfig = new RESTClientFactoryConfig(props, null);
RESTClientFactory factory = new RESTClientFactory(mainConfig);
this.client = factory.getStoreClient(STORE_NAME);
}
@After
public void tearDown() throws Exception {
for(VoldemortServer server: servers) {
ServerTestUtils.stopVoldemortServer(server);
}
coordinator.stop();
// clean up the temporary file created in set up
COPY_OF_FAT_CLIENT_CONFIG_FILE.delete();
}
@Override
@Test
public void testGetWithDefault() {
assertEquals("GET of missing key should return default.",
new Versioned<String>("v"),
client.get("k", new Versioned<String>("v")));
assertEquals("null should be an acceptable default value.",
null,
client.getValue("k", null));
client.put("k", "v");
VectorClock expectedVC = new VectorClock().incremented(nodeId, time.getMilliseconds());
assertEquals("If there is a value for k, get(k) should return it.",
"v",
client.get("k", new Versioned<String>("v2")).getValue());
assertNotNull(client.get("k").getVersion());
}
@Override
@Test
public void testPutVersioned() {
VectorClock vc = new VectorClock();
vc.incrementVersion(this.nodeId, System.currentTimeMillis());
VectorClock initialVC = vc.clone();
client.put("k", new Versioned<String>("v", vc));
Versioned<String> v = client.get("k");
assertEquals("GET should return the version set by PUT.", "v", v.getValue());
VectorClock expected = initialVC.clone();
expected.incrementVersion(this.nodeId, System.currentTimeMillis());
assertEquals("The version should be incremented after a put.",
expected.getEntries(),
((VectorClock) v.getVersion()).getEntries());
try {
client.put("k", new Versioned<String>("v", initialVC));
fail("Put of obsolete version should throw exception.");
} catch(ObsoleteVersionException e) {
// this is good
}
// PUT of a concurrent version should succeed
client.put("k",
new Versioned<String>("v2",
new VectorClock().incremented(nodeId + 1,
time.getMilliseconds())));
assertEquals("GET should return the new value set by PUT.", "v2", client.getValue("k"));
assertEquals("GET should return the new version set by PUT.",
expected.incremented(nodeId + 1, time.getMilliseconds()),
client.get("k").getVersion());
}
@Override
@Test
public void testPutIfNotObsolete() {
VectorClock vc = new VectorClock();
vc.incrementVersion(this.nodeId, System.currentTimeMillis());
VectorClock initialVC = vc.clone();
client.putIfNotObsolete("k", new Versioned<String>("v", vc));
assertEquals("PUT of non-obsolete version should succeed.", "v", client.getValue("k"));
assertFalse(client.putIfNotObsolete("k", new Versioned<String>("v2", initialVC)));
assertEquals("Failed PUT should not change the value stored.", "v", client.getValue("k"));
}
@Override
@Test
public void testDeleteVersion() {
VectorClock vc = new VectorClock();
vc.incrementVersion(this.nodeId, System.currentTimeMillis());
VectorClock initialVC = vc.clone();
assertFalse("Delete of non-existant key should be false.", client.delete("k", vc));
client.put("k", new Versioned<String>("v", vc));
assertFalse("Delete of a lesser version should be false.", client.delete("k", initialVC));
assertNotNull("After failed delete, value should still be there.", client.get("k"));
assertTrue("Delete of k, with the current version should succeed.",
client.delete("k", initialVC.incremented(this.nodeId, time.getMilliseconds())));
assertNull("After a successful delete(k), get(k) should return null.", client.get("k"));
}
}