blob: 9a31e376515fdb1ea4b84c811b7d71e40222db58 [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 common
import java.io.File
import scala.collection.JavaConverters._
import scala.collection.mutable.Buffer
import org.scalatest.Matchers
import TestUtils._
import scala.concurrent.duration._
import scala.collection.mutable
trait RunCliCmd extends Matchers {
/**
* The base command to run. This returns a new mutable buffer, intended for building the rest of the command line.
*/
def baseCommand: Buffer[String]
val prohibitAuthOverride = false
/**
* Delegates execution of the command to an underlying implementation.
*
* @param expectedExitCode the expected exit code
* @param dir the working directory
* @param env an environment for the command
* @param fileStdin argument file to redirect to stdin (optional)
* @param params parameters to pass on the command line
* @return an instance of RunResult
*/
def runCmd(expectedExitCode: Int,
dir: File,
env: Map[String, String],
fileStdin: Option[File],
params: Seq[String]): RunResult = {
TestUtils.runCmd(expectedExitCode, dir, TestUtils.logger, env.asJava, fileStdin.getOrElse(null), params: _*)
}
/**
* Runs a command wsk [params] where the arguments come in as a sequence.
*
* @return RunResult which contains stdout, stderr, exit code
*/
def cli(params: Seq[String],
expectedExitCode: Int = SUCCESS_EXIT,
verbose: Boolean = false,
env: Map[String, String] = Map("WSK_CONFIG_FILE" -> ""),
workingDir: File = new File("."),
stdinFile: Option[File] = None,
showCmd: Boolean = false,
hideFromOutput: Seq[String] = Seq.empty,
retriesOnError: Int = 3): RunResult = {
require(retriesOnError >= 0, "retry count on network error must not be negative")
val args = baseCommand
if (verbose) args += "--verbose"
val finalParams = if (!prohibitAuthOverride) { params } else {
params.filter(s =>
!s.equals("--auth") && !(params.indexOf(s) > 0 && params(params.indexOf(s) - 1).equals("--auth")))
}
args.appendAll(finalParams)
if (showCmd) println(args.mkString(" "))
val rr =
retry(0, retriesOnError, () => runCmd(DONTCARE_EXIT, workingDir, sys.env ++ env, stdinFile, args.toSeq))
withClue(hideStr(reportFailure(args, expectedExitCode, rr).toString(), hideFromOutput)) {
if (expectedExitCode != TestUtils.DONTCARE_EXIT) {
val ok = (rr.exitCode == expectedExitCode) || (expectedExitCode == TestUtils.ANY_ERROR_EXIT && rr.exitCode != 0)
if (!ok) {
rr.exitCode shouldBe expectedExitCode
}
}
}
rr
}
/** Retries cmd on network error exit. */
private def retry(i: Int, N: Int, cmd: () => RunResult): RunResult = {
val rr = cmd()
if (rr.exitCode != SUCCESS_EXIT && i < N) {
Thread.sleep(1.second.toMillis)
println(s"command will retry to due to network error: $rr")
retry(i + 1, N, cmd)
} else rr
}
/**
* Takes a string and a list of sensitive strings. Any sensistive string found in
* the target string will be replaced with "XXXXX", returning the processed string.
*/
private def hideStr(str: String, hideThese: Seq[String]): String = {
// Iterate through each string to hide, replacing it in the target string (str)
hideThese.fold(str)((updatedStr, replaceThis) => updatedStr.replace(replaceThis, "XXXXX"))
}
private def reportFailure(args: Buffer[String], ec: Integer, rr: RunResult) = {
val s = new StringBuilder()
s.append(args.mkString(" ") + "\n")
if (rr.stdout.nonEmpty) s.append(rr.stdout + "\n")
if (rr.stderr.nonEmpty) s.append(rr.stderr)
s.append("exit code:")
}
}
object WskAdmin {
val wskadmin = new RunCliCmd {
override def baseCommand: mutable.Buffer[String] = WskAdmin.baseCommand
}
private val binDir = WhiskProperties.getFileRelativeToWhiskHome("bin")
private val binaryName = "wskadmin"
def exists = {
val dir = binDir
val exec = new File(dir, binaryName)
assert(dir.exists, s"did not find $dir")
assert(exec.exists, s"did not find $exec")
}
def baseCommand = {
Buffer(WhiskProperties.python, new File(binDir, binaryName).toString)
}
def listKeys(namespace: String, pick: Integer = 1): List[(String, String)] = {
wskadmin
.cli(Seq("user", "list", namespace, "--pick", pick.toString))
.stdout
.split("\n")
.map("""\s+""".r.split(_))
.map(parts => (parts(0), parts(1)))
.toList
}
}