Refactoring the test cases to install openwhisk-catalog

Currently, all the actions in openwhisk-catalog have been synchronized
with the ones in openwhisk. The test coverage of actions is equal to
openwhisk. We are technically able to switch from openwhisk/catalog to the
openwhisk-catalog.

Some tests in WskBasicTests have been moved under whisk.core.cli.test,
so that whisk.core.entity.Subject can be accessed to create the fake user.
diff --git a/tests/src/system/basic/WskActionSequenceTests.scala b/tests/src/system/basic/WskActionSequenceTests.scala
index 9b747d9..c6a2e1e 100644
--- a/tests/src/system/basic/WskActionSequenceTests.scala
+++ b/tests/src/system/basic/WskActionSequenceTests.scala
@@ -45,22 +45,24 @@
 
     implicit val wskprops = WskProps()
     val wsk = new Wsk(usePythonCLI = false)
-    val defaultAction = Some(TestUtils.getCatalogFilename("samples/hello.js"))
     val allowedActionDuration = 120 seconds
 
     behavior of "Wsk Action Sequence"
 
     it should "invoke a blocking action and get only the result" in withAssetCleaner(wskprops) {
         (wp, assetHelper) =>
-            val pkgname = "my package"
-            val name = "sequence action"
+            val name = "sequence"
 
-            assetHelper.withCleaner(wsk.pkg, pkgname) {
-                (pkg, _) => pkg.bind("/whisk.system/util", pkgname)
+            val actions = Seq("split", "sort", "head", "cat")
+            for (actionName <- actions) {
+                val file = TestUtils.getTestActionFilename(s"$actionName.js")
+                assetHelper.withCleaner(wsk.action, actionName) { (action, _) =>
+                    action.create(name = actionName, artifact = Some(file))
+                }
             }
 
             assetHelper.withCleaner(wsk.action, name) {
-                val sequence = Seq("split", "sort", "head", "cat") map { a => s"$pkgname/$a" } mkString (",")
+                val sequence = actions.mkString (",")
                 (action, _) => action.create(name, Some(sequence), kind = Some("sequence"), timeout = Some(allowedActionDuration))
             }
 
@@ -77,7 +79,7 @@
             }
 
             // update action sequence
-            val newSequence = Seq("split", "sort") map { a => s"$pkgname/$a" } mkString (",")
+            val newSequence = Seq("split", "sort").mkString (",")
             wsk.action.create(name, Some(newSequence), kind = Some("sequence"), timeout = Some(allowedActionDuration), update = true)
             val secondrun = wsk.action.invoke(name, Map("payload" -> args.mkString("\n").toJson))
             withActivation(wsk.activation, secondrun, totalWait = allowedActionDuration) {
diff --git a/tests/src/system/basic/WskBasicTests.scala b/tests/src/system/basic/WskBasicTests.scala
index 0019b1c..25dd577 100644
--- a/tests/src/system/basic/WskBasicTests.scala
+++ b/tests/src/system/basic/WskBasicTests.scala
@@ -25,12 +25,8 @@
 
 import common.TestHelpers
 import common.TestUtils
-import common.TestUtils.ANY_ERROR_EXIT
 import common.TestUtils.CONFLICT
-import common.TestUtils.FORBIDDEN
-import common.TestUtils.NOT_FOUND
 import common.TestUtils.SUCCESS_EXIT
-import common.TestUtils.TIMEOUT
 import common.TestUtils.UNAUTHORIZED
 import common.Wsk
 import common.WskProps
@@ -38,7 +34,6 @@
 import spray.json._
 import spray.json.DefaultJsonProtocol._
 import spray.json.pimpAny
-import whisk.core.entity.WhiskPackage
 
 @RunWith(classOf[JUnitRunner])
 class WskBasicTests
@@ -47,7 +42,7 @@
 
     implicit val wskprops = WskProps()
     val wsk = new Wsk(usePythonCLI = false)
-    val defaultAction = Some(TestUtils.getCatalogFilename("samples/hello.js"))
+    val defaultAction = Some(TestUtils.getTestActionFilename("hello.js"))
 
     behavior of "Wsk CLI"
 
@@ -93,43 +88,11 @@
             stderr should include(errormsg)
     }
 
-    it should "reject deleting action in shared package not owned by authkey" in {
-        wsk.action.get("/whisk.system/util/cat") // make sure it exists
-        wsk.action.delete("/whisk.system/util/cat", expectedExitCode = FORBIDDEN)
-    }
-
-    it should "reject create action in shared package not owned by authkey" in {
-        wsk.action.get("/whisk.system/util/notallowed", expectedExitCode = NOT_FOUND) // make sure it does not exist
-        val file = Some(TestUtils.getCatalogFilename("samples/hello.js"))
-        try {
-            wsk.action.create("/whisk.system/util/notallowed", file, expectedExitCode = FORBIDDEN)
-        } finally {
-            wsk.action.sanitize("/whisk.system/util/notallowed")
-        }
-    }
-
-    it should "reject update action in shared package not owned by authkey" in {
-        wsk.action.create("/whisk.system/util/cat", None,
-            update = true, shared = Some(true), expectedExitCode = FORBIDDEN)
-    }
-
     behavior of "Wsk Package CLI"
 
-    it should "list shared packages" in {
-        val result = wsk.pkg.list(Some("/whisk.system")).stdout
-        result should include regex ("""/whisk.system/samples\s+shared""")
-        result should include regex ("""/whisk.system/util\s+shared""")
-    }
-
-    it should "list shared package actions" in {
-        val result = wsk.action.list(Some("/whisk.system/util")).stdout
-        result should include regex ("""/whisk.system/util/head\s+shared""")
-        result should include regex ("""/whisk.system/util/date\s+shared""")
-    }
-
     it should "create, update, get and list a package" in withAssetCleaner(wskprops) {
         (wp, assetHelper) =>
-            val name = "samplePackage"
+            val name = "testPackage"
             val params = Map("a" -> "A".toJson)
             assetHelper.withCleaner(wsk.pkg, name) {
                 (pkg, _) =>
@@ -144,22 +107,6 @@
             wsk.pkg.list().stdout should include(name)
     }
 
-    it should "create a package binding" in withAssetCleaner(wskprops) {
-        (wp, assetHelper) =>
-            val name = "bindPackage"
-            val provider = "/whisk.system/samples"
-            val annotations = Map("a" -> "A".toJson, WhiskPackage.bindingFieldName -> "xxx".toJson)
-            assetHelper.withCleaner(wsk.pkg, name) {
-                (pkg, _) =>
-                    pkg.bind(provider, name, annotations = annotations)
-            }
-            val stdout = wsk.pkg.get(name).stdout
-            stdout should include regex (""""key": "a"""")
-            stdout should include regex (""""value": "A"""")
-            stdout should include regex (s""""key": "${WhiskPackage.bindingFieldName}"""")
-            stdout should not include regex(""""key": "xxx"""")
-    }
-
     behavior of "Wsk Action CLI"
 
     it should "create the same action twice with different cases" in withAssetCleaner(wskprops) {
@@ -171,7 +118,7 @@
     it should "create an action, then update its kind" in withAssetCleaner(wskprops) {
         (wp, assetHelper) =>
             val name = "createAndUpdate"
-            val file = Some(TestUtils.getCatalogFilename("samples/hello.js"))
+            val file = Some(TestUtils.getTestActionFilename("hello.js"))
 
             assetHelper.withCleaner(wsk.action, name) {
                 (action, _) => action.create(name, file, kind = Some("nodejs"))
@@ -188,7 +135,7 @@
     it should "create, update, get and list an action" in withAssetCleaner(wskprops) {
         (wp, assetHelper) =>
             val name = "createAndUpdate"
-            val file = Some(TestUtils.getCatalogFilename("samples/hello.js"))
+            val file = Some(TestUtils.getTestActionFilename("hello.js"))
             val params = Map("a" -> "A".toJson)
             assetHelper.withCleaner(wsk.action, name) {
                 (action, _) =>
@@ -205,11 +152,6 @@
             wsk.action.list().stdout should include(name)
     }
 
-    it should "get an action" in {
-        wsk.action.get("/whisk.system/samples/wordCount").
-            stdout should include("words")
-    }
-
     it should "reject delete of action that does not exist" in {
         wsk.action.sanitize("deleteFantasy").
             stderr should include regex ("""The requested resource does not exist. \(code \d+\)""")
@@ -274,7 +216,7 @@
         (wp, assetHelper) =>
             val name = "basicInvoke"
             assetHelper.withCleaner(wsk.action, name) {
-                (action, _) => action.create(name, Some(TestUtils.getCatalogFilename("samples/wc.js")))
+                (action, _) => action.create(name, Some(TestUtils.getTestActionFilename("wordcount.js")))
             }
             wsk.action.invoke(name, Map("payload" -> "one two three".toJson), blocking = true, result = true)
                 .stdout should include regex (""""count": 3""")
@@ -308,36 +250,6 @@
             wsk.trigger.list().stdout should include(name)
     }
 
-    it should "not create a trigger when feed fails to initialize" in withAssetCleaner(wskprops) {
-        (wp, assetHelper) =>
-            assetHelper.withCleaner(wsk.trigger, "badfeed", confirmDelete = false) {
-                (trigger, name) =>
-                    trigger.create(name, feed = Some(s"bogus"), expectedExitCode = ANY_ERROR_EXIT).
-                        exitCode should { equal(NOT_FOUND) or equal(FORBIDDEN) }
-                    trigger.get(name, expectedExitCode = NOT_FOUND)
-
-                    trigger.create(name, feed = Some(s"bogus/feed"), expectedExitCode = ANY_ERROR_EXIT).
-                        exitCode should { equal(NOT_FOUND) or equal(FORBIDDEN) }
-                    trigger.get(name, expectedExitCode = NOT_FOUND)
-
-                    // verify that the feed runs and returns an application error (502 or Gateway Timeout)
-                    trigger.create(name, feed = Some(s"/whisk.system/github/webhook"), expectedExitCode = TIMEOUT)
-                    trigger.get(name, expectedExitCode = NOT_FOUND)
-            }
-    }
-
-    it should "display a trigger summary when --summary flag is used with 'wsk trigger get'" in withAssetCleaner(wskprops) {
-        (wp, assetHelper) =>
-            val triggerName = "mySummaryTrigger"
-            assetHelper.withCleaner(wsk.trigger, triggerName, confirmDelete = false) {
-                (trigger, name) => trigger.create(name)
-            }
-            // Summary namespace should match one of the allowable namespaces (typically 'guest')
-            val ns_regex_list = wsk.namespace.list().stdout.trim.replace('\n', '|')
-            val stdout = wsk.trigger.get(triggerName, summary = true).stdout
-            stdout should include regex (s"(?i)trigger\\s+/${ns_regex_list}/${triggerName}")
-    }
-
     behavior of "Wsk Rule CLI"
 
     it should "create rule, get rule, update rule and list rule" in withAssetCleaner(wskprops) {
diff --git a/tests/src/whisk/core/cli/test/WskBasicUsageTests.scala b/tests/src/whisk/core/cli/test/WskBasicUsageTests.scala
index 6081def..fda6ae0 100644
--- a/tests/src/whisk/core/cli/test/WskBasicUsageTests.scala
+++ b/tests/src/whisk/core/cli/test/WskBasicUsageTests.scala
@@ -36,6 +36,8 @@
 import common.TestUtils.MISUSE_EXIT
 import common.TestUtils.NOTALLOWED
 import common.TestUtils.SUCCESS_EXIT
+import common.TestUtils.FORBIDDEN
+import common.TestUtils.NOT_FOUND
 import common.WhiskProperties
 import common.Wsk
 import common.WskProps
@@ -311,13 +313,11 @@
     it should "not create an action when -a is specified without arguments" in withAssetCleaner(wskprops) {
         (wp, assetHelper) =>
             val name = "actionName"
-            var stderr = ""
             assetHelper.withCleaner(wsk.action, name, confirmDelete = false) {
                 (action, _) =>
                     val runresult = wsk.cli(wskprops.overrides ++ Seq("action", "create", name, "--auth", wp.authKey,
                         "-a"), expectedExitCode = ERROR_EXIT)
-                    stderr = runresult.stderr
-                    stderr should include("Annotation arguments must be a key value pair")
+                    runresult.stderr should include("Annotation arguments must be a key value pair")
                     runresult
             }
     }
@@ -325,15 +325,11 @@
     it should "not create an action when -p is specified without arguments" in withAssetCleaner(wskprops) {
         (wp, assetHelper) =>
             val name = "actionName"
-            var stderr = ""
             assetHelper.withCleaner(wsk.action, name, confirmDelete = false) {
                 (action, _) =>
                     val runresult = wsk.cli(wskprops.overrides ++ Seq("action", "create", name, "--auth", wp.authKey,
                         "-p"), expectedExitCode = ERROR_EXIT)
-                    stderr = runresult.stderr
-                    //val stderr = wsk.cli(wskprops.overrides ++ Seq("action", "create", name, "--auth", wp.authKey,
-                    //    "-p"), expectedExitCode = ERROR_EXIT).stderr
-                    stderr should include("Parameter arguments must be a key value pair")
+                    runresult.stderr should include("Parameter arguments must be a key value pair")
                     runresult
             }
     }
@@ -488,13 +484,11 @@
     it should "not create a package when -a is specified without arguments" in withAssetCleaner(wskprops) {
         (wp, assetHelper) =>
             val name = "packageName"
-            var stderr = ""
             assetHelper.withCleaner(wsk.pkg, name, confirmDelete = false) {
                 (pkg, _) =>
                     val runresult = wsk.cli(wskprops.overrides ++ Seq("package", "create", name, "--auth", wp.authKey,
                         "-a"), expectedExitCode = ERROR_EXIT)
-                    stderr = runresult.stderr
-                    stderr should include("Annotation arguments must be a key value pair")
+                    runresult.stderr should include("Annotation arguments must be a key value pair")
                     runresult
             }
     }
@@ -502,13 +496,11 @@
     it should "not create a package when -p is specified without arguments" in withAssetCleaner(wskprops) {
         (wp, assetHelper) =>
             val name = "packageName"
-            var stderr = ""
             assetHelper.withCleaner(wsk.pkg, name, confirmDelete = false) {
                 (pkg, _) =>
                     val runresult = wsk.cli(wskprops.overrides ++ Seq("package", "create", name, "--auth", wp.authKey,
                         "-p"), expectedExitCode = ERROR_EXIT)
-                    stderr = runresult.stderr
-                    stderr should include("Parameter arguments must be a key value pair")
+                    runresult.stderr should include("Parameter arguments must be a key value pair")
                     runresult
             }
     }
@@ -577,16 +569,27 @@
             wsk.parseJsonString(stdout).fields("parameters") shouldBe getValidJSONTestArgOutput
     }
 
+    it should "display a trigger summary when --summary flag is used with 'wsk trigger get'" in withAssetCleaner(wskprops) {
+        (wp, assetHelper) =>
+            val triggerName = "mySummaryTrigger"
+            assetHelper.withCleaner(wsk.trigger, triggerName, confirmDelete = false) {
+                (trigger, name) => trigger.create(name)
+            }
+
+            // Summary namespace should match one of the allowable namespaces (typically 'guest')
+            val ns_regex_list = wsk.namespace.list().stdout.trim.replace('\n', '|')
+            val stdout = wsk.trigger.get(triggerName, summary = true).stdout
+            stdout should include regex (s"(?i)trigger\\s+/${ns_regex_list}/${triggerName}")
+    }
+
     it should "not create a trigger when -a is specified without arguments" in withAssetCleaner(wskprops) {
         (wp, assetHelper) =>
             val name = "triggerName"
-            var stderr = ""
             assetHelper.withCleaner(wsk.trigger, name, confirmDelete = false) {
                 (trigger, _) =>
                     val runresult = wsk.cli(wskprops.overrides ++ Seq("trigger", "create", name, "--auth", wp.authKey,
                         "-a"), expectedExitCode = ERROR_EXIT)
-                    stderr = runresult.stderr
-                    stderr should include("Annotation arguments must be a key value pair")
+                    runresult.stderr should include("Annotation arguments must be a key value pair")
                     runresult
             }
     }
@@ -594,13 +597,11 @@
     it should "not create a trigger when -p is specified without arguments" in withAssetCleaner(wskprops) {
         (wp, assetHelper) =>
             val name = "triggerName"
-            var stderr = ""
             assetHelper.withCleaner(wsk.trigger, name, confirmDelete = false) {
                 (trigger, _) =>
                     val runresult = wsk.cli(wskprops.overrides ++ Seq("trigger", "create", name, "--auth", wp.authKey,
                         "-p"), expectedExitCode = ERROR_EXIT)
-                    stderr = runresult.stderr
-                    stderr should include("Parameter arguments must be a key value pair")
+                    runresult.stderr should include("Parameter arguments must be a key value pair")
                     runresult
             }
     }
@@ -637,6 +638,20 @@
             wsk.parseJsonString(stdout).fields("annotations") shouldBe getEscapedJSONTestArgOutput
     }
 
+    it should "not create a trigger when feed fails to initialize" in withAssetCleaner(wskprops) {
+        (wp, assetHelper) =>
+            assetHelper.withCleaner(wsk.trigger, "badfeed", confirmDelete = false) {
+                (trigger, name) =>
+                    trigger.create(name, feed = Some(s"bogus"), expectedExitCode = ANY_ERROR_EXIT).
+                        exitCode should equal(NOT_FOUND)
+                    trigger.get(name, expectedExitCode = NOT_FOUND)
+
+                    trigger.create(name, feed = Some(s"bogus/feed"), expectedExitCode = ANY_ERROR_EXIT).
+                        exitCode should { equal(FORBIDDEN) or equal(NOT_FOUND) } // response differs in the presence of entitlement service
+                    trigger.get(name, expectedExitCode = NOT_FOUND)
+            }
+    }
+
     behavior of "Wsk entity list formatting"
 
     it should "create, and list a package with a long name" in withAssetCleaner(wskprops) {
diff --git a/tests/src/whisk/core/cli/test/WskEntitlementTests.scala b/tests/src/whisk/core/cli/test/WskEntitlementTests.scala
new file mode 100644
index 0000000..aa2d9bb
--- /dev/null
+++ b/tests/src/whisk/core/cli/test/WskEntitlementTests.scala
@@ -0,0 +1,222 @@
+/*
+ * Copyright 2015-2016 IBM Corporation
+ *
+ * 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.
+ */
+
+package whisk.core.cli.test
+
+import org.junit.runner.RunWith
+import org.scalatest.junit.JUnitRunner
+import org.scalatest.BeforeAndAfterAll
+
+import common.RunWskAdminCmd
+import common.TestHelpers
+import common.TestUtils
+import common.TestUtils.FORBIDDEN
+import common.TestUtils.NOT_FOUND
+import common.TestUtils.TIMEOUT
+import common.Wsk
+import common.WskProps
+import common.WskTestHelpers
+import spray.json.DefaultJsonProtocol._
+import spray.json.pimpAny
+import whisk.core.entity.Subject
+import whisk.core.entity.WhiskPackage
+
+@RunWith(classOf[JUnitRunner])
+class WskCoreBasicTests
+    extends TestHelpers
+    with WskTestHelpers
+    with BeforeAndAfterAll {
+
+    val originWskProps = WskProps()
+    val wsk = new Wsk(usePythonCLI = false)
+
+    val wskadmin = new RunWskAdminCmd {}
+    val otherNamespace = Subject().toString
+    val create = wskadmin.cli(Seq("user", "create", otherNamespace))
+    val otherAuthkey = create.stdout.trim
+    val otherWskProps = WskProps(namespace = otherNamespace, authKey = otherAuthkey)
+    val samplePackage = "samplePackage"
+    val sampleAction = s"$samplePackage/sampleAction"
+
+    override def afterAll() = {
+        withClue(s"failed to delete temporary namespace $otherNamespace") {
+            wskadmin.cli(Seq("user", "delete", otherNamespace)).stdout should include("Subject deleted")
+        }
+    }
+
+    behavior of "Wsk CLI"
+
+    it should "reject deleting action in shared package not owned by authkey" in withAssetCleaner(otherWskProps) {
+        (wp, assetHelper) =>
+            assetHelper.withCleaner(wsk.pkg, samplePackage) {
+                (pkg, _) => pkg.create(samplePackage, shared = Some(true))(wp)
+            }
+
+            assetHelper.withCleaner(wsk.action, sampleAction) {
+                val file = Some(TestUtils.getTestActionFilename("empty.js"))
+                (action, _) => action.create(sampleAction, file, shared = Some(true))(wp)
+            }
+
+            val fullyQualifiedActionName = s"/$otherNamespace/$sampleAction"
+            wsk.action.get(fullyQualifiedActionName)(originWskProps)
+            wsk.action.delete(fullyQualifiedActionName, expectedExitCode = FORBIDDEN)(originWskProps)
+    }
+
+    it should "reject create action in shared package not owned by authkey" in withAssetCleaner(otherWskProps) {
+        (wp, assetHelper) =>
+            assetHelper.withCleaner(wsk.pkg, samplePackage) {
+                (pkg, name) => pkg.create(name, shared = Some(true))(wp)
+            }
+
+            val fullyQualifiedActionName = s"/$otherNamespace/notallowed"
+            val file = Some(TestUtils.getTestActionFilename("empty.js"))
+
+            withAssetCleaner(originWskProps) {
+                (wp, assetHelper) =>
+                    assetHelper.withCleaner(wsk.action, fullyQualifiedActionName, confirmDelete = false) {
+                        (action, name) => action.create(name, file, expectedExitCode = FORBIDDEN)(wp)
+                    }
+            }
+    }
+
+    it should "reject update action in shared package not owned by authkey" in withAssetCleaner(otherWskProps) {
+        (wp, assetHelper) =>
+            assetHelper.withCleaner(wsk.pkg, samplePackage) {
+                (pkg, _) => pkg.create(samplePackage, shared = Some(true))(wp)
+            }
+
+            assetHelper.withCleaner(wsk.action, sampleAction) {
+                val file = Some(TestUtils.getTestActionFilename("empty.js"))
+                (action, _) => action.create(sampleAction, file, shared = Some(true))(wp)
+            }
+
+            val fullyQualifiedActionName = s"/$otherNamespace/$sampleAction"
+            wsk.action.create(fullyQualifiedActionName, None, update = true, expectedExitCode = FORBIDDEN)(originWskProps)
+    }
+
+    behavior of "Wsk Package CLI"
+
+    it should "list shared packages" in withAssetCleaner(otherWskProps) {
+        (wp, assetHelper) =>
+            assetHelper.withCleaner(wsk.pkg, samplePackage) {
+                (pkg, _) => pkg.create(samplePackage, shared = Some(true))(wp)
+            }
+
+            val fullyQualifiedPackageName = s"/$otherNamespace/$samplePackage"
+            val result = wsk.pkg.list(Some(s"/$otherNamespace"))(originWskProps).stdout
+            result should include regex (fullyQualifiedPackageName + """\s+shared""")
+    }
+
+    it should "not list private packages" in withAssetCleaner(otherWskProps) {
+        (wp, assetHelper) =>
+            assetHelper.withCleaner(wsk.pkg, samplePackage) {
+                (pkg, _) => pkg.create(samplePackage)(wp)
+            }
+
+            val fullyQualifiedPackageName = s"/$otherNamespace/$samplePackage"
+            val result = wsk.pkg.list(Some(s"/$otherNamespace"))(originWskProps).stdout
+            result should not include regex(fullyQualifiedPackageName)
+    }
+
+    it should "list shared package actions" in withAssetCleaner(otherWskProps) {
+        (wp, assetHelper) =>
+            assetHelper.withCleaner(wsk.pkg, samplePackage) {
+                (pkg, _) => pkg.create(samplePackage, shared = Some(true))(wp)
+            }
+
+            assetHelper.withCleaner(wsk.action, sampleAction) {
+                val file = Some(TestUtils.getTestActionFilename("empty.js"))
+                (action, _) => action.create(sampleAction, file, kind = Some("nodejs"), shared = Some(true))(wp)
+            }
+
+            val fullyQualifiedPackageName = s"/$otherNamespace/$samplePackage"
+            val fullyQualifiedActionName = s"/$otherNamespace/$sampleAction"
+            val result = wsk.action.list(Some(fullyQualifiedPackageName))(originWskProps).stdout
+            result should include regex (fullyQualifiedActionName + """\s+shared""")
+    }
+
+    it should "create a package binding" in withAssetCleaner(otherWskProps) {
+        (wp, assetHelper) =>
+            assetHelper.withCleaner(wsk.pkg, samplePackage) {
+                (pkg, _) => pkg.create(samplePackage, shared = Some(true))(wp)
+            }
+
+            val name = "bindPackage"
+            val annotations = Map("a" -> "A".toJson, WhiskPackage.bindingFieldName -> "xxx".toJson)
+            val provider = s"/$otherNamespace/$samplePackage"
+            withAssetCleaner(originWskProps) {
+                (wp, assetHelper) =>
+                    assetHelper.withCleaner(wsk.pkg, name) {
+                        (pkg, _) => pkg.bind(provider, name, annotations = annotations)(wp)
+                    }
+
+                    val stdout = wsk.pkg.get(name)(originWskProps).stdout
+                    val annotationString = wsk.parseJsonString(stdout).fields("annotations").toString
+                    annotationString should include regex (""""key":"a"""")
+                    annotationString should include regex (""""value":"A"""")
+                    annotationString should include regex (s""""key":"${WhiskPackage.bindingFieldName}"""")
+                    annotationString should not include regex(""""key":"xxx"""")
+                    annotationString should include regex (s""""name":"${samplePackage}"""")
+            }
+    }
+
+    behavior of "Wsk Action CLI"
+
+    it should "get an action from package" in withAssetCleaner(otherWskProps) {
+        (wp, assetHelper) =>
+            assetHelper.withCleaner(wsk.pkg, samplePackage) {
+                (pkg, _) => pkg.create(samplePackage, parameters = Map("a" -> "A".toJson), shared = Some(true))(wp)
+            }
+
+            assetHelper.withCleaner(wsk.action, sampleAction) {
+                val file = Some(TestUtils.getTestActionFilename("empty.js"))
+                (action, _) => action.create(sampleAction, file, shared = Some(true))(wp)
+            }
+
+            val fullyQualifiedActionName = s"/$otherNamespace/$sampleAction"
+            val stdout = wsk.action.get(fullyQualifiedActionName)(originWskProps).stdout
+            stdout should include("name")
+            stdout should include("parameters")
+            stdout should include("limits")
+            stdout should include regex (""""key": "a"""")
+            stdout should include regex (""""value": "A"""")
+    }
+
+    behavior of "Wsk Trigger CLI"
+
+    it should "not create a trigger with timeout error when feed fails to initialize" in withAssetCleaner(otherWskProps) {
+        (wp, assetHelper) =>
+            assetHelper.withCleaner(wsk.pkg, samplePackage) {
+                (pkg, _) => pkg.create(samplePackage, shared = Some(true))(wp)
+            }
+
+            val sampleFeed = s"$samplePackage/sampleFeed"
+            assetHelper.withCleaner(wsk.action, sampleFeed) {
+                val file = Some(TestUtils.getTestActionFilename("empty.js"))
+                (action, _) => action.create(sampleFeed, file, kind = Some("nodejs"), shared = Some(true))(wp)
+            }
+
+            val fullyQualifiedFeedName = s"/$otherNamespace/$sampleFeed"
+            withAssetCleaner(originWskProps) {
+                (wp, assetHelper) =>
+                    assetHelper.withCleaner(wsk.trigger, "badfeed", confirmDelete = false) {
+                        (trigger, name) => trigger.create(name, feed = Some(fullyQualifiedFeedName), expectedExitCode = TIMEOUT)(wp)
+                    }
+                    wsk.trigger.get("badfeed", expectedExitCode = NOT_FOUND)(wp)
+            }
+    }
+
+}