You are viewing a plain text version of this content. The canonical link for it is here.
Posted to issues@openwhisk.apache.org by GitBox <gi...@apache.org> on 2017/11/17 19:24:30 UTC

[GitHub] csantanapr closed pull request #109: add startDate and stopDate support for the alarms feed

csantanapr closed pull request #109: add startDate and stopDate support for the alarms feed
URL: https://github.com/apache/incubator-openwhisk-package-alarms/pull/109
 
 
   

This is a PR merged from a forked repository.
As GitHub hides the original diff on merge, it is displayed below for
the sake of provenance:

As this is a foreign pull request (from a fork), the diff is supplied
below (as it won't show otherwise due to GitHub magic):

diff --git a/README.md b/README.md
index 66d3dee..33f383c 100644
--- a/README.md
+++ b/README.md
@@ -5,12 +5,13 @@
 
 The `/whisk.system/alarms` package can be used to fire a trigger at a specified frequency. This is useful for setting up recurring jobs or tasks, such as invoking a system backup action every hour.
 
-The package includes the following feed.
+The package includes the following feeds.
 
 | Entity | Type | Parameters | Description |
 | --- | --- | --- | --- |
 | `/whisk.system/alarms` | package | - | Alarms and periodic utility |
-| `/whisk.system/alarms/alarm` | feed | cron, trigger_payload, maxTriggers | Fire trigger event periodically |
+| `/whisk.system/alarms/alarm` | feed | cron, trigger_payload, maxTriggers, startDate, stopDate | Fire trigger event periodically |
+| `/whisk.system/alarms/once` | feed | date, trigger_payload | Fire trigger event once on a specific date |
 
 
 ## Firing a trigger event periodically
@@ -24,24 +25,54 @@ For more details about using cron syntax, see: http://crontab.org. Following are
   - `0 * * * *`: top of every hour.
   - `0 */2 * * *`: every 2 hours (i.e. 02:00:00, 04:00:00, ...)
   - `0 9 8 * *`: at 9:00:00AM (UTC) on the eighth day of every month
+  
+  **Note**: The parameter `cron` also supports a custom syntax of six fields, where the first field represents seconds.
+  For more details about using this custom cron syntax, see: https://github.com/ncb000gt/node-cron.
+  Here is an example using six fields notation:
+    - `*/30 * * * * *`: every thirty seconds.
 
 - `trigger_payload`: The value of this parameter becomes the content of the trigger every time the trigger is fired.
 
-- `maxTriggers`: Stop firing triggers when this limit is reached. Defaults to 1,000,000. You can set it to infinite (-1).
+- `maxTriggers`: Stop firing triggers when this limit is reached. Defaults to infinite (-1).
 
-The following is an example of creating a trigger that will be fired once every 2 minutes with `name` and `place` values in the trigger event.
+- `startDate`: The date when the trigger will start running.  The trigger will fire based on the schedule specified by the `cron` parameter.   
+
+- `stopDate`: The date when the trigger will stop running.  Triggers will no longer be fired once this date has been reached.
+
+  **Note**: The `startDate` and `stopDate` parameters support an integer or string value.  The integer value represents the number of milliseconds 
+  since 1 January 1970 00:00:00 UTC and the string value should be in the ISO 8601 format (http://www.ecma-international.org/ecma-262/5.1/#sec-15.9.1.15).
+
+
+The following is an example of creating a trigger that will be fired once every 2 minutes with `name` and `place` values in the trigger event.  The trigger will not start firing until
+January 1, 2019, 00:00:00 UTC and will stop firing January 31, 2019, 23:59:00 UTC.
 
   ```
   wsk trigger create periodic \
     --feed /whisk.system/alarms/alarm \
     --param cron "*/2 * * * *" \
-    --param trigger_payload "{\"name\":\"Odin\",\"place\":\"Asgard\"}"
+    --param trigger_payload "{\"name\":\"Odin\",\"place\":\"Asgard\"}" \
+    --param startDate "2019-01-01T00:00:00.000Z" \
+    --param stopDate "2019-01-31T23:59:00.000Z"
   ```
 
 Each generated event will include as parameters the properties specified in the `trigger_payload` value. In this case, each trigger event will have parameters `name=Odin` and `place=Asgard`.
 
-**Note**: The parameter `cron` also supports a custom syntax of six fields, where the first field represents seconds.
-For more details about using this custom cron syntax, see: https://github.com/ncb000gt/node-cron.
-Here is an example using six fields notation:
-  - `*/30 * * * * *`: every thirty seconds.
+## Firing a trigger event once  
+
+The `/whisk.system/alarms/once` feed configures the Alarm service to fire a trigger event on a specified date. The parameters are as follows:
 
+- `date`: The date when the trigger will be fired.  The trigger will be fired just once at the given time. 
+
+  **Note**: The `date` parameter supports an integer or string value.  The integer value represents the number of milliseconds 
+  since 1 January 1970 00:00:00 UTC and the string value should be in the ISO 8601 format (http://www.ecma-international.org/ecma-262/5.1/#sec-15.9.1.15).
+
+- `trigger_payload`: The value of this parameter becomes the content of the trigger when the trigger is fired. 
+
+The following is an example of creating a trigger that will be fired once on December 25, 2017, 12:30:00 UTC.
+
+  ```
+  wsk trigger create fireOnce \
+    --feed /whisk.system/alarms/once \
+    --param trigger_payload "{\"name\":\"Odin\",\"place\":\"Asgard\"}" \
+    --param date "2017-12-25T12:30:00.000Z"
+  ``` 
diff --git a/action/alarm.js b/action/alarm.js
index 6e72985..ef624b3 100644
--- a/action/alarm.js
+++ b/action/alarm.js
@@ -3,7 +3,7 @@ const common = require('./lib/common');
 function main(msg) {
 
     let eventMap = {
-        CREATE: 'put',
+        CREATE: 'post',
         READ: 'get',
         // UPDATE: 'put',
         DELETE: 'delete'
diff --git a/action/alarmOnce.js b/action/alarmOnce.js
deleted file mode 100644
index 38a7ebc..0000000
--- a/action/alarmOnce.js
+++ /dev/null
@@ -1,31 +0,0 @@
-const common = require('./lib/common');
-
-function main(msg) {
-
-    let eventMap = {
-        CREATE: 'put',
-        READ: 'get',
-        // UPDATE: 'put',
-        DELETE: 'delete'
-    };
-    // for creation -> CREATE
-    // for reading -> READ
-    // for deletion -> DELETE
-    var lifecycleEvent = msg.lifecycleEvent;
-
-    var endpoint = msg.apihost;
-    var webparams = common.createWebParams(msg);
-    webparams.fireOnce = true;
-
-    var url = `https://${endpoint}/api/v1/web/whisk.system/alarmsWeb/alarmWebAction.http`;
-
-    if (lifecycleEvent in eventMap) {
-        var method = eventMap[lifecycleEvent];
-        return common.requestHelper(url, webparams, method);
-    } else {
-        return Promise.reject('unsupported lifecycleEvent');
-    }
-}
-
-
-exports.main = main;
diff --git a/action/alarmOnce_package.json b/action/alarmOnce_package.json
deleted file mode 100644
index e48cd14..0000000
--- a/action/alarmOnce_package.json
+++ /dev/null
@@ -1,5 +0,0 @@
-{
-  "name": "alarmOnce",
-  "version": "1.0.0",
-  "main": "alarmOnce.js"
-}
diff --git a/action/alarmWebAction.js b/action/alarmWebAction.js
index 4ba3a73..9f8789c 100644
--- a/action/alarmWebAction.js
+++ b/action/alarmWebAction.js
@@ -20,7 +20,7 @@ function main(params) {
     var workers = params.workers instanceof Array ? params.workers : [];
     var db;
 
-    if (params.__ow_method === "put") {
+    if (params.__ow_method === "post") {
 
         if (typeof params.trigger_payload === 'string') {
             params.trigger_payload = {payload: params.trigger_payload};
@@ -42,30 +42,49 @@ function main(params) {
             if (!params.date) {
                 return common.sendError(400, 'alarms once trigger feed is missing the date parameter');
             }
-            else {
-                var date = new Date(params.date);
-                if (isNaN(date.getTime())) {
-                    return common.sendError(400, `date parameter '${params.date}' is not a valid Date`);
-                }
-                else if (Date.now() >= date.getTime()) {
-                    return common.sendError(400, `date parameter '${params.date}' must be in the future`);
-                }
-                else {
-                    newTrigger.date = params.date;
-                }
+            var date = validateDate(params.date, 'date');
+            if (date !== params.date) {
+                return common.sendError(400, date);
             }
+            newTrigger.date = date;
         }
         else {
             if (!params.cron) {
                 return common.sendError(400, 'alarms trigger feed is missing the cron parameter');
             }
-            else {
-                try {
-                    new CronJob(params.cron, function() {});
-                    newTrigger.cron = params.cron;
-                } catch(ex) {
-                    return common.sendError(400, `cron pattern '${params.cron}' is not valid`);
+
+            var cronHandle;
+            try {
+                cronHandle = new CronJob(params.cron, function() {});
+                newTrigger.cron = params.cron;
+            } catch(ex) {
+                return common.sendError(400, `cron pattern '${params.cron}' is not valid`);
+            }
+
+            if (params.startDate) {
+                var startDate = validateDate(params.startDate, 'startDate');
+                if (startDate !== params.startDate) {
+                    return common.sendError(400, startDate);
+                }
+                newTrigger.startDate = startDate;
+            }
+
+            if (params.stopDate) {
+                if (params.maxTriggers) {
+                    return common.sendError(400, 'maxTriggers is not allowed when the stopDate parameter is specified');
+                }
+
+                var stopDate = validateDate(params.stopDate, 'stopDate', params.startDate);
+                if (stopDate !== params.stopDate) {
+                    return common.sendError(400, stopDate);
                 }
+                //verify that the next scheduled trigger fire will occur before the stop date
+                var triggerDate = cronHandle.nextDate();
+                if (triggerDate.isAfter(new Date(params.stopDate))) {
+                    return common.sendError(400, 'the next scheduled trigger fire is not until after the stop date');
+                }
+
+                newTrigger.stopDate = stopDate;
             }
         }
 
@@ -119,6 +138,8 @@ function main(params) {
                 }
                 else {
                     body.config.cron = doc.cron;
+                    body.config.startDate = doc.startDate;
+                    body.config.stopDate = doc.stopDate;
                 }
                 resolve({
                     statusCode: 200,
@@ -159,6 +180,25 @@ function main(params) {
     }
 }
 
+function validateDate(date, paramName, startDate) {
+
+    var dateObject = new Date(date);
+
+    if (isNaN(dateObject.getTime())) {
+        return `${paramName} parameter '${date}' is not a valid Date`;
+    }
+    else if (Date.now() >= dateObject.getTime()) {
+        return `${paramName} parameter '${date}' must be in the future`;
+    }
+    else if (startDate && dateObject <= new Date(startDate).getTime()) {
+        return `${paramName} parameter '${date}' must be greater than the startDate parameter ${startDate}`;
+    }
+    else {
+        return date;
+    }
+
+}
+
 exports.main = main;
 
 
diff --git a/installCatalog.sh b/installCatalog.sh
index 63fde64..3b34e49 100755
--- a/installCatalog.sh
+++ b/installCatalog.sh
@@ -50,9 +50,8 @@ echo Installing Alarms package.
 
 $WSK_CLI -i --apihost "$EDGEHOST" package update --auth "$AUTH" --shared yes alarms \
      -a description 'Alarms and periodic utility' \
-     -a parameters '[ {"name":"cron", "required":true}, {"name":"trigger_payload", "required":false} ]' \
+     -a parameters '[ {"name":"trigger_payload", "required":false} ]' \
      -p apihost "$APIHOST" \
-     -p cron '' \
      -p trigger_payload ''
 
 # make alarmFeed.zip
@@ -68,21 +67,14 @@ zip -r alarmFeed.zip lib package.json alarm.js
 
 $WSK_CLI -i --apihost "$EDGEHOST" action update --kind nodejs:6 --auth "$AUTH" alarms/alarm "$PACKAGE_HOME/action/alarmFeed.zip" \
      -a description 'Fire trigger when alarm occurs' \
+     -a parameters '[ {"name":"cron", "required":true}, {"name":"startDate", "required":false}, {"name":"stopDate", "required":false} ]' \
      -a feed true
 
-
-# make alarmOnce.zip
-if [ -e alarmOnce.zip ]
-then
-    rm -rf alarmOnce.zip
-fi
-
-cp -f alarmOnce_package.json package.json
-zip -r alarmOnce.zip lib package.json alarmOnce.js
-
-$WSK_CLI -i --apihost "$EDGEHOST" action update --kind nodejs:6 --auth "$AUTH" alarms/once "$PACKAGE_HOME/action/alarmOnce.zip" \
+$WSK_CLI -i --apihost "$EDGEHOST" action update --kind nodejs:6 --auth "$AUTH" alarms/once "$PACKAGE_HOME/action/alarmFeed.zip" \
      -a description 'Fire trigger once when alarm occurs' \
-     -a feed true
+     -a parameters '[ {"name":"date", "required":true} ]' \
+     -a feed true \
+     -p fireOnce true
 
 if [ -n "$WORKERS" ];
 then
diff --git a/package.json b/package.json
index 6331109..7b89d74 100755
--- a/package.json
+++ b/package.json
@@ -18,6 +18,7 @@
     "request-promise": "^1.0.2",
     "redis":"^2.7.1",
     "bluebird": "^3.5.0",
-    "systeminformation": "^3.19.0"
+    "systeminformation": "^3.19.0",
+    "long-timeout": "^0.1.1"
   }
 }
\ No newline at end of file
diff --git a/provider/app.js b/provider/app.js
index 3d90fd3..9ba5f98 100755
--- a/provider/app.js
+++ b/provider/app.js
@@ -5,7 +5,6 @@
  */
 var http = require('http');
 var express = require('express');
-var request = require('request');
 var bodyParser = require('body-parser');
 var bluebird = require('bluebird');
 var logger = require('./Logger');
diff --git a/provider/lib/cronAlarm.js b/provider/lib/cronAlarm.js
index efc68c9..98b691b 100644
--- a/provider/lib/cronAlarm.js
+++ b/provider/lib/cronAlarm.js
@@ -1,4 +1,5 @@
 var CronJob = require('cron').CronJob;
+var lt =  require('long-timeout');
 var constants = require('./constants.js');
 
 module.exports = function(logger, newTrigger) {
@@ -9,9 +10,7 @@ module.exports = function(logger, newTrigger) {
         apikey: newTrigger.apikey,
         name: newTrigger.name,
         namespace: newTrigger.namespace,
-        cron: newTrigger.cron,
-        triggersLeft: maxTriggers,
-        maxTriggers: maxTriggers
+        cron: newTrigger.cron
     };
 
     this.scheduleAlarm = function(triggerIdentifier, callback) {
@@ -21,11 +20,42 @@ module.exports = function(logger, newTrigger) {
             return new Promise(function(resolve, reject) {
 
                 var cronHandle = new CronJob(newTrigger.cron, callback);
-                logger.info(method, triggerIdentifier, 'starting cron job');
-                cronHandle.start();
 
-                cachedTrigger.cronHandle = cronHandle;
-                resolve(cachedTrigger);
+                if (newTrigger.stopDate) {
+                    cachedTrigger.stopDate = newTrigger.stopDate;
+                    //do not create trigger if the stopDate is in the past
+                    //or if it will never fire before the stopDate occurs
+                    if (new Date(newTrigger.stopDate).getTime() <= Date.now()) {
+                        return reject('the stop date has expired');
+                    }
+                    else if (cronHandle.nextDate().isAfter(new Date(newTrigger.stopDate))) {
+                        return reject('the next scheduled trigger fire is after the stop date');
+                    }
+                }
+                else {
+                    cachedTrigger.triggersLeft = maxTriggers;
+                    cachedTrigger.maxTriggers = maxTriggers;
+                }
+
+                if (newTrigger.startDate && new Date(newTrigger.startDate).getTime() > Date.now()) {
+                    var startDate = new Date(newTrigger.startDate).getTime();
+                    logger.info(method, triggerIdentifier, 'waiting for start date', startDate);
+                    lt.setTimeout(function() {
+                        logger.info(method, triggerIdentifier, 'starting cron job upon reaching start date', startDate);
+                        cronHandle.start();
+
+                        cachedTrigger.cronHandle = cronHandle;
+                        resolve(cachedTrigger);
+                    }, startDate - Date.now());
+                }
+                else {
+                    logger.info(method, triggerIdentifier, 'starting cron job');
+                    cronHandle.start();
+
+                    cachedTrigger.cronHandle = cronHandle;
+                    resolve(cachedTrigger);
+                }
+
             });
         } catch (err) {
             return Promise.reject(err);
diff --git a/provider/lib/dateAlarm.js b/provider/lib/dateAlarm.js
index 656ac40..04d2ec0 100644
--- a/provider/lib/dateAlarm.js
+++ b/provider/lib/dateAlarm.js
@@ -26,7 +26,7 @@ module.exports = function(logger, newTrigger) {
                     resolve(cachedTrigger);
                 }
                 else {
-                    return reject("the fire once date has expired");
+                    return reject('the fire once date has expired');
                 }
             });
         } catch (err) {
diff --git a/provider/lib/utils.js b/provider/lib/utils.js
index f5ee08f..8c7040b 100644
--- a/provider/lib/utils.js
+++ b/provider/lib/utils.js
@@ -1,4 +1,3 @@
-var _ = require('lodash');
 var request = require('request');
 var HttpStatus = require('http-status-codes');
 var constants = require('./constants.js');
@@ -152,6 +151,13 @@ module.exports = function(
             utils.disableTrigger(triggerIdentifier, undefined, 'Automatically disabled after firing once');
             logger.info(method, 'the fire once date has expired, disabled', triggerIdentifier);
         }
+        else if (dataTrigger.stopDate) {
+            //check if the next scheduled trigger is after the stop date
+            if (dataTrigger.cronHandle && dataTrigger.cronHandle.nextDate().isAfter(new Date(dataTrigger.stopDate))) {
+                utils.disableTrigger(triggerIdentifier, undefined, 'Automatically disabled after firing last scheduled trigger');
+                logger.info(method, 'last scheduled trigger before stop date, disabled', triggerIdentifier);
+            }
+        }
         else if (dataTrigger.maxTriggers && dataTrigger.triggersLeft === 0) {
             utils.disableTrigger(triggerIdentifier, undefined, 'Automatically disabled after reaching max triggers');
             logger.warn(method, 'no more triggers left, disabled', triggerIdentifier);
@@ -240,7 +246,7 @@ module.exports = function(
                         }, function (error, response) {
                             //disable trigger in database if trigger is dead
                             if (!error && utils.shouldDisableTrigger(response.statusCode)) {
-                                var message = 'Automatically disabled after receiving a ' + response.statusCode + ' status code on init trigger';
+                                var message = 'Automatically disabled after receiving a ' + response.statusCode + ' status code on trigger initialization';
                                 utils.disableTrigger(triggerIdentifier, response.statusCode, message);
                                 logger.error(method, 'trigger', triggerIdentifier, 'has been disabled due to status code:', response.statusCode);
                             }
@@ -251,9 +257,9 @@ module.exports = function(
                                     logger.info(method, triggerIdentifier, 'created successfully');
                                 })
                                 .catch(err => {
-                                    var message = 'Automatically disabled after receiving exception on init trigger: ' + err;
+                                    var message = 'Automatically disabled after receiving error on trigger initialization: ' + err;
                                     utils.disableTrigger(triggerIdentifier, undefined, message);
-                                    logger.error(method, 'Disabled trigger', triggerIdentifier, 'due to exception:', err);
+                                    logger.error(method, 'Disabled trigger', triggerIdentifier, err);
                                 });
                             }
                         });
@@ -296,9 +302,9 @@ module.exports = function(
                             logger.info(method, triggerIdentifier, 'created successfully');
                         })
                         .catch(err => {
-                            var message = 'Automatically disabled after receiving exception on create trigger: ' + err;
+                            var message = 'Automatically disabled after receiving error on trigger creation: ' + err;
                             utils.disableTrigger(triggerIdentifier, undefined, message);
-                            logger.error(method, 'Disabled trigger', triggerIdentifier, 'due to exception:', err);
+                            logger.error(method, 'Disabled trigger', triggerIdentifier, err);
                         });
                     }
                 }
diff --git a/tests/src/test/scala/system/health/AlarmsHealthFeedTests.scala b/tests/src/test/scala/system/health/AlarmsHealthFeedTests.scala
index fe70822..fb7c6d8 100644
--- a/tests/src/test/scala/system/health/AlarmsHealthFeedTests.scala
+++ b/tests/src/test/scala/system/health/AlarmsHealthFeedTests.scala
@@ -106,7 +106,7 @@ class AlarmsHealthFeedTests
                 (pkg, name) => pkg.bind("/whisk.system/alarms", name)
             }
 
-            val futureDate = System.currentTimeMillis + (1000 * 30)
+            val futureDate = System.currentTimeMillis + (1000 * 20)
 
             // create whisk stuff
             println(s"Creating trigger: $triggerName")
@@ -119,7 +119,7 @@ class AlarmsHealthFeedTests
             feedCreationResult.stdout should include("ok")
 
             println("waiting for trigger")
-            val activations = wsk.activation.pollFor(N = 1, Some(triggerName), retries = 60).length
+            val activations = wsk.activation.pollFor(N = 1, Some(triggerName), retries = 30).length
             println(s"Found activation size (should be 1): $activations")
             activations should be(1)
     }
@@ -186,4 +186,48 @@ class AlarmsHealthFeedTests
             }
 
     }
+
+    it should "fire cron trigger using startDate and stopDate" in withAssetCleaner(wskprops) {
+        (wp, assetHelper) =>
+            implicit val wskprops = wp // shadow global props and make implicit
+            val triggerName = s"dummyAlarmsTrigger-${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)
+            }
+
+            val startDate = System.currentTimeMillis + (1000 * 20)
+            val stopDate = startDate + (1000 * 10)
+
+            println(s"Creating trigger: $triggerName")
+            // create whisk stuff
+            val feedCreationResult = assetHelper.withCleaner(wsk.trigger, triggerName) {
+                (trigger, name) =>
+                    trigger.create(name, feed = Some(s"$packageName/alarm"), parameters = Map(
+                        "cron" -> "* * * * * *".toJson,
+                        "startDate" -> startDate.toJson,
+                        "stopDate" -> stopDate.toJson))
+            }
+            feedCreationResult.stdout should include("ok")
+
+            println("waiting for triggers")
+            val activations = wsk.activation.pollFor(N = 20, Some(triggerName), retries = 45).length
+            println(s"Found activation size (should be at least 5): $activations")
+            activations should be >= 5
+
+
+            // get activation list again, should be same as before sleeping
+            println("confirming no new triggers")
+            val activationsAfterWait = wsk.activation.pollFor(N = activations + 1, Some(triggerName)).length
+            println(s"Found activation size after wait: $activationsAfterWait")
+            println("Activation list after wait should equal with activation list after stopDate")
+            activationsAfterWait should be(activations)
+    }
 }
diff --git a/tests/src/test/scala/system/packages/AlarmsFeedTests.scala b/tests/src/test/scala/system/packages/AlarmsFeedTests.scala
index 45ec618..2ad09c7 100644
--- a/tests/src/test/scala/system/packages/AlarmsFeedTests.scala
+++ b/tests/src/test/scala/system/packages/AlarmsFeedTests.scala
@@ -224,4 +224,70 @@ class AlarmsFeedTests
             feedCreationResult.stderr should include(s"date parameter '${pastDate}' must be in the future")
 
     }
+
+    it should "return error message when alarms startDate parameter is not a future date" 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)
+            }
+
+            val pastDate = System.currentTimeMillis - 5000
+
+            // create whisk stuff
+            val feedCreationResult = assetHelper.withCleaner(wsk.trigger, triggerName, confirmDelete = false) {
+                (trigger, name) =>
+                    trigger.create(name, feed = Some(s"$packageName/$feed"), parameters = Map(
+                        "startDate" -> pastDate.toJson,
+                        "cron" -> "* * * * *".toJson),
+                        expectedExitCode = 246)
+            }
+            feedCreationResult.stderr should include(s"startDate parameter '${pastDate}' must be in the future")
+
+    }
+
+    it should "return error message when alarms stopDate parameter is not greater than startDate" 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)
+            }
+
+            val stopDate = System.currentTimeMillis + 5000
+            val startDate = stopDate
+
+            // create whisk stuff
+            val feedCreationResult = assetHelper.withCleaner(wsk.trigger, triggerName, confirmDelete = false) {
+                (trigger, name) =>
+                    trigger.create(name, feed = Some(s"$packageName/$feed"), parameters = Map(
+                        "startDate" -> startDate.toJson,
+                        "stopDate" -> stopDate.toJson,
+                        "cron" -> "* * * * *".toJson),
+                        expectedExitCode = 246)
+            }
+            feedCreationResult.stderr should include(s"stopDate parameter '${stopDate}' must be greater than the startDate")
+
+    }
 }


 

----------------------------------------------------------------
This is an automated message from the Apache Git Service.
To respond to the message, please log on GitHub and use the
URL above to go to the specific comment.
 
For queries about this service, please contact Infrastructure at:
users@infra.apache.org


With regards,
Apache Git Services