/*
* Copyright 2012 LinkedIn, 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 voldemort.server;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNull;
import java.io.IOException;
import java.util.Arrays;
import java.util.Collection;
import java.util.Map;
import java.util.Properties;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.Parameterized;
import org.junit.runners.Parameterized.Parameters;
import voldemort.ServerTestUtils;
import voldemort.client.ClientConfig;
import voldemort.client.SocketStoreClientFactory;
import voldemort.client.StoreClient;
import voldemort.client.StoreClientFactory;
import voldemort.cluster.Cluster;
import voldemort.cluster.Node;
import voldemort.store.socket.SocketStoreFactory;
import voldemort.store.socket.clientrequest.ClientRequestExecutorPool;
import voldemort.versioning.Occurred;
import voldemort.versioning.VectorClock;
import voldemort.versioning.Version;
import voldemort.versioning.Versioned;
/**
* Provides an unmocked end to end unit test of a Voldemort cluster.
*
*/
@RunWith(Parameterized.class)
public class EndToEndTest {
private static final String STORE_NAME = "test-readrepair-memory";
private static final String STORES_XML = "test/common/voldemort/config/stores.xml";
private final SocketStoreFactory socketStoreFactory = new ClientRequestExecutorPool(2,
10000,
100000,
32 * 1024);
private final boolean useNio;
private StoreClient<String, String> storeClient;
public EndToEndTest(boolean useNio) {
this.useNio = useNio;
}
@Parameters
public static Collection<Object[]> configs() {
return Arrays.asList(new Object[][] { { true }, { false } });
}
@Before
public void setUp() throws IOException {
int numServers = 2;
VoldemortServer[] servers = new VoldemortServer[numServers];
int partitionMap[][] = { { 0, 2, 4, 6 }, { 1, 3, 5, 7 } };
Cluster cluster = ServerTestUtils.startVoldemortCluster(numServers,
servers,
partitionMap,
socketStoreFactory,
useNio,
null,
STORES_XML,
new Properties());
Node node = cluster.getNodeById(0);
String bootstrapUrl = "tcp://" + node.getHost() + ":" + node.getSocketPort();
StoreClientFactory storeClientFactory = new SocketStoreClientFactory(new ClientConfig().setBootstrapUrls(bootstrapUrl));
storeClient = storeClientFactory.getStoreClient(STORE_NAME);
}
@After
public void tearDown() {
socketStoreFactory.close();
}
/**
* Test the basic get/getAll/put/delete functionality.
*/
@Test
public void testSanity() {
storeClient.put("Belarus", "Minsk");
storeClient.put("Russia", "Moscow");
storeClient.put("Ukraine", "Kiev");
storeClient.put("Kazakhstan", "Almaty");
Versioned<String> v1 = storeClient.get("Belarus");
assertEquals("get/put work as expected", "Minsk", v1.getValue());
storeClient.put("Kazakhstan", "Astana");
Versioned<String> v2 = storeClient.get("Kazakhstan");
assertEquals("clobbering a value works as expected, we have read-your-writes consistency",
"Astana",
v2.getValue());
Map<String, Versioned<String>> capitals = storeClient.getAll(Arrays.asList("Russia",
"Ukraine",
"Japan"));
assertEquals("getAll works as expected", "Moscow", capitals.get("Russia").getValue());
assertEquals("getAll works as expected", "Kiev", capitals.get("Ukraine").getValue());
assertFalse("getAll works as expected", capitals.containsKey("Japan"));
storeClient.delete("Ukraine");
assertNull("delete works as expected", storeClient.get("Ukraine"));
}
/**
* Test the new put that returns the new version
*/
@Test
public void testPutReturnVersion() {
Version baseVersion = new VectorClock();
Version oldVersion = null;
Version newVersion = null;
Versioned<String> getVersioned = null;
String oldValue = null;
String newValue = null;
for(int i = 0; i < 5; i++) {
oldValue = "value" + i;
newValue = "value" + (i + 1);
oldVersion = storeClient.put("key1", Versioned.value(oldValue, baseVersion));
newVersion = storeClient.put("key1",
Versioned.value(newValue,
((VectorClock) oldVersion).clone()));
getVersioned = storeClient.get("key1");
baseVersion = newVersion;
verifyResults(oldVersion, newVersion, getVersioned, newValue);
}
}
@Test
public void testUnversionedPutReturnVersion() {
Version oldVersion = null;
Version newVersion = null;
Versioned<String> getVersioned = null;
String oldValue = null;
String newValue = null;
for(int i = 0; i < 5; i++) {
oldValue = "value" + i;
newValue = "value" + i + 1;
oldVersion = storeClient.put("key1", oldValue);
newVersion = storeClient.put("key1", newValue);
assertEquals("Version did not advance", Occurred.AFTER, newVersion.compare(oldVersion));
getVersioned = storeClient.get("key1");
verifyResults(oldVersion, newVersion, getVersioned, newValue);
}
}
private void verifyResults(Version oldVersion,
Version newVersion,
Versioned<String> getVersioned,
String newValue) {
// make sure version advances between two puts
assertEquals("Versions of put did not advance",
Occurred.AFTER,
newVersion.compare(oldVersion));
// make sure version of last put equals version of the get
assertEquals("Version of put is larger than version of get",
Occurred.BEFORE /* before can mean equal, funny! */,
newVersion.compare(getVersioned.getVersion()));
assertEquals("Version of put is smaller than version of get",
Occurred.BEFORE /* before can mean equal, funny! */,
getVersioned.getVersion().compare(newVersion));
// make sure we get what we just put in
assertEquals("Value of put does not match value of get", newValue, getVersioned.getValue());
}
}