csantanapr closed pull request #2944: Replace test cases of api gateway with 
REST
URL: https://github.com/apache/incubator-openwhisk/pull/2944
 
 
   

This is a PR merged from a forked repository.
As GitHub hides the original diff on merge, it is displayed below for
the sake of provenance:

As this is a foreign pull request (from a fork), the diff is supplied
below (as it won't show otherwise due to GitHub magic):

diff --git a/tests/src/test/scala/apigw/healthtests/ApiGwCliEndToEndTests.scala 
b/tests/src/test/scala/apigw/healthtests/ApiGwCliEndToEndTests.scala
new file mode 100644
index 0000000000..3025fab242
--- /dev/null
+++ b/tests/src/test/scala/apigw/healthtests/ApiGwCliEndToEndTests.scala
@@ -0,0 +1,33 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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 apigw.healthtests
+
+import org.junit.runner.RunWith
+import org.scalatest.junit.JUnitRunner
+
+import common.Wsk
+import common.TestUtils._
+
+/**
+ * Basic tests of the download link for Go CLI binaries
+ */
+@RunWith(classOf[JUnitRunner])
+class ApiGwCliEndToEndTests extends ApiGwEndToEndTests {
+  override lazy val wsk: common.Wsk = new Wsk
+  override val createCode: Int = SUCCESS_EXIT
+}
diff --git a/tests/src/test/scala/apigw/healthtests/ApiGwEndToEndTests.scala 
b/tests/src/test/scala/apigw/healthtests/ApiGwEndToEndTests.scala
index d0dbe92658..8995c7a7be 100644
--- a/tests/src/test/scala/apigw/healthtests/ApiGwEndToEndTests.scala
+++ b/tests/src/test/scala/apigw/healthtests/ApiGwEndToEndTests.scala
@@ -34,7 +34,7 @@ import com.jayway.restassured.RestAssured
 import common.TestHelpers
 import common.TestUtils
 import common.TestUtils._
-import common.Wsk
+import common.BaseWsk
 import common.WskProps
 import common.WskTestHelpers
 import spray.json._
@@ -45,7 +45,7 @@ import system.rest.RestUtil
  * Basic tests of the download link for Go CLI binaries
  */
 @RunWith(classOf[JUnitRunner])
-class ApiGwEndToEndTests
+abstract class ApiGwEndToEndTests
     extends FlatSpec
     with Matchers
     with RestUtil
@@ -53,23 +53,58 @@ class ApiGwEndToEndTests
     with WskTestHelpers
     with BeforeAndAfterAll {
 
-  implicit val wskprops = WskProps()
-  val wsk = new Wsk
-  val clinamespace = wsk.namespace.whois()
+  implicit val wskprops: common.WskProps = WskProps()
+  val wsk: BaseWsk
+  val namespace: String = wsk.namespace.whois()
+  val createCode: Int
 
   // Custom CLI properties file
-  val cliWskPropsFile = File.createTempFile("wskprops", ".tmp")
+  val cliWskPropsFile: java.io.File = File.createTempFile("wskprops", ".tmp")
 
   /*
    * Create a CLI properties file for use by the tests
    */
-  override def beforeAll() = {
+  override def beforeAll: Unit = {
     cliWskPropsFile.deleteOnExit()
     val wskprops = WskProps(token = "SOME TOKEN")
     wskprops.writeFile(cliWskPropsFile)
     println(s"wsk temporary props file created here: 
${cliWskPropsFile.getCanonicalPath()}")
   }
 
+  def verifyAPICreated(rr: RunResult): Unit = {
+    rr.stdout should include("ok: created API")
+    val apiurl = rr.stdout.split("\n")(1)
+    println(s"apiurl: '$apiurl'")
+  }
+
+  def verifyAPIList(rr: RunResult,
+                    actionName: String,
+                    testurlop: String,
+                    testapiname: String,
+                    testbasepath: String,
+                    testrelpath: String): Unit = {
+    rr.stdout should include("ok: APIs")
+    rr.stdout should include regex 
(s"$actionName\\s+$testurlop\\s+$testapiname\\s+")
+    rr.stdout should include(testbasepath + testrelpath)
+  }
+
+  def verifyAPISwaggerCreated(rr: RunResult): Unit = {
+    rr.stdout should include("ok: created API")
+  }
+
+  def writeSwaggerFile(rr: RunResult): File = {
+    val swaggerfile = File.createTempFile("api", ".json")
+    swaggerfile.deleteOnExit()
+    val bw = new BufferedWriter(new FileWriter(swaggerfile))
+    bw.write(rr.stdout)
+    bw.close()
+    return swaggerfile
+  }
+
+  def getSwaggerApiUrl(rr: RunResult): String = {
+    return rr.stdout.split("\n")(1)
+  }
+
   behavior of "Wsk api"
 
   it should s"create an API and successfully invoke that API" in {
@@ -83,7 +118,7 @@ class ApiGwEndToEndTests
     val urlqueryvalue = testName
 
     try {
-      println("cli namespace: " + clinamespace)
+      println("Namespace: " + namespace)
 
       // Delete any lingering stale api from previous run that may not have 
been deleted properly
       wsk.api.delete(
@@ -93,12 +128,14 @@ class ApiGwEndToEndTests
 
       // Create the action for the API.  It must be a "web-action" action.
       val file = TestUtils.getTestActionFilename(s"echo-web-http.js")
+      println("action creation Namespace: " + namespace)
       wsk.action.create(
         name = actionName,
         artifact = Some(file),
-        expectedExitCode = SUCCESS_EXIT,
+        expectedExitCode = createCode,
         annotations = Map("web-export" -> true.toJson))
 
+      println("creation Namespace: " + namespace)
       // Create the API
       var rr = wsk.api.create(
         basepath = Some(testbasepath),
@@ -108,9 +145,7 @@ class ApiGwEndToEndTests
         apiname = Some(testapiname),
         responsetype = Some("http"),
         cliCfgFile = Some(cliWskPropsFile.getCanonicalPath()))
-      rr.stdout should include("ok: created API")
-      val apiurl = rr.stdout.split("\n")(1)
-      println(s"apiurl: '$apiurl'")
+      verifyAPICreated(rr)
 
       // Validate the API was successfully created
       // List result will look like:
@@ -122,17 +157,11 @@ class ApiGwEndToEndTests
         relpath = Some(testrelpath),
         operation = Some(testurlop),
         cliCfgFile = Some(cliWskPropsFile.getCanonicalPath()))
-      rr.stdout should include("ok: APIs")
-      rr.stdout should include regex 
(s"$actionName\\s+$testurlop\\s+$testapiname\\s+")
-      rr.stdout should include(testbasepath + testrelpath)
+      verifyAPIList(rr, actionName, testurlop, testapiname, testbasepath, 
testrelpath)
 
       // Recreate the API using a JSON swagger file
       rr = wsk.api.get(basepathOrApiName = Some(testbasepath), cliCfgFile = 
Some(cliWskPropsFile.getCanonicalPath()))
-      val swaggerfile = File.createTempFile("api", ".json")
-      swaggerfile.deleteOnExit()
-      val bw = new BufferedWriter(new FileWriter(swaggerfile))
-      bw.write(rr.stdout)
-      bw.close()
+      val swaggerfile = writeSwaggerFile(rr)
 
       // Delete API to that it can be recreated again using the generated 
swagger file
       val deleteApiResult = wsk.api.delete(
@@ -143,8 +172,8 @@ class ApiGwEndToEndTests
       // Create the API again, but use the swagger file this time
       rr = wsk.api
         .create(swagger = Some(swaggerfile.getAbsolutePath()), cliCfgFile = 
Some(cliWskPropsFile.getCanonicalPath()))
-      rr.stdout should include("ok: created API")
-      val swaggerapiurl = rr.stdout.split("\n")(1)
+      verifyAPISwaggerCreated(rr)
+      val swaggerapiurl = getSwaggerApiUrl(rr)
       println(s"Returned api url: '${swaggerapiurl}'")
 
       // Call the API URL and validate the results
diff --git 
a/tests/src/test/scala/apigw/healthtests/ApiGwRestEndToEndTests.scala 
b/tests/src/test/scala/apigw/healthtests/ApiGwRestEndToEndTests.scala
new file mode 100644
index 0000000000..279da3cc09
--- /dev/null
+++ b/tests/src/test/scala/apigw/healthtests/ApiGwRestEndToEndTests.scala
@@ -0,0 +1,93 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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 apigw.healthtests
+
+import java.io.BufferedWriter
+import java.io.File
+import java.io.FileWriter
+
+import akka.http.scaladsl.model.StatusCodes.OK
+
+import org.junit.runner.RunWith
+import org.scalatest.junit.JUnitRunner
+
+import common.TestUtils._
+import common.rest.WskRest
+import common.rest.RestResult
+
+@RunWith(classOf[JUnitRunner])
+class ApiGwRestEndToEndTests extends ApiGwEndToEndTests {
+
+  override lazy val wsk: common.rest.WskRest = new WskRest
+  override val createCode: Int = OK.intValue
+
+  override def verifyAPICreated(rr: RunResult): Unit = {
+    val apiResultRest = rr.asInstanceOf[RestResult]
+    apiResultRest.statusCode shouldBe OK
+    val apiurl = apiResultRest.getField("gwApiUrl") + "/path"
+    println(s"apiurl: '$apiurl'")
+  }
+
+  override def verifyAPIList(rr: RunResult,
+                             actionName: String,
+                             testurlop: String,
+                             testapiname: String,
+                             testbasepath: String,
+                             testrelpath: String): Unit = {
+    val apiResultRest = rr.asInstanceOf[RestResult]
+    val apiValue = 
RestResult.getFieldJsObject(apiResultRest.getFieldListJsObject("apis")(0), 
"value")
+    val apidoc = RestResult.getFieldJsObject(apiValue, "apidoc")
+    val basepath = RestResult.getField(apidoc, "basePath")
+    basepath shouldBe testbasepath
+
+    val paths = RestResult.getFieldJsObject(apidoc, "paths")
+    paths.fields.contains(testrelpath) shouldBe true
+
+    val info = RestResult.getFieldJsObject(apidoc, "info")
+    val title = RestResult.getField(info, "title")
+    title shouldBe testapiname
+
+    val relpath = RestResult.getFieldJsObject(paths, testrelpath)
+    val urlop = RestResult.getFieldJsObject(relpath, testurlop)
+    val openwhisk = RestResult.getFieldJsObject(urlop, "x-openwhisk")
+    val actionN = RestResult.getField(openwhisk, "action")
+    actionN shouldBe actionName
+  }
+
+  override def verifyAPISwaggerCreated(rr: RunResult): Unit = {
+    val apiResultRest = rr.asInstanceOf[RestResult]
+    apiResultRest.statusCode shouldBe OK
+  }
+
+  override def writeSwaggerFile(rr: RunResult): File = {
+    val swaggerfile = File.createTempFile("api", ".json")
+    swaggerfile.deleteOnExit()
+    val bw = new BufferedWriter(new FileWriter(swaggerfile))
+    val apiResultRest = rr.asInstanceOf[RestResult]
+    val apiValue = 
RestResult.getFieldJsObject(apiResultRest.getFieldListJsObject("apis")(0), 
"value")
+    val apidoc = RestResult.getFieldJsObject(apiValue, "apidoc")
+    bw.write(apidoc.toString())
+    bw.close()
+    return swaggerfile
+  }
+
+  override def getSwaggerApiUrl(rr: RunResult): String = {
+    val apiResultRest = rr.asInstanceOf[RestResult]
+    return apiResultRest.getField("gwApiUrl") + "/path"
+  }
+}
diff --git a/tests/src/test/scala/common/rest/WskRest.scala 
b/tests/src/test/scala/common/rest/WskRest.scala
index 71551a65f4..0ae28f93a5 100644
--- a/tests/src/test/scala/common/rest/WskRest.scala
+++ b/tests/src/test/scala/common/rest/WskRest.scala
@@ -190,8 +190,8 @@ trait DeleteFromCollectionRest extends 
BaseDeleteFromCollection {
    * @param expectedExitCode (optional) the expected exit code for the command
    * if the code is anything but DONTCARE_EXIT, assert the code is as expected
    */
-  override def delete(entity: String, expectedExitCode: Int = 
OK.intValue)(implicit wp: WskProps): RestResult = {
-    val (ns, entityName) = getNamespaceEntityName(entity)
+  override def delete(name: String, expectedExitCode: Int = 
OK.intValue)(implicit wp: WskProps): RestResult = {
+    val (ns, entityName) = getNamespaceEntityName(name)
     val path = Path(s"$basePath/namespaces/$ns/$noun/$entityName")
     val resp = requestEntity(DELETE, path)(wp)
     val r = new RestResult(resp.status, getRespData(resp))
@@ -482,7 +482,7 @@ class WskRestTrigger
       var body: Map[String, JsValue] = Map(
         "lifecycleEvent" -> "CREATE".toJson,
         "triggerName" -> s"/$ns/$triggerName".toJson,
-        "authKey" -> s"${getAuthKey(wp)}".toJson)
+        "authKey" -> s"${wp.authKey}".toJson)
       body = body ++ parameters
       val resp = requestEntity(POST, path, paramMap, 
Some(body.toJson.toString()))
       val resultInvoke = new RestResult(resp.status, getRespData(resp))
@@ -971,11 +971,10 @@ class WskRestApi extends RunWskRestCmd with BaseApi {
     val r = action match {
       case Some(action) => {
         val (ns, actionName) = this.getNamespaceEntityName(action)
-        val actionUrl = 
s"${WhiskProperties.getApiHostForAction}/$basePath/web/$ns/default/$actionName.http"
-        val actionAuthKey = this.getAuthKey(wp)
+        val actionUrl = 
s"${WhiskProperties.getApiHostForAction}$basePath/web/$ns/default/$actionName.http"
+        val actionAuthKey = wp.authKey
         val testaction = Some(
-          ApiAction(name = actionName, namespace = ns, backendUrl = actionUrl, 
authkey = actionAuthKey))
-
+          new ApiAction(name = actionName, namespace = ns, backendUrl = 
actionUrl, authkey = actionAuthKey))
         val parms = Map[String, JsValue]() ++ { Map("namespace" -> ns.toJson) 
} ++ {
           basepath map { b =>
             Map("gatewayBasePath" -> b.toJson)
@@ -1003,14 +1002,16 @@ class WskRestApi extends RunWskRestCmd with BaseApi {
           } getOrElse Map[String, JsValue]()
         }
 
-        val parm = Map[String, JsValue]("apidoc" -> JsObject(parms)) ++ { 
Map("__ow_user" -> ns.toJson) } ++ {
+        val spaceguid = if (wp.authKey.contains(":")) wp.authKey.split(":")(0) 
else wp.authKey
+
+        val parm = Map[String, JsValue]("apidoc" -> JsObject(parms)) ++ {
           responsetype map { r =>
             Map("responsetype" -> r.toJson)
           } getOrElse Map[String, JsValue]()
         } ++ {
           Map("accesstoken" -> wp.authKey.toJson)
         } ++ {
-          Map("spaceguid" -> wp.authKey.split(":")(0).toJson)
+          Map("spaceguid" -> spaceguid.toJson)
         }
 
         invokeAction(
@@ -1018,10 +1019,44 @@ class WskRestApi extends RunWskRestCmd with BaseApi {
           parameters = parm,
           blocking = true,
           result = true,
+          web = true,
           expectedExitCode = expectedExitCode)(wp)
       }
       case None => {
-        new RestResult(NotFound)
+        swagger match {
+          case Some(swaggerFile) => {
+            var file = ""
+            val fileName = swaggerFile.toString()
+            try {
+              file = FileUtils.readFileToString(new File(fileName))
+            } catch {
+              case e: Throwable =>
+                return new RestResult(
+                  NotFound,
+                  JsObject("error" -> s"Error reading swagger file 
'$fileName'".toJson).toString())
+            }
+            val parms = Map("namespace" -> s"${wp.namespace}".toJson, 
"swagger" -> file.toJson)
+            val parm = Map[String, JsValue]("apidoc" -> JsObject(parms)) ++ {
+              responsetype map { r =>
+                Map("responsetype" -> r.toJson)
+              } getOrElse Map[String, JsValue]()
+            } ++ {
+              Map("accesstoken" -> wp.authKey.toJson)
+            } ++ {
+              Map("spaceguid" -> wp.authKey.split(":")(0).toJson)
+            }
+            invokeAction(
+              name = "apimgmt/createApi",
+              parameters = parm,
+              blocking = true,
+              result = true,
+              web = true,
+              expectedExitCode = expectedExitCode)(wp)
+          }
+          case None => {
+            new RestResult(NotFound)
+          }
+        }
       }
     }
     r
@@ -1043,8 +1078,7 @@ class WskRestApi extends RunWskRestCmd with BaseApi {
                     expectedExitCode: Int = SUCCESS_EXIT,
                     cliCfgFile: Option[String] = None)(implicit wp: WskProps): 
RestResult = {
 
-    val parms = Map[String, JsValue]() ++
-      Map("__ow_user" -> wp.namespace.toJson) ++ {
+    val parms = Map[String, JsValue]() ++ {
       basepathOrApiName map { b =>
         Map("basepath" -> b.toJson)
       } getOrElse Map[String, JsValue]()
@@ -1061,11 +1095,13 @@ class WskRestApi extends RunWskRestCmd with BaseApi {
     } ++ {
       Map("spaceguid" -> wp.authKey.split(":")(0).toJson)
     }
+
     val rr = invokeAction(
       name = "apimgmt/getApi",
       parameters = parms,
       blocking = true,
       result = true,
+      web = true,
       expectedExitCode = OK.intValue)(wp)
     rr
   }
@@ -1082,8 +1118,7 @@ class WskRestApi extends RunWskRestCmd with BaseApi {
                    expectedExitCode: Int = SUCCESS_EXIT,
                    cliCfgFile: Option[String] = None,
                    format: Option[String] = None)(implicit wp: WskProps): 
RestResult = {
-    val parms = Map[String, JsValue]() ++
-      Map("__ow_user" -> wp.namespace.toJson) ++ {
+    val parms = Map[String, JsValue]() ++ {
       basepathOrApiName map { b =>
         Map("basepath" -> b.toJson)
       } getOrElse Map[String, JsValue]()
@@ -1098,6 +1133,7 @@ class WskRestApi extends RunWskRestCmd with BaseApi {
       parameters = parms,
       blocking = true,
       result = true,
+      web = true,
       expectedExitCode = OK.intValue)(wp)
     result
   }
@@ -1113,7 +1149,7 @@ class WskRestApi extends RunWskRestCmd with BaseApi {
                       operation: Option[String] = None,
                       expectedExitCode: Int = SUCCESS_EXIT,
                       cliCfgFile: Option[String] = None)(implicit wp: 
WskProps): RestResult = {
-    val parms = Map[String, JsValue]() ++ { Map("__ow_user" -> 
wp.namespace.toJson) } ++ {
+    val parms = Map[String, JsValue]() ++ {
       Map("basepath" -> basepathOrApiName.toJson)
     } ++ {
       relpath map { r =>
@@ -1134,18 +1170,10 @@ class WskRestApi extends RunWskRestCmd with BaseApi {
       parameters = parms,
       blocking = true,
       result = true,
+      web = true,
       expectedExitCode = expectedExitCode)(wp)
     return rr
   }
-
-  def getApi(basepathOrApiName: String, params: Map[String, String] = Map(), 
expectedExitCode: Int = OK.intValue)(
-    implicit wp: WskProps): RestResult = {
-    val whiskUrl = Uri(WhiskProperties.getApiHostForAction)
-    val path = Path(s"/api/${wp.authKey.split(":")(0)}$basepathOrApiName/path")
-    val resp = requestEntity(GET, path, params, whiskUrl = whiskUrl)
-    val result = new RestResult(resp.status, getRespData(resp))
-    result
-  }
 }
 
 class RunWskRestCmd() extends FlatSpec with RunWskCmd with Matchers with 
ScalaFutures with WskActorSystem {
@@ -1155,6 +1183,7 @@ class RunWskRestCmd() extends FlatSpec with RunWskCmd 
with Matchers with ScalaFu
   val queueSize = 10
   val maxOpenRequest = 1024
   val basePath = Path("/api/v1")
+  val systemNamespace = "whisk.system"
 
   val sslConfig = AkkaSSLConfig().mapSettings { s =>
     
s.withHostnameVerifierClass(classOf[AcceptAllHostNameVerifier].asInstanceOf[Class[HostnameVerifier]])
@@ -1239,11 +1268,6 @@ class RunWskRestCmd() extends FlatSpec with RunWskCmd 
with Matchers with ScalaFu
     }
   }
 
-  def getAuthKey(wp: WskProps): String = {
-    val authKey = wp.authKey.split(":")
-    s"${authKey(0)}:${authKey(1)}"
-  }
-
   def getParamsAnnos(parameters: Map[String, JsValue] = Map(),
                      annotations: Map[String, JsValue] = Map(),
                      parameterFile: Option[String] = None,
@@ -1345,9 +1369,12 @@ class RunWskRestCmd() extends FlatSpec with RunWskCmd 
with Matchers with ScalaFu
                    parameterFile: Option[String] = None,
                    blocking: Boolean = false,
                    result: Boolean = false,
+                   web: Boolean = false,
                    expectedExitCode: Int = Accepted.intValue)(implicit wp: 
WskProps): RestResult = {
     val (ns, actName) = this.getNamespaceEntityName(name)
-    val path = Path(s"$basePath/namespaces/$ns/actions/$actName")
+    val path =
+      if (web) Path(s"$basePath/web/$systemNamespace/$actName.http")
+      else Path(s"$basePath/namespaces/$ns/actions/$actName")
     var paramMap = Map("blocking" -> blocking.toString, "result" -> 
result.toString)
     val input = parameterFile map { pf =>
       Some(FileUtils.readFileToString(new File(pf)))
@@ -1496,11 +1523,11 @@ class RestResult(var statusCode: StatusCode, var 
respData: String = "", blocking
   }
 }
 
-case class ApiAction(name: String,
-                     namespace: String,
-                     backendMethod: String = "POST",
-                     backendUrl: String,
-                     authkey: String) {
+class ApiAction(var name: String,
+                var namespace: String,
+                var backendMethod: String = "POST",
+                var backendUrl: String,
+                var authkey: String) {
   def toJson(): JsObject = {
     return JsObject(
       "name" -> name.toJson,
diff --git 
a/tests/src/test/scala/whisk/core/apigw/actions/test/ApiGwCliRoutemgmtActionTests.scala
 
b/tests/src/test/scala/whisk/core/apigw/actions/test/ApiGwCliRoutemgmtActionTests.scala
new file mode 100644
index 0000000000..4f0f131632
--- /dev/null
+++ 
b/tests/src/test/scala/whisk/core/apigw/actions/test/ApiGwCliRoutemgmtActionTests.scala
@@ -0,0 +1,28 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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.apigw.actions.test
+
+import org.junit.runner.RunWith
+import org.scalatest.junit.JUnitRunner
+
+import common.Wsk
+
+@RunWith(classOf[JUnitRunner])
+class ApiGwCliRoutemgmtActionTests extends ApiGwRoutemgmtActionTests {
+  override lazy val wsk = new Wsk
+}
diff --git 
a/tests/src/test/scala/whisk/core/apigw/actions/test/ApiGwRestRoutemgmtActionTests.scala
 
b/tests/src/test/scala/whisk/core/apigw/actions/test/ApiGwRestRoutemgmtActionTests.scala
new file mode 100644
index 0000000000..aff8072144
--- /dev/null
+++ 
b/tests/src/test/scala/whisk/core/apigw/actions/test/ApiGwRestRoutemgmtActionTests.scala
@@ -0,0 +1,31 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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.apigw.actions.test
+
+import org.junit.runner.RunWith
+import org.scalatest.junit.JUnitRunner
+
+import common.rest.WskRest
+
+/**
+ * Tests for basic CLI usage. Some of these tests require a deployed backend.
+ */
+@RunWith(classOf[JUnitRunner])
+class ApiGwRestRoutemgmtActionTests extends ApiGwRoutemgmtActionTests {
+  override lazy val wsk = new WskRest
+}
diff --git 
a/tests/src/test/scala/whisk/core/apigw/actions/test/ApiGwRoutemgmtActionTests.scala
 
b/tests/src/test/scala/whisk/core/apigw/actions/test/ApiGwRoutemgmtActionTests.scala
index fa56de62a0..57449e6931 100644
--- 
a/tests/src/test/scala/whisk/core/apigw/actions/test/ApiGwRoutemgmtActionTests.scala
+++ 
b/tests/src/test/scala/whisk/core/apigw/actions/test/ApiGwRoutemgmtActionTests.scala
@@ -24,38 +24,23 @@ import org.scalatest.junit.JUnitRunner
 import common.JsHelpers
 import common.StreamLogging
 import common.TestHelpers
-import common.TestUtils.ANY_ERROR_EXIT
 import common.TestUtils.DONTCARE_EXIT
 import common.TestUtils.RunResult
 import common.TestUtils.SUCCESS_EXIT
-import common.Wsk
+import common.BaseWsk
 import common.WskActorSystem
 import common.WskAdmin
 import common.WskProps
+import common.rest.ApiAction
 import common.WskTestHelpers
 import spray.json._
 import spray.json.DefaultJsonProtocol._
 
-case class ApiAction(name: String,
-                     namespace: String,
-                     backendMethod: String = "POST",
-                     backendUrl: String,
-                     authkey: String) {
-  def toJson(): JsObject = {
-    return JsObject(
-      "name" -> name.toJson,
-      "namespace" -> namespace.toJson,
-      "backendMethod" -> backendMethod.toJson,
-      "backendUrl" -> backendUrl.toJson,
-      "authkey" -> authkey.toJson)
-  }
-}
-
 /**
  * Tests for basic CLI usage. Some of these tests require a deployed backend.
  */
 @RunWith(classOf[JUnitRunner])
-class ApiGwRoutemgmtActionTests
+abstract class ApiGwRoutemgmtActionTests
     extends TestHelpers
     with BeforeAndAfterAll
     with WskActorSystem
@@ -65,7 +50,7 @@ class ApiGwRoutemgmtActionTests
 
   val systemId = "whisk.system"
   implicit val wskprops = WskProps(authKey = 
WskAdmin.listKeys(systemId)(0)._1, namespace = systemId)
-  val wsk = new Wsk
+  val wsk: BaseWsk
 
   def getApis(bpOrName: Option[String],
               relpath: Option[String] = None,
@@ -299,7 +284,7 @@ class ApiGwRoutemgmtActionTests
     val actionUrl = "https://some.whisk.host/api/v1/web/"; + actionNamespace + 
"/default/" + actionName + ".json"
     val actionAuthKey = testName + "_authkey"
     val testaction =
-      ApiAction(name = actionName, namespace = actionNamespace, backendUrl = 
actionUrl, authkey = actionAuthKey)
+      new ApiAction(name = actionName, namespace = actionNamespace, backendUrl 
= actionUrl, authkey = actionAuthKey)
 
     try {
       val createResult = createApi(
@@ -330,7 +315,7 @@ class ApiGwRoutemgmtActionTests
     val actionUrl = "https://some.whisk.host/api/v1/web/"; + actionNamespace + 
"/default/" + actionName + ".json"
     val actionAuthKey = testName + "_authkey"
     val testaction =
-      ApiAction(name = actionName, namespace = actionNamespace, backendUrl = 
actionUrl, authkey = actionAuthKey)
+      new ApiAction(name = actionName, namespace = actionNamespace, backendUrl 
= actionUrl, authkey = actionAuthKey)
 
     try {
       val createResult = createApi(
@@ -366,7 +351,7 @@ class ApiGwRoutemgmtActionTests
     val actionUrl = "https://some.whisk.host/api/v1/web/"; + actionNamespace + 
"/default/" + actionName + ".json"
     val actionAuthKey = testName + "_authkey"
     val testaction =
-      ApiAction(name = actionName, namespace = actionNamespace, backendUrl = 
actionUrl, authkey = actionAuthKey)
+      new ApiAction(name = actionName, namespace = actionNamespace, backendUrl 
= actionUrl, authkey = actionAuthKey)
 
     try {
       var createResult = createApi(
@@ -393,202 +378,4 @@ class ApiGwRoutemgmtActionTests
         deleteApi(namespace = Some(wskprops.namespace), basepath = 
Some(testbasepath), expectedExitCode = DONTCARE_EXIT)
     }
   }
-
-  it should "reject apimgmt actions that are invoked with not enough 
parameters" in {
-    val invalidArgs = Seq(
-      //getApi
-      ("/whisk.system/apimgmt/getApi", ANY_ERROR_EXIT, "Invalid 
authentication.", Seq()),
-      //deleteApi
-      (
-        "/whisk.system/apimgmt/deleteApi",
-        ANY_ERROR_EXIT,
-        "Invalid authentication.",
-        Seq("-p", "basepath", "/ApiGwRoutemgmtActionTests_bp")),
-      (
-        "/whisk.system/apimgmt/deleteApi",
-        ANY_ERROR_EXIT,
-        "basepath is required",
-        Seq("-p", "__ow_user", "_", "-p", "accesstoken", "TOKEN")),
-      (
-        "/whisk.system/apimgmt/deleteApi",
-        ANY_ERROR_EXIT,
-        "When specifying an operation, the path is required",
-        Seq(
-          "-p",
-          "__ow_user",
-          "_",
-          "-p",
-          "accesstoken",
-          "TOKEN",
-          "-p",
-          "basepath",
-          "/ApiGwRoutemgmtActionTests_bp",
-          "-p",
-          "operation",
-          "get")),
-      //createApi
-      (
-        "/whisk.system/apimgmt/createApi",
-        ANY_ERROR_EXIT,
-        "apidoc is required",
-        Seq("-p", "__ow_user", "_", "-p", "accesstoken", "TOKEN")),
-      (
-        "/whisk.system/apimgmt/createApi",
-        ANY_ERROR_EXIT,
-        "apidoc is missing the namespace field",
-        Seq("-p", "__ow_user", "_", "-p", "accesstoken", "TOKEN", "-p", 
"apidoc", "{}")),
-      (
-        "/whisk.system/apimgmt/createApi",
-        ANY_ERROR_EXIT,
-        "apidoc is missing the gatewayBasePath field",
-        Seq("-p", "__ow_user", "_", "-p", "accesstoken", "TOKEN", "-p", 
"apidoc", """{"namespace":"_"}""")),
-      (
-        "/whisk.system/apimgmt/createApi",
-        ANY_ERROR_EXIT,
-        "apidoc is missing the gatewayPath field",
-        Seq(
-          "-p",
-          "__ow_user",
-          "_",
-          "-p",
-          "accesstoken",
-          "TOKEN",
-          "-p",
-          "apidoc",
-          
"""{"namespace":"_","gatewayBasePath":"/ApiGwRoutemgmtActionTests_bp"}""")),
-      (
-        "/whisk.system/apimgmt/createApi",
-        ANY_ERROR_EXIT,
-        "apidoc is missing the gatewayMethod field",
-        Seq(
-          "-p",
-          "__ow_user",
-          "_",
-          "-p",
-          "accesstoken",
-          "TOKEN",
-          "-p",
-          "apidoc",
-          
"""{"namespace":"_","gatewayBasePath":"/ApiGwRoutemgmtActionTests_bp","gatewayPath":"ApiGwRoutemgmtActionTests_rp"}""")),
-      (
-        "/whisk.system/apimgmt/createApi",
-        ANY_ERROR_EXIT,
-        "apidoc is missing the action field",
-        Seq(
-          "-p",
-          "__ow_user",
-          "_",
-          "-p",
-          "accesstoken",
-          "TOKEN",
-          "-p",
-          "apidoc",
-          
"""{"namespace":"_","gatewayBasePath":"/ApiGwRoutemgmtActionTests_bp","gatewayPath":"ApiGwRoutemgmtActionTests_rp","gatewayMethod":"get"}""")),
-      (
-        "/whisk.system/apimgmt/createApi",
-        ANY_ERROR_EXIT,
-        "action is missing the backendMethod field",
-        Seq(
-          "-p",
-          "__ow_user",
-          "_",
-          "-p",
-          "accesstoken",
-          "TOKEN",
-          "-p",
-          "apidoc",
-          
"""{"namespace":"_","gatewayBasePath":"/ApiGwRoutemgmtActionTests_bp","gatewayPath":"ApiGwRoutemgmtActionTests_rp","gatewayMethod":"get","action":{}}""")),
-      (
-        "/whisk.system/apimgmt/createApi",
-        ANY_ERROR_EXIT,
-        "action is missing the backendUrl field",
-        Seq(
-          "-p",
-          "__ow_user",
-          "_",
-          "-p",
-          "accesstoken",
-          "TOKEN",
-          "-p",
-          "apidoc",
-          
"""{"namespace":"_","gatewayBasePath":"/ApiGwRoutemgmtActionTests_bp","gatewayPath":"ApiGwRoutemgmtActionTests_rp","gatewayMethod":"get","action":{"backendMethod":"post"}}""")),
-      (
-        "/whisk.system/apimgmt/createApi",
-        ANY_ERROR_EXIT,
-        "action is missing the namespace field",
-        Seq(
-          "-p",
-          "__ow_user",
-          "_",
-          "-p",
-          "accesstoken",
-          "TOKEN",
-          "-p",
-          "apidoc",
-          
"""{"namespace":"_","gatewayBasePath":"/ApiGwRoutemgmtActionTests_bp","gatewayPath":"ApiGwRoutemgmtActionTests_rp","gatewayMethod":"get","action":{"backendMethod":"post","backendUrl":"URL"}}""")),
-      (
-        "/whisk.system/apimgmt/createApi",
-        ANY_ERROR_EXIT,
-        "action is missing the name field",
-        Seq(
-          "-p",
-          "__ow_user",
-          "_",
-          "-p",
-          "accesstoken",
-          "TOKEN",
-          "-p",
-          "apidoc",
-          
"""{"namespace":"_","gatewayBasePath":"/ApiGwRoutemgmtActionTests_bp","gatewayPath":"ApiGwRoutemgmtActionTests_rp","gatewayMethod":"get","action":{"backendMethod":"post","backendUrl":"URL","namespace":"_"}}""")),
-      (
-        "/whisk.system/apimgmt/createApi",
-        ANY_ERROR_EXIT,
-        "action is missing the authkey field",
-        Seq(
-          "-p",
-          "__ow_user",
-          "_",
-          "-p",
-          "accesstoken",
-          "TOKEN",
-          "-p",
-          "apidoc",
-          
"""{"namespace":"_","gatewayBasePath":"/ApiGwRoutemgmtActionTests_bp","gatewayPath":"ApiGwRoutemgmtActionTests_rp","gatewayMethod":"get","action":{"backendMethod":"post","backendUrl":"URL","namespace":"_","name":"N"}}""")),
-      (
-        "/whisk.system/apimgmt/createApi",
-        ANY_ERROR_EXIT,
-        "swagger and gatewayBasePath are mutually exclusive and cannot be 
specified together",
-        Seq(
-          "-p",
-          "__ow_user",
-          "_",
-          "-p",
-          "accesstoken",
-          "TOKEN",
-          "-p",
-          "apidoc",
-          
"""{"namespace":"_","gatewayBasePath":"/ApiGwRoutemgmtActionTests_bp","gatewayPath":"ApiGwRoutemgmtActionTests_rp","gatewayMethod":"get","action":{"backendMethod":"post","backendUrl":"URL","namespace":"_","name":"N","authkey":"XXXX"},"swagger":{}}""")),
-      (
-        "/whisk.system/apimgmt/createApi",
-        ANY_ERROR_EXIT,
-        "apidoc field cannot be parsed. Ensure it is valid JSON",
-        Seq("-p", "__ow_user", "_", "-p", "accesstoken", "TOKEN", "-p", 
"apidoc", "{1:[}}}")))
-
-    invalidArgs foreach {
-      case (action: String, exitcode: Int, errmsg: String, params: 
Seq[String]) =>
-        val cmd: Seq[String] = Seq(
-          "action",
-          "invoke",
-          action,
-          "-i",
-          "-b",
-          "-r",
-          "--apihost",
-          wskprops.apihost,
-          "--auth",
-          wskprops.authKey) ++ params
-        val rr = wsk.cli(cmd, expectedExitCode = exitcode)
-        rr.stderr should include regex (errmsg)
-    }
-  }
 }
diff --git a/tests/src/test/scala/whisk/core/cli/test/ApiGwCliTests.scala 
b/tests/src/test/scala/whisk/core/cli/test/ApiGwCliTests.scala
new file mode 100644
index 0000000000..ba886c0f0b
--- /dev/null
+++ b/tests/src/test/scala/whisk/core/cli/test/ApiGwCliTests.scala
@@ -0,0 +1,33 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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 common.Wsk
+import common.TestUtils.SUCCESS_EXIT
+
+/**
+ * Tests for basic CLI usage. Some of these tests require a deployed backend.
+ */
+@RunWith(classOf[JUnitRunner])
+class ApiGwCliTests extends ApiGwTests {
+  override lazy val wsk: common.Wsk = new Wsk
+  override lazy val createCode = SUCCESS_EXIT
+}
diff --git a/tests/src/test/scala/whisk/core/cli/test/ApiGwRestTests.scala 
b/tests/src/test/scala/whisk/core/cli/test/ApiGwRestTests.scala
new file mode 100644
index 0000000000..88099537f8
--- /dev/null
+++ b/tests/src/test/scala/whisk/core/cli/test/ApiGwRestTests.scala
@@ -0,0 +1,248 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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 akka.http.scaladsl.model.StatusCodes.OK
+
+import org.junit.runner.RunWith
+import org.scalatest.junit.JUnitRunner
+import spray.json.JsObject
+
+import common.rest.WskRest
+import common.rest.RestResult
+import common.TestUtils.RunResult
+
+/**
+ * Tests for testing the CLI "api" subcommand.  Most of these tests require a 
deployed backend.
+ */
+@RunWith(classOf[JUnitRunner])
+class ApiGwRestTests extends ApiGwTests {
+  override lazy val wsk = new WskRest
+  override lazy val createCode = OK.intValue
+
+  override def verifyBadCommands(rr: RunResult, badpath: String): Unit = {
+    val apiResultRest = rr.asInstanceOf[RestResult]
+    val error = RestResult.getField(apiResultRest.respBody, "error")
+    error should include("Error: Resource path must begin with '/'.")
+  }
+
+  override def verifyBadCommandsDelete(rr: RunResult, badpath: String): Unit = 
{
+    val apiResultRest = rr.asInstanceOf[RestResult]
+    val error = RestResult.getField(apiResultRest.respBody, "error")
+    error should include(s"API deletion failure: API '/basepath' does not 
exist")
+  }
+
+  override def verifyBadCommandsList(rr: RunResult, badpath: String): Unit = {
+    val apiResultRest = rr.asInstanceOf[RestResult]
+    val apis = apiResultRest.getFieldListJsObject("apis")
+    apis.size shouldBe 0
+  }
+
+  override def verifyInvalidCommands(rr: RunResult, badverb: String): Unit = {
+    val apiResultRest = rr.asInstanceOf[RestResult]
+    val error = apiResultRest.getField("error")
+    error should include(s"Error: Resource verb '${badverb}' not supported")
+  }
+
+  override def verifyInvalidCommandsDelete(rr: RunResult, badverb: String): 
Unit = {
+    verifyBadCommandsDelete(rr, badverb)
+  }
+
+  override def verifyInvalidCommandsList(rr: RunResult, badverb: String): Unit 
= {
+    verifyBadCommandsList(rr, badverb)
+  }
+
+  override def verifyNonJsonSwagger(rr: RunResult, filename: String): Unit = {
+    val apiResultRest = rr.asInstanceOf[RestResult]
+    val error = apiResultRest.getField("error")
+    error should include(s"swagger field cannot be parsed. Ensure it is valid 
JSON")
+  }
+
+  override def verifyMissingField(rr: RunResult): Unit = {
+    val apiResultRest = rr.asInstanceOf[RestResult]
+    val error = apiResultRest.getField("error")
+    error should include(s"swagger is missing the basePath field.")
+  }
+
+  override def verifyApiCreated(rr: RunResult): Unit = {
+    val apiResultRest = rr.asInstanceOf[RestResult]
+    apiResultRest.statusCode shouldBe OK
+  }
+
+  def verifyList(rr: RunResult,
+                 namespace: String,
+                 actionName: String,
+                 testurlop: String,
+                 testbasepath: String,
+                 testrelpath: String,
+                 testapiname: String,
+                 newEndpoint: String = ""): Unit = {
+    val apiResultRest = rr.asInstanceOf[RestResult]
+    val apiValue = 
RestResult.getFieldJsObject(apiResultRest.getFieldListJsObject("apis")(0), 
"value")
+    val apidoc = RestResult.getFieldJsObject(apiValue, "apidoc")
+    val basepath = RestResult.getField(apidoc, "basePath")
+    basepath shouldBe testbasepath
+
+    val paths = RestResult.getFieldJsObject(apidoc, "paths")
+    paths.fields.contains(testrelpath) shouldBe true
+
+    val info = RestResult.getFieldJsObject(apidoc, "info")
+    val title = RestResult.getField(info, "title")
+    title shouldBe testapiname
+
+    verifyPaths(paths, testrelpath, testurlop, actionName, namespace)
+
+    if (newEndpoint != "") {
+      verifyPaths(paths, newEndpoint, testurlop, actionName, namespace)
+    }
+  }
+
+  def verifyPaths(paths: JsObject,
+                  testrelpath: String,
+                  testurlop: String,
+                  actionName: String,
+                  namespace: String = "") = {
+    val relpath = RestResult.getFieldJsObject(paths, testrelpath)
+    val urlop = RestResult.getFieldJsObject(relpath, testurlop)
+    val openwhisk = RestResult.getFieldJsObject(urlop, "x-openwhisk")
+    val actionN = RestResult.getField(openwhisk, "action")
+    actionN shouldBe actionName
+
+    if (namespace != "") {
+      val namespaceS = RestResult.getField(openwhisk, "namespace")
+      namespaceS shouldBe namespace
+    }
+  }
+
+  override def verifyApiList(rr: RunResult,
+                             clinamespace: String,
+                             actionName: String,
+                             testurlop: String,
+                             testbasepath: String,
+                             testrelpath: String,
+                             testapiname: String): Unit = {
+    verifyList(rr, clinamespace, actionName, testurlop, testbasepath, 
testrelpath, testapiname)
+  }
+
+  override def verifyApiGet(rr: RunResult): Unit = {
+    rr.stdout should include regex 
(s""""operationId":"getPathWithSub_pathsInIt"""")
+  }
+
+  override def verifyApiFullList(rr: RunResult,
+                                 clinamespace: String,
+                                 actionName: String,
+                                 testurlop: String,
+                                 testbasepath: String,
+                                 testrelpath: String,
+                                 testapiname: String): Unit = {
+    verifyList(rr, clinamespace, actionName, testurlop, testbasepath, 
testrelpath, testapiname)
+  }
+
+  override def verifyApiFullListDouble(rr: RunResult,
+                                       clinamespace: String,
+                                       actionName: String,
+                                       testurlop: String,
+                                       testbasepath: String,
+                                       testrelpath: String,
+                                       testapiname: String,
+                                       newEndpoint: String): Unit = {
+    verifyList(rr, clinamespace, actionName, testurlop, testbasepath, 
testrelpath, testapiname, newEndpoint)
+  }
+
+  override def verifyApiDeleted(rr: RunResult): Unit = {
+    val apiResultRest = rr.asInstanceOf[RestResult]
+    apiResultRest.statusCode shouldBe OK
+  }
+
+  override def verifyApiDeletedRelpath(rr: RunResult,
+                                       testrelpath: String,
+                                       testbasepath: String,
+                                       op: String = ""): Unit = {
+    verifyApiDeleted(rr)
+  }
+
+  override def verifyApiNameGet(rr: RunResult,
+                                testbasepath: String,
+                                actionName: String,
+                                responseType: String = "json"): Unit = {
+    val apiResultRest = rr.asInstanceOf[RestResult]
+
+    val apiValue = 
RestResult.getFieldJsObject(apiResultRest.getFieldListJsObject("apis")(0), 
"value")
+    val apidoc = RestResult.getFieldJsObject(apiValue, "apidoc")
+
+    val config = RestResult.getFieldJsObject(apidoc, "x-ibm-configuration")
+
+    val cors = RestResult.getFieldJsObject(config, "cors")
+    val enabled = RestResult.getFieldJsValue(cors, "enabled").toString()
+    enabled shouldBe "true"
+
+    val basepath = RestResult.getField(apidoc, "basePath")
+    basepath shouldBe testbasepath
+
+    val paths = RestResult.getFieldJsObject(apidoc, "paths")
+    val relpath = RestResult.getFieldJsObject(paths, "/path")
+    val urlop = RestResult.getFieldJsObject(relpath, "get")
+    val openwhisk = RestResult.getFieldJsObject(urlop, "x-openwhisk")
+    val actionN = RestResult.getField(openwhisk, "action")
+    actionN shouldBe actionName
+    rr.stdout should include regex 
(s""""target-url":".*${actionName}.${responseType}"""")
+  }
+
+  override def verifyInvalidSwagger(rr: RunResult): Unit = {
+    verifyMissingField(rr)
+  }
+
+  override def verifyApiOp(rr: RunResult, testurlop: String, testapiname: 
String): Unit = {
+    val apiResultRest = rr.asInstanceOf[RestResult]
+    val apiValue = 
RestResult.getFieldJsObject(apiResultRest.getFieldListJsObject("apis")(0), 
"value")
+    val apidoc = RestResult.getFieldJsObject(apiValue, "apidoc")
+    val info = RestResult.getFieldJsObject(apidoc, "info")
+    val title = RestResult.getField(info, "title")
+    title shouldBe testapiname
+    val paths = RestResult.getFieldJsObject(apidoc, "paths")
+    val relpath = RestResult.getFieldJsObject(paths, "/")
+    val urlop = RestResult.getFieldJsObject(relpath, testurlop)
+    relpath.fields.contains(testurlop) shouldBe true
+  }
+
+  override def verifyApiBaseRelPath(rr: RunResult, testbasepath: String, 
testrelpath: String): Unit = {
+    val apiResultRest = rr.asInstanceOf[RestResult]
+    val apiValue = 
RestResult.getFieldJsObject(apiResultRest.getFieldListJsObject("apis")(0), 
"value")
+    val apidoc = RestResult.getFieldJsObject(apiValue, "apidoc")
+    val basepath = RestResult.getField(apidoc, "basePath")
+    basepath shouldBe testbasepath
+
+    val paths = RestResult.getFieldJsObject(apidoc, "paths")
+    paths.fields.contains(testrelpath) shouldBe true
+  }
+
+  override def verifyApiOpVerb(rr: RunResult, testurlop: String): Unit = {
+    val apiResultRest = rr.asInstanceOf[RestResult]
+    val apiValue = 
RestResult.getFieldJsObject(apiResultRest.getFieldListJsObject("apis")(0), 
"value")
+    val apidoc = RestResult.getFieldJsObject(apiValue, "apidoc")
+    val paths = RestResult.getFieldJsObject(apidoc, "paths")
+    val relpath = RestResult.getFieldJsObject(paths, "/")
+    val urlop = RestResult.getFieldJsObject(relpath, testurlop)
+    relpath.fields.contains(testurlop) shouldBe true
+  }
+
+  override def verifyInvalidKey(rr: RunResult): Unit = {
+    rr.stderr should include("A valid auth key is required")
+  }
+
+}
diff --git a/tests/src/test/scala/whisk/core/cli/test/ApiGwTests.scala 
b/tests/src/test/scala/whisk/core/cli/test/ApiGwTests.scala
index 9f152b08e5..145ea6bb00 100644
--- a/tests/src/test/scala/whisk/core/cli/test/ApiGwTests.scala
+++ b/tests/src/test/scala/whisk/core/cli/test/ApiGwTests.scala
@@ -20,149 +20,147 @@ package whisk.core.cli.test
 import java.io.File
 import java.io.BufferedWriter
 import java.io.FileWriter
-import java.time.Instant
-
-import scala.collection.mutable.ArrayBuffer
-import scala.concurrent.duration._
 
 import org.junit.runner.RunWith
 
-import org.scalatest.BeforeAndAfterAll
-import org.scalatest.BeforeAndAfterEach
 import org.scalatest.junit.JUnitRunner
 
-import common.TestHelpers
 import common.TestUtils._
 import common.TestUtils
-import common.WhiskProperties
-import common.Wsk
 import common.WskProps
-import common.WskTestHelpers
 
 /**
  * Tests for testing the CLI "api" subcommand.  Most of these tests require a 
deployed backend.
  */
 @RunWith(classOf[JUnitRunner])
-class ApiGwTests extends TestHelpers with WskTestHelpers with 
BeforeAndAfterEach with BeforeAndAfterAll {
+abstract class ApiGwTests extends BaseApiGwTests {
 
-  implicit val wskprops = WskProps()
-  val wsk = new Wsk
   val clinamespace = wsk.namespace.whois()
+  val createCode: Int
 
-  // This test suite makes enough CLI invocations in 60 seconds to trigger the 
OpenWhisk
-  // throttling restriction.  To avoid CLI failures due to being throttled, 
track the
-  // CLI invocation calls and when at the throttle limit, pause the next CLI 
invocation
-  // with exactly enough time to relax the throttling.
-  val maxActionsPerMin = WhiskProperties.getMaxActionInvokesPerMinute()
-  val invocationTimes = new ArrayBuffer[Instant]()
-
-  // Custom CLI properties file
-  val cliWskPropsFile = File.createTempFile("wskprops", ".tmp")
-
-  /**
-   * Expected to be called before each test.
-   * Assumes that each test will not invoke more than 5 actions and
-   * settle the throttle when there isn't enough capacity to handle the test.
-   */
-  def checkThrottle(maxInvocationsBeforeThrottle: Int = maxActionsPerMin, 
expectedActivationsPerTest: Int = 5) = {
-    val t = Instant.now
-    val tminus60 = t.minusSeconds(60)
-    val invocationsLast60Seconds = 
invocationTimes.filter(_.isAfter(tminus60)).sorted
-    val invocationCount = invocationsLast60Seconds.length
-    println(s"Action invokes within last minute: ${invocationCount}")
-
-    if (invocationCount >= maxInvocationsBeforeThrottle) {
-      // Instead of waiting a fixed 60 seconds to settle the throttle,
-      // calculate a wait time that will clear out about half of the
-      // current invocations (assuming even distribution) from the
-      // next 60 second period.
-      val oldestInvocationInLast60Seconds = invocationsLast60Seconds.head
-
-      // Take the oldest invocation time in this 60 second period.  To clear
-      // this invocation from the next 60 second period, the wait time will be
-      // (60sec - oldest invocation's delta time away from the period end).
-      // This will clear all of the invocations from the next period at the
-      // expense of potentially waiting uncessarily long. Instead, this 
calculation
-      // halves the delta time as a compromise.
-      val throttleTime = 60.seconds.toMillis - ((t.toEpochMilli - 
oldestInvocationInLast60Seconds.toEpochMilli) / 2)
-      println(s"Waiting ${throttleTime} milliseconds to settle the throttle")
-      Thread.sleep(throttleTime)
-    }
+  def verifyBadCommands(rr: RunResult, badpath: String): Unit = {
+    rr.stderr should include(s"'${badpath}' must begin with '/'")
+  }
+
+  def verifyBadCommandsDelete(rr: RunResult, badpath: String): Unit = {
+    verifyBadCommands(rr, badpath)
+  }
+
+  def verifyBadCommandsList(rr: RunResult, badpath: String): Unit = {
+    verifyBadCommands(rr, badpath)
+  }
+
+  def verifyInvalidCommands(rr: RunResult, badverb: String): Unit = {
+    rr.stderr should include(s"'${badverb}' is not a valid API verb.  Valid 
values are:")
+  }
+
+  def verifyInvalidCommandsDelete(rr: RunResult, badverb: String): Unit = {
+    verifyInvalidCommands(rr, badverb)
+  }
+
+  def verifyInvalidCommandsList(rr: RunResult, badverb: String): Unit = {
+    verifyInvalidCommands(rr, badverb)
+  }
+
+  def verifyNonJsonSwagger(rr: RunResult, filename: String): Unit = {
+    rr.stderr should include(s"Error parsing swagger file '${filename}':")
+  }
+
+  def verifyMissingField(rr: RunResult): Unit = {
+    rr.stderr should include(s"Swagger file is invalid (missing basePath, 
info, paths, or swagger fields")
+  }
+
+  def verifyApiCreated(rr: RunResult): Unit = {
+    rr.stdout should include("ok: created API")
+  }
 
-    invocationTimes += Instant.now
+  def verifyApiList(rr: RunResult,
+                    clinamespace: String,
+                    actionName: String,
+                    testurlop: String,
+                    testbasepath: String,
+                    testrelpath: String,
+                    testapiname: String): Unit = {
+    rr.stdout should include("ok: APIs")
+    rr.stdout should include regex 
(s"Action:\\s+/${clinamespace}/${actionName}\n")
+    rr.stdout should include regex (s"Verb:\\s+${testurlop}\n")
+    rr.stdout should include regex (s"Base path:\\s+${testbasepath}\n")
+    rr.stdout should include regex (s"Path:\\s+${testrelpath}\n")
+    rr.stdout should include regex (s"API Name:\\s+${testapiname}\n")
+    rr.stdout should include regex (s"URL:\\s+")
+    rr.stdout should include(testbasepath + testrelpath)
   }
 
-  override def beforeEach() = {
-    //checkThrottle()
+  def verifyApiBaseRelPath(rr: RunResult, testbasepath: String, testrelpath: 
String): Unit = {
+    rr.stdout should include(testbasepath + testrelpath)
   }
 
-  /*
-   * Create a CLI properties file for use by the tests
-   */
-  override def beforeAll() = {
-    cliWskPropsFile.deleteOnExit()
-    val wskprops = WskProps(token = "SOME TOKEN")
-    wskprops.writeFile(cliWskPropsFile)
-    println(s"wsk temporary props file created here: 
${cliWskPropsFile.getCanonicalPath()}")
+  def verifyApiGet(rr: RunResult): Unit = {
+    rr.stdout should include regex 
(s""""operationId":\\s+"getPathWithSub_pathsInIt"""")
   }
 
-  /*
-   * Forcibly clear the throttle so that downstream tests are not affected by
-   * this test suite
-   */
-  override def afterAll() = {
-    // Check and settle the throttle so that this test won't cause issues with 
and follow on tests
-    checkThrottle(30)
+  def verifyApiFullList(rr: RunResult,
+                        clinamespace: String,
+                        actionName: String,
+                        testurlop: String,
+                        testbasepath: String,
+                        testrelpath: String,
+                        testapiname: String): Unit = {
+
+    rr.stdout should include("ok: APIs")
+    if (clinamespace == "") {
+      rr.stdout should include regex 
(s"/[@\\w._\\-]+/${actionName}\\s+${testurlop}\\s+${testapiname}\\s+")
+    } else {
+      rr.stdout should include regex 
(s"/${clinamespace}/${actionName}\\s+${testurlop}\\s+${testapiname}\\s+")
+    }
+    rr.stdout should include(testbasepath + testrelpath)
+
+  }
+
+  def verifyApiFullListDouble(rr: RunResult,
+                              clinamespace: String,
+                              actionName: String,
+                              testurlop: String,
+                              testbasepath: String,
+                              testrelpath: String,
+                              testapiname: String,
+                              newEndpoint: String): Unit = {
+    verifyApiFullList(rr, clinamespace, actionName, testurlop, testbasepath, 
testrelpath, testapiname)
+    rr.stdout should include(testbasepath + newEndpoint)
+  }
+
+  def verifyApiDeleted(rr: RunResult): Unit = {
+    rr.stdout should include("ok: deleted API")
   }
 
-  def apiCreate(basepath: Option[String] = None,
-                relpath: Option[String] = None,
-                operation: Option[String] = None,
-                action: Option[String] = None,
-                apiname: Option[String] = None,
-                swagger: Option[String] = None,
-                responsetype: Option[String] = None,
-                expectedExitCode: Int = SUCCESS_EXIT,
-                cliCfgFile: Option[String] = 
Some(cliWskPropsFile.getCanonicalPath()))(
-    implicit wskpropsOverride: WskProps): RunResult = {
-
-    checkThrottle()
-    wsk.api.create(basepath, relpath, operation, action, apiname, swagger, 
responsetype, expectedExitCode, cliCfgFile)(
-      wskpropsOverride)
+  def verifyApiDeletedRelpath(rr: RunResult, testrelpath: String, 
testbasepath: String, op: String = ""): Unit = {
+    if (op != "")
+      rr.stdout should include("ok: deleted " + testrelpath + " " + 
op.toUpperCase() + " from " + testbasepath)
+    else
+      rr.stdout should include("ok: deleted " + testrelpath + " from " + 
testbasepath)
   }
 
-  def apiList(basepathOrApiName: Option[String] = None,
-              relpath: Option[String] = None,
-              operation: Option[String] = None,
-              limit: Option[Int] = None,
-              since: Option[Instant] = None,
-              full: Option[Boolean] = None,
-              nameSort: Option[Boolean] = None,
-              expectedExitCode: Int = SUCCESS_EXIT,
-              cliCfgFile: Option[String] = 
Some(cliWskPropsFile.getCanonicalPath())): RunResult = {
-
-    checkThrottle()
-    wsk.api.list(basepathOrApiName, relpath, operation, limit, since, full, 
nameSort, expectedExitCode, cliCfgFile)
+  def verifyApiNameGet(rr: RunResult, testbasepath: String, actionName: 
String, responseType: String = "json"): Unit = {
+    rr.stdout should include(testbasepath)
+    rr.stdout should include(s"${actionName}")
+    rr.stdout should include regex 
(""""cors":\s*\{\s*\n\s*"enabled":\s*true""")
+    rr.stdout should include regex 
(s""""target-url":\\s+.*${actionName}.${responseType}""")
   }
 
-  def apiGet(basepathOrApiName: Option[String] = None,
-             full: Option[Boolean] = None,
-             expectedExitCode: Int = SUCCESS_EXIT,
-             cliCfgFile: Option[String] = 
Some(cliWskPropsFile.getCanonicalPath()),
-             format: Option[String] = None): RunResult = {
+  def verifyInvalidSwagger(rr: RunResult): Unit = {
+    rr.stderr should include(s"Swagger file is invalid")
+  }
 
-    checkThrottle()
-    wsk.api.get(basepathOrApiName, full, expectedExitCode, cliCfgFile, format)
+  def verifyApiOp(rr: RunResult, testurlop: String, testapiname: String): Unit 
= {
+    rr.stdout should include regex (s"\\s+${testurlop}\\s+${testapiname}\\s+")
   }
 
-  def apiDelete(basepathOrApiName: String,
-                relpath: Option[String] = None,
-                operation: Option[String] = None,
-                expectedExitCode: Int = SUCCESS_EXIT,
-                cliCfgFile: Option[String] = 
Some(cliWskPropsFile.getCanonicalPath())): RunResult = {
+  def verifyApiOpVerb(rr: RunResult, testurlop: String): Unit = {
+    rr.stdout should include regex (s"Verb:\\s+${testurlop}")
+  }
 
-    checkThrottle()
-    wsk.api.delete(basepathOrApiName, relpath, operation, expectedExitCode, 
cliCfgFile)
+  def verifyInvalidKey(rr: RunResult): Unit = {
+    rr.stderr should include("The supplied authentication is invalid")
   }
 
   behavior of "Wsk api"
@@ -176,21 +174,21 @@ class ApiGwTests extends TestHelpers with WskTestHelpers 
with BeforeAndAfterEach
       operation = Some("GET"),
       action = Some("action"),
       expectedExitCode = ANY_ERROR_EXIT)
-    rr.stderr should include(s"'${badpath}' must begin with '/'")
+    verifyBadCommands(rr, badpath)
 
     rr = apiDelete(
       basepathOrApiName = "/basepath",
       relpath = Some(badpath),
       operation = Some("GET"),
       expectedExitCode = ANY_ERROR_EXIT)
-    rr.stderr should include(s"'${badpath}' must begin with '/'")
+    verifyBadCommandsDelete(rr, badpath)
 
     rr = apiList(
       basepathOrApiName = Some("/basepath"),
       relpath = Some(badpath),
       operation = Some("GET"),
       expectedExitCode = ANY_ERROR_EXIT)
-    rr.stderr should include(s"'${badpath}' must begin with '/'")
+    verifyBadCommandsList(rr, badpath)
   }
 
   it should "reject an api commands with an invalid verb parameter" in {
@@ -202,28 +200,28 @@ class ApiGwTests extends TestHelpers with WskTestHelpers 
with BeforeAndAfterEach
       operation = Some(badverb),
       action = Some("action"),
       expectedExitCode = ANY_ERROR_EXIT)
-    rr.stderr should include(s"'${badverb}' is not a valid API verb.  Valid 
values are:")
+    verifyInvalidCommands(rr, badverb)
 
     rr = apiDelete(
       basepathOrApiName = "/basepath",
       relpath = Some("/path"),
       operation = Some(badverb),
       expectedExitCode = ANY_ERROR_EXIT)
-    rr.stderr should include(s"'${badverb}' is not a valid API verb.  Valid 
values are:")
+    verifyInvalidCommandsDelete(rr, badverb)
 
     rr = apiList(
       basepathOrApiName = Some("/basepath"),
       relpath = Some("/path"),
       operation = Some(badverb),
       expectedExitCode = ANY_ERROR_EXIT)
-    rr.stderr should include(s"'${badverb}' is not a valid API verb.  Valid 
values are:")
+    verifyInvalidCommandsList(rr, badverb)
   }
 
   it should "reject an api create command that specifies a nonexistent 
configuration file" in {
     val configfile = "/nonexistent/file"
 
     val rr = apiCreate(swagger = Some(configfile), expectedExitCode = 
ANY_ERROR_EXIT)
-    rr.stderr should include(s"Error reading swagger file '${configfile}':")
+    rr.stderr should include(s"Error reading swagger file '${configfile}'")
   }
 
   it should "reject an api create command specifying a non-JSON configuration 
file" in {
@@ -236,7 +234,7 @@ class ApiGwTests extends TestHelpers with WskTestHelpers 
with BeforeAndAfterEach
     bw.close()
 
     val rr = apiCreate(swagger = Some(filename), expectedExitCode = 
ANY_ERROR_EXIT)
-    rr.stderr should include(s"Error parsing swagger file '${filename}':")
+    verifyNonJsonSwagger(rr, filename)
   }
 
   it should "reject an api create command specifying a non-swagger JSON 
configuration file" in {
@@ -261,7 +259,7 @@ class ApiGwTests extends TestHelpers with WskTestHelpers 
with BeforeAndAfterEach
     bw.close()
 
     val rr = apiCreate(swagger = Some(filename), expectedExitCode = 
ANY_ERROR_EXIT)
-    rr.stderr should include(s"Swagger file is invalid (missing basePath, 
info, paths, or swagger fields")
+    verifyMissingField(rr)
   }
 
   it should "verify full list output" in {
@@ -276,7 +274,7 @@ class ApiGwTests extends TestHelpers with WskTestHelpers 
with BeforeAndAfterEach
       println("cli namespace: " + clinamespace)
       // Create the action for the API.  It must be a "web-action" action.
       val file = TestUtils.getTestActionFilename(s"echo.js")
-      wsk.action.create(name = actionName, artifact = Some(file), 
expectedExitCode = SUCCESS_EXIT, web = Some("true"))
+      wsk.action.create(name = actionName, artifact = Some(file), 
expectedExitCode = createCode, web = Some("true"))
 
       var rr = apiCreate(
         basepath = Some(testbasepath),
@@ -285,21 +283,14 @@ class ApiGwTests extends TestHelpers with WskTestHelpers 
with BeforeAndAfterEach
         action = Some(actionName),
         apiname = Some(testapiname))
       println("api create: " + rr.stdout)
-      rr.stdout should include("ok: created API")
+      verifyApiCreated(rr)
       rr = apiList(
         basepathOrApiName = Some(testbasepath),
         relpath = Some(testrelpath),
         operation = Some(testurlop),
         full = Some(true))
       println("api list: " + rr.stdout)
-      rr.stdout should include("ok: APIs")
-      rr.stdout should include regex 
(s"Action:\\s+/${clinamespace}/${actionName}\n")
-      rr.stdout should include regex (s"Verb:\\s+${testurlop}\n")
-      rr.stdout should include regex (s"Base path:\\s+${testbasepath}\n")
-      rr.stdout should include regex (s"Path:\\s+${testrelpath}\n")
-      rr.stdout should include regex (s"API Name:\\s+${testapiname}\n")
-      rr.stdout should include regex (s"URL:\\s+")
-      rr.stdout should include(testbasepath + testrelpath)
+      verifyApiList(rr, clinamespace, actionName, testurlop, testbasepath, 
testrelpath, testapiname)
     } finally {
       wsk.action.delete(name = actionName, expectedExitCode = DONTCARE_EXIT)
       apiDelete(basepathOrApiName = testbasepath)
@@ -319,7 +310,7 @@ class ApiGwTests extends TestHelpers with WskTestHelpers 
with BeforeAndAfterEach
 
       // Create the action for the API.  It must be a "web-action" action.
       val file = TestUtils.getTestActionFilename(s"echo.js")
-      wsk.action.create(name = actionName, artifact = Some(file), 
expectedExitCode = SUCCESS_EXIT, web = Some("true"))
+      wsk.action.create(name = actionName, artifact = Some(file), 
expectedExitCode = createCode, web = Some("true"))
 
       var rr = apiCreate(
         basepath = Some(testbasepath),
@@ -327,15 +318,13 @@ class ApiGwTests extends TestHelpers with WskTestHelpers 
with BeforeAndAfterEach
         operation = Some(testurlop),
         action = Some(actionName),
         apiname = Some(testapiname))
-      rr.stdout should include("ok: created API")
+      verifyApiCreated(rr)
       rr = apiList(basepathOrApiName = Some(testbasepath), relpath = 
Some(testrelpath), operation = Some(testurlop))
-      rr.stdout should include("ok: APIs")
-      rr.stdout should include regex 
(s"/${clinamespace}/${actionName}\\s+${testurlop}\\s+${testapiname}\\s+")
-      rr.stdout should include(testbasepath + testrelpath)
+      verifyApiFullList(rr, clinamespace, actionName, testurlop, testbasepath, 
testrelpath, testapiname)
       rr = apiGet(basepathOrApiName = Some(testbasepath))
-      rr.stdout should include regex 
(s""""operationId":\\s+"getPathWithSub_pathsInIt"""")
+      verifyApiGet(rr)
       val deleteresult = apiDelete(basepathOrApiName = testbasepath)
-      deleteresult.stdout should include("ok: deleted API")
+      verifyApiDeleted(deleteresult)
     } finally {
       wsk.action.delete(name = actionName, expectedExitCode = DONTCARE_EXIT)
       apiDelete(basepathOrApiName = testbasepath, expectedExitCode = 
DONTCARE_EXIT)
@@ -353,7 +342,7 @@ class ApiGwTests extends TestHelpers with WskTestHelpers 
with BeforeAndAfterEach
     try {
       // Create the action for the API.  It must be a "web-action" action.
       val file = TestUtils.getTestActionFilename(s"echo.js")
-      wsk.action.create(name = actionName, artifact = Some(file), 
expectedExitCode = SUCCESS_EXIT, web = Some("true"))
+      wsk.action.create(name = actionName, artifact = Some(file), 
expectedExitCode = createCode, web = Some("true"))
 
       var rr = apiCreate(
         basepath = Some(testbasepath),
@@ -361,12 +350,9 @@ class ApiGwTests extends TestHelpers with WskTestHelpers 
with BeforeAndAfterEach
         operation = Some(testurlop),
         action = Some(actionName),
         apiname = Some(testapiname))
-      rr.stdout should include("ok: created API")
+      verifyApiCreated(rr)
       rr = apiGet(basepathOrApiName = Some(testapiname))
-      rr.stdout should include(testbasepath)
-      rr.stdout should include(s"${actionName}")
-      rr.stdout should include regex 
(""""cors":\s*\{\s*\n\s*"enabled":\s*true""")
-      rr.stdout should include regex 
(s""""target-url":\\s+.*${actionName}.json""")
+      verifyApiNameGet(rr, testbasepath, actionName)
     } finally {
       wsk.action.delete(name = actionName, expectedExitCode = DONTCARE_EXIT)
       apiDelete(basepathOrApiName = testbasepath, expectedExitCode = 
DONTCARE_EXIT)
@@ -384,7 +370,7 @@ class ApiGwTests extends TestHelpers with WskTestHelpers 
with BeforeAndAfterEach
     try {
       // Create the action for the API.  It must be a "web-action" action.
       val file = TestUtils.getTestActionFilename(s"echo.js")
-      wsk.action.create(name = actionName, artifact = Some(file), 
expectedExitCode = SUCCESS_EXIT, web = Some("true"))
+      wsk.action.create(name = actionName, artifact = Some(file), 
expectedExitCode = createCode, web = Some("true"))
 
       var rr = apiCreate(
         basepath = Some(testbasepath),
@@ -392,9 +378,9 @@ class ApiGwTests extends TestHelpers with WskTestHelpers 
with BeforeAndAfterEach
         operation = Some(testurlop),
         action = Some(actionName),
         apiname = Some(testapiname))
-      rr.stdout should include("ok: created API")
+      verifyApiCreated(rr)
       rr = apiDelete(basepathOrApiName = testapiname)
-      rr.stdout should include("ok: deleted API")
+      verifyApiDeleted(rr)
     } finally {
       wsk.action.delete(name = actionName, expectedExitCode = DONTCARE_EXIT)
       apiDelete(basepathOrApiName = testbasepath, expectedExitCode = 
DONTCARE_EXIT)
@@ -412,7 +398,7 @@ class ApiGwTests extends TestHelpers with WskTestHelpers 
with BeforeAndAfterEach
     try {
       // Create the action for the API.  It must be a "web-action" action.
       val file = TestUtils.getTestActionFilename(s"echo.js")
-      wsk.action.create(name = actionName, artifact = Some(file), 
expectedExitCode = SUCCESS_EXIT, web = Some("true"))
+      wsk.action.create(name = actionName, artifact = Some(file), 
expectedExitCode = createCode, web = Some("true"))
 
       var rr = apiCreate(
         basepath = Some(testbasepath),
@@ -420,9 +406,9 @@ class ApiGwTests extends TestHelpers with WskTestHelpers 
with BeforeAndAfterEach
         operation = Some(testurlop),
         action = Some(actionName),
         apiname = Some(testapiname))
-      rr.stdout should include("ok: created API")
+      verifyApiCreated(rr)
       rr = apiDelete(basepathOrApiName = testbasepath)
-      rr.stdout should include("ok: deleted API")
+      verifyApiDeleted(rr)
     } finally {
       wsk.action.delete(name = actionName, expectedExitCode = DONTCARE_EXIT)
       apiDelete(basepathOrApiName = testbasepath, expectedExitCode = 
DONTCARE_EXIT)
@@ -441,7 +427,7 @@ class ApiGwTests extends TestHelpers with WskTestHelpers 
with BeforeAndAfterEach
     try {
       // Create the action for the API.  It must be a "web-action" action.
       val file = TestUtils.getTestActionFilename(s"echo.js")
-      wsk.action.create(name = actionName, artifact = Some(file), 
expectedExitCode = SUCCESS_EXIT, web = Some("true"))
+      wsk.action.create(name = actionName, artifact = Some(file), 
expectedExitCode = createCode, web = Some("true"))
 
       var rr = apiCreate(
         basepath = Some(testbasepath),
@@ -449,19 +435,24 @@ class ApiGwTests extends TestHelpers with WskTestHelpers 
with BeforeAndAfterEach
         operation = Some(testurlop),
         action = Some(actionName),
         apiname = Some(testapiname))
-      rr.stdout should include("ok: created API")
+      verifyApiCreated(rr)
       rr = apiCreate(
         basepath = Some(testbasepath),
         relpath = Some(newEndpoint),
         operation = Some(testurlop),
         action = Some(actionName),
         apiname = Some(testapiname))
-      rr.stdout should include("ok: created API")
+      verifyApiCreated(rr)
       rr = apiList(basepathOrApiName = Some(testbasepath))
-      rr.stdout should include("ok: APIs")
-      rr.stdout should include regex 
(s"/${clinamespace}/${actionName}\\s+${testurlop}\\s+${testapiname}\\s+")
-      rr.stdout should include(testbasepath + testrelpath)
-      rr.stdout should include(testbasepath + newEndpoint)
+      verifyApiFullListDouble(
+        rr,
+        clinamespace,
+        actionName,
+        testurlop,
+        testbasepath,
+        newEndpoint,
+        testapiname,
+        newEndpoint)
     } finally {
       wsk.action.delete(name = actionName, expectedExitCode = DONTCARE_EXIT)
       apiDelete(basepathOrApiName = testbasepath, expectedExitCode = 
DONTCARE_EXIT)
@@ -479,14 +470,12 @@ class ApiGwTests extends TestHelpers with WskTestHelpers 
with BeforeAndAfterEach
     val swaggerPath = TestUtils.getTestApiGwFilename("testswaggerdoc1")
     try {
       var rr = apiCreate(swagger = Some(swaggerPath))
-      rr.stdout should include("ok: created API")
+      verifyApiCreated(rr)
       rr = apiList(basepathOrApiName = Some(testbasepath), relpath = 
Some(testrelpath), operation = Some(testurlop))
       println("list stdout: " + rr.stdout)
       println("list stderr: " + rr.stderr)
-      rr.stdout should include("ok: APIs")
-      // Actual CLI namespace will vary from local dev to automated test 
environments, so don't check
-      rr.stdout should include regex 
(s"/[@\\w._\\-]+/${actionName}\\s+${testurlop}\\s+${testapiname}\\s+")
-      rr.stdout should include(testbasepath + testrelpath)
+      verifyApiFullList(rr, "", actionName, testurlop, testbasepath, 
testrelpath, testapiname)
+
     } finally {
       apiDelete(basepathOrApiName = testbasepath, expectedExitCode = 
DONTCARE_EXIT)
     }
@@ -506,7 +495,7 @@ class ApiGwTests extends TestHelpers with WskTestHelpers 
with BeforeAndAfterEach
     try {
       // Create the action for the API.  It must be a "web-action" action.
       val file = TestUtils.getTestActionFilename(s"echo.js")
-      wsk.action.create(name = actionName, artifact = Some(file), 
expectedExitCode = SUCCESS_EXIT, web = Some("true"))
+      wsk.action.create(name = actionName, artifact = Some(file), 
expectedExitCode = createCode, web = Some("true"))
 
       var rr = apiCreate(
         basepath = Some(testbasepath),
@@ -514,14 +503,14 @@ class ApiGwTests extends TestHelpers with WskTestHelpers 
with BeforeAndAfterEach
         operation = Some(testurlop),
         action = Some(actionName),
         apiname = Some(testapiname))
-      rr.stdout should include("ok: created API")
+      verifyApiCreated(rr)
       rr = apiCreate(
         basepath = Some(testbasepath2),
         relpath = Some(testrelpath),
         operation = Some(testurlop),
         action = Some(actionName),
         apiname = Some(testapiname2))
-      rr.stdout should include("ok: created API")
+      verifyApiCreated(rr)
 
       // Update both APIs - each with a new endpoint
       rr = apiCreate(
@@ -529,25 +518,36 @@ class ApiGwTests extends TestHelpers with WskTestHelpers 
with BeforeAndAfterEach
         relpath = Some(newEndpoint),
         operation = Some(testurlop),
         action = Some(actionName))
-      rr.stdout should include("ok: created API")
+      verifyApiCreated(rr)
       rr = apiCreate(
         basepath = Some(testbasepath2),
         relpath = Some(newEndpoint),
         operation = Some(testurlop),
         action = Some(actionName))
-      rr.stdout should include("ok: created API")
+      verifyApiCreated(rr)
 
       rr = apiList(basepathOrApiName = Some(testbasepath))
-      rr.stdout should include("ok: APIs")
-      rr.stdout should include regex 
(s"/${clinamespace}/${actionName}\\s+${testurlop}\\s+${testapiname}\\s+")
-      rr.stdout should include(testbasepath + testrelpath)
-      rr.stdout should include(testbasepath + newEndpoint)
+      verifyApiFullListDouble(
+        rr,
+        clinamespace,
+        actionName,
+        testurlop,
+        testbasepath,
+        testrelpath,
+        testapiname,
+        newEndpoint)
 
       rr = apiList(basepathOrApiName = Some(testbasepath2))
-      rr.stdout should include("ok: APIs")
-      rr.stdout should include regex 
(s"/${clinamespace}/${actionName}\\s+${testurlop}\\s+${testapiname}\\s+")
-      rr.stdout should include(testbasepath2 + testrelpath)
-      rr.stdout should include(testbasepath2 + newEndpoint)
+      verifyApiFullListDouble(
+        rr,
+        clinamespace,
+        actionName,
+        testurlop,
+        testbasepath2,
+        testrelpath,
+        testapiname2,
+        newEndpoint)
+
     } finally {
       wsk.action.delete(name = actionName, expectedExitCode = DONTCARE_EXIT)
       apiDelete(basepathOrApiName = testbasepath, expectedExitCode = 
DONTCARE_EXIT)
@@ -570,7 +570,7 @@ class ApiGwTests extends TestHelpers with WskTestHelpers 
with BeforeAndAfterEach
 
       // Create the action for the API.  It must be a "web-action" action.
       val file = TestUtils.getTestActionFilename(s"echo.js")
-      wsk.action.create(name = actionName, artifact = Some(file), 
expectedExitCode = SUCCESS_EXIT, web = Some("true"))
+      wsk.action.create(name = actionName, artifact = Some(file), 
expectedExitCode = createCode, web = Some("true"))
 
       var rr = apiCreate(
         basepath = Some(testbasepath),
@@ -578,13 +578,11 @@ class ApiGwTests extends TestHelpers with WskTestHelpers 
with BeforeAndAfterEach
         operation = Some(testurlop),
         action = Some(actionName),
         apiname = Some(testapiname))
-      rr.stdout should include("ok: created API")
+      verifyApiCreated(rr)
       rr = apiList(basepathOrApiName = Some(testbasepath), relpath = 
Some(testrelpath), operation = Some(testurlop))
-      rr.stdout should include("ok: APIs")
-      rr.stdout should include regex 
(s"/${clinamespace}/${actionName}\\s+${testurlop}\\s+${testapiname}\\s+")
-      rr.stdout should include(testbasepath + testrelpath)
+      verifyApiFullList(rr, clinamespace, actionName, testurlop, testbasepath, 
testrelpath, testapiname)
       val deleteresult = apiDelete(basepathOrApiName = testbasepath)
-      deleteresult.stdout should include("ok: deleted API")
+      verifyApiDeleted(deleteresult)
     } finally {
       wsk.action.delete(name = actionName, expectedExitCode = DONTCARE_EXIT)
       apiDelete(basepathOrApiName = testbasepath, expectedExitCode = 
DONTCARE_EXIT)
@@ -604,7 +602,7 @@ class ApiGwTests extends TestHelpers with WskTestHelpers 
with BeforeAndAfterEach
       val rr = apiCreate(swagger = Some(swaggerPath), expectedExitCode = 
ANY_ERROR_EXIT)
       println("api create stdout: " + rr.stdout)
       println("api create stderr: " + rr.stderr)
-      rr.stderr should include(s"Swagger file is invalid")
+      verifyInvalidSwagger(rr)
     } finally {
       apiDelete(basepathOrApiName = testbasepath, expectedExitCode = 
DONTCARE_EXIT)
     }
@@ -621,7 +619,7 @@ class ApiGwTests extends TestHelpers with WskTestHelpers 
with BeforeAndAfterEach
     try {
       // Create the action for the API.  It must be a "web-action" action.
       val file = TestUtils.getTestActionFilename(s"echo.js")
-      wsk.action.create(name = actionName, artifact = Some(file), 
expectedExitCode = SUCCESS_EXIT, web = Some("true"))
+      wsk.action.create(name = actionName, artifact = Some(file), 
expectedExitCode = createCode, web = Some("true"))
 
       var rr = apiCreate(
         basepath = Some(testbasepath),
@@ -629,20 +627,18 @@ class ApiGwTests extends TestHelpers with WskTestHelpers 
with BeforeAndAfterEach
         operation = Some(testurlop),
         action = Some(actionName),
         apiname = Some(testapiname))
-      rr.stdout should include("ok: created API")
+      verifyApiCreated(rr)
       var rr2 = apiCreate(
         basepath = Some(testbasepath),
         relpath = Some(testnewrelpath),
         operation = Some(testurlop),
         action = Some(actionName),
         apiname = Some(testapiname))
-      rr2.stdout should include("ok: created API")
+      verifyApiCreated(rr2)
       rr = apiDelete(basepathOrApiName = testbasepath, relpath = 
Some(testrelpath))
-      rr.stdout should include("ok: deleted " + testrelpath + " from " + 
testbasepath)
+      verifyApiDeletedRelpath(rr, testrelpath, testbasepath)
       rr2 = apiList(basepathOrApiName = Some(testbasepath), relpath = 
Some(testnewrelpath))
-      rr2.stdout should include("ok: APIs")
-      rr2.stdout should include regex 
(s"/${clinamespace}/${actionName}\\s+${testurlop}\\s+${testapiname}\\s+")
-      rr2.stdout should include(testbasepath + testnewrelpath)
+      verifyApiFullList(rr2, clinamespace, actionName, testurlop, 
testbasepath, testnewrelpath, testapiname)
     } finally {
       wsk.action.delete(name = actionName, expectedExitCode = DONTCARE_EXIT)
       apiDelete(basepathOrApiName = testbasepath, expectedExitCode = 
DONTCARE_EXIT)
@@ -661,7 +657,7 @@ class ApiGwTests extends TestHelpers with WskTestHelpers 
with BeforeAndAfterEach
     try {
       // Create the action for the API.  It must be a "web-action" action.
       val file = TestUtils.getTestActionFilename(s"echo.js")
-      wsk.action.create(name = actionName, artifact = Some(file), 
expectedExitCode = SUCCESS_EXIT, web = Some("true"))
+      wsk.action.create(name = actionName, artifact = Some(file), 
expectedExitCode = createCode, web = Some("true"))
 
       var rr = apiCreate(
         basepath = Some(testbasepath),
@@ -669,22 +665,22 @@ class ApiGwTests extends TestHelpers with WskTestHelpers 
with BeforeAndAfterEach
         operation = Some(testurlop),
         action = Some(actionName),
         apiname = Some(testapiname))
-      rr.stdout should include("ok: created API")
+      verifyApiCreated(rr)
       rr = apiCreate(
         basepath = Some(testbasepath),
         relpath = Some(testrelpath),
         operation = Some(testurlop2),
         action = Some(actionName),
         apiname = Some(testapiname))
-      rr.stdout should include("ok: created API")
+      verifyApiCreated(rr)
       rr = apiList(basepathOrApiName = Some(testbasepath))
-      rr.stdout should include("ok: APIs")
-      rr.stdout should include regex 
(s"/${clinamespace}/${actionName}\\s+${testurlop}\\s+${testapiname}\\s+")
-      rr.stdout should include(testbasepath + testrelpath)
+      verifyApiFullList(rr, clinamespace, actionName, testurlop, testbasepath, 
testrelpath, testapiname)
+      verifyApiFullList(rr, clinamespace, actionName, testurlop2, 
testbasepath, testrelpath, testapiname)
       rr = apiDelete(basepathOrApiName = testbasepath, relpath = 
Some(testrelpath), operation = Some(testurlop2))
-      rr.stdout should include("ok: deleted " + testrelpath + " " + "POST" + " 
from " + testbasepath)
+      verifyApiDeletedRelpath(rr, testrelpath, testbasepath, testurlop2)
+
       rr = apiList(basepathOrApiName = Some(testbasepath))
-      rr.stdout should include regex 
(s"/${clinamespace}/${actionName}\\s+${testurlop}\\s+${testapiname}\\s+")
+      verifyApiFullList(rr, clinamespace, actionName, testurlop, testbasepath, 
testrelpath, testapiname)
     } finally {
       wsk.action.delete(name = actionName, expectedExitCode = DONTCARE_EXIT)
       apiDelete(basepathOrApiName = testbasepath, expectedExitCode = 
DONTCARE_EXIT)
@@ -697,6 +693,7 @@ class ApiGwTests extends TestHelpers with WskTestHelpers 
with BeforeAndAfterEach
     val testrelpath = "/whisk_system/utils/echo"
     val testrelpath2 = "/whisk_system/utils/split"
     val testurlop = "get"
+    val testurlop2 = "post"
     val testapiname = testName + " API Name"
     val actionName = "test1a"
     val swaggerPath = TestUtils.getTestApiGwFilename(s"testswaggerdoc2")
@@ -704,13 +701,10 @@ class ApiGwTests extends TestHelpers with WskTestHelpers 
with BeforeAndAfterEach
       var rr = apiCreate(swagger = Some(swaggerPath))
       println("api create stdout: " + rr.stdout)
       println("api create stderror: " + rr.stderr)
-      rr.stdout should include("ok: created API")
+      verifyApiCreated(rr)
       rr = apiList(basepathOrApiName = Some(testbasepath))
-      rr.stdout should include("ok: APIs")
-      // Actual CLI namespace will vary from local dev to automated test 
environments, so don't check
-      rr.stdout should include regex 
(s"/[@\\w._\\-]+/${actionName}\\s+${testurlop}\\s+${testapiname}\\s+")
-      rr.stdout should include(testbasepath + testrelpath)
-      rr.stdout should include(testbasepath + testrelpath2)
+      verifyApiFullList(rr, "", actionName, testurlop, testbasepath, 
testrelpath, testapiname)
+      verifyApiFullList(rr, "", actionName, testurlop2, testbasepath, 
testrelpath2, testapiname)
     } finally {
       apiDelete(basepathOrApiName = testbasepath, expectedExitCode = 
DONTCARE_EXIT)
     }
@@ -729,7 +723,7 @@ class ApiGwTests extends TestHelpers with WskTestHelpers 
with BeforeAndAfterEach
     try {
       // Create the action for the API.  It must be a "web-action" action.
       val file = TestUtils.getTestActionFilename(s"echo.js")
-      wsk.action.create(name = actionName, artifact = Some(file), 
expectedExitCode = SUCCESS_EXIT, web = Some("true"))
+      wsk.action.create(name = actionName, artifact = Some(file), 
expectedExitCode = createCode, web = Some("true"))
 
       var rr = apiCreate(
         basepath = Some(testbasepath),
@@ -737,30 +731,24 @@ class ApiGwTests extends TestHelpers with WskTestHelpers 
with BeforeAndAfterEach
         operation = Some(testurlop),
         action = Some(actionName),
         apiname = Some(testapiname))
-      rr.stdout should include("ok: created API")
+      verifyApiCreated(rr)
       rr = apiList(basepathOrApiName = Some(testbasepath), relpath = 
Some(testrelpath), operation = Some(testurlop))
-      rr.stdout should include("ok: APIs")
-      rr.stdout should include regex 
(s"/${clinamespace}/${actionName}\\s+${testurlop}\\s+${testapiname}\\s+")
-      rr.stdout should include(testbasepath + testrelpath)
+      verifyApiFullList(rr, clinamespace, actionName, testurlop, testbasepath, 
testrelpath, testapiname)
       rr = apiCreate(
         basepath = Some(testbasepath2),
         relpath = Some(testrelpath),
         operation = Some(testurlop),
         action = Some(actionName),
         apiname = Some(testapiname2))
-      rr.stdout should include("ok: created API")
+      verifyApiCreated(rr)
       rr = apiList(basepathOrApiName = Some(testbasepath2), relpath = 
Some(testrelpath), operation = Some(testurlop))
-      rr.stdout should include("ok: APIs")
-      rr.stdout should include regex 
(s"/${clinamespace}/${actionName}\\s+${testurlop}\\s+${testapiname}\\s+")
-      rr.stdout should include(testbasepath2 + testrelpath)
+      verifyApiFullList(rr, clinamespace, actionName, testurlop, 
testbasepath2, testrelpath, testapiname2)
       rr = apiDelete(basepathOrApiName = testbasepath2)
-      rr.stdout should include("ok: deleted API")
+      verifyApiDeleted(rr)
       rr = apiList(basepathOrApiName = Some(testbasepath), relpath = 
Some(testrelpath), operation = Some(testurlop))
-      rr.stdout should include("ok: APIs")
-      rr.stdout should include regex 
(s"/${clinamespace}/${actionName}\\s+${testurlop}\\s+${testapiname}\\s+")
-      rr.stdout should include(testbasepath + testrelpath)
+      verifyApiFullList(rr, clinamespace, actionName, testurlop, testbasepath, 
testrelpath, testapiname)
       rr = apiDelete(basepathOrApiName = testbasepath)
-      rr.stdout should include("ok: deleted API")
+      verifyApiDeleted(rr)
     } finally {
       wsk.action.delete(name = actionName, expectedExitCode = DONTCARE_EXIT)
       apiDelete(basepathOrApiName = testbasepath, expectedExitCode = 
DONTCARE_EXIT)
@@ -768,55 +756,6 @@ class ApiGwTests extends TestHelpers with WskTestHelpers 
with BeforeAndAfterEach
     }
   }
 
-  it should "reject an API created with a non-existent action" in {
-    val testName = "CLI_APIGWTEST15"
-    val testbasepath = "/" + testName + "_bp"
-    val testrelpath = "/path"
-    val testnewrelpath = "/path_new"
-    val testurlop = "get"
-    val testapiname = testName + " API Name"
-    val actionName = testName + "_action"
-    try {
-      val rr = apiCreate(
-        basepath = Some(testbasepath),
-        relpath = Some(testrelpath),
-        operation = Some(testurlop),
-        action = Some(actionName),
-        apiname = Some(testapiname),
-        expectedExitCode = ANY_ERROR_EXIT)
-      rr.stderr should include("does not exist")
-    } finally {
-      apiDelete(basepathOrApiName = testbasepath, expectedExitCode = 
DONTCARE_EXIT)
-    }
-  }
-
-  it should "reject an API created with an action that is not a web action" in 
{
-    val testName = "CLI_APIGWTEST16"
-    val testbasepath = "/" + testName + "_bp"
-    val testrelpath = "/path"
-    val testnewrelpath = "/path_new"
-    val testurlop = "get"
-    val testapiname = testName + " API Name"
-    val actionName = testName + "_action"
-    try {
-      // Create the action for the API.  It must NOT be a "web-action" action 
for this test
-      val file = TestUtils.getTestActionFilename(s"echo.js")
-      wsk.action.create(name = actionName, artifact = Some(file), 
expectedExitCode = SUCCESS_EXIT)
-
-      val rr = apiCreate(
-        basepath = Some(testbasepath),
-        relpath = Some(testrelpath),
-        operation = Some(testurlop),
-        action = Some(actionName),
-        apiname = Some(testapiname),
-        expectedExitCode = ANY_ERROR_EXIT)
-      rr.stderr should include("is not a web action")
-    } finally {
-      wsk.action.delete(name = actionName, expectedExitCode = DONTCARE_EXIT)
-      apiDelete(basepathOrApiName = testbasepath, expectedExitCode = 
DONTCARE_EXIT)
-    }
-  }
-
   it should "verify API with http response type " in {
     val testName = "CLI_APIGWTEST17"
     val testbasepath = "/" + testName + "_bp"
@@ -829,133 +768,25 @@ class ApiGwTests extends TestHelpers with WskTestHelpers 
with BeforeAndAfterEach
     try {
       // Create the action for the API.  It must be a "web-action" action.
       val file = TestUtils.getTestActionFilename(s"echo.js")
-      wsk.action.create(name = actionName, artifact = Some(file), 
expectedExitCode = SUCCESS_EXIT, web = Some("true"))
-
-      apiCreate(
-        basepath = Some(testbasepath),
-        relpath = Some(testrelpath),
-        operation = Some(testurlop),
-        action = Some(actionName),
-        apiname = Some(testapiname),
-        responsetype = Some(responseType)).stdout should include("ok: created 
API")
-
-      val rr = apiGet(basepathOrApiName = Some(testapiname))
-      rr.stdout should include(testbasepath)
-      rr.stdout should include(s"${actionName}")
-      rr.stdout should include regex 
(s""""target-url":\\s+.*${actionName}.${responseType}""")
-    } finally {
-      wsk.action.delete(name = actionName, expectedExitCode = DONTCARE_EXIT)
-      apiDelete(basepathOrApiName = testbasepath, expectedExitCode = 
DONTCARE_EXIT)
-    }
-  }
-
-  it should "reject API export when export type is invalid" in {
-    val testName = "CLI_APIGWTEST18"
-    val testbasepath = "/" + testName + "_bp"
-
-    val rr = apiGet(basepathOrApiName = Some(testbasepath), format = 
Some("BadType"), expectedExitCode = ANY_ERROR_EXIT)
-    rr.stderr should include("Invalid format type")
-  }
-
-  it should "successfully export an API in YAML format" in {
-    val testName = "CLI_APIGWTEST19"
-    val testbasepath = "/" + testName + "_bp"
-    val testrelpath = "/path"
-    val testnewrelpath = "/path_new"
-    val testurlop = "get"
-    val testapiname = testName + " API Name"
-    val actionName = testName + "_action"
-    val responseType = "http"
-    try {
-      // Create the action for the API.  It must be a "web-action" action.
-      val file = TestUtils.getTestActionFilename(s"echo.js")
-      wsk.action.create(name = actionName, artifact = Some(file), 
expectedExitCode = SUCCESS_EXIT, web = Some("true"))
+      wsk.action.create(name = actionName, artifact = Some(file), 
expectedExitCode = createCode, web = Some("true"))
 
-      apiCreate(
-        basepath = Some(testbasepath),
-        relpath = Some(testrelpath),
-        operation = Some(testurlop),
-        action = Some(actionName),
-        apiname = Some(testapiname),
-        responsetype = Some(responseType)).stdout should include("ok: created 
API")
-
-      val rr = apiGet(basepathOrApiName = Some(testapiname), format = 
Some("yaml"))
-      rr.stdout should include(s"basePath: ${testbasepath}")
-    } finally {
-      wsk.action.delete(name = actionName, expectedExitCode = DONTCARE_EXIT)
-      apiDelete(basepathOrApiName = testbasepath, expectedExitCode = 
DONTCARE_EXIT)
-    }
-  }
-
-  it should "successfully export an API when JSON format is explcitly 
specified" in {
-    val testName = "CLI_APIGWTEST20"
-    val testbasepath = "/" + testName + "_bp"
-    val testrelpath = "/path"
-    val testnewrelpath = "/path_new"
-    val testurlop = "get"
-    val testapiname = testName + " API Name"
-    val actionName = testName + "_action"
-    val responseType = "http"
-    try {
-      // Create the action for the API.  It must be a "web-action" action.
-      val file = TestUtils.getTestActionFilename(s"echo.js")
-      wsk.action.create(name = actionName, artifact = Some(file), 
expectedExitCode = SUCCESS_EXIT, web = Some("true"))
-
-      apiCreate(
+      var rr = apiCreate(
         basepath = Some(testbasepath),
         relpath = Some(testrelpath),
         operation = Some(testurlop),
         action = Some(actionName),
         apiname = Some(testapiname),
-        responsetype = Some(responseType)).stdout should include("ok: created 
API")
+        responsetype = Some(responseType))
+      verifyApiCreated(rr)
 
-      val rr = apiGet(basepathOrApiName = Some(testapiname), format = 
Some("json"))
-      rr.stdout should include(testbasepath)
-      rr.stdout should include(s"${actionName}")
-      rr.stdout should include regex 
(s""""target-url":\\s+.*${actionName}.${responseType}""")
+      rr = apiGet(basepathOrApiName = Some(testapiname))
+      verifyApiNameGet(rr, testbasepath, actionName, responseType)
     } finally {
       wsk.action.delete(name = actionName, expectedExitCode = DONTCARE_EXIT)
       apiDelete(basepathOrApiName = testbasepath, expectedExitCode = 
DONTCARE_EXIT)
     }
   }
 
-  it should "successfully create an API from a YAML formatted API 
configuration file" in {
-    val testName = "CLI_APIGWTEST21"
-    val testbasepath = "/bp"
-    val testrelpath = "/rp"
-    val testurlop = "get"
-    val testapiname = testbasepath
-    val actionName = "webhttpecho"
-    val swaggerPath = TestUtils.getTestApiGwFilename(s"local.api.yaml")
-    try {
-      var rr = apiCreate(swagger = Some(swaggerPath))
-      println("api create stdout: " + rr.stdout)
-      println("api create stderror: " + rr.stderr)
-      rr.stdout should include("ok: created API")
-      rr = apiList(basepathOrApiName = Some(testbasepath))
-      rr.stdout should include("ok: APIs")
-      // Actual CLI namespace will vary from local dev to automated test 
environments, so don't check
-      rr.stdout should include regex 
(s"/[@\\w._\\-]+/${actionName}\\s+${testurlop}\\s+${testapiname}\\s+")
-      rr.stdout should include(testbasepath + testrelpath)
-    } finally {
-      apiDelete(basepathOrApiName = testbasepath, expectedExitCode = 
DONTCARE_EXIT)
-    }
-  }
-
-  it should "reject creation of an API from invalid YAML formatted API 
configuration file" in {
-    val testName = "CLI_APIGWTEST22"
-    val testbasepath = "/" + testName + "_bp"
-    val swaggerPath = TestUtils.getTestApiGwFilename(s"local.api.bad.yaml")
-    try {
-      val rr = apiCreate(swagger = Some(swaggerPath), expectedExitCode = 
ANY_ERROR_EXIT)
-      println("api create stdout: " + rr.stdout)
-      println("api create stderror: " + rr.stderr)
-      rr.stderr should include("Unable to parse YAML configuration file")
-    } finally {
-      apiDelete(basepathOrApiName = testbasepath, expectedExitCode = 
DONTCARE_EXIT)
-    }
-  }
-
   it should "reject deletion of a non-existent api" in {
     val nonexistentApi = "/not-there"
 
@@ -975,21 +806,21 @@ class ApiGwTests extends TestHelpers with WskTestHelpers 
with BeforeAndAfterEach
       var rr = apiCreate(swagger = Some(swaggerPath))
       println("api create stdout: " + rr.stdout)
       println("api create stderror: " + rr.stderr)
-      rr.stdout should include("ok: created API")
+      this.verifyApiCreated(rr)
 
       rr = apiList(basepathOrApiName = Some(testbasepath))
       println("api list:\n" + rr.stdout)
       testops foreach { testurlop =>
-        rr.stdout should include regex 
(s"\\s+${testurlop}\\s+${testapiname}\\s+")
+        verifyApiOp(rr, testurlop, testapiname)
       }
-      rr.stdout should include(testbasepath + testrelpath)
+      verifyApiBaseRelPath(rr, testbasepath, testrelpath)
 
       rr = apiList(basepathOrApiName = Some(testbasepath), full = Some(true))
       println("api full list:\n" + rr.stdout)
       testops foreach { testurlop =>
-        rr.stdout should include regex (s"Verb:\\s+${testurlop}")
+        verifyApiOpVerb(rr, testurlop)
       }
-      rr.stdout should include(testbasepath + testrelpath)
+      verifyApiBaseRelPath(rr, testbasepath, testrelpath)
 
     } finally {
       apiDelete(basepathOrApiName = testbasepath, expectedExitCode = 
DONTCARE_EXIT)
@@ -1007,58 +838,22 @@ class ApiGwTests extends TestHelpers with WskTestHelpers 
with BeforeAndAfterEach
     try {
       // Create the action for the API.
       val file = TestUtils.getTestActionFilename(s"echo.js")
-      wsk.action.create(name = actionName, artifact = Some(file), 
expectedExitCode = SUCCESS_EXIT, web = Some("true"))
+      wsk.action.create(name = actionName, artifact = Some(file), 
expectedExitCode = createCode, web = Some("true"))
 
       // Set an invalid auth key
       val badWskProps = WskProps(authKey = "bad-auth-key")
 
-      apiCreate(
+      val rr = apiCreate(
         basepath = Some(testbasepath),
         relpath = Some(testrelpath),
         operation = Some(testurlop),
         action = Some(actionName),
         apiname = Some(testapiname),
-        expectedExitCode = ANY_ERROR_EXIT)(badWskProps).stderr should 
include("The supplied authentication is invalid")
+        expectedExitCode = ANY_ERROR_EXIT)(badWskProps)
+      verifyInvalidKey(rr)
     } finally {
       wsk.action.delete(name = actionName, expectedExitCode = DONTCARE_EXIT)
       apiDelete(basepathOrApiName = testbasepath, expectedExitCode = 
DONTCARE_EXIT)
     }
   }
-
-  it should "list api alphabetically by Base/Rel/Verb" in {
-    val baseName = "/BaseTestPathApiList"
-    val actionName = "actionName"
-    val file = TestUtils.getTestActionFilename(s"echo-web-http.js")
-    try {
-      // Create Action for apis
-      var action =
-        wsk.action.create(name = actionName, artifact = Some(file), 
expectedExitCode = SUCCESS_EXIT, web = Some("true"))
-      println("action creation: " + action.stdout)
-      // Create apis
-      for (i <- 1 to 3) {
-        val base = s"$baseName$i"
-        var api = apiCreate(
-          basepath = Some(base),
-          relpath = Some("/relPath"),
-          operation = Some("GET"),
-          action = Some(actionName))
-        println("api creation: " + api.stdout)
-      }
-      val original = apiList(nameSort = Some(true)).stdout
-      val originalFull = apiList(full = Some(true), nameSort = 
Some(true)).stdout
-      val scalaSorted = List(s"${baseName}1" + "/", s"${baseName}2" + "/", 
s"${baseName}3" + "/")
-      val regex = s"${baseName}[1-3]/".r
-      val list = (regex.findAllMatchIn(original)).toList
-      val listFull = (regex.findAllMatchIn(originalFull)).toList
-
-      scalaSorted.toString shouldEqual list.toString
-      scalaSorted.toString shouldEqual listFull.toString
-    } finally {
-      // Clean up Apis
-      for (i <- 1 to 3) {
-        apiDelete(basepathOrApiName = s"${baseName}$i", expectedExitCode = 
DONTCARE_EXIT)
-      }
-      wsk.action.delete(name = actionName, expectedExitCode = DONTCARE_EXIT)
-    }
-  }
 }
diff --git a/tests/src/test/scala/whisk/core/cli/test/BaseApiGwTests.scala 
b/tests/src/test/scala/whisk/core/cli/test/BaseApiGwTests.scala
new file mode 100644
index 0000000000..f55ab797eb
--- /dev/null
+++ b/tests/src/test/scala/whisk/core/cli/test/BaseApiGwTests.scala
@@ -0,0 +1,165 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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 java.io.File
+import java.time.Instant
+
+import scala.collection.mutable.ArrayBuffer
+import scala.concurrent.duration._
+
+import org.junit.runner.RunWith
+
+import org.scalatest.BeforeAndAfterAll
+import org.scalatest.BeforeAndAfterEach
+import org.scalatest.junit.JUnitRunner
+
+import common.TestHelpers
+import common.TestUtils._
+import common.WhiskProperties
+import common.BaseWsk
+import common.WskProps
+import common.WskTestHelpers
+
+/**
+ * Tests for testing the CLI "api" subcommand.  Most of these tests require a 
deployed backend.
+ */
+@RunWith(classOf[JUnitRunner])
+abstract class BaseApiGwTests extends TestHelpers with WskTestHelpers with 
BeforeAndAfterEach with BeforeAndAfterAll {
+
+  implicit val wskprops = WskProps()
+  val wsk: BaseWsk
+
+  // This test suite makes enough CLI invocations in 60 seconds to trigger the 
OpenWhisk
+  // throttling restriction.  To avoid CLI failures due to being throttled, 
track the
+  // CLI invocation calls and when at the throttle limit, pause the next CLI 
invocation
+  // with exactly enough time to relax the throttling.
+  val maxActionsPerMin = WhiskProperties.getMaxActionInvokesPerMinute()
+  val invocationTimes = new ArrayBuffer[Instant]()
+
+  // Custom CLI properties file
+  val cliWskPropsFile = File.createTempFile("wskprops", ".tmp")
+
+  /**
+   * Expected to be called before each test.
+   * Assumes that each test will not invoke more than 5 actions and
+   * settle the throttle when there isn't enough capacity to handle the test.
+   */
+  def checkThrottle(maxInvocationsBeforeThrottle: Int = maxActionsPerMin, 
expectedActivationsPerTest: Int = 5) = {
+    val t = Instant.now
+    val tminus60 = t.minusSeconds(60)
+    val invocationsLast60Seconds = 
invocationTimes.filter(_.isAfter(tminus60)).sorted
+    val invocationCount = invocationsLast60Seconds.length
+    println(s"Action invokes within last minute: ${invocationCount}")
+
+    if (invocationCount >= maxInvocationsBeforeThrottle) {
+      // Instead of waiting a fixed 60 seconds to settle the throttle,
+      // calculate a wait time that will clear out about half of the
+      // current invocations (assuming even distribution) from the
+      // next 60 second period.
+      val oldestInvocationInLast60Seconds = invocationsLast60Seconds.head
+
+      // Take the oldest invocation time in this 60 second period.  To clear
+      // this invocation from the next 60 second period, the wait time will be
+      // (60sec - oldest invocation's delta time away from the period end).
+      // This will clear all of the invocations from the next period at the
+      // expense of potentially waiting uncessarily long. Instead, this 
calculation
+      // halves the delta time as a compromise.
+      val throttleTime = 60.seconds.toMillis - ((t.toEpochMilli - 
oldestInvocationInLast60Seconds.toEpochMilli) / 2)
+      println(s"Waiting ${throttleTime} milliseconds to settle the throttle")
+      Thread.sleep(throttleTime)
+    }
+
+    invocationTimes += Instant.now
+  }
+
+  override def beforeEach() = {
+    //checkThrottle()
+  }
+
+  /*
+   * Create a CLI properties file for use by the tests
+   */
+  override def beforeAll() = {
+    cliWskPropsFile.deleteOnExit()
+    val wskprops = WskProps(token = "SOME TOKEN")
+    wskprops.writeFile(cliWskPropsFile)
+    println(s"wsk temporary props file created here: 
${cliWskPropsFile.getCanonicalPath()}")
+  }
+
+  /*
+   * Forcibly clear the throttle so that downstream tests are not affected by
+   * this test suite
+   */
+  override def afterAll() = {
+    // Check and settle the throttle so that this test won't cause issues with 
and follow on tests
+    checkThrottle(30)
+  }
+
+  def apiCreate(basepath: Option[String] = None,
+                relpath: Option[String] = None,
+                operation: Option[String] = None,
+                action: Option[String] = None,
+                apiname: Option[String] = None,
+                swagger: Option[String] = None,
+                responsetype: Option[String] = None,
+                expectedExitCode: Int = SUCCESS_EXIT,
+                cliCfgFile: Option[String] = 
Some(cliWskPropsFile.getCanonicalPath()))(
+    implicit wskpropsOverride: WskProps): RunResult = {
+
+    println("parmssss is fdasdadasdddddddddsfsd")
+    checkThrottle()
+    println("create is fdasdadasdddddddddsfsd")
+    wsk.api.create(basepath, relpath, operation, action, apiname, swagger, 
responsetype, expectedExitCode, cliCfgFile)(
+      wskpropsOverride)
+  }
+
+  def apiList(basepathOrApiName: Option[String] = None,
+              relpath: Option[String] = None,
+              operation: Option[String] = None,
+              limit: Option[Int] = None,
+              since: Option[Instant] = None,
+              full: Option[Boolean] = None,
+              nameSort: Option[Boolean] = None,
+              expectedExitCode: Int = SUCCESS_EXIT,
+              cliCfgFile: Option[String] = 
Some(cliWskPropsFile.getCanonicalPath())): RunResult = {
+
+    checkThrottle()
+    wsk.api.list(basepathOrApiName, relpath, operation, limit, since, full, 
nameSort, expectedExitCode, cliCfgFile)
+  }
+
+  def apiGet(basepathOrApiName: Option[String] = None,
+             full: Option[Boolean] = None,
+             expectedExitCode: Int = SUCCESS_EXIT,
+             cliCfgFile: Option[String] = 
Some(cliWskPropsFile.getCanonicalPath()),
+             format: Option[String] = None): RunResult = {
+
+    checkThrottle()
+    wsk.api.get(basepathOrApiName, full, expectedExitCode, cliCfgFile, format)
+  }
+
+  def apiDelete(basepathOrApiName: String,
+                relpath: Option[String] = None,
+                operation: Option[String] = None,
+                expectedExitCode: Int = SUCCESS_EXIT,
+                cliCfgFile: Option[String] = 
Some(cliWskPropsFile.getCanonicalPath())): RunResult = {
+
+    checkThrottle()
+    wsk.api.delete(basepathOrApiName, relpath, operation, expectedExitCode, 
cliCfgFile)
+  }
+}
diff --git a/tests/src/test/scala/whisk/core/cli/test/WskCliApiGwTests.scala 
b/tests/src/test/scala/whisk/core/cli/test/WskCliApiGwTests.scala
new file mode 100644
index 0000000000..088b6c5a06
--- /dev/null
+++ b/tests/src/test/scala/whisk/core/cli/test/WskCliApiGwTests.scala
@@ -0,0 +1,438 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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 common.JsHelpers
+import common.StreamLogging
+import common.TestUtils
+import common.TestUtils.ANY_ERROR_EXIT
+import common.TestUtils.DONTCARE_EXIT
+import common.TestUtils.SUCCESS_EXIT
+import common.Wsk
+import common.WskActorSystem
+import common.WskAdmin
+import common.WskProps
+
+/**
+ * Tests for basic CLI usage. Some of these tests require a deployed backend.
+ */
+@RunWith(classOf[JUnitRunner])
+class WskCliApiGwTests extends BaseApiGwTests with WskActorSystem with 
JsHelpers with StreamLogging {
+
+  val systemId: String = "whisk.system"
+  override implicit val wskprops = WskProps(authKey = 
WskAdmin.listKeys(systemId)(0)._1, namespace = systemId)
+  val wsk: common.Wsk = new Wsk
+
+  it should "reject apimgmt actions that are invoked with not enough 
parameters" in {
+    val invalidArgs = Seq(
+      //getApi
+      ("/whisk.system/apimgmt/getApi", ANY_ERROR_EXIT, "Invalid 
authentication.", Seq()),
+      //deleteApi
+      (
+        "/whisk.system/apimgmt/deleteApi",
+        ANY_ERROR_EXIT,
+        "Invalid authentication.",
+        Seq("-p", "basepath", "/ApiGwRoutemgmtActionTests_bp")),
+      (
+        "/whisk.system/apimgmt/deleteApi",
+        ANY_ERROR_EXIT,
+        "basepath is required",
+        Seq("-p", "__ow_user", "_", "-p", "accesstoken", "TOKEN")),
+      (
+        "/whisk.system/apimgmt/deleteApi",
+        ANY_ERROR_EXIT,
+        "When specifying an operation, the path is required",
+        Seq(
+          "-p",
+          "__ow_user",
+          "_",
+          "-p",
+          "accesstoken",
+          "TOKEN",
+          "-p",
+          "basepath",
+          "/ApiGwRoutemgmtActionTests_bp",
+          "-p",
+          "operation",
+          "get")),
+      //createApi
+      (
+        "/whisk.system/apimgmt/createApi",
+        ANY_ERROR_EXIT,
+        "apidoc is required",
+        Seq("-p", "__ow_user", "_", "-p", "accesstoken", "TOKEN")),
+      (
+        "/whisk.system/apimgmt/createApi",
+        ANY_ERROR_EXIT,
+        "apidoc is missing the namespace field",
+        Seq("-p", "__ow_user", "_", "-p", "accesstoken", "TOKEN", "-p", 
"apidoc", "{}")),
+      (
+        "/whisk.system/apimgmt/createApi",
+        ANY_ERROR_EXIT,
+        "apidoc is missing the gatewayBasePath field",
+        Seq("-p", "__ow_user", "_", "-p", "accesstoken", "TOKEN", "-p", 
"apidoc", """{"namespace":"_"}""")),
+      (
+        "/whisk.system/apimgmt/createApi",
+        ANY_ERROR_EXIT,
+        "apidoc is missing the gatewayPath field",
+        Seq(
+          "-p",
+          "__ow_user",
+          "_",
+          "-p",
+          "accesstoken",
+          "TOKEN",
+          "-p",
+          "apidoc",
+          
"""{"namespace":"_","gatewayBasePath":"/ApiGwRoutemgmtActionTests_bp"}""")),
+      (
+        "/whisk.system/apimgmt/createApi",
+        ANY_ERROR_EXIT,
+        "apidoc is missing the gatewayMethod field",
+        Seq(
+          "-p",
+          "__ow_user",
+          "_",
+          "-p",
+          "accesstoken",
+          "TOKEN",
+          "-p",
+          "apidoc",
+          
"""{"namespace":"_","gatewayBasePath":"/ApiGwRoutemgmtActionTests_bp","gatewayPath":"ApiGwRoutemgmtActionTests_rp"}""")),
+      (
+        "/whisk.system/apimgmt/createApi",
+        ANY_ERROR_EXIT,
+        "apidoc is missing the action field",
+        Seq(
+          "-p",
+          "__ow_user",
+          "_",
+          "-p",
+          "accesstoken",
+          "TOKEN",
+          "-p",
+          "apidoc",
+          
"""{"namespace":"_","gatewayBasePath":"/ApiGwRoutemgmtActionTests_bp","gatewayPath":"ApiGwRoutemgmtActionTests_rp","gatewayMethod":"get"}""")),
+      (
+        "/whisk.system/apimgmt/createApi",
+        ANY_ERROR_EXIT,
+        "action is missing the backendMethod field",
+        Seq(
+          "-p",
+          "__ow_user",
+          "_",
+          "-p",
+          "accesstoken",
+          "TOKEN",
+          "-p",
+          "apidoc",
+          
"""{"namespace":"_","gatewayBasePath":"/ApiGwRoutemgmtActionTests_bp","gatewayPath":"ApiGwRoutemgmtActionTests_rp","gatewayMethod":"get","action":{}}""")),
+      (
+        "/whisk.system/apimgmt/createApi",
+        ANY_ERROR_EXIT,
+        "action is missing the backendUrl field",
+        Seq(
+          "-p",
+          "__ow_user",
+          "_",
+          "-p",
+          "accesstoken",
+          "TOKEN",
+          "-p",
+          "apidoc",
+          
"""{"namespace":"_","gatewayBasePath":"/ApiGwRoutemgmtActionTests_bp","gatewayPath":"ApiGwRoutemgmtActionTests_rp","gatewayMethod":"get","action":{"backendMethod":"post"}}""")),
+      (
+        "/whisk.system/apimgmt/createApi",
+        ANY_ERROR_EXIT,
+        "action is missing the namespace field",
+        Seq(
+          "-p",
+          "__ow_user",
+          "_",
+          "-p",
+          "accesstoken",
+          "TOKEN",
+          "-p",
+          "apidoc",
+          
"""{"namespace":"_","gatewayBasePath":"/ApiGwRoutemgmtActionTests_bp","gatewayPath":"ApiGwRoutemgmtActionTests_rp","gatewayMethod":"get","action":{"backendMethod":"post","backendUrl":"URL"}}""")),
+      (
+        "/whisk.system/apimgmt/createApi",
+        ANY_ERROR_EXIT,
+        "action is missing the name field",
+        Seq(
+          "-p",
+          "__ow_user",
+          "_",
+          "-p",
+          "accesstoken",
+          "TOKEN",
+          "-p",
+          "apidoc",
+          
"""{"namespace":"_","gatewayBasePath":"/ApiGwRoutemgmtActionTests_bp","gatewayPath":"ApiGwRoutemgmtActionTests_rp","gatewayMethod":"get","action":{"backendMethod":"post","backendUrl":"URL","namespace":"_"}}""")),
+      (
+        "/whisk.system/apimgmt/createApi",
+        ANY_ERROR_EXIT,
+        "action is missing the authkey field",
+        Seq(
+          "-p",
+          "__ow_user",
+          "_",
+          "-p",
+          "accesstoken",
+          "TOKEN",
+          "-p",
+          "apidoc",
+          
"""{"namespace":"_","gatewayBasePath":"/ApiGwRoutemgmtActionTests_bp","gatewayPath":"ApiGwRoutemgmtActionTests_rp","gatewayMethod":"get","action":{"backendMethod":"post","backendUrl":"URL","namespace":"_","name":"N"}}""")),
+      (
+        "/whisk.system/apimgmt/createApi",
+        ANY_ERROR_EXIT,
+        "swagger and gatewayBasePath are mutually exclusive and cannot be 
specified together",
+        Seq(
+          "-p",
+          "__ow_user",
+          "_",
+          "-p",
+          "accesstoken",
+          "TOKEN",
+          "-p",
+          "apidoc",
+          
"""{"namespace":"_","gatewayBasePath":"/ApiGwRoutemgmtActionTests_bp","gatewayPath":"ApiGwRoutemgmtActionTests_rp","gatewayMethod":"get","action":{"backendMethod":"post","backendUrl":"URL","namespace":"_","name":"N","authkey":"XXXX"},"swagger":{}}""")),
+      (
+        "/whisk.system/apimgmt/createApi",
+        ANY_ERROR_EXIT,
+        "apidoc field cannot be parsed. Ensure it is valid JSON",
+        Seq("-p", "__ow_user", "_", "-p", "accesstoken", "TOKEN", "-p", 
"apidoc", "{1:[}}}")))
+
+    invalidArgs foreach {
+      case (action: String, exitcode: Int, errmsg: String, params: 
Seq[String]) =>
+        val cmd: Seq[String] = Seq(
+          "action",
+          "invoke",
+          action,
+          "-i",
+          "-b",
+          "-r",
+          "--apihost",
+          wskprops.apihost,
+          "--auth",
+          wskprops.authKey) ++ params
+        val rr = wsk.cli(cmd, expectedExitCode = exitcode)
+        rr.stderr should include regex (errmsg)
+    }
+  }
+
+  it should "reject an API created with a non-existent action" in {
+    val testName = "CLI_APIGWTEST15"
+    val testbasepath = "/" + testName + "_bp"
+    val testrelpath = "/path"
+    val testnewrelpath = "/path_new"
+    val testurlop = "get"
+    val testapiname = testName + " API Name"
+    val actionName = testName + "_action"
+    try {
+      val rr = apiCreate(
+        basepath = Some(testbasepath),
+        relpath = Some(testrelpath),
+        operation = Some(testurlop),
+        action = Some(actionName),
+        apiname = Some(testapiname),
+        expectedExitCode = ANY_ERROR_EXIT)
+      rr.stderr should include("does not exist")
+    } finally {
+      apiDelete(basepathOrApiName = testbasepath, expectedExitCode = 
DONTCARE_EXIT)
+    }
+  }
+
+  it should "reject an API created with an action that is not a web action" in 
{
+    val testName = "CLI_APIGWTEST16"
+    val testbasepath = "/" + testName + "_bp"
+    val testrelpath = "/path"
+    val testnewrelpath = "/path_new"
+    val testurlop = "get"
+    val testapiname = testName + " API Name"
+    val actionName = testName + "_action"
+    try {
+      // Create the action for the API.  It must NOT be a "web-action" action 
for this test
+      val file = TestUtils.getTestActionFilename(s"echo.js")
+      wsk.action.create(name = actionName, artifact = Some(file), 
expectedExitCode = SUCCESS_EXIT)
+
+      val rr = apiCreate(
+        basepath = Some(testbasepath),
+        relpath = Some(testrelpath),
+        operation = Some(testurlop),
+        action = Some(actionName),
+        apiname = Some(testapiname),
+        expectedExitCode = ANY_ERROR_EXIT)
+      rr.stderr should include("is not a web action")
+    } finally {
+      wsk.action.delete(name = actionName, expectedExitCode = DONTCARE_EXIT)
+      apiDelete(basepathOrApiName = testbasepath, expectedExitCode = 
DONTCARE_EXIT)
+    }
+  }
+
+  it should "reject API export when export type is invalid" in {
+    val testName = "CLI_APIGWTEST18"
+    val testbasepath = "/" + testName + "_bp"
+
+    val rr = apiGet(basepathOrApiName = Some(testbasepath), format = 
Some("BadType"), expectedExitCode = ANY_ERROR_EXIT)
+    rr.stderr should include("Invalid format type")
+  }
+
+  it should "list api alphabetically by Base/Rel/Verb" in {
+    val baseName = "/BaseTestPathApiList"
+    val actionName = "actionName"
+    val file = TestUtils.getTestActionFilename(s"echo-web-http.js")
+    try {
+      // Create Action for apis
+      var action =
+        wsk.action.create(name = actionName, artifact = Some(file), 
expectedExitCode = SUCCESS_EXIT, web = Some("true"))
+      println("action creation: " + action.stdout)
+      // Create apis
+      for (i <- 1 to 3) {
+        val base = s"$baseName$i"
+        var api = apiCreate(
+          basepath = Some(base),
+          relpath = Some("/relPath"),
+          operation = Some("GET"),
+          action = Some(actionName))
+        println("api creation: " + api.stdout)
+      }
+      val original = apiList(nameSort = Some(true))
+      val originalFull = apiList(full = Some(true), nameSort = Some(true))
+      val scalaSorted = List(s"${baseName}1" + "/", s"${baseName}2" + "/", 
s"${baseName}3" + "/")
+
+      val regex = s"${baseName}[1-3]/".r
+      val list = (regex.findAllMatchIn(original.stdout)).toList
+      val listFull = (regex.findAllMatchIn(originalFull.stdout)).toList
+
+      scalaSorted.toString shouldEqual list.toString
+      scalaSorted.toString shouldEqual listFull.toString
+
+    } finally {
+      // Clean up Apis
+      for (i <- 1 to 3) {
+        apiDelete(basepathOrApiName = s"${baseName}$i", expectedExitCode = 
DONTCARE_EXIT)
+      }
+      wsk.action.delete(name = actionName, expectedExitCode = DONTCARE_EXIT)
+    }
+  }
+
+  it should "successfully export an API in YAML format" in {
+    val testName = "CLI_APIGWTEST19"
+    val testbasepath = "/" + testName + "_bp"
+    val testrelpath = "/path"
+    val testnewrelpath = "/path_new"
+    val testurlop = "get"
+    val testapiname = testName + " API Name"
+    val actionName = testName + "_action"
+    val responseType = "http"
+    try {
+      // Create the action for the API.  It must be a "web-action" action.
+      val file = TestUtils.getTestActionFilename(s"echo.js")
+      wsk.action.create(name = actionName, artifact = Some(file), 
expectedExitCode = SUCCESS_EXIT, web = Some("true"))
+
+      var rr = apiCreate(
+        basepath = Some(testbasepath),
+        relpath = Some(testrelpath),
+        operation = Some(testurlop),
+        action = Some(actionName),
+        apiname = Some(testapiname),
+        responsetype = Some(responseType))
+      rr.stdout should include("ok: created API")
+
+      rr = apiGet(basepathOrApiName = Some(testapiname), format = Some("yaml"))
+      rr.stdout should include(s"basePath: ${testbasepath}")
+    } finally {
+      wsk.action.delete(name = actionName, expectedExitCode = DONTCARE_EXIT)
+      apiDelete(basepathOrApiName = testbasepath, expectedExitCode = 
DONTCARE_EXIT)
+    }
+  }
+
+  it should "successfully export an API when JSON format is explcitly 
specified" in {
+    val testName = "CLI_APIGWTEST20"
+    val testbasepath = "/" + testName + "_bp"
+    val testrelpath = "/path"
+    val testnewrelpath = "/path_new"
+    val testurlop = "get"
+    val testapiname = testName + " API Name"
+    val actionName = testName + "_action"
+    val responseType = "http"
+    try {
+      // Create the action for the API.  It must be a "web-action" action.
+      val file = TestUtils.getTestActionFilename(s"echo.js")
+      wsk.action.create(name = actionName, artifact = Some(file), 
expectedExitCode = SUCCESS_EXIT, web = Some("true"))
+
+      var rr = apiCreate(
+        basepath = Some(testbasepath),
+        relpath = Some(testrelpath),
+        operation = Some(testurlop),
+        action = Some(actionName),
+        apiname = Some(testapiname),
+        responsetype = Some(responseType))
+      rr.stdout should include("ok: created API")
+
+      rr = apiGet(basepathOrApiName = Some(testapiname), format = Some("json"))
+      rr.stdout should include(testbasepath)
+      rr.stdout should include(s"${actionName}")
+      rr.stdout should include regex 
(""""cors":\s*\{\s*\n\s*"enabled":\s*true""")
+      rr.stdout should include regex 
(s""""target-url":\\s+.*${actionName}.${responseType}""")
+    } finally {
+      wsk.action.delete(name = actionName, expectedExitCode = DONTCARE_EXIT)
+      apiDelete(basepathOrApiName = testbasepath, expectedExitCode = 
DONTCARE_EXIT)
+    }
+  }
+
+  it should "successfully create an API from a YAML formatted API 
configuration file" in {
+    val testName = "CLI_APIGWTEST21"
+    val testbasepath = "/bp"
+    val testrelpath = "/rp"
+    val testurlop = "get"
+    val testapiname = testbasepath
+    val actionName = "webhttpecho"
+    val swaggerPath = TestUtils.getTestApiGwFilename(s"local.api.yaml")
+    try {
+      var rr = apiCreate(swagger = Some(swaggerPath))
+      println("api create stdout: " + rr.stdout)
+      println("api create stderror: " + rr.stderr)
+      rr.stdout should include("ok: created API")
+      rr = apiList(basepathOrApiName = Some(testbasepath))
+      rr.stdout should include("ok: APIs")
+      rr.stdout should include regex 
(s"/[@\\w._\\-]+/${actionName}\\s+${testurlop}\\s+${testapiname}\\s+")
+      rr.stdout should include(testbasepath + testrelpath)
+    } finally {
+      apiDelete(basepathOrApiName = testbasepath, expectedExitCode = 
DONTCARE_EXIT)
+    }
+  }
+
+  it should "reject creation of an API from invalid YAML formatted API 
configuration file" in {
+    val testName = "CLI_APIGWTEST22"
+    val testbasepath = "/" + testName + "_bp"
+    val swaggerPath = TestUtils.getTestApiGwFilename(s"local.api.bad.yaml")
+    try {
+      val rr = apiCreate(swagger = Some(swaggerPath), expectedExitCode = 
ANY_ERROR_EXIT)
+      println("api create stdout: " + rr.stdout)
+      println("api create stderror: " + rr.stderr)
+      rr.stderr should include("Unable to parse YAML configuration file")
+    } finally {
+      apiDelete(basepathOrApiName = testbasepath, expectedExitCode = 
DONTCARE_EXIT)
+    }
+  }
+}


 

----------------------------------------------------------------
This is an automated message from the Apache Git Service.
To respond to the message, please log on GitHub and use the
URL above to go to the specific comment.
 
For queries about this service, please contact Infrastructure at:
[email protected]


With regards,
Apache Git Services

Reply via email to