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-package-alarms.git


The following commit(s) were added to refs/heads/master by this push:
     new b8d4d67  optionally limit cron fields to 5 instead of 6 (#126)
b8d4d67 is described below

commit b8d4d67abb015e728ea1db23c4b39e4b8674b45e
Author: Jason Peterson <jason...@us.ibm.com>
AuthorDate: Tue Feb 13 12:14:21 2018 -0500

    optionally limit cron fields to 5 instead of 6 (#126)
---
 action/alarmWebAction.js                           | 35 +++++-----
 action/lib/common.js                               | 17 ++++-
 installCatalog.sh                                  | 37 +++++-----
 .../system/health/AlarmsHealthFeedTests.scala      | 78 +++-------------------
 .../scala/system/packages/AlarmsFeedTests.scala    | 31 ++++++++-
 5 files changed, 92 insertions(+), 106 deletions(-)

diff --git a/action/alarmWebAction.js b/action/alarmWebAction.js
index d56a159..b5b5bde 100644
--- a/action/alarmWebAction.js
+++ b/action/alarmWebAction.js
@@ -72,6 +72,10 @@ function main(params) {
 
                 try {
                     cronHandle = new CronJob(params.cron, function() {});
+                    //validate cron granularity if 5 fields are allowed 
instead of 6
+                    if (params.limitCronFields && 
hasSecondsGranularity(params.cron)) {
+                        return common.sendError(400, 'cron pattern is limited 
to 5 fields with 1 minute as the finest granularity');
+                    }
                     newTrigger.cron = params.cron;
                 } catch(ex) {
                     return common.sendError(400, `cron pattern 
'${params.cron}' is not valid`);
@@ -198,7 +202,7 @@ function main(params) {
                 }
 
                 if (params.trigger_payload) {
-                    updatedParams.payload = 
constructPayload(params.trigger_payload);
+                    updatedParams.payload = 
common.constructPayload(params.trigger_payload);
                 }
 
                 if (trigger.date) {
@@ -228,6 +232,10 @@ function main(params) {
                         if (params.cron) {
                             try {
                                 new CronJob(params.cron, function() {});
+                                //validate cron granularity if 5 fields are 
allowed instead of 6
+                                if (params.limitCronFields && 
hasSecondsGranularity(params.cron)) {
+                                    return common.sendError(400, 'cron pattern 
is limited to 5 fields with 1 minute as the finest granularity');
+                                }
                             } catch (ex) {
                                 return reject(common.sendError(400, `cron 
pattern '${params.cron}' is not valid`));
                             }
@@ -313,20 +321,6 @@ function main(params) {
     }
 }
 
-function constructPayload(payload) {
-
-    var updatedPayload;
-    if (payload) {
-        if (typeof payload === 'string') {
-            updatedPayload = {payload: payload};
-        }
-        if (typeof payload === 'object') {
-            updatedPayload = payload;
-        }
-    }
-    return updatedPayload;
-}
-
 function validateDate(date, paramName, startDate) {
 
     var dateObject = new Date(date);
@@ -346,6 +340,17 @@ function validateDate(date, paramName, startDate) {
 
 }
 
+function hasSecondsGranularity(cron) {
+
+    var fields = (cron + '').trim().split(/\s+/);
+
+    if (fields.length > 5 && fields[fields.length - 6] !== '0') {
+        return true;
+    }
+
+    return false;
+}
+
 exports.main = main;
 
 
diff --git a/action/lib/common.js b/action/lib/common.js
index c62e1f8..663be12 100644
--- a/action/lib/common.js
+++ b/action/lib/common.js
@@ -104,11 +104,26 @@ function sendError(statusCode, error, message) {
     };
 }
 
+function constructPayload(payload) {
+
+    var updatedPayload;
+    if (payload) {
+        if (typeof payload === 'string') {
+            updatedPayload = {payload: payload};
+        }
+        if (typeof payload === 'object') {
+            updatedPayload = payload;
+        }
+    }
+    return updatedPayload;
+}
+
 
 module.exports = {
     'requestHelper': requestHelper,
     'createWebParams': createWebParams,
     'verifyTriggerAuth': verifyTriggerAuth,
     'parseQName': parseQName,
-    'sendError': sendError
+    'sendError': sendError,
+    'constructPayload': constructPayload
 };
diff --git a/installCatalog.sh b/installCatalog.sh
index ddc9337..85f6467 100755
--- a/installCatalog.sh
+++ b/installCatalog.sh
@@ -12,9 +12,8 @@ set -x
 : ${OPENWHISK_HOME:?"OPENWHISK_HOME must be set and non-empty"}
 WSK_CLI="$OPENWHISK_HOME/bin/wsk"
 
-if [ $# -eq 0 ]
-then
-echo "Usage: ./installCatalog.sh <authkey> <edgehost> <dburl> <dbprefix> 
<apihost> <workers>"
+if [ $# -eq 0 ]; then
+    echo "Usage: ./installCatalog.sh <authkey> <edgehost> <dburl> <dbprefix> 
<apihost> <workers>"
 fi
 
 AUTH="$1"
@@ -23,6 +22,7 @@ DB_URL="$3"
 DB_NAME="${4}alarmservice"
 APIHOST="$5"
 WORKERS="$6"
+LIMIT_CRON_FIELDS="${LIMIT_CRON_FIELDS}"
 
 # If the auth key file exists, read the key in the file. Otherwise, take the
 # first argument as the key itself.
@@ -57,8 +57,7 @@ $WSK_CLI -i --apihost "$EDGEHOST" package update --auth 
"$AUTH" --shared yes ala
 # make alarmFeed.zip
 cd action
 
-if [ -e alarmFeed.zip ]
-then
+if [ -e alarmFeed.zip ]; then
     rm -rf alarmFeed.zip
 fi
 
@@ -82,26 +81,26 @@ $WSK_CLI -i --apihost "$EDGEHOST" action update --kind 
nodejs:6 --auth "$AUTH" a
      -a feed true \
      -p isInterval true
 
-if [ -n "$WORKERS" ];
-then
-    $WSK_CLI -i --apihost "$EDGEHOST" package update --auth "$AUTH" --shared 
no alarmsWeb \
-        -p DB_URL "$DB_URL" \
-        -p DB_NAME "$DB_NAME" \
-        -p apihost "$APIHOST" \
-        -p workers "$WORKERS"
-else
-    $WSK_CLI -i --apihost "$EDGEHOST" package update --auth "$AUTH" --shared 
no alarmsWeb \
-        -p DB_URL "$DB_URL" \
-        -p DB_NAME "$DB_NAME" \
-        -p apihost "$APIHOST"
+COMMAND=" -i --apihost $EDGEHOST package update --auth $AUTH --shared no 
alarmsWeb \
+    -p DB_URL $DB_URL \
+    -p DB_NAME $DB_NAME \
+    -p apihost $APIHOST"
+
+if [ -n "$WORKERS" ]; then
+    COMMAND+=" -p workers $WORKERS"
+fi
+
+if [ -n "$LIMIT_CRON_FIELDS" ]; then
+    COMMAND+=" -p limitCronFields $LIMIT_CRON_FIELDS"
 fi
 
+$WSK_CLI $COMMAND
+
 # make alarmWebAction.zip
 cp -f alarmWeb_package.json package.json
 npm install
 
-if [ -e alarmWebAction.zip ];
-then
+if [ -e alarmWebAction.zip ]; then
     rm -rf alarmWebAction.zip
 fi
 
diff --git a/tests/src/test/scala/system/health/AlarmsHealthFeedTests.scala 
b/tests/src/test/scala/system/health/AlarmsHealthFeedTests.scala
index cbee2c5..e1b84f4 100644
--- a/tests/src/test/scala/system/health/AlarmsHealthFeedTests.scala
+++ b/tests/src/test/scala/system/health/AlarmsHealthFeedTests.scala
@@ -43,67 +43,6 @@ class AlarmsHealthFeedTests
 
     behavior of "Alarms Health tests"
 
-    it should "bind alarm package and fire periodic trigger using cron feed" 
in withAssetCleaner(wskprops) {
-        (wp, assetHelper) =>
-            implicit val wskprops = wp // shadow global props and make implicit
-            val triggerName = s"dummyAlarmsTrigger-${System.currentTimeMillis}"
-            val ruleName = s"dummyAlarmsRule-${System.currentTimeMillis}"
-            val actionName = s"dummyAlarmsAction-${System.currentTimeMillis}"
-            val packageName = "dummyAlarmsPackage"
-
-            // the package alarms should be there
-            val packageGetResult = wsk.pkg.get("/whisk.system/alarms")
-            println("fetched package alarms")
-            packageGetResult.stdout should include("ok")
-
-            // create package binding
-            assetHelper.withCleaner(wsk.pkg, packageName) {
-                (pkg, name) => pkg.bind("/whisk.system/alarms", name)
-            }
-
-            // create action
-            assetHelper.withCleaner(wsk.action, actionName) { (action, name) =>
-                action.create(name, defaultAction)
-            }
-
-            // create trigger feed
-            println(s"Creating trigger: $triggerName")
-            assetHelper.withCleaner(wsk.trigger, triggerName) {
-                (trigger, name) =>
-                    trigger.create(name, feed = Some(s"$packageName/alarm"), 
parameters = Map(
-                        "trigger_payload" -> "alarmTest".toJson,
-                        "cron" -> "* * * * * *".toJson))
-            }
-
-            // create rule
-            assetHelper.withCleaner(wsk.rule, ruleName) { (rule, name) =>
-                rule.create(name, trigger = triggerName, action = actionName)
-            }
-
-            println("waiting for triggers")
-            val activations = wsk.activation.pollFor(N = 5, Some(triggerName), 
retries = 30).length
-            println(s"Found activation size (should be at least 5): 
$activations")
-            activations should be >= 5
-
-            // delete the whisk trigger, which must also delete the feed
-            wsk.trigger.delete(triggerName)
-
-            // get activation list after delete of the trigger
-            val activationsAfterDelete = wsk.activation.pollFor(N = 100, 
Some(triggerName), retries = 30).length
-            val now = Instant.now(Clock.systemUTC())
-            println(s"Found activation size after delete ($now): 
$activationsAfterDelete")
-
-            // recreate the trigger now without the feed
-            wsk.trigger.create(triggerName)
-
-            // get activation list again, should be same as before waiting
-            println("confirming no new triggers")
-            val activationsAfterWait = wsk.activation.pollFor(N = 
activationsAfterDelete + 1, Some(triggerName)).length
-            println(s"Found activation size after wait: $activationsAfterWait")
-            println("Activation list after wait should equal with activation 
list after delete")
-            activationsAfterWait should be(activationsAfterDelete)
-    }
-
     it should "fire an alarm once trigger when specifying a future date" in 
withAssetCleaner(wskprops) {
         (wp, assetHelper) =>
             implicit val wskprops = wp // shadow global props and make implicit
@@ -173,14 +112,14 @@ class AlarmsHealthFeedTests
             }
 
             val startDate = System.currentTimeMillis + (1000 * 20)
-            val stopDate = startDate + (1000 * 10)
+            val stopDate = startDate + (1000 * 60)
 
             // create trigger feed
             println(s"Creating trigger: $triggerName")
             assetHelper.withCleaner(wsk.trigger, triggerName) {
                 (trigger, name) =>
                     trigger.create(name, feed = Some(s"$packageName/alarm"), 
parameters = Map(
-                        "cron" -> "* * * * * *".toJson,
+                        "cron" -> "* * * * *".toJson,
                         "startDate" -> startDate.toJson,
                         "stopDate" -> stopDate.toJson))
             }
@@ -191,9 +130,9 @@ class AlarmsHealthFeedTests
             }
 
             println("waiting for triggers")
-            val activations = wsk.activation.pollFor(N = 20, 
Some(triggerName), retries = 60).length
-            println(s"Found activation size (should be at least 5): 
$activations")
-            activations should be >= 5
+            val activations = wsk.activation.pollFor(N = 1, Some(triggerName), 
retries = 90).length
+            println(s"Found activation size (should be 1): $activations")
+            activations should be(1)
 
 
             // get activation list again, should be same as before waiting
@@ -277,8 +216,7 @@ class AlarmsHealthFeedTests
             val triggerPayload = JsObject(
                 "test" -> JsString("alarmsTest")
             )
-            val cronString = "* * * * * *"
-            val maxTriggers = -1
+            val cronString = "* * * * *"
 
             // create trigger feed
             val feedCreationResult = assetHelper.withCleaner(wsk.trigger, 
triggerName) {
@@ -335,7 +273,7 @@ class AlarmsHealthFeedTests
                 (pkg, name) => pkg.bind("/whisk.system/alarms", name)
             }
 
-            val cron = "* * * * * *"
+            val cron = "* * * * *"
             val startDate = System.currentTimeMillis + (1000 * 20)
             val stopDate = startDate + (1000 * 10)
 
@@ -371,7 +309,7 @@ class AlarmsHealthFeedTests
                     }
             }
 
-            val updatedCron = "*/2 * * * * *"
+            val updatedCron = "*/2 * * * *"
             val updatedStartDate = System.currentTimeMillis + (1000 * 20)
             val updatedStopDate = updatedStartDate + (1000 * 10)
 
diff --git a/tests/src/test/scala/system/packages/AlarmsFeedTests.scala 
b/tests/src/test/scala/system/packages/AlarmsFeedTests.scala
index 62dd74f..59c4b0a 100644
--- a/tests/src/test/scala/system/packages/AlarmsFeedTests.scala
+++ b/tests/src/test/scala/system/packages/AlarmsFeedTests.scala
@@ -20,7 +20,7 @@ import common._
 import org.junit.runner.RunWith
 import org.scalatest.FlatSpec
 import org.scalatest.junit.JUnitRunner
-import spray.json.DefaultJsonProtocol.{IntJsonFormat, LongJsonFormat, 
StringJsonFormat}
+import spray.json.DefaultJsonProtocol.{BooleanJsonFormat, IntJsonFormat, 
LongJsonFormat, StringJsonFormat}
 import spray.json.{JsString, pimpAny}
 
 /**
@@ -452,4 +452,33 @@ class AlarmsFeedTests
                     error.fields("error") shouldBe JsString(s"startDate 
parameter '${updatedStartDate}' must be less than the stopDate parameter 
'${stopDate}'")
             }
     }
+
+    it should "return error message when limitCronFields is true and 6 cron 
fields are used" in withAssetCleaner(wskprops) {
+        (wp, assetHelper) =>
+            implicit val wskprops = wp // shadow global props and make implicit
+            val triggerName = 
s"dummyCloudantTrigger-${System.currentTimeMillis}"
+            val packageName = "dummyCloudantPackage"
+            val feed = "alarm"
+
+            // the package alarms should be there
+            val packageGetResult = wsk.pkg.get("/whisk.system/alarms")
+            println("fetched package alarms")
+            packageGetResult.stdout should include("ok")
+
+            // create package binding
+            assetHelper.withCleaner(wsk.pkg, packageName) {
+                (pkg, name) => pkg.bind("/whisk.system/alarms", name)
+            }
+
+            // create trigger with feed
+            val feedCreationResult = assetHelper.withCleaner(wsk.trigger, 
triggerName, confirmDelete = false) {
+                (trigger, name) =>
+                    trigger.create(name, feed = Some(s"$packageName/$feed"), 
parameters = Map(
+                        "cron" -> "* * * * * *".toJson,
+                        "limitCronFields" -> true.toJson),
+                        expectedExitCode = 246)
+            }
+            feedCreationResult.stderr should include("cron pattern is limited 
to 5 fields with 1 minute as the finest granularity")
+
+    }
 }

-- 
To stop receiving notification emails like this one, please contact
csantan...@apache.org.

Reply via email to