Enhancing STC and scenarios.

Change-Id: I57a4d25b7fb726a1242073055474ff5c7c3c1087
diff --git a/tools/dev/bin/onos-create-app b/tools/dev/bin/onos-create-app
index 9546b1d..279ec06 100755
--- a/tools/dev/bin/onos-create-app
+++ b/tools/dev/bin/onos-create-app
@@ -8,8 +8,10 @@
 
 type=${1:-bundle}
 
+[ $type = app ] && archetype=bundle || archetype=$type
+
 if [ "$1" = "-?" -o "$1" = "-h" -o "$1" = "--help" ]; then
-    echo "usage: $(basename $0) {bundle|ui|cli|api} groupId artifactId version package mvn-options"
+    echo "usage: $(basename $0) {app|bundle|ui|cli|api} groupId artifactId version package mvn-options"
     echo "        All arguments are optional"
     exit 1
 fi
@@ -17,10 +19,16 @@
 otherOptions=""
 [ -n "$1" ] && shift
 [ -n "$1" ] && otherOptions="$otherOptions -DgroupId=$1" && shift
-[ -n "$1" ] && otherOptions="$otherOptions -DartifactId=$1" && shift
+[ -n "$1" ] && otherOptions="$otherOptions -DartifactId=$1" && dir=$1 && shift
 [ -n "$1" ] && otherOptions="$otherOptions -Dversion=$1" && shift
 [ -n "$1" ] && otherOptions="$otherOptions -Dpackage=$1" && shift
 
 mvn archetype:generate -DarchetypeGroupId=org.onosproject \
-    -DarchetypeArtifactId=onos-$type-archetype -DarchetypeVersion=$ONOS_POM_VERSION \
-    $otherOptions "$@"
\ No newline at end of file
+    -DarchetypeArtifactId=onos-$archetype-archetype \
+    -DarchetypeVersion=$ONOS_POM_VERSION $otherOptions "$@"
+
+# Patch the pom.xml file to make this an app.
+if [ $type = app -a -d $dir ]; then
+    egrep -v "        (<!--|-->)" $dir/pom.xml > $dir/pom.app.xml
+    mv $dir/pom.app.xml $dir/pom.xml
+fi
\ No newline at end of file
diff --git a/tools/package/archetypes/bundle/src/main/resources/archetype-resources/pom.xml b/tools/package/archetypes/bundle/src/main/resources/archetype-resources/pom.xml
index 2b9a2b6..c6505ac 100644
--- a/tools/package/archetypes/bundle/src/main/resources/archetype-resources/pom.xml
+++ b/tools/package/archetypes/bundle/src/main/resources/archetype-resources/pom.xml
@@ -108,7 +108,7 @@
             <plugin>
                 <groupId>org.onosproject</groupId>
                 <artifactId>onos-maven-plugin</artifactId>
-                <version>1.4-SNAPSHOT</version>
+                <version>1.4</version>
                 <executions>
                     <execution>
                         <id>cfg</id>
diff --git a/tools/test/bin/ogroup-opts b/tools/test/bin/ogroup-opts
index e9b030c..3b4248c 100644
--- a/tools/test/bin/ogroup-opts
+++ b/tools/test/bin/ogroup-opts
@@ -1,14 +1,43 @@
-# tab completion settings for onos-group.
 
-# options available to onos-group
-GOPTS='install kill patch-vm push-keys uninstall'
-
+# Tab completion settings for onos-group.
 function _ogroup-opts () {
   local cur=${COMP_WORDS[COMP_CWORD]}
-
   if [ $COMP_CWORD -eq 1 ]; then
-    COMPREPLY=( $( compgen -W "$GOPTS help" -- $cur ) )
+    COMPREPLY=( $( compgen -W "install kill patch-vm push-keys uninstall help" -- $cur ) )
   fi
 }
 
 complete -F _ogroup-opts onos-group
+
+
+# Tab completion settings for stc
+function _stc-opts () {
+  local cur=${COMP_WORDS[COMP_CWORD]}
+  if [ $COMP_CWORD -eq 1 ]; then
+    COMPREPLY=( $( compgen -W "$(cd $ONOS_ROOT/tools/test/scenarios && ls -1 | sed 's/.xml//g')" -- $cur ) )
+  fi
+}
+
+complete -F _stc-opts stc
+
+
+# Tab completion settings for cell
+function _cell-opts () {
+  local cur=${COMP_WORDS[COMP_CWORD]}
+  if [ $COMP_CWORD -eq 1 ]; then
+    COMPREPLY=( $( compgen -W "$(cd $ONOS_ROOT/tools/test/cells && ls -1)" -- $cur ) )
+  fi
+}
+
+complete -F _cell-opts cell
+
+
+# Tab completion settings for onos-create-app.
+function _ocapp-opts () {
+  local cur=${COMP_WORDS[COMP_CWORD]}
+  if [ $COMP_CWORD -eq 1 ]; then
+    COMPREPLY=( $( compgen -W "bundle ui cli" -- $cur ) )
+  fi
+}
+
+complete -F _ocapp-opts onos-create-app
diff --git a/tools/test/bin/onos-check-bits b/tools/test/bin/onos-check-bits
index 0cf5fe5..0423c34 100755
--- a/tools/test/bin/onos-check-bits
+++ b/tools/test/bin/onos-check-bits
@@ -6,4 +6,4 @@
 [ ! -d "$ONOS_ROOT" ] && echo "ONOS_ROOT is not defined" >&2 && exit 1
 . $ONOS_ROOT/tools/build/envDefaults
 
-test -f $ONOS_TAR
+ls -l $ONOS_TAR && cksum $ONOS_TAR
diff --git a/tools/test/bin/onos-check-components b/tools/test/bin/onos-check-components
index 38fb9a3..f4c2df2 100755
--- a/tools/test/bin/onos-check-components
+++ b/tools/test/bin/onos-check-components
@@ -8,4 +8,10 @@
 
 onos ${1:-$OCI} scr:list > $aux
 cat $aux
-grep -q UNSATISFIED $aux && exit 1 || exit 0
+grep -q UNSATISFIED $aux && exit 1
+
+if [ -n "$2" ]; then
+    echo "Searching for ACTIVE $2"
+    egrep "ACTIVE.*$2" $aux || exit 1
+fi
+exit 0
\ No newline at end of file
diff --git a/tools/test/bin/stc b/tools/test/bin/stc
index 9dfa38f..fd201b6 100755
--- a/tools/test/bin/stc
+++ b/tools/test/bin/stc
@@ -3,11 +3,14 @@
 #   System Test Coordinator
 #-------------------------------------------------------------------------------
 
-STC_ROOT=${STC_ROOT:-$(dirname $0)/..}
-cd $STC_ROOT
 VER=1.2.0-SNAPSHOT
+JAR=~/.m2/repository/org/onosproject/onlab-stc/$VER/onlab-stc-$VER.jar
+SCENARIOS=$ONOS_ROOT/tools/test/scenarios
 
-PATH=$PWD/bin:$PATH
+scenario=${1:-smoke}
 
-java -jar ~/.m2/repository/org/onosproject/onlab-stc/$VER/onlab-stc-$VER.jar \
-    "${@:-$ONOS_ROOT/tools/test/scenarios/smoke.xml}"
+[ ! -f $scenario ] && scenario=$SCENARIOS/$scenario
+[ ! -f $scenario ] && scenario=$scenario.xml
+[ ! -f $scenario ] && echo "Scenario $scenario file not found" && exit 1
+
+java -jar $JAR $scenario
diff --git a/tools/test/bin/stc-launcher b/tools/test/bin/stc-launcher
index 3ef661e..d5da4f1 100755
--- a/tools/test/bin/stc-launcher
+++ b/tools/test/bin/stc-launcher
@@ -2,4 +2,22 @@
 #-------------------------------------------------------------------------------
 #   System Test Coordinator process launcher
 #-------------------------------------------------------------------------------
+
+env=$1 && shift
+cwd=$1 && shift
+
+if [ $env != "-" -a $env != "~" ]; then
+    [ ! -f $env ] && echo "$env file not found" && exit 1
+    source $env
+fi
+
+if [ $cwd != "-" ]; then
+    [ ! -d $cwd ] && echo "$cwd directory not found" && exit 1
+    cd $cwd
+fi
+
 "$@" 2>&1
+status=$?
+
+[ $env != "~" ] && exit $status
+exit 0
diff --git a/tools/test/scenarios/archetypes.xml b/tools/test/scenarios/archetypes.xml
new file mode 100644
index 0000000..42c4ffb
--- /dev/null
+++ b/tools/test/scenarios/archetypes.xml
@@ -0,0 +1,45 @@
+<!--
+  ~ Copyright 2015 Open Networking Laboratory
+  ~
+  ~ 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.
+  -->
+<scenario name="archetypes-test" description="ONOS archetypes test">
+    <group name="Archetypes" cwd="${WORKSPACE}/tmp/test-app">
+        <step name="Clean-Up" cwd="${WORKSPACE}/tmp" env="~"
+              exec="rm -r test-app"/>
+
+        <step name="Create-App" cwd="${WORKSPACE}/tmp" requires="Clean-Up"
+              exec="onos-create-app app org.test.app test-app 1.2.3 org.test.app -DinteractiveMode=false"/>
+        <step name="Build-App" requires="Create-App" exec="mvn clean install"/>
+        <step name="Install-App" requires="Build-App"
+              exec="onos-app ${OCI} install! target/test-app-1.2.3.oar"/>
+        <step name="Verify-App" requires="Install-App"
+              exec="onos-check-components ${OCI} org.test.app.AppComponent"/>
+
+        <step name="Create-App-CLI-Overlay" requires="Install-App"
+              exec="onos-create-app cli org.test.app test-app 1.2.3 org.test.app -DinteractiveMode=false"/>
+        <step name="Build-App-With-CLI" requires="Create-App-CLI-Overlay"
+              exec="mvn clean install"/>
+        <step name="Reinstall-App-With-CLI" requires="Build-App-With-CLI,-Verify-App"
+              exec="onos-app ${OCI} reinstall! target/test-app-1.2.3.oar"/>
+        <step name="Verify-CLI" requires="Reinstall-App-With-CLI"
+              exec="onos ${OCI} sample"/>
+
+        <step name="Create-App-UI-Overlay" requires="Reinstall-App-With-CLI"
+              exec="onos-create-app ui org.test.app test-app 1.2.3 org.test.app -DinteractiveMode=false"/>
+        <step name="Build-App-With-UI" requires="Create-App-UI-Overlay"
+              exec="mvn clean install"/>
+        <step name="Reinstall-App-With-UI" requires="Build-App-With-UI,-Verify-CLI"
+              exec="onos-app ${OCI} reinstall! target/test-app-1.2.3.oar"/>
+    </group>
+</scenario>
diff --git a/utils/stc/bin/stc-launcher b/utils/stc/bin/stc-launcher
index 3ef661e..0d56017 100755
--- a/utils/stc/bin/stc-launcher
+++ b/utils/stc/bin/stc-launcher
@@ -2,4 +2,18 @@
 #-------------------------------------------------------------------------------
 #   System Test Coordinator process launcher
 #-------------------------------------------------------------------------------
+
+env=$1 && shift
+cwd=$1 && shift
+
+if [ $env != "-" ]; then
+    [ ! -f $env ] && echo "$env file not found" && exit 1
+    source $env
+fi
+
+if [ $cwd != "-" ]; then
+    [ ! -d $cwd ] && echo "$cwd directory not found" && exit 1
+    cd $cwd
+fi
+
 "$@" 2>&1
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 6ee03c5..167570c 100644
--- a/utils/stc/src/main/java/org/onlab/stc/Compiler.java
+++ b/utils/stc/src/main/java/org/onlab/stc/Compiler.java
@@ -50,6 +50,8 @@
     private static final String LOG_DIR = "[@logDir]";
     private static final String NAME = "[@name]";
     private static final String COMMAND = "[@exec]";
+    private static final String ENV = "[@env]";
+    private static final String CWD = "[@cwd]";
     private static final String REQUIRES = "[@requires]";
     private static final String IF = "[@if]";
     private static final String UNLESS = "[@unless]";
@@ -200,11 +202,12 @@
     private void processStep(HierarchicalConfiguration cfg,
                              String namespace, Group parentGroup) {
         String name = expand(prefix(cfg.getString(NAME), namespace));
-        String defaultValue = parentGroup != null ? parentGroup.command() : null;
-        String command = expand(cfg.getString(COMMAND, defaultValue));
+        String command = expand(cfg.getString(COMMAND, parentGroup != null ? parentGroup.command() : null));
+        String env = expand(cfg.getString(ENV, parentGroup != null ? parentGroup.env() : null));
+        String cwd = expand(cfg.getString(CWD, parentGroup != null ? parentGroup.cwd() : null));
 
-        print("step name=%s command=%s", name, command);
-        Step step = new Step(name, command, parentGroup);
+        print("step name=%s command=%s env=%s cwd=%s", name, command, env, cwd);
+        Step step = new Step(name, command, env, cwd, parentGroup);
         registerStep(step, cfg, namespace, parentGroup);
     }
 
@@ -218,11 +221,12 @@
     private void processGroup(HierarchicalConfiguration cfg,
                               String namespace, Group parentGroup) {
         String name = expand(prefix(cfg.getString(NAME), namespace));
-        String defaultValue = parentGroup != null ? parentGroup.command() : null;
-        String command = expand(cfg.getString(COMMAND, defaultValue));
+        String command = expand(cfg.getString(COMMAND, parentGroup != null ? parentGroup.command() : null));
+        String env = expand(cfg.getString(ENV, parentGroup != null ? parentGroup.env() : null));
+        String cwd = expand(cfg.getString(CWD, parentGroup != null ? parentGroup.cwd() : null));
 
-        print("group name=%s command=%s", name, command);
-        Group group = new Group(name, command, parentGroup);
+        print("group name=%s command=%s env=%s cwd=%s", name, command, env, cwd);
+        Group group = new Group(name, command, env, cwd, parentGroup);
         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 a094828..0281c36 100644
--- a/utils/stc/src/main/java/org/onlab/stc/Group.java
+++ b/utils/stc/src/main/java/org/onlab/stc/Group.java
@@ -31,11 +31,13 @@
      * Creates a new test step.
      *
      * @param name    group name
-     * @param command group default command
+     * @param command default command
+     * @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
      */
-    public Group(String name, String command, Group group) {
-        super(name, command, group);
+    public Group(String name, String command, String env, String cwd, Group group) {
+        super(name, command, env, cwd, group);
     }
 
     /**
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 834e0ec..3d8ea98 100644
--- a/utils/stc/src/main/java/org/onlab/stc/Step.java
+++ b/utils/stc/src/main/java/org/onlab/stc/Step.java
@@ -29,22 +29,28 @@
 
     protected final String name;
     protected final String command;
+    protected final String env;
+    protected final String cwd;
     protected final Group group;
 
     /**
      * Creates a new test step.
      *
-     * @param name     step name
-     * @param command  step command to execute
-     * @param group    optional group to which this step belongs
+     * @param name    step name
+     * @param command step command to execute
+     * @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
      */
-    public Step(String name, String command, Group group) {
+    public Step(String name, String command, String env, String cwd, Group group) {
         this.name = checkNotNull(name, "Name cannot be null");
         this.group = group;
 
-        // Set the command; if one is not given default to the enclosing group
-        this.command = command != null ? command :
-                group != null && group.command != null ? group.command : null;
+        // Set the command, environment and cwd
+        // If one is not given use the value from the enclosing group
+        this.command = command != null ? command : group != null && group.command != null ? group.command : null;
+        this.env = env != null ? env : group != null && group.env != null ? group.env : null;
+        this.cwd = cwd != null ? cwd : group != null && group.cwd != null ? group.cwd : null;
     }
 
     /**
@@ -66,6 +72,24 @@
     }
 
     /**
+     * Returns the step environment script path.
+     *
+     * @return env script path
+     */
+    public String env() {
+        return env;
+    }
+
+    /**
+     * Returns the step current working directory path.
+     *
+     * @return current working dir path
+     */
+    public String cwd() {
+        return cwd;
+    }
+
+    /**
      * Returns the enclosing group; null if none.
      *
      * @return enclosing group or null
@@ -97,6 +121,8 @@
         return MoreObjects.toStringHelper(this)
                 .add("name", name)
                 .add("command", command)
+                .add("env", env)
+                .add("cwd", cwd)
                 .add("group", group)
                 .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 b2d7635..95d5c86 100644
--- a/utils/stc/src/main/java/org/onlab/stc/StepProcessor.java
+++ b/utils/stc/src/main/java/org/onlab/stc/StepProcessor.java
@@ -22,6 +22,7 @@
 import java.io.InputStreamReader;
 import java.io.PrintWriter;
 
+import static java.lang.String.format;
 import static org.onlab.stc.Coordinator.print;
 
 /**
@@ -71,8 +72,8 @@
      * @return exit code
      */
     private int execute() {
-        try (PrintWriter pw = new PrintWriter(logFile(step))) {
-            process = Runtime.getRuntime().exec(launcher + step.command());
+        try (PrintWriter pw = new PrintWriter(logFile())) {
+            process = Runtime.getRuntime().exec(command());
             processOutput(pw);
 
             // Wait for the process to complete and get its exit code.
@@ -90,6 +91,18 @@
     }
 
     /**
+     * Returns ready-to-run command for the step.
+     *
+     * @return command to execute
+     */
+    private String command() {
+        return format("%s %s %s %s", launcher,
+                      step.env() != null ? step.env() : "-",
+                      step.cwd() != null ? step.cwd() : "-",
+                      step.command());
+    }
+
+    /**
      * Captures output of the step process.
      *
      * @param pw print writer to send output to
@@ -108,12 +121,11 @@
     }
 
     /**
-     * Returns the log file for the specified step.
+     * Returns the log file for the step output.
      *
-     * @param step test step
      * @return log file
      */
-    private File logFile(Step step) {
+    private File logFile() {
         return new File(logDir, step.name() + ".log");
     }
 
diff --git a/utils/stc/src/test/java/org/onlab/stc/DependencyTest.java b/utils/stc/src/test/java/org/onlab/stc/DependencyTest.java
index 7d56892..4438303 100644
--- a/utils/stc/src/test/java/org/onlab/stc/DependencyTest.java
+++ b/utils/stc/src/test/java/org/onlab/stc/DependencyTest.java
@@ -32,8 +32,8 @@
     @Before
     public void setUp() throws ConfigurationException {
         super.setUp();
-        step1 = new Step("step1", CMD, null);
-        step2 = new Step("step2", CMD, null);
+        step1 = new Step("step1", CMD, null, null, null);
+        step2 = new Step("step2", CMD, null, null, null);
     }
 
     @Test
diff --git a/utils/stc/src/test/java/org/onlab/stc/GroupTest.java b/utils/stc/src/test/java/org/onlab/stc/GroupTest.java
index 8062fe5..9b612c8 100644
--- a/utils/stc/src/test/java/org/onlab/stc/GroupTest.java
+++ b/utils/stc/src/test/java/org/onlab/stc/GroupTest.java
@@ -28,21 +28,23 @@
 
     @Test
     public void basics() {
-        Group group = new Group(NAME, CMD, parent);
+        Group group = new Group(NAME, CMD, ENV, CWD, parent);
         assertEquals("incorrect name", NAME, group.name());
         assertEquals("incorrect command", CMD, group.command());
+        assertEquals("incorrect env", ENV, group.env());
+        assertEquals("incorrect cwd", CWD, group.cwd());
         assertSame("incorrect group", parent, group.group());
 
-        Step step = new Step("step", null, group);
+        Step step = new Step("step", null, null, null, group);
         group.addChild(step);
         assertSame("incorrect child", step, group.children().iterator().next());
     }
 
     @Test
     public void equality() {
-        Group g1 = new Group(NAME, CMD, parent);
-        Group g2 = new Group(NAME, CMD, null);
-        Group g3 = new Group("foo", null, parent);
+        Group g1 = new Group(NAME, CMD, null, null, parent);
+        Group g2 = new Group(NAME, CMD, ENV, CWD, null);
+        Group g3 = new Group("foo", null, null, null, parent);
         new EqualsTester()
                 .addEqualityGroup(g1, g2)
                 .addEqualityGroup(g3)
diff --git a/utils/stc/src/test/java/org/onlab/stc/StepProcessorTest.java b/utils/stc/src/test/java/org/onlab/stc/StepProcessorTest.java
index 0a932a4..d87372f 100644
--- a/utils/stc/src/test/java/org/onlab/stc/StepProcessorTest.java
+++ b/utils/stc/src/test/java/org/onlab/stc/StepProcessorTest.java
@@ -36,7 +36,7 @@
 
     @BeforeClass
     public static void setUpClass() {
-        StepProcessor.launcher = "";
+        StepProcessor.launcher = "echo";
         DIR.mkdirs();
     }
 
@@ -47,7 +47,7 @@
 
     @Test
     public void executed() {
-        Step step = new Step("foo", "ls /tmp", null);
+        Step step = new Step("foo", "ls /tmp", null, null, null);
         StepProcessor processor = new StepProcessor(step, false, DIR, delegate);
         processor.run();
         assertTrue("should be started", delegate.started);
@@ -59,7 +59,7 @@
 
     @Test
     public void skipped() {
-        Step step = new Step("foo", "ls /tmp", null);
+        Step step = new Step("foo", "ls /tmp", null, null, null);
         StepProcessor processor = new StepProcessor(step, true, DIR, delegate);
         processor.run();
         assertTrue("should be started", delegate.started);
diff --git a/utils/stc/src/test/java/org/onlab/stc/StepTest.java b/utils/stc/src/test/java/org/onlab/stc/StepTest.java
index 6b3ee79..7108362 100644
--- a/utils/stc/src/test/java/org/onlab/stc/StepTest.java
+++ b/utils/stc/src/test/java/org/onlab/stc/StepTest.java
@@ -30,26 +30,30 @@
 
     protected static final String NAME = "step";
     protected static final String CMD = "command";
+    protected static final String ENV = "environment";
+    protected static final String CWD = "directory";
     protected Group parent;
 
     @Before
     public void setUp() throws ConfigurationException {
-        parent = new Group("parent", null, null);
+        parent = new Group("parent", null, null, null, null);
     }
 
     @Test
     public void basics() {
-        Step step = new Step(NAME, CMD, parent);
+        Step step = new Step(NAME, CMD, ENV, CWD, parent);
         assertEquals("incorrect name", NAME, step.name());
         assertEquals("incorrect command", CMD, step.command());
+        assertEquals("incorrect env", ENV, step.env());
+        assertEquals("incorrect cwd", CWD, step.cwd());
         assertSame("incorrect group", parent, step.group());
     }
 
     @Test
     public void equality() {
-        Step s1 = new Step(NAME, CMD, parent);
-        Step s2 = new Step(NAME, CMD, null);
-        Step s3 = new Step("foo", null, parent);
+        Step s1 = new Step(NAME, CMD, null, null, parent);
+        Step s2 = new Step(NAME, CMD, ENV, CWD, null);
+        Step s3 = new Step("foo", null, null, null, parent);
         new EqualsTester()
                 .addEqualityGroup(s1, s2)
                 .addEqualityGroup(s3)