dubeejw commented on a change in pull request #2593: Add BaseWsk class for Wsk and WskRest to inherit URL: https://github.com/apache/incubator-openwhisk/pull/2593#discussion_r138094877
########## File path: tests/src/test/scala/common/BaseWsk.scala ########## @@ -0,0 +1,406 @@ +/* + * 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 common + +import java.io.BufferedWriter +import java.io.File +import java.io.FileWriter +import java.time.Instant + +import scala.concurrent.duration.DurationInt +import scala.collection.JavaConversions.mapAsJavaMap +import scala.collection.mutable.Buffer +import scala.concurrent.duration.Duration + +import org.scalatest.Matchers + +import TestUtils._ +import spray.json.JsObject +import spray.json.JsValue +import spray.json.pimpString +import whisk.core.entity.ByteSize + +case class WskProps( + authKey: String = WhiskProperties.readAuthKey(WhiskProperties.getAuthFileForTesting), + cert: String = + WhiskProperties.getFileRelativeToWhiskHome("ansible/roles/nginx/files/openwhisk-client-cert.pem").getAbsolutePath, + key: String = + WhiskProperties.getFileRelativeToWhiskHome("ansible/roles/nginx/files/openwhisk-client-key.pem").getAbsolutePath, + namespace: String = "_", + apiversion: String = "v1", + apihost: String = WhiskProperties.getEdgeHost, + token: String = "") { + def overrides = Seq("-i", "--apihost", apihost, "--apiversion", apiversion) + def writeFile(propsfile: File) = { + val propsStr = + s"NAMESPACE=$namespace\nAPIVERSION=$apiversion\nAUTH=$authKey\nAPIHOST=$apihost\nAPIGW_ACCESS_TOKEN=$token\n" + val bw = new BufferedWriter(new FileWriter(propsfile)) + try { + bw.write(propsStr) + } finally { + bw.close() + } + } +} + +trait BaseWsk extends RunWskCmd { + val action: BaseAction + val trigger: BaseTrigger + val rule: BaseRule + val activation: BaseActivation + val pkg: BasePackage + val namespace: BaseNamespace + val api: BaseApi +} + +trait FullyQualifiedNames { + + /** + * Fully qualifies the name of an entity with its namespace. + * If the name already starts with the PATHSEP character, then + * it already is fully qualified. Otherwise (package name or + * basic entity name) it is prefixed with the namespace. The + * namespace is derived from the implicit whisk properties. + * + * @param name to fully qualify iff it is not already fully qualified + * @param wp whisk properties + * @return name if it is fully qualified else a name fully qualified for a namespace + */ + def fqn(name: String)(implicit wp: WskProps) = { + val sep = "/" // Namespace.PATHSEP + if (name.startsWith(sep) || name.count(_ == sep(0)) == 2) name + else s"$sep${wp.namespace}$sep$name" + } + + /** + * Resolves a namespace. If argument is defined, it takes precedence. + * else resolve to namespace in implicit WskProps. + * + * @param namespace an optional namespace + * @param wp whisk properties + * @return resolved namespace + */ + def resolve(namespace: Option[String])(implicit wp: WskProps) = { + val sep = "/" // Namespace.PATHSEP + namespace getOrElse s"$sep${wp.namespace}" + } +} + +trait ListOrGetFromCollection extends FullyQualifiedNames { + self: RunWskCmd => + + protected val noun: String + + /** + * List entities in collection. + * + * @param namespace (optional) if specified must be fully qualified namespace + * @param expectedExitCode (optional) the expected exit code for the command + * if the code is anything but DONTCARE_EXIT, assert the code is as expected + */ + def list(namespace: Option[String] = None, + limit: Option[Int] = None, + nameSort: Option[Boolean] = None, + expectedExitCode: Int = SUCCESS_EXIT)(implicit wp: WskProps): RunResult = { + val params = Seq(noun, "list", resolve(namespace), "--auth", wp.authKey) ++ { + limit map { l => + Seq("--limit", l.toString) + } getOrElse Seq() + } ++ { + nameSort map { n => + Seq("--name-sort") + } getOrElse Seq() + } + cli(wp.overrides ++ params, expectedExitCode) + } + + /** + * Gets entity from collection. + * + * @param name either a fully qualified name or a simple entity name + * @param expectedExitCode (optional) the expected exit code for the command + * if the code is anything but DONTCARE_EXIT, assert the code is as expected + */ + def get(name: String, + expectedExitCode: Int = SUCCESS_EXIT, + summary: Boolean = false, + fieldFilter: Option[String] = None, + url: Option[Boolean] = None)(implicit wp: WskProps): RunResult = { + val params = Seq(noun, "get", "--auth", wp.authKey) ++ + Seq(fqn(name)) ++ { if (summary) Seq("--summary") else Seq() } ++ { + fieldFilter map { f => + Seq(f) + } getOrElse Seq() + } ++ { + url map { u => + Seq("--url") + } getOrElse Seq() + } + + cli(wp.overrides ++ params, expectedExitCode) + } +} + +trait DeleteFromCollection extends FullyQualifiedNames { + self: RunWskCmd => + + protected val noun: String + + /** + * Deletes entity from collection. + * + * @param name either a fully qualified name or a simple entity name + * @param expectedExitCode (optional) the expected exit code for the command + * if the code is anything but DONTCARE_EXIT, assert the code is as expected + */ + def delete(name: String, expectedExitCode: Int = SUCCESS_EXIT)(implicit wp: WskProps): RunResult = { + cli(wp.overrides ++ Seq(noun, "delete", "--auth", wp.authKey, fqn(name)), expectedExitCode) + } + + /** + * Deletes entity from collection but does not assert that the command succeeds. + * Use this if deleting an entity that may not exist and it is OK if it does not. + * + * @param name either a fully qualified name or a simple entity name + */ + def sanitize(name: String)(implicit wp: WskProps): RunResult = { + delete(name, DONTCARE_EXIT) + } +} + +trait BaseAction extends RunWskCmd with DeleteFromCollection with ListOrGetFromCollection { + + def create(name: String, + artifact: Option[String], + kind: Option[String] = None, + main: Option[String] = None, + docker: Option[String] = None, + parameters: Map[String, JsValue] = Map(), + annotations: Map[String, JsValue] = Map(), + parameterFile: Option[String] = None, + annotationFile: Option[String] = None, + timeout: Option[Duration] = None, + memory: Option[ByteSize] = None, + logsize: Option[ByteSize] = None, + shared: Option[Boolean] = None, + update: Boolean = false, + web: Option[String] = None, + expectedExitCode: Int = SUCCESS_EXIT)(implicit wp: WskProps): RunResult + + def invoke(name: String, + parameters: Map[String, JsValue] = Map(), + parameterFile: Option[String] = None, + blocking: Boolean = false, + result: Boolean = false, + expectedExitCode: Int = SUCCESS_EXIT)(implicit wp: WskProps): RunResult +} + +trait BasePackage extends RunWskCmd with DeleteFromCollection with ListOrGetFromCollection { + + def create(name: String, + parameters: Map[String, JsValue] = Map(), + annotations: Map[String, JsValue] = Map(), + parameterFile: Option[String] = None, + annotationFile: Option[String] = None, + shared: Option[Boolean] = None, + update: Boolean = false, + expectedExitCode: Int = SUCCESS_EXIT)(implicit wp: WskProps): RunResult + + def bind(provider: String, + name: String, + parameters: Map[String, JsValue] = Map(), + annotations: Map[String, JsValue] = Map(), + expectedExitCode: Int = SUCCESS_EXIT)(implicit wp: WskProps): RunResult +} + +trait BaseTrigger extends RunWskCmd with DeleteFromCollection with ListOrGetFromCollection { + + def create(name: String, + parameters: Map[String, JsValue] = Map(), + annotations: Map[String, JsValue] = Map(), + parameterFile: Option[String] = None, + annotationFile: Option[String] = None, + feed: Option[String] = None, + shared: Option[Boolean] = None, + update: Boolean = false, + expectedExitCode: Int = SUCCESS_EXIT)(implicit wp: WskProps): RunResult + + def fire(name: String, + parameters: Map[String, JsValue] = Map(), + parameterFile: Option[String] = None, + expectedExitCode: Int = SUCCESS_EXIT)(implicit wp: WskProps): RunResult +} + +trait BaseRule extends RunWskCmd with DeleteFromCollection with ListOrGetFromCollection { + + def create(name: String, + trigger: String, + action: String, + annotations: Map[String, JsValue] = Map(), + shared: Option[Boolean] = None, + update: Boolean = false, + expectedExitCode: Int = SUCCESS_EXIT)(implicit wp: WskProps): RunResult + + def enable(name: String, expectedExitCode: Int = SUCCESS_EXIT)(implicit wp: WskProps): RunResult + + def disable(name: String, expectedExitCode: Int = SUCCESS_EXIT)(implicit wp: WskProps): RunResult + + def state(name: String, expectedExitCode: Int = SUCCESS_EXIT)(implicit wp: WskProps): RunResult +} + +trait BaseActivation extends RunWskCmd { + + def extractActivationId(result: RunResult): Option[String] + + def pollFor(N: Int, + entity: Option[String], + limit: Option[Int] = None, + since: Option[Instant], + retries: Int, + pollPeriod: Duration = 1.second)(implicit wp: WskProps): Seq[String] + + def waitForActivation(activationId: String, initialWait: Duration, pollPeriod: Duration, totalWait: Duration)( + implicit wp: WskProps): Either[String, JsObject] + + def get(activationId: Option[String] = None, + expectedExitCode: Int = SUCCESS_EXIT, + fieldFilter: Option[String] = None, + last: Option[Boolean] = None)(implicit wp: WskProps): RunResult + + def console(duration: Duration, since: Option[Duration] = None, expectedExitCode: Int = SUCCESS_EXIT)( + implicit wp: WskProps): RunResult + + def logs(activationId: Option[String] = None, expectedExitCode: Int = SUCCESS_EXIT, last: Option[Boolean] = None)( + implicit wp: WskProps): RunResult + + def result(activationId: Option[String] = None, expectedExitCode: Int = SUCCESS_EXIT, last: Option[Boolean] = None)( + implicit wp: WskProps): RunResult + +} + +trait BaseNamespace extends RunWskCmd { + + def list(expectedExitCode: Int = SUCCESS_EXIT, nameSort: Option[Boolean] = None)(implicit wp: WskProps): RunResult + + def whois()(implicit wskprops: WskProps): String + + def get(namespace: Option[String] = None, expectedExitCode: Int, nameSort: Option[Boolean] = None)( + implicit wp: WskProps): RunResult +} + +trait BaseApi extends RunWskCmd { + + def create(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] = None)(implicit wp: WskProps): RunResult + + def list(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] = None)(implicit wp: WskProps): RunResult + + def get(basepathOrApiName: Option[String] = None, + full: Option[Boolean] = None, + expectedExitCode: Int = SUCCESS_EXIT, + cliCfgFile: Option[String] = None, + format: Option[String] = None)(implicit wp: WskProps): RunResult + + def delete(basepathOrApiName: String, + relpath: Option[String] = None, + operation: Option[String] = None, + expectedExitCode: Int = SUCCESS_EXIT, + cliCfgFile: Option[String] = None)(implicit wp: WskProps): RunResult +} + +trait RunWskCmd extends Matchers { + + /** + * The base command to run. + */ + def baseCommand = Wsk.baseCommand Review comment: Here you make a call out to the Wsk singleton object that is defined in Wsk.scala. Since this file is the base for Wsk to inherit from, I don't think it should reference Wsk.scala at all. ---------------------------------------------------------------- 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
