diff --git a/src/main/java/com/netflix/simianarmy/Monkey.java b/src/main/java/com/netflix/simianarmy/Monkey.java index d7b76b00..23fc25a5 100644 --- a/src/main/java/com/netflix/simianarmy/Monkey.java +++ b/src/main/java/com/netflix/simianarmy/Monkey.java @@ -43,6 +43,10 @@ public Monkey(Context ctx) { public abstract void doMonkeyBusiness(); + public Context context() { + return ctx; + } + public void start() { final Monkey me = this; ctx.scheduler().start(type().name(), new Runnable() { diff --git a/src/main/java/com/netflix/simianarmy/MonkeyRunner.java b/src/main/java/com/netflix/simianarmy/MonkeyRunner.java index 7772c561..1cb586a1 100644 --- a/src/main/java/com/netflix/simianarmy/MonkeyRunner.java +++ b/src/main/java/com/netflix/simianarmy/MonkeyRunner.java @@ -88,7 +88,8 @@ public void replaceMonkey(Class monkeyClass, Class monkeyClass) { @@ -101,12 +102,22 @@ public void removeMonkey(Class monkeyClass) { break; } } - monkeyMap.remove(monkeyClass); } public T factory(Class monkeyClass) { - return factory(monkeyClass, getContextClass(monkeyClass)); + Class ctxClass = getContextClass(monkeyClass); + if (ctxClass == null) { + // look for derived class already in our map + for (Map.Entry, Class> pair : monkeyMap.entrySet()) { + if (monkeyClass.isAssignableFrom(pair.getKey())) { + @SuppressWarnings("unchecked") + T monkey = (T) factory(pair.getKey(), pair.getValue()); + return monkey; + } + } + } + return factory(monkeyClass, ctxClass); } public T factory(Class monkeyClass, Class contextClass) { @@ -115,14 +126,22 @@ public T factory(Class monkeyClass, Class ctor = monkeyClass.getDeclaredConstructor(ctorArgClass); - return ctor.newInstance(contextClass.newInstance()); + for (Constructor ctor : monkeyClass.getDeclaredConstructors()) { + Class[] paramTypes = ctor.getParameterTypes(); + if (paramTypes.length != 1) { + continue; + } + if (paramTypes[0].getName().endsWith("$Context")) { + @SuppressWarnings("unchecked") + T monkey = (T) ctor.newInstance(contextClass.newInstance()); + return monkey; + } + } } catch (Exception e) { - LOGGER.error("monkeyFactory error: ", e); + LOGGER.error("monkeyFactory error, cannot make monkey from " + monkeyClass.getName() + " with " + + (contextClass == null ? null : contextClass.getName()), e); } return null; diff --git a/src/main/java/com/netflix/simianarmy/basic/BasicContext.java b/src/main/java/com/netflix/simianarmy/basic/BasicContext.java index 1c81dc18..853ad5d0 100644 --- a/src/main/java/com/netflix/simianarmy/basic/BasicContext.java +++ b/src/main/java/com/netflix/simianarmy/basic/BasicContext.java @@ -32,6 +32,9 @@ import com.netflix.simianarmy.aws.AWSClient; import com.netflix.simianarmy.aws.SimpleDBRecorder; +import com.netflix.simianarmy.basic.chaos.BasicChaosCrawler; +import com.netflix.simianarmy.basic.chaos.BasicChaosInstanceSelector; + import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -72,7 +75,7 @@ public BasicContext() { client = new AWSClient(account, secret, region); scheduler = new BasicScheduler((int) config.getNumOrElse("monkey.threads", MONKEY_THREADS)); crawler = new BasicChaosCrawler(client); - selector = new ChaosInstanceSelector(); + selector = new BasicChaosInstanceSelector(); String domain = config.getStrOrElse("domain", "SIMIAN_ARMY"); recorder = new SimpleDBRecorder(account, secret, region, domain); } diff --git a/src/main/java/com/netflix/simianarmy/basic/BasicMonkeyServer.java b/src/main/java/com/netflix/simianarmy/basic/BasicMonkeyServer.java index 36522db2..1c4f81d0 100644 --- a/src/main/java/com/netflix/simianarmy/basic/BasicMonkeyServer.java +++ b/src/main/java/com/netflix/simianarmy/basic/BasicMonkeyServer.java @@ -24,7 +24,7 @@ import org.slf4j.LoggerFactory; import com.netflix.simianarmy.MonkeyRunner; -import com.netflix.simianarmy.chaos.ChaosMonkey; +import com.netflix.simianarmy.basic.chaos.BasicChaosMonkey; @SuppressWarnings("serial") public class BasicMonkeyServer extends HttpServlet { @@ -34,14 +34,14 @@ public class BasicMonkeyServer extends HttpServlet { @Override public void init() throws ServletException { super.init(); - RUNNER.replaceMonkey(ChaosMonkey.class, BasicContext.class); + RUNNER.replaceMonkey(BasicChaosMonkey.class, BasicContext.class); RUNNER.start(); } @Override public void destroy() { RUNNER.stop(); - RUNNER.removeMonkey(ChaosMonkey.class); + RUNNER.removeMonkey(BasicChaosMonkey.class); super.destroy(); } } diff --git a/src/main/java/com/netflix/simianarmy/basic/BasicChaosCrawler.java b/src/main/java/com/netflix/simianarmy/basic/chaos/BasicChaosCrawler.java similarity index 98% rename from src/main/java/com/netflix/simianarmy/basic/BasicChaosCrawler.java rename to src/main/java/com/netflix/simianarmy/basic/chaos/BasicChaosCrawler.java index 15a416c1..c11cca93 100644 --- a/src/main/java/com/netflix/simianarmy/basic/BasicChaosCrawler.java +++ b/src/main/java/com/netflix/simianarmy/basic/chaos/BasicChaosCrawler.java @@ -15,7 +15,7 @@ * limitations under the License. * */ -package com.netflix.simianarmy.basic; +package com.netflix.simianarmy.basic.chaos; import java.util.List; import java.util.LinkedList; @@ -43,7 +43,7 @@ public BasicChaosCrawler(AWSClient awsClient) { public static class BasicInstanceGroup implements InstanceGroup { private final String name; private final Enum type; - + public BasicInstanceGroup(String name) { this.name = name; this.type = Types.ASG; diff --git a/src/main/java/com/netflix/simianarmy/basic/chaos/BasicChaosInstanceSelector.java b/src/main/java/com/netflix/simianarmy/basic/chaos/BasicChaosInstanceSelector.java new file mode 100644 index 00000000..60745796 --- /dev/null +++ b/src/main/java/com/netflix/simianarmy/basic/chaos/BasicChaosInstanceSelector.java @@ -0,0 +1,50 @@ +/* + * + * Copyright 2012 Netflix, 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 com.netflix.simianarmy.basic.chaos; + +import java.util.Random; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import com.netflix.simianarmy.chaos.ChaosInstanceSelector; +import com.netflix.simianarmy.chaos.ChaosCrawler.InstanceGroup; + +public class BasicChaosInstanceSelector implements ChaosInstanceSelector { + private static final Logger LOGGER = LoggerFactory.getLogger(ChaosInstanceSelector.class); + private static final Random RANDOM = new Random(); + + protected Logger logger() { + return LOGGER; + } + + public String select(InstanceGroup group, double probability) { + if (probability <= 0) { + logger().info("Group {} [type {}] has disabled probability: {}", + new Object[] {group.name(), group.type(), probability}); + return null; + } + double rand = Math.random(); + if (rand > probability) { + logger().info("Group {} [type {}] got lucky: {} > {}", + new Object[] {group.name(), group.type(), rand, probability}); + return null; + } + return group.instances().get(RANDOM.nextInt(group.instances().size())); + } +} diff --git a/src/main/java/com/netflix/simianarmy/basic/chaos/BasicChaosMonkey.java b/src/main/java/com/netflix/simianarmy/basic/chaos/BasicChaosMonkey.java new file mode 100644 index 00000000..910a367d --- /dev/null +++ b/src/main/java/com/netflix/simianarmy/basic/chaos/BasicChaosMonkey.java @@ -0,0 +1,180 @@ +/* + * + * Copyright 2012 Netflix, 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 com.netflix.simianarmy.basic.chaos; + +import com.netflix.simianarmy.chaos.ChaosMonkey; +import com.netflix.simianarmy.MonkeyConfiguration; +import com.netflix.simianarmy.MonkeyRunner; +import com.netflix.simianarmy.MonkeyRecorder.Event; +import com.netflix.simianarmy.chaos.ChaosCrawler.InstanceGroup; + +import java.util.Map; +import java.util.HashMap; +import java.util.List; +import java.util.Calendar; +import java.util.Date; +import java.util.concurrent.TimeUnit; +import java.io.ByteArrayOutputStream; +import java.io.IOException; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import javax.ws.rs.GET; +import javax.ws.rs.Path; +import javax.ws.rs.core.Response; +import javax.ws.rs.core.UriInfo; + +import org.codehaus.jackson.JsonEncoding; +import org.codehaus.jackson.JsonGenerator; +import org.codehaus.jackson.map.MappingJsonFactory; + +public class BasicChaosMonkey extends ChaosMonkey { + private static final Logger LOGGER = LoggerFactory.getLogger(ChaosMonkey.class); + private static final String NS = "simianarmy.chaos."; + + private MonkeyConfiguration cfg; + private long runsPerDay; + + public BasicChaosMonkey(ChaosMonkey.Context ctx) { + super(ctx); + + this.cfg = ctx.configuration(); + + Calendar open = ctx.calendar().now(); + Calendar close = ctx.calendar().now(); + open.set(Calendar.HOUR, ctx.calendar().openHour()); + close.set(Calendar.HOUR, ctx.calendar().closeHour()); + + TimeUnit freqUnit = ctx.scheduler().frequencyUnit(); + long units = freqUnit.convert(close.getTimeInMillis() - open.getTimeInMillis(), TimeUnit.MILLISECONDS); + runsPerDay = units / ctx.scheduler().frequency(); + } + + public void doMonkeyBusiness() { + cfg.reload(); + String prop = NS + "enabled"; + if (!cfg.getBoolOrElse(prop, true)) { + LOGGER.info("ChaosMonkey disabled, set {}=true", prop); + return; + } + + for (InstanceGroup group : context().chaosCrawler().groups()) { + prop = NS + group.type() + "." + group.name() + ".enabled"; + String defaultProp = NS + group.type(); + if (cfg.getBoolOrElse(prop, cfg.getBool(defaultProp + ".enabled"))) { + String probProp = NS + group.type() + "." + group.name() + ".probability"; + double prob = cfg.getNumOrElse(probProp, cfg.getNumOrElse(defaultProp + ".probability", 1.0)); + String inst = context().chaosInstanceSelector().select(group, prob / runsPerDay); + if (inst != null) { + prop = NS + "leashed"; + if (cfg.getBoolOrElse(prop, true)) { + LOGGER.info("leashed ChaosMonkey prevented from killing {}, set {}=false", inst, prop); + } else { + if (hasPreviousTerminations(group)) { + LOGGER.info("ChaosMonkey takes pity on group {} [{}] since it was attacked ealier today", + group.name(), group.type()); + continue; + } + try { + recordTermination(group, inst); + context().cloudClient().terminateInstance(inst); + } catch (Exception e) { + handleTerminationError(inst, e); + } + } + } + } else { + LOGGER.info("Group {} [type {}] disabled, set {}=true or {}=true", + new Object[] {group.name(), group.type(), prop, defaultProp + ".enabled"}); + } + } + } + + // abstracted so subclasses can decide to continue causing chaos if desired + protected void handleTerminationError(String instance, Throwable e) { + LOGGER.error("failed to terminate instance " + instance, e.getMessage()); + throw new RuntimeException("failed to terminate instance " + instance, e); + } + + public boolean hasPreviousTerminations(InstanceGroup group) { + Map query = new HashMap(); + query.put("groupType", group.type().name()); + query.put("groupName", group.name()); + Calendar today = Calendar.getInstance(); + // set to midnight + today.set(Calendar.HOUR_OF_DAY, 0); + today.set(Calendar.MINUTE, 0); + today.set(Calendar.SECOND, 0); + today.set(Calendar.MILLISECOND, 0); + List evts = context().recorder().findEvents(Type.CHAOS, EventTypes.CHAOS_TERMINATION, query, + today.getTime()); + return !evts.isEmpty(); + } + + public void recordTermination(InstanceGroup group, String instance) { + Event evt = context().recorder().newEvent(Type.CHAOS, EventTypes.CHAOS_TERMINATION, instance); + evt.addField("groupType", group.type().name()); + evt.addField("groupName", group.name()); + context().recorder().recordEvent(evt); + } + + @Path("/chaos") + @SuppressWarnings("serial") + public static class Servlet { + private static final MappingJsonFactory JSON_FACTORY = new MappingJsonFactory(); + + private ChaosMonkey monkey = MonkeyRunner.getInstance().factory(ChaosMonkey.class); + + @GET + public Response getChaosEvents(@javax.ws.rs.core.Context UriInfo uriInfo) throws IOException { + Map query = new HashMap(); + Date date = new Date(0); + for (Map.Entry> pair : uriInfo.getQueryParameters().entrySet()) { + if (pair.getValue().isEmpty()) { + continue; + } + if (pair.getKey().equals("since")) { + date = new Date(Long.parseLong(pair.getValue().get(0))); + } else { + query.put(pair.getKey(), pair.getValue().get(0)); + } + } + + List evts = monkey.context().recorder() + .findEvents(Type.CHAOS, EventTypes.CHAOS_TERMINATION, query, date); + + ByteArrayOutputStream baos = new ByteArrayOutputStream(); + JsonGenerator gen = JSON_FACTORY.createJsonGenerator(baos, JsonEncoding.UTF8); + gen.writeStartArray(); + for (Event evt : evts) { + gen.writeStartObject(); + gen.writeStringField("monkeyType", evt.monkeyType().name()); + gen.writeStringField("eventType", evt.eventType().name()); + gen.writeNumberField("eventTime", evt.eventTime().getTime()); + for (Map.Entry pair : evt.fields().entrySet()) { + gen.writeStringField(pair.getKey(), pair.getValue()); + } + gen.writeEndObject(); + } + gen.writeEndArray(); + gen.close(); + return Response.status(Response.Status.OK).entity(baos).build(); + } + } +} diff --git a/src/main/java/com/netflix/simianarmy/chaos/ChaosInstanceSelector.java b/src/main/java/com/netflix/simianarmy/chaos/ChaosInstanceSelector.java index 4ebbe1d1..077fff98 100644 --- a/src/main/java/com/netflix/simianarmy/chaos/ChaosInstanceSelector.java +++ b/src/main/java/com/netflix/simianarmy/chaos/ChaosInstanceSelector.java @@ -17,33 +17,8 @@ */ package com.netflix.simianarmy.chaos; -import java.util.Random; - -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - import com.netflix.simianarmy.chaos.ChaosCrawler.InstanceGroup; -public class ChaosInstanceSelector { - private static final Logger LOGGER = LoggerFactory.getLogger(ChaosInstanceSelector.class); - private static final Random RANDOM = new Random(); - - protected Logger logger() { - return LOGGER; - } - - public String select(InstanceGroup group, double probability) { - if (probability <= 0) { - logger().info("Group {} [type {}] has disabled probability: {}", - new Object[] {group.name(), group.type(), probability}); - return null; - } - double rand = Math.random(); - if (rand > probability) { - logger().info("Group {} [type {}] got lucky: {} > {}", - new Object[] {group.name(), group.type(), rand, probability}); - return null; - } - return group.instances().get(RANDOM.nextInt(group.instances().size())); - } +public interface ChaosInstanceSelector { + String select(InstanceGroup group, double probability); } diff --git a/src/main/java/com/netflix/simianarmy/chaos/ChaosMonkey.java b/src/main/java/com/netflix/simianarmy/chaos/ChaosMonkey.java index 3ef85f8f..860f273b 100644 --- a/src/main/java/com/netflix/simianarmy/chaos/ChaosMonkey.java +++ b/src/main/java/com/netflix/simianarmy/chaos/ChaosMonkey.java @@ -20,35 +20,7 @@ import com.netflix.simianarmy.Monkey; import com.netflix.simianarmy.MonkeyConfiguration; -import java.util.Map; -import java.util.HashMap; -import java.util.List; -import java.util.Calendar; -import java.util.Date; -import java.util.concurrent.TimeUnit; -import java.io.ByteArrayOutputStream; -import java.io.IOException; - -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -import com.netflix.simianarmy.MonkeyRunner; -import com.netflix.simianarmy.MonkeyRecorder.Event; -import com.netflix.simianarmy.chaos.ChaosCrawler.InstanceGroup; - -import javax.ws.rs.GET; -import javax.ws.rs.Path; -import javax.ws.rs.core.Context; -import javax.ws.rs.core.Response; -import javax.ws.rs.core.UriInfo; - -import org.codehaus.jackson.JsonEncoding; -import org.codehaus.jackson.JsonGenerator; -import org.codehaus.jackson.map.MappingJsonFactory; - -public class ChaosMonkey extends Monkey { - private static final Logger LOGGER = LoggerFactory.getLogger(ChaosMonkey.class); - private static final String NS = "simianarmy.chaos."; +public abstract class ChaosMonkey extends Monkey { public interface Context extends Monkey.Context { MonkeyConfiguration configuration(); @@ -59,143 +31,31 @@ public interface Context extends Monkey.Context { } private Context ctx; - private MonkeyConfiguration cfg; - private long runsPerDay; public ChaosMonkey(Context ctx) { super(ctx); this.ctx = ctx; - this.cfg = ctx.configuration(); - - Calendar open = ctx.calendar().now(); - Calendar close = ctx.calendar().now(); - open.set(Calendar.HOUR, ctx.calendar().openHour()); - close.set(Calendar.HOUR, ctx.calendar().closeHour()); - - TimeUnit freqUnit = ctx.scheduler().frequencyUnit(); - long units = freqUnit.convert(close.getTimeInMillis() - open.getTimeInMillis(), TimeUnit.MILLISECONDS); - runsPerDay = units / ctx.scheduler().frequency(); } public enum Type { CHAOS } - public Enum type() { - return Type.CHAOS; - } - public enum EventTypes { CHAOS_TERMINATION } - public void doMonkeyBusiness() { - cfg.reload(); - String prop = NS + "enabled"; - if (!cfg.getBoolOrElse(prop, true)) { - LOGGER.info("ChaosMonkey disabled, set {}=true", prop); - return; - } - - for (InstanceGroup group : ctx.chaosCrawler().groups()) { - prop = NS + group.type() + "." + group.name() + ".enabled"; - String defaultProp = NS + group.type(); - if (cfg.getBoolOrElse(prop, cfg.getBool(defaultProp + ".enabled"))) { - String probProp = NS + group.type() + "." + group.name() + ".probability"; - double prob = cfg.getNumOrElse(probProp, cfg.getNumOrElse(defaultProp + ".probability", 1.0)); - String inst = ctx.chaosInstanceSelector().select(group, prob / runsPerDay); - if (inst != null) { - prop = NS + "leashed"; - if (cfg.getBoolOrElse(prop, true)) { - LOGGER.info("leashed ChaosMonkey prevented from killing {}, set {}=false", inst, prop); - } else { - if (hasPreviousTerminations(group)) { - LOGGER.info("ChaosMonkey takes pity on group {} [{}] since it was attacked ealier today", - group.name(), group.type()); - continue; - } - try { - recordTermination(group, inst); - ctx.cloudClient().terminateInstance(inst); - } catch (Exception e) { - handleTerminationError(inst, e); - } - } - } - } else { - LOGGER.info("Group {} [type {}] disabled, set {}=true or {}=true", - new Object[] {group.name(), group.type(), prop, defaultProp + ".enabled"}); - } - } - } - - // abstracted so subclasses can decide to continue causing chaos if desired - protected void handleTerminationError(String instance, Throwable e) { - LOGGER.error("failed to terminate instance " + instance, e.getMessage()); - throw new RuntimeException("failed to terminate instance " + instance, e); - } - - protected boolean hasPreviousTerminations(InstanceGroup group) { - Map query = new HashMap(); - query.put("groupType", group.type().name()); - query.put("groupName", group.name()); - Calendar today = Calendar.getInstance(); - // set to midnight - today.set(Calendar.HOUR_OF_DAY, 0); - today.set(Calendar.MINUTE, 0); - today.set(Calendar.SECOND, 0); - today.set(Calendar.MILLISECOND, 0); - List evts = ctx.recorder().findEvents(Type.CHAOS, EventTypes.CHAOS_TERMINATION, query, today.getTime()); - return !evts.isEmpty(); + public final Enum type() { + return Type.CHAOS; } - protected void recordTermination(InstanceGroup group, String instance) { - Event evt = ctx.recorder().newEvent(Type.CHAOS, EventTypes.CHAOS_TERMINATION, instance); - evt.addField("groupType", group.type().name()); - evt.addField("groupName", group.name()); - ctx.recorder().recordEvent(evt); + public Context context() { + return ctx; } - @Path("/chaos") - @SuppressWarnings("serial") - public static class Servlet { - private static final MappingJsonFactory JSON_FACTORY = new MappingJsonFactory(); - - private ChaosMonkey monkey = MonkeyRunner.getInstance().factory(ChaosMonkey.class); + public abstract void doMonkeyBusiness(); - @GET - public Response getChaosEvents(@javax.ws.rs.core.Context UriInfo uriInfo) throws IOException { - Map query = new HashMap(); - Date date = new Date(0); - for (Map.Entry> pair : uriInfo.getQueryParameters().entrySet()) { - if (pair.getValue().isEmpty()) { - continue; - } - if (pair.getKey().equals("since")) { - date = new Date(Long.parseLong(pair.getValue().get(0))); - } else { - query.put(pair.getKey(), pair.getValue().get(0)); - } - } + public abstract boolean hasPreviousTerminations(ChaosCrawler.InstanceGroup group); - List evts = monkey.ctx.recorder().findEvents(Type.CHAOS, EventTypes.CHAOS_TERMINATION, query, date); - - ByteArrayOutputStream baos = new ByteArrayOutputStream(); - JsonGenerator gen = JSON_FACTORY.createJsonGenerator(baos, JsonEncoding.UTF8); - gen.writeStartArray(); - for (Event evt : evts) { - gen.writeStartObject(); - gen.writeStringField("monkeyType", evt.monkeyType().name()); - gen.writeStringField("eventType", evt.eventType().name()); - gen.writeNumberField("eventTime", evt.eventTime().getTime()); - for (Map.Entry pair : evt.fields().entrySet()) { - gen.writeStringField(pair.getKey(), pair.getValue()); - } - gen.writeEndObject(); - } - gen.writeEndArray(); - gen.close(); - return Response.status(Response.Status.OK).entity(baos).build(); - } - } + public abstract void recordTermination(ChaosCrawler.InstanceGroup group, String instance); } diff --git a/src/test/java/com/netflix/simianarmy/basic/TestBasicChaosCrawler.java b/src/test/java/com/netflix/simianarmy/basic/chaos/TestBasicChaosCrawler.java similarity index 98% rename from src/test/java/com/netflix/simianarmy/basic/TestBasicChaosCrawler.java rename to src/test/java/com/netflix/simianarmy/basic/chaos/TestBasicChaosCrawler.java index ab7e0ba9..0dd72200 100644 --- a/src/test/java/com/netflix/simianarmy/basic/TestBasicChaosCrawler.java +++ b/src/test/java/com/netflix/simianarmy/basic/chaos/TestBasicChaosCrawler.java @@ -15,7 +15,7 @@ * limitations under the License. * */ -package com.netflix.simianarmy.basic; +package com.netflix.simianarmy.basic.chaos; import org.testng.annotations.Test; import org.testng.Assert; diff --git a/src/test/java/com/netflix/simianarmy/chaos/TestChaosInstanceSelector.java b/src/test/java/com/netflix/simianarmy/basic/chaos/TestBasicChaosInstanceSelector.java similarity index 93% rename from src/test/java/com/netflix/simianarmy/chaos/TestChaosInstanceSelector.java rename to src/test/java/com/netflix/simianarmy/basic/chaos/TestBasicChaosInstanceSelector.java index 3c2f1a0d..7adfb23f 100644 --- a/src/test/java/com/netflix/simianarmy/chaos/TestChaosInstanceSelector.java +++ b/src/test/java/com/netflix/simianarmy/basic/chaos/TestBasicChaosInstanceSelector.java @@ -15,12 +15,13 @@ * limitations under the License. * */ -package com.netflix.simianarmy.chaos; +package com.netflix.simianarmy.basic.chaos; import java.util.List; import java.util.Arrays; import java.util.Map; import java.util.HashMap; +import com.netflix.simianarmy.chaos.ChaosInstanceSelector; import com.netflix.simianarmy.chaos.ChaosCrawler.InstanceGroup; import org.testng.annotations.Test; @@ -31,9 +32,9 @@ import static org.slf4j.helpers.NOPLogger.NOP_LOGGER; // CHECKSTYLE IGNORE MagicNumberCheck -public class TestChaosInstanceSelector { - private ChaosInstanceSelector selector = new ChaosInstanceSelector() { - // turn off selector logger for this test since we call is ~1m times +public class TestBasicChaosInstanceSelector { + private ChaosInstanceSelector selector = new BasicChaosInstanceSelector() { + // turn off selector logger for this test since we call it ~1M times protected Logger logger() { return NOP_LOGGER; } diff --git a/src/test/java/com/netflix/simianarmy/chaos/TestChaosMonkey.java b/src/test/java/com/netflix/simianarmy/basic/chaos/TestBasicChaosMonkey.java similarity index 92% rename from src/test/java/com/netflix/simianarmy/chaos/TestChaosMonkey.java rename to src/test/java/com/netflix/simianarmy/basic/chaos/TestBasicChaosMonkey.java index d0c36e25..361f60e1 100644 --- a/src/test/java/com/netflix/simianarmy/chaos/TestChaosMonkey.java +++ b/src/test/java/com/netflix/simianarmy/basic/chaos/TestBasicChaosMonkey.java @@ -15,20 +15,23 @@ * limitations under the License. * */ -package com.netflix.simianarmy.chaos; +package com.netflix.simianarmy.basic.chaos; import java.util.List; +import com.netflix.simianarmy.chaos.ChaosMonkey; import com.netflix.simianarmy.chaos.ChaosCrawler.InstanceGroup; +import com.netflix.simianarmy.chaos.TestChaosMonkeyContext; + import org.testng.annotations.Test; import org.testng.Assert; // CHECKSTYLE IGNORE MagicNumberCheck -public class TestChaosMonkey { +public class TestBasicChaosMonkey { @Test public void testDisabled() { TestChaosMonkeyContext ctx = new TestChaosMonkeyContext("disabled.properties"); - ChaosMonkey chaos = new ChaosMonkey(ctx); + ChaosMonkey chaos = new BasicChaosMonkey(ctx); chaos.start(); chaos.stop(); List selectedOn = ctx.selectedOn(); @@ -40,7 +43,7 @@ public void testDisabled() { @Test public void testEnabledA() { TestChaosMonkeyContext ctx = new TestChaosMonkeyContext("enabledA.properties"); - ChaosMonkey chaos = new ChaosMonkey(ctx); + ChaosMonkey chaos = new BasicChaosMonkey(ctx); chaos.start(); chaos.stop(); List selectedOn = ctx.selectedOn(); @@ -56,7 +59,7 @@ public void testEnabledA() { @Test public void testUnleashedEnabledA() { TestChaosMonkeyContext ctx = new TestChaosMonkeyContext("unleashedEnabledA.properties"); - ChaosMonkey chaos = new ChaosMonkey(ctx); + ChaosMonkey chaos = new BasicChaosMonkey(ctx); chaos.start(); chaos.stop(); List selectedOn = ctx.selectedOn(); @@ -74,7 +77,7 @@ public void testUnleashedEnabledA() { @Test public void testEnabledB() { TestChaosMonkeyContext ctx = new TestChaosMonkeyContext("enabledB.properties"); - ChaosMonkey chaos = new ChaosMonkey(ctx); + ChaosMonkey chaos = new BasicChaosMonkey(ctx); chaos.start(); chaos.stop(); List selectedOn = ctx.selectedOn(); @@ -90,7 +93,7 @@ public void testEnabledB() { @Test public void testUnleashedEnabledB() { TestChaosMonkeyContext ctx = new TestChaosMonkeyContext("unleashedEnabledB.properties"); - ChaosMonkey chaos = new ChaosMonkey(ctx); + ChaosMonkey chaos = new BasicChaosMonkey(ctx); chaos.start(); chaos.stop(); List selectedOn = ctx.selectedOn(); @@ -108,7 +111,7 @@ public void testUnleashedEnabledB() { @Test public void testEnabledAwithout1() { TestChaosMonkeyContext ctx = new TestChaosMonkeyContext("enabledAwithout1.properties"); - ChaosMonkey chaos = new ChaosMonkey(ctx); + ChaosMonkey chaos = new BasicChaosMonkey(ctx); chaos.start(); chaos.stop(); List selectedOn = ctx.selectedOn(); @@ -123,7 +126,7 @@ public void testEnabledAwithout1() { @Test public void testEnabledAwith0() { TestChaosMonkeyContext ctx = new TestChaosMonkeyContext("enabledAwith0.properties"); - ChaosMonkey chaos = new ChaosMonkey(ctx); + ChaosMonkey chaos = new BasicChaosMonkey(ctx); chaos.start(); chaos.stop(); List selectedOn = ctx.selectedOn(); @@ -138,7 +141,7 @@ public void testEnabledAwith0() { @Test public void testAll() { TestChaosMonkeyContext ctx = new TestChaosMonkeyContext("all.properties"); - ChaosMonkey chaos = new ChaosMonkey(ctx); + ChaosMonkey chaos = new BasicChaosMonkey(ctx); chaos.start(); chaos.stop(); List selectedOn = ctx.selectedOn(); @@ -162,7 +165,7 @@ public void testAll() { @Test public void testNoProbability() { TestChaosMonkeyContext ctx = new TestChaosMonkeyContext("noProbability.properties"); - ChaosMonkey chaos = new ChaosMonkey(ctx); + ChaosMonkey chaos = new BasicChaosMonkey(ctx); chaos.start(); chaos.stop(); List selectedOn = ctx.selectedOn(); @@ -182,7 +185,7 @@ public void testNoProbability() { @Test public void testNoProbabilityByName() { TestChaosMonkeyContext ctx = new TestChaosMonkeyContext("noProbabilityByName.properties"); - ChaosMonkey chaos = new ChaosMonkey(ctx); + ChaosMonkey chaos = new BasicChaosMonkey(ctx); chaos.start(); chaos.stop(); List selectedOn = ctx.selectedOn(); diff --git a/src/test/java/com/netflix/simianarmy/chaos/TestChaosMonkeyServlet.java b/src/test/java/com/netflix/simianarmy/basic/chaos/TestBasicChaosMonkeyServlet.java similarity index 89% rename from src/test/java/com/netflix/simianarmy/chaos/TestChaosMonkeyServlet.java rename to src/test/java/com/netflix/simianarmy/basic/chaos/TestBasicChaosMonkeyServlet.java index ef2eeb93..e0715e7f 100644 --- a/src/test/java/com/netflix/simianarmy/chaos/TestChaosMonkeyServlet.java +++ b/src/test/java/com/netflix/simianarmy/basic/chaos/TestBasicChaosMonkeyServlet.java @@ -15,7 +15,7 @@ * limitations under the License. * */ -package com.netflix.simianarmy.chaos; +package com.netflix.simianarmy.basic.chaos; import java.util.Arrays; import java.util.Date; @@ -42,13 +42,16 @@ import com.netflix.simianarmy.MonkeyRunner; import com.netflix.simianarmy.MonkeyRecorder; +import com.netflix.simianarmy.chaos.ChaosMonkey; import com.netflix.simianarmy.basic.BasicRecorderEvent; +import com.netflix.simianarmy.chaos.TestChaosMonkeyContext; + import org.slf4j.Logger; import org.slf4j.LoggerFactory; -public class TestChaosMonkeyServlet { - private static final Logger LOGGER = LoggerFactory.getLogger(TestChaosMonkey.class); +public class TestBasicChaosMonkeyServlet { + private static final Logger LOGGER = LoggerFactory.getLogger(TestBasicChaosMonkeyServlet.class); @Captor private ArgumentCaptor monkeyTypeArg; @@ -71,9 +74,9 @@ public void init() { @Test public void testServlet() { - MonkeyRunner.getInstance().replaceMonkey(ChaosMonkey.class, MockTestChaosMonkeyContext.class); + MonkeyRunner.getInstance().replaceMonkey(BasicChaosMonkey.class, MockTestChaosMonkeyContext.class); - ChaosMonkey.Servlet servlet = new ChaosMonkey.Servlet(); + BasicChaosMonkey.Servlet servlet = new BasicChaosMonkey.Servlet(); MultivaluedMap queryParams = new MultivaluedMapImpl(); queryParams.add("groupType", "ASG"); @@ -124,6 +127,6 @@ public MonkeyRecorder recorder() { String getResource(String name) { // get resource as stream, use Scanner to read stream as one token - return new Scanner(TestChaosMonkey.class.getResourceAsStream(name), "UTF-8").useDelimiter("\\A").next(); + return new Scanner(TestBasicChaosMonkey.class.getResourceAsStream(name), "UTF-8").useDelimiter("\\A").next(); } } diff --git a/src/test/java/com/netflix/simianarmy/chaos/TestChaosMonkeyContext.java b/src/test/java/com/netflix/simianarmy/chaos/TestChaosMonkeyContext.java index 1410499b..31917b90 100644 --- a/src/test/java/com/netflix/simianarmy/chaos/TestChaosMonkeyContext.java +++ b/src/test/java/com/netflix/simianarmy/chaos/TestChaosMonkeyContext.java @@ -19,9 +19,10 @@ import com.netflix.simianarmy.TestMonkeyContext; import com.netflix.simianarmy.MonkeyConfiguration; -import com.netflix.simianarmy.basic.BasicConfiguration; import com.netflix.simianarmy.CloudClient; import com.netflix.simianarmy.chaos.ChaosCrawler.InstanceGroup; +import com.netflix.simianarmy.basic.BasicConfiguration; +import com.netflix.simianarmy.basic.chaos.BasicChaosInstanceSelector; import java.util.Properties; import java.io.InputStream; @@ -117,7 +118,7 @@ public List selectedOn() { } public ChaosInstanceSelector chaosInstanceSelector() { - return new ChaosInstanceSelector() { + return new BasicChaosInstanceSelector() { public String select(InstanceGroup group, double probability) { selectedOn.add(group); return super.select(group, probability); diff --git a/src/test/resources/com/netflix/simianarmy/chaos/getChaosEventsResponse.json b/src/test/resources/com/netflix/simianarmy/basic/chaos/getChaosEventsResponse.json similarity index 100% rename from src/test/resources/com/netflix/simianarmy/chaos/getChaosEventsResponse.json rename to src/test/resources/com/netflix/simianarmy/basic/chaos/getChaosEventsResponse.json