private void testCollectionsAPI() throws Exception { // TODO: fragile - because we dont pass collection.confName, it will only // find a default if a conf set with a name matching the collection name is found, or // if there is only one conf set. That and the fact that other tests run first in this // env make this pretty fragile // create new collections rapid fire Map<String, List<Integer>> collectionInfos = new HashMap<String, List<Integer>>(); int cnt = random().nextInt(TEST_NIGHTLY ? 6 : 3) + 1; for (int i = 0; i < cnt; i++) { int numShards = _TestUtil.nextInt(random(), 0, shardCount) + 1; int replicationFactor = _TestUtil.nextInt(random(), 0, 3) + 1; int maxShardsPerNode = (((numShards * replicationFactor) / getCommonCloudSolrServer() .getZkStateReader() .getClusterState() .getLiveNodes() .size())) + 1; CloudSolrServer client = null; try { if (i == 0) { // Test if we can create a collection through CloudSolrServer where // you havnt set default-collection // This is nice because you want to be able to create you first // collection using CloudSolrServer, and in such case there is // nothing reasonable to set as default-collection client = createCloudClient(null); } else if (i == 1) { // Test if we can create a collection through CloudSolrServer where // you have set default-collection to a non-existing collection // This is nice because you want to be able to create you first // collection using CloudSolrServer, and in such case there is // nothing reasonable to set as default-collection, but you might want // to use the same CloudSolrServer throughout the entire // lifetime of your client-application, so it is nice to be able to // set a default-collection on this CloudSolrServer once and for all // and use this CloudSolrServer to create the collection client = createCloudClient("awholynewcollection_" + i); } if (secondConfigSet) { createCollection( collectionInfos, "awholynewcollection_" + i, numShards, replicationFactor, maxShardsPerNode, client, null, "conf2"); } else { createCollection( collectionInfos, "awholynewcollection_" + i, numShards, replicationFactor, maxShardsPerNode, client, null); } } finally { if (client != null) client.shutdown(); } } Set<Entry<String, List<Integer>>> collectionInfosEntrySet = collectionInfos.entrySet(); for (Entry<String, List<Integer>> entry : collectionInfosEntrySet) { String collection = entry.getKey(); List<Integer> list = entry.getValue(); checkForCollection(collection, list, null); String url = getUrlFromZk(collection); HttpSolrServer collectionClient = new HttpSolrServer(url); // poll for a second - it can take a moment before we are ready to serve waitForNon403or404or503(collectionClient); } // sometimes we restart one of the jetty nodes if (random().nextBoolean()) { JettySolrRunner jetty = jettys.get(random().nextInt(jettys.size())); ChaosMonkey.stop(jetty); ChaosMonkey.start(jetty); for (Entry<String, List<Integer>> entry : collectionInfosEntrySet) { String collection = entry.getKey(); List<Integer> list = entry.getValue(); checkForCollection(collection, list, null); String url = getUrlFromZk(collection); HttpSolrServer collectionClient = new HttpSolrServer(url); // poll for a second - it can take a moment before we are ready to serve waitForNon403or404or503(collectionClient); } } // sometimes we restart zookeeper if (random().nextBoolean()) { zkServer.shutdown(); zkServer = new ZkTestServer(zkServer.getZkDir(), zkServer.getPort()); zkServer.run(); } // sometimes we cause a connection loss - sometimes it will hit the overseer if (random().nextBoolean()) { JettySolrRunner jetty = jettys.get(random().nextInt(jettys.size())); ChaosMonkey.causeConnectionLoss(jetty); } ZkStateReader zkStateReader = getCommonCloudSolrServer().getZkStateReader(); for (int j = 0; j < cnt; j++) { waitForRecoveriesToFinish("awholynewcollection_" + j, zkStateReader, false); if (secondConfigSet) { // let's see if they are using the second config set byte[] data = zkStateReader .getZkClient() .getData( ZkStateReader.COLLECTIONS_ZKNODE + "/" + "awholynewcollection_" + j, null, null, true); assertNotNull(data); ZkNodeProps props = ZkNodeProps.load(data); String configName = props.getStr(ZkController.CONFIGNAME_PROP); assertEquals("conf2", configName); } } checkInstanceDirs(jettys.get(0)); List<String> collectionNameList = new ArrayList<String>(); collectionNameList.addAll(collectionInfos.keySet()); String collectionName = collectionNameList.get(random().nextInt(collectionNameList.size())); String url = getUrlFromZk(collectionName); HttpSolrServer collectionClient = new HttpSolrServer(url); // lets try and use the solrj client to index a couple documents SolrInputDocument doc1 = getDoc(id, 6, i1, -600, tlong, 600, t1, "humpty dumpy sat on a wall"); SolrInputDocument doc2 = getDoc(id, 7, i1, -600, tlong, 600, t1, "humpty dumpy3 sat on a walls"); SolrInputDocument doc3 = getDoc(id, 8, i1, -600, tlong, 600, t1, "humpty dumpy2 sat on a walled"); collectionClient.add(doc1); collectionClient.add(doc2); collectionClient.add(doc3); collectionClient.commit(); assertEquals(3, collectionClient.query(new SolrQuery("*:*")).getResults().getNumFound()); // lets try a collection reload // get core open times Map<String, Long> urlToTimeBefore = new HashMap<String, Long>(); collectStartTimes(collectionName, urlToTimeBefore); assertTrue(urlToTimeBefore.size() > 0); ModifiableSolrParams params = new ModifiableSolrParams(); params.set("action", CollectionAction.RELOAD.toString()); params.set("name", collectionName); QueryRequest request = new QueryRequest(params); request.setPath("/admin/collections"); // we can use this client because we just want base url final String baseUrl = getBaseUrl((HttpSolrServer) clients.get(0)); createNewSolrServer("", baseUrl).request(request); // reloads make take a short while boolean allTimesAreCorrect = waitForReloads(collectionName, urlToTimeBefore); assertTrue("some core start times did not change on reload", allTimesAreCorrect); waitForRecoveriesToFinish("awholynewcollection_" + (cnt - 1), zkStateReader, false); // remove a collection params = new ModifiableSolrParams(); params.set("action", CollectionAction.DELETE.toString()); params.set("name", collectionName); request = new QueryRequest(params); request.setPath("/admin/collections"); createNewSolrServer("", baseUrl).request(request); // ensure its out of the state checkForMissingCollection(collectionName); // collectionNameList.remove(collectionName); // remove an unknown collection params = new ModifiableSolrParams(); params.set("action", CollectionAction.DELETE.toString()); params.set("name", "unknown_collection"); request = new QueryRequest(params); request.setPath("/admin/collections"); boolean exp = false; try { createNewSolrServer("", baseUrl).request(request); } catch (SolrException e) { exp = true; } assertTrue("Expected exception", exp); // create another collection should still work params = new ModifiableSolrParams(); params.set("action", CollectionAction.CREATE.toString()); params.set("numShards", 1); params.set(REPLICATION_FACTOR, 2); collectionName = "acollectionafterbaddelete"; params.set("name", collectionName); if (secondConfigSet) { params.set("collection.configName", "conf1"); } request = new QueryRequest(params); request.setPath("/admin/collections"); createNewSolrServer("", baseUrl).request(request); List<Integer> list = new ArrayList<Integer>(2); list.add(1); list.add(2); checkForCollection(collectionName, list, null); url = getUrlFromZk(collectionName); collectionClient = new HttpSolrServer(url); // poll for a second - it can take a moment before we are ready to serve waitForNon403or404or503(collectionClient); for (int j = 0; j < cnt; j++) { waitForRecoveriesToFinish(collectionName, zkStateReader, false); } // test maxShardsPerNode int numLiveNodes = getCommonCloudSolrServer().getZkStateReader().getClusterState().getLiveNodes().size(); int numShards = (numLiveNodes / 2) + 1; int replicationFactor = 2; int maxShardsPerNode = 1; collectionInfos = new HashMap<String, List<Integer>>(); CloudSolrServer client = createCloudClient("awholynewcollection_" + cnt); try { exp = false; try { createCollection( collectionInfos, "awholynewcollection_" + cnt, numShards, replicationFactor, maxShardsPerNode, client, null, "conf1"); } catch (SolrException e) { exp = true; } assertTrue("expected exception", exp); } finally { client.shutdown(); } // Test createNodeSet numLiveNodes = getCommonCloudSolrServer().getZkStateReader().getClusterState().getLiveNodes().size(); List<String> createNodeList = new ArrayList<String>(); int numOfCreateNodes = numLiveNodes / 2; assertFalse( "createNodeSet test is pointless with only " + numLiveNodes + " nodes running", numOfCreateNodes == 0); int i = 0; for (String liveNode : getCommonCloudSolrServer().getZkStateReader().getClusterState().getLiveNodes()) { if (i < numOfCreateNodes) { createNodeList.add(liveNode); i++; } else { break; } } maxShardsPerNode = 2; numShards = createNodeList.size() * maxShardsPerNode; replicationFactor = 1; collectionInfos = new HashMap<String, List<Integer>>(); client = createCloudClient("awholynewcollection_" + (cnt + 1)); try { createCollection( collectionInfos, "awholynewcollection_" + (cnt + 1), numShards, replicationFactor, maxShardsPerNode, client, StrUtils.join(createNodeList, ','), "conf1"); } finally { client.shutdown(); } checkForCollection( collectionInfos.keySet().iterator().next(), collectionInfos.entrySet().iterator().next().getValue(), createNodeList); checkNoTwoShardsUseTheSameIndexDir(); }
protected Set<String> commonMocks(int liveNodesCount) throws Exception { shardHandlerFactoryMock.getShardHandler(); expectLastCall() .andAnswer( new IAnswer<ShardHandler>() { @Override public ShardHandler answer() throws Throwable { log.info("SHARDHANDLER"); return shardHandlerMock; } }) .anyTimes(); workQueueMock.peekTopN(EasyMock.anyInt(), anyObject(Set.class), EasyMock.anyLong()); expectLastCall() .andAnswer( new IAnswer<List>() { @Override public List answer() throws Throwable { Object result; int count = 0; while ((result = queue.peek()) == null) { Thread.sleep(1000); count++; if (count > 1) return null; } return Arrays.asList(result); } }) .anyTimes(); workQueueMock.getTailId(); expectLastCall() .andAnswer( new IAnswer<Object>() { @Override public Object answer() throws Throwable { Object result = null; Iterator iter = queue.iterator(); while (iter.hasNext()) { result = iter.next(); } return result == null ? null : ((QueueEvent) result).getId(); } }) .anyTimes(); workQueueMock.peek(true); expectLastCall() .andAnswer( new IAnswer<Object>() { @Override public Object answer() throws Throwable { Object result; while ((result = queue.peek()) == null) { Thread.sleep(1000); } return result; } }) .anyTimes(); workQueueMock.remove(anyObject(QueueEvent.class)); expectLastCall() .andAnswer( new IAnswer<Object>() { @Override public Object answer() throws Throwable { queue.remove((QueueEvent) getCurrentArguments()[0]); return null; } }) .anyTimes(); workQueueMock.poll(); expectLastCall() .andAnswer( new IAnswer<Object>() { @Override public Object answer() throws Throwable { return queue.poll(); } }) .anyTimes(); zkStateReaderMock.getClusterState(); expectLastCall() .andAnswer( new IAnswer<Object>() { @Override public Object answer() throws Throwable { return clusterStateMock; } }) .anyTimes(); zkStateReaderMock.getZkClient(); expectLastCall() .andAnswer( new IAnswer<Object>() { @Override public Object answer() throws Throwable { return solrZkClientMock; } }) .anyTimes(); zkStateReaderMock.updateClusterState(anyBoolean()); clusterStateMock.getCollections(); expectLastCall() .andAnswer( new IAnswer<Object>() { @Override public Object answer() throws Throwable { return collectionsSet; } }) .anyTimes(); final Set<String> liveNodes = new HashSet<>(); for (int i = 0; i < liveNodesCount; i++) { final String address = "localhost:" + (8963 + i) + "_solr"; liveNodes.add(address); zkStateReaderMock.getBaseUrlForNodeName(address); expectLastCall() .andAnswer( new IAnswer<Object>() { @Override public Object answer() throws Throwable { // This works as long as this test does not use a // webapp context with an underscore in it return address.replaceAll("_", "/"); } }) .anyTimes(); } zkStateReaderMock.getClusterProps(); expectLastCall() .andAnswer( new IAnswer<Map>() { @Override public Map answer() throws Throwable { return new HashMap(); } }); solrZkClientMock.getZkClientTimeout(); expectLastCall() .andAnswer( new IAnswer<Object>() { @Override public Object answer() throws Throwable { return 30000; } }) .anyTimes(); clusterStateMock.hasCollection(anyObject(String.class)); expectLastCall() .andAnswer( new IAnswer<Boolean>() { @Override public Boolean answer() throws Throwable { String key = (String) getCurrentArguments()[0]; return collectionsSet.contains(key); } }) .anyTimes(); clusterStateMock.getLiveNodes(); expectLastCall() .andAnswer( new IAnswer<Object>() { @Override public Object answer() throws Throwable { return liveNodes; } }) .anyTimes(); solrZkClientMock.create( anyObject(String.class), anyObject(byte[].class), anyObject(CreateMode.class), anyBoolean()); expectLastCall() .andAnswer( new IAnswer<String>() { @Override public String answer() throws Throwable { String key = (String) getCurrentArguments()[0]; zkMap.put(key, null); handleCreateCollMessage((byte[]) getCurrentArguments()[1]); return key; } }) .anyTimes(); solrZkClientMock.makePath(anyObject(String.class), anyObject(byte[].class), anyBoolean()); expectLastCall() .andAnswer( new IAnswer<String>() { @Override public String answer() throws Throwable { String key = (String) getCurrentArguments()[0]; return key; } }) .anyTimes(); solrZkClientMock.makePath( anyObject(String.class), anyObject(byte[].class), anyObject(CreateMode.class), anyBoolean()); expectLastCall() .andAnswer( new IAnswer<String>() { @Override public String answer() throws Throwable { String key = (String) getCurrentArguments()[0]; return key; } }) .anyTimes(); solrZkClientMock.exists(anyObject(String.class), anyBoolean()); expectLastCall() .andAnswer( new IAnswer<Boolean>() { @Override public Boolean answer() throws Throwable { String key = (String) getCurrentArguments()[0]; return zkMap.containsKey(key); } }) .anyTimes(); zkMap.put("/configs/myconfig", null); return liveNodes; }