This is an automated email from the ASF dual-hosted git repository. csantanapr pushed a commit to branch master in repository https://gitbox.apache.org/repos/asf/incubator-openwhisk-cli.git
commit 616a1e1e404b275fb1d04a3747dc1daba4229758 Author: Justin Berstler <bjus...@us.ibm.com> AuthorDate: Tue May 9 10:21:29 2017 -0400 Add a fudge factor to handle clock skew in the invokers (#2197) Due to clock skew among invokers, it is possible for an action invoked by a rule _appears_ to start before the trigger which activated the rule was even fired. As such, these tests tend to fail because it is looking for action activations that start strictly after the time the trigger activation started. This change introduces a "fudge factor" to allow the test to find the expected action activations that appear to start at most 500ms before the trigger activation start time. Introducing the fudge factor makes it possible that activations from previous tests are found. Ensuring that entity names are unique between tests avoids this potential problem. --- .../src/test/scala/system/basic/WskRuleTests.scala | 105 ++++++++++++--------- 1 file changed, 59 insertions(+), 46 deletions(-) diff --git a/tests/src/test/scala/system/basic/WskRuleTests.scala b/tests/src/test/scala/system/basic/WskRuleTests.scala index 461639d..8f5fe85 100644 --- a/tests/src/test/scala/system/basic/WskRuleTests.scala +++ b/tests/src/test/scala/system/basic/WskRuleTests.scala @@ -41,6 +41,14 @@ class WskRuleTests 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. * @@ -74,13 +82,18 @@ class WskRuleTests } } + /** + * Append the current timestamp in ms + */ + def withTimestamp(text: String) = s"${text}-${System.currentTimeMillis}" + behavior of "Whisk rules" it should "invoke the action attached on trigger fire, creating an activation for each entity including the cause" in withAssetCleaner(wskprops) { (wp, assetHelper) => - val ruleName = "r1to1" - val triggerName = "t1to1" - val actionName = "a1 to 1" // spaces in name intended for greater test coverage + val ruleName = withTimestamp("r1to1") + val triggerName = withTimestamp("t1to1") + val actionName = withTimestamp("a1 to 1") // spaces in name intended for greater test coverage ruleSetup(Seq( (ruleName, triggerName, (actionName, actionName, defaultAction))), @@ -92,11 +105,11 @@ class WskRuleTests triggerActivation => triggerActivation.cause shouldBe None - withActivationsFromEntity(wsk.activation, ruleName, since = Some(triggerActivation.start)) { + withActivationsFromEntity(wsk.activation, ruleName, since = Some(triggerActivation.start.minusMillis(activationTimeSkewFactorMs))) { _.head.cause shouldBe Some(triggerActivation.activationId) } - withActivationsFromEntity(wsk.activation, actionName, since = Some(triggerActivation.start)) { activationList => + withActivationsFromEntity(wsk.activation, actionName, since = Some(triggerActivation.start.minusMillis(activationTimeSkewFactorMs))) { activationList => activationList.head.response.result shouldBe Some(testResult) activationList.head.cause shouldBe None } @@ -105,10 +118,10 @@ class WskRuleTests it should "invoke the action from a package attached on trigger fire, creating an activation for each entity including the cause" in withAssetCleaner(wskprops) { (wp, assetHelper) => - val ruleName = "pr1to1" - val triggerName = "pt1to1" - val pkgName = "rule pkg" // spaces in name intended to test uri path encoding - val actionName = "a1 to 1" + val ruleName = withTimestamp("pr1to1") + val triggerName = withTimestamp("pt1to1") + val pkgName = withTimestamp("rule pkg") // spaces in name intended to test uri path encoding + val actionName = withTimestamp("a1 to 1") val pkgActionName = s"$pkgName/$actionName" assetHelper.withCleaner(wsk.pkg, pkgName) { @@ -126,11 +139,11 @@ class WskRuleTests triggerActivation => triggerActivation.cause shouldBe None - withActivationsFromEntity(wsk.activation, ruleName, since = Some(triggerActivation.start)) { + withActivationsFromEntity(wsk.activation, ruleName, since = Some(triggerActivation.start.minusMillis(activationTimeSkewFactorMs))) { _.head.cause shouldBe Some(triggerActivation.activationId) } - withActivationsFromEntity(wsk.activation, actionName, since = Some(triggerActivation.start)) { + withActivationsFromEntity(wsk.activation, actionName, since = Some(triggerActivation.start.minusMillis(activationTimeSkewFactorMs))) { _.head.response.result shouldBe Some(testResult) } } @@ -138,11 +151,11 @@ class WskRuleTests it should "invoke the action from a package binding attached on trigger fire, creating an activation for each entity including the cause" in withAssetCleaner(wskprops) { (wp, assetHelper) => - val ruleName = "pr1to1" - val triggerName = "pt1to1" - val pkgName = "rule pkg" // spaces in name intended to test uri path encoding - val pkgBindingName = "rule pkg binding" - val actionName = "a1 to 1" + val ruleName = withTimestamp("pr1to1") + val triggerName = withTimestamp("pt1to1") + val pkgName = withTimestamp("rule pkg") // spaces in name intended to test uri path encoding + val pkgBindingName = withTimestamp("rule pkg binding") + val actionName = withTimestamp("a1 to 1") val pkgActionName = s"$pkgName/$actionName" assetHelper.withCleaner(wsk.pkg, pkgName) { @@ -163,11 +176,11 @@ class WskRuleTests triggerActivation => triggerActivation.cause shouldBe None - withActivationsFromEntity(wsk.activation, ruleName, since = Some(triggerActivation.start)) { + withActivationsFromEntity(wsk.activation, ruleName, since = Some(triggerActivation.start.minusMillis(activationTimeSkewFactorMs))) { _.head.cause shouldBe Some(triggerActivation.activationId) } - withActivationsFromEntity(wsk.activation, actionName, since = Some(triggerActivation.start)) { + withActivationsFromEntity(wsk.activation, actionName, since = Some(triggerActivation.start.minusMillis(activationTimeSkewFactorMs))) { _.head.response.result shouldBe Some(testResult) } } @@ -175,9 +188,9 @@ class WskRuleTests it should "not activate an action if the rule is deleted when the trigger is fired" in withAssetCleaner(wskprops) { (wp, assetHelper) => - val ruleName = "ruleDelete" - val triggerName = "ruleDeleteTrigger" - val actionName = "ruleDeleteAction" + val ruleName = withTimestamp("ruleDelete") + val triggerName = withTimestamp("ruleDeleteTrigger") + val actionName = withTimestamp("ruleDeleteAction") assetHelper.withCleaner(wsk.trigger, triggerName) { (trigger, name) => trigger.create(name) @@ -196,7 +209,7 @@ class WskRuleTests 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), retries = 30) + val activations = wsk.activation.pollFor(2, Some(actionName), since = Some(activation.start.minusMillis(activationTimeSkewFactorMs)), retries = 30) activations.length shouldBe 1 } @@ -204,9 +217,9 @@ class WskRuleTests it should "enable and disable a rule and check action is activated only when rule is enabled" in withAssetCleaner(wskprops) { (wp, assetHelper) => - val ruleName = "ruleDisable" - val triggerName = "ruleDisableTrigger" - val actionName = "ruleDisableAction" + val ruleName = withTimestamp("ruleDisable") + val triggerName = withTimestamp("ruleDisableTrigger") + val actionName = withTimestamp("ruleDisableAction") ruleSetup(Seq( (ruleName, triggerName, (actionName, actionName, defaultAction))), @@ -220,7 +233,7 @@ class WskRuleTests withActivation(wsk.activation, first) { triggerActivation => - withActivationsFromEntity(wsk.activation, actionName, N = 2, since = Some(triggerActivation.start)) { + 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)) @@ -230,10 +243,10 @@ class WskRuleTests it should "be able to recreate a rule with the same name and match it successfully" in withAssetCleaner(wskprops) { (wp, assetHelper) => - val ruleName = "ruleRecreate" - val triggerName1 = "ruleRecreateTrigger1" - val triggerName2 = "ruleRecreateTrigger2" - val actionName = "ruleRecreateAction" + val ruleName = withTimestamp("ruleRecreate") + val triggerName1 = withTimestamp("ruleRecreateTrigger1") + val triggerName2 = withTimestamp("ruleRecreateTrigger2") + val actionName = withTimestamp("ruleRecreateAction") assetHelper.withCleaner(wsk.trigger, triggerName1) { (trigger, name) => trigger.create(name) @@ -257,7 +270,7 @@ class WskRuleTests val first = wsk.trigger.fire(triggerName2, Map("payload" -> testString.toJson)) withActivation(wsk.activation, first) { triggerActivation => - withActivationsFromEntity(wsk.activation, actionName, since = Some(triggerActivation.start)) { + withActivationsFromEntity(wsk.activation, actionName, since = Some(triggerActivation.start.minusMillis(activationTimeSkewFactorMs))) { _.head.response.result shouldBe Some(testResult) } } @@ -265,9 +278,9 @@ class WskRuleTests it should "connect two triggers via rules to one action and activate it accordingly" in withAssetCleaner(wskprops) { (wp, assetHelper) => - val triggerName1 = "t2to1a" - val triggerName2 = "t2to1b" - val actionName = "a2to1" + val triggerName1 = withTimestamp("t2to1a") + val triggerName2 = withTimestamp("t2to1b") + val actionName = withTimestamp("a2to1") ruleSetup(Seq( ("r2to1a", triggerName1, (actionName, actionName, defaultAction)), @@ -281,7 +294,7 @@ class WskRuleTests withActivation(wsk.activation, run) { triggerActivation => - withActivationsFromEntity(wsk.activation, actionName, N = 2, since = Some(triggerActivation.start)) { + withActivationsFromEntity(wsk.activation, actionName, N = 2, since = Some(triggerActivation.start.minusMillis(activationTimeSkewFactorMs))) { activations => val results = activations.map(_.response.result) val expectedResults = testPayloads.map { payload => @@ -295,9 +308,9 @@ class WskRuleTests it should "connect one trigger to two different actions, invoking them both eventually" in withAssetCleaner(wskprops) { (wp, assetHelper) => - val triggerName = "t1to2" - val actionName1 = "a1to2a" - val actionName2 = "a1to2b" + val triggerName = withTimestamp("t1to2") + val actionName1 = withTimestamp("a1to2a") + val actionName2 = withTimestamp("a1to2b") ruleSetup(Seq( ("r1to2a", triggerName, (actionName1, actionName1, defaultAction)), @@ -308,10 +321,10 @@ class WskRuleTests withActivation(wsk.activation, run) { triggerActivation => - withActivationsFromEntity(wsk.activation, actionName1, since = Some(triggerActivation.start)) { + withActivationsFromEntity(wsk.activation, actionName1, since = Some(triggerActivation.start.minusMillis(activationTimeSkewFactorMs))) { _.head.response.result shouldBe Some(testResult) } - withActivationsFromEntity(wsk.activation, actionName2, since = Some(triggerActivation.start)) { + withActivationsFromEntity(wsk.activation, actionName2, since = Some(triggerActivation.start.minusMillis(activationTimeSkewFactorMs))) { _.head.logs.get.mkString(" ") should include(s"hello, $testString") } } @@ -319,10 +332,10 @@ class WskRuleTests it should "connect two triggers to two different actions, invoking them both eventually" in withAssetCleaner(wskprops) { (wp, assetHelper) => - val triggerName1 = "t1to1a" - val triggerName2 = "t1to1b" - val actionName1 = "a1to1a" - val actionName2 = "a1to1b" + val triggerName1 = withTimestamp("t1to1a") + val triggerName2 = withTimestamp("t1to1b") + val actionName1 = withTimestamp("a1to1a") + val actionName2 = withTimestamp("a1to1b") ruleSetup(Seq( ("r2to2a", triggerName1, (actionName1, actionName1, defaultAction)), @@ -337,7 +350,7 @@ class WskRuleTests withActivation(wsk.activation, run) { triggerActivation => - withActivationsFromEntity(wsk.activation, actionName1, N = 2, since = Some(triggerActivation.start)) { + withActivationsFromEntity(wsk.activation, actionName1, N = 2, since = Some(triggerActivation.start.minusMillis(activationTimeSkewFactorMs))) { activations => val results = activations.map(_.response.result) val expectedResults = testPayloads.map { payload => @@ -346,7 +359,7 @@ class WskRuleTests results should contain theSameElementsAs expectedResults } - withActivationsFromEntity(wsk.activation, actionName2, N = 2, since = Some(triggerActivation.start)) { + 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 -- To stop receiving notification emails like this one, please contact "commits@openwhisk.apache.org" <commits@openwhisk.apache.org>.