/* * Copyright 2014 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.tools; import static org.junit.Assert.assertTrue; import java.io.IOException; import java.util.List; import java.util.Properties; import org.junit.After; import org.junit.Before; import org.junit.Test; import voldemort.ServerTestUtils; import voldemort.client.protocol.admin.AdminClient; import voldemort.client.protocol.admin.AdminClientConfig; import voldemort.cluster.Cluster; import voldemort.server.VoldemortServer; import voldemort.store.socket.SocketStoreFactory; import voldemort.store.socket.clientrequest.ClientRequestExecutorPool; import com.google.common.collect.Lists; public class ReadOnlyReplicationHelperTest { private static String storesXmlfile = "test/common/voldemort/config/stores.xml"; private SocketStoreFactory socketStoreFactory = new ClientRequestExecutorPool(2, 10000, 100000, 32 * 1024); private VoldemortServer[] servers; private Cluster cluster; private AdminClient adminClient; @Before public void setUp() throws IOException { int numServers = 2; servers = new VoldemortServer[numServers]; int partitionMap[][] = { { 0, 1, 2, 3 }, { 4, 5, 6, 7 } }; Properties serverProperties = new Properties(); serverProperties.setProperty("client.max.connections.per.node", "20"); cluster = ServerTestUtils.startVoldemortCluster(numServers, servers, partitionMap, socketStoreFactory, false, null, storesXmlfile, serverProperties); Properties adminProperties = new Properties(); adminProperties.setProperty("max_connections", "20"); adminClient = new AdminClient(cluster, new AdminClientConfig(adminProperties)); } @After public void tearDown() throws IOException { adminClient.close(); for(VoldemortServer server: servers) { ServerTestUtils.stopVoldemortServer(server); } socketStoreFactory.close(); } private List<String> getSourceFileList(List<String> infoList, String storeName, Integer srcNodeId) { List<String> fileList = Lists.newArrayList(); for(String info: infoList) { String[] infoSplit = info.split(","); String nodeId = infoSplit[1]; String relPath = infoSplit[2]; String[] pathSplit = relPath.split("/"); String parsedStoreName = pathSplit[0]; String parserFileName = pathSplit[2]; if(storeName.equals(parsedStoreName) && srcNodeId.equals(Integer.parseInt(nodeId))) { fileList.add(parserFileName); } } return fileList; } private List<String> getDestFileList(List<String> infoList, String storeName, Integer srcNodeId) { List<String> fileList = Lists.newArrayList(); for(String info: infoList) { String[] infoSplit = info.split(","); String nodeId = infoSplit[1]; String relPath = infoSplit[3]; String[] pathSplit = relPath.split("/"); String parsedStoreName = pathSplit[0]; String parserFileName = pathSplit[2]; if(storeName.equals(parsedStoreName) && srcNodeId.equals(Integer.parseInt(nodeId))) { fileList.add(parserFileName); } } return fileList; } private Boolean compareStringLists(List<String> list1, List<String> list2) { if(list1 == null && list2 == null) { return true; } if(list1 == null || list2 == null || list1.size() != list2.size()) { return false; } for(String s1: list1) { if(!list2.contains(s1)) { return false; } } return true; } /** * Match string with wildcard pattern * * @param s Input string * @param p Pattern string with wildcard (* and ?) * @param i Iterator of characters in s * @param j Iterator of characters in p * @return true if string can be matched by pattern */ private Boolean isMatch(String s, String p, int i, int j) { while (i < s.length() && j < p.length() && p.charAt(j) != '*') { if(s.charAt(i) == p.charAt(j) || p.charAt(j) == '?') { i++; j++; } else { return false; } } if(j == p.length()) { return i == s.length(); } if(i == s.length()) { while(j < p.length() && p.charAt(j) == '*') { j++; } return j == p.length(); } return isMatch(s, p, i + 1, j) || isMatch(s, p, i, j + 1); } private Boolean isMatch(String s, String p) { return isMatch(s, p, 0, 0); } private Boolean compareWildcardStringLists(List<String> strings, List<String> patterns) { if(patterns == null) { return strings == null; } else if(strings == null) { return true; } for(String string: strings) { boolean match = false; for(String pattern: patterns) { if (isMatch(string, pattern)) { match = true; break; } } if (!match) return false; } return true; } @Test public void testGetROStorageFileListRemotely() { String storeName = "test-readonly-fetchfiles"; // file list on node 0 List<String> fileList0 = adminClient.readonlyOps.getROStorageFileList(0, storeName); // file list on node 1 List<String> fileList1 = adminClient.readonlyOps.getROStorageFileList(1, storeName); // info list for node 0 List<String> infoList0 = ReadOnlyReplicationHelperCLI.getReadOnlyReplicationInfo(adminClient, 0, false); // info list for node 1 List<String> infoList1 = ReadOnlyReplicationHelperCLI.getReadOnlyReplicationInfo(adminClient, 1, false); for(String info: infoList0) { System.out.println(info); } // source list for node 0, i.e. file list on node 1 List<String> srcList0 = getSourceFileList(infoList0, storeName, 1); // dest list for node 0, i.e. file list on node 0 List<String> dstList0 = getDestFileList(infoList0, storeName, 1); // source list for node 1, i.e. file list on node 0 List<String> srcList1 = getSourceFileList(infoList1, storeName, 0); // dest list for node 1, i.e. file list on node 1 List<String> dstList1 = getDestFileList(infoList1, storeName, 0); // compare assertTrue(fileList0.size() > 0); assertTrue(fileList1.size() > 0); assertTrue(compareStringLists(srcList0, fileList1)); assertTrue(compareStringLists(dstList0, fileList0)); assertTrue(compareStringLists(srcList1, fileList0)); assertTrue(compareStringLists(dstList1, fileList1)); } @Test public void testGetROStorageFileListLocally() { String storeName = "test-readonly-fetchfiles"; // file list on node 0 List<String> fileList0 = adminClient.readonlyOps.getROStorageFileList(0, storeName); // file list on node 1 List<String> fileList1 = adminClient.readonlyOps.getROStorageFileList(1, storeName); // info list for node 0 List<String> infoList0 = ReadOnlyReplicationHelperCLI.getReadOnlyReplicationInfo(adminClient, 0, true); // info list for node 1 List<String> infoList1 = ReadOnlyReplicationHelperCLI.getReadOnlyReplicationInfo(adminClient, 1, true); // source list for node 0, i.e. file list on node 1 List<String> srcList0 = getSourceFileList(infoList0, storeName, 1); // dest list for node 0, i.e. file list on node 0 List<String> dstList0 = getDestFileList(infoList0, storeName, 1); // source list for node 1, i.e. file list on node 0 List<String> srcList1 = getSourceFileList(infoList1, storeName, 0); // dest list for node 1, i.e. file list on node 1 List<String> dstList1 = getDestFileList(infoList1, storeName, 0); // compare assertTrue(fileList0.size() > 0); assertTrue(fileList1.size() > 0); assertTrue(isMatch("0_1_0", "0_1_*")); assertTrue(compareWildcardStringLists(fileList1, srcList0)); assertTrue(compareWildcardStringLists(fileList0, dstList0)); assertTrue(compareWildcardStringLists(fileList0, srcList1)); assertTrue(compareWildcardStringLists(fileList1, dstList1)); } }