blob: f80b947b22243e3acf96e079c835108afc918584 [file] [log] [blame]
/*
* 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 org.apache.openwhisk.core.cli.test
import io.restassured.RestAssured
import java.io.File
import java.io.BufferedWriter
import java.io.FileWriter
import org.junit.runner.RunWith
import org.scalatest.junit.JUnitRunner
import io.restassured.config.RestAssuredConfig
import io.restassured.config.SSLConfig
import common.TestUtils._
import common.TestUtils
import common.WhiskProperties
import common.{TestUtils, WhiskProperties, WskProps}
import scala.concurrent.duration.DurationInt
import scala.util.matching.Regex
import org.apache.commons.io.FileUtils
import spray.json._
import spray.json.DefaultJsonProtocol._
/**
* Tests for testing the CLI "api" subcommand. Most of these tests require a deployed backend.
*/
@RunWith(classOf[JUnitRunner])
abstract class ApiGwCliBasicTests extends BaseApiGwTests {
val clinamespace = wsk.namespace.whois()
val createCode: Int
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")
}
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)
}
def verifyApiBaseRelPath(rr: RunResult, testbasepath: String, testrelpath: String): Unit = {
rr.stdout should include(testbasepath + testrelpath)
}
def verifyApiGet(rr: RunResult, apihost: String): Unit = {
rr.stdout should include regex (s""""operationId":\\s+"getPathWithSub_pathsInIt"""")
rr.stdout should include regex (s""""target-url":\\s+"https://$apihost""")
}
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 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 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 verifyInvalidSwagger(rr: RunResult): Unit = {
rr.stderr should include(s"Swagger file is invalid")
}
def verifyApiOp(rr: RunResult, testurlop: String, testapiname: String): Unit = {
rr.stdout should include regex (s"\\s+${testurlop}\\s+${testapiname}\\s+")
}
def verifyApiOpVerb(rr: RunResult, testurlop: String): Unit = {
rr.stdout should include regex (s"Verb:\\s+${testurlop}")
}
def verifyInvalidKey(rr: RunResult): Unit = {
rr.stderr should include("The supplied authentication is invalid")
}
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 getSwaggerUrl(rr: RunResult): String = {
rr.stdout.split("\n")(1)
}
def replaceStringInFile(fileName: String, replacements: Map[Regex, String]): String = {
val encoding = "UTF-8"
val contents = FileUtils.readFileToString(new File(fileName), encoding)
var newContents = contents
replacements foreach ((regex) => newContents = regex._1.replaceAllIn(newContents, regex._2))
val tmpFileName = fileName + "-" + System.currentTimeMillis() + ".tmp"
val tmpFile = new File(tmpFileName)
if (tmpFile.exists()) {
FileUtils.forceDelete(tmpFile)
}
FileUtils.writeStringToFile(new File(tmpFileName), newContents, encoding)
tmpFileName
}
def getParametersFromJson(json: JsObject, pathName: String): Vector[JsValue] = {
json
.fields("paths")
.asJsObject
.fields(pathName)
.asJsObject
.fields("get")
.asJsObject
.fields("parameters")
.convertTo[JsArray]
.elements
}
def getSslConfig(): RestAssuredConfig = {
// force RestAssured to allow all hosts in SSL certificates
new RestAssuredConfig()
.sslConfig(new SSLConfig().keyStore("keystore", WhiskProperties.getSslCertificateChallenge).allowAllHostnames())
}
def validateParameter(parameter: JsObject,
name: String,
in: String,
required: Boolean,
pType: String,
description: String): Unit = {
parameter.fields("name") should be(name.toJson)
parameter.fields("in") should be(in.toJson)
parameter.fields("required") should be(required.toJson)
parameter.fields("type") should be(pType.toJson)
parameter.fields("description") should be(description.toJson)
}
behavior of "Wsk api"
behavior of "Cli Wsk api creation with path parameters with swagger"
it should "create the API when swagger file contains path parameters" in withAssetCleaner(wskprops) {
(wp, assetHelper) =>
val actionName = "cli_apigwtest_path_param_swagger_action"
val apiName = "/guest/v1"
val reqPath = "\\$\\(request.path\\)"
val testRelPath = "/api2/greeting2/{name}"
val testUrlName = "scooby"
val testRelPathGet = s"/api2/greeting2/$testUrlName"
val testUrlOp = "get"
var file = TestUtils.getTestActionFilename(s"echo-web-http.js")
val hostRegex = "%HOST%".r
assetHelper.withCleaner(wsk.action, actionName, confirmDelete = true) { (action, _) =>
action.create(actionName, Some(file), web = Some("true"))
}
try {
//Create the API
var rr: RunResult = apiCreate(
basepath = Some(apiName),
relpath = Some(testRelPath),
operation = Some(testUrlOp),
action = Some(actionName),
responsetype = Some("http"))
verifyApiCreated(rr)
//Get the api so we can create the swagger from the returned output
rr = apiGet(basepathOrApiName = Some(apiName))
rr.stdout should include regex (s"""target-url.*${actionName}.http${reqPath}""")
val swaggerFile = writeSwaggerFile(rr)
//Delete the api so we can re-create it using the swagger
rr = apiDelete(basepathOrApiName = apiName)
verifyApiDeleted(rr)
//Create the api using the swagger file.
rr = apiCreate(swagger = Some(swaggerFile.getAbsolutePath()), expectedExitCode = SUCCESS_EXIT)
verifyApiCreated(rr)
val swaggerApiUrl = getSwaggerUrl(rr).replace("{name}", testUrlName)
//Lets validate that the swagger we get from the create contains the correct info.
rr = apiGet(basepathOrApiName = Some(apiName))
rr.stdout should include regex (s"""target-url.*${actionName}.http${reqPath}""")
val params = getParametersFromJson(rr.stdout.parseJson.asJsObject, testRelPath)
params.size should be(1)
validateParameter(params(0).asJsObject, "name", "path", true, "string", "Default description for 'name'")
//Lets call the swagger url so we can make sure the response is valid and contains our path in the ow path
val apiToInvoke = s"$swaggerApiUrl"
println(s"Invoking: '${apiToInvoke}'")
val response = org.apache.openwhisk.utils.retry({
val response = RestAssured.given().config(getSslConfig()).get(s"$apiToInvoke")
response.statusCode should be(200)
response
}, 6, Some(2.second))
val jsonResponse = response.body.asString.parseJson.asJsObject
jsonResponse.fields("__ow_path").toString should include(testRelPathGet)
} finally {
apiDelete(basepathOrApiName = apiName)
}
}
it should "reject an api commands with an invalid path parameter" in {
val badpath = "badpath"
var rr = apiCreate(
basepath = Some("/basepath"),
relpath = Some(badpath),
operation = Some("GET"),
action = Some("action"),
expectedExitCode = ANY_ERROR_EXIT)
verifyBadCommands(rr, badpath)
rr = apiDelete(
basepathOrApiName = "/basepath",
relpath = Some(badpath),
operation = Some("GET"),
expectedExitCode = ANY_ERROR_EXIT)
verifyBadCommandsDelete(rr, badpath)
rr = apiList(
basepathOrApiName = Some("/basepath"),
relpath = Some(badpath),
operation = Some("GET"),
expectedExitCode = ANY_ERROR_EXIT)
verifyBadCommandsList(rr, badpath)
}
it should "reject an api commands with an invalid verb parameter" in {
val badverb = "badverb"
var rr = apiCreate(
basepath = Some("/basepath"),
relpath = Some("/path"),
operation = Some(badverb),
action = Some("action"),
expectedExitCode = ANY_ERROR_EXIT)
verifyInvalidCommands(rr, badverb)
rr = apiDelete(
basepathOrApiName = "/basepath",
relpath = Some("/path"),
operation = Some(badverb),
expectedExitCode = ANY_ERROR_EXIT)
verifyInvalidCommandsDelete(rr, badverb)
rr = apiList(
basepathOrApiName = Some("/basepath"),
relpath = Some("/path"),
operation = Some(badverb),
expectedExitCode = ANY_ERROR_EXIT)
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}'")
}
it should "reject an api create command specifying a non-JSON configuration file" in {
val file = File.createTempFile("api.json", ".txt")
file.deleteOnExit()
val filename = file.getAbsolutePath()
val bw = new BufferedWriter(new FileWriter(file))
bw.write("a=A")
bw.close()
val rr = apiCreate(swagger = Some(filename), expectedExitCode = ANY_ERROR_EXIT)
verifyNonJsonSwagger(rr, filename)
}
it should "reject an api create command specifying a non-swagger JSON configuration file" in {
val file = File.createTempFile("api.json", ".txt")
file.deleteOnExit()
val filename = file.getAbsolutePath()
val bw = new BufferedWriter(new FileWriter(file))
bw.write("""|{
| "swagger": "2.0",
| "info": {
| "title": "My API",
| "version": "1.0.0"
| },
| "BADbasePath": "/bp",
| "paths": {
| "/rp": {
| "get":{}
| }
| }
|}""".stripMargin)
bw.close()
val rr = apiCreate(swagger = Some(filename), expectedExitCode = ANY_ERROR_EXIT)
verifyMissingField(rr)
}
it should "verify full list output" in {
val testName = "CLI_APIGWTEST_RO1"
val testbasepath = "/" + testName + "_bp"
val testrelpath = "/path"
val testnewrelpath = "/path_new"
val testurlop = "get"
val testapiname = testName + " API Name"
val actionName = testName + "_action"
try {
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 = createCode, web = Some("true"))
var rr = apiCreate(
basepath = Some(testbasepath),
relpath = Some(testrelpath),
operation = Some(testurlop),
action = Some(actionName),
apiname = Some(testapiname))
println("api create: " + rr.stdout)
verifyApiCreated(rr)
rr = apiList(
basepathOrApiName = Some(testbasepath),
relpath = Some(testrelpath),
operation = Some(testurlop),
full = Some(true))
println("api list: " + rr.stdout)
verifyApiList(rr, clinamespace, actionName, testurlop, testbasepath, testrelpath, testapiname)
} finally {
wsk.action.delete(name = actionName, expectedExitCode = DONTCARE_EXIT)
apiDelete(basepathOrApiName = testbasepath)
}
}
it should "verify successful creation and deletion of a new API" in {
val testName = "CLI_APIGWTEST1"
val testbasepath = "/" + testName + "_bp"
val testrelpath = "/path/with/sub_paths/in/it"
val testnewrelpath = "/path_new"
val testurlop = "get"
val testapiname = testName + " API Name"
val actionName = testName + "_action"
try {
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 = createCode, web = Some("true"))
var rr = apiCreate(
basepath = Some(testbasepath),
relpath = Some(testrelpath),
operation = Some(testurlop),
action = Some(actionName),
apiname = Some(testapiname))
verifyApiCreated(rr)
rr = apiList(basepathOrApiName = Some(testbasepath), relpath = Some(testrelpath), operation = Some(testurlop))
verifyApiFullList(rr, clinamespace, actionName, testurlop, testbasepath, testrelpath, testapiname)
rr = apiGet(basepathOrApiName = Some(testbasepath))
verifyApiGet(rr, wskprops.apihost)
val deleteresult = apiDelete(basepathOrApiName = testbasepath)
verifyApiDeleted(deleteresult)
} finally {
wsk.action.delete(name = actionName, expectedExitCode = DONTCARE_EXIT)
apiDelete(basepathOrApiName = testbasepath, expectedExitCode = DONTCARE_EXIT)
}
}
it should "verify successful creation and deletion of a new API when apihost specifies the protocol" in {
val testName = "CLI_APIGWTEST2"
val testbasepath = "/" + testName + "_bp"
val testrelpath = "/path/with/sub_paths/in/it"
val testnewrelpath = "/path_new"
val testurlop = "get"
val testapiname = testName + " API Name"
val actionName = testName + "_action"
try {
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 = createCode, web = Some("true"))
val explicitProtocol = if (wskprops.apihost.startsWith("http")) "" else "https://"
val wskpropsOverride = WskProps(apihost = explicitProtocol + wskprops.apihost)
var rr = apiCreate(
basepath = Some(testbasepath),
relpath = Some(testrelpath),
operation = Some(testurlop),
action = Some(actionName),
apiname = Some(testapiname))(wskpropsOverride)
verifyApiCreated(rr)
rr = apiList(basepathOrApiName = Some(testbasepath), relpath = Some(testrelpath), operation = Some(testurlop))
verifyApiFullList(rr, clinamespace, actionName, testurlop, testbasepath, testrelpath, testapiname)
rr = apiGet(basepathOrApiName = Some(testbasepath))
verifyApiGet(rr, wskprops.apihost)
val deleteresult = apiDelete(basepathOrApiName = testbasepath)
verifyApiDeleted(deleteresult)
} finally {
wsk.action.delete(name = actionName, expectedExitCode = DONTCARE_EXIT)
apiDelete(basepathOrApiName = testbasepath, expectedExitCode = DONTCARE_EXIT)
}
}
it should "verify get API name " in {
val testName = "CLI_APIGWTEST3"
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 be a "web-action" action.
val file = TestUtils.getTestActionFilename(s"echo.js")
wsk.action.create(name = actionName, artifact = Some(file), expectedExitCode = createCode, web = Some("true"))
var rr = apiCreate(
basepath = Some(testbasepath),
relpath = Some(testrelpath),
operation = Some(testurlop),
action = Some(actionName),
apiname = Some(testapiname))
verifyApiCreated(rr)
rr = apiGet(basepathOrApiName = Some(testapiname))
verifyApiNameGet(rr, testbasepath, actionName)
} finally {
wsk.action.delete(name = actionName, expectedExitCode = DONTCARE_EXIT)
apiDelete(basepathOrApiName = testbasepath, expectedExitCode = DONTCARE_EXIT)
}
}
it should "verify delete API name " in {
val testName = "CLI_APIGWTEST4"
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 be a "web-action" action.
val file = TestUtils.getTestActionFilename(s"echo.js")
wsk.action.create(name = actionName, artifact = Some(file), expectedExitCode = createCode, web = Some("true"))
var rr = apiCreate(
basepath = Some(testbasepath),
relpath = Some(testrelpath),
operation = Some(testurlop),
action = Some(actionName),
apiname = Some(testapiname))
verifyApiCreated(rr)
rr = apiDelete(basepathOrApiName = testapiname)
verifyApiDeleted(rr)
} finally {
wsk.action.delete(name = actionName, expectedExitCode = DONTCARE_EXIT)
apiDelete(basepathOrApiName = testbasepath, expectedExitCode = DONTCARE_EXIT)
}
}
it should "verify delete API basepath " in {
val testName = "CLI_APIGWTEST5"
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 be a "web-action" action.
val file = TestUtils.getTestActionFilename(s"echo.js")
wsk.action.create(name = actionName, artifact = Some(file), expectedExitCode = createCode, web = Some("true"))
var rr = apiCreate(
basepath = Some(testbasepath),
relpath = Some(testrelpath),
operation = Some(testurlop),
action = Some(actionName),
apiname = Some(testapiname))
verifyApiCreated(rr)
rr = apiDelete(basepathOrApiName = testbasepath)
verifyApiDeleted(rr)
} finally {
wsk.action.delete(name = actionName, expectedExitCode = DONTCARE_EXIT)
apiDelete(basepathOrApiName = testbasepath, expectedExitCode = DONTCARE_EXIT)
}
}
it should "verify adding endpoints to existing api" in {
val testName = "CLI_APIGWTEST6"
val testbasepath = "/" + testName + "_bp"
val testrelpath = "/path2"
val testnewrelpath = "/path_new"
val testurlop = "get"
val testapiname = testName + " API Name"
val actionName = testName + "_action"
val newEndpoint = "/newEndpoint"
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 = createCode, web = Some("true"))
var rr = apiCreate(
basepath = Some(testbasepath),
relpath = Some(testrelpath),
operation = Some(testurlop),
action = Some(actionName),
apiname = Some(testapiname))
verifyApiCreated(rr)
rr = apiCreate(
basepath = Some(testbasepath),
relpath = Some(newEndpoint),
operation = Some(testurlop),
action = Some(actionName),
apiname = Some(testapiname))
verifyApiCreated(rr)
rr = apiList(basepathOrApiName = Some(testbasepath))
verifyApiFullListDouble(
rr,
clinamespace,
actionName,
testurlop,
testbasepath,
newEndpoint,
testapiname,
newEndpoint)
} finally {
wsk.action.delete(name = actionName, expectedExitCode = DONTCARE_EXIT)
apiDelete(basepathOrApiName = testbasepath, expectedExitCode = DONTCARE_EXIT)
}
}
it should "verify successful creation with swagger doc as input" in {
// NOTE: These values must match the swagger file contents
val testName = "CLI_APIGWTEST7"
val testbasepath = "/" + testName + "_bp"
val testrelpath = "/path"
val testurlop = "get"
val testapiname = testName + " API Name"
val actionName = testName + "_action"
val swaggerPath = TestUtils.getTestApiGwFilename("testswaggerdoc1")
try {
var rr = apiCreate(swagger = Some(swaggerPath))
verifyApiCreated(rr)
rr = apiList(basepathOrApiName = Some(testbasepath), relpath = Some(testrelpath), operation = Some(testurlop))
println("list stdout: " + rr.stdout)
println("list stderr: " + rr.stderr)
verifyApiFullList(rr, "", actionName, testurlop, testbasepath, testrelpath, testapiname)
} finally {
apiDelete(basepathOrApiName = testbasepath, expectedExitCode = DONTCARE_EXIT)
}
}
it should "verify adding endpoints to two existing apis" in {
val testName = "CLI_APIGWTEST8"
val testbasepath = "/" + testName + "_bp"
val testbasepath2 = "/" + testName + "_bp2"
val testrelpath = "/path2"
val testnewrelpath = "/path_new"
val testurlop = "get"
val testapiname = testName + " API Name"
val testapiname2 = testName + " API Name 2"
val actionName = testName + "_action"
val newEndpoint = "/newEndpoint"
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 = createCode, web = Some("true"))
var rr = apiCreate(
basepath = Some(testbasepath),
relpath = Some(testrelpath),
operation = Some(testurlop),
action = Some(actionName),
apiname = Some(testapiname))
verifyApiCreated(rr)
rr = apiCreate(
basepath = Some(testbasepath2),
relpath = Some(testrelpath),
operation = Some(testurlop),
action = Some(actionName),
apiname = Some(testapiname2))
verifyApiCreated(rr)
// Update both APIs - each with a new endpoint
rr = apiCreate(
basepath = Some(testbasepath),
relpath = Some(newEndpoint),
operation = Some(testurlop),
action = Some(actionName))
verifyApiCreated(rr)
rr = apiCreate(
basepath = Some(testbasepath2),
relpath = Some(newEndpoint),
operation = Some(testurlop),
action = Some(actionName))
verifyApiCreated(rr)
rr = apiList(basepathOrApiName = Some(testbasepath))
verifyApiFullListDouble(
rr,
clinamespace,
actionName,
testurlop,
testbasepath,
testrelpath,
testapiname,
newEndpoint)
rr = apiList(basepathOrApiName = Some(testbasepath2))
verifyApiFullListDouble(
rr,
clinamespace,
actionName,
testurlop,
testbasepath2,
testrelpath,
testapiname2,
newEndpoint)
} finally {
wsk.action.delete(name = actionName, expectedExitCode = DONTCARE_EXIT)
apiDelete(basepathOrApiName = testbasepath, expectedExitCode = DONTCARE_EXIT)
apiDelete(basepathOrApiName = testbasepath2, expectedExitCode = DONTCARE_EXIT)
}
}
it should "verify successful creation of a new API using an action name using all allowed characters" in {
val testName = "CLI_APIGWTEST9"
val testbasepath = "/" + testName + "_bp"
val testrelpath = "/path"
val testnewrelpath = "/path_new"
val testurlop = "get"
val testapiname = testName + " API Name"
val actionName = testName + "a-c@t ion"
try {
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 = createCode, web = Some("true"))
var rr = apiCreate(
basepath = Some(testbasepath),
relpath = Some(testrelpath),
operation = Some(testurlop),
action = Some(actionName),
apiname = Some(testapiname))
verifyApiCreated(rr)
rr = apiList(basepathOrApiName = Some(testbasepath), relpath = Some(testrelpath), operation = Some(testurlop))
verifyApiFullList(rr, clinamespace, actionName, testurlop, testbasepath, testrelpath, testapiname)
val deleteresult = apiDelete(basepathOrApiName = testbasepath)
verifyApiDeleted(deleteresult)
} finally {
wsk.action.delete(name = actionName, expectedExitCode = DONTCARE_EXIT)
apiDelete(basepathOrApiName = testbasepath, expectedExitCode = DONTCARE_EXIT)
}
}
it should "verify failed creation with invalid swagger doc as input" in {
val testName = "CLI_APIGWTEST10"
val testbasepath = "/" + testName + "_bp"
val testrelpath = "/path"
val testnewrelpath = "/path_new"
val testurlop = "get"
val testapiname = testName + " API Name"
val actionName = testName + "_action"
val swaggerPath = TestUtils.getTestApiGwFilename(s"testswaggerdocinvalid")
try {
val rr = apiCreate(swagger = Some(swaggerPath), expectedExitCode = ANY_ERROR_EXIT)
println("api create stdout: " + rr.stdout)
println("api create stderr: " + rr.stderr)
verifyInvalidSwagger(rr)
} finally {
apiDelete(basepathOrApiName = testbasepath, expectedExitCode = DONTCARE_EXIT)
}
}
it should "verify delete basepath/path " in {
val testName = "CLI_APIGWTEST11"
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 be a "web-action" action.
val file = TestUtils.getTestActionFilename(s"echo.js")
wsk.action.create(name = actionName, artifact = Some(file), expectedExitCode = createCode, web = Some("true"))
var rr = apiCreate(
basepath = Some(testbasepath),
relpath = Some(testrelpath),
operation = Some(testurlop),
action = Some(actionName),
apiname = Some(testapiname))
verifyApiCreated(rr)
var rr2 = apiCreate(
basepath = Some(testbasepath),
relpath = Some(testnewrelpath),
operation = Some(testurlop),
action = Some(actionName),
apiname = Some(testapiname))
verifyApiCreated(rr2)
rr = apiDelete(basepathOrApiName = testbasepath, relpath = Some(testrelpath))
verifyApiDeletedRelpath(rr, testrelpath, testbasepath)
rr2 = apiList(basepathOrApiName = Some(testbasepath), relpath = Some(testnewrelpath))
verifyApiFullList(rr2, clinamespace, actionName, testurlop, testbasepath, testnewrelpath, testapiname)
} finally {
wsk.action.delete(name = actionName, expectedExitCode = DONTCARE_EXIT)
apiDelete(basepathOrApiName = testbasepath, expectedExitCode = DONTCARE_EXIT)
}
}
it should "verify delete single operation from existing API basepath/path/operation(s) " in {
val testName = "CLI_APIGWTEST12"
val testbasepath = "/" + testName + "_bp"
val testrelpath = "/path2"
val testnewrelpath = "/path_new"
val testurlop = "get"
val testurlop2 = "post"
val testapiname = testName + " API Name"
val actionName = testName + "_action"
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 = createCode, web = Some("true"))
var rr = apiCreate(
basepath = Some(testbasepath),
relpath = Some(testrelpath),
operation = Some(testurlop),
action = Some(actionName),
apiname = Some(testapiname))
verifyApiCreated(rr)
rr = apiCreate(
basepath = Some(testbasepath),
relpath = Some(testrelpath),
operation = Some(testurlop2),
action = Some(actionName),
apiname = Some(testapiname))
verifyApiCreated(rr)
rr = apiList(basepathOrApiName = Some(testbasepath))
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))
verifyApiDeletedRelpath(rr, testrelpath, testbasepath, testurlop2)
rr = apiList(basepathOrApiName = Some(testbasepath))
verifyApiFullList(rr, clinamespace, actionName, testurlop, testbasepath, testrelpath, testapiname)
} finally {
wsk.action.delete(name = actionName, expectedExitCode = DONTCARE_EXIT)
apiDelete(basepathOrApiName = testbasepath, expectedExitCode = DONTCARE_EXIT)
}
}
it should "verify successful creation with complex swagger doc as input" in {
val testName = "CLI_APIGWTEST13"
val testbasepath = "/test1/v1"
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")
try {
var rr = apiCreate(swagger = Some(swaggerPath))
println("api create stdout: " + rr.stdout)
println("api create stderror: " + rr.stderr)
verifyApiCreated(rr)
rr = apiList(basepathOrApiName = Some(testbasepath))
verifyApiFullList(rr, "", actionName, testurlop, testbasepath, testrelpath, testapiname)
verifyApiFullList(rr, "", actionName, testurlop2, testbasepath, testrelpath2, testapiname)
} finally {
apiDelete(basepathOrApiName = testbasepath, expectedExitCode = DONTCARE_EXIT)
}
}
it should "verify successful creation and deletion with multiple base paths" in {
val testName = "CLI_APIGWTEST14"
val testbasepath = "/" + testName + "_bp"
val testbasepath2 = "/" + testName + "_bp2"
val testrelpath = "/path"
val testnewrelpath = "/path_new"
val testurlop = "get"
val testapiname = testName + " API Name"
val testapiname2 = testName + " API Name 2"
val actionName = testName + "_action"
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 = createCode, web = Some("true"))
var rr = apiCreate(
basepath = Some(testbasepath),
relpath = Some(testrelpath),
operation = Some(testurlop),
action = Some(actionName),
apiname = Some(testapiname))
verifyApiCreated(rr)
rr = apiList(basepathOrApiName = Some(testbasepath), relpath = Some(testrelpath), operation = Some(testurlop))
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))
verifyApiCreated(rr)
rr = apiList(basepathOrApiName = Some(testbasepath2), relpath = Some(testrelpath), operation = Some(testurlop))
verifyApiFullList(rr, clinamespace, actionName, testurlop, testbasepath2, testrelpath, testapiname2)
rr = apiDelete(basepathOrApiName = testbasepath2)
verifyApiDeleted(rr)
rr = apiList(basepathOrApiName = Some(testbasepath), relpath = Some(testrelpath), operation = Some(testurlop))
verifyApiFullList(rr, clinamespace, actionName, testurlop, testbasepath, testrelpath, testapiname)
rr = apiDelete(basepathOrApiName = testbasepath)
verifyApiDeleted(rr)
} finally {
wsk.action.delete(name = actionName, expectedExitCode = DONTCARE_EXIT)
apiDelete(basepathOrApiName = testbasepath, expectedExitCode = DONTCARE_EXIT)
apiDelete(basepathOrApiName = testbasepath2, expectedExitCode = DONTCARE_EXIT)
}
}
it should "verify API with http response type " in {
val testName = "CLI_APIGWTEST17"
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 = createCode, web = Some("true"))
var rr = apiCreate(
basepath = Some(testbasepath),
relpath = Some(testrelpath),
operation = Some(testurlop),
action = Some(actionName),
apiname = Some(testapiname),
responsetype = Some(responseType))
verifyApiCreated(rr)
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 "reject deletion of a non-existent api" in {
val nonexistentApi = "/not-there"
val rr = apiDelete(basepathOrApiName = nonexistentApi, expectedExitCode = ANY_ERROR_EXIT)
rr.stderr should include(s"API '${nonexistentApi}' does not exist")
}
it should "successfully list an API whose endpoints are not mapped to actions" in {
val testName = "CLI_APIGWTEST23"
val testapiname = "A descriptive name"
val testbasepath = "/NoActions"
val testrelpath = "/"
val testops: Seq[String] = Seq("put", "delete", "get", "head", "options", "patch", "post")
val swaggerPath = TestUtils.getTestApiGwFilename(s"endpoints.without.action.swagger.json")
try {
var rr = apiCreate(swagger = Some(swaggerPath))
println("api create stdout: " + rr.stdout)
println("api create stderror: " + rr.stderr)
this.verifyApiCreated(rr)
rr = apiList(basepathOrApiName = Some(testbasepath))
println("api list:\n" + rr.stdout)
testops foreach { testurlop =>
verifyApiOp(rr, testurlop, testapiname)
}
verifyApiBaseRelPath(rr, testbasepath, testrelpath)
rr = apiList(basepathOrApiName = Some(testbasepath), full = Some(true))
println("api full list:\n" + rr.stdout)
testops foreach { testurlop =>
verifyApiOpVerb(rr, testurlop)
}
verifyApiBaseRelPath(rr, testbasepath, testrelpath)
} finally {
apiDelete(basepathOrApiName = testbasepath, expectedExitCode = DONTCARE_EXIT)
}
}
it should "reject creation of an API with invalid auth key" in {
val testName = "CLI_APIGWTEST24"
val testbasepath = "/" + testName + "_bp"
val testrelpath = "/path"
val testurlop = "get"
val testapiname = testName + " API Name"
val actionName = testName + "_action"
try {
// Create the action for the API.
val file = TestUtils.getTestActionFilename(s"echo.js")
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")
val rr = apiCreate(
basepath = Some(testbasepath),
relpath = Some(testrelpath),
operation = Some(testurlop),
action = Some(actionName),
apiname = Some(testapiname),
expectedExitCode = ANY_ERROR_EXIT)(badWskProps)
verifyInvalidKey(rr)
} finally {
wsk.action.delete(name = actionName, expectedExitCode = DONTCARE_EXIT)
apiDelete(basepathOrApiName = testbasepath, expectedExitCode = DONTCARE_EXIT)
}
}
it should "verify get API name that uses custom package" in {
val testName = "CLI_APIGWTEST25"
val testbasepath = "/" + testName + "_bp"
val testrelpath = "/path"
val testnewrelpath = "/path_new"
val testurlop = "get"
val testapiname = testName + " API Name"
val packageName = withTimestamp("pkg")
val actionName = packageName + "/" + testName + "_action"
try {
wsk.pkg.create(packageName).stdout should include regex (s"""ok: created package $packageName""")
// 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 = createCode, web = Some("true"))
var rr = apiCreate(
basepath = Some(testbasepath),
relpath = Some(testrelpath),
operation = Some(testurlop),
action = Some(actionName),
apiname = Some(testapiname))
verifyApiCreated(rr)
rr = apiGet(basepathOrApiName = Some(testapiname))
verifyApiNameGet(rr, testbasepath, actionName)
} finally {
wsk.action.delete(name = actionName, expectedExitCode = DONTCARE_EXIT)
apiDelete(basepathOrApiName = testbasepath, expectedExitCode = DONTCARE_EXIT)
wsk.pkg.delete(packageName).stdout should include regex (s"""ok: deleted package $packageName""")
}
}
}