You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@openwhisk.apache.org by cs...@apache.org on 2017/11/22 22:35:51 UTC
[incubator-openwhisk-package-alarms] branch master updated: Add
interval support (#113)
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 e828151 Add interval support (#113)
e828151 is described below
commit e8281517dd53194335205994061cba8e7fd32828
Author: Jason Peterson <ja...@us.ibm.com>
AuthorDate: Wed Nov 22 17:35:50 2017 -0500
Add interval support (#113)
* add interval support
* add documentation for the interval trigger feed
* add tests for interval trigger feed
---
README.md | 32 +++++++++-
action/alarmWebAction.js | 70 +++++++++++++++-------
action/lib/Database.js | 6 +-
installCatalog.sh | 6 ++
provider/lib/cronAlarm.js | 1 +
provider/lib/dateAlarm.js | 1 +
provider/lib/intervalAlarm.js | 66 ++++++++++++++++++++
provider/lib/utils.js | 51 ++++++++++++----
.../system/health/AlarmsHealthFeedTests.scala | 43 ++++++++++++-
.../scala/system/packages/AlarmsFeedTests.scala | 59 ++++++++++++++++++
.../scala/system/packages/AlarmsFeedWebTests.scala | 8 +--
11 files changed, 301 insertions(+), 42 deletions(-)
diff --git a/README.md b/README.md
index 33f383c..2b0d0d5 100644
--- a/README.md
+++ b/README.md
@@ -12,9 +12,10 @@ The package includes the following feeds.
| `/whisk.system/alarms` | package | - | Alarms and periodic utility |
| `/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 |
+| `/whisk.system/alarms/interval` | feed | minutes, trigger_payload, startDate, stopDate | Fire trigger event on an interval based schedule |
-## Firing a trigger event periodically
+## Firing a trigger event periodically on a time based schedule
The `/whisk.system/alarms/alarm` feed configures the Alarm service to fire a trigger event at a specified frequency. The parameters are as follows:
@@ -57,6 +58,35 @@ January 1, 2019, 00:00:00 UTC and will stop firing January 31, 2019, 23:59:00 UT
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`.
+
+## Firing a trigger event periodically on an interval based schedule
+
+The `/whisk.system/alarms/interval` feed configures the Alarm service to fire a trigger event on an interval based schedule. The parameters are as follows:
+
+- `minutes`: An integer representing the length of the interval (in minutes) between trigger fires.
+
+- `trigger_payload`: The value of this parameter becomes the content of the trigger every time the trigger is fired.
+
+- `startDate`: The date when the first trigger will be fired. Subsequent fires will occur based on the interval length specified by the `minutes` 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 90 minutes. 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 interval \
+ --feed /whisk.system/alarms/interval \
+ --param minutes 90 \
+ --param trigger_payload "{\"name\":\"Odin\",\"place\":\"Asgard\"}" \
+ --param startDate "2019-01-01T00:00:00.000Z" \
+ --param stopDate "2019-01-31T23:59:00.000Z"
+ ```
+
## 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:
diff --git a/action/alarmWebAction.js b/action/alarmWebAction.js
index 9f8789c..7c620c6 100644
--- a/action/alarmWebAction.js
+++ b/action/alarmWebAction.js
@@ -49,16 +49,33 @@ function main(params) {
newTrigger.date = date;
}
else {
- if (!params.cron) {
- return common.sendError(400, 'alarms trigger feed is missing the cron parameter');
+ var cronHandle;
+
+ if (params.isInterval) {
+ if (!params.minutes) {
+ return common.sendError(400, 'interval trigger feed is missing the minutes parameter');
+ }
+ if (+params.minutes !== parseInt(params.minutes)) {
+ return common.sendError(400, 'the minutes parameter must be an integer');
+ }
+ var minutesParam = parseInt(params.minutes);
+
+ if (minutesParam <= 0) {
+ return common.sendError(400, 'the minutes parameter must be an integer greater than zero');
+ }
+ newTrigger.minutes = minutesParam;
}
+ else {
+ if (!params.cron) {
+ return common.sendError(400, 'alarms trigger feed is missing the cron parameter');
+ }
- 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`);
+ 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) {
@@ -68,23 +85,31 @@ function main(params) {
}
newTrigger.startDate = startDate;
}
+ else if (params.isInterval) {
+ //if startDate was not given we will start it 30 seconds
+ //from now since startDate must be in the future
+ newTrigger.startDate = Date.now() + (1000 * 30);
+ }
- if (params.stopDate) {
- if (params.maxTriggers) {
+ if (params.maxTriggers && params.stopDate) {
+ if (params.isInterval) {
+ return common.sendError(400, 'maxTriggers is not supported for the interval trigger feed');
+ }
+ else {
return common.sendError(400, 'maxTriggers is not allowed when the stopDate parameter is specified');
}
-
- var stopDate = validateDate(params.stopDate, 'stopDate', params.startDate);
+ }
+ else if (params.stopDate) {
+ var stopDate = validateDate(params.stopDate, 'stopDate', newTrigger.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;
+
+ //verify that the first scheduled trigger fire will occur before the stop date
+ if (cronHandle && cronHandle.nextDate().isAfter(new Date(params.stopDate))) {
+ return common.sendError(400, 'the first scheduled trigger fire is not until after the stop date');
+ }
}
}
@@ -137,9 +162,14 @@ function main(params) {
body.config.date = doc.date;
}
else {
- body.config.cron = doc.cron;
body.config.startDate = doc.startDate;
body.config.stopDate = doc.stopDate;
+ if (doc.minutes) {
+ body.config.minutes = doc.minutes;
+ }
+ else {
+ body.config.cron = doc.cron;
+ }
}
resolve({
statusCode: 200,
@@ -158,7 +188,7 @@ function main(params) {
common.verifyTriggerAuth(triggerURL, params.authKey, true)
.then(() => {
db = new Database(params.DB_URL, params.DB_NAME);
- return db.updateTrigger(triggerID, 0);
+ return db.disableTrigger(triggerID, 0);
})
.then(id => {
return db.deleteTrigger(id, 0);
diff --git a/action/lib/Database.js b/action/lib/Database.js
index e1fdb27..a878b85 100644
--- a/action/lib/Database.js
+++ b/action/lib/Database.js
@@ -85,7 +85,7 @@ module.exports = function(dbURL, dbName) {
});
};
- this.updateTrigger = function(triggerID, retryCount) {
+ this.disableTrigger = function(triggerID, retryCount) {
return new Promise(function(resolve, reject) {
@@ -98,7 +98,7 @@ module.exports = function(dbURL, dbName) {
if (err) {
if (err.statusCode === 409 && retryCount < 5) {
setTimeout(function () {
- utilsDB.updateTrigger(triggerID, (retryCount + 1))
+ utilsDB.disableTrigger(triggerID, (retryCount + 1))
.then(id => {
resolve(id);
})
@@ -121,7 +121,7 @@ module.exports = function(dbURL, dbName) {
if (retryCount === 0) {
var parts = triggerID.split('/');
var id = parts[0] + '/_/' + parts[2];
- utilsDB.updateTrigger(id, (retryCount + 1))
+ utilsDB.disableTrigger(id, (retryCount + 1))
.then(id => {
resolve(id);
})
diff --git a/installCatalog.sh b/installCatalog.sh
index 3b34e49..ddc9337 100755
--- a/installCatalog.sh
+++ b/installCatalog.sh
@@ -76,6 +76,12 @@ $WSK_CLI -i --apihost "$EDGEHOST" action update --kind nodejs:6 --auth "$AUTH" a
-a feed true \
-p fireOnce true
+$WSK_CLI -i --apihost "$EDGEHOST" action update --kind nodejs:6 --auth "$AUTH" alarms/interval "$PACKAGE_HOME/action/alarmFeed.zip" \
+ -a description 'Fire trigger at specified interval' \
+ -a parameters '[ {"name":"minutes", "required":true}, {"name":"startDate", "required":false}, {"name":"stopDate", "required":false} ]' \
+ -a feed true \
+ -p isInterval true
+
if [ -n "$WORKERS" ];
then
$WSK_CLI -i --apihost "$EDGEHOST" package update --auth "$AUTH" --shared no alarmsWeb \
diff --git a/provider/lib/cronAlarm.js b/provider/lib/cronAlarm.js
index 98b691b..f60ec62 100644
--- a/provider/lib/cronAlarm.js
+++ b/provider/lib/cronAlarm.js
@@ -10,6 +10,7 @@ module.exports = function(logger, newTrigger) {
apikey: newTrigger.apikey,
name: newTrigger.name,
namespace: newTrigger.namespace,
+ payload: newTrigger.payload,
cron: newTrigger.cron
};
diff --git a/provider/lib/dateAlarm.js b/provider/lib/dateAlarm.js
index 04d2ec0..011261d 100644
--- a/provider/lib/dateAlarm.js
+++ b/provider/lib/dateAlarm.js
@@ -6,6 +6,7 @@ module.exports = function(logger, newTrigger) {
apikey: newTrigger.apikey,
name: newTrigger.name,
namespace: newTrigger.namespace,
+ payload: newTrigger.payload,
date: newTrigger.date
};
diff --git a/provider/lib/intervalAlarm.js b/provider/lib/intervalAlarm.js
new file mode 100644
index 0000000..077a68b
--- /dev/null
+++ b/provider/lib/intervalAlarm.js
@@ -0,0 +1,66 @@
+var lt = require('long-timeout');
+
+module.exports = function(logger, newTrigger) {
+
+
+ var cachedTrigger = {
+ apikey: newTrigger.apikey,
+ name: newTrigger.name,
+ namespace: newTrigger.namespace,
+ payload: newTrigger.payload,
+ minutes: newTrigger.minutes
+ };
+
+ this.scheduleAlarm = function(triggerIdentifier, callback) {
+ var method = 'scheduleIntervalAlarm';
+
+ try {
+ return new Promise(function(resolve, reject) {
+
+ var intervalInMilliSeconds = newTrigger.minutes * 1000 * 60;
+ var startDate = new Date(newTrigger.startDate).getTime();
+
+ if (newTrigger.stopDate) {
+ cachedTrigger.stopDate = newTrigger.stopDate;
+ //do not create trigger if the stopDate is in the past
+ if (new Date(newTrigger.stopDate).getTime() <= Date.now()) {
+ return reject('the stop date has expired');
+ }
+ }
+
+ if (startDate > Date.now()) {
+ //fire the trigger and start the interval on the start date
+ logger.info(method, triggerIdentifier, 'waiting for start date', startDate);
+ lt.setTimeout(function() {
+ logger.info(method, triggerIdentifier, 'firing first trigger and starting interval upon reaching start date', startDate);
+ var intervalHandle = lt.setInterval(callback, intervalInMilliSeconds);
+ cachedTrigger.intervalHandle = intervalHandle;
+ resolve(cachedTrigger);
+ }, startDate - Date.now());
+ }
+ else {
+ //fire the trigger and start the interval at the next scheduled interval
+ //as long as the next scheduled interval is not past the stop date
+ var intervalsFired = Math.floor((Date.now() - startDate)/intervalInMilliSeconds);
+ var nextScheduledInterval = startDate + (intervalInMilliSeconds * (intervalsFired + 1));
+
+ if (newTrigger.stopDate && nextScheduledInterval > new Date(newTrigger.stopDate).getTime()) {
+ return reject('the next scheduled trigger fire is after the stop date');
+ }
+
+ logger.info(method, triggerIdentifier, 'waiting for next interval');
+ lt.setTimeout(function() {
+ logger.info(method, triggerIdentifier, 'firing trigger and starting interval for trigger past its start date');
+ var intervalHandle = lt.setInterval(callback, intervalInMilliSeconds);
+ cachedTrigger.intervalHandle = intervalHandle;
+ resolve(cachedTrigger);
+ }, nextScheduledInterval - Date.now());
+ }
+
+ });
+ } catch (err) {
+ return Promise.reject(err);
+ }
+ };
+
+};
diff --git a/provider/lib/utils.js b/provider/lib/utils.js
index 8c7040b..a8f3153 100644
--- a/provider/lib/utils.js
+++ b/provider/lib/utils.js
@@ -1,8 +1,10 @@
var request = require('request');
var HttpStatus = require('http-status-codes');
+var lt = require('long-timeout');
var constants = require('./constants.js');
var DateAlarm = require('./dateAlarm.js');
var CronAlarm = require('./cronAlarm.js');
+var IntervalAlarm = require('./intervalAlarm.js');
module.exports = function(
logger,
@@ -36,7 +38,7 @@ module.exports = function(
var triggerHandle = utils.triggers[triggerIdentifier];
if (triggerHandle && (!triggerHandle.maxTriggers || triggerHandle.maxTriggers === -1 || triggerHandle.triggersLeft > 0)) {
try {
- utils.fireTrigger(newTrigger.namespace, newTrigger.name, newTrigger.payload, newTrigger.apikey);
+ utils.fireTrigger(triggerHandle);
} catch (e) {
logger.error(method, 'Exception occurred while firing trigger', triggerIdentifier, e);
}
@@ -48,6 +50,9 @@ module.exports = function(
if (newTrigger.date) {
alarm = new DateAlarm(logger, newTrigger);
}
+ else if (newTrigger.minutes) {
+ alarm = new IntervalAlarm(logger, newTrigger);
+ }
else {
alarm = new CronAlarm(logger, newTrigger);
}
@@ -55,17 +60,16 @@ module.exports = function(
return alarm.scheduleAlarm(triggerIdentifier, callback);
};
- this.fireTrigger = function(namespace, name, payload, apikey) {
+ this.fireTrigger = function(dataTrigger) {
var method = 'fireTrigger';
- var triggerIdentifier = utils.getTriggerIdentifier(apikey, namespace, name);
+ var triggerIdentifier = utils.getTriggerIdentifier(dataTrigger.apikey, dataTrigger.namespace, dataTrigger.name);
var host = 'https://' + utils.routerHost + ':443';
- var auth = apikey.split(':');
- var dataTrigger = utils.triggers[triggerIdentifier];
- var uri = host + '/api/v1/namespaces/' + namespace + '/triggers/' + name;
+ var auth = dataTrigger.apikey.split(':');
+ var uri = host + '/api/v1/namespaces/' + dataTrigger.namespace + '/triggers/' + dataTrigger.name;
- logger.info(method, 'Cron fired for', triggerIdentifier, 'attempting to fire trigger');
- utils.postTrigger(dataTrigger, payload, uri, auth, 0)
+ logger.info(method, 'Alarm fired for', triggerIdentifier, 'attempting to fire trigger');
+ utils.postTrigger(dataTrigger, uri, auth, 0)
.then(triggerId => {
logger.info(method, 'Trigger', triggerId, 'was successfully fired');
utils.disableExtinctTriggers(triggerIdentifier, dataTrigger);
@@ -76,7 +80,7 @@ module.exports = function(
});
};
- this.postTrigger = function(dataTrigger, payload, uri, auth, retryCount) {
+ this.postTrigger = function(dataTrigger, uri, auth, retryCount) {
var method = 'postTrigger';
return new Promise(function(resolve, reject) {
@@ -93,7 +97,7 @@ module.exports = function(
user: auth[0],
pass: auth[1]
},
- json: payload
+ json: dataTrigger.payload
}, function(error, response) {
try {
var triggerIdentifier = utils.getTriggerIdentifier(dataTrigger.apikey, dataTrigger.namespace, dataTrigger.name);
@@ -115,7 +119,7 @@ module.exports = function(
if (retryCount < retryAttempts) {
logger.info(method, 'attempting to fire trigger again', triggerIdentifier, 'Retry Count:', (retryCount + 1));
setTimeout(function () {
- utils.postTrigger(dataTrigger, payload, uri, auth, (retryCount + 1))
+ utils.postTrigger(dataTrigger, uri, auth, (retryCount + 1))
.then(triggerId => {
resolve(triggerId);
})
@@ -154,8 +158,12 @@ module.exports = function(
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);
+ utils.disableTrigger(triggerIdentifier, undefined, 'Automatically disabled after firing last scheduled cron trigger');
+ logger.info(method, 'last scheduled cron trigger before stop date, disabled', triggerIdentifier);
+ }
+ else if (dataTrigger.minutes && (Date.now() + (dataTrigger.minutes * 1000 * 60) > new Date(dataTrigger.stopDate).getTime())) {
+ utils.disableTrigger(triggerIdentifier, undefined, 'Automatically disabled after firing last scheduled interval trigger');
+ logger.info(method, 'last scheduled interval trigger before stop date, disabled', triggerIdentifier);
}
}
else if (dataTrigger.maxTriggers && dataTrigger.triggersLeft === 0) {
@@ -204,6 +212,9 @@ module.exports = function(
if (utils.triggers[triggerIdentifier].cronHandle) {
utils.triggers[triggerIdentifier].cronHandle.stop();
}
+ else if (utils.triggers[triggerIdentifier].intervalHandle) {
+ lt.clearInterval(utils.triggers[triggerIdentifier].intervalHandle);
+ }
delete utils.triggers[triggerIdentifier];
logger.info(method, 'trigger', triggerIdentifier, 'successfully deleted from memory');
}
@@ -255,6 +266,13 @@ module.exports = function(
.then(cachedTrigger => {
utils.triggers[triggerIdentifier] = cachedTrigger;
logger.info(method, triggerIdentifier, 'created successfully');
+ if (cachedTrigger.intervalHandle && utils.activeHost === utils.host) {
+ try {
+ utils.fireTrigger(cachedTrigger);
+ } catch (e) {
+ logger.error(method, 'Exception occurred while firing trigger', triggerIdentifier, e);
+ }
+ }
})
.catch(err => {
var message = 'Automatically disabled after receiving error on trigger initialization: ' + err;
@@ -300,6 +318,13 @@ module.exports = function(
.then(cachedTrigger => {
utils.triggers[triggerIdentifier] = cachedTrigger;
logger.info(method, triggerIdentifier, 'created successfully');
+ if (cachedTrigger.intervalHandle && utils.activeHost === utils.host) {
+ try {
+ utils.fireTrigger(cachedTrigger);
+ } catch (e) {
+ logger.error(method, 'Exception occurred while firing trigger', triggerIdentifier, e);
+ }
+ }
})
.catch(err => {
var message = 'Automatically disabled after receiving error on trigger creation: ' + err;
diff --git a/tests/src/test/scala/system/health/AlarmsHealthFeedTests.scala b/tests/src/test/scala/system/health/AlarmsHealthFeedTests.scala
index fb7c6d8..da901e8 100644
--- a/tests/src/test/scala/system/health/AlarmsHealthFeedTests.scala
+++ b/tests/src/test/scala/system/health/AlarmsHealthFeedTests.scala
@@ -22,7 +22,7 @@ import common.{TestHelpers, Wsk, WskProps, WskTestHelpers}
import org.junit.runner.RunWith
import org.scalatest.{FlatSpec, Inside}
import org.scalatest.junit.JUnitRunner
-import spray.json.DefaultJsonProtocol.{LongJsonFormat, StringJsonFormat, BooleanJsonFormat}
+import spray.json.DefaultJsonProtocol.{IntJsonFormat, LongJsonFormat, StringJsonFormat, BooleanJsonFormat}
import spray.json.{JsObject, JsString, pimpAny}
/**
@@ -230,4 +230,45 @@ class AlarmsHealthFeedTests
println("Activation list after wait should equal with activation list after stopDate")
activationsAfterWait should be(activations)
}
+
+ it should "fire interval 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 * 90)
+
+ println(s"Creating trigger: $triggerName")
+ // create whisk stuff
+ val feedCreationResult = assetHelper.withCleaner(wsk.trigger, triggerName) {
+ (trigger, name) =>
+ trigger.create(name, feed = Some(s"$packageName/interval"), parameters = Map(
+ "minutes" -> 1.toJson,
+ "startDate" -> startDate.toJson,
+ "stopDate" -> stopDate.toJson))
+ }
+ feedCreationResult.stdout should include("ok")
+
+ println("waiting for start date")
+ val activations = wsk.activation.pollFor(N = 1, Some(triggerName), retries = 45).length
+ println(s"Found activation size (should be 1): $activations")
+ activations should be(1)
+
+ println("waiting for interval")
+ val activationsAfterInterval = wsk.activation.pollFor(N = 2, Some(triggerName), retries = 90).length
+ println(s"Found activation size (should be 2): $activationsAfterInterval")
+ activationsAfterInterval should be(2)
+ }
}
diff --git a/tests/src/test/scala/system/packages/AlarmsFeedTests.scala b/tests/src/test/scala/system/packages/AlarmsFeedTests.scala
index 2ad09c7..876b070 100644
--- a/tests/src/test/scala/system/packages/AlarmsFeedTests.scala
+++ b/tests/src/test/scala/system/packages/AlarmsFeedTests.scala
@@ -290,4 +290,63 @@ class AlarmsFeedTests
feedCreationResult.stderr should include(s"stopDate parameter '${stopDate}' must be greater than the startDate")
}
+
+ it should "return error message when interval action does not include minutes parameter" 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 = "interval"
+
+ // 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 whisk stuff
+ val feedCreationResult = assetHelper.withCleaner(wsk.trigger, triggerName, confirmDelete = false) {
+ (trigger, name) =>
+ trigger.create(name, feed = Some(s"$packageName/$feed"), parameters = Map(
+ "trigger_payload" -> "alarmTest".toJson),
+ expectedExitCode = 246)
+ }
+ feedCreationResult.stderr should include("interval trigger feed is missing the minutes parameter")
+
+ }
+
+ it should "return error message when interval action includes invalid minutes parameter" 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 = "interval"
+
+ // 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 whisk stuff
+ val feedCreationResult = assetHelper.withCleaner(wsk.trigger, triggerName, confirmDelete = false) {
+ (trigger, name) =>
+ trigger.create(name, feed = Some(s"$packageName/$feed"), parameters = Map(
+ "trigger_payload" -> "alarmTest".toJson,
+ "minutes" -> "five".toJson),
+ expectedExitCode = 246)
+ }
+ feedCreationResult.stderr should include("the minutes parameter must be an integer")
+
+ }
}
diff --git a/tests/src/test/scala/system/packages/AlarmsFeedWebTests.scala b/tests/src/test/scala/system/packages/AlarmsFeedWebTests.scala
index a1f3060..cb8d41f 100644
--- a/tests/src/test/scala/system/packages/AlarmsFeedWebTests.scala
+++ b/tests/src/test/scala/system/packages/AlarmsFeedWebTests.scala
@@ -51,25 +51,25 @@ class AlarmsFeedWebTests
wsk.action.get(webAction, FORBIDDEN)
}
- it should "reject put of a trigger due to missing triggerName argument" in {
+ it should "reject post of a trigger due to missing triggerName argument" in {
val params = JsObject(originalParams.fields - "triggerName")
makePostCallWithExpectedResult(params, JsObject("error" -> JsString("no trigger name parameter was provided")), 400)
}
- it should "reject put of a trigger due to missing cron argument" in {
+ it should "reject post of a trigger due to missing cron argument" in {
val params = JsObject(originalParams.fields - "cron")
makePostCallWithExpectedResult(params, JsObject("error" -> JsString("alarms trigger feed is missing the cron parameter")), 400)
}
- it should "reject put of a trigger due to invalid cron argument" in {
+ it should "reject post of a trigger due to invalid cron argument" in {
val params = JsObject(originalParams.fields + ("cron" -> JsString("***")))
makePostCallWithExpectedResult(params, JsObject("error" -> JsString("cron pattern '***' is not valid")), 400)
}
- it should "reject put of a trigger when authentication fails" in {
+ it should "reject post of a trigger when authentication fails" in {
val params = JsObject(originalParams.fields + ("cron" -> JsString("* * * * *")))
makePostCallWithExpectedResult(params, JsObject("error" -> JsString("Trigger authentication request failed.")), 401)
}
--
To stop receiving notification emails like this one, please contact
['"commits@openwhisk.apache.org" <co...@openwhisk.apache.org>'].