This is an automated email from the ASF dual-hosted git repository. mdeuser pushed a commit to branch master in repository https://gitbox.apache.org/repos/asf/incubator-openwhisk.git
commit 474d2e584b158326a554d6475f4f1ea6befcb247 Author: Rodric Rabbah <[email protected]> AuthorDate: Sun Jun 17 11:58:52 2018 -0400 Allow for commands to on network error. Add test for run cmd with retry. --- tests/src/test/scala/common/RunCliCmd.scala | 32 +++++--- .../test/scala/whisk/common/RunCliCmdTests.scala | 90 ++++++++++++++++++++++ 2 files changed, 113 insertions(+), 9 deletions(-) diff --git a/tests/src/test/scala/common/RunCliCmd.scala b/tests/src/test/scala/common/RunCliCmd.scala index a7c0c24..682e7c6 100644 --- a/tests/src/test/scala/common/RunCliCmd.scala +++ b/tests/src/test/scala/common/RunCliCmd.scala @@ -23,7 +23,6 @@ import scala.collection.JavaConversions.mapAsJavaMap import scala.collection.mutable.Buffer import org.scalatest.Matchers import TestUtils._ -import whisk.utils.retry import scala.concurrent.duration._ import scala.collection.mutable @@ -35,6 +34,24 @@ trait RunCliCmd extends Matchers { def baseCommand: Buffer[String] /** + * 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, 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 @@ -48,20 +65,16 @@ trait RunCliCmd extends Matchers { showCmd: Boolean = false, hideFromOutput: Seq[String] = Seq(), retriesOnNetworkError: Int = 3): RunResult = { + require(retriesOnNetworkError >= 0, "retry count on network error must not be negative") + val args = baseCommand if (verbose) args += "--verbose" if (showCmd) println(args.mkString(" ") + " " + params.mkString(" ")) + val rr = retry( 0, retriesOnNetworkError, - () => - TestUtils.runCmd( - DONTCARE_EXIT, - workingDir, - TestUtils.logger, - sys.env ++ env, - stdinFile.getOrElse(null), - args ++ params: _*)) + () => runCmd(DONTCARE_EXIT, workingDir, sys.env ++ env, stdinFile, args ++ params)) withClue(hideStr(reportFailure(args ++ params, expectedExitCode, rr).toString(), hideFromOutput)) { if (expectedExitCode != TestUtils.DONTCARE_EXIT) { @@ -83,6 +96,7 @@ trait RunCliCmd extends Matchers { 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 diff --git a/tests/src/test/scala/whisk/common/RunCliCmdTests.scala b/tests/src/test/scala/whisk/common/RunCliCmdTests.scala new file mode 100644 index 0000000..548aa06 --- /dev/null +++ b/tests/src/test/scala/whisk/common/RunCliCmdTests.scala @@ -0,0 +1,90 @@ +/* + * 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.common + +import java.io.File + +import org.junit.runner.RunWith +import org.scalatest.{BeforeAndAfterEach, FlatSpec} +import org.scalatest.junit.JUnitRunner +import common.RunCliCmd +import common.TestUtils._ + +import scala.collection.mutable.Buffer + +@RunWith(classOf[JUnitRunner]) +class RunCliCmdTests extends FlatSpec with RunCliCmd with BeforeAndAfterEach { + + case class TestRunResult(code: Int) extends RunResult(code, "", "") + val defaultRR = TestRunResult(0) + + override def baseCommand = Buffer.empty + + override def runCmd(expectedExitCode: Int, + dir: File, + env: Map[String, String], + fileStdin: Option[File], + params: Seq[String]): RunResult = { + cmdCount += 1 + rr.getOrElse(defaultRR) + } + + override def beforeEach() = { + rr = None + cmdCount = 0 + } + + var rr: Option[TestRunResult] = None // optional run result override per test + var cmdCount = 0 + + it should "retry commands that experience network errors" in { + Seq(ANY_ERROR_EXIT, DONTCARE_EXIT, NETWORK_ERROR_EXIT).foreach { code => + cmdCount = 0 + + rr = Some(TestRunResult(NETWORK_ERROR_EXIT)) + noException shouldBe thrownBy { + cli(Seq.empty, expectedExitCode = code) + } + + cmdCount shouldBe 3 + 1 + } + } + + it should "not retry commands if retry is disabled" in { + rr = Some(TestRunResult(NETWORK_ERROR_EXIT)) + noException shouldBe thrownBy { + cli(Seq.empty, expectedExitCode = ANY_ERROR_EXIT, retriesOnNetworkError = 0) + } + + cmdCount shouldBe 1 + } + + it should "not retry commands if failure is not retriable" in { + Seq(MISUSE_EXIT, ERROR_EXIT, SUCCESS_EXIT).foreach { code => + cmdCount = 0 + + rr = Some(TestRunResult(code)) + noException shouldBe thrownBy { + cli(Seq.empty, expectedExitCode = DONTCARE_EXIT, retriesOnNetworkError = 3) + } + + cmdCount shouldBe 1 + } + } + +}
