Skip to content

Commit

Permalink
version 3.0.2-SNAPSHOT, added onScheduledEvent
Browse files Browse the repository at this point in the history
  • Loading branch information
PeterPaul-Perfana committed Feb 6, 2024
1 parent 2bc6c94 commit d4dda68
Show file tree
Hide file tree
Showing 5 changed files with 110 additions and 10 deletions.
14 changes: 14 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,12 @@ remote running load test process.
Use `onAfterTest` for a command that is called on an `after-test` event. For instance, clean up
artifacts from a another command.

Use `onScheduledEvent` for a command that is called in an event scheduler script.
Use `runcommand` event. Use `name` to match one specific command runner event to trigger.
Use key=value parameters with `;` separated key=value pairs.
In the command surround the keys underscores to be replaced, like `__key__`.
Use `__testRunId__` to be replaced by the test run id from the current test context.

Only when _all_ polling commands that are indicated as `continueOnKeepAliveParticipant` request a stop,
the test-run is actually stopped.

Expand Down Expand Up @@ -62,6 +68,10 @@ commands end, e.g. by running `rm -v /tmp/test-run-*.busy`.
<buildResultsUrl>${CIBuildResultsUrl}</buildResultsUrl>
<rampupTimeInSeconds>${rampupTimeInSeconds}</rampupTimeInSeconds>
<constantLoadTimeInSeconds>${constantLoadTimeInSeconds}</constantLoadTimeInSeconds>
<eventSchedulerScript>
PT30S|run-command(scale to 3)|name=k8sCommand;app=myapp;namespace=mynamespace;replicas=3
PT1M|run-command(scale to 1)|name=k8sCommand;app=myapp;namespace=mynamespace;replicas=1
</eventSchedulerScript>
<annotations>${annotations}</annotations>
<tags>${tags}</tags>
</testConfig>
Expand All @@ -86,6 +96,10 @@ commands end, e.g. by running `rm -v /tmp/test-run-*.busy`.
echo abort K6 runner 2</onAbort>
<onAfterTest>rm /tmp/test-run-2.busy; echo end ${testRunId}</onAfterTest>
</eventConfig>
<eventConfig implementation="io.perfana.events.commandrunner.CommandRunnerEventConfig">
<name>k8sCommand</name>
<onScheduledEvent>kubectl -n __namespace__ scale --replicas=__replicas__ --timeout=1m deployment __app__</onScheduledEvent>
</eventConfig>
</eventConfigs>
</eventSchedulerConfig>
</configuration>
Expand Down
2 changes: 1 addition & 1 deletion pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@

<groupId>io.perfana</groupId>
<artifactId>test-events-command-runner</artifactId>
<version>3.0.1</version>
<version>3.0.2-SNAPSHOT</version>
<description>Run a command via the command process runner. Abort when needed.</description>
<packaging>jar</packaging>

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
*/
package io.perfana.events.commandrunner;

import io.perfana.eventscheduler.api.CustomEvent;
import io.perfana.eventscheduler.api.EventAdapter;
import io.perfana.eventscheduler.api.EventLogger;
import io.perfana.eventscheduler.api.config.TestContext;
Expand All @@ -33,13 +34,48 @@
import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;
import java.util.stream.Collectors;
import java.util.stream.Stream;

import static io.perfana.events.commandrunner.CommandRunnerEvent.AllowedCustomEvents.runcommand;
import static io.perfana.events.commandrunner.CommandRunnerEvent.AllowedCustomEvents.stream;

public class CommandRunnerEvent extends EventAdapter<CommandRunnerEventContext> {

private Future<ProcessResult> future;

private final boolean isWindows;

enum AllowedCustomEvents {
runcommand("run-command");

private final String eventName;

AllowedCustomEvents(String eventName) {
this.eventName = eventName;
}

public String getEventName() {
return eventName;
}

public static Stream<AllowedCustomEvents> stream() {
return Stream.of(values());
}

public boolean hasEventName(String name) {
return this.eventName.equals(name);
}
}

private final Set<String> allowedCustomEvents = setOf(stream()
.map(AllowedCustomEvents::getEventName)
.toArray(String[]::new));

@Override
public Collection<String> allowedCustomEvents() {
return allowedCustomEvents;
}

public CommandRunnerEvent(CommandRunnerEventContext eventContext, TestContext testContext, EventMessageBus messageBus, EventLogger logger) {
super(eventContext, testContext, messageBus, logger);
isWindows = systemGetPropertyNullSafe("os.name", logger).startsWith("Windows");
Expand All @@ -54,13 +90,38 @@ private static String systemGetPropertyNullSafe(String property, EventLogger log
return prop == null ? "" : prop;
}

@Override
public void customEvent(CustomEvent scheduleEvent) {
String eventName = scheduleEvent.getName();
try {
if (runcommand.hasEventName(eventName)) {
Map<String, String> parsedSettings = parseSettings(scheduleEvent.getSettings());

// if name is set, only run the command if the name matches
String name = parsedSettings.get("name");
if (name != null && !eventContext.getName().equals(name)) {
logger.info("Ignoring event [" + eventName + "] for [" + name + "], this is [" + eventContext.getName() + "]");
return;
}

String command = eventContext.getOnScheduledEvent();
command = parsedSettings.entrySet().stream()
.reduce(command, (k, v) -> k.replaceAll("__" + v.getKey() + "__", v.getValue()), String::concat);

runCommand(command, "scheduledEvent");
} else {
logger.warn("ignoring unknown event [" + eventName + "]");
}
} catch (Exception e) {
logger.error("Failed to run custom event: " + eventName, e);
}
}

@Override
public void beforeTest() {

String pluginName = CommandRunnerEvent.class.getSimpleName() + "-" + eventContext.getName();

String newTestRunId = testContext.getTestRunId();

// default sending of command is disabled: might contain secrets
if (eventContext.isSendTestRunConfig()) {
String tags = "command-runner";
Expand All @@ -70,8 +131,6 @@ public void beforeTest() {

String command = eventContext.getOnBeforeTest();

command = command.replace("__testRunId__", newTestRunId);

Future<ProcessResult> beforeTestCommandFuture = runCommand(command, "beforeTest");

if (beforeTestCommandFuture == null) {
Expand Down Expand Up @@ -177,6 +236,9 @@ private Future<ProcessResult> runCommand(String command, String commandType) {
}
logger.info("About to run " + commandType + " [" + command + "]");

String newTestRunId = testContext.getTestRunId();
command = command.replace("__testRunId__", newTestRunId);

List<String> commandList;

if (isWindows) {
Expand Down Expand Up @@ -272,4 +334,13 @@ private static int getExitCode(Future<ProcessResult> future) {
}
return processResult.getExitValue();
}

static Map<String, String> parseSettings(String eventSettings) {
if (eventSettings == null || eventSettings.trim().isEmpty()) {
return Collections.emptyMap();
}
return Arrays.stream(eventSettings.split(";"))
.map(s -> s.split("="))
.collect(Collectors.toMap(k -> k[0], v -> v.length == 2 ? v[1] : ""));
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -22,19 +22,18 @@
public class CommandRunnerEventConfig extends EventConfig {

private String onStartTest = "";

private String onBeforeTest = "";
private String onKeepAlive = "";

private String onAbort = "";

private String onAfterTest = "";

private String onScheduledEvent = "";

private boolean sendTestRunConfig = false;

@Override
public CommandRunnerEventContext toContext() {
return new CommandRunnerEventContext(super.toContext(), onBeforeTest, onStartTest, onKeepAlive, onAbort, onAfterTest, sendTestRunConfig);
return new CommandRunnerEventContext(super.toContext(), onBeforeTest, onStartTest, onKeepAlive, onAbort, onAfterTest, onScheduledEvent, sendTestRunConfig);
}

public String getOnBeforeTest() {
Expand Down Expand Up @@ -85,6 +84,14 @@ public void setOnAfterTest(String onAfterTest) {
this.onAfterTest = onAfterTest;
}

public String getOnScheduledEvent() {
return onScheduledEvent;
}

public void setOnScheduledEvent(String onScheduledEvent) {
this.onScheduledEvent = onScheduledEvent;
}

@Override
public String toString() {
return "CommandRunnerEventConfig{" +
Expand All @@ -93,6 +100,7 @@ public String toString() {
", onKeepAlive='" + onKeepAlive + '\'' +
", onAbort='" + onAbort + '\'' +
", onAfterTest='" + onAfterTest + '\'' +
", onCustomEvent='" + onScheduledEvent + '\'' +
", sendTestRunConfig=" + sendTestRunConfig +
'}';
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,15 +28,17 @@ public class CommandRunnerEventContext extends EventContext {
private final String onKeepAlive;
private final String onAbort;
private final String onAfterTest;
private final String onScheduledEvent;
private final boolean sendTestRunConfig;

protected CommandRunnerEventContext(EventContext context, String onBeforeTest, String onStartTest, String onKeepAlive, String onAbort, String onAfterTest, boolean sendTestRunConfig) {
protected CommandRunnerEventContext(EventContext context, String onBeforeTest, String onStartTest, String onKeepAlive, String onAbort, String onAfterTest, String onCustomEvent, boolean sendTestRunConfig) {
super(context, CommandRunnerEventFactory.class.getName());
this.onStartTest = onStartTest;
this.onBeforeTest = onBeforeTest;
this.onKeepAlive = onKeepAlive;
this.onAbort = onAbort;
this.onAfterTest = onAfterTest;
this.onScheduledEvent = onCustomEvent;
this.sendTestRunConfig = sendTestRunConfig;
}

Expand All @@ -60,6 +62,10 @@ public String getOnBeforeTest() {
return onBeforeTest;
}

public String getOnScheduledEvent() {
return onScheduledEvent;
}

public boolean isSendTestRunConfig() {
return sendTestRunConfig;
}
Expand All @@ -72,6 +78,7 @@ public String toString() {
", onKeepAlive='" + onKeepAlive + '\'' +
", onAbort='" + onAbort + '\'' +
", onAfterTest='" + onAfterTest + '\'' +
", onScheduledEvent='" + onScheduledEvent + '\'' +
", sendTestRunConfig=" + sendTestRunConfig +
'}';
}
Expand Down

0 comments on commit d4dda68

Please sign in to comment.