You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@openwhisk.apache.org by cb...@apache.org on 2018/02/21 09:41:47 UTC
[incubator-openwhisk] branch master updated: Rework rule tests to
not rely on views anymore. (#3309)
This is an automated email from the ASF dual-hosted git repository.
cbickel pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/incubator-openwhisk.git
The following commit(s) were added to refs/heads/master by this push:
new a6fd056 Rework rule tests to not rely on views anymore. (#3309)
a6fd056 is described below
commit a6fd056c92683ce42b662c6cb24cd50d87f2cbc2
Author: Markus Thömmes <ma...@me.com>
AuthorDate: Wed Feb 21 10:41:43 2018 +0100
Rework rule tests to not rely on views anymore. (#3309)
Relying on views is brittle and will fail if the database is under high load. We don't need to rely on those anymore.
---
tests/src/test/scala/common/WskTestHelpers.scala | 40 +---
.../src/test/scala/system/basic/WskRuleTests.scala | 230 +++++++++------------
.../test/scala/system/basic/WskSequenceTests.scala | 8 +-
3 files changed, 117 insertions(+), 161 deletions(-)
diff --git a/tests/src/test/scala/common/WskTestHelpers.scala b/tests/src/test/scala/common/WskTestHelpers.scala
index eb4bad6..5be175c 100644
--- a/tests/src/test/scala/common/WskTestHelpers.scala
+++ b/tests/src/test/scala/common/WskTestHelpers.scala
@@ -119,6 +119,12 @@ object ActivationResult extends DefaultJsonProtocol {
}
}
+/** The result of a rule-activation written into the trigger activation */
+case class RuleActivationResult(statusCode: Int, success: Boolean, activationId: String, action: String)
+object RuleActivationResult extends DefaultJsonProtocol {
+ implicit val serdes = jsonFormat4(RuleActivationResult.apply)
+}
+
/**
* Test fixture to ease cleaning of whisk entities created during testing.
*
@@ -232,37 +238,9 @@ trait WskTestHelpers extends Matchers {
}
}
}
-
- /**
- * Polls until it finds {@code N} activationIds from an entity. Asserts the count
- * of the activationIds actually equal {@code N}. Takes a {@code since} parameter
- * defining the oldest activationId to consider valid.
- */
- def withActivationsFromEntity(
- wsk: BaseActivation,
- entity: String,
- N: Int = 1,
- since: Option[Instant] = None,
- pollPeriod: Duration = 1.second,
- totalWait: Duration = 60.seconds)(check: Seq[ActivationResult] => Unit)(implicit wskprops: WskProps): Unit = {
-
- val activationIds =
- wsk.pollFor(N, Some(entity), since = since, retries = (totalWait / pollPeriod).toInt, pollPeriod = pollPeriod)
- withClue(
- s"expecting $N activations matching '$entity' name since $since but found ${activationIds.mkString(",")} instead") {
- activationIds.length shouldBe N
- }
-
- val parsed = activationIds.map { id =>
- wsk.parseJsonString(wsk.get(Some(id)).stdout).convertTo[ActivationResult]
- }
- try {
- check(parsed)
- } catch {
- case error: Throwable =>
- println(s"check failed for activations $activationIds: $parsed")
- throw error
- }
+ def withActivation(wsk: BaseActivation, activationId: String)(check: ActivationResult => Unit)(
+ implicit wskprops: WskProps): Unit = {
+ withActivation(wsk, activationId, 1.second, 1.second, 60.seconds)(check)
}
/**
diff --git a/tests/src/test/scala/system/basic/WskRuleTests.scala b/tests/src/test/scala/system/basic/WskRuleTests.scala
index 62890b7..bd30bc7 100644
--- a/tests/src/test/scala/system/basic/WskRuleTests.scala
+++ b/tests/src/test/scala/system/basic/WskRuleTests.scala
@@ -25,6 +25,7 @@ import common.TestUtils.RunResult
import common.BaseWsk
import common.WskProps
import common.WskTestHelpers
+import common.RuleActivationResult
import spray.json._
import spray.json.DefaultJsonProtocol._
import java.time.Instant
@@ -40,14 +41,6 @@ abstract class WskRuleTests extends TestHelpers with WskTestHelpers {
val testResult = JsObject("count" -> testString.split(" ").length.toJson)
/**
- * Invoker clock skew can sometimes make it appear as if an action was invoked
- * _before_ the trigger was fired. The "fudge factor" below allows the test to look
- * for action activations that occur starting at most this amount of time before
- * the trigger was fired.
- */
- val activationTimeSkewFactorMs = 500
-
- /**
* Sets up trigger -> rule -> action triplets. Deduplicates triggers and rules
* and links it all up.
*
@@ -56,7 +49,7 @@ abstract class WskRuleTests extends TestHelpers with WskTestHelpers {
* where the action name for the created action is allowed to differ from that used by the rule binding
* for cases that reference actions in a package binding.
*/
- def ruleSetup(rules: Seq[(String, String, (String, String, String))], assetHelper: AssetCleaner) = {
+ def ruleSetup(rules: Seq[(String, String, (String, String, String))], assetHelper: AssetCleaner): Unit = {
val triggers = rules.map(_._2).distinct
val actions = rules.map(_._3).distinct
@@ -84,7 +77,7 @@ abstract class WskRuleTests extends TestHelpers with WskTestHelpers {
/**
* Append the current timestamp in ms
*/
- def withTimestamp(text: String) = s"${text}-${System.currentTimeMillis}"
+ def withTimestamp(text: String) = s"$text-${System.currentTimeMillis}"
behavior of "Whisk rules"
@@ -112,8 +105,8 @@ abstract class WskRuleTests extends TestHelpers with WskTestHelpers {
.parseJson
.asJsObject
.fields
- .get("status") shouldBe (status)
- wsk.rule.get(ruleName).stdout.parseJson.asJsObject.fields.get("status") shouldBe (status)
+ .get("status") shouldBe status
+ wsk.rule.get(ruleName).stdout.parseJson.asJsObject.fields.get("status") shouldBe status
}
}
@@ -129,18 +122,16 @@ abstract class WskRuleTests extends TestHelpers with WskTestHelpers {
withActivation(wsk.activation, run) { triggerActivation =>
triggerActivation.cause shouldBe None
- triggerActivation.logs.get.size shouldBe (1)
- val logs = triggerActivation.logs.get.mkString(" ")
- logs should include(""""statusCode":0""")
- logs should include(""""activationId":""")
- logs should include(""""success":true""")
-
- withActivationsFromEntity(
- wsk.activation,
- actionName,
- since = Some(triggerActivation.start.minusMillis(activationTimeSkewFactorMs))) { activationList =>
- activationList.head.response.result shouldBe Some(testResult)
- activationList.head.cause shouldBe None
+
+ val ruleActivations = triggerActivation.logs.get.map(_.parseJson.convertTo[RuleActivationResult])
+ ruleActivations should have size 1
+ val ruleActivation = ruleActivations.head
+ ruleActivation.success shouldBe true
+ ruleActivation.statusCode shouldBe 0
+
+ withActivation(wsk.activation, ruleActivation.activationId) { actionActivation =>
+ actionActivation.response.result shouldBe Some(testResult)
+ actionActivation.cause shouldBe None
}
}
}
@@ -164,17 +155,15 @@ abstract class WskRuleTests extends TestHelpers with WskTestHelpers {
withActivation(wsk.activation, run) { triggerActivation =>
triggerActivation.cause shouldBe None
- triggerActivation.logs.get.size shouldBe (1)
- val logs = triggerActivation.logs.get.mkString(" ")
- logs should include(""""statusCode":0""")
- logs should include(""""activationId":""")
- logs should include(""""success":true""")
-
- withActivationsFromEntity(
- wsk.activation,
- pkgActionName,
- since = Some(triggerActivation.start.minusMillis(activationTimeSkewFactorMs))) {
- _.head.response.result shouldBe Some(testResult)
+
+ val ruleActivations = triggerActivation.logs.get.map(_.parseJson.convertTo[RuleActivationResult])
+ ruleActivations should have size 1
+ val ruleActivation = ruleActivations.head
+ ruleActivation.success shouldBe true
+ ruleActivation.statusCode shouldBe 0
+
+ withActivation(wsk.activation, ruleActivation.activationId) { actionActivation =>
+ actionActivation.response.result shouldBe Some(testResult)
}
}
}
@@ -202,17 +191,16 @@ abstract class WskRuleTests extends TestHelpers with WskTestHelpers {
withActivation(wsk.activation, run) { triggerActivation =>
triggerActivation.cause shouldBe None
- triggerActivation.logs.get.size shouldBe (1)
- val logs = triggerActivation.logs.get.mkString(" ")
- logs should include(""""statusCode":0""")
- logs should include(""""activationId":""")
- logs should include(""""success":true""")
-
- withActivationsFromEntity(
- wsk.activation,
- pkgActionName,
- since = Some(triggerActivation.start.minusMillis(activationTimeSkewFactorMs))) {
- _.head.response.result shouldBe Some(testResult)
+
+ val ruleActivations = triggerActivation.logs.get.map(_.parseJson.convertTo[RuleActivationResult])
+ ruleActivations should have size 1
+ val ruleActivation = ruleActivations.head
+ ruleActivation.success shouldBe true
+ ruleActivation.statusCode shouldBe 0
+
+ withActivation(wsk.activation, ruleActivation.activationId) { actionActivation =>
+ actionActivation.response.result shouldBe Some(testResult)
+ actionActivation.cause shouldBe None
}
}
}
@@ -229,24 +217,16 @@ abstract class WskRuleTests extends TestHelpers with WskTestHelpers {
assetHelper.withCleaner(wsk.action, actionName) { (action, name) =>
action.create(name, Some(defaultAction))
}
- assetHelper.withCleaner(wsk.rule, ruleName, false) { (rule, name) =>
+ assetHelper.withCleaner(wsk.rule, ruleName, confirmDelete = false) { (rule, name) =>
rule.create(name, triggerName, actionName)
}
val first = wsk.trigger.fire(triggerName, Map("payload" -> "bogus".toJson))
wsk.rule.delete(ruleName)
- wsk.trigger.fire(triggerName, Map("payload" -> "bogus2".toJson))
-
- withActivation(wsk.activation, first) { activation =>
- // tries to find 2 activations for the action, should only find 1
- val activations = wsk.activation.pollFor(
- 2,
- Some(actionName),
- since = Some(activation.start.minusMillis(activationTimeSkewFactorMs)),
- retries = 30)
+ val second = wsk.trigger.fire(triggerName, Map("payload" -> "bogus2".toJson))
- activations.length shouldBe 1
- }
+ withActivation(wsk.activation, first)(activation => activation.logs.get should have size 1)
+ // there won't be an activation for the second fire since there is no rule
}
it should "enable and disable a rule and check action is activated only when rule is enabled" in withAssetCleaner(
@@ -259,18 +239,27 @@ abstract class WskRuleTests extends TestHelpers with WskTestHelpers {
val first = wsk.trigger.fire(triggerName, Map("payload" -> testString.toJson))
wsk.rule.disable(ruleName)
- wsk.trigger.fire(triggerName, Map("payload" -> s"$testString with added words".toJson))
+ val second = wsk.trigger.fire(triggerName, Map("payload" -> s"$testString with added words".toJson))
wsk.rule.enable(ruleName)
- wsk.trigger.fire(triggerName, Map("payload" -> testString.toJson))
+ val third = wsk.trigger.fire(triggerName, Map("payload" -> testString.toJson))
withActivation(wsk.activation, first) { triggerActivation =>
- withActivationsFromEntity(
- wsk.activation,
- actionName,
- N = 2,
- since = Some(triggerActivation.start.minusMillis(activationTimeSkewFactorMs))) { activations =>
- val results = activations.map(_.response.result)
- results should contain theSameElementsAs Seq(Some(testResult), Some(testResult))
+ val ruleActivations = triggerActivation.logs.get.map(_.parseJson.convertTo[RuleActivationResult])
+ ruleActivations should have size 1
+ val ruleActivation = ruleActivations.head
+ withActivation(wsk.activation, ruleActivation.activationId) { actionActivation =>
+ actionActivation.response.result shouldBe Some(testResult)
+ }
+ }
+
+ // second fire will not write an activation
+
+ withActivation(wsk.activation, third) { triggerActivation =>
+ val ruleActivations = triggerActivation.logs.get.map(_.parseJson.convertTo[RuleActivationResult])
+ ruleActivations should have size 1
+ val ruleActivation = ruleActivations.head
+ withActivation(wsk.activation, ruleActivation.activationId) { actionActivation =>
+ actionActivation.response.result shouldBe Some(testResult)
}
}
}
@@ -288,7 +277,7 @@ abstract class WskRuleTests extends TestHelpers with WskTestHelpers {
assetHelper.withCleaner(wsk.action, actionName) { (action, name) =>
action.create(name, Some(defaultAction))
}
- assetHelper.withCleaner(wsk.rule, ruleName, false) { (rule, name) =>
+ assetHelper.withCleaner(wsk.rule, ruleName, confirmDelete = false) { (rule, name) =>
rule.create(name, triggerName1, actionName)
}
@@ -303,11 +292,11 @@ abstract class WskRuleTests extends TestHelpers with WskTestHelpers {
val first = wsk.trigger.fire(triggerName2, Map("payload" -> testString.toJson))
withActivation(wsk.activation, first) { triggerActivation =>
- withActivationsFromEntity(
- wsk.activation,
- actionName,
- since = Some(triggerActivation.start.minusMillis(activationTimeSkewFactorMs))) {
- _.head.response.result shouldBe Some(testResult)
+ val ruleActivations = triggerActivation.logs.get.map(_.parseJson.convertTo[RuleActivationResult])
+ ruleActivations should have size 1
+ val ruleActivation = ruleActivations.head
+ withActivation(wsk.activation, ruleActivation.activationId) { actionActivation =>
+ actionActivation.response.result shouldBe Some(testResult)
}
}
}
@@ -325,23 +314,18 @@ abstract class WskRuleTests extends TestHelpers with WskTestHelpers {
assetHelper)
val testPayloads = Seq("got three words", "got four words, period")
-
- val run = wsk.trigger.fire(triggerName1, Map("payload" -> testPayloads(0).toJson))
- wsk.trigger.fire(triggerName2, Map("payload" -> testPayloads(1).toJson))
-
- withActivation(wsk.activation, run) { triggerActivation =>
- withActivationsFromEntity(
- wsk.activation,
- actionName,
- N = 2,
- since = Some(triggerActivation.start.minusMillis(activationTimeSkewFactorMs))) { activations =>
- val results = activations.map(_.response.result)
- val expectedResults = testPayloads.map { payload =>
- Some(JsObject("count" -> payload.split(" ").length.toJson))
+ val runs = testPayloads.map(payload => wsk.trigger.fire(triggerName1, Map("payload" -> payload.toJson)))
+
+ runs.zip(testPayloads).foreach {
+ case (run, payload) =>
+ withActivation(wsk.activation, run) { triggerActivation =>
+ val ruleActivations = triggerActivation.logs.get.map(_.parseJson.convertTo[RuleActivationResult])
+ ruleActivations should have size 1
+ val ruleActivation = ruleActivations.head
+ withActivation(wsk.activation, ruleActivation.activationId) { actionActivation =>
+ actionActivation.response.result shouldBe Some(JsObject("count" -> payload.split(" ").length.toJson))
+ }
}
-
- results should contain theSameElementsAs expectedResults
- }
}
}
@@ -360,17 +344,17 @@ abstract class WskRuleTests extends TestHelpers with WskTestHelpers {
val run = wsk.trigger.fire(triggerName, Map("payload" -> testString.toJson))
withActivation(wsk.activation, run) { triggerActivation =>
- withActivationsFromEntity(
- wsk.activation,
- actionName1,
- since = Some(triggerActivation.start.minusMillis(activationTimeSkewFactorMs))) {
- _.head.response.result shouldBe Some(testResult)
+ val ruleActivations = triggerActivation.logs.get.map(_.parseJson.convertTo[RuleActivationResult])
+ ruleActivations should have size 2
+
+ val action1Result = ruleActivations.find(_.action.contains(actionName1)).get
+ val action2Result = ruleActivations.find(_.action.contains(actionName2)).get
+
+ withActivation(wsk.activation, action1Result.activationId) { actionActivation =>
+ actionActivation.response.result shouldBe Some(testResult)
}
- withActivationsFromEntity(
- wsk.activation,
- actionName2,
- since = Some(triggerActivation.start.minusMillis(activationTimeSkewFactorMs))) {
- _.head.logs.get.mkString(" ") should include(s"hello, $testString")
+ withActivation(wsk.activation, action2Result.activationId) { actionActivation =>
+ actionActivation.logs.get.mkString(" ") should include(s"hello, $testString")
}
}
}
@@ -391,35 +375,27 @@ abstract class WskRuleTests extends TestHelpers with WskTestHelpers {
assetHelper)
val testPayloads = Seq("got three words", "got four words, period")
- val run = wsk.trigger.fire(triggerName1, Map("payload" -> testPayloads(0).toJson))
- wsk.trigger.fire(triggerName2, Map("payload" -> testPayloads(1).toJson))
+ val runs = Seq(triggerName1, triggerName2).zip(testPayloads).map {
+ case (trigger, payload) =>
+ payload -> wsk.trigger.fire(trigger, Map("payload" -> payload.toJson))
+ }
- withActivation(wsk.activation, run) { triggerActivation =>
- withActivationsFromEntity(
- wsk.activation,
- actionName1,
- N = 2,
- since = Some(triggerActivation.start.minusMillis(activationTimeSkewFactorMs))) { activations =>
- val results = activations.map(_.response.result)
- val expectedResults = testPayloads.map { payload =>
- Some(JsObject("count" -> payload.split(" ").length.toJson))
+ runs.foreach {
+ case (payload, run) =>
+ withActivation(wsk.activation, run) { triggerActivation =>
+ val ruleActivations = triggerActivation.logs.get.map(_.parseJson.convertTo[RuleActivationResult])
+ ruleActivations should have size 2 // each trigger has 2 actions attached
+
+ val action1Result = ruleActivations.find(_.action.contains(actionName1)).get
+ val action2Result = ruleActivations.find(_.action.contains(actionName2)).get
+
+ withActivation(wsk.activation, action1Result.activationId) { actionActivation =>
+ actionActivation.response.result shouldBe Some(JsObject("count" -> payload.split(" ").length.toJson))
+ }
+ withActivation(wsk.activation, action2Result.activationId) { actionActivation =>
+ actionActivation.logs.get.mkString(" ") should include(s"hello, $payload")
+ }
}
-
- results should contain theSameElementsAs expectedResults
- }
- withActivationsFromEntity(
- wsk.activation,
- actionName2,
- N = 2,
- since = Some(triggerActivation.start.minusMillis(activationTimeSkewFactorMs))) { activations =>
- // drops the leftmost 39 characters (timestamp + streamname)
- val logs = activations.map(_.logs.get.map(_.drop(39))).flatten
- val expectedLogs = testPayloads.map { payload =>
- s"hello, $payload!"
- }
-
- logs should contain theSameElementsAs expectedLogs
- }
}
}
@@ -446,6 +422,6 @@ abstract class WskRuleTests extends TestHelpers with WskTestHelpers {
val listOutput = ruleList.lines
listOutput.find(_.contains(ruleNameEnable)).get should (include(ruleNameEnable) and include("active"))
listOutput.find(_.contains(ruleName)).get should (include(ruleName) and include("inactive"))
- ruleList should not include ("Unknown")
+ ruleList should not include "Unknown"
}
}
diff --git a/tests/src/test/scala/system/basic/WskSequenceTests.scala b/tests/src/test/scala/system/basic/WskSequenceTests.scala
index 99fa8fa..f7dc39d 100644
--- a/tests/src/test/scala/system/basic/WskSequenceTests.scala
+++ b/tests/src/test/scala/system/basic/WskSequenceTests.scala
@@ -34,6 +34,7 @@ import common.TestUtils
import common.TestUtils._
import common.BaseWsk
import common.WskProps
+import common.RuleActivationResult
import common.WskTestHelpers
import akka.http.scaladsl.testkit.ScalatestRouteTest
@@ -472,9 +473,10 @@ abstract class WskSequenceTests extends TestHelpers with ScalatestRouteTest with
*/
private def checkEchoSeqRuleResult(triggerFireRun: RunResult, seqName: String, triggerPayload: JsObject) = {
withActivation(wsk.activation, triggerFireRun) { triggerActivation =>
- withActivationsFromEntity(wsk.activation, seqName, since = Some(triggerActivation.start)) { activationList =>
- activationList.head.response.result shouldBe Some(triggerPayload)
- activationList.head.cause shouldBe None
+ val ruleActivation = triggerActivation.logs.get.map(_.parseJson.convertTo[RuleActivationResult]).head
+ withActivation(wsk.activation, ruleActivation.activationId) { actionActivation =>
+ actionActivation.response.result shouldBe Some(triggerPayload)
+ actionActivation.cause shouldBe None
}
}
}
--
To stop receiving notification emails like this one, please contact
cbickel@apache.org.