From f8c182db5c2284f1c9b9cffd18d00202d0980516 Mon Sep 17 00:00:00 2001 From: seonghyun Date: Tue, 24 Sep 2019 18:14:19 +0900 Subject: [PATCH 01/18] Add updated field on WhiskAction json format --- .../openwhisk/core/entity/WhiskAction.scala | 32 +++++++++++-------- 1 file changed, 19 insertions(+), 13 deletions(-) diff --git a/common/scala/src/main/scala/org/apache/openwhisk/core/entity/WhiskAction.scala b/common/scala/src/main/scala/org/apache/openwhisk/core/entity/WhiskAction.scala index 887adc38788..40fa74ffdac 100644 --- a/common/scala/src/main/scala/org/apache/openwhisk/core/entity/WhiskAction.scala +++ b/common/scala/src/main/scala/org/apache/openwhisk/core/entity/WhiskAction.scala @@ -101,7 +101,8 @@ abstract class WhiskActionLike(override val name: EntityName) extends WhiskEntit "limits" -> limits.toJson, "version" -> version.toJson, "publish" -> publish.toJson, - "annotations" -> annotations.toJson) + "annotations" -> annotations.toJson, + "updated" -> updated.getEpochSecond.toJson) } abstract class WhiskActionLikeMetaData(override val name: EntityName) extends WhiskActionLike(name) { @@ -549,20 +550,25 @@ object WhiskActionMetaData override val collectionName = "actions" - override implicit val serdes = jsonFormat( - WhiskActionMetaData.apply, - "namespace", - "name", - "exec", - "parameters", - "limits", - "version", - "publish", - "annotations", - "binding") - override val cacheEnabled = true + override implicit val serdes = new RootJsonFormat[WhiskActionMetaData] { + def write(result: WhiskActionMetaData) = result.toJson + def read(value: JsValue): WhiskActionMetaData = { + val fields = value.asJsObject.fields + WhiskActionMetaData( + fields("namespace").convertTo[EntityPath], + fields("name").convertTo[EntityName], + fields("exec").convertTo[ExecMetaDataBase], + fields("parameters").convertTo[Parameters], + fields("limits").convertTo[ActionLimits], + fields("version").convertTo[SemVer], + fields("publish").convertTo[Boolean], + fields("annotations").convertTo[Parameters], + ) + } + } + /** * Resolves an action name if it is contained in a package. * Look up the package to determine if it is a binding or the actual package. From df3852d70051336cb7d63020f7abc16ba2672629 Mon Sep 17 00:00:00 2001 From: seonghyun Date: Wed, 25 Sep 2019 16:39:50 +0900 Subject: [PATCH 02/18] Update custom serdes --- .../openwhisk/core/entity/WhiskAction.scala | 19 +++++++++++++++---- 1 file changed, 15 insertions(+), 4 deletions(-) diff --git a/common/scala/src/main/scala/org/apache/openwhisk/core/entity/WhiskAction.scala b/common/scala/src/main/scala/org/apache/openwhisk/core/entity/WhiskAction.scala index 40fa74ffdac..e0462217018 100644 --- a/common/scala/src/main/scala/org/apache/openwhisk/core/entity/WhiskAction.scala +++ b/common/scala/src/main/scala/org/apache/openwhisk/core/entity/WhiskAction.scala @@ -92,7 +92,7 @@ abstract class WhiskActionLike(override val name: EntityName) extends WhiskEntit parameters.definedParameters } else Set.empty[String] - def toJson = + def toJson = { JsObject( "namespace" -> namespace.toJson, "name" -> name.toJson, @@ -101,8 +101,8 @@ abstract class WhiskActionLike(override val name: EntityName) extends WhiskEntit "limits" -> limits.toJson, "version" -> version.toJson, "publish" -> publish.toJson, - "annotations" -> annotations.toJson, - "updated" -> updated.getEpochSecond.toJson) + "annotations" -> annotations.toJson) + } } abstract class WhiskActionLikeMetaData(override val name: EntityName) extends WhiskActionLike(name) { @@ -553,7 +553,18 @@ object WhiskActionMetaData override val cacheEnabled = true override implicit val serdes = new RootJsonFormat[WhiskActionMetaData] { - def write(result: WhiskActionMetaData) = result.toJson + def write(w: WhiskActionMetaData) = { + JsObject( + "namespace" -> w.namespace.toJson, + "name" -> w.name.toJson, + "exec" -> w.exec.toJson, + "parameters" -> w.parameters.toJson, + "limits" -> w.limits.toJson, + "version" -> w.version.toJson, + "publish" -> w.publish.toJson, + "annotations" -> w.annotations.toJson, + "updated" -> w.updated.getEpochSecond.toJson) + } def read(value: JsValue): WhiskActionMetaData = { val fields = value.asJsObject.fields WhiskActionMetaData( From 82bdc65150aa543c0b2282ac59cdeec094e22589 Mon Sep 17 00:00:00 2001 From: seonghyun Date: Wed, 25 Sep 2019 19:21:52 +0900 Subject: [PATCH 03/18] Add updated field at case class --- .../openwhisk/core/entity/WhiskAction.scala | 59 ++++---- .../controller/test/ActionsApiTests.scala | 130 +++++++++++++----- 2 files changed, 120 insertions(+), 69 deletions(-) diff --git a/common/scala/src/main/scala/org/apache/openwhisk/core/entity/WhiskAction.scala b/common/scala/src/main/scala/org/apache/openwhisk/core/entity/WhiskAction.scala index e0462217018..b47b7ebbecd 100644 --- a/common/scala/src/main/scala/org/apache/openwhisk/core/entity/WhiskAction.scala +++ b/common/scala/src/main/scala/org/apache/openwhisk/core/entity/WhiskAction.scala @@ -19,6 +19,8 @@ package org.apache.openwhisk.core.entity import java.io.{ByteArrayInputStream, ByteArrayOutputStream} import java.nio.charset.StandardCharsets.UTF_8 +import java.time.temporal.ChronoUnit +import java.time.{Clock, Instant} import java.util.Base64 import akka.http.scaladsl.model.ContentTypes @@ -134,7 +136,8 @@ case class WhiskAction(namespace: EntityPath, limits: ActionLimits = ActionLimits(), version: SemVer = SemVer(), publish: Boolean = false, - annotations: Parameters = Parameters()) + annotations: Parameters = Parameters(), + override val updated: Instant = Instant.now(Clock.systemUTC()).truncatedTo(ChronoUnit.MILLIS)) extends WhiskActionLike(name) { require(exec != null, "exec undefined") @@ -201,6 +204,9 @@ case class WhiskActionMetaData(namespace: EntityPath, version: SemVer = SemVer(), publish: Boolean = false, annotations: Parameters = Parameters(), + override val updated: Instant = Instant + .now(Clock.systemUTC()) + .truncatedTo(ChronoUnit.MILLIS), binding: Option[EntityPath] = None) extends WhiskActionLikeMetaData(name) { @@ -331,7 +337,7 @@ case class ExecutableWhiskActionMetaData(namespace: EntityPath, require(limits != null, "limits undefined") def toWhiskAction = - WhiskActionMetaData(namespace, name, exec, parameters, limits, version, publish, annotations) + WhiskActionMetaData(namespace, name, exec, parameters, limits, version, publish, annotations, updated) .revision[WhiskActionMetaData](rev) /** @@ -343,11 +349,13 @@ case class ExecutableWhiskActionMetaData(namespace: EntityPath, } object WhiskAction extends DocumentFactory[WhiskAction] with WhiskEntityQueries[WhiskAction] with DefaultJsonProtocol { + import WhiskActivation.instantSerdes val execFieldName = "exec" val requireWhiskAuthHeader = "x-require-whisk-auth" override val collectionName = "actions" + override val cacheEnabled = true override implicit val serdes = jsonFormat( WhiskAction.apply, @@ -358,9 +366,8 @@ object WhiskAction extends DocumentFactory[WhiskAction] with WhiskEntityQueries[ "limits", "version", "publish", - "annotations") - - override val cacheEnabled = true + "annotations", + "updated") // overriden to store attached code override def put[A >: WhiskAction](db: ArtifactStore[A], doc: WhiskAction, old: Option[WhiskAction])( @@ -548,37 +555,23 @@ object WhiskActionMetaData with WhiskEntityQueries[WhiskActionMetaData] with DefaultJsonProtocol { - override val collectionName = "actions" + import WhiskActivation.instantSerdes + override val collectionName = "actions" override val cacheEnabled = true - override implicit val serdes = new RootJsonFormat[WhiskActionMetaData] { - def write(w: WhiskActionMetaData) = { - JsObject( - "namespace" -> w.namespace.toJson, - "name" -> w.name.toJson, - "exec" -> w.exec.toJson, - "parameters" -> w.parameters.toJson, - "limits" -> w.limits.toJson, - "version" -> w.version.toJson, - "publish" -> w.publish.toJson, - "annotations" -> w.annotations.toJson, - "updated" -> w.updated.getEpochSecond.toJson) - } - def read(value: JsValue): WhiskActionMetaData = { - val fields = value.asJsObject.fields - WhiskActionMetaData( - fields("namespace").convertTo[EntityPath], - fields("name").convertTo[EntityName], - fields("exec").convertTo[ExecMetaDataBase], - fields("parameters").convertTo[Parameters], - fields("limits").convertTo[ActionLimits], - fields("version").convertTo[SemVer], - fields("publish").convertTo[Boolean], - fields("annotations").convertTo[Parameters], - ) - } - } + override implicit val serdes = jsonFormat( + WhiskActionMetaData.apply, + "namespace", + "name", + "exec", + "parameters", + "limits", + "version", + "publish", + "annotations", + "updated", + "binding") /** * Resolves an action name if it is contained in a package. diff --git a/tests/src/test/scala/org/apache/openwhisk/core/controller/test/ActionsApiTests.scala b/tests/src/test/scala/org/apache/openwhisk/core/controller/test/ActionsApiTests.scala index 95a1425b04a..ab982b13567 100644 --- a/tests/src/test/scala/org/apache/openwhisk/core/controller/test/ActionsApiTests.scala +++ b/tests/src/test/scala/org/apache/openwhisk/core/controller/test/ActionsApiTests.scala @@ -194,6 +194,7 @@ class ActionsApiTests extends ControllerTestCommon with WhiskActionsApi { implicit val tid = transid() val action = WhiskAction(namespace, aname(), jsDefault("??"), Parameters("x", "b")) put(entityStore, action) + Get(s"$collectionPath/${action.name}") ~> Route.seal(routes(creds)) ~> check { status should be(OK) val response = responseAs[WhiskAction] @@ -201,20 +202,41 @@ class ActionsApiTests extends ControllerTestCommon with WhiskActionsApi { } } - it should "get action by name in explicit namespace" in { + it should "get action with `updated` field" in { implicit val tid = transid() + val action = WhiskAction(namespace, aname(), jsDefault("??"), Parameters("x", "b")) put(entityStore, action) + + // `updated` field should be compared with a document in DB + val a = get(entityStore, action.docid, WhiskAction) + + Get(s"/$namespace/${collection.path}/${action.name}?code=false") ~> Route.seal(routes(creds)) ~> check { + status should be(OK) + val responseJson = responseAs[JsObject] + responseJson.fields("updated").convertTo[Long] should be(a.updated.toEpochMilli) + } + Get(s"/$namespace/${collection.path}/${action.name}") ~> Route.seal(routes(creds)) ~> check { status should be(OK) - val response = responseAs[WhiskAction] - response should be(action) + val responseJson = responseAs[JsObject] + responseJson.fields("updated").convertTo[Long] should be(a.updated.toEpochMilli) } + } - // it should "reject get action by name in explicit namespace not owned by subject" in - val auser = WhiskAuthHelpers.newIdentity() - Get(s"/$namespace/${collection.path}/${action.name}") ~> Route.seal(routes(auser)) ~> check { - status should be(Forbidden) + it should "not put `updated` field" in { + implicit val tid = transid() + + val action = WhiskAction(namespace, aname(), jsDefault("")) + val dummyUpdated = 1569400000000L; + val content = JsObject( + "exec" -> JsObject("code" -> "".toJson, "kind" -> action.exec.kind.toJson), + "updated" -> dummyUpdated.toJson) + + Put(s"$collectionPath/${action.name}", content) ~> Route.seal(routes(creds)) ~> check { + status should be(OK) + val response = responseAs[WhiskAction] + response.updated.toEpochMilli should not be (dummyUpdated) } } @@ -324,7 +346,11 @@ class ActionsApiTests extends ControllerTestCommon with WhiskActionsApi { Put(s"$collectionPath/${action.name}", content) ~> Route.seal(routes(creds)) ~> check { status should be(OK) val response = responseAs[WhiskAction] - response should be(expectedWhiskAction) + + // If an action is created with a request, its `updated` timestamp is not known before inserting it + // So it compares with the value of a response + val expectedAction = expectedWhiskAction copy (updated = response.updated) + response should be(expectedAction) } Get(s"$collectionPath/${action.name}?code=false") ~> Route.seal(routes(creds)) ~> check { @@ -332,21 +358,26 @@ class ActionsApiTests extends ControllerTestCommon with WhiskActionsApi { val responseJson = responseAs[JsObject] responseJson.fields("exec").asJsObject.fields should not(contain key "code") val response = responseAs[WhiskActionMetaData] - response should be(expectedWhiskActionMetaData) + + // updated field is overwritten for the same reason as above + response should be(expectedWhiskActionMetaData copy (updated = response.updated)) } Seq(s"$collectionPath/${action.name}", s"$collectionPath/${action.name}?code=true").foreach { path => Get(path) ~> Route.seal(routes(creds)) ~> check { status should be(OK) val response = responseAs[WhiskAction] - response should be(expectedWhiskAction) + // updated field is overwritten for the same reason as above + response should be(expectedWhiskAction copy (updated = response.updated)) } } Delete(s"$collectionPath/${action.name}") ~> Route.seal(routes(creds)) ~> check { status should be(OK) val response = responseAs[WhiskAction] - response should be(expectedWhiskAction) + + // updated field is overwritten for the same reason as above + response should be(expectedWhiskAction copy (updated = response.updated)) } } } @@ -554,7 +585,8 @@ class ActionsApiTests extends ControllerTestCommon with WhiskActionsApi { action.limits, action.version, action.publish, - action.annotations ++ systemAnnotations(NODEJS10))) + action.annotations ++ systemAnnotations(NODEJS10), + updated = response.updated)) // ignore updated field } } @@ -575,7 +607,8 @@ class ActionsApiTests extends ControllerTestCommon with WhiskActionsApi { action.limits, action.version, action.publish, - action.annotations ++ systemAnnotations(BLACKBOX))) + action.annotations ++ systemAnnotations(BLACKBOX), + updated = response.updated)) // ignore updated field response.exec shouldBe an[BlackBoxExec] response.exec.asInstanceOf[BlackBoxExec].code shouldBe empty } @@ -598,7 +631,8 @@ class ActionsApiTests extends ControllerTestCommon with WhiskActionsApi { action.limits, action.version, action.publish, - action.annotations ++ systemAnnotations(BLACKBOX))) + action.annotations ++ systemAnnotations(BLACKBOX), + updated = response.updated)) response.exec shouldBe an[BlackBoxExec] val bb = response.exec.asInstanceOf[BlackBoxExec] bb.code shouldBe Some(Inline("cc")) @@ -626,7 +660,8 @@ class ActionsApiTests extends ControllerTestCommon with WhiskActionsApi { action.limits, action.version.upPatch, action.publish, - action.annotations ++ Parameters(WhiskAction.execFieldName, action.exec.kind))) + action.annotations ++ Parameters(WhiskAction.execFieldName, action.exec.kind), + updated = response.updated)) } content = """{"annotations":[{"key":"a","value":"B"}]}""".parseJson.asJsObject @@ -644,7 +679,8 @@ class ActionsApiTests extends ControllerTestCommon with WhiskActionsApi { action.limits, action.version.upPatch.upPatch, action.publish, - action.annotations ++ Parameters("a", "B") ++ Parameters(WhiskAction.execFieldName, action.exec.kind))) + action.annotations ++ Parameters("a", "B") ++ Parameters(WhiskAction.execFieldName, action.exec.kind), + updated = response.updated)) } } @@ -715,7 +751,8 @@ class ActionsApiTests extends ControllerTestCommon with WhiskActionsApi { action.limits, action.version, action.publish, - action.annotations ++ systemAnnotations(NODEJS10))) + action.annotations ++ systemAnnotations(NODEJS10), + updated = response.updated)) } } @@ -755,11 +792,13 @@ class ActionsApiTests extends ControllerTestCommon with WhiskActionsApi { action.limits, action.version, action.publish, - action.annotations ++ systemAnnotations(NODEJS10))) + action.annotations ++ systemAnnotations(NODEJS10), + updated = response.updated)) } } it should "put and then get an action from cache" in { + implicit val tid = transid() val javaAction = WhiskAction(namespace, aname(), javaDefault("ZHViZWU=", Some("hello")), annotations = Parameters("exec", "java")) val nodeAction = WhiskAction(namespace, aname(), jsDefault("??"), Parameters("x", "b")) @@ -790,7 +829,8 @@ class ActionsApiTests extends ControllerTestCommon with WhiskActionsApi { action.limits, action.version, action.publish, - action.annotations ++ systemAnnotations(kind))) + action.annotations ++ systemAnnotations(kind), + updated = response.updated)) } stream.toString should include(s"caching ${CacheKey(action)}") stream.toString should not include (s"invalidating ${CacheKey(action)} on delete") @@ -809,7 +849,8 @@ class ActionsApiTests extends ControllerTestCommon with WhiskActionsApi { action.limits, action.version, action.publish, - action.annotations ++ systemAnnotations(kind))) + action.annotations ++ systemAnnotations(kind), + updated = response.updated)) } stream.toString should include(s"serving from cache: ${CacheKey(action)}") stream.reset() @@ -827,7 +868,8 @@ class ActionsApiTests extends ControllerTestCommon with WhiskActionsApi { action.limits, action.version.upPatch, action.publish, - action.annotations ++ systemAnnotations(kind)) + action.annotations ++ systemAnnotations(kind), + updated = response.updated) } } stream.toString should include(s"entity exists, will try to update '$action'") @@ -848,7 +890,8 @@ class ActionsApiTests extends ControllerTestCommon with WhiskActionsApi { action.limits, action.version.upPatch, action.publish, - action.annotations ++ systemAnnotations(kind))) + action.annotations ++ systemAnnotations(kind), + updated = response.updated)) } stream.toString should include(s"invalidating ${CacheKey(action)}") stream.reset() @@ -902,7 +945,8 @@ class ActionsApiTests extends ControllerTestCommon with WhiskActionsApi { action.limits, action.version, action.publish, - action.annotations ++ systemAnnotations(kind))) + action.annotations ++ systemAnnotations(kind), + updated = response.updated)) } stream.toString should not include (s"invalidating ${CacheKey(action)} on delete") @@ -922,7 +966,8 @@ class ActionsApiTests extends ControllerTestCommon with WhiskActionsApi { action.limits, action.version, action.publish, - action.annotations ++ systemAnnotations(kind))) + action.annotations ++ systemAnnotations(kind), + updated = response.updated)) } stream.toString should include(s"serving from cache: ${CacheKey(action)}") stream.toString should not include regex(notExpectedGetLog) @@ -941,7 +986,8 @@ class ActionsApiTests extends ControllerTestCommon with WhiskActionsApi { action.limits, action.version, action.publish, - action.annotations ++ systemAnnotations(kind))) + action.annotations ++ systemAnnotations(kind), + updated = response.updated)) } stream.toString should include(s"invalidating ${CacheKey(action)}") @@ -985,7 +1031,8 @@ class ActionsApiTests extends ControllerTestCommon with WhiskActionsApi { action.limits, action.version, action.publish, - action.annotations ++ systemAnnotations(JAVA_DEFAULT))) + action.annotations ++ systemAnnotations(JAVA_DEFAULT), + updated = response.updated)) } stream.toString should not include (s"invalidating ${CacheKey(action)} on delete") @@ -1005,7 +1052,8 @@ class ActionsApiTests extends ControllerTestCommon with WhiskActionsApi { action.limits, action.version, action.publish, - action.annotations ++ systemAnnotations(JAVA_DEFAULT))) + action.annotations ++ systemAnnotations(JAVA_DEFAULT), + updated = response.updated)) } stream.toString should include(s"serving from cache: ${CacheKey(action)}") @@ -1025,7 +1073,8 @@ class ActionsApiTests extends ControllerTestCommon with WhiskActionsApi { action.limits, action.version, action.publish, - action.annotations ++ systemAnnotations(JAVA_DEFAULT))) + action.annotations ++ systemAnnotations(JAVA_DEFAULT), + updated = response.updated)) } stream.toString should include(s"invalidating ${CacheKey(action)}") stream.reset() @@ -1074,7 +1123,8 @@ class ActionsApiTests extends ControllerTestCommon with WhiskActionsApi { action.limits, action.version, action.publish, - action.annotations ++ systemAnnotations(kind))) + action.annotations ++ systemAnnotations(kind), + updated = response.updated)) } stream.toString should include regex (expectedGetLog) @@ -1124,7 +1174,7 @@ class ActionsApiTests extends ControllerTestCommon with WhiskActionsApi { Get(s"$collectionPath/$name") ~> Route.seal(routes(creds)(transid())) ~> check { status should be(OK) val response = responseAs[WhiskAction] - response should be(expectedAction) + response should be(expectedAction copy (updated = response.updated)) } } @@ -1181,7 +1231,8 @@ class ActionsApiTests extends ControllerTestCommon with WhiskActionsApi { action.limits, action.version.upPatch, action.publish, - action.annotations ++ systemAnnotations(kind))) + action.annotations ++ systemAnnotations(kind), + updated = response.updated)) } stream.toString should include regex (expectedPutLog) stream.reset() @@ -1199,7 +1250,8 @@ class ActionsApiTests extends ControllerTestCommon with WhiskActionsApi { action.limits, action.version.upPatch, action.publish, - action.annotations ++ systemAnnotations(kind))) + action.annotations ++ systemAnnotations(kind), + updated = response.updated)) } stream.toString should include(s"invalidating ${CacheKey(action)}") stream.reset() @@ -1246,7 +1298,8 @@ class ActionsApiTests extends ControllerTestCommon with WhiskActionsApi { actionOldSchema.limits, actionOldSchema.version.upPatch, actionOldSchema.publish, - actionOldSchema.annotations ++ systemAnnotations(NODEJS10, create = false))) + actionOldSchema.annotations ++ systemAnnotations(NODEJS10, create = false), + updated = response.updated)) } stream.toString should include regex (expectedPutLog) @@ -1270,7 +1323,8 @@ class ActionsApiTests extends ControllerTestCommon with WhiskActionsApi { actionOldSchema.limits, actionOldSchema.version.upPatch, actionOldSchema.publish, - actionOldSchema.annotations ++ systemAnnotations(NODEJS10, create = false))) + actionOldSchema.annotations ++ systemAnnotations(NODEJS10, create = false), + updated = response.updated)) } } @@ -1301,6 +1355,8 @@ class ActionsApiTests extends ControllerTestCommon with WhiskActionsApi { deleteAction(action.docid) status should be(OK) val response = responseAs[WhiskAction] + + response.updated should not be action.updated response should be { WhiskAction( action.namespace, @@ -1313,7 +1369,8 @@ class ActionsApiTests extends ControllerTestCommon with WhiskActionsApi { content.limits.get.logs.get, content.limits.get.concurrency.get), version = action.version.upPatch, - annotations = action.annotations ++ systemAnnotations(NODEJS10, create = false)) + annotations = action.annotations ++ systemAnnotations(NODEJS10, create = false), + updated = response.updated) } } } @@ -1334,7 +1391,8 @@ class ActionsApiTests extends ControllerTestCommon with WhiskActionsApi { action.exec, content.parameters.get, version = action.version.upPatch, - annotations = action.annotations ++ systemAnnotations(NODEJS10, false)) + annotations = action.annotations ++ systemAnnotations(NODEJS10, false), + updated = response.updated) } } } From 776a27d2f1ad85f3ab264813c04ae407612c17ac Mon Sep 17 00:00:00 2001 From: seonghyun Date: Thu, 26 Sep 2019 12:18:44 +0900 Subject: [PATCH 04/18] Fix package api test --- .../core/controller/test/PackageActionsApiTests.scala | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/tests/src/test/scala/org/apache/openwhisk/core/controller/test/PackageActionsApiTests.scala b/tests/src/test/scala/org/apache/openwhisk/core/controller/test/PackageActionsApiTests.scala index d1033b00828..a645e87c3ee 100644 --- a/tests/src/test/scala/org/apache/openwhisk/core/controller/test/PackageActionsApiTests.scala +++ b/tests/src/test/scala/org/apache/openwhisk/core/controller/test/PackageActionsApiTests.scala @@ -162,7 +162,8 @@ class PackageActionsApiTests extends ControllerTestCommon with WhiskActionsApi { action.limits, action.version, action.publish, - action.annotations ++ systemAnnotations(NODEJS10))) + action.annotations ++ systemAnnotations(NODEJS10), + updated = response.updated)) } } From 2e5bd4a099b342df8dd359a476dfa6ea8beed5d7 Mon Sep 17 00:00:00 2001 From: seonghyun Date: Thu, 26 Sep 2019 14:07:19 +0900 Subject: [PATCH 05/18] Modified test case name --- .../apache/openwhisk/core/controller/test/ActionsApiTests.scala | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/src/test/scala/org/apache/openwhisk/core/controller/test/ActionsApiTests.scala b/tests/src/test/scala/org/apache/openwhisk/core/controller/test/ActionsApiTests.scala index ab982b13567..c4e0aa9a4bb 100644 --- a/tests/src/test/scala/org/apache/openwhisk/core/controller/test/ActionsApiTests.scala +++ b/tests/src/test/scala/org/apache/openwhisk/core/controller/test/ActionsApiTests.scala @@ -224,7 +224,7 @@ class ActionsApiTests extends ControllerTestCommon with WhiskActionsApi { } } - it should "not put `updated` field" in { + it should "not update action `updated` field with a put" in { implicit val tid = transid() val action = WhiskAction(namespace, aname(), jsDefault("")) From 00dddf6182dcbde0c7cd2b15b81b3dc1288434a0 Mon Sep 17 00:00:00 2001 From: seonghyun Date: Thu, 26 Sep 2019 14:51:53 +0900 Subject: [PATCH 06/18] Add annotation --- .../openwhisk/core/entity/WhiskAction.scala | 9 ++-- .../controller/test/ActionsApiTests.scala | 46 +++++++++---------- 2 files changed, 28 insertions(+), 27 deletions(-) diff --git a/common/scala/src/main/scala/org/apache/openwhisk/core/entity/WhiskAction.scala b/common/scala/src/main/scala/org/apache/openwhisk/core/entity/WhiskAction.scala index b47b7ebbecd..391f471030e 100644 --- a/common/scala/src/main/scala/org/apache/openwhisk/core/entity/WhiskAction.scala +++ b/common/scala/src/main/scala/org/apache/openwhisk/core/entity/WhiskAction.scala @@ -94,7 +94,7 @@ abstract class WhiskActionLike(override val name: EntityName) extends WhiskEntit parameters.definedParameters } else Set.empty[String] - def toJson = { + def toJson = JsObject( "namespace" -> namespace.toJson, "name" -> name.toJson, @@ -104,7 +104,6 @@ abstract class WhiskActionLike(override val name: EntityName) extends WhiskEntit "version" -> version.toJson, "publish" -> publish.toJson, "annotations" -> annotations.toJson) - } } abstract class WhiskActionLikeMetaData(override val name: EntityName) extends WhiskActionLike(name) { @@ -125,7 +124,9 @@ abstract class WhiskActionLikeMetaData(override val name: EntityName) extends Wh * @param limits the limits to impose on the action * @param version the semantic version * @param publish true to share the action or false otherwise - * @param annotation the set of annotations to attribute to the action + * @param annotations the set of annotations to attribute to the action + * @param updated the timestamp when the action is updated. + * Since it's stored in milliseconds in the db, it's truncated. * @throws IllegalArgumentException if any argument is undefined */ @throws[IllegalArgumentException] @@ -271,7 +272,7 @@ case class WhiskActionMetaData(namespace: EntityPath, * @param limits the limits to impose on the action * @param version the semantic version * @param publish true to share the action or false otherwise - * @param annotation the set of annotations to attribute to the action + * @param annotations the set of annotations to attribute to the action * @param binding the path of the package binding if any * @throws IllegalArgumentException if any argument is undefined */ diff --git a/tests/src/test/scala/org/apache/openwhisk/core/controller/test/ActionsApiTests.scala b/tests/src/test/scala/org/apache/openwhisk/core/controller/test/ActionsApiTests.scala index c4e0aa9a4bb..0b2ebded7cf 100644 --- a/tests/src/test/scala/org/apache/openwhisk/core/controller/test/ActionsApiTests.scala +++ b/tests/src/test/scala/org/apache/openwhisk/core/controller/test/ActionsApiTests.scala @@ -586,7 +586,7 @@ class ActionsApiTests extends ControllerTestCommon with WhiskActionsApi { action.version, action.publish, action.annotations ++ systemAnnotations(NODEJS10), - updated = response.updated)) // ignore updated field + updated = response.updated)) // ignored `updated` field because another test covers it } } @@ -608,7 +608,7 @@ class ActionsApiTests extends ControllerTestCommon with WhiskActionsApi { action.version, action.publish, action.annotations ++ systemAnnotations(BLACKBOX), - updated = response.updated)) // ignore updated field + updated = response.updated)) // ignored `updated` field because another test covers it response.exec shouldBe an[BlackBoxExec] response.exec.asInstanceOf[BlackBoxExec].code shouldBe empty } @@ -632,7 +632,7 @@ class ActionsApiTests extends ControllerTestCommon with WhiskActionsApi { action.version, action.publish, action.annotations ++ systemAnnotations(BLACKBOX), - updated = response.updated)) + updated = response.updated)) // ignored `updated` field because another test covers it response.exec shouldBe an[BlackBoxExec] val bb = response.exec.asInstanceOf[BlackBoxExec] bb.code shouldBe Some(Inline("cc")) @@ -680,7 +680,7 @@ class ActionsApiTests extends ControllerTestCommon with WhiskActionsApi { action.version.upPatch.upPatch, action.publish, action.annotations ++ Parameters("a", "B") ++ Parameters(WhiskAction.execFieldName, action.exec.kind), - updated = response.updated)) + updated = response.updated)) // ignored `updated` field because another test covers it } } @@ -752,7 +752,7 @@ class ActionsApiTests extends ControllerTestCommon with WhiskActionsApi { action.version, action.publish, action.annotations ++ systemAnnotations(NODEJS10), - updated = response.updated)) + updated = response.updated)) // ignored `updated` field because another test covers it } } @@ -793,7 +793,7 @@ class ActionsApiTests extends ControllerTestCommon with WhiskActionsApi { action.version, action.publish, action.annotations ++ systemAnnotations(NODEJS10), - updated = response.updated)) + updated = response.updated)) // ignored `updated` field because another test covers it } } @@ -830,7 +830,7 @@ class ActionsApiTests extends ControllerTestCommon with WhiskActionsApi { action.version, action.publish, action.annotations ++ systemAnnotations(kind), - updated = response.updated)) + updated = response.updated)) // ignored `updated` field because another test covers it } stream.toString should include(s"caching ${CacheKey(action)}") stream.toString should not include (s"invalidating ${CacheKey(action)} on delete") @@ -850,7 +850,7 @@ class ActionsApiTests extends ControllerTestCommon with WhiskActionsApi { action.version, action.publish, action.annotations ++ systemAnnotations(kind), - updated = response.updated)) + updated = response.updated)) // ignored `updated` field because another test covers it } stream.toString should include(s"serving from cache: ${CacheKey(action)}") stream.reset() @@ -869,7 +869,7 @@ class ActionsApiTests extends ControllerTestCommon with WhiskActionsApi { action.version.upPatch, action.publish, action.annotations ++ systemAnnotations(kind), - updated = response.updated) + updated = response.updated) // ignored `updated` field because another test covers it } } stream.toString should include(s"entity exists, will try to update '$action'") @@ -891,7 +891,7 @@ class ActionsApiTests extends ControllerTestCommon with WhiskActionsApi { action.version.upPatch, action.publish, action.annotations ++ systemAnnotations(kind), - updated = response.updated)) + updated = response.updated)) // ignored `updated` field because another test covers it } stream.toString should include(s"invalidating ${CacheKey(action)}") stream.reset() @@ -946,7 +946,7 @@ class ActionsApiTests extends ControllerTestCommon with WhiskActionsApi { action.version, action.publish, action.annotations ++ systemAnnotations(kind), - updated = response.updated)) + updated = response.updated)) // ignored `updated` field because another test covers it } stream.toString should not include (s"invalidating ${CacheKey(action)} on delete") @@ -967,7 +967,7 @@ class ActionsApiTests extends ControllerTestCommon with WhiskActionsApi { action.version, action.publish, action.annotations ++ systemAnnotations(kind), - updated = response.updated)) + updated = response.updated)) // ignored `updated` field because another test covers it } stream.toString should include(s"serving from cache: ${CacheKey(action)}") stream.toString should not include regex(notExpectedGetLog) @@ -987,7 +987,7 @@ class ActionsApiTests extends ControllerTestCommon with WhiskActionsApi { action.version, action.publish, action.annotations ++ systemAnnotations(kind), - updated = response.updated)) + updated = response.updated)) // ignored `updated` field because another test covers it } stream.toString should include(s"invalidating ${CacheKey(action)}") @@ -1032,7 +1032,7 @@ class ActionsApiTests extends ControllerTestCommon with WhiskActionsApi { action.version, action.publish, action.annotations ++ systemAnnotations(JAVA_DEFAULT), - updated = response.updated)) + updated = response.updated)) // ignored `updated` field because another test covers it } stream.toString should not include (s"invalidating ${CacheKey(action)} on delete") @@ -1053,7 +1053,7 @@ class ActionsApiTests extends ControllerTestCommon with WhiskActionsApi { action.version, action.publish, action.annotations ++ systemAnnotations(JAVA_DEFAULT), - updated = response.updated)) + updated = response.updated)) // ignored `updated` field because another test covers it } stream.toString should include(s"serving from cache: ${CacheKey(action)}") @@ -1074,7 +1074,7 @@ class ActionsApiTests extends ControllerTestCommon with WhiskActionsApi { action.version, action.publish, action.annotations ++ systemAnnotations(JAVA_DEFAULT), - updated = response.updated)) + updated = response.updated)) // ignored `updated` field because another test covers it } stream.toString should include(s"invalidating ${CacheKey(action)}") stream.reset() @@ -1124,7 +1124,7 @@ class ActionsApiTests extends ControllerTestCommon with WhiskActionsApi { action.version, action.publish, action.annotations ++ systemAnnotations(kind), - updated = response.updated)) + updated = response.updated)) // ignored `updated` field because another test covers it } stream.toString should include regex (expectedGetLog) @@ -1232,7 +1232,7 @@ class ActionsApiTests extends ControllerTestCommon with WhiskActionsApi { action.version.upPatch, action.publish, action.annotations ++ systemAnnotations(kind), - updated = response.updated)) + updated = response.updated)) // ignored `updated` field because another test covers it } stream.toString should include regex (expectedPutLog) stream.reset() @@ -1251,7 +1251,7 @@ class ActionsApiTests extends ControllerTestCommon with WhiskActionsApi { action.version.upPatch, action.publish, action.annotations ++ systemAnnotations(kind), - updated = response.updated)) + updated = response.updated)) // ignored `updated` field because another test covers it } stream.toString should include(s"invalidating ${CacheKey(action)}") stream.reset() @@ -1299,7 +1299,7 @@ class ActionsApiTests extends ControllerTestCommon with WhiskActionsApi { actionOldSchema.version.upPatch, actionOldSchema.publish, actionOldSchema.annotations ++ systemAnnotations(NODEJS10, create = false), - updated = response.updated)) + updated = response.updated)) // ignored `updated` field because another test covers it } stream.toString should include regex (expectedPutLog) @@ -1324,7 +1324,7 @@ class ActionsApiTests extends ControllerTestCommon with WhiskActionsApi { actionOldSchema.version.upPatch, actionOldSchema.publish, actionOldSchema.annotations ++ systemAnnotations(NODEJS10, create = false), - updated = response.updated)) + updated = response.updated)) // ignored `updated` field because another test covers it } } @@ -1370,7 +1370,7 @@ class ActionsApiTests extends ControllerTestCommon with WhiskActionsApi { content.limits.get.concurrency.get), version = action.version.upPatch, annotations = action.annotations ++ systemAnnotations(NODEJS10, create = false), - updated = response.updated) + updated = response.updated) // ignored `updated` field because another test covers it } } } @@ -1392,7 +1392,7 @@ class ActionsApiTests extends ControllerTestCommon with WhiskActionsApi { content.parameters.get, version = action.version.upPatch, annotations = action.annotations ++ systemAnnotations(NODEJS10, false), - updated = response.updated) + updated = response.updated) // ignored `updated` field because another test covers it } } } From f5b8a927cf13b25c36ff92e4ceb9410587aaca69 Mon Sep 17 00:00:00 2001 From: seonghyun Date: Fri, 27 Sep 2019 15:16:45 +0900 Subject: [PATCH 07/18] Add singleton method to get current timestamp --- .../apache/openwhisk/core/entity/WhiskAction.scala | 12 ++++-------- .../apache/openwhisk/core/entity/WhiskEntity.scala | 14 +++++++++++--- 2 files changed, 15 insertions(+), 11 deletions(-) diff --git a/common/scala/src/main/scala/org/apache/openwhisk/core/entity/WhiskAction.scala b/common/scala/src/main/scala/org/apache/openwhisk/core/entity/WhiskAction.scala index 391f471030e..1b9fa4eb16c 100644 --- a/common/scala/src/main/scala/org/apache/openwhisk/core/entity/WhiskAction.scala +++ b/common/scala/src/main/scala/org/apache/openwhisk/core/entity/WhiskAction.scala @@ -19,8 +19,7 @@ package org.apache.openwhisk.core.entity import java.io.{ByteArrayInputStream, ByteArrayOutputStream} import java.nio.charset.StandardCharsets.UTF_8 -import java.time.temporal.ChronoUnit -import java.time.{Clock, Instant} +import java.time.Instant import java.util.Base64 import akka.http.scaladsl.model.ContentTypes @@ -125,8 +124,7 @@ abstract class WhiskActionLikeMetaData(override val name: EntityName) extends Wh * @param version the semantic version * @param publish true to share the action or false otherwise * @param annotations the set of annotations to attribute to the action - * @param updated the timestamp when the action is updated. - * Since it's stored in milliseconds in the db, it's truncated. + * @param updated the timestamp when the action is updated * @throws IllegalArgumentException if any argument is undefined */ @throws[IllegalArgumentException] @@ -138,7 +136,7 @@ case class WhiskAction(namespace: EntityPath, version: SemVer = SemVer(), publish: Boolean = false, annotations: Parameters = Parameters(), - override val updated: Instant = Instant.now(Clock.systemUTC()).truncatedTo(ChronoUnit.MILLIS)) + override val updated: Instant = WhiskEntity.currentMillis()) extends WhiskActionLike(name) { require(exec != null, "exec undefined") @@ -205,9 +203,7 @@ case class WhiskActionMetaData(namespace: EntityPath, version: SemVer = SemVer(), publish: Boolean = false, annotations: Parameters = Parameters(), - override val updated: Instant = Instant - .now(Clock.systemUTC()) - .truncatedTo(ChronoUnit.MILLIS), + override val updated: Instant = WhiskEntity.currentMillis(), binding: Option[EntityPath] = None) extends WhiskActionLikeMetaData(name) { diff --git a/common/scala/src/main/scala/org/apache/openwhisk/core/entity/WhiskEntity.scala b/common/scala/src/main/scala/org/apache/openwhisk/core/entity/WhiskEntity.scala index baa64621cc0..b84c1f34e01 100644 --- a/common/scala/src/main/scala/org/apache/openwhisk/core/entity/WhiskEntity.scala +++ b/common/scala/src/main/scala/org/apache/openwhisk/core/entity/WhiskEntity.scala @@ -19,10 +19,9 @@ package org.apache.openwhisk.core.entity import java.time.Clock import java.time.Instant +import java.time.temporal.ChronoUnit -import scala.Stream import scala.util.Try - import spray.json._ import org.apache.openwhisk.core.database.DocumentUnreadable import org.apache.openwhisk.core.database.DocumentTypeMismatchException @@ -49,7 +48,7 @@ abstract class WhiskEntity protected[entity] (en: EntityName, val entityType: St val version: SemVer val publish: Boolean val annotations: Parameters - val updated = Instant.now(Clock.systemUTC()) + val updated = WhiskEntity.currentMillis() /** * The name of the entity qualified with its namespace and version for @@ -112,6 +111,15 @@ object WhiskEntity { def qualifiedName(namespace: EntityPath, activationId: ActivationId) = { s"$namespace${EntityPath.PATHSEP}$activationId" } + + /** + * Get Instant with a millisecond precision + * because it's stored in milliseconds in the db + */ + def currentMillis() = { + Instant.now(Clock.systemUTC()).truncatedTo(ChronoUnit.MILLIS) + } + } object WhiskDocumentReader extends DocumentReader { From 7a56f532e821c553285268e368766d0b743c370c Mon Sep 17 00:00:00 2001 From: seonghyun Date: Fri, 27 Sep 2019 15:34:19 +0900 Subject: [PATCH 08/18] Modify test case --- .../openwhisk/core/controller/test/ActionsApiTests.scala | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/tests/src/test/scala/org/apache/openwhisk/core/controller/test/ActionsApiTests.scala b/tests/src/test/scala/org/apache/openwhisk/core/controller/test/ActionsApiTests.scala index 0b2ebded7cf..0902410b647 100644 --- a/tests/src/test/scala/org/apache/openwhisk/core/controller/test/ActionsApiTests.scala +++ b/tests/src/test/scala/org/apache/openwhisk/core/controller/test/ActionsApiTests.scala @@ -228,7 +228,8 @@ class ActionsApiTests extends ControllerTestCommon with WhiskActionsApi { implicit val tid = transid() val action = WhiskAction(namespace, aname(), jsDefault("")) - val dummyUpdated = 1569400000000L; + val dummyUpdated = WhiskEntity.currentMillis().toEpochMilli + val content = JsObject( "exec" -> JsObject("code" -> "".toJson, "kind" -> action.exec.kind.toJson), "updated" -> dummyUpdated.toJson) @@ -236,7 +237,7 @@ class ActionsApiTests extends ControllerTestCommon with WhiskActionsApi { Put(s"$collectionPath/${action.name}", content) ~> Route.seal(routes(creds)) ~> check { status should be(OK) val response = responseAs[WhiskAction] - response.updated.toEpochMilli should not be (dummyUpdated) + response.updated.toEpochMilli should be > dummyUpdated } } From 95fadfc584358517f3a7a1749a0f213e84ddc637 Mon Sep 17 00:00:00 2001 From: seonghyun Date: Fri, 27 Sep 2019 15:37:02 +0900 Subject: [PATCH 09/18] Update annotation --- .../org/apache/openwhisk/core/entity/WhiskEntity.scala | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/common/scala/src/main/scala/org/apache/openwhisk/core/entity/WhiskEntity.scala b/common/scala/src/main/scala/org/apache/openwhisk/core/entity/WhiskEntity.scala index b84c1f34e01..0fd81d38ef0 100644 --- a/common/scala/src/main/scala/org/apache/openwhisk/core/entity/WhiskEntity.scala +++ b/common/scala/src/main/scala/org/apache/openwhisk/core/entity/WhiskEntity.scala @@ -36,7 +36,7 @@ import org.apache.openwhisk.http.Messages * @param namespace the namespace for the entity as an abstract field * @param version the semantic version as an abstract field * @param publish true to share the entity and false to keep it private as an abstract field - * @param annotation the set of annotations to attribute to the entity + * @param annotations the set of annotations to attribute to the entity * * @throws IllegalArgumentException if any argument is undefined */ @@ -113,8 +113,8 @@ object WhiskEntity { } /** - * Get Instant with a millisecond precision - * because it's stored in milliseconds in the db + * Get Instant object with a millisecond precision + * timestamp of whisk entity is stored in milliseconds in the db */ def currentMillis() = { Instant.now(Clock.systemUTC()).truncatedTo(ChronoUnit.MILLIS) From 9d66af70240af7bb97668ad7da950a3d07edfe29 Mon Sep 17 00:00:00 2001 From: seonghyun Date: Fri, 27 Sep 2019 17:56:30 +0900 Subject: [PATCH 10/18] Add updated field on package entity --- .../openwhisk/core/entity/WhiskPackage.scala | 13 +++++--- .../controller/test/ActionsApiTests.scala | 4 +-- .../controller/test/PackagesApiTests.scala | 33 ++++++++++++++++--- 3 files changed, 39 insertions(+), 11 deletions(-) diff --git a/common/scala/src/main/scala/org/apache/openwhisk/core/entity/WhiskPackage.scala b/common/scala/src/main/scala/org/apache/openwhisk/core/entity/WhiskPackage.scala index c3c5050d100..c606867852f 100644 --- a/common/scala/src/main/scala/org/apache/openwhisk/core/entity/WhiskPackage.scala +++ b/common/scala/src/main/scala/org/apache/openwhisk/core/entity/WhiskPackage.scala @@ -17,11 +17,12 @@ package org.apache.openwhisk.core.entity +import java.time.Instant + import scala.concurrent.ExecutionContext import scala.concurrent.Future import scala.language.postfixOps import scala.util.Try - import spray.json.DefaultJsonProtocol import spray.json.DefaultJsonProtocol._ import spray.json._ @@ -60,7 +61,8 @@ case class WhiskPackagePut(binding: Option[Binding] = None, * @param parameters the set of parameters to bind to the action environment * @param version the semantic version * @param publish true to share the action or false otherwise - * @param annotation the set of annotations to attribute to the package + * @param annotations the set of annotations to attribute to the package + * @param updated the timestamp when the package is updated * @throws IllegalArgumentException if any argument is undefined */ @throws[IllegalArgumentException] @@ -70,7 +72,8 @@ case class WhiskPackage(namespace: EntityPath, parameters: Parameters = Parameters(), version: SemVer = SemVer(), publish: Boolean = false, - annotations: Parameters = Parameters()) + annotations: Parameters = Parameters(), + override val updated: Instant = WhiskEntity.currentMillis()) extends WhiskEntity(name, "package") { require(binding != null || (binding map { _ != null } getOrElse true), "binding undefined") @@ -159,6 +162,8 @@ object WhiskPackage with WhiskEntityQueries[WhiskPackage] with DefaultJsonProtocol { + import WhiskActivation.instantSerdes + val bindingFieldName = "binding" override val collectionName = "packages" @@ -197,7 +202,7 @@ object WhiskPackage override def write(b: Option[Binding]) = Binding.optionalBindingSerializer.write(b) override def read(js: JsValue) = Binding.optionalBindingDeserializer.read(js) } - jsonFormat7(WhiskPackage.apply) + jsonFormat8(WhiskPackage.apply) } override val cacheEnabled = true diff --git a/tests/src/test/scala/org/apache/openwhisk/core/controller/test/ActionsApiTests.scala b/tests/src/test/scala/org/apache/openwhisk/core/controller/test/ActionsApiTests.scala index 0902410b647..169d0d60715 100644 --- a/tests/src/test/scala/org/apache/openwhisk/core/controller/test/ActionsApiTests.scala +++ b/tests/src/test/scala/org/apache/openwhisk/core/controller/test/ActionsApiTests.scala @@ -202,7 +202,7 @@ class ActionsApiTests extends ControllerTestCommon with WhiskActionsApi { } } - it should "get action with `updated` field" in { + it should "get action with updated field" in { implicit val tid = transid() val action = WhiskAction(namespace, aname(), jsDefault("??"), Parameters("x", "b")) @@ -224,7 +224,7 @@ class ActionsApiTests extends ControllerTestCommon with WhiskActionsApi { } } - it should "not update action `updated` field with a put" in { + it should "ignore updated field when updating action" in { implicit val tid = transid() val action = WhiskAction(namespace, aname(), jsDefault("")) diff --git a/tests/src/test/scala/org/apache/openwhisk/core/controller/test/PackagesApiTests.scala b/tests/src/test/scala/org/apache/openwhisk/core/controller/test/PackagesApiTests.scala index 5d1ecca243b..2c86f92fb78 100644 --- a/tests/src/test/scala/org/apache/openwhisk/core/controller/test/PackagesApiTests.scala +++ b/tests/src/test/scala/org/apache/openwhisk/core/controller/test/PackagesApiTests.scala @@ -297,6 +297,21 @@ class PackagesApiTests extends ControllerTestCommon with WhiskPackagesApi { } } + it should "get package with updated field" in { + implicit val tid = transid() + val provider = WhiskPackage(namespace, aname(), None) + put(entityStore, provider) + + // `updated` field should be compared with a document in DB + val pkg = get(entityStore, provider.docid, WhiskPackage) + + Get(s"$collectionPath/${provider.name}") ~> Route.seal(routes(creds)) ~> check { + status should be(OK) + val response = responseAs[WhiskPackageWithActions] + response should be(provider copy (updated = pkg.updated) withActions ()) + } + } + it should "get package reference for private package in same namespace" in { implicit val tid = transid() val provider = WhiskPackage(namespace, aname(), None, Parameters("a", "A") ++ Parameters("b", "B")) @@ -422,7 +437,7 @@ class PackagesApiTests extends ControllerTestCommon with WhiskPackagesApi { deletePackage(provider.docid) status should be(OK) val response = responseAs[WhiskPackage] - response should be(provider) + response should be(provider copy (updated = response.updated)) // ignored `updated` field because another test covers it } } @@ -492,7 +507,7 @@ class PackagesApiTests extends ControllerTestCommon with WhiskPackagesApi { deletePackage(reference.docid) status should be(OK) val response = responseAs[WhiskPackage] - response should be(reference) + response should be(reference copy (updated = response.updated)) // ignored `updated` field because another test covers it } } @@ -527,7 +542,8 @@ class PackagesApiTests extends ControllerTestCommon with WhiskPackagesApi { reference.namespace, reference.name, provider.bind, - annotations = bindingAnnotation(provider.bind.get)) + annotations = bindingAnnotation(provider.bind.get), + updated = response.updated) // ignored `updated` field because another test covers it } } } @@ -633,7 +649,13 @@ class PackagesApiTests extends ControllerTestCommon with WhiskPackagesApi { deletePackage(provider.docid) val response = responseAs[WhiskPackage] response should be( - WhiskPackage(namespace, provider.name, None, version = provider.version.upPatch, publish = true)) + WhiskPackage( + namespace, + provider.name, + None, + version = provider.version.upPatch, + publish = true, + updated = response.updated)) // ignored `updated` field because another test covers it } } @@ -664,7 +686,8 @@ class PackagesApiTests extends ControllerTestCommon with WhiskPackagesApi { reference.binding, version = reference.version.upPatch, publish = true, - annotations = reference.annotations ++ Parameters("a", "b")) + annotations = reference.annotations ++ Parameters("a", "b"), + updated = response.updated) // ignored `updated` field because another test covers it } } } From 36079f3fb5c5889b971861a316dfe8816c45329d Mon Sep 17 00:00:00 2001 From: seonghyun Date: Fri, 27 Sep 2019 18:15:19 +0900 Subject: [PATCH 11/18] Add updated field on trigger entity --- .../openwhisk/core/entity/WhiskTrigger.scala | 11 ++++-- .../controller/test/TriggersApiTests.scala | 35 ++++++++++++++----- 2 files changed, 35 insertions(+), 11 deletions(-) diff --git a/common/scala/src/main/scala/org/apache/openwhisk/core/entity/WhiskTrigger.scala b/common/scala/src/main/scala/org/apache/openwhisk/core/entity/WhiskTrigger.scala index d6668a9cb92..0470980812b 100644 --- a/common/scala/src/main/scala/org/apache/openwhisk/core/entity/WhiskTrigger.scala +++ b/common/scala/src/main/scala/org/apache/openwhisk/core/entity/WhiskTrigger.scala @@ -17,6 +17,8 @@ package org.apache.openwhisk.core.entity +import java.time.Instant + import spray.json.DefaultJsonProtocol import org.apache.openwhisk.core.database.DocumentFactory import spray.json._ @@ -54,8 +56,9 @@ case class ReducedRule(action: FullyQualifiedEntityName, status: Status) * @param limits the limits to impose on the trigger * @param version the semantic version * @param publish true to share the action or false otherwise - * @param annotation the set of annotations to attribute to the trigger + * @param annotations the set of annotations to attribute to the trigger * @param rules the map of the rules that are associated with this trigger. Key is the rulename and value is the ReducedRule + * @param updated the timestamp when the trigger is updated * @throws IllegalArgumentException if any argument is undefined */ @throws[IllegalArgumentException] @@ -66,7 +69,8 @@ case class WhiskTrigger(namespace: EntityPath, version: SemVer = SemVer(), publish: Boolean = false, annotations: Parameters = Parameters(), - rules: Option[Map[FullyQualifiedEntityName, ReducedRule]] = None) + rules: Option[Map[FullyQualifiedEntityName, ReducedRule]] = None, + override val updated: Instant = WhiskEntity.currentMillis()) extends WhiskEntity(name, "trigger") { require(limits != null, "limits undefined") @@ -108,11 +112,12 @@ object WhiskTrigger extends DocumentFactory[WhiskTrigger] with WhiskEntityQueries[WhiskTrigger] with DefaultJsonProtocol { + import WhiskActivation.instantSerdes override val collectionName = "triggers" private implicit val fqnSerdesAsDocId = FullyQualifiedEntityName.serdesAsDocId - override implicit val serdes = jsonFormat8(WhiskTrigger.apply) + override implicit val serdes = jsonFormat9(WhiskTrigger.apply) override val cacheEnabled = true } diff --git a/tests/src/test/scala/org/apache/openwhisk/core/controller/test/TriggersApiTests.scala b/tests/src/test/scala/org/apache/openwhisk/core/controller/test/TriggersApiTests.scala index 91b22a279c8..3caf864cd08 100644 --- a/tests/src/test/scala/org/apache/openwhisk/core/controller/test/TriggersApiTests.scala +++ b/tests/src/test/scala/org/apache/openwhisk/core/controller/test/TriggersApiTests.scala @@ -183,6 +183,21 @@ class TriggersApiTests extends ControllerTestCommon with WhiskTriggersApi { } } + it should "get trigger with updated field" in { + implicit val tid = transid() + val trigger = WhiskTrigger(namespace, aname(), Parameters("x", "b")) + put(entityStore, trigger) + + // `updated` field should be compared with a document in DB + val t = get(entityStore, trigger.docid, WhiskTrigger) + + Get(s"$collectionPath/${trigger.name}") ~> Route.seal(routes(creds)) ~> check { + status should be(OK) + val response = responseAs[WhiskTrigger] + response should be(trigger copy(updated = t.updated)) + } + } + it should "report Conflict if the name was of a different type" in { implicit val tid = transid() val rule = WhiskRule( @@ -217,7 +232,7 @@ class TriggersApiTests extends ControllerTestCommon with WhiskTriggersApi { deleteTrigger(trigger.docid) status should be(OK) val response = responseAs[WhiskTrigger] - response should be(trigger.withoutRules) + response should be(trigger.withoutRules copy (updated = response.updated)) // ignored `updated` field because another test covers it } } @@ -229,7 +244,7 @@ class TriggersApiTests extends ControllerTestCommon with WhiskTriggersApi { deleteTrigger(trigger.docid) status should be(OK) val response = responseAs[WhiskTrigger] - response should be(trigger.withoutRules) + response should be(trigger.withoutRules copy (updated = response.updated)) } } @@ -323,11 +338,14 @@ class TriggersApiTests extends ControllerTestCommon with WhiskTriggersApi { deleteTrigger(trigger.docid) status should be(OK) val response = responseAs[WhiskTrigger] - response should be(WhiskTrigger( - trigger.namespace, - trigger.name, - trigger.parameters, - version = trigger.version.upPatch).withoutRules) + response should be( + WhiskTrigger( + trigger.namespace, + trigger.name, + trigger.parameters, + version = trigger.version.upPatch, + // ignored `updated` field because another test covers it + updated = response.updated).withoutRules) } } @@ -433,7 +451,8 @@ class TriggersApiTests extends ControllerTestCommon with WhiskTriggersApi { val response = responseAs[WhiskTrigger] status should be(OK) - response should be(trigger.toWhiskTrigger) + // ignored `updated` field because another test covers it + response should be(trigger.toWhiskTrigger copy (updated = response.updated)) } } From 33fa090f7e64d6b9110e8aef5bd689fc19d0ebef Mon Sep 17 00:00:00 2001 From: seonghyun Date: Fri, 27 Sep 2019 18:40:18 +0900 Subject: [PATCH 12/18] Serialize updated field in rules entity --- .../openwhisk/core/entity/WhiskRule.scala | 23 +++-- .../core/controller/test/RulesApiTests.scala | 83 ++++++++++++++----- 2 files changed, 78 insertions(+), 28 deletions(-) diff --git a/common/scala/src/main/scala/org/apache/openwhisk/core/entity/WhiskRule.scala b/common/scala/src/main/scala/org/apache/openwhisk/core/entity/WhiskRule.scala index 6a7e929bcf5..259a6123d4f 100644 --- a/common/scala/src/main/scala/org/apache/openwhisk/core/entity/WhiskRule.scala +++ b/common/scala/src/main/scala/org/apache/openwhisk/core/entity/WhiskRule.scala @@ -17,10 +17,11 @@ package org.apache.openwhisk.core.entity +import java.time.Instant + import scala.util.Failure import scala.util.Success import scala.util.Try - import spray.json.DefaultJsonProtocol import spray.json.DeserializationException import spray.json.JsObject @@ -65,7 +66,8 @@ case class WhiskRulePut(trigger: Option[FullyQualifiedEntityName] = None, * @param action the action name to invoke invoke when trigger is fired * @param version the semantic version * @param publish true to share the action or false otherwise - * @param annotation the set of annotations to attribute to the rule + * @param annotations the set of annotations to attribute to the rule + * @param updated the timestamp when the rule is updated * @throws IllegalArgumentException if any argument is undefined */ @throws[IllegalArgumentException] @@ -75,10 +77,12 @@ case class WhiskRule(namespace: EntityPath, action: FullyQualifiedEntityName, version: SemVer = SemVer(), publish: Boolean = false, - annotations: Parameters = Parameters()) + annotations: Parameters = Parameters(), + override val updated: Instant = WhiskEntity.currentMillis()) extends WhiskEntity(name, "rule") { - def withStatus(s: Status) = WhiskRuleResponse(namespace, name, s, trigger, action, version, publish, annotations) + def withStatus(s: Status) = + WhiskRuleResponse(namespace, name, s, trigger, action, version, publish, annotations, updated) def toJson = WhiskRule.serdes.write(this).asJsObject } @@ -95,7 +99,7 @@ case class WhiskRule(namespace: EntityPath, * @param action the action name to invoke invoke when trigger is fired * @param version the semantic version * @param publish true to share the action or false otherwise - * @param annotation the set of annotations to attribute to the rule + * @param annotations the set of annotations to attribute to the rule */ case class WhiskRuleResponse(namespace: EntityPath, name: EntityName, @@ -104,7 +108,8 @@ case class WhiskRuleResponse(namespace: EntityPath, action: FullyQualifiedEntityName, version: SemVer = SemVer(), publish: Boolean = false, - annotations: Parameters = Parameters()) { + annotations: Parameters = Parameters(), + updated: Instant) { def toWhiskRule = WhiskRule(namespace, name, trigger, action, version, publish, annotations) } @@ -195,11 +200,12 @@ protected[core] object Status extends ArgNormalizer[Status] { } object WhiskRule extends DocumentFactory[WhiskRule] with WhiskEntityQueries[WhiskRule] with DefaultJsonProtocol { + import WhiskActivation.instantSerdes override val collectionName = "rules" private implicit val fqnSerdes = FullyQualifiedEntityName.serdes - private val caseClassSerdes = jsonFormat7(WhiskRule.apply) + private val caseClassSerdes = jsonFormat8(WhiskRule.apply) override implicit val serdes = new RootJsonFormat[WhiskRule] { def write(r: WhiskRule) = caseClassSerdes.write(r) @@ -233,8 +239,9 @@ object WhiskRule extends DocumentFactory[WhiskRule] with WhiskEntityQueries[Whis } object WhiskRuleResponse extends DefaultJsonProtocol { + import WhiskActivation.instantSerdes private implicit val fqnSerdes = FullyQualifiedEntityName.serdes - implicit val serdes = jsonFormat8(WhiskRuleResponse.apply) + implicit val serdes = jsonFormat9(WhiskRuleResponse.apply) } object WhiskRulePut extends DefaultJsonProtocol { diff --git a/tests/src/test/scala/org/apache/openwhisk/core/controller/test/RulesApiTests.scala b/tests/src/test/scala/org/apache/openwhisk/core/controller/test/RulesApiTests.scala index d497593d29f..f144de589a0 100644 --- a/tests/src/test/scala/org/apache/openwhisk/core/controller/test/RulesApiTests.scala +++ b/tests/src/test/scala/org/apache/openwhisk/core/controller/test/RulesApiTests.scala @@ -164,14 +164,14 @@ class RulesApiTests extends ControllerTestCommon with WhiskRulesApi { Get(s"$collectionPath/${rule.name}") ~> Route.seal(routes(creds)) ~> check { status should be(OK) val response = responseAs[WhiskRuleResponse] - response should be(rule.withStatus(Status.INACTIVE)) + response should be(rule.withStatus(Status.INACTIVE) copy (updated = response.updated)) } // it should "get trigger by name in explicit namespace owned by subject" in Get(s"/$namespace/${collection.path}/${rule.name}") ~> Route.seal(routes(creds)) ~> check { status should be(OK) val response = responseAs[WhiskRuleResponse] - response should be(rule.withStatus(Status.INACTIVE)) + response should be(rule.withStatus(Status.INACTIVE) copy (updated = response.updated)) } // it should "reject get trigger by name in explicit namespace not owned by subject" in @@ -207,7 +207,33 @@ class RulesApiTests extends ControllerTestCommon with WhiskRulesApi { Get(s"$collectionPath/${rule.name}") ~> Route.seal(routes(creds)) ~> check { status should be(OK) val response = responseAs[WhiskRuleResponse] - response should be(rule.withStatus(Status.ACTIVE)) + // ignored `updated` field because another test covers it + response should be(rule.withStatus(Status.ACTIVE) copy (updated = response.updated)) + } + } + + it should "get rule with updated field" in { + implicit val tid = transid() + + val rule = WhiskRule( + namespace, + EntityName("get_active_rule"), + afullname(namespace, "get_active_rule trigger"), + afullname(namespace, "an action")) + val trigger = WhiskTrigger(rule.trigger.path, rule.trigger.name, rules = Some { + Map(rule.fullyQualifiedName(false) -> ReducedRule(rule.action, Status.ACTIVE)) + }) + + put(entityStore, trigger) + put(entityStore, rule) + + // `updated` field should be compared with a document in DB + val r = get(entityStore, rule.docid, WhiskRule) + + Get(s"$collectionPath/${rule.name}") ~> Route.seal(routes(creds)) ~> check { + status should be(OK) + val response = responseAs[WhiskRuleResponse] + response should be(rule.withStatus(Status.ACTIVE) copy (updated = r.updated)) } } @@ -227,7 +253,8 @@ class RulesApiTests extends ControllerTestCommon with WhiskRulesApi { Get(s"$collectionPath/${rule.name}") ~> Route.seal(routes(creds)) ~> check { status should be(OK) val response = responseAs[WhiskRuleResponse] - response should be(rule.withStatus(Status.INACTIVE)) + // ignored `updated` field because another test covers it + response should be(rule.withStatus(Status.INACTIVE) copy (updated = response.updated)) } } @@ -264,7 +291,8 @@ class RulesApiTests extends ControllerTestCommon with WhiskRulesApi { status should be(OK) val response = responseAs[WhiskRuleResponse] - response should be(rule.withStatus(Status.INACTIVE)) + // ignored `updated` field because another test covers it + response should be(rule.withStatus(Status.INACTIVE) copy (updated = response.updated)) } } @@ -292,7 +320,8 @@ class RulesApiTests extends ControllerTestCommon with WhiskRulesApi { status should be(OK) t.rules.get.get(rule.fullyQualifiedName(false)) shouldBe None val response = responseAs[WhiskRuleResponse] - response should be(rule.withStatus(Status.INACTIVE)) + // ignored `updated` field because another test covers it + response should be(rule.withStatus(Status.INACTIVE) copy (updated = response.updated)) } } @@ -310,7 +339,8 @@ class RulesApiTests extends ControllerTestCommon with WhiskRulesApi { Delete(s"$collectionPath/${rule.name}") ~> Route.seal(routes(creds)) ~> check { status should be(OK) val response = responseAs[WhiskRuleResponse] - response should be(rule.withStatus(Status.INACTIVE)) + // ignored `updated` field because another test covers it + response should be(rule.withStatus(Status.INACTIVE) copy (updated = response.updated)) } } @@ -329,7 +359,8 @@ class RulesApiTests extends ControllerTestCommon with WhiskRulesApi { status should be(OK) val response = responseAs[WhiskRuleResponse] - response should be(rule.withStatus(Status.INACTIVE)) + // ignored `updated` field because another test covers it + response should be(rule.withStatus(Status.INACTIVE) copy (updated = response.updated)) } } @@ -356,7 +387,8 @@ class RulesApiTests extends ControllerTestCommon with WhiskRulesApi { status should be(OK) val response = responseAs[WhiskRuleResponse] - response should be(rule.withStatus(Status.ACTIVE)) + // ignored `updated` field because another test covers it + response should be(rule.withStatus(Status.ACTIVE) copy (updated = response.updated)) t.rules.get(rule.fullyQualifiedName(false)) shouldBe ReducedRule(action.fullyQualifiedName(false), Status.ACTIVE) } } @@ -385,7 +417,8 @@ class RulesApiTests extends ControllerTestCommon with WhiskRulesApi { status should be(OK) val response = responseAs[WhiskRuleResponse] - response should be(rule.withStatus(Status.ACTIVE)) + // ignored `updated` field because another test covers it + response should be(rule.withStatus(Status.ACTIVE) copy (updated = response.updated)) t.rules.get(rule.fullyQualifiedName(false)) shouldBe ReducedRule(action.fullyQualifiedName(false), Status.ACTIVE) } } @@ -436,7 +469,8 @@ class RulesApiTests extends ControllerTestCommon with WhiskRulesApi { status should be(OK) val response = responseAs[WhiskRuleResponse] - response should be(rule.withStatus(Status.ACTIVE)) + // ignored `updated` field because another test covers it + response should be(rule.withStatus(Status.ACTIVE) copy (updated = response.updated)) t.rules.get(rule.fullyQualifiedName(false)) shouldBe ReducedRule(action.fullyQualifiedName(false), Status.ACTIVE) } } @@ -468,7 +502,7 @@ class RulesApiTests extends ControllerTestCommon with WhiskRulesApi { status should be(OK) val response = responseAs[WhiskRuleResponse] - response should be(rule.withStatus(Status.ACTIVE)) + response should be(rule.withStatus(Status.ACTIVE) copy (updated = response.updated)) t.rules.get(rule.fullyQualifiedName(false)) shouldBe ReducedRule(action.fullyQualifiedName(false), Status.ACTIVE) } } @@ -599,7 +633,8 @@ class RulesApiTests extends ControllerTestCommon with WhiskRulesApi { Status.INACTIVE, trigger.fullyQualifiedName(false), action.fullyQualifiedName(false), - version = SemVer().upPatch)) + version = SemVer().upPatch, + updated = response.updated)) // ignored `updated` field because another test covers it } } @@ -630,7 +665,8 @@ class RulesApiTests extends ControllerTestCommon with WhiskRulesApi { Status.INACTIVE, trigger.fullyQualifiedName(false), action.fullyQualifiedName(false), - version = SemVer().upPatch)) + version = SemVer().upPatch, + updated = response.updated)) // ignored `updated` field because another test covers it } } @@ -661,7 +697,8 @@ class RulesApiTests extends ControllerTestCommon with WhiskRulesApi { Status.INACTIVE, trigger.fullyQualifiedName(false), action.fullyQualifiedName(false), - version = SemVer().upPatch)) + version = SemVer().upPatch, + updated = response.updated)) // ignored `updated` field because another test covers it } } @@ -692,7 +729,8 @@ class RulesApiTests extends ControllerTestCommon with WhiskRulesApi { Status.INACTIVE, trigger.fullyQualifiedName(false), action.fullyQualifiedName(false), - version = SemVer().upPatch)) + version = SemVer().upPatch, + updated = response.updated)) // ignored `updated` field because another test covers it } } @@ -720,7 +758,8 @@ class RulesApiTests extends ControllerTestCommon with WhiskRulesApi { Status.INACTIVE, trigger.fullyQualifiedName(false), action.fullyQualifiedName(false), - version = SemVer().upPatch)) + version = SemVer().upPatch, + updated = response.updated)) // ignored `updated` field because another test covers it } } @@ -802,7 +841,8 @@ class RulesApiTests extends ControllerTestCommon with WhiskRulesApi { Status.ACTIVE, trigger.fullyQualifiedName(false), action.fullyQualifiedName(false), - version = SemVer().upPatch)) + version = SemVer().upPatch, + updated = response.updated)) // ignored `updated` field because another test covers it } } @@ -948,7 +988,8 @@ class RulesApiTests extends ControllerTestCommon with WhiskRulesApi { Get(s"$collectionPath/${rule.name}") ~> Route.seal(routes(creds)) ~> check { status should be(OK) val response = responseAs[WhiskRuleResponse] - response should be(rule.toWhiskRule.withStatus(Status.INACTIVE)) + // ignored `updated` field because another test covers it + response should be(rule.toWhiskRule.withStatus(Status.INACTIVE) copy (updated = response.updated)) } } @@ -972,7 +1013,9 @@ class RulesApiTests extends ControllerTestCommon with WhiskRulesApi { status should be(OK) t.rules.get(rule.fullyQualifiedName(false)) shouldBe ReducedRule(action.fullyQualifiedName(false), Status.ACTIVE) val response = responseAs[WhiskRuleResponse] - response should be(rule.withStatus(Status.ACTIVE)) + + // ignored `updated` field because another test covers it + response should be(rule.withStatus(Status.ACTIVE) copy (updated = response.updated)) } } From 2cdf7ebee707a1e1c8fe22a92df2af21eb709df0 Mon Sep 17 00:00:00 2001 From: seonghyun Date: Fri, 27 Sep 2019 18:44:07 +0900 Subject: [PATCH 13/18] Fix scheme tests --- .../openwhisk/core/controller/test/TriggersApiTests.scala | 2 +- .../org/apache/openwhisk/core/entity/test/SchemaTests.scala | 6 ++++-- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/tests/src/test/scala/org/apache/openwhisk/core/controller/test/TriggersApiTests.scala b/tests/src/test/scala/org/apache/openwhisk/core/controller/test/TriggersApiTests.scala index 3caf864cd08..d44de42c9ec 100644 --- a/tests/src/test/scala/org/apache/openwhisk/core/controller/test/TriggersApiTests.scala +++ b/tests/src/test/scala/org/apache/openwhisk/core/controller/test/TriggersApiTests.scala @@ -194,7 +194,7 @@ class TriggersApiTests extends ControllerTestCommon with WhiskTriggersApi { Get(s"$collectionPath/${trigger.name}") ~> Route.seal(routes(creds)) ~> check { status should be(OK) val response = responseAs[WhiskTrigger] - response should be(trigger copy(updated = t.updated)) + response should be(trigger copy (updated = t.updated)) } } diff --git a/tests/src/test/scala/org/apache/openwhisk/core/entity/test/SchemaTests.scala b/tests/src/test/scala/org/apache/openwhisk/core/entity/test/SchemaTests.scala index 6f9a322ca1b..42fb0d0dfda 100644 --- a/tests/src/test/scala/org/apache/openwhisk/core/entity/test/SchemaTests.scala +++ b/tests/src/test/scala/org/apache/openwhisk/core/entity/test/SchemaTests.scala @@ -431,7 +431,8 @@ class SchemaTests extends FlatSpec with BeforeAndAfter with ExecHelpers with Mat "parameters" -> Parameters().toJson, "version" -> SemVer().toJson, "publish" -> JsFalse, - "annotations" -> Parameters().toJson) + "annotations" -> Parameters().toJson, + "updated" -> pkg.updated.toEpochMilli.toJson) } it should "serialize and deserialize package binding" in { @@ -443,7 +444,8 @@ class SchemaTests extends FlatSpec with BeforeAndAfter with ExecHelpers with Mat "parameters" -> Parameters().toJson, "version" -> SemVer().toJson, "publish" -> JsFalse, - "annotations" -> Parameters().toJson) + "annotations" -> Parameters().toJson, + "updated" -> pkg.updated.toEpochMilli.toJson) //val legacyPkgAsJson = JsObject(pkgAsJson.fields + ("binding" -> JsObject("namespace" -> "x".toJson, "name" -> "y".toJson))) WhiskPackage.serdes.write(pkg) shouldBe pkgAsJson WhiskPackage.serdes.read(pkgAsJson) shouldBe pkg From fda58eb5d7c4e15cba021a4e43e92696c2cbccf4 Mon Sep 17 00:00:00 2001 From: seonghyun Date: Mon, 30 Sep 2019 11:50:12 +0900 Subject: [PATCH 14/18] Update apiv1swagger.json --- core/controller/src/main/resources/apiv1swagger.json | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/core/controller/src/main/resources/apiv1swagger.json b/core/controller/src/main/resources/apiv1swagger.json index 4a3aca7cf98..b9c1060a962 100644 --- a/core/controller/src/main/resources/apiv1swagger.json +++ b/core/controller/src/main/resources/apiv1swagger.json @@ -1998,6 +1998,10 @@ "deactivating" ] }, + "updated": { + "type": "integer", + "description": "Time when the rule was updated" + }, "trigger": { "$ref": "#/definitions/PathName" }, From 348ac8f6949cb355ae5ffc8089715d09735b8cd0 Mon Sep 17 00:00:00 2001 From: seonghyun Date: Wed, 13 Nov 2019 17:21:19 +0900 Subject: [PATCH 15/18] Refactor test code --- .../controller/test/ActionsApiTests.scala | 174 +++++++++--------- .../controller/test/PackagesApiTests.scala | 33 ++-- .../core/controller/test/RulesApiTests.scala | 79 ++++---- .../controller/test/TriggersApiTests.scala | 19 +- 4 files changed, 151 insertions(+), 154 deletions(-) diff --git a/tests/src/test/scala/org/apache/openwhisk/core/controller/test/ActionsApiTests.scala b/tests/src/test/scala/org/apache/openwhisk/core/controller/test/ActionsApiTests.scala index 169d0d60715..1b957bb0ad8 100644 --- a/tests/src/test/scala/org/apache/openwhisk/core/controller/test/ActionsApiTests.scala +++ b/tests/src/test/scala/org/apache/openwhisk/core/controller/test/ActionsApiTests.scala @@ -71,6 +71,14 @@ class ActionsApiTests extends ControllerTestCommon with WhiskActionsApi { val actionLimit = Exec.sizeLimit val parametersLimit = Parameters.sizeLimit + def checkWhiskActionResponse(response: WhiskAction, expected: WhiskAction) = + // ignore `updated` field because another test covers it + response should be(expected copy (updated = response.updated)) + + def checkWhiskActionMetadataResponse(response: WhiskActionMetaData, expected: WhiskActionMetaData) = + // ignore `updated` field because another test covers it + response should be(expected copy (updated = response.updated)) + //// GET /actions it should "return empty list when no actions exist" in { implicit val tid = transid() @@ -347,11 +355,7 @@ class ActionsApiTests extends ControllerTestCommon with WhiskActionsApi { Put(s"$collectionPath/${action.name}", content) ~> Route.seal(routes(creds)) ~> check { status should be(OK) val response = responseAs[WhiskAction] - - // If an action is created with a request, its `updated` timestamp is not known before inserting it - // So it compares with the value of a response - val expectedAction = expectedWhiskAction copy (updated = response.updated) - response should be(expectedAction) + checkWhiskActionResponse(response, expectedWhiskAction) } Get(s"$collectionPath/${action.name}?code=false") ~> Route.seal(routes(creds)) ~> check { @@ -359,26 +363,21 @@ class ActionsApiTests extends ControllerTestCommon with WhiskActionsApi { val responseJson = responseAs[JsObject] responseJson.fields("exec").asJsObject.fields should not(contain key "code") val response = responseAs[WhiskActionMetaData] - - // updated field is overwritten for the same reason as above - response should be(expectedWhiskActionMetaData copy (updated = response.updated)) + checkWhiskActionMetadataResponse(response, expectedWhiskActionMetaData) } Seq(s"$collectionPath/${action.name}", s"$collectionPath/${action.name}?code=true").foreach { path => Get(path) ~> Route.seal(routes(creds)) ~> check { status should be(OK) val response = responseAs[WhiskAction] - // updated field is overwritten for the same reason as above - response should be(expectedWhiskAction copy (updated = response.updated)) + checkWhiskActionResponse(response, expectedWhiskAction) } } Delete(s"$collectionPath/${action.name}") ~> Route.seal(routes(creds)) ~> check { status should be(OK) val response = responseAs[WhiskAction] - - // updated field is overwritten for the same reason as above - response should be(expectedWhiskAction copy (updated = response.updated)) + checkWhiskActionResponse(response, expectedWhiskAction) } } } @@ -577,7 +576,8 @@ class ActionsApiTests extends ControllerTestCommon with WhiskActionsApi { deleteAction(action.docid) status should be(OK) val response = responseAs[WhiskAction] - response should be( + checkWhiskActionResponse( + response, WhiskAction( action.namespace, action.name, @@ -586,8 +586,7 @@ class ActionsApiTests extends ControllerTestCommon with WhiskActionsApi { action.limits, action.version, action.publish, - action.annotations ++ systemAnnotations(NODEJS10), - updated = response.updated)) // ignored `updated` field because another test covers it + action.annotations ++ systemAnnotations(NODEJS10))) } } @@ -599,7 +598,8 @@ class ActionsApiTests extends ControllerTestCommon with WhiskActionsApi { deleteAction(action.docid) status should be(OK) val response = responseAs[WhiskAction] - response should be( + checkWhiskActionResponse( + response, WhiskAction( action.namespace, action.name, @@ -608,8 +608,7 @@ class ActionsApiTests extends ControllerTestCommon with WhiskActionsApi { action.limits, action.version, action.publish, - action.annotations ++ systemAnnotations(BLACKBOX), - updated = response.updated)) // ignored `updated` field because another test covers it + action.annotations ++ systemAnnotations(BLACKBOX))) response.exec shouldBe an[BlackBoxExec] response.exec.asInstanceOf[BlackBoxExec].code shouldBe empty } @@ -623,7 +622,8 @@ class ActionsApiTests extends ControllerTestCommon with WhiskActionsApi { deleteAction(action.docid) status should be(OK) val response = responseAs[WhiskAction] - response should be( + checkWhiskActionResponse( + response, WhiskAction( action.namespace, action.name, @@ -632,8 +632,7 @@ class ActionsApiTests extends ControllerTestCommon with WhiskActionsApi { action.limits, action.version, action.publish, - action.annotations ++ systemAnnotations(BLACKBOX), - updated = response.updated)) // ignored `updated` field because another test covers it + action.annotations ++ systemAnnotations(BLACKBOX))) response.exec shouldBe an[BlackBoxExec] val bb = response.exec.asInstanceOf[BlackBoxExec] bb.code shouldBe Some(Inline("cc")) @@ -652,7 +651,8 @@ class ActionsApiTests extends ControllerTestCommon with WhiskActionsApi { Put(s"$collectionPath/${action.name}?overwrite=true", content) ~> Route.seal(routes(creds)) ~> check { status should be(OK) val response = responseAs[WhiskAction] - response should be( + checkWhiskActionResponse( + response, WhiskAction( action.namespace, action.name, @@ -661,8 +661,7 @@ class ActionsApiTests extends ControllerTestCommon with WhiskActionsApi { action.limits, action.version.upPatch, action.publish, - action.annotations ++ Parameters(WhiskAction.execFieldName, action.exec.kind), - updated = response.updated)) + action.annotations ++ Parameters(WhiskAction.execFieldName, action.exec.kind))) } content = """{"annotations":[{"key":"a","value":"B"}]}""".parseJson.asJsObject @@ -671,7 +670,8 @@ class ActionsApiTests extends ControllerTestCommon with WhiskActionsApi { deleteAction(action.docid) status should be(OK) val response = responseAs[WhiskAction] - response should be( + checkWhiskActionResponse( + response, WhiskAction( action.namespace, action.name, @@ -680,8 +680,7 @@ class ActionsApiTests extends ControllerTestCommon with WhiskActionsApi { action.limits, action.version.upPatch.upPatch, action.publish, - action.annotations ++ Parameters("a", "B") ++ Parameters(WhiskAction.execFieldName, action.exec.kind), - updated = response.updated)) // ignored `updated` field because another test covers it + action.annotations ++ Parameters("a", "B") ++ Parameters(WhiskAction.execFieldName, action.exec.kind))) } } @@ -743,7 +742,8 @@ class ActionsApiTests extends ControllerTestCommon with WhiskActionsApi { deleteAction(action.docid) status should be(OK) val response = responseAs[WhiskAction] - response should be( + checkWhiskActionResponse( + response, WhiskAction( action.namespace, action.name, @@ -752,8 +752,7 @@ class ActionsApiTests extends ControllerTestCommon with WhiskActionsApi { action.limits, action.version, action.publish, - action.annotations ++ systemAnnotations(NODEJS10), - updated = response.updated)) // ignored `updated` field because another test covers it + action.annotations ++ systemAnnotations(NODEJS10))) } } @@ -784,7 +783,8 @@ class ActionsApiTests extends ControllerTestCommon with WhiskActionsApi { deleteAction(action.docid) status should be(OK) val response = responseAs[WhiskAction] - response should be( + checkWhiskActionResponse( + response, WhiskAction( action.namespace, action.name, @@ -793,8 +793,7 @@ class ActionsApiTests extends ControllerTestCommon with WhiskActionsApi { action.limits, action.version, action.publish, - action.annotations ++ systemAnnotations(NODEJS10), - updated = response.updated)) // ignored `updated` field because another test covers it + action.annotations ++ systemAnnotations(NODEJS10))) } } @@ -821,7 +820,8 @@ class ActionsApiTests extends ControllerTestCommon with WhiskActionsApi { Put(s"$collectionPath/${action.name}", content) ~> Route.seal(routes(creds)(transid())) ~> check { status should be(OK) val response = responseAs[WhiskAction] - response should be( + checkWhiskActionResponse( + response, WhiskAction( action.namespace, action.name, @@ -830,8 +830,7 @@ class ActionsApiTests extends ControllerTestCommon with WhiskActionsApi { action.limits, action.version, action.publish, - action.annotations ++ systemAnnotations(kind), - updated = response.updated)) // ignored `updated` field because another test covers it + action.annotations ++ systemAnnotations(kind))) } stream.toString should include(s"caching ${CacheKey(action)}") stream.toString should not include (s"invalidating ${CacheKey(action)} on delete") @@ -841,7 +840,8 @@ class ActionsApiTests extends ControllerTestCommon with WhiskActionsApi { Get(s"$collectionPath/${action.name}") ~> Route.seal(routes(creds)(transid())) ~> check { status should be(OK) val response = responseAs[WhiskAction] - response should be( + checkWhiskActionResponse( + response, WhiskAction( action.namespace, action.name, @@ -850,8 +850,7 @@ class ActionsApiTests extends ControllerTestCommon with WhiskActionsApi { action.limits, action.version, action.publish, - action.annotations ++ systemAnnotations(kind), - updated = response.updated)) // ignored `updated` field because another test covers it + action.annotations ++ systemAnnotations(kind))) } stream.toString should include(s"serving from cache: ${CacheKey(action)}") stream.reset() @@ -860,7 +859,8 @@ class ActionsApiTests extends ControllerTestCommon with WhiskActionsApi { Put(s"$collectionPath/${action.name}?overwrite=true", content) ~> Route.seal(routes(creds)(transid())) ~> check { status should be(OK) val response = responseAs[WhiskAction] - response should be { + checkWhiskActionResponse( + response, WhiskAction( action.namespace, action.name, @@ -869,9 +869,7 @@ class ActionsApiTests extends ControllerTestCommon with WhiskActionsApi { action.limits, action.version.upPatch, action.publish, - action.annotations ++ systemAnnotations(kind), - updated = response.updated) // ignored `updated` field because another test covers it - } + action.annotations ++ systemAnnotations(kind))) } stream.toString should include(s"entity exists, will try to update '$action'") stream.toString should include(s"invalidating ${CacheKey(action)}") @@ -882,7 +880,8 @@ class ActionsApiTests extends ControllerTestCommon with WhiskActionsApi { Delete(s"$collectionPath/${action.name}") ~> Route.seal(routes(creds)(transid())) ~> check { status should be(OK) val response = responseAs[WhiskAction] - response should be( + checkWhiskActionResponse( + response, WhiskAction( action.namespace, action.name, @@ -891,8 +890,7 @@ class ActionsApiTests extends ControllerTestCommon with WhiskActionsApi { action.limits, action.version.upPatch, action.publish, - action.annotations ++ systemAnnotations(kind), - updated = response.updated)) // ignored `updated` field because another test covers it + action.annotations ++ systemAnnotations(kind))) } stream.toString should include(s"invalidating ${CacheKey(action)}") stream.reset() @@ -937,7 +935,8 @@ class ActionsApiTests extends ControllerTestCommon with WhiskActionsApi { Put(s"$collectionPath/${action.name}", content) ~> Route.seal(routes(creds)(transid())) ~> check { status should be(OK) val response = responseAs[WhiskAction] - response should be( + checkWhiskActionResponse( + response, WhiskAction( action.namespace, action.name, @@ -946,8 +945,7 @@ class ActionsApiTests extends ControllerTestCommon with WhiskActionsApi { action.limits, action.version, action.publish, - action.annotations ++ systemAnnotations(kind), - updated = response.updated)) // ignored `updated` field because another test covers it + action.annotations ++ systemAnnotations(kind))) } stream.toString should not include (s"invalidating ${CacheKey(action)} on delete") @@ -958,7 +956,8 @@ class ActionsApiTests extends ControllerTestCommon with WhiskActionsApi { Get(s"$collectionPath/${action.name}") ~> Route.seal(routes(creds)(transid())) ~> check { status should be(OK) val response = responseAs[WhiskAction] - response should be( + checkWhiskActionResponse( + response, WhiskAction( action.namespace, action.name, @@ -967,8 +966,7 @@ class ActionsApiTests extends ControllerTestCommon with WhiskActionsApi { action.limits, action.version, action.publish, - action.annotations ++ systemAnnotations(kind), - updated = response.updated)) // ignored `updated` field because another test covers it + action.annotations ++ systemAnnotations(kind))) } stream.toString should include(s"serving from cache: ${CacheKey(action)}") stream.toString should not include regex(notExpectedGetLog) @@ -978,7 +976,8 @@ class ActionsApiTests extends ControllerTestCommon with WhiskActionsApi { Delete(s"$collectionPath/${action.name}") ~> Route.seal(routes(creds)(transid())) ~> check { status should be(OK) val response = responseAs[WhiskAction] - response should be( + checkWhiskActionResponse( + response, WhiskAction( action.namespace, action.name, @@ -987,8 +986,7 @@ class ActionsApiTests extends ControllerTestCommon with WhiskActionsApi { action.limits, action.version, action.publish, - action.annotations ++ systemAnnotations(kind), - updated = response.updated)) // ignored `updated` field because another test covers it + action.annotations ++ systemAnnotations(kind))) } stream.toString should include(s"invalidating ${CacheKey(action)}") @@ -1023,7 +1021,8 @@ class ActionsApiTests extends ControllerTestCommon with WhiskActionsApi { Put(s"$collectionPath/$name", content) ~> Route.seal(routes(creds)(transid())) ~> check { status should be(OK) val response = responseAs[WhiskAction] - response should be( + checkWhiskActionResponse( + response, WhiskAction( action.namespace, action.name, @@ -1032,8 +1031,7 @@ class ActionsApiTests extends ControllerTestCommon with WhiskActionsApi { action.limits, action.version, action.publish, - action.annotations ++ systemAnnotations(JAVA_DEFAULT), - updated = response.updated)) // ignored `updated` field because another test covers it + action.annotations ++ systemAnnotations(JAVA_DEFAULT))) } stream.toString should not include (s"invalidating ${CacheKey(action)} on delete") @@ -1044,7 +1042,8 @@ class ActionsApiTests extends ControllerTestCommon with WhiskActionsApi { Get(s"$collectionPath/$name") ~> Route.seal(routes(creds)(transid())) ~> check { status should be(OK) val response = responseAs[WhiskAction] - response should be( + checkWhiskActionResponse( + response, WhiskAction( action.namespace, action.name, @@ -1053,8 +1052,7 @@ class ActionsApiTests extends ControllerTestCommon with WhiskActionsApi { action.limits, action.version, action.publish, - action.annotations ++ systemAnnotations(JAVA_DEFAULT), - updated = response.updated)) // ignored `updated` field because another test covers it + action.annotations ++ systemAnnotations(JAVA_DEFAULT))) } stream.toString should include(s"serving from cache: ${CacheKey(action)}") @@ -1065,7 +1063,8 @@ class ActionsApiTests extends ControllerTestCommon with WhiskActionsApi { Delete(s"$collectionPath/$name") ~> Route.seal(routes(creds)(transid())) ~> check { status should be(OK) val response = responseAs[WhiskAction] - response should be( + checkWhiskActionResponse( + response, WhiskAction( action.namespace, action.name, @@ -1074,8 +1073,7 @@ class ActionsApiTests extends ControllerTestCommon with WhiskActionsApi { action.limits, action.version, action.publish, - action.annotations ++ systemAnnotations(JAVA_DEFAULT), - updated = response.updated)) // ignored `updated` field because another test covers it + action.annotations ++ systemAnnotations(JAVA_DEFAULT))) } stream.toString should include(s"invalidating ${CacheKey(action)}") stream.reset() @@ -1115,7 +1113,8 @@ class ActionsApiTests extends ControllerTestCommon with WhiskActionsApi { Get(s"$collectionPath/$name") ~> Route.seal(routes(creds)(transid())) ~> check { status should be(OK) val response = responseAs[WhiskAction] - response should be( + checkWhiskActionResponse( + response, WhiskAction( action.namespace, action.name, @@ -1124,8 +1123,7 @@ class ActionsApiTests extends ControllerTestCommon with WhiskActionsApi { action.limits, action.version, action.publish, - action.annotations ++ systemAnnotations(kind), - updated = response.updated)) // ignored `updated` field because another test covers it + action.annotations ++ systemAnnotations(kind))) } stream.toString should include regex (expectedGetLog) @@ -1175,7 +1173,7 @@ class ActionsApiTests extends ControllerTestCommon with WhiskActionsApi { Get(s"$collectionPath/$name") ~> Route.seal(routes(creds)(transid())) ~> check { status should be(OK) val response = responseAs[WhiskAction] - response should be(expectedAction copy (updated = response.updated)) + checkWhiskActionResponse(response, expectedAction) } } @@ -1223,7 +1221,8 @@ class ActionsApiTests extends ControllerTestCommon with WhiskActionsApi { Put(s"$collectionPath/$name?overwrite=true", content) ~> Route.seal(routes(creds)(transid())) ~> check { status should be(OK) val response = responseAs[WhiskAction] - response should be( + checkWhiskActionResponse( + response, WhiskAction( action.namespace, action.name, @@ -1232,8 +1231,7 @@ class ActionsApiTests extends ControllerTestCommon with WhiskActionsApi { action.limits, action.version.upPatch, action.publish, - action.annotations ++ systemAnnotations(kind), - updated = response.updated)) // ignored `updated` field because another test covers it + action.annotations ++ systemAnnotations(kind))) } stream.toString should include regex (expectedPutLog) stream.reset() @@ -1242,7 +1240,8 @@ class ActionsApiTests extends ControllerTestCommon with WhiskActionsApi { Delete(s"$collectionPath/$name") ~> Route.seal(routes(creds)(transid())) ~> check { status should be(OK) val response = responseAs[WhiskAction] - response should be( + checkWhiskActionResponse( + response, WhiskAction( action.namespace, action.name, @@ -1251,8 +1250,7 @@ class ActionsApiTests extends ControllerTestCommon with WhiskActionsApi { action.limits, action.version.upPatch, action.publish, - action.annotations ++ systemAnnotations(kind), - updated = response.updated)) // ignored `updated` field because another test covers it + action.annotations ++ systemAnnotations(kind))) } stream.toString should include(s"invalidating ${CacheKey(action)}") stream.reset() @@ -1290,7 +1288,8 @@ class ActionsApiTests extends ControllerTestCommon with WhiskActionsApi { Put(s"$collectionPath/${actionOldSchema.name}?overwrite=true", content) ~> Route.seal(routes(creds)) ~> check { val response = responseAs[WhiskAction] - response should be( + checkWhiskActionResponse( + response, WhiskAction( actionOldSchema.namespace, actionOldSchema.name, @@ -1299,8 +1298,7 @@ class ActionsApiTests extends ControllerTestCommon with WhiskActionsApi { actionOldSchema.limits, actionOldSchema.version.upPatch, actionOldSchema.publish, - actionOldSchema.annotations ++ systemAnnotations(NODEJS10, create = false), - updated = response.updated)) // ignored `updated` field because another test covers it + actionOldSchema.annotations ++ systemAnnotations(NODEJS10, create = false))) } stream.toString should include regex (expectedPutLog) @@ -1315,7 +1313,8 @@ class ActionsApiTests extends ControllerTestCommon with WhiskActionsApi { Delete(s"$collectionPath/${actionOldSchema.name}") ~> Route.seal(routes(creds)) ~> check { status should be(OK) val response = responseAs[WhiskAction] - response should be( + checkWhiskActionResponse( + response, WhiskAction( actionOldSchema.namespace, actionOldSchema.name, @@ -1324,8 +1323,7 @@ class ActionsApiTests extends ControllerTestCommon with WhiskActionsApi { actionOldSchema.limits, actionOldSchema.version.upPatch, actionOldSchema.publish, - actionOldSchema.annotations ++ systemAnnotations(NODEJS10, create = false), - updated = response.updated)) // ignored `updated` field because another test covers it + actionOldSchema.annotations ++ systemAnnotations(NODEJS10, create = false))) } } @@ -1358,7 +1356,8 @@ class ActionsApiTests extends ControllerTestCommon with WhiskActionsApi { val response = responseAs[WhiskAction] response.updated should not be action.updated - response should be { + checkWhiskActionResponse( + response, WhiskAction( action.namespace, action.name, @@ -1370,9 +1369,7 @@ class ActionsApiTests extends ControllerTestCommon with WhiskActionsApi { content.limits.get.logs.get, content.limits.get.concurrency.get), version = action.version.upPatch, - annotations = action.annotations ++ systemAnnotations(NODEJS10, create = false), - updated = response.updated) // ignored `updated` field because another test covers it - } + annotations = action.annotations ++ systemAnnotations(NODEJS10, create = false))) } } @@ -1385,16 +1382,15 @@ class ActionsApiTests extends ControllerTestCommon with WhiskActionsApi { deleteAction(action.docid) status should be(OK) val response = responseAs[WhiskAction] - response should be { + checkWhiskActionResponse( + response, WhiskAction( action.namespace, action.name, action.exec, content.parameters.get, version = action.version.upPatch, - annotations = action.annotations ++ systemAnnotations(NODEJS10, false), - updated = response.updated) // ignored `updated` field because another test covers it - } + annotations = action.annotations ++ systemAnnotations(NODEJS10, false))) } } diff --git a/tests/src/test/scala/org/apache/openwhisk/core/controller/test/PackagesApiTests.scala b/tests/src/test/scala/org/apache/openwhisk/core/controller/test/PackagesApiTests.scala index 2c86f92fb78..9d7537c232a 100644 --- a/tests/src/test/scala/org/apache/openwhisk/core/controller/test/PackagesApiTests.scala +++ b/tests/src/test/scala/org/apache/openwhisk/core/controller/test/PackagesApiTests.scala @@ -54,6 +54,10 @@ class PackagesApiTests extends ControllerTestCommon with WhiskPackagesApi { def aname() = MakeName.next("packages_tests") val parametersLimit = Parameters.sizeLimit + def checkResponse(response: WhiskPackage, expected: WhiskPackage) = + // ignore `updated` field because another test covers it + response should be(expected copy (updated = response.updated)) + private def bindingAnnotation(binding: Binding) = { Parameters(WhiskPackage.bindingFieldName, Binding.serdes.write(binding)) } @@ -437,7 +441,7 @@ class PackagesApiTests extends ControllerTestCommon with WhiskPackagesApi { deletePackage(provider.docid) status should be(OK) val response = responseAs[WhiskPackage] - response should be(provider copy (updated = response.updated)) // ignored `updated` field because another test covers it + checkResponse(response, provider) } } @@ -507,7 +511,7 @@ class PackagesApiTests extends ControllerTestCommon with WhiskPackagesApi { deletePackage(reference.docid) status should be(OK) val response = responseAs[WhiskPackage] - response should be(reference copy (updated = response.updated)) // ignored `updated` field because another test covers it + checkResponse(response, reference) } } @@ -537,14 +541,13 @@ class PackagesApiTests extends ControllerTestCommon with WhiskPackagesApi { deletePackage(reference.docid) status should be(OK) val response = responseAs[WhiskPackage] - response should be { + checkResponse( + response, WhiskPackage( reference.namespace, reference.name, provider.bind, - annotations = bindingAnnotation(provider.bind.get), - updated = response.updated) // ignored `updated` field because another test covers it - } + annotations = bindingAnnotation(provider.bind.get))) } } @@ -648,14 +651,9 @@ class PackagesApiTests extends ControllerTestCommon with WhiskPackagesApi { Put(s"$collectionPath/${provider.name}?overwrite=true", content) ~> Route.seal(routes(creds)) ~> check { deletePackage(provider.docid) val response = responseAs[WhiskPackage] - response should be( - WhiskPackage( - namespace, - provider.name, - None, - version = provider.version.upPatch, - publish = true, - updated = response.updated)) // ignored `updated` field because another test covers it + checkResponse( + response, + WhiskPackage(namespace, provider.name, None, version = provider.version.upPatch, publish = true)) } } @@ -679,16 +677,15 @@ class PackagesApiTests extends ControllerTestCommon with WhiskPackagesApi { deletePackage(reference.docid) status should be(OK) val response = responseAs[WhiskPackage] - response should be { + checkResponse( + response, WhiskPackage( reference.namespace, reference.name, reference.binding, version = reference.version.upPatch, publish = true, - annotations = reference.annotations ++ Parameters("a", "b"), - updated = response.updated) // ignored `updated` field because another test covers it - } + annotations = reference.annotations ++ Parameters("a", "b"))) } } diff --git a/tests/src/test/scala/org/apache/openwhisk/core/controller/test/RulesApiTests.scala b/tests/src/test/scala/org/apache/openwhisk/core/controller/test/RulesApiTests.scala index f144de589a0..9aee5dab835 100644 --- a/tests/src/test/scala/org/apache/openwhisk/core/controller/test/RulesApiTests.scala +++ b/tests/src/test/scala/org/apache/openwhisk/core/controller/test/RulesApiTests.scala @@ -17,6 +17,8 @@ package org.apache.openwhisk.core.controller.test +import java.time.Instant + import scala.language.postfixOps import org.junit.runner.RunWith import org.scalatest.junit.JUnitRunner @@ -27,7 +29,7 @@ import spray.json.DefaultJsonProtocol._ import spray.json._ import org.apache.openwhisk.core.controller.WhiskRulesApi import org.apache.openwhisk.core.entitlement.Collection -import org.apache.openwhisk.core.entity._ +import org.apache.openwhisk.core.entity.{WhiskRuleResponse, _} import org.apache.openwhisk.core.entity.test.OldWhiskTrigger import org.apache.openwhisk.http.ErrorResponse @@ -61,6 +63,11 @@ class RulesApiTests extends ControllerTestCommon with WhiskRulesApi { val activeStatus = s"""{"status":"${Status.ACTIVE}"}""".parseJson.asJsObject val inactiveStatus = s"""{"status":"${Status.INACTIVE}"}""".parseJson.asJsObject val parametersLimit = Parameters.sizeLimit + val dummyInstant = Instant.now() + + def checkResponse(response: WhiskRuleResponse, expected: WhiskRuleResponse) = + // ignore `updated` field because another test covers it + response should be(expected copy (updated = response.updated)) //// GET /rules it should "list rules by default/explicit namespace" in { @@ -164,14 +171,14 @@ class RulesApiTests extends ControllerTestCommon with WhiskRulesApi { Get(s"$collectionPath/${rule.name}") ~> Route.seal(routes(creds)) ~> check { status should be(OK) val response = responseAs[WhiskRuleResponse] - response should be(rule.withStatus(Status.INACTIVE) copy (updated = response.updated)) + checkResponse(response, rule.withStatus(Status.INACTIVE)) } // it should "get trigger by name in explicit namespace owned by subject" in Get(s"/$namespace/${collection.path}/${rule.name}") ~> Route.seal(routes(creds)) ~> check { status should be(OK) val response = responseAs[WhiskRuleResponse] - response should be(rule.withStatus(Status.INACTIVE) copy (updated = response.updated)) + checkResponse(response, rule.withStatus(Status.INACTIVE)) } // it should "reject get trigger by name in explicit namespace not owned by subject" in @@ -207,8 +214,7 @@ class RulesApiTests extends ControllerTestCommon with WhiskRulesApi { Get(s"$collectionPath/${rule.name}") ~> Route.seal(routes(creds)) ~> check { status should be(OK) val response = responseAs[WhiskRuleResponse] - // ignored `updated` field because another test covers it - response should be(rule.withStatus(Status.ACTIVE) copy (updated = response.updated)) + checkResponse(response, rule.withStatus(Status.ACTIVE)) } } @@ -253,8 +259,7 @@ class RulesApiTests extends ControllerTestCommon with WhiskRulesApi { Get(s"$collectionPath/${rule.name}") ~> Route.seal(routes(creds)) ~> check { status should be(OK) val response = responseAs[WhiskRuleResponse] - // ignored `updated` field because another test covers it - response should be(rule.withStatus(Status.INACTIVE) copy (updated = response.updated)) + checkResponse(response, rule.withStatus(Status.INACTIVE)) } } @@ -291,8 +296,7 @@ class RulesApiTests extends ControllerTestCommon with WhiskRulesApi { status should be(OK) val response = responseAs[WhiskRuleResponse] - // ignored `updated` field because another test covers it - response should be(rule.withStatus(Status.INACTIVE) copy (updated = response.updated)) + checkResponse(response, rule.withStatus(Status.INACTIVE)) } } @@ -320,8 +324,7 @@ class RulesApiTests extends ControllerTestCommon with WhiskRulesApi { status should be(OK) t.rules.get.get(rule.fullyQualifiedName(false)) shouldBe None val response = responseAs[WhiskRuleResponse] - // ignored `updated` field because another test covers it - response should be(rule.withStatus(Status.INACTIVE) copy (updated = response.updated)) + checkResponse(response, rule.withStatus(Status.INACTIVE)) } } @@ -339,8 +342,7 @@ class RulesApiTests extends ControllerTestCommon with WhiskRulesApi { Delete(s"$collectionPath/${rule.name}") ~> Route.seal(routes(creds)) ~> check { status should be(OK) val response = responseAs[WhiskRuleResponse] - // ignored `updated` field because another test covers it - response should be(rule.withStatus(Status.INACTIVE) copy (updated = response.updated)) + checkResponse(response, rule.withStatus(Status.INACTIVE)) } } @@ -359,8 +361,7 @@ class RulesApiTests extends ControllerTestCommon with WhiskRulesApi { status should be(OK) val response = responseAs[WhiskRuleResponse] - // ignored `updated` field because another test covers it - response should be(rule.withStatus(Status.INACTIVE) copy (updated = response.updated)) + checkResponse(response, rule.withStatus(Status.INACTIVE)) } } @@ -387,8 +388,7 @@ class RulesApiTests extends ControllerTestCommon with WhiskRulesApi { status should be(OK) val response = responseAs[WhiskRuleResponse] - // ignored `updated` field because another test covers it - response should be(rule.withStatus(Status.ACTIVE) copy (updated = response.updated)) + checkResponse(response, rule.withStatus(Status.ACTIVE)) t.rules.get(rule.fullyQualifiedName(false)) shouldBe ReducedRule(action.fullyQualifiedName(false), Status.ACTIVE) } } @@ -417,8 +417,7 @@ class RulesApiTests extends ControllerTestCommon with WhiskRulesApi { status should be(OK) val response = responseAs[WhiskRuleResponse] - // ignored `updated` field because another test covers it - response should be(rule.withStatus(Status.ACTIVE) copy (updated = response.updated)) + checkResponse(response, rule.withStatus(Status.ACTIVE)) t.rules.get(rule.fullyQualifiedName(false)) shouldBe ReducedRule(action.fullyQualifiedName(false), Status.ACTIVE) } } @@ -469,8 +468,7 @@ class RulesApiTests extends ControllerTestCommon with WhiskRulesApi { status should be(OK) val response = responseAs[WhiskRuleResponse] - // ignored `updated` field because another test covers it - response should be(rule.withStatus(Status.ACTIVE) copy (updated = response.updated)) + checkResponse(response, rule.withStatus(Status.ACTIVE)) t.rules.get(rule.fullyQualifiedName(false)) shouldBe ReducedRule(action.fullyQualifiedName(false), Status.ACTIVE) } } @@ -502,7 +500,7 @@ class RulesApiTests extends ControllerTestCommon with WhiskRulesApi { status should be(OK) val response = responseAs[WhiskRuleResponse] - response should be(rule.withStatus(Status.ACTIVE) copy (updated = response.updated)) + checkResponse(response, rule.withStatus(Status.ACTIVE)) t.rules.get(rule.fullyQualifiedName(false)) shouldBe ReducedRule(action.fullyQualifiedName(false), Status.ACTIVE) } } @@ -626,7 +624,8 @@ class RulesApiTests extends ControllerTestCommon with WhiskRulesApi { t.rules.get(rule.fullyQualifiedName(false)).action should be(action.fullyQualifiedName(false)) val response = responseAs[WhiskRuleResponse] - response should be( + checkResponse( + response, WhiskRuleResponse( namespace, rule.name, @@ -634,7 +633,7 @@ class RulesApiTests extends ControllerTestCommon with WhiskRulesApi { trigger.fullyQualifiedName(false), action.fullyQualifiedName(false), version = SemVer().upPatch, - updated = response.updated)) // ignored `updated` field because another test covers it + updated = dummyInstant)) } } @@ -658,7 +657,8 @@ class RulesApiTests extends ControllerTestCommon with WhiskRulesApi { status should be(OK) t.rules.get(rule.fullyQualifiedName(false)).action should be(action.fullyQualifiedName(false)) val response = responseAs[WhiskRuleResponse] - response should be( + checkResponse( + response, WhiskRuleResponse( namespace, rule.name, @@ -666,7 +666,7 @@ class RulesApiTests extends ControllerTestCommon with WhiskRulesApi { trigger.fullyQualifiedName(false), action.fullyQualifiedName(false), version = SemVer().upPatch, - updated = response.updated)) // ignored `updated` field because another test covers it + updated = dummyInstant)) } } @@ -690,7 +690,8 @@ class RulesApiTests extends ControllerTestCommon with WhiskRulesApi { status should be(OK) t.rules.get(rule.fullyQualifiedName(false)).action should be(action.fullyQualifiedName(false)) val response = responseAs[WhiskRuleResponse] - response should be( + checkResponse( + response, WhiskRuleResponse( namespace, rule.name, @@ -698,7 +699,7 @@ class RulesApiTests extends ControllerTestCommon with WhiskRulesApi { trigger.fullyQualifiedName(false), action.fullyQualifiedName(false), version = SemVer().upPatch, - updated = response.updated)) // ignored `updated` field because another test covers it + updated = dummyInstant)) } } @@ -722,7 +723,8 @@ class RulesApiTests extends ControllerTestCommon with WhiskRulesApi { status should be(OK) t.rules.get.get(rule.fullyQualifiedName(false)) shouldBe a[Some[_]] val response = responseAs[WhiskRuleResponse] - response should be( + checkResponse( + response, WhiskRuleResponse( namespace, rule.name, @@ -730,7 +732,7 @@ class RulesApiTests extends ControllerTestCommon with WhiskRulesApi { trigger.fullyQualifiedName(false), action.fullyQualifiedName(false), version = SemVer().upPatch, - updated = response.updated)) // ignored `updated` field because another test covers it + updated = dummyInstant)) } } @@ -751,7 +753,8 @@ class RulesApiTests extends ControllerTestCommon with WhiskRulesApi { status should be(OK) val response = responseAs[WhiskRuleResponse] - response should be( + checkResponse( + response, WhiskRuleResponse( namespace, rule.name, @@ -759,7 +762,7 @@ class RulesApiTests extends ControllerTestCommon with WhiskRulesApi { trigger.fullyQualifiedName(false), action.fullyQualifiedName(false), version = SemVer().upPatch, - updated = response.updated)) // ignored `updated` field because another test covers it + updated = dummyInstant)) } } @@ -834,7 +837,8 @@ class RulesApiTests extends ControllerTestCommon with WhiskRulesApi { status should be(OK) t.rules.get(rule.fullyQualifiedName(false)).action should be(action.fullyQualifiedName(false)) val response = responseAs[WhiskRuleResponse] - response should be( + checkResponse( + response, WhiskRuleResponse( namespace, rule.name, @@ -842,7 +846,7 @@ class RulesApiTests extends ControllerTestCommon with WhiskRulesApi { trigger.fullyQualifiedName(false), action.fullyQualifiedName(false), version = SemVer().upPatch, - updated = response.updated)) // ignored `updated` field because another test covers it + updated = dummyInstant)) } } @@ -988,8 +992,7 @@ class RulesApiTests extends ControllerTestCommon with WhiskRulesApi { Get(s"$collectionPath/${rule.name}") ~> Route.seal(routes(creds)) ~> check { status should be(OK) val response = responseAs[WhiskRuleResponse] - // ignored `updated` field because another test covers it - response should be(rule.toWhiskRule.withStatus(Status.INACTIVE) copy (updated = response.updated)) + checkResponse(response, rule.toWhiskRule.withStatus(Status.INACTIVE)) } } @@ -1013,9 +1016,7 @@ class RulesApiTests extends ControllerTestCommon with WhiskRulesApi { status should be(OK) t.rules.get(rule.fullyQualifiedName(false)) shouldBe ReducedRule(action.fullyQualifiedName(false), Status.ACTIVE) val response = responseAs[WhiskRuleResponse] - - // ignored `updated` field because another test covers it - response should be(rule.withStatus(Status.ACTIVE) copy (updated = response.updated)) + checkResponse(response, rule.withStatus(Status.ACTIVE)) } } diff --git a/tests/src/test/scala/org/apache/openwhisk/core/controller/test/TriggersApiTests.scala b/tests/src/test/scala/org/apache/openwhisk/core/controller/test/TriggersApiTests.scala index d44de42c9ec..f3f91c39095 100644 --- a/tests/src/test/scala/org/apache/openwhisk/core/controller/test/TriggersApiTests.scala +++ b/tests/src/test/scala/org/apache/openwhisk/core/controller/test/TriggersApiTests.scala @@ -67,6 +67,11 @@ class TriggersApiTests extends ControllerTestCommon with WhiskTriggersApi { def aname() = MakeName.next("triggers_tests") def afullname(namespace: EntityPath, name: String) = FullyQualifiedEntityName(namespace, EntityName(name)) val parametersLimit = Parameters.sizeLimit + val dummyInstant = Instant.now() + + def checkResponse(response: WhiskTrigger, expected: WhiskTrigger) = + // ignore `updated` field because another test covers it + response should be(expected copy (updated = response.updated)) //// GET /triggers it should "list triggers by default/explicit namespace" in { @@ -232,7 +237,7 @@ class TriggersApiTests extends ControllerTestCommon with WhiskTriggersApi { deleteTrigger(trigger.docid) status should be(OK) val response = responseAs[WhiskTrigger] - response should be(trigger.withoutRules copy (updated = response.updated)) // ignored `updated` field because another test covers it + checkResponse(response, trigger.withoutRules) } } @@ -244,7 +249,7 @@ class TriggersApiTests extends ControllerTestCommon with WhiskTriggersApi { deleteTrigger(trigger.docid) status should be(OK) val response = responseAs[WhiskTrigger] - response should be(trigger.withoutRules copy (updated = response.updated)) + checkResponse(response, trigger.withoutRules) } } @@ -338,14 +343,14 @@ class TriggersApiTests extends ControllerTestCommon with WhiskTriggersApi { deleteTrigger(trigger.docid) status should be(OK) val response = responseAs[WhiskTrigger] - response should be( + checkResponse( + response, WhiskTrigger( trigger.namespace, trigger.name, trigger.parameters, version = trigger.version.upPatch, - // ignored `updated` field because another test covers it - updated = response.updated).withoutRules) + updated = dummyInstant).withoutRules) } } @@ -450,9 +455,7 @@ class TriggersApiTests extends ControllerTestCommon with WhiskTriggersApi { Get(s"$collectionPath/${trigger.name}") ~> Route.seal(routes(creds)) ~> check { val response = responseAs[WhiskTrigger] status should be(OK) - - // ignored `updated` field because another test covers it - response should be(trigger.toWhiskTrigger copy (updated = response.updated)) + checkResponse(response, trigger.toWhiskTrigger) } } From 2f8571b2a42dce2faa914eecddee4dcd04f1b3bd Mon Sep 17 00:00:00 2001 From: seonghyun Date: Fri, 15 Nov 2019 11:05:49 +0900 Subject: [PATCH 16/18] Fix test case --- .../openwhisk/core/entity/test/WhiskEntityTests.scala | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/tests/src/test/scala/org/apache/openwhisk/core/entity/test/WhiskEntityTests.scala b/tests/src/test/scala/org/apache/openwhisk/core/entity/test/WhiskEntityTests.scala index e473070b97d..26f61a03d17 100644 --- a/tests/src/test/scala/org/apache/openwhisk/core/entity/test/WhiskEntityTests.scala +++ b/tests/src/test/scala/org/apache/openwhisk/core/entity/test/WhiskEntityTests.scala @@ -186,7 +186,8 @@ class WhiskEntityTests extends FlatSpec with ExecHelpers with Matchers { | "timeout": 60000, | "memory": 256 | }, - | "namespace": "namespace" + | "namespace": "namespace", + | "updated": 1546268400000 |}""".stripMargin.parseJson val action = WhiskDocumentReader.read(manifest[WhiskAction], json) @@ -213,7 +214,8 @@ class WhiskEntityTests extends FlatSpec with ExecHelpers with Matchers { | "timeout": 60000, | "memory": 256 | }, - | "namespace": "namespace" + | "namespace": "namespace", + | "updated": 1546268400000 |}""".stripMargin.parseJson val action = WhiskDocumentReader.read(manifest[WhiskAction], json) assertType(action.asInstanceOf[WhiskEntity], "action") From 0fa89f802e6c801338e12a2b765919b411271f43 Mon Sep 17 00:00:00 2001 From: seonghyun Date: Fri, 15 Nov 2019 11:07:43 +0900 Subject: [PATCH 17/18] Fix typo --- .../apache/openwhisk/core/entity/test/WhiskEntityTests.scala | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/src/test/scala/org/apache/openwhisk/core/entity/test/WhiskEntityTests.scala b/tests/src/test/scala/org/apache/openwhisk/core/entity/test/WhiskEntityTests.scala index 26f61a03d17..3b10d766333 100644 --- a/tests/src/test/scala/org/apache/openwhisk/core/entity/test/WhiskEntityTests.scala +++ b/tests/src/test/scala/org/apache/openwhisk/core/entity/test/WhiskEntityTests.scala @@ -187,7 +187,7 @@ class WhiskEntityTests extends FlatSpec with ExecHelpers with Matchers { | "memory": 256 | }, | "namespace": "namespace", - | "updated": 1546268400000 + | "updated": 1546268400000 |}""".stripMargin.parseJson val action = WhiskDocumentReader.read(manifest[WhiskAction], json) From 26a446fbe9bdc97ea6cb8f3fc9e2be814c82e182 Mon Sep 17 00:00:00 2001 From: seonghyun Date: Fri, 29 Nov 2019 11:25:23 +0900 Subject: [PATCH 18/18] Refactor test code --- .../controller/test/ActionsApiTests.scala | 66 ++++++++----------- .../test/ControllerTestCommon.scala | 12 ++++ .../controller/test/PackagesApiTests.scala | 14 ++-- .../controller/test/TriggersApiTests.scala | 12 ++-- 4 files changed, 50 insertions(+), 54 deletions(-) diff --git a/tests/src/test/scala/org/apache/openwhisk/core/controller/test/ActionsApiTests.scala b/tests/src/test/scala/org/apache/openwhisk/core/controller/test/ActionsApiTests.scala index 1b957bb0ad8..8758c0d9837 100644 --- a/tests/src/test/scala/org/apache/openwhisk/core/controller/test/ActionsApiTests.scala +++ b/tests/src/test/scala/org/apache/openwhisk/core/controller/test/ActionsApiTests.scala @@ -71,14 +71,6 @@ class ActionsApiTests extends ControllerTestCommon with WhiskActionsApi { val actionLimit = Exec.sizeLimit val parametersLimit = Parameters.sizeLimit - def checkWhiskActionResponse(response: WhiskAction, expected: WhiskAction) = - // ignore `updated` field because another test covers it - response should be(expected copy (updated = response.updated)) - - def checkWhiskActionMetadataResponse(response: WhiskActionMetaData, expected: WhiskActionMetaData) = - // ignore `updated` field because another test covers it - response should be(expected copy (updated = response.updated)) - //// GET /actions it should "return empty list when no actions exist" in { implicit val tid = transid() @@ -355,7 +347,7 @@ class ActionsApiTests extends ControllerTestCommon with WhiskActionsApi { Put(s"$collectionPath/${action.name}", content) ~> Route.seal(routes(creds)) ~> check { status should be(OK) val response = responseAs[WhiskAction] - checkWhiskActionResponse(response, expectedWhiskAction) + checkWhiskEntityResponse(response, expectedWhiskAction) } Get(s"$collectionPath/${action.name}?code=false") ~> Route.seal(routes(creds)) ~> check { @@ -363,21 +355,21 @@ class ActionsApiTests extends ControllerTestCommon with WhiskActionsApi { val responseJson = responseAs[JsObject] responseJson.fields("exec").asJsObject.fields should not(contain key "code") val response = responseAs[WhiskActionMetaData] - checkWhiskActionMetadataResponse(response, expectedWhiskActionMetaData) + checkWhiskEntityResponse(response, expectedWhiskActionMetaData) } Seq(s"$collectionPath/${action.name}", s"$collectionPath/${action.name}?code=true").foreach { path => Get(path) ~> Route.seal(routes(creds)) ~> check { status should be(OK) val response = responseAs[WhiskAction] - checkWhiskActionResponse(response, expectedWhiskAction) + checkWhiskEntityResponse(response, expectedWhiskAction) } } Delete(s"$collectionPath/${action.name}") ~> Route.seal(routes(creds)) ~> check { status should be(OK) val response = responseAs[WhiskAction] - checkWhiskActionResponse(response, expectedWhiskAction) + checkWhiskEntityResponse(response, expectedWhiskAction) } } } @@ -576,7 +568,7 @@ class ActionsApiTests extends ControllerTestCommon with WhiskActionsApi { deleteAction(action.docid) status should be(OK) val response = responseAs[WhiskAction] - checkWhiskActionResponse( + checkWhiskEntityResponse( response, WhiskAction( action.namespace, @@ -598,7 +590,7 @@ class ActionsApiTests extends ControllerTestCommon with WhiskActionsApi { deleteAction(action.docid) status should be(OK) val response = responseAs[WhiskAction] - checkWhiskActionResponse( + checkWhiskEntityResponse( response, WhiskAction( action.namespace, @@ -622,7 +614,7 @@ class ActionsApiTests extends ControllerTestCommon with WhiskActionsApi { deleteAction(action.docid) status should be(OK) val response = responseAs[WhiskAction] - checkWhiskActionResponse( + checkWhiskEntityResponse( response, WhiskAction( action.namespace, @@ -651,7 +643,7 @@ class ActionsApiTests extends ControllerTestCommon with WhiskActionsApi { Put(s"$collectionPath/${action.name}?overwrite=true", content) ~> Route.seal(routes(creds)) ~> check { status should be(OK) val response = responseAs[WhiskAction] - checkWhiskActionResponse( + checkWhiskEntityResponse( response, WhiskAction( action.namespace, @@ -670,7 +662,7 @@ class ActionsApiTests extends ControllerTestCommon with WhiskActionsApi { deleteAction(action.docid) status should be(OK) val response = responseAs[WhiskAction] - checkWhiskActionResponse( + checkWhiskEntityResponse( response, WhiskAction( action.namespace, @@ -742,7 +734,7 @@ class ActionsApiTests extends ControllerTestCommon with WhiskActionsApi { deleteAction(action.docid) status should be(OK) val response = responseAs[WhiskAction] - checkWhiskActionResponse( + checkWhiskEntityResponse( response, WhiskAction( action.namespace, @@ -783,7 +775,7 @@ class ActionsApiTests extends ControllerTestCommon with WhiskActionsApi { deleteAction(action.docid) status should be(OK) val response = responseAs[WhiskAction] - checkWhiskActionResponse( + checkWhiskEntityResponse( response, WhiskAction( action.namespace, @@ -820,7 +812,7 @@ class ActionsApiTests extends ControllerTestCommon with WhiskActionsApi { Put(s"$collectionPath/${action.name}", content) ~> Route.seal(routes(creds)(transid())) ~> check { status should be(OK) val response = responseAs[WhiskAction] - checkWhiskActionResponse( + checkWhiskEntityResponse( response, WhiskAction( action.namespace, @@ -840,7 +832,7 @@ class ActionsApiTests extends ControllerTestCommon with WhiskActionsApi { Get(s"$collectionPath/${action.name}") ~> Route.seal(routes(creds)(transid())) ~> check { status should be(OK) val response = responseAs[WhiskAction] - checkWhiskActionResponse( + checkWhiskEntityResponse( response, WhiskAction( action.namespace, @@ -859,7 +851,7 @@ class ActionsApiTests extends ControllerTestCommon with WhiskActionsApi { Put(s"$collectionPath/${action.name}?overwrite=true", content) ~> Route.seal(routes(creds)(transid())) ~> check { status should be(OK) val response = responseAs[WhiskAction] - checkWhiskActionResponse( + checkWhiskEntityResponse( response, WhiskAction( action.namespace, @@ -880,7 +872,7 @@ class ActionsApiTests extends ControllerTestCommon with WhiskActionsApi { Delete(s"$collectionPath/${action.name}") ~> Route.seal(routes(creds)(transid())) ~> check { status should be(OK) val response = responseAs[WhiskAction] - checkWhiskActionResponse( + checkWhiskEntityResponse( response, WhiskAction( action.namespace, @@ -935,7 +927,7 @@ class ActionsApiTests extends ControllerTestCommon with WhiskActionsApi { Put(s"$collectionPath/${action.name}", content) ~> Route.seal(routes(creds)(transid())) ~> check { status should be(OK) val response = responseAs[WhiskAction] - checkWhiskActionResponse( + checkWhiskEntityResponse( response, WhiskAction( action.namespace, @@ -956,7 +948,7 @@ class ActionsApiTests extends ControllerTestCommon with WhiskActionsApi { Get(s"$collectionPath/${action.name}") ~> Route.seal(routes(creds)(transid())) ~> check { status should be(OK) val response = responseAs[WhiskAction] - checkWhiskActionResponse( + checkWhiskEntityResponse( response, WhiskAction( action.namespace, @@ -976,7 +968,7 @@ class ActionsApiTests extends ControllerTestCommon with WhiskActionsApi { Delete(s"$collectionPath/${action.name}") ~> Route.seal(routes(creds)(transid())) ~> check { status should be(OK) val response = responseAs[WhiskAction] - checkWhiskActionResponse( + checkWhiskEntityResponse( response, WhiskAction( action.namespace, @@ -1021,7 +1013,7 @@ class ActionsApiTests extends ControllerTestCommon with WhiskActionsApi { Put(s"$collectionPath/$name", content) ~> Route.seal(routes(creds)(transid())) ~> check { status should be(OK) val response = responseAs[WhiskAction] - checkWhiskActionResponse( + checkWhiskEntityResponse( response, WhiskAction( action.namespace, @@ -1042,7 +1034,7 @@ class ActionsApiTests extends ControllerTestCommon with WhiskActionsApi { Get(s"$collectionPath/$name") ~> Route.seal(routes(creds)(transid())) ~> check { status should be(OK) val response = responseAs[WhiskAction] - checkWhiskActionResponse( + checkWhiskEntityResponse( response, WhiskAction( action.namespace, @@ -1063,7 +1055,7 @@ class ActionsApiTests extends ControllerTestCommon with WhiskActionsApi { Delete(s"$collectionPath/$name") ~> Route.seal(routes(creds)(transid())) ~> check { status should be(OK) val response = responseAs[WhiskAction] - checkWhiskActionResponse( + checkWhiskEntityResponse( response, WhiskAction( action.namespace, @@ -1113,7 +1105,7 @@ class ActionsApiTests extends ControllerTestCommon with WhiskActionsApi { Get(s"$collectionPath/$name") ~> Route.seal(routes(creds)(transid())) ~> check { status should be(OK) val response = responseAs[WhiskAction] - checkWhiskActionResponse( + checkWhiskEntityResponse( response, WhiskAction( action.namespace, @@ -1173,7 +1165,7 @@ class ActionsApiTests extends ControllerTestCommon with WhiskActionsApi { Get(s"$collectionPath/$name") ~> Route.seal(routes(creds)(transid())) ~> check { status should be(OK) val response = responseAs[WhiskAction] - checkWhiskActionResponse(response, expectedAction) + checkWhiskEntityResponse(response, expectedAction) } } @@ -1221,7 +1213,7 @@ class ActionsApiTests extends ControllerTestCommon with WhiskActionsApi { Put(s"$collectionPath/$name?overwrite=true", content) ~> Route.seal(routes(creds)(transid())) ~> check { status should be(OK) val response = responseAs[WhiskAction] - checkWhiskActionResponse( + checkWhiskEntityResponse( response, WhiskAction( action.namespace, @@ -1240,7 +1232,7 @@ class ActionsApiTests extends ControllerTestCommon with WhiskActionsApi { Delete(s"$collectionPath/$name") ~> Route.seal(routes(creds)(transid())) ~> check { status should be(OK) val response = responseAs[WhiskAction] - checkWhiskActionResponse( + checkWhiskEntityResponse( response, WhiskAction( action.namespace, @@ -1288,7 +1280,7 @@ class ActionsApiTests extends ControllerTestCommon with WhiskActionsApi { Put(s"$collectionPath/${actionOldSchema.name}?overwrite=true", content) ~> Route.seal(routes(creds)) ~> check { val response = responseAs[WhiskAction] - checkWhiskActionResponse( + checkWhiskEntityResponse( response, WhiskAction( actionOldSchema.namespace, @@ -1313,7 +1305,7 @@ class ActionsApiTests extends ControllerTestCommon with WhiskActionsApi { Delete(s"$collectionPath/${actionOldSchema.name}") ~> Route.seal(routes(creds)) ~> check { status should be(OK) val response = responseAs[WhiskAction] - checkWhiskActionResponse( + checkWhiskEntityResponse( response, WhiskAction( actionOldSchema.namespace, @@ -1356,7 +1348,7 @@ class ActionsApiTests extends ControllerTestCommon with WhiskActionsApi { val response = responseAs[WhiskAction] response.updated should not be action.updated - checkWhiskActionResponse( + checkWhiskEntityResponse( response, WhiskAction( action.namespace, @@ -1382,7 +1374,7 @@ class ActionsApiTests extends ControllerTestCommon with WhiskActionsApi { deleteAction(action.docid) status should be(OK) val response = responseAs[WhiskAction] - checkWhiskActionResponse( + checkWhiskEntityResponse( response, WhiskAction( action.namespace, diff --git a/tests/src/test/scala/org/apache/openwhisk/core/controller/test/ControllerTestCommon.scala b/tests/src/test/scala/org/apache/openwhisk/core/controller/test/ControllerTestCommon.scala index fca9fafd13c..9817bef6052 100644 --- a/tests/src/test/scala/org/apache/openwhisk/core/controller/test/ControllerTestCommon.scala +++ b/tests/src/test/scala/org/apache/openwhisk/core/controller/test/ControllerTestCommon.scala @@ -85,6 +85,18 @@ protected trait ControllerTestCommon } } + def checkWhiskEntityResponse(response: WhiskEntity, expected: WhiskEntity): Unit = { + // Used to ignore `updated` field because timestamp is not known before inserting into the DB + // If you use this method, test case that checks timestamp must be added + val r = response match { + case whiskAction: WhiskAction => whiskAction.copy(updated = expected.updated) + case whiskActionMetaData: WhiskActionMetaData => whiskActionMetaData.copy(updated = expected.updated) + case whiskTrigger: WhiskTrigger => whiskTrigger.copy(updated = expected.updated) + case whiskPackage: WhiskPackage => whiskPackage.copy(updated = expected.updated) + } + r should be(expected) + } + def systemAnnotations(kind: String, create: Boolean = true): Parameters = { val base = if (create && FeatureFlags.requireApiKeyAnnotation) { Parameters(Annotations.ProvideApiKeyAnnotationName, JsFalse) diff --git a/tests/src/test/scala/org/apache/openwhisk/core/controller/test/PackagesApiTests.scala b/tests/src/test/scala/org/apache/openwhisk/core/controller/test/PackagesApiTests.scala index 9d7537c232a..5ea915d8a41 100644 --- a/tests/src/test/scala/org/apache/openwhisk/core/controller/test/PackagesApiTests.scala +++ b/tests/src/test/scala/org/apache/openwhisk/core/controller/test/PackagesApiTests.scala @@ -54,10 +54,6 @@ class PackagesApiTests extends ControllerTestCommon with WhiskPackagesApi { def aname() = MakeName.next("packages_tests") val parametersLimit = Parameters.sizeLimit - def checkResponse(response: WhiskPackage, expected: WhiskPackage) = - // ignore `updated` field because another test covers it - response should be(expected copy (updated = response.updated)) - private def bindingAnnotation(binding: Binding) = { Parameters(WhiskPackage.bindingFieldName, Binding.serdes.write(binding)) } @@ -441,7 +437,7 @@ class PackagesApiTests extends ControllerTestCommon with WhiskPackagesApi { deletePackage(provider.docid) status should be(OK) val response = responseAs[WhiskPackage] - checkResponse(response, provider) + checkWhiskEntityResponse(response, provider) } } @@ -511,7 +507,7 @@ class PackagesApiTests extends ControllerTestCommon with WhiskPackagesApi { deletePackage(reference.docid) status should be(OK) val response = responseAs[WhiskPackage] - checkResponse(response, reference) + checkWhiskEntityResponse(response, reference) } } @@ -541,7 +537,7 @@ class PackagesApiTests extends ControllerTestCommon with WhiskPackagesApi { deletePackage(reference.docid) status should be(OK) val response = responseAs[WhiskPackage] - checkResponse( + checkWhiskEntityResponse( response, WhiskPackage( reference.namespace, @@ -651,7 +647,7 @@ class PackagesApiTests extends ControllerTestCommon with WhiskPackagesApi { Put(s"$collectionPath/${provider.name}?overwrite=true", content) ~> Route.seal(routes(creds)) ~> check { deletePackage(provider.docid) val response = responseAs[WhiskPackage] - checkResponse( + checkWhiskEntityResponse( response, WhiskPackage(namespace, provider.name, None, version = provider.version.upPatch, publish = true)) } @@ -677,7 +673,7 @@ class PackagesApiTests extends ControllerTestCommon with WhiskPackagesApi { deletePackage(reference.docid) status should be(OK) val response = responseAs[WhiskPackage] - checkResponse( + checkWhiskEntityResponse( response, WhiskPackage( reference.namespace, diff --git a/tests/src/test/scala/org/apache/openwhisk/core/controller/test/TriggersApiTests.scala b/tests/src/test/scala/org/apache/openwhisk/core/controller/test/TriggersApiTests.scala index f3f91c39095..d87751b4daa 100644 --- a/tests/src/test/scala/org/apache/openwhisk/core/controller/test/TriggersApiTests.scala +++ b/tests/src/test/scala/org/apache/openwhisk/core/controller/test/TriggersApiTests.scala @@ -69,10 +69,6 @@ class TriggersApiTests extends ControllerTestCommon with WhiskTriggersApi { val parametersLimit = Parameters.sizeLimit val dummyInstant = Instant.now() - def checkResponse(response: WhiskTrigger, expected: WhiskTrigger) = - // ignore `updated` field because another test covers it - response should be(expected copy (updated = response.updated)) - //// GET /triggers it should "list triggers by default/explicit namespace" in { implicit val tid = transid() @@ -237,7 +233,7 @@ class TriggersApiTests extends ControllerTestCommon with WhiskTriggersApi { deleteTrigger(trigger.docid) status should be(OK) val response = responseAs[WhiskTrigger] - checkResponse(response, trigger.withoutRules) + checkWhiskEntityResponse(response, trigger.withoutRules) } } @@ -249,7 +245,7 @@ class TriggersApiTests extends ControllerTestCommon with WhiskTriggersApi { deleteTrigger(trigger.docid) status should be(OK) val response = responseAs[WhiskTrigger] - checkResponse(response, trigger.withoutRules) + checkWhiskEntityResponse(response, trigger.withoutRules) } } @@ -343,7 +339,7 @@ class TriggersApiTests extends ControllerTestCommon with WhiskTriggersApi { deleteTrigger(trigger.docid) status should be(OK) val response = responseAs[WhiskTrigger] - checkResponse( + checkWhiskEntityResponse( response, WhiskTrigger( trigger.namespace, @@ -455,7 +451,7 @@ class TriggersApiTests extends ControllerTestCommon with WhiskTriggersApi { Get(s"$collectionPath/${trigger.name}") ~> Route.seal(routes(creds)) ~> check { val response = responseAs[WhiskTrigger] status should be(OK) - checkResponse(response, trigger.toWhiskTrigger) + checkWhiskEntityResponse(response, trigger.toWhiskTrigger) } }