diff --git a/src/main/java/com/bioraft/rundeck/conditional/Switch.java b/src/main/java/com/bioraft/rundeck/conditional/Switch.java index c89a994..4fd6464 100644 --- a/src/main/java/com/bioraft/rundeck/conditional/Switch.java +++ b/src/main/java/com/bioraft/rundeck/conditional/Switch.java @@ -17,6 +17,7 @@ import com.dtolabs.rundeck.core.Constants; import com.dtolabs.rundeck.core.dispatcher.ContextView; +import com.dtolabs.rundeck.core.execution.workflow.steps.FailureReason; import com.dtolabs.rundeck.plugins.step.PluginStepContext; import com.fasterxml.jackson.core.JsonProcessingException; import com.fasterxml.jackson.databind.JsonNode; @@ -57,15 +58,22 @@ public Switch(PluginStepContext ctx) { * @param elevate If specified, also create a variable in global export * context. */ - public void switchCase(String group, String name, String cases, String test, String defaultValue, boolean elevate) { + public void switchCase(String group, String name, String cases, String test, String defaultValue, boolean elevate) throws JsonProcessingException { // If no case was matched, assign defaultValue if it is not null. - if (!switchCase(group, name, cases, test, elevate)) { - if (defaultValue != null && defaultValue.length() > 0) { - addOutput(elevate, group, name, defaultValue); - ctx.getLogger().log(Constants.DEBUG_LEVEL, "No match, using default."); - } else { - ctx.getLogger().log(Constants.DEBUG_LEVEL, "No match, default is empty."); + try { + if (!switchCase(group, name, cases, test, elevate)) { + if (defaultValue != null && defaultValue.length() > 0) { + addOutput(elevate, group, name, defaultValue); + ctx.getLogger().log(Constants.DEBUG_LEVEL, "No match, using default."); + } else { + ctx.getLogger().log(Constants.DEBUG_LEVEL, "No match, default is empty."); + } } + } catch (JsonProcessingException e) { + ctx.getLogger().log(Constants.ERR_LEVEL, "Failed to parse cases."); + ctx.getLogger().log(Constants.ERR_LEVEL, e.getMessage()); + e.printStackTrace(); + throw e; } } @@ -80,23 +88,19 @@ public void switchCase(String group, String name, String cases, String test, Str * * @return True if matched, false otherwise. */ - public boolean switchCase(String group, String name, String cases, String test, boolean elevate) { + public boolean switchCase(String group, String name, String cases, String test, boolean elevate) throws JsonProcessingException { ObjectMapper objectMapper = new ObjectMapper(); - try { - JsonNode map = objectMapper.readTree(ensureStringIsJsonObject(cases)); - Iterator> iterator = map.fields(); - while (iterator.hasNext()) { - Map.Entry entry = iterator.next(); - String key = entry.getKey(); - String value = entry.getValue().asText(); - if (test.equals(key)) { - addOutput(elevate, group, name, value); - ctx.getLogger().log(Constants.DEBUG_LEVEL, "Matched " + key + "."); - return true; - } + JsonNode map = objectMapper.readTree(ensureStringIsJsonObject(cases)); + Iterator> iterator = map.fields(); + while (iterator.hasNext()) { + Map.Entry entry = iterator.next(); + String key = entry.getKey(); + String value = entry.getValue().asText(); + if (test.equals(key)) { + addOutput(elevate, group, name, value); + ctx.getLogger().log(Constants.DEBUG_LEVEL, "Matched " + key + "."); + return true; } - } catch (JsonProcessingException e) { - return false; } return false; } @@ -125,4 +129,8 @@ public static String ensureStringIsJsonObject(String string) { String trimmed = string.replaceFirst("^\\s*\\{?", "{").replaceFirst("\\s*$", ""); return trimmed + (trimmed.endsWith("}") ? "" : "}"); } + + enum Causes implements FailureReason { + InvalidJSON + } } diff --git a/src/main/java/com/bioraft/rundeck/conditional/SwitchCaseNodeStepPlugin.java b/src/main/java/com/bioraft/rundeck/conditional/SwitchCaseNodeStepPlugin.java index 297fc1f..758cedd 100644 --- a/src/main/java/com/bioraft/rundeck/conditional/SwitchCaseNodeStepPlugin.java +++ b/src/main/java/com/bioraft/rundeck/conditional/SwitchCaseNodeStepPlugin.java @@ -28,6 +28,7 @@ import com.dtolabs.rundeck.plugins.descriptions.RenderingOptions; import com.dtolabs.rundeck.plugins.step.NodeStepPlugin; import com.dtolabs.rundeck.plugins.step.PluginStepContext; +import com.fasterxml.jackson.core.JsonProcessingException; import static com.dtolabs.rundeck.core.plugins.configuration.StringRenderingConstants.CODE_SYNTAX_MODE; import static com.dtolabs.rundeck.core.plugins.configuration.StringRenderingConstants.DISPLAY_TYPE_KEY; @@ -61,21 +62,23 @@ public class SwitchCaseNodeStepPlugin implements NodeStepPlugin { @PluginProperty(title = "Test Value", description = "Test value", required = true) private String testValue; - @PluginProperty(title = "Default", description = "Default value", required = false) + @PluginProperty(title = "Default", description = "Default value") private String defaultValue; - @PluginProperty(title = "Make global?", description = "Elevate this variable to global scope (default: false)", required = false) + @PluginProperty(title = "Make global?", description = "Elevate this variable to global scope (default: false)") private boolean elevateToGlobal; @Override public void executeNodeStep(PluginStepContext ctx, Map cfg, INodeEntry node) throws NodeStepException { - String group = cfg.getOrDefault("group", this.group).toString(); - String name = cfg.getOrDefault("name", this.name).toString(); - String cases = cfg.getOrDefault("cases", this.cases).toString(); - String testValue = cfg.getOrDefault("testValue", this.testValue).toString(); - boolean elevateToGlobal = cfg.getOrDefault("elevateToGlobal", this.elevateToGlobal).equals("true"); + group = cfg.getOrDefault("group", this.group).toString(); + name = cfg.getOrDefault("name", this.name).toString(); + cases = cfg.getOrDefault("cases", this.cases).toString(); + testValue = cfg.getOrDefault("testValue", this.testValue).toString(); + if (cfg.containsKey("elevateToGlobal")) { + elevateToGlobal = cfg.get("elevateToGlobal").equals("true"); + } boolean globalHasDefault = defaultValue != null && defaultValue.length() > 0; boolean cfgHasDefault = cfg.containsKey("defaultValue") && cfg.get("defaultValue") != null; @@ -86,10 +89,14 @@ public void executeNodeStep(PluginStepContext ctx, Map cfg, INod ctx.getLogger().log(Constants.DEBUG_LEVEL, "Setting " + group + "." + name + " based on " + testValue + " " + cases); - if (cfgHasDefault || globalHasDefault) { - (new Switch(ctx)).switchCase(group, name, cases, testValue, defaultValue, elevateToGlobal); - } else { - (new Switch(ctx)).switchCase(group, name, cases, testValue, elevateToGlobal); + try { + if (cfgHasDefault || globalHasDefault) { + (new Switch(ctx)).switchCase(group, name, cases, testValue, defaultValue, elevateToGlobal); + } else { + (new Switch(ctx)).switchCase(group, name, cases, testValue, elevateToGlobal); + } + } catch (JsonProcessingException e) { + throw new NodeStepException(e.getMessage(), Switch.Causes.InvalidJSON, node.getNodename()); } } diff --git a/src/main/java/com/bioraft/rundeck/conditional/SwitchCaseStepPlugin.java b/src/main/java/com/bioraft/rundeck/conditional/SwitchCaseStepPlugin.java index 3784ad9..26c84db 100644 --- a/src/main/java/com/bioraft/rundeck/conditional/SwitchCaseStepPlugin.java +++ b/src/main/java/com/bioraft/rundeck/conditional/SwitchCaseStepPlugin.java @@ -27,6 +27,7 @@ import com.dtolabs.rundeck.plugins.descriptions.RenderingOptions; import com.dtolabs.rundeck.plugins.step.PluginStepContext; import com.dtolabs.rundeck.plugins.step.StepPlugin; +import com.fasterxml.jackson.core.JsonProcessingException; import static com.dtolabs.rundeck.core.plugins.configuration.StringRenderingConstants.CODE_SYNTAX_MODE; import static com.dtolabs.rundeck.core.plugins.configuration.StringRenderingConstants.DISPLAY_TYPE_KEY; @@ -59,20 +60,23 @@ public class SwitchCaseStepPlugin implements StepPlugin { @PluginProperty(title = "Test Value", description = "Test value", required = true) private String testValue; - @PluginProperty(title = "Default", description = "Default value", required = false) + @PluginProperty(title = "Default", description = "Default value") private String defaultValue; - @PluginProperty(title = "Make global?", description = "Elevate this variable to global scope (default: false)", required = false) + @PluginProperty(title = "Make global?", description = "Elevate this variable to global scope (default: false)") private boolean elevateToGlobal; @Override public void executeStep(final PluginStepContext ctx, final Map cfg) throws StepException { - String group = cfg.getOrDefault("group", this.group).toString(); - String name = cfg.getOrDefault("name", this.name).toString(); - String cases = cfg.getOrDefault("cases", this.cases).toString(); - String testValue = cfg.getOrDefault("testValue", this.testValue).toString(); - boolean elevateToGlobal = cfg.getOrDefault("elevateToGlobal", this.elevateToGlobal).toString().equals("true"); + group = cfg.getOrDefault("group", this.group).toString(); + name = cfg.getOrDefault("name", this.name).toString(); + cases = cfg.getOrDefault("cases", this.cases).toString(); + testValue = cfg.getOrDefault("testValue", this.testValue).toString(); + if (cfg.containsKey("elevateToGlobal")) { + elevateToGlobal = cfg.get("elevateToGlobal").equals("true"); + } + boolean globalHasDefault = defaultValue != null && defaultValue.length() > 0; boolean cfgHasDefault = cfg.containsKey("defaultValue") && cfg.get("defaultValue") != null; if (cfgHasDefault) { @@ -82,10 +86,15 @@ public void executeStep(final PluginStepContext ctx, final Map c ctx.getLogger().log(Constants.DEBUG_LEVEL, "Setting " + group + "." + name + " based on " + testValue + " " + cases); - if (cfgHasDefault || globalHasDefault) { - (new Switch(ctx)).switchCase(group, name, cases, testValue, defaultValue, elevateToGlobal); - } else { - (new Switch(ctx)).switchCase(group, name, cases, testValue, elevateToGlobal); + try { + if (cfgHasDefault || globalHasDefault) { + (new Switch(ctx)).switchCase(group, name, cases, testValue, defaultValue, elevateToGlobal); + } else { + (new Switch(ctx)).switchCase(group, name, cases, testValue, elevateToGlobal); + } + } catch ( + JsonProcessingException e) { + throw new StepException(e.getMessage(), Switch.Causes.InvalidJSON); } } diff --git a/src/test/java/com/bioraft/rundeck/conditional/SwitchCaseNodeStepPluginTest.java b/src/test/java/com/bioraft/rundeck/conditional/SwitchCaseNodeStepPluginTest.java index 98ae6a0..7980212 100644 --- a/src/test/java/com/bioraft/rundeck/conditional/SwitchCaseNodeStepPluginTest.java +++ b/src/test/java/com/bioraft/rundeck/conditional/SwitchCaseNodeStepPluginTest.java @@ -60,6 +60,10 @@ public class SwitchCaseNodeStepPluginTest { @Mock INodeEntry node; + private final String group = "raft"; + private final String name = "test"; + private final String testValue = "any"; + private final String defaultValue = "any"; @Before public void setUp() { @@ -69,7 +73,7 @@ public void setUp() { @Test public void runTestOne() throws NodeStepException { Map cases = ImmutableMap.builder().put("k1", "v1").put("k2", "v2").build(); - this.runTest("v1", "k1", cases, "any"); + this.runTest("v1", "k1", cases, defaultValue); } @Test @@ -81,7 +85,7 @@ public void runTestTwo() throws NodeStepException { @Test public void returnsDefaultOnNoMatch() throws NodeStepException { Map cases = ImmutableMap.builder().put("k1", "v1").put("k2", "v2").build(); - this.runTest("any", "k3", cases, "any"); + this.runTest(testValue, "k3", cases, defaultValue); } @Test @@ -97,10 +101,32 @@ public void runTestNoDefaultValue() throws NodeStepException { this.runTestNoDefault(configuration); } + @Test(expected = NodeStepException.class) + public void testInvalidCases() throws NodeStepException { + StringBuffer caseString = new StringBuffer(); + Map cases = ImmutableMap.builder().put("k1", "v1").put("k2", "v2").build(); + cases.forEach((k, v) -> caseString.append('"').append(k).append('"').append(":").append('"').append(v).append('"').append(",")); + invalidInput(caseString.toString()); + } + + private void invalidInput(String caseString) + throws NodeStepException { + + Map configuration = new HashMap<>(); + configuration.put("group", group); + configuration.put("name", name); + configuration.put("cases", caseString); + configuration.put("testValue", testValue); + configuration.put("defaultValue", defaultValue); + + when(context.getOutputContext()).thenReturn(sharedOutputContext); + when(context.getLogger()).thenReturn(logger); + + this.plugin.executeNodeStep(context, configuration, node); + } + private void runTest(String expected, String testValue, Map cases, String defaultValue) throws NodeStepException { - String group = "raft"; - String name = "test"; StringBuffer caseString = new StringBuffer(); cases.forEach((k, v) -> caseString.append('"').append(k).append('"').append(":").append('"').append(v).append('"').append(",")); caseString.setLength(caseString.length() - 1); @@ -122,8 +148,6 @@ private void runTest(String expected, String testValue, Map case public void runTestNoDefault(Map configuration) throws NodeStepException { - String group = "raft"; - String name = "test"; Map cases = ImmutableMap.builder().put("k1", "v1").put("k2", "v2").build(); StringBuilder caseString = new StringBuilder(); @@ -143,4 +167,6 @@ public void runTestNoDefault(Map configuration) verify(sharedOutputContext, never()).addOutput(any(String.class), any(String.class), any(String.class)); } + + }