Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Issue 111 - Support CommandGroups in CommandTester #113

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ public class CommandTester {
private final CommandRunner runner;

public CommandTester(Command command) {
runner = new CommandRunner(command);
runner = CommandRunner.create(command);
}

/**
Expand Down
21 changes: 17 additions & 4 deletions strongback-tests/src/org/strongback/command/CommandRunnerTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ public Logger logger() {
@Test
public void shouldRunCommandWithTimeout() {
WatchedCommand watched = WatchedCommand.watch(Command.pause(1000,TimeUnit.MILLISECONDS));
CommandRunner runner = new CommandRunner(watched);
CommandRunner runner = CommandRunner.create(watched);
assertThat(runner.step(INITIAL_TIME)).isFalse();
assertThat(runner.state()).isEqualTo(CommandState.RUNNING);
assertIncomplete(watched);
Expand All @@ -68,15 +68,15 @@ public boolean execute() {
return false;
}
});
CommandRunner runner = new CommandRunner(CONTEXT,watched);
CommandRunner runner = CommandRunner.create(CONTEXT,watched);
assertThat(runner.step(INITIAL_TIME)).isTrue(); // completes because it is interrupted
assertInterrupted(watched);
}

@Test
public void shouldInterruptCommandThatThrowsExceptionDuringFirstExecute() {
WatchedCommand watched = WatchedCommand.watch(Command.create((Runnable)()->{throw new IllegalStateException();}));
CommandRunner runner = new CommandRunner(CONTEXT,watched);
CommandRunner runner = CommandRunner.create(CONTEXT,watched);
assertThat(runner.step(INITIAL_TIME)).isTrue(); // completes because it is interrupted
assertExecutedAtLeast(watched,1);
assertInterrupted(watched);
Expand All @@ -93,14 +93,27 @@ public boolean execute() {
return false;
}
});
CommandRunner runner = new CommandRunner(CONTEXT,watched);
CommandRunner runner = CommandRunner.create(CONTEXT,watched);
assertThat(runner.step(INITIAL_TIME)).isFalse(); // executed correctly the first time
assertExecutedAtLeast(watched,1);
assertThat(runner.step(INITIAL_TIME)).isTrue(); // completes because it is interrupted
assertExecutedAtLeast(watched,2);
assertInterrupted(watched);
}

@Test
public void shouldSupportCommandGroups() {
Command command = Command.pause(100, TimeUnit.MILLISECONDS);
WatchedCommand watched = WatchedCommand.watch(command); // CommandGroups don't call end(), so watch Command
CommandRunner tester = CommandRunner.create(CONTEXT, CommandGroup.runSequentially(watched));

tester.step(1);
assertIncomplete(watched);

tester.step(101);
assertComplete(watched);
}

protected void assertIncomplete( WatchedCommand watched ) {
assertThat(watched.isInitialized()).isTrue();
assertThat(watched.isExecuted()).isTrue();
Expand Down
27 changes: 27 additions & 0 deletions strongback-tests/src/org/strongback/command/CommandTesterTest.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
package org.strongback.command;

import org.junit.Test;

import java.util.concurrent.TimeUnit;

import static org.fest.assertions.Assertions.assertThat;

/**
* @author Rothanak So
*/
public class CommandTesterTest {

@Test
public void shouldSupportCommandGroups() {
// Regression test for issue #111: https://github.com/strongback/strongback-java/issues/111
Command command = Command.pause(100, TimeUnit.MILLISECONDS);
WatchedCommand watched = WatchedCommand.watch(command); // CommandGroups don't call end(), so watch Command
CommandTester tester = new CommandTester(CommandGroup.runSequentially(watched));

tester.step(1);
assertThat(watched.isEnded()).isFalse();

tester.step(101);
assertThat(watched.isEnded()).isTrue();
}
}
40 changes: 32 additions & 8 deletions strongback/src/org/strongback/command/CommandRunner.java
Original file line number Diff line number Diff line change
Expand Up @@ -62,25 +62,49 @@ public Logger logger() {
private CommandState state = CommandState.UNINITIALIZED;
private final Context context;

CommandRunner(Command command) {
// Just a command and no next is a leaf
this(DEFAULT_CONTEXT, command);
static CommandRunner create(Command command) {
return create(DEFAULT_CONTEXT, command);
}

CommandRunner(Context context, Command command) {
// Just a command and no next is a leaf
this(context, null, command);
static CommandRunner create(Context context, Command command) {
return buildRunner(context, command, null);
}

CommandRunner(Context context, CommandRunner next, Command command) {
private static CommandRunner buildRunner(Context context, Command command, CommandRunner last) {
if (command instanceof CommandGroup) {
CommandGroup cg = (CommandGroup) command;
Command[] commands = cg.getCommands();
switch (cg.getType()) {
case SEQUENTIAL:
for (int i = commands.length - 1; i >= 0; i--) {
last = buildRunner(context, commands[i], last);
}
return last;
case PARRALLEL:
CommandRunner[] crs = new CommandRunner[commands.length];
for (int i = 0; i < crs.length; i++) {
crs[i] = buildRunner(context, commands[i], null);
}
return new CommandRunner(context, last, crs);
case FORK:
assert commands.length == 1;
return new CommandRunner(context, last, new CommandRunner(context, buildRunner(context, commands[0], null)));
}
// This line should never happen, the switch will throw an exception first
throw new IllegalStateException("Unexpected command type: " + cg.getType());
}
return new CommandRunner(context, last, command);
}

private CommandRunner(Context context, CommandRunner next, Command command) {
// A command and a next is a node
this.command = command;
this.next = next;
this.timeoutInMillis = (long) (command.getTimeoutInSeconds() * 1000);
this.context = context != null ? context : DEFAULT_CONTEXT;
}

CommandRunner(Context context, CommandRunner next, CommandRunner... commands) {
private CommandRunner(Context context, CommandRunner next, CommandRunner... commands) {
// A next and several children is a branch
if (commands.length != 0) this.children = commands;
this.next = next;
Expand Down
28 changes: 1 addition & 27 deletions strongback/src/org/strongback/command/Scheduler.java
Original file line number Diff line number Diff line change
Expand Up @@ -65,37 +65,11 @@ public void killAll() {
*/
public void submit(Command command) {
if (command != null) {
CommandRunner runner = buildRunner(command, null);
CommandRunner runner = CommandRunner.create(context, command);
commands.add(runner);
}
}

private CommandRunner buildRunner(Command command, CommandRunner last) {
if (command instanceof CommandGroup) {
CommandGroup cg = (CommandGroup) command;
Command[] commands = cg.getCommands();
switch (cg.getType()) {
case SEQUENTIAL:
for (int i = commands.length - 1; i >= 0; i--) {
last = buildRunner(commands[i], last);
}
return last;
case PARRALLEL:
CommandRunner[] crs = new CommandRunner[commands.length];
for (int i = 0; i < crs.length; i++) {
crs[i] = buildRunner(commands[i], null);
}
return new CommandRunner(context, last, crs);
case FORK:
assert commands.length == 1;
return new CommandRunner(context, last, new CommandRunner(context, buildRunner(commands[0], null)));
}
// This line should never happen, the switch will throw an exception first
throw new IllegalStateException("Unexpected command type: " + cg.getType());
}
return new CommandRunner(context, last, command);
}

/**
* Steps once though all of the {@link Command}s in the {@link Scheduler}.
*
Expand Down