blob: 4e2f7d6acd814492637fed0b1c487385ae2a8bd6 [file] [log] [blame]
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You 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 org.apache.solr.cloud.autoscaling.sim;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.PrintStream;
import java.util.List;
import java.util.Map;
import java.util.concurrent.TimeUnit;
import org.apache.solr.client.solrj.cloud.autoscaling.Suggester;
import org.apache.solr.cloud.CloudUtil;
import org.apache.solr.common.util.Utils;
import org.apache.solr.util.LogLevel;
import org.junit.Test;
/**
*
*/
@LogLevel("org.apache.solr.cloud.autoscaling=DEBUG")
public class TestSimScenario extends SimSolrCloudTestCase {
// simple scenario to test .autoAddReplicas trigger
String autoAddReplicasScenario =
"# standard comment\n" +
"// java comment\n" +
"create_cluster numNodes=2 // inline comment\n" +
"load_autoscaling json={'cluster-policy'+:+[{'replica'+:+'<3',+'shard'+:+'#EACH',+'collection'+:+'testCollection','node':'#ANY'}]}&defaultWaitFor=10\n" +
"solr_request /admin/collections?action=CREATE&autoAddReplicas=true&name=testCollection&numShards=2&replicationFactor=2&maxShardsPerNode=2\n" +
"wait_collection collection=testCollection&shards=2&replicas=2\n" +
"event_listener trigger=.auto_add_replicas&stage=SUCCEEDED\n" +
"kill_nodes node=${_random_node_}\n" +
"wait_event trigger=.auto_add_replicas&wait=60\n" +
"wait_collection collection=testCollection&shards=2&replicas=2\n" +
"save_snapshot path=${snapshotPath}\n";
@Test
public void testAutoAddReplicas() throws Exception {
String snapshotPath = createTempDir() + "/snapshot";
try (SimScenario scenario = SimScenario.load(autoAddReplicasScenario)) {
scenario.context.put("snapshotPath", snapshotPath);
scenario.run();
}
SnapshotCloudManager snapshotCloudManager = SnapshotCloudManager.readSnapshot(new File(snapshotPath));
CloudUtil.waitForState(snapshotCloudManager, "testCollection", 1, TimeUnit.SECONDS,
CloudUtil.clusterShape(2, 2));
}
String testSuggestionsScenario =
"create_cluster numNodes=2\n" +
"solr_request /admin/collections?action=CREATE&autoAddReplicas=true&name=testCollection&numShards=2&replicationFactor=2&maxShardsPerNode=2\n" +
"wait_collection collection=testCollection&shards=2&replicas=2\n" +
"ctx_set key=myNode&value=${_random_node_}\n" +
"solr_request /admin/collections?action=ADDREPLICA&collection=testCollection&shard=shard1&node=${myNode}\n" +
"solr_request /admin/collections?action=ADDREPLICA&collection=testCollection&shard=shard1&node=${myNode}\n" +
"loop_start iterations=${iterative}\n" +
" calculate_suggestions\n" +
" apply_suggestions\n" +
" solr_request /admin/collections?action=ADDREPLICA&collection=testCollection&shard=shard1&node=${myNode}\n" +
" solr_request /admin/collections?action=ADDREPLICA&collection=testCollection&shard=shard1&node=${myNode}\n" +
"loop_end\n" +
"loop_start iterations=${justCalc}\n" +
" calculate_suggestions\n" +
" save_snapshot path=${snapshotPath}/${_loop_iter_}\n" +
"loop_end\n" +
"dump redact=true";
@Test
public void testSuggestions() throws Exception {
String snapshotPath = createTempDir() + "/snapshot";
try (SimScenario scenario = SimScenario.load(testSuggestionsScenario)) {
scenario.context.put("snapshotPath", snapshotPath);
ByteArrayOutputStream baos = new ByteArrayOutputStream();
PrintStream ps = new PrintStream(baos, true, "UTF-8");
scenario.console = ps;
scenario.context.put("iterative", "0");
scenario.context.put("justCalc", "1");
scenario.run();
@SuppressWarnings({"unchecked"})
List<Suggester.SuggestionInfo> suggestions = (List<Suggester.SuggestionInfo>)scenario.context.get(SimScenario.SUGGESTIONS_CTX_PROP);
assertNotNull(suggestions);
assertEquals(suggestions.toString(), 1, suggestions.size());
// reconstruct the snapshot from the dump
@SuppressWarnings({"unchecked"})
Map<String, Object> snapshot = (Map<String, Object>)Utils.fromJSON(baos.toByteArray());
@SuppressWarnings({"unchecked"})
Map<String, Object> autoscalingState = (Map<String, Object>)snapshot.get(SnapshotCloudManager.AUTOSCALING_STATE_KEY);
assertNotNull(autoscalingState);
assertEquals(autoscalingState.toString(), 1, autoscalingState.size());
assertTrue(autoscalingState.toString(), autoscalingState.containsKey("suggestions"));
@SuppressWarnings({"unchecked"})
List<Map<String, Object>> snapSuggestions = (List<Map<String, Object>>)autoscalingState.get("suggestions");
assertEquals(snapSuggestions.toString(), 1, snapSuggestions.size());
// _loop_iter_ should be present and 0 (first iteration)
assertEquals("0", scenario.context.get(SimScenario.LOOP_ITER_PROP));
}
// try looping more times
try (SimScenario scenario = SimScenario.load(testSuggestionsScenario)) {
scenario.context.put("iterative", "10");
scenario.context.put("justCalc", "0");
scenario.run();
assertEquals("9", scenario.context.get(SimScenario.LOOP_ITER_PROP));
}
}
String indexingScenario =
"create_cluster numNodes=100\n" +
"solr_request /admin/collections?action=CREATE&autoAddReplicas=true&name=testCollection&numShards=2&replicationFactor=2&maxShardsPerNode=2\n" +
"wait_collection collection=testCollection&shards=2&replicas=2\n" +
"solr_request /admin/autoscaling?httpMethod=POST&stream.body=" +
"{'set-trigger':{'name':'indexSizeTrigger','event':'indexSize','waitFor':'10s','aboveDocs':1000,'enabled':true,"+
"'actions':[{'name':'compute_plan','class':'solr.ComputePlanAction'},{'name':'execute_plan','class':'solr.ExecutePlanAction'}]}}\n" +
"event_listener trigger=indexSizeTrigger&stage=SUCCEEDED\n" +
"index_docs collection=testCollection&numDocs=3000\n" +
"run\n" +
"wait_event trigger=indexSizeTrigger&wait=60\n" +
"assert condition=not_null&key=_trigger_event_indexSizeTrigger\n" +
"assert condition=equals&key=_trigger_event_indexSizeTrigger/eventType&expected=INDEXSIZE\n" +
"assert condition=equals&key=_trigger_event_indexSizeTrigger/properties/requestedOps[0]/action&expected=SPLITSHARD\n" +
"wait_collection collection=testCollection&shards=6&withInactive=true&requireLeaders=false&replicas=2";
@Test
public void testIndexing() throws Exception {
try (SimScenario scenario = SimScenario.load(indexingScenario)) {
scenario.run();
}
}
String splitShardScenario =
"create_cluster numNodes=2\n" +
"solr_request /admin/collections?action=CREATE&name=testCollection&numShards=2&replicationFactor=2&maxShardsPerNode=5\n" +
"wait_collection collection=testCollection&shards=2&replicas=2\n" +
"set_shard_metrics collection=testCollection&shard=shard1&INDEX.sizeInBytes=1000000000\n" +
"set_node_metrics nodeset=#ANY&freedisk=1.5\n" +
"solr_request /admin/collection?action=SPLITSHARD&collection=testCollection&shard=shard1&splitMethod=${method}\n" +
"wait_collection collection=testCollection&shards=4&&withInactive=true&replicas=2&requireLeaders=true\n"
;
@Test
public void testSplitShard() throws Exception {
try (SimScenario scenario = SimScenario.load(splitShardScenario)) {
scenario.context.put("method", "REWRITE");
scenario.run();
} catch (Exception e) {
assertTrue(e.toString(), e.toString().contains("not enough free disk"));
}
try (SimScenario scenario = SimScenario.load(splitShardScenario)) {
scenario.context.put("method", "LINK");
scenario.run();
} catch (Exception e) {
fail("should have succeeded with method LINK, but failed: " + e.toString());
}
}
}