/*
* Copyright 2008-2009 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.assertNull;
import java.io.IOException;
import java.security.Security;
import java.util.List;
import java.util.Properties;
import junit.framework.Assert;
import org.bouncycastle.jce.provider.BouncyCastleProvider;
import org.junit.After;
import org.junit.Test;
import voldemort.ServerTestUtils;
import voldemort.TestUtils;
import voldemort.VoldemortException;
import voldemort.client.protocol.admin.AdminClient;
import voldemort.cluster.Cluster;
import voldemort.cluster.Node;
import voldemort.store.metadata.MetadataStore;
import voldemort.versioning.VectorClockUtils;
import com.google.common.collect.Lists;
/**
* Unit test for VoldemortServer.
*/
public class VoldemortServerTest {
private VoldemortServer server;
private AdminClient oldAdminClient;
@After
public void tearDown() throws Exception {
if(oldAdminClient != null) {
oldAdminClient.close();
}
if(server != null) {
ServerTestUtils.stopVoldemortServer(server);
}
}
private VoldemortConfig getVoldemortConfig(Properties properties) throws IOException {
properties.setProperty(VoldemortConfig.ENABLE_NODE_ID_DETECTION, Boolean.toString(true));
VoldemortConfig config = ServerTestUtils.createServerConfig(true,
-1,
TestUtils.createTempDir().getAbsolutePath(),
null,
null,
properties);
return config;
}
private VoldemortServer getVoldemortServer(Properties properties) throws IOException {
VoldemortConfig config = getVoldemortConfig(properties);
Cluster cluster = ServerTestUtils.getLocalCluster(1);
return new VoldemortServer(config, cluster);
}
@Test
public void testSSLProviders() throws IOException {
// The SSL providers changes the state of the JVM
// if the methods are run in parallel or the ordering
// changes the test fails. TestBouncyCastle is the
// only test to enable this SSL. If other tests introduce
// them the test could fails as well.
testJCEProvider();
testBouncyCastleProvider();
}
private void testJCEProvider() throws IOException {
Properties properties = new Properties();
// Default configuration. Bouncy castle provider will not be used.
server = getVoldemortServer(properties);
assertNull(Security.getProvider(BouncyCastleProvider.PROVIDER_NAME));
}
private void testBouncyCastleProvider() throws IOException {
Properties properties = new Properties();
// Use bouncy castle as first choice of JCE provider.
properties.setProperty("use.bouncycastle.for.ssl", "true");
server = getVoldemortServer(properties);
assertEquals(BouncyCastleProvider.PROVIDER_NAME, Security.getProviders()[0].getName());
}
@Test
public void testNodeIdDetection() throws IOException {
final int NUM_NODES = 10;
final int NODE_ID = 5;
VoldemortConfig config = getVoldemortConfig(new Properties());
final String SOMEHOST = "host" + NODE_ID;
config.setNodeIdImplementation(new MockHostMatcher(SOMEHOST));
List<String> hostNames = Lists.newArrayList();
for(int i = 0; i < NUM_NODES; i ++) {
hostNames.add("host"+i);
}
Assert.assertEquals("At first no node Id", -1, config.getNodeId());
Cluster cluster = HostMatcherTest.getCluster(hostNames);
server = new VoldemortServer(config, cluster);
server.start();
Assert.assertEquals("Node id is not auto detected", NODE_ID, config.getNodeId());
Assert.assertEquals("Node id is not auto detected", NODE_ID, server.getMetadataStore()
.getNodeId());
}
@Test
public void testInvalidNodeIdUpdateFails() throws IOException {
Cluster localCluster = ServerTestUtils.getLocalCluster(1);
VoldemortConfig config = getVoldemortConfig(new Properties());
server = new VoldemortServer(config, localCluster);
server.start();
final int UPDATED_NODE_ID = 3;
Node oldNode = localCluster.getNodes().iterator().next();
// For single local node, host matcher is not used.
config.setNodeIdImplementation(new NodeIdHostMatcher(UPDATED_NODE_ID));
oldAdminClient = new AdminClient(localCluster);
try {
oldAdminClient.metadataMgmtOps.updateRemoteMetadata(oldNode.getId(),
MetadataStore.NODE_ID_KEY,
Integer.toString(UPDATED_NODE_ID));
Assert.fail("Invalid node id should have failed");
} catch(VoldemortException ex) {
// Expected, ignore
}
}
@Test
public void testClusterWithDifferentStateFails() throws IOException {
Cluster localCluster = ServerTestUtils.getLocalCluster(1);
VoldemortConfig config = getVoldemortConfig(new Properties());
server = new VoldemortServer(config, localCluster);
server.start();
final int UPDATED_NODE_ID = 3;
Node oldNode = localCluster.getNodes().iterator().next();
// For single local node, host matcher is not used.
config.setNodeIdImplementation(new NodeIdHostMatcher(UPDATED_NODE_ID));
Cluster updatedCluster = ServerTestUtils.getLocalCluster(UPDATED_NODE_ID + 1);
oldAdminClient = new AdminClient(localCluster);
try {
oldAdminClient.metadataMgmtOps.updateRemoteCluster(oldNode.getId(),
updatedCluster,
VectorClockUtils.makeClockWithCurrentTime(localCluster.getNodeIds()));
Assert.fail("Invalid node id should have failed");
} catch(VoldemortException ex) {
// Expected, ignore
}
}
@Test
public void testClusterUpdateWithAutoDetection() throws IOException {
Cluster localCluster = ServerTestUtils.getLocalCluster(1);
VoldemortConfig config = getVoldemortConfig(new Properties());
server = new VoldemortServer(config, localCluster);
server.start();
final int UPDATED_NODE_ID = 3;
Node oldNode = localCluster.getNodes().iterator().next();
// For single local node, host matcher is not used.
config.setNodeIdImplementation(new NodeIdHostMatcher(UPDATED_NODE_ID));
Cluster updatedCluster = ServerTestUtils.getLocalCluster(UPDATED_NODE_ID + 1);
oldAdminClient = new AdminClient(localCluster);
List<Node> newNodes = Lists.newArrayList();
for(Node node: updatedCluster.getNodes()) {
if(node.getId() != UPDATED_NODE_ID) {
newNodes.add(node);
}
}
Node nodeToBeReplaced = updatedCluster.getNodeById(UPDATED_NODE_ID);
Node updatedNode = new Node(UPDATED_NODE_ID,
oldNode.getHost(),
oldNode.getHttpPort(),
oldNode.getSocketPort(),
oldNode.getAdminPort(),
nodeToBeReplaced.getPartitionIds());
newNodes.add(updatedNode);
Cluster updatedClusterWithCorrectNode = new Cluster("updated-cluster", newNodes);
oldAdminClient.metadataMgmtOps.updateRemoteCluster(oldNode.getId(),
updatedClusterWithCorrectNode,
VectorClockUtils.makeClockWithCurrentTime(localCluster.getNodeIds()));
Assert.assertEquals("Identity node is not auto detected",
UPDATED_NODE_ID,
server.getIdentityNode().getId());
Assert.assertEquals("Voldemort config is not updated",
UPDATED_NODE_ID,
server.getVoldemortConfig().getNodeId());
Assert.assertEquals("Metadata store is not updated",
UPDATED_NODE_ID,
server.getMetadataStore().getNodeId());
}
}