houshengbo closed pull request #2922: Replace non cli tests with REST implementation URL: https://github.com/apache/incubator-openwhisk/pull/2922
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/resources/application.conf b/tests/src/test/resources/application.conf index 03b3e0df5b..39960d76af 100644 --- a/tests/src/test/resources/application.conf +++ b/tests/src/test/resources/application.conf @@ -1,5 +1,3 @@ -akka.ssl-config.hostnameVerifierClass = common.rest.AcceptAllHostNameVerifier - whisk.spi { SimpleSpi = whisk.spi.SimpleSpiImpl MissingSpi = whisk.spi.MissingImpl diff --git a/tests/src/test/scala/common/TestUtils.java b/tests/src/test/scala/common/TestUtils.java index 0042445469..15fb11d862 100644 --- a/tests/src/test/scala/common/TestUtils.java +++ b/tests/src/test/scala/common/TestUtils.java @@ -65,11 +65,15 @@ public static final int UNAUTHORIZED = 145; // 401 - 256 = 145 public static final int FORBIDDEN = 147; // 403 - 256 = 147 public static final int NOT_FOUND = 148; // 404 - 256 = 148 + public static final int NOT_FOUND_HTTP = 404; public static final int NOT_ALLOWED = 149; // 405 - 256 = 149 public static final int CONFLICT = 153; // 409 - 256 = 153 public static final int TOO_LARGE = 157; // 413 - 256 = 157 + public static final int TOO_LARGE_HTTP = 413; public static final int THROTTLED = 173; // 429 (TOO_MANY_REQUESTS) - 256 = 173 + public static final int THROTTLED_HTTP = 429; public static final int APP_ERROR = 246; // 502 - 256 = 246 + public static final int APP_ERROR_HTTP = 502; public static final int TIMEOUT = 246; // 502 (GATEWAY_TIMEOUT) - 256 = 246 private static final File catalogDir = WhiskProperties.getFileRelativeToWhiskHome("catalog"); diff --git a/tests/src/test/scala/common/WhiskProperties.java b/tests/src/test/scala/common/WhiskProperties.java index 915ed6a761..781f0bf91e 100644 --- a/tests/src/test/scala/common/WhiskProperties.java +++ b/tests/src/test/scala/common/WhiskProperties.java @@ -200,11 +200,20 @@ public static String getRouterHost() { return whiskProperties.getProperty("router.host"); } + public static String getApiProto() { + return whiskProperties.getProperty("whisk.api.host.proto"); + } + + public static String getApiHost() { + return whiskProperties.getProperty("whisk.api.host.name"); + } + + public static String getApiPort() { + return whiskProperties.getProperty("whisk.api.host.port"); + } + public static String getApiHostForAction() { - String proto = whiskProperties.getProperty("whisk.api.host.proto"); - String port = whiskProperties.getProperty("whisk.api.host.port"); - String host = whiskProperties.getProperty("whisk.api.host.name"); - return proto + "://" + host + ":" + port; + return getApiProto() + "://" + getApiHost() + ":" + getApiPort(); } public static String getApiHostForClient(String subdomain, boolean includeProtocol) { @@ -235,11 +244,11 @@ public static int getControllerBasePort() { } public static String getBaseControllerHost() { - return getControllerHosts().split(",")[0]; + return getControllerHosts().split(",")[0]; } public static String getBaseControllerAddress() { - return getBaseControllerHost() + ":" + getControllerBasePort(); + return getBaseControllerHost() + ":" + getControllerBasePort(); } public static int getMaxActionInvokesPerMinute() { diff --git a/tests/src/test/scala/common/rest/WskRest.scala b/tests/src/test/scala/common/rest/WskRest.scala index 199d7d6139..5767072331 100644 --- a/tests/src/test/scala/common/rest/WskRest.scala +++ b/tests/src/test/scala/common/rest/WskRest.scala @@ -35,12 +35,14 @@ import scala.collection.mutable.Buffer import scala.collection.immutable.Seq import scala.concurrent.duration.Duration import scala.concurrent.duration.DurationInt -import scala.concurrent.Future import scala.language.postfixOps import scala.util.Failure import scala.util.Success import scala.util.Try import scala.util.{Failure, Success} +import akka.stream.scaladsl.{Keep, Sink, Source} +import akka.stream.{OverflowStrategy, QueueOfferResult} +import scala.concurrent.{Future, Promise} import akka.http.scaladsl.model.StatusCode import akka.http.scaladsl.model.StatusCodes.Accepted @@ -62,6 +64,7 @@ import akka.http.scaladsl.model.HttpMethods.GET import akka.http.scaladsl.model.HttpMethods.POST import akka.http.scaladsl.model.HttpMethods.PUT import akka.http.scaladsl.HttpsConnectionContext +import akka.http.scaladsl.settings.ConnectionPoolSettings import akka.stream.ActorMaterializer @@ -95,7 +98,7 @@ import javax.net.ssl.{HostnameVerifier, KeyManager, SSLContext, SSLSession, X509 import com.typesafe.sslconfig.akka.AkkaSSLConfig class AcceptAllHostNameVerifier extends HostnameVerifier { - def verify(s: String, sslSession: SSLSession) = true + override def verify(s: String, sslSession: SSLSession): Boolean = true } object SSL { @@ -374,14 +377,23 @@ class WskRestAction } } else { bodyContent = bodyContent ++ Map("exec" -> exec.toJson, "parameters" -> params, "annotations" -> annos) + } - bodyContent = bodyContent ++ { - timeout map { t => - Map("limits" -> JsObject("timeout" -> t.toMillis.toJson)) - } getOrElse Map[String, JsValue]() - } + val limits = Map[String, JsValue]() ++ { + timeout map { t => + Map("timeout" -> t.toMillis.toJson) + } getOrElse Map[String, JsValue]() + } ++ { + logsize map { log => + Map("logs" -> log.toMB.toJson) + } getOrElse Map[String, JsValue]() + } ++ { + memory map { m => + Map("memory" -> m.toMB.toJson) + } getOrElse Map[String, JsValue]() } + bodyContent = if (!limits.isEmpty) bodyContent ++ Map("limits" -> limits.toJson) else bodyContent val path = Path(s"$basePath/namespaces/$namespace/$noun/$actName") val resp = if (update) requestEntity(PUT, path, Map("overwrite" -> "true"), Some(JsObject(bodyContent).toString)) @@ -1138,16 +1150,21 @@ class RunWskRestCmd() extends FlatSpec with RunWskCmd with Matchers with ScalaFu implicit val config = PatienceConfig(100 seconds, 15 milliseconds) implicit val materializer = ActorMaterializer() - val whiskRestUrl = Uri(WhiskProperties.getApiHostForAction) + val queueSize = 10 + val maxOpenRequest = 1024 val basePath = Path("/api/v1") val sslConfig = AkkaSSLConfig().mapSettings { s => - s.withLoose(s.loose.withAcceptAnyCertificate(true).withDisableHostnameVerification(true)) + s.withHostnameVerifierClass(classOf[AcceptAllHostNameVerifier].asInstanceOf[Class[HostnameVerifier]]) } + val connectionContext = new HttpsConnectionContext(SSL.nonValidatingContext, Some(sslConfig)) def isStatusCodeExpected(expectedExitCode: Int, statusCode: Int): Boolean = { - return statusCode == expectedExitCode + if ((expectedExitCode != DONTCARE_EXIT) && (expectedExitCode != ANY_ERROR_EXIT)) + statusCode == expectedExitCode + else + true } def validateStatusCode(expectedExitCode: Int, statusCode: Int) = { @@ -1175,15 +1192,38 @@ class RunWskRestCmd() extends FlatSpec with RunWskCmd with Matchers with ScalaFu HttpEntity(ContentTypes.`application/json`, b) } getOrElse HttpEntity(ContentTypes.`application/json`, "") val request = HttpRequest(method, uri, List(Authorization(creds)), entity = entity) - - Http().singleRequest(request, connectionContext) + val connectionPoolSettings = ConnectionPoolSettings(actorSystem).withMaxOpenRequests(maxOpenRequest) + val pool = Http().cachedHostConnectionPoolHttps[Promise[HttpResponse]]( + host = WhiskProperties.getApiHost, + connectionContext = connectionContext, + settings = connectionPoolSettings) + val queue = Source + .queue[(HttpRequest, Promise[HttpResponse])](queueSize, OverflowStrategy.dropNew) + .via(pool) + .toMat(Sink.foreach({ + case ((Success(resp), p)) => p.success(resp) + case ((Failure(e), p)) => p.failure(e) + }))(Keep.left) + .run + + val promise = Promise[HttpResponse] + val responsePromise = Promise[HttpResponse]() + queue.offer(request -> responsePromise).flatMap { + case QueueOfferResult.Enqueued => responsePromise.future + case QueueOfferResult.Dropped => + Future.failed(new RuntimeException("Queue has overflowed. Please try again later.")) + case QueueOfferResult.Failure(ex) => Future.failed(ex) + case QueueOfferResult.QueueClosed => + Future.failed( + new RuntimeException("Queue was closed (pool shut down) while running the request. Please try again later.")) + } } def requestEntity(method: HttpMethod, path: Path, params: Map[String, String] = Map(), body: Option[String] = None, - whiskUrl: Uri = whiskRestUrl)(implicit wp: WskProps): HttpResponse = { + whiskUrl: Uri = Uri(""))(implicit wp: WskProps): HttpResponse = { val creds = getBasicHttpCredentials(wp) request(method, whiskUrl.withPath(path).withQuery(Uri.Query(params)), body, creds = creds).futureValue } @@ -1298,7 +1338,7 @@ class RunWskRestCmd() extends FlatSpec with RunWskCmd with Matchers with ScalaFu Some(FileUtils.readFileToString(new File(pf))) } getOrElse Some(parameters.toJson.toString()) val resp = requestEntity(POST, path, paramMap, input) - val r = new RestResult(resp.status.intValue, getRespData(resp)) + val r = new RestResult(resp.status.intValue, getRespData(resp), blocking) // If the statusCode does not not equal to expectedExitCode, it is acceptable that the statusCode // equals to 200 for the case that either blocking or result is set to true. if (!isStatusCodeExpected(expectedExitCode, r.statusCode.intValue)) { @@ -1393,8 +1433,8 @@ object RestResult { obj.fields.get(key).map(_.convertTo[Vector[JsObject]]).getOrElse(Vector(JsObject())) } - def convertStausCodeToExitCode(statusCode: StatusCode): Int = { - if (statusCode == OK) + def convertStausCodeToExitCode(statusCode: StatusCode, blocking: Boolean = false): Int = { + if ((statusCode == OK) || (!blocking && (statusCode == Accepted))) return 0 if (statusCode.intValue < BadRequest.intValue) statusCode.intValue else statusCode.intValue - codeConversion } @@ -1408,9 +1448,9 @@ object RestResult { } } -class RestResult(var statusCode: StatusCode, var respData: String = "") +class RestResult(var statusCode: StatusCode, var respData: String = "", blocking: Boolean = false) extends RunResult( - RestResult.convertStausCodeToExitCode(statusCode), + RestResult.convertStausCodeToExitCode(statusCode, blocking), respData, RestResult.convertHttpResponseToStderr(respData)) { diff --git a/tests/src/test/scala/ha/ShootComponentsTests.scala b/tests/src/test/scala/ha/ShootComponentsTests.scala index 4b28ded8ed..fa1aba121e 100644 --- a/tests/src/test/scala/ha/ShootComponentsTests.scala +++ b/tests/src/test/scala/ha/ShootComponentsTests.scala @@ -36,7 +36,7 @@ import akka.http.scaladsl.unmarshalling.Unmarshal import akka.stream.ActorMaterializer import common.TestUtils import common.WhiskProperties -import common.Wsk +import common.rest.WskRest import common.WskActorSystem import common.WskProps import common.WskTestHelpers @@ -47,7 +47,7 @@ import whisk.utils.retry class ShootComponentsTests extends FlatSpec with Matchers with WskTestHelpers with ScalaFutures with WskActorSystem { implicit val wskprops = WskProps() - val wsk = new Wsk + val wsk = new WskRest val defaultAction = Some(TestUtils.getTestActionFilename("hello.js")) implicit val materializer = ActorMaterializer() diff --git a/tests/src/test/scala/limits/ThrottleTests.scala b/tests/src/test/scala/limits/ThrottleTests.scala index 8da66e811d..eef21eee3a 100644 --- a/tests/src/test/scala/limits/ThrottleTests.scala +++ b/tests/src/test/scala/limits/ThrottleTests.scala @@ -34,7 +34,7 @@ import common.TestHelpers import common.TestUtils import common.TestUtils._ import common.WhiskProperties -import common.Wsk +import common.rest.WskRest import common.WskActorSystem import common.WskProps import common.WskTestHelpers @@ -65,7 +65,7 @@ class ThrottleTests implicit val testConfig = PatienceConfig(5.minutes) implicit val wskprops = WskProps() - val wsk = new Wsk + val wsk = new WskRest val defaultAction = Some(TestUtils.getTestActionFilename("hello.js")) val throttleWindow = 1.minute @@ -296,7 +296,7 @@ class NamespaceSpecificThrottleTests with LocalHelper { val wskadmin = new RunWskAdminCmd {} - val wsk = new Wsk + val wsk = new WskRest val defaultAction = Some(TestUtils.getTestActionFilename("hello.js")) @@ -346,10 +346,10 @@ class NamespaceSpecificThrottleTests trigger.create(triggerName) } - wsk.action.invoke(actionName, expectedExitCode = TestUtils.THROTTLED).stderr should { + wsk.action.invoke(actionName, expectedExitCode = TestUtils.THROTTLED_HTTP).stderr should { include(prefix(tooManyRequests(0, 0))) and include("allowed: 0") } - wsk.trigger.fire(triggerName, expectedExitCode = TestUtils.THROTTLED).stderr should { + wsk.trigger.fire(triggerName, expectedExitCode = TestUtils.THROTTLED_HTTP).stderr should { include(prefix(tooManyRequests(0, 0))) and include("allowed: 0") } } @@ -401,7 +401,7 @@ class NamespaceSpecificThrottleTests action.create(actionName, defaultAction) } - wsk.action.invoke(actionName, expectedExitCode = TestUtils.THROTTLED).stderr should { + wsk.action.invoke(actionName, expectedExitCode = TestUtils.THROTTLED_HTTP).stderr should { include(prefix(tooManyConcurrentRequests(0, 0))) and include("allowed: 0") } } diff --git a/tests/src/test/scala/services/HeadersTests.scala b/tests/src/test/scala/services/HeadersTests.scala index 6d0b4c267f..f3184c87f1 100644 --- a/tests/src/test/scala/services/HeadersTests.scala +++ b/tests/src/test/scala/services/HeadersTests.scala @@ -31,7 +31,7 @@ import org.scalatest.time.Span.convertDurationToSpan import common.TestUtils import common.WhiskProperties -import common.Wsk +import common.rest.WskRest import common.WskProps import common.WskTestHelpers @@ -82,7 +82,7 @@ class HeadersTests extends FlatSpec with Matchers with ScalaFutures with WskActo val basePath = Path("/api/v1") implicit val wskprops = WskProps() - val wsk = new Wsk + val wsk = new WskRest /** * Checks, if the required headers are in the list of all headers. diff --git a/tests/src/test/scala/system/rest/ActionSchemaTests.scala b/tests/src/test/scala/system/rest/ActionSchemaTests.scala index 9b0560aec1..b88b231887 100644 --- a/tests/src/test/scala/system/rest/ActionSchemaTests.scala +++ b/tests/src/test/scala/system/rest/ActionSchemaTests.scala @@ -29,7 +29,7 @@ import com.jayway.restassured.RestAssured import common.TestUtils import common.WhiskProperties -import common.Wsk +import common.rest.WskRest import common.WskProps import common.WskTestHelpers import spray.json.JsArray @@ -43,7 +43,7 @@ import spray.json.pimpString class ActionSchemaTests extends FlatSpec with Matchers with RestUtil with JsonSchema with WskTestHelpers { implicit val wskprops = WskProps() - val wsk = new Wsk + val wsk = new WskRest val guestNamespace = wskprops.namespace it should "respond to GET /actions as documented in swagger" in withAssetCleaner(wskprops) { (wp, assetHelper) => diff --git a/tests/src/test/scala/whisk/core/admin/WskAdminTests.scala b/tests/src/test/scala/whisk/core/admin/WskAdminTests.scala index c42e2e8cf9..b2bc3b4289 100644 --- a/tests/src/test/scala/whisk/core/admin/WskAdminTests.scala +++ b/tests/src/test/scala/whisk/core/admin/WskAdminTests.scala @@ -25,7 +25,7 @@ import org.scalatest.junit.JUnitRunner import common.RunWskAdminCmd import common.TestHelpers -import common.Wsk +import common.rest.WskRest import common.WskAdmin import common.WskProps import whisk.core.entity.AuthKey @@ -87,7 +87,7 @@ class WskAdminTests extends TestHelpers with Matchers { it should "verify guest account installed correctly" in { val wskadmin = new RunWskAdminCmd {} implicit val wskprops = WskProps() - val wsk = new Wsk + val wsk = new WskRest val ns = wsk.namespace.whois() wskadmin.cli(Seq("user", "get", ns)).stdout.trim should be(wskprops.authKey) } diff --git a/tests/src/test/scala/whisk/core/database/test/CacheConcurrencyTests.scala b/tests/src/test/scala/whisk/core/database/test/CacheConcurrencyTests.scala index 7bc56ba7d6..66f3ef4441 100644 --- a/tests/src/test/scala/whisk/core/database/test/CacheConcurrencyTests.scala +++ b/tests/src/test/scala/whisk/core/database/test/CacheConcurrencyTests.scala @@ -27,7 +27,7 @@ import org.scalatest.junit.JUnitRunner import common.TestUtils import common.TestUtils._ -import common.Wsk +import common.rest.WskRest import common.WskProps import common.WskTestHelpers import spray.json.JsString @@ -40,7 +40,7 @@ class CacheConcurrencyTests extends FlatSpec with WskTestHelpers with BeforeAndA implicit private val transId = TransactionId.testing implicit private val wp = WskProps() - private val wsk = new Wsk + private val wsk = new WskRest val nExternalIters = 1 val nInternalIters = 5 @@ -97,7 +97,7 @@ class CacheConcurrencyTests extends FlatSpec with WskTestHelpers with BeforeAndA } run("get after delete") { name => - wsk.action.get(name, expectedExitCode = NOT_FOUND) + wsk.action.get(name, expectedExitCode = NOT_FOUND_HTTP) } run("recreate") { name => diff --git a/tests/src/test/scala/whisk/core/limits/ActionLimitsTests.scala b/tests/src/test/scala/whisk/core/limits/ActionLimitsTests.scala index 4ac38f267a..ca1337a186 100644 --- a/tests/src/test/scala/whisk/core/limits/ActionLimitsTests.scala +++ b/tests/src/test/scala/whisk/core/limits/ActionLimitsTests.scala @@ -29,9 +29,9 @@ import org.scalatest.junit.JUnitRunner import common.ActivationResult import common.TestHelpers import common.TestUtils -import common.TestUtils.TOO_LARGE +import common.TestUtils.TOO_LARGE_HTTP import common.WhiskProperties -import common.Wsk +import common.rest.WskRest import common.WskProps import common.WskTestHelpers import spray.json._ @@ -47,7 +47,7 @@ import whisk.http.Messages class ActionLimitsTests extends TestHelpers with WskTestHelpers { implicit val wskprops = WskProps() - val wsk = new Wsk() + val wsk = new WskRest val defaultDosAction = TestUtils.getTestActionFilename("timeout.js") val allowedActionDuration = 10 seconds @@ -148,10 +148,10 @@ class ActionLimitsTests extends TestHelpers with WskTestHelpers { // this tests an active ack failure to post from invoker val args = Map("size" -> (allowedSize + 1).toJson, "char" -> "a".toJson) - val code = if (blocking) TestUtils.APP_ERROR else TestUtils.SUCCESS_EXIT + val code = if (blocking) TestUtils.APP_ERROR_HTTP else TestUtils.ACCEPTED val rr = wsk.action.invoke(name, args, blocking = blocking, expectedExitCode = code) if (blocking) { - checkResponse(wsk.parseJsonString(rr.stderr).convertTo[ActivationResult]) + checkResponse(wsk.parseJsonString(rr.respData).convertTo[ActivationResult]) } else { withActivation(wsk.activation, rr, totalWait = 120 seconds) { checkResponse(_) } } @@ -187,7 +187,7 @@ class ActionLimitsTests extends TestHelpers with WskTestHelpers { pw.close assetHelper.withCleaner(wsk.action, name, confirmDelete = false) { (action, _) => - action.create(name, Some(actionCode.getAbsolutePath), expectedExitCode = TOO_LARGE) + action.create(name, Some(actionCode.getAbsolutePath), expectedExitCode = TOO_LARGE_HTTP) } actionCode.delete diff --git a/tests/src/test/scala/whisk/core/limits/MaxActionDurationTests.scala b/tests/src/test/scala/whisk/core/limits/MaxActionDurationTests.scala index 261e300d99..dba2eebffe 100644 --- a/tests/src/test/scala/whisk/core/limits/MaxActionDurationTests.scala +++ b/tests/src/test/scala/whisk/core/limits/MaxActionDurationTests.scala @@ -24,7 +24,7 @@ import org.scalatest.junit.JUnitRunner import common.TestHelpers import common.TestUtils -import common.Wsk +import common.rest.WskRest import common.WskProps import common.WskTestHelpers import whisk.core.entity._ @@ -40,7 +40,7 @@ import whisk.core.entity.TimeLimit class MaxActionDurationTests extends TestHelpers with WskTestHelpers { implicit val wskprops = WskProps() - val wsk = new Wsk + val wsk = new WskRest // swift is not tested, because it uses the same proxy like python "node-, python, and java-action" should "run up to the max allowed duration" in withAssetCleaner(wskprops) { ---------------------------------------------------------------- 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: us...@infra.apache.org With regards, Apache Git Services