This is an automated email from the ASF dual-hosted git repository.
style95 pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/openwhisk.git
The following commit(s) were added to refs/heads/master by this push:
new 7c5a5d696 Forward header from a trigger to actions. (#5273)
7c5a5d696 is described below
commit 7c5a5d6964a62deb931445684bab0b0524a9ad64
Author: Dominic Kim <[email protected]>
AuthorDate: Fri Jul 15 14:28:03 2022 +0900
Forward header from a trigger to actions. (#5273)
* Forward header from a trigger to actions.
* Add the Apache header.
---
.../openwhisk/core/controller/Triggers.scala | 17 +++-
tests/dat/actions/params.js | 20 +++++
.../core/cli/test/WskRestBasicUsageTests.scala | 97 +++++++++++++++++++++-
.../test/scala/system/basic/WskSequenceTests.scala | 9 +-
4 files changed, 135 insertions(+), 8 deletions(-)
diff --git
a/core/controller/src/main/scala/org/apache/openwhisk/core/controller/Triggers.scala
b/core/controller/src/main/scala/org/apache/openwhisk/core/controller/Triggers.scala
index 57510993a..0c00e3a9b 100644
---
a/core/controller/src/main/scala/org/apache/openwhisk/core/controller/Triggers.scala
+++
b/core/controller/src/main/scala/org/apache/openwhisk/core/controller/Triggers.scala
@@ -18,7 +18,6 @@
package org.apache.openwhisk.core.controller
import java.time.{Clock, Instant}
-
import scala.collection.immutable.Map
import scala.concurrent.Future
import scala.util.Try
@@ -28,7 +27,7 @@ import
akka.http.scaladsl.marshallers.sprayjson.SprayJsonSupport._
import akka.http.scaladsl.model.HttpMethods.POST
import akka.http.scaladsl.model.StatusCodes.{Accepted, BadRequest,
InternalServerError, NoContent, OK, ServerError}
import akka.http.scaladsl.model.Uri.Path
-import akka.http.scaladsl.model.headers.Authorization
+import akka.http.scaladsl.model.headers.{`Timeout-Access`, Authorization}
import akka.http.scaladsl.model._
import akka.http.scaladsl.server.{RequestContext, RouteResult}
import akka.http.scaladsl.unmarshalling.{Unmarshal, Unmarshaller}
@@ -151,7 +150,19 @@ trait WhiskTriggersApi extends WhiskCollectionAPI {
response = ActivationResponse.success(payload orElse
Some(JsObject.empty)),
version = trigger.version,
duration = None)
- val args: JsObject =
trigger.parameters.merge(payload).getOrElse(JsObject.empty)
+ val headers = JsObject(
+ Map(new WebApiDirectives().headers -> request.headers
+ .collect {
+ case h if h.name != `Timeout-Access`.name =>
h.lowercaseName -> h.value
+ }
+ .toMap
+ .toJson))
+
+ val mergedPayload = Some {
+ (headers.fields ++ (payload getOrElse
JsObject.empty).fields).toJson.asJsObject
+ }
+
+ val args: JsObject =
trigger.parameters.merge(mergedPayload).getOrElse(JsObject.empty)
activateRules(user, args, trigger.rules.getOrElse(Map.empty))
.map(results =>
triggerActivation.withLogs(ActivationLogs(results.map(_.toJson.compactPrint).toVector)))
diff --git a/tests/dat/actions/params.js b/tests/dat/actions/params.js
new file mode 100644
index 000000000..81826c291
--- /dev/null
+++ b/tests/dat/actions/params.js
@@ -0,0 +1,20 @@
+/*
+ * 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.
+ */
+
+function main(args) {
+ return {args}
+}
diff --git
a/tests/src/test/scala/org/apache/openwhisk/core/cli/test/WskRestBasicUsageTests.scala
b/tests/src/test/scala/org/apache/openwhisk/core/cli/test/WskRestBasicUsageTests.scala
index fc9e54dd7..6e0cbb04f 100644
---
a/tests/src/test/scala/org/apache/openwhisk/core/cli/test/WskRestBasicUsageTests.scala
+++
b/tests/src/test/scala/org/apache/openwhisk/core/cli/test/WskRestBasicUsageTests.scala
@@ -21,9 +21,9 @@ import akka.http.scaladsl.model.StatusCodes.NotFound
import akka.http.scaladsl.model.StatusCodes.OK
import akka.http.scaladsl.model.StatusCodes.BadRequest
import akka.http.scaladsl.model.StatusCodes.Conflict
+
import java.time.Instant
import java.time.Clock
-
import scala.language.postfixOps
import scala.concurrent.duration.DurationInt
import scala.util.Random
@@ -36,22 +36,29 @@ import common.WhiskProperties
import common.WskProps
import common.WskTestHelpers
import common.WskActorSystem
-import common.rest.WskRestOperations
+import common.rest.{RestResult, RunRestCmd, WskRestOperations}
import spray.json.DefaultJsonProtocol._
import spray.json._
import org.apache.openwhisk.core.entity._
import org.apache.openwhisk.core.entity.size.SizeInt
import TestJsonArgs._
+import akka.http.scaladsl.Http
+import akka.http.scaladsl.model.HttpMethods.POST
+import akka.http.scaladsl.model.{ContentTypes, HttpEntity, HttpHeader,
HttpMethod, HttpRequest, HttpResponse, Uri}
+import akka.http.scaladsl.model.Uri.{Path, Query}
+import akka.http.scaladsl.model.headers.{Authorization, BasicHttpCredentials,
RawHeader}
+import akka.util.ByteString
import org.apache.openwhisk.http.Messages
/**
* Tests for basic CLI usage. Some of these tests require a deployed backend.
*/
@RunWith(classOf[JUnitRunner])
-class WskRestBasicUsageTests extends TestHelpers with WskTestHelpers with
WskActorSystem {
+class WskRestBasicUsageTests extends TestHelpers with WskTestHelpers with
WskActorSystem with RunRestCmd {
implicit val wskprops = WskProps()
- val wsk = new WskRestOperations
+ implicit lazy override val executionContext = actorSystem.dispatcher
+ val wsk = new WskRestOperations()
val defaultAction: Some[String] =
Some(TestUtils.getTestActionFilename("hello.js"))
val usrAgentHeaderRegEx: String = """\bUser-Agent\b":
\[\s+"OpenWhisk\-CLI/1.\d+.*"""
@@ -737,4 +744,86 @@ class WskRestBasicUsageTests extends TestHelpers with
WskTestHelpers with WskAct
wsk.trigger.delete(triggerName).statusCode shouldBe OK
}
}
+
+ it should "forward headers as parameters to the associated action" in
withAssetCleaner(wskprops) {
+ (wp, assetHelper) =>
+ val guestNamespace = wsk.namespace.whois()
+ val name = "triggerWithHeaders"
+ val actionName = "params"
+ val ruleName = "ruleWithHeaders"
+
+ assetHelper.withCleaner(wsk.trigger, name) { (trigger, _) =>
+ trigger.create(name)
+ }
+
+ assetHelper.withCleaner(wsk.action, actionName) { (action, _) =>
+ action.create(actionName,
Some(TestUtils.getTestActionFilename("params.js")))
+ }
+
+ assetHelper.withCleaner(wsk.rule, ruleName) { (rule, _) =>
+ rule.create(ruleName, trigger = name, action = actionName)
+ rule.enable(ruleName)
+ }
+
+ val path = Path(s"$basePath/namespaces/$guestNamespace/triggers/$name")
+
+ val resp = requestEntityWithHeader(POST, path, List(RawHeader("Foo",
"Bar")))(wp)
+ val result = new RestResult(resp.status.intValue,
getTransactionId(resp), getRespData(resp))
+
+ withActivation(wsk.activation, result) { triggerActivation =>
+ val ruleActivation =
triggerActivation.logs.get.map(_.parseJson.convertTo[common.RuleActivationResult]).head
+ withActivation(wsk.activation, ruleActivation.activationId) {
actionActivation =>
+ actionActivation.response.result match {
+ case Some(result) =>
+ result.fields.get("args") map { headers =>
+ headers.asJsObject.fields.get("__ow_headers") map { params =>
+ params.asJsObject.fields.get("foo") map { foo =>
+ foo shouldBe JsString("Bar")
+ }
+ }
+ }
+
+ case others =>
+ fail(s"no result found: $others")
+
+ }
+ actionActivation.cause shouldBe None
+ }
+ }
+ }
+
+ def requestEntityWithHeader(method: HttpMethod,
+ path: Path,
+ headers: List[HttpHeader],
+ params: Map[String, String] = Map.empty,
+ body: Option[String] = None)(implicit wp:
WskProps): HttpResponse = {
+ val credentials = wp.authKey.split(":")
+ val creds = new BasicHttpCredentials(credentials(0), credentials(1))
+
+ // startsWith(http) includes https
+ val hostWithScheme = if (wp.apihost.startsWith("http")) {
+ Uri(wp.apihost)
+ } else {
+ Uri().withScheme("https").withHost(wp.apihost)
+ }
+
+ val request = HttpRequest(
+ method,
+ hostWithScheme.withPath(path).withQuery(Query(params)),
+ Authorization(creds) :: headers,
+ entity =
+ body.map(b => HttpEntity.Strict(ContentTypes.`application/json`,
ByteString(b))).getOrElse(HttpEntity.Empty))
+ val response = Http().singleRequest(request, connectionContext).flatMap {
_.toStrict(toStrictTimeout) }.futureValue
+
+ logger.debug(this, s"Request: $request")
+ logger.debug(this, s"Response: $response")
+
+ val validationErrors = validateRequestAndResponse(request, response)
+ if (validationErrors.nonEmpty) {
+ fail(
+ s"HTTP request or response did not match the Swagger spec.\nRequest:
$request\n" +
+ s"Response: $response\nValidation Error: $validationErrors")
+ }
+ response
+ }
}
diff --git a/tests/src/test/scala/system/basic/WskSequenceTests.scala
b/tests/src/test/scala/system/basic/WskSequenceTests.scala
index 1cf265f47..73728b92e 100644
--- a/tests/src/test/scala/system/basic/WskSequenceTests.scala
+++ b/tests/src/test/scala/system/basic/WskSequenceTests.scala
@@ -551,7 +551,14 @@ class WskSequenceTests extends TestHelpers with
WskTestHelpers with StreamLoggin
withActivation(wsk.activation, triggerFireRun) { triggerActivation =>
val ruleActivation =
triggerActivation.logs.get.map(_.parseJson.convertTo[RuleActivationResult]).head
withActivation(wsk.activation, ruleActivation.activationId) {
actionActivation =>
- actionActivation.response.result shouldBe Some(triggerPayload)
+ actionActivation.response.result match {
+ case Some(result) =>
+ val (_, part2) = result.fields partition (p => p._1 ==
"__ow_headers") // excluding headers
+ JsObject(part2) shouldBe triggerPayload
+ case others =>
+ fail(s"no result found: $others")
+
+ }
actionActivation.cause shouldBe None
}
}