Adding ability to delay before executing a step in STC.

Change-Id: I9822ac35d37e6735068ebdf39b952db913a10e14
diff --git a/utils/stc/src/main/java/org/onlab/stc/Compiler.java b/utils/stc/src/main/java/org/onlab/stc/Compiler.java
index 919cbd5..64e0153 100644
--- a/utils/stc/src/main/java/org/onlab/stc/Compiler.java
+++ b/utils/stc/src/main/java/org/onlab/stc/Compiler.java
@@ -32,6 +32,7 @@
 
 import static com.google.common.base.Preconditions.*;
 import static com.google.common.base.Strings.isNullOrEmpty;
+import static java.lang.Integer.parseInt;
 import static org.onlab.graph.DepthFirstSearch.EdgeType.BACK_EDGE;
 import static org.onlab.graph.GraphPathSearch.ALL_PATHS;
 import static org.onlab.stc.Scenario.loadScenario;
@@ -56,6 +57,7 @@
     private static final String COMMAND = "[@exec]";
     private static final String ENV = "[@env]";
     private static final String CWD = "[@cwd]";
+    private static final String DELAY = "[@delay]";
     private static final String REQUIRES = "[@requires]";
     private static final String IF = "[@if]";
     private static final String UNLESS = "[@unless]";
@@ -245,9 +247,10 @@
         String command = expand(cfg.getString(COMMAND, parentGroup != null ? parentGroup.command() : null), true);
         String env = expand(cfg.getString(ENV, parentGroup != null ? parentGroup.env() : null));
         String cwd = expand(cfg.getString(CWD, parentGroup != null ? parentGroup.cwd() : null));
+        int delay = parseInt(expand(cfg.getString(DELAY, parentGroup != null ? "" + parentGroup.delay() : "0")));
 
-        print("step name=%s command=%s env=%s cwd=%s", name, command, env, cwd);
-        Step step = new Step(name, command, env, cwd, parentGroup);
+        print("step name=%s command=%s env=%s cwd=%s delay=%d", name, command, env, cwd, delay);
+        Step step = new Step(name, command, env, cwd, parentGroup, delay);
         registerStep(step, cfg, namespace, parentGroup);
     }
 
@@ -264,9 +267,10 @@
         String command = expand(cfg.getString(COMMAND, parentGroup != null ? parentGroup.command() : null), true);
         String env = expand(cfg.getString(ENV, parentGroup != null ? parentGroup.env() : null));
         String cwd = expand(cfg.getString(CWD, parentGroup != null ? parentGroup.cwd() : null));
+        int delay = parseInt(expand(cfg.getString(DELAY, parentGroup != null ? "" + parentGroup.delay() : "0")));
 
-        print("group name=%s command=%s env=%s cwd=%s", name, command, env, cwd);
-        Group group = new Group(name, command, env, cwd, parentGroup);
+        print("group name=%s command=%s env=%s cwd=%s delay=%d", name, command, env, cwd, delay);
+        Group group = new Group(name, command, env, cwd, parentGroup, delay);
         if (registerStep(group, cfg, namespace, parentGroup)) {
             compile(cfg, namespace, group);
         }
diff --git a/utils/stc/src/main/java/org/onlab/stc/Group.java b/utils/stc/src/main/java/org/onlab/stc/Group.java
index 0281c36..e5f6efd 100644
--- a/utils/stc/src/main/java/org/onlab/stc/Group.java
+++ b/utils/stc/src/main/java/org/onlab/stc/Group.java
@@ -35,9 +35,10 @@
      * @param env     default path to file to be sourced into the environment
      * @param cwd     default path to current working directory for the step
      * @param group   optional group to which this step belongs
+     * @param delay   seconds to delay before executing
      */
-    public Group(String name, String command, String env, String cwd, Group group) {
-        super(name, command, env, cwd, group);
+    public Group(String name, String command, String env, String cwd, Group group, int delay) {
+        super(name, command, env, cwd, group, delay);
     }
 
     /**
diff --git a/utils/stc/src/main/java/org/onlab/stc/Step.java b/utils/stc/src/main/java/org/onlab/stc/Step.java
index e14addb..0c2c8ed 100644
--- a/utils/stc/src/main/java/org/onlab/stc/Step.java
+++ b/utils/stc/src/main/java/org/onlab/stc/Step.java
@@ -32,6 +32,7 @@
     protected final String env;
     protected final String cwd;
     protected final Group group;
+    protected final int delay;
 
     /**
      * Creates a new test step.
@@ -41,10 +42,12 @@
      * @param env     path to file to be sourced into the environment
      * @param cwd     path to current working directory for the step
      * @param group   optional group to which this step belongs
+     * @param delay   seconds to delay before executing
      */
-    public Step(String name, String command, String env, String cwd, Group group) {
+    public Step(String name, String command, String env, String cwd, Group group, int delay) {
         this.name = checkNotNull(name, "Name cannot be null");
         this.group = group;
+        this.delay = delay;
 
         // Set the command, environment and cwd
         // If one is not given use the value from the enclosing group
@@ -98,6 +101,14 @@
         return group;
     }
 
+    /**
+     * Returns the start delay in seconds.
+     *
+     * @return number of seconds
+     */
+    public int delay() {
+        return delay;
+    }
 
     @Override
     public int hashCode() {
@@ -124,6 +135,7 @@
                 .add("env", env)
                 .add("cwd", cwd)
                 .add("group", group)
+                .add("delay", delay)
                 .toString();
     }
 }
diff --git a/utils/stc/src/main/java/org/onlab/stc/StepProcessor.java b/utils/stc/src/main/java/org/onlab/stc/StepProcessor.java
index 4994369..f88c4bf1 100644
--- a/utils/stc/src/main/java/org/onlab/stc/StepProcessor.java
+++ b/utils/stc/src/main/java/org/onlab/stc/StepProcessor.java
@@ -38,6 +38,7 @@
     private static final String NEGATE_CODE = "!";
 
     private static final int FAIL = -1;
+    private static final int SECONDS = 1_000;
 
     static String launcher = "stc-launcher ";
 
@@ -67,6 +68,7 @@
     @Override
     public void run() {
         delegate.onStart(step, command);
+        delayIfNeeded();
         int code = execute();
         boolean ignoreCode = step.env() != null && step.env.equals(IGNORE_CODE);
         boolean negateCode = step.env() != null && step.env.equals(NEGATE_CODE);
@@ -76,6 +78,19 @@
     }
 
     /**
+     * Pauses if the step requires it.
+     */
+    private void delayIfNeeded() {
+        if (step.delay() > 0) {
+            try {
+                Thread.sleep(step.delay() * SECONDS);
+            } catch (InterruptedException e) {
+                throw new RuntimeException("Interrupted", e);
+            }
+        }
+    }
+
+    /**
      * Executes the step process.
      *
      * @return exit code