csantanapr closed pull request #119: Add update lifecycle support
URL: https://github.com/apache/incubator-openwhisk-package-alarms/pull/119
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/action/alarm.js b/action/alarm.js
index ef624b3..9467ece 100644
--- a/action/alarm.js
+++ b/action/alarm.js
@@ -5,11 +5,12 @@ function main(msg) {
let eventMap = {
CREATE: 'post',
READ: 'get',
- // UPDATE: 'put',
+ UPDATE: 'put',
DELETE: 'delete'
};
// for creation -> CREATE
// for reading -> READ
+ // for updating -> UPDATE
// for deletion -> DELETE
var lifecycleEvent = msg.lifecycleEvent;
diff --git a/action/alarmWebAction.js b/action/alarmWebAction.js
index 7c620c6..d56a159 100644
--- a/action/alarmWebAction.js
+++ b/action/alarmWebAction.js
@@ -182,16 +182,119 @@ function main(params) {
});
});
}
+ else if (params.__ow_method === "put") {
+
+ return new Promise(function (resolve, reject) {
+ var updatedParams = {};
+
+ common.verifyTriggerAuth(triggerURL, params.authKey, false)
+ .then(() => {
+ db = new Database(params.DB_URL, params.DB_NAME);
+ return db.getTrigger(triggerID);
+ })
+ .then(trigger => {
+ if (trigger.status && trigger.status.reason &&
trigger.status.reason.kind === 'ADMIN') {
+ return reject(common.sendError(400, `${params.triggerName}
cannot be updated because it was disabled by an admin. Please contact support
for further assistance`));
+ }
+
+ if (params.trigger_payload) {
+ updatedParams.payload =
constructPayload(params.trigger_payload);
+ }
+
+ if (trigger.date) {
+ if (params.date) {
+ var date = validateDate(params.date, 'date');
+ if (date !== params.date) {
+ return reject(common.sendError(400, date));
+ }
+ updatedParams.date = date;
+ }
+ }
+ else {
+ if (trigger.minutes) {
+ if (params.minutes) {
+ if (+params.minutes !== parseInt(params.minutes)) {
+ return reject(common.sendError(400, 'the
minutes parameter must be an integer'));
+ }
+ var minutesParam = parseInt(params.minutes);
+
+ if (minutesParam <= 0) {
+ return reject(common.sendError(400, 'the
minutes parameter must be an integer greater than zero'));
+ }
+ updatedParams.minutes = minutesParam;
+ }
+ }
+ else {
+ if (params.cron) {
+ try {
+ new CronJob(params.cron, function() {});
+ } catch (ex) {
+ return reject(common.sendError(400, `cron
pattern '${params.cron}' is not valid`));
+ }
+ updatedParams.cron = params.cron;
+ }
+ }
+
+ if (params.startDate) {
+ var startDate = validateDate(params.startDate,
'startDate');
+ if (startDate !== params.startDate) {
+ return reject(common.sendError(400, startDate));
+ }
+ updatedParams.startDate = startDate;
+ }
+
+ if (params.stopDate) {
+ var stopDate = validateDate(params.stopDate,
'stopDate', params.startDate || trigger.startDate);
+ if (stopDate !== params.stopDate) {
+ return reject(common.sendError(400, stopDate));
+ }
+ updatedParams.stopDate = stopDate;
+ }
+ else if (params.startDate && trigger.stopDate) {
+ //need to verify that new start date is before
existing stop date
+ if (new Date(params.startDate).getTime() >= new
Date(trigger.stopDate).getTime()) {
+ return reject(common.sendError(400, `startDate
parameter '${params.startDate}' must be less than the stopDate parameter
'${trigger.stopDate}'`));
+ }
+
+ }
+ }
+
+ if (Object.keys(updatedParams).length === 0) {
+ return reject(common.sendError(400, 'no updatable
parameters were specified'));
+ }
+ return db.disableTrigger(trigger._id, trigger, 0, 'updating');
+ })
+ .then(triggerID => {
+ return db.getTrigger(triggerID, false);
+ })
+ .then(trigger => {
+ return db.updateTrigger(trigger._id, trigger, updatedParams,
0);
+ })
+ .then(() => {
+ resolve({
+ statusCode: 200,
+ headers: {'Content-Type': 'application/json'},
+ body: new Buffer(JSON.stringify({'status':
'success'})).toString('base64')
+ });
+ })
+ .catch(err => {
+ reject(err);
+ });
+ });
+ }
else if (params.__ow_method === "delete") {
return new Promise(function (resolve, reject) {
common.verifyTriggerAuth(triggerURL, params.authKey, true)
.then(() => {
db = new Database(params.DB_URL, params.DB_NAME);
- return db.disableTrigger(triggerID, 0);
+ return db.getTrigger(triggerID);
+ })
+ .then(trigger => {
+ return db.disableTrigger(trigger._id, trigger, 0, 'deleting');
})
- .then(id => {
- return db.deleteTrigger(id, 0);
+ .then(triggerID => {
+ return db.deleteTrigger(triggerID, 0);
})
.then(() => {
resolve({
@@ -210,6 +313,20 @@ 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);
@@ -221,7 +338,7 @@ function validateDate(date, paramName, startDate) {
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}`;
+ return `${paramName} parameter '${date}' must be greater than the
startDate parameter '${startDate}'`;
}
else {
return date;
diff --git a/action/lib/Database.js b/action/lib/Database.js
index a878b85..fcf062b 100644
--- a/action/lib/Database.js
+++ b/action/lib/Database.js
@@ -85,56 +85,48 @@ module.exports = function(dbURL, dbName) {
});
};
- this.disableTrigger = function(triggerID, retryCount) {
+ this.disableTrigger = function(triggerID, trigger, retryCount,
crudMessage) {
- return new Promise(function(resolve, reject) {
+ if (retryCount === 0) {
+ //check if it is already disabled
+ if (trigger.status && trigger.status.active === false) {
+ return Promise.resolve(triggerID);
+ }
- utilsDB.db.get(triggerID, function (err, existing) {
- if (!err) {
- var updatedTrigger = existing;
- updatedTrigger.status = {'active': false};
+ var message = `Automatically disabled trigger while
${crudMessage}`;
+ var status = {
+ 'active': false,
+ 'dateChanged': Date.now(),
+ 'reason': {'kind': 'AUTO', 'statusCode': undefined, 'message':
message}
+ };
+ trigger.status = status;
+ }
- utilsDB.db.insert(updatedTrigger, triggerID, function
(err) {
- if (err) {
- if (err.statusCode === 409 && retryCount < 5) {
- setTimeout(function () {
- utilsDB.disableTrigger(triggerID,
(retryCount + 1))
- .then(id => {
- resolve(id);
- })
- .catch(err => {
- reject(err);
- });
- }, 1000);
- }
- else {
- reject(common.sendError(err.statusCode, 'there
was an error while marking the trigger for delete in the database.',
err.message));
- }
- }
- else {
- resolve(triggerID);
- }
- });
- }
- else {
- //legacy alarms triggers may have been created with _
namespace
- if (retryCount === 0) {
- var parts = triggerID.split('/');
- var id = parts[0] + '/_/' + parts[2];
- utilsDB.disableTrigger(id, (retryCount + 1))
- .then(id => {
- resolve(id);
- })
- .catch(err => {
- reject(err);
- });
+ return new Promise(function(resolve, reject) {
+
+ utilsDB.db.insert(trigger, triggerID, function (err) {
+ if (err) {
+ if (err.statusCode === 409 && retryCount < 5) {
+ setTimeout(function () {
+ utilsDB.disableTrigger(triggerID, trigger,
(retryCount + 1))
+ .then(id => {
+ resolve(id);
+ })
+ .catch(err => {
+ reject(err);
+ });
+ }, 1000);
}
else {
- reject(common.sendError(err.statusCode, 'could not
find the trigger in the database'));
+ reject(common.sendError(err.statusCode, 'there was an
error while disabling the trigger in the database.', err.message));
}
}
+ else {
+ resolve(triggerID);
+ }
});
});
+
};
this.deleteTrigger = function(triggerID, retryCount) {
@@ -169,4 +161,43 @@ module.exports = function(dbURL, dbName) {
});
});
};
+
+ this.updateTrigger = function(triggerID, trigger, params, retryCount) {
+
+ if (retryCount === 0) {
+ for (var key in params) {
+ trigger[key] = params[key];
+ }
+ var status = {
+ 'active': true,
+ 'dateChanged': Date.now()
+ };
+ trigger.status = status;
+ }
+
+ return new Promise(function(resolve, reject) {
+ utilsDB.db.insert(trigger, triggerID, function (err) {
+ if (err) {
+ if (err.statusCode === 409 && retryCount < 5) {
+ setTimeout(function () {
+ utilsDB.updateTrigger(triggerID, trigger, params,
(retryCount + 1))
+ .then(id => {
+ resolve(id);
+ })
+ .catch(err => {
+ reject(err);
+ });
+ }, 1000);
+ }
+ else {
+ reject(common.sendError(err.statusCode, 'there was an
error while updating the trigger in the database.', err.message));
+ }
+ }
+ else {
+ resolve(triggerID);
+ }
+ });
+ });
+ };
+
};
diff --git a/tests/src/test/scala/system/health/AlarmsHealthFeedTests.scala
b/tests/src/test/scala/system/health/AlarmsHealthFeedTests.scala
index 0e72e69..cbee2c5 100644
--- a/tests/src/test/scala/system/health/AlarmsHealthFeedTests.scala
+++ b/tests/src/test/scala/system/health/AlarmsHealthFeedTests.scala
@@ -40,7 +40,6 @@ class AlarmsHealthFeedTests
val defaultAction = Some(TestUtils.getTestActionFilename("hello.js"))
- val defaultActionName = "hello"
behavior of "Alarms Health tests"
@@ -49,6 +48,7 @@ class AlarmsHealthFeedTests
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
@@ -61,21 +61,23 @@ class AlarmsHealthFeedTests
(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")
- // create whisk stuff
- val feedCreationResult = assetHelper.withCleaner(wsk.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))
}
- feedCreationResult.stdout should include("ok")
- assetHelper.withCleaner(wsk.action, defaultActionName) { (action,
name) =>
- action.create(name, defaultAction)
- }
+ // create rule
assetHelper.withCleaner(wsk.rule, ruleName) { (rule, name) =>
- rule.create(name, trigger = triggerName, action =
defaultActionName)
+ rule.create(name, trigger = triggerName, action = actionName)
}
println("waiting for triggers")
@@ -107,6 +109,7 @@ class AlarmsHealthFeedTests
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
@@ -119,29 +122,138 @@ class AlarmsHealthFeedTests
(pkg, name) => pkg.bind("/whisk.system/alarms", name)
}
+ //create action
+ assetHelper.withCleaner(wsk.action, actionName) { (action, name) =>
+ action.create(name, defaultAction)
+ }
+
val futureDate = System.currentTimeMillis + (1000 * 20)
- // create whisk stuff
+ // create trigger feed
println(s"Creating trigger: $triggerName")
- val feedCreationResult = assetHelper.withCleaner(wsk.trigger,
triggerName) {
+ assetHelper.withCleaner(wsk.trigger, triggerName) {
(trigger, name) =>
trigger.create(name, feed = Some(s"$packageName/once"),
parameters = Map(
"trigger_payload" -> "alarmTest".toJson,
"date" -> futureDate.toJson))
}
- feedCreationResult.stdout should include("ok")
- assetHelper.withCleaner(wsk.action, defaultActionName) { (action,
name) =>
+ // create rule
+ assetHelper.withCleaner(wsk.rule, ruleName) { (rule, name) =>
+ rule.create(name, trigger = triggerName, action = actionName)
+ }
+
+ println("waiting for trigger")
+ 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)
+ }
+
+ 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 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)
}
+
+ val startDate = System.currentTimeMillis + (1000 * 20)
+ val stopDate = startDate + (1000 * 10)
+
+ // 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,
+ "startDate" -> startDate.toJson,
+ "stopDate" -> stopDate.toJson))
+ }
+
+ // create rule
assetHelper.withCleaner(wsk.rule, ruleName) { (rule, name) =>
- rule.create(name, trigger = triggerName, action =
defaultActionName)
+ rule.create(name, trigger = triggerName, action = actionName)
}
- println("waiting for trigger")
+ 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
+
+
+ // get activation list again, should be same as before waiting
+ 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)
+ }
+
+ 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 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)
+ }
+
+ val startDate = System.currentTimeMillis + (1000 * 20)
+ val stopDate = startDate + (1000 * 90)
+
+ // create trigger feed
+ println(s"Creating trigger: $triggerName")
+ 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))
+ }
+
+ // create rule
+ assetHelper.withCleaner(wsk.rule, ruleName) { (rule, name) =>
+ rule.create(name, trigger = triggerName, action = actionName)
+ }
+
+ println("waiting for start date")
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)
+
+ 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)
}
it should "return correct status and configuration" in
withAssetCleaner(wskprops) {
@@ -168,7 +280,7 @@ class AlarmsHealthFeedTests
val cronString = "* * * * * *"
val maxTriggers = -1
- // create whisk stuff
+ // create trigger feed
val feedCreationResult = assetHelper.withCleaner(wsk.trigger,
triggerName) {
(trigger, name) =>
trigger.create(name, feed = Some(s"$packageName/alarm"),
parameters = Map(
@@ -207,11 +319,10 @@ class AlarmsHealthFeedTests
}
- it should "fire cron trigger using startDate and stopDate" in
withAssetCleaner(wskprops) {
+ it should "update cron, startDate and stopDate parameters" in
withAssetCleaner(wskprops) {
(wp, assetHelper) =>
- implicit val wskprops = wp // shadow global props and make implicit
+ implicit val wskProps = wp
val triggerName = s"dummyAlarmsTrigger-${System.currentTimeMillis}"
- val ruleName = s"dummyAlarmsRule-${System.currentTimeMillis}"
val packageName = "dummyAlarmsPackage"
// the package alarms should be there
@@ -224,46 +335,85 @@ class AlarmsHealthFeedTests
(pkg, name) => pkg.bind("/whisk.system/alarms", name)
}
+ val cron = "* * * * * *"
val startDate = System.currentTimeMillis + (1000 * 20)
val stopDate = startDate + (1000 * 10)
+ // create trigger feed
println(s"Creating trigger: $triggerName")
- // create whisk stuff
- val feedCreationResult = assetHelper.withCleaner(wsk.trigger,
triggerName) {
+ assetHelper.withCleaner(wsk.trigger, triggerName) {
(trigger, name) =>
trigger.create(name, feed = Some(s"$packageName/alarm"),
parameters = Map(
- "cron" -> "* * * * * *".toJson,
+ "cron" -> cron.toJson,
"startDate" -> startDate.toJson,
"stopDate" -> stopDate.toJson))
}
- feedCreationResult.stdout should include("ok")
- assetHelper.withCleaner(wsk.action, defaultActionName) { (action,
name) =>
- action.create(name, defaultAction)
+
+ val actionName = s"$packageName/alarm"
+ val readRunResult = wsk.action.invoke(actionName, parameters = Map(
+ "triggerName" -> triggerName.toJson,
+ "lifecycleEvent" -> "READ".toJson,
+ "authKey" -> wskProps.authKey.toJson
+ ))
+
+ withActivation(wsk.activation, readRunResult) {
+ activation =>
+ activation.response.success shouldBe true
+
+ inside(activation.response.result) {
+ case Some(result) =>
+ val config =
result.getFields("config").head.asInstanceOf[JsObject].fields
+
+ config should contain("cron" -> cron.toJson)
+ config should contain("startDate" ->
startDate.toJson)
+ config should contain("stopDate" ->
stopDate.toJson)
+ }
}
- assetHelper.withCleaner(wsk.rule, ruleName) { (rule, name) =>
- rule.create(name, trigger = triggerName, action =
defaultActionName)
+
+ val updatedCron = "*/2 * * * * *"
+ val updatedStartDate = System.currentTimeMillis + (1000 * 20)
+ val updatedStopDate = updatedStartDate + (1000 * 10)
+
+ val updateRunAction = wsk.action.invoke(actionName, parameters =
Map(
+ "triggerName" -> triggerName.toJson,
+ "lifecycleEvent" -> "UPDATE".toJson,
+ "authKey" -> wskProps.authKey.toJson,
+ "cron" -> updatedCron.toJson,
+ "startDate" -> updatedStartDate.toJson,
+ "stopDate" -> updatedStopDate.toJson
+ ))
+
+ withActivation(wsk.activation, updateRunAction) {
+ activation =>
+ activation.response.success shouldBe true
}
- 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 runResult = wsk.action.invoke(actionName, parameters = Map(
+ "triggerName" -> triggerName.toJson,
+ "lifecycleEvent" -> "READ".toJson,
+ "authKey" -> wskProps.authKey.toJson
+ ))
+ withActivation(wsk.activation, runResult) {
+ activation =>
+ activation.response.success shouldBe true
- // get activation list again, should be same as before waiting
- 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)
+ inside(activation.response.result) {
+ case Some(result) =>
+ val config =
result.getFields("config").head.asInstanceOf[JsObject].fields
+
+ config should contain("cron" -> updatedCron.toJson)
+ config should contain("startDate" ->
updatedStartDate.toJson)
+ config should contain("stopDate" ->
updatedStopDate.toJson)
+ }
+ }
}
- it should "fire interval trigger using startDate and stopDate" in
withAssetCleaner(wskprops) {
+ it should "update fireOnce and payload parameters" in
withAssetCleaner(wskprops) {
(wp, assetHelper) =>
- implicit val wskprops = wp // shadow global props and make implicit
+ implicit val wskProps = wp
val triggerName = s"dummyAlarmsTrigger-${System.currentTimeMillis}"
- val ruleName = s"dummyAlarmsRule-${System.currentTimeMillis}"
val packageName = "dummyAlarmsPackage"
// the package alarms should be there
@@ -276,35 +426,166 @@ class AlarmsHealthFeedTests
(pkg, name) => pkg.bind("/whisk.system/alarms", name)
}
+ val futureDate = System.currentTimeMillis + (1000 * 20)
+ val payload = JsObject(
+ "test" -> JsString("alarmsTest")
+ )
+
+ // create trigger feed
+ println(s"Creating trigger: $triggerName")
+ assetHelper.withCleaner(wsk.trigger, triggerName) {
+ (trigger, name) =>
+ trigger.create(name, feed = Some(s"$packageName/once"),
parameters = Map(
+ "trigger_payload" -> payload,
+ "date" -> futureDate.toJson))
+ }
+
+ val actionName = s"$packageName/alarm"
+ val readRunResult = wsk.action.invoke(actionName, parameters = Map(
+ "triggerName" -> triggerName.toJson,
+ "lifecycleEvent" -> "READ".toJson,
+ "authKey" -> wskProps.authKey.toJson
+ ))
+
+ withActivation(wsk.activation, readRunResult) {
+ activation =>
+ activation.response.success shouldBe true
+
+ inside(activation.response.result) {
+ case Some(result) =>
+ val config =
result.getFields("config").head.asInstanceOf[JsObject].fields
+
+ config should contain("date" -> futureDate.toJson)
+ config should contain("payload" -> payload)
+ }
+ }
+
+ val updatedFutureDate = System.currentTimeMillis + (1000 * 20)
+ val updatedPayload = JsObject(
+ "update_test" -> JsString("alarmsTest")
+ )
+
+ val updateRunAction = wsk.action.invoke(actionName, parameters =
Map(
+ "triggerName" -> triggerName.toJson,
+ "lifecycleEvent" -> "UPDATE".toJson,
+ "authKey" -> wskProps.authKey.toJson,
+ "trigger_payload" ->updatedPayload,
+ "date" -> updatedFutureDate.toJson
+ ))
+
+ withActivation(wsk.activation, updateRunAction) {
+ activation =>
+ activation.response.success shouldBe true
+ }
+
+ val runResult = wsk.action.invoke(actionName, parameters = Map(
+ "triggerName" -> triggerName.toJson,
+ "lifecycleEvent" -> "READ".toJson,
+ "authKey" -> wskProps.authKey.toJson
+ ))
+
+ withActivation(wsk.activation, runResult) {
+ activation =>
+ activation.response.success shouldBe true
+
+ inside(activation.response.result) {
+ case Some(result) =>
+ val config =
result.getFields("config").head.asInstanceOf[JsObject].fields
+
+ config should contain("date" ->
updatedFutureDate.toJson)
+ config should contain("payload" -> updatedPayload)
+ }
+ }
+ }
+
+ it should "update minutes parameter for interval feed" in
withAssetCleaner(wskprops) {
+ (wp, assetHelper) =>
+ implicit val wskProps = wp
+ 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 minutes = 1
val startDate = System.currentTimeMillis + (1000 * 20)
val stopDate = startDate + (1000 * 90)
+ // create trigger feed
println(s"Creating trigger: $triggerName")
- // create whisk stuff
- val feedCreationResult = assetHelper.withCleaner(wsk.trigger,
triggerName) {
+ assetHelper.withCleaner(wsk.trigger, triggerName) {
(trigger, name) =>
trigger.create(name, feed =
Some(s"$packageName/interval"), parameters = Map(
- "minutes" -> 1.toJson,
+ "minutes" -> minutes.toJson,
"startDate" -> startDate.toJson,
"stopDate" -> stopDate.toJson))
}
- feedCreationResult.stdout should include("ok")
- assetHelper.withCleaner(wsk.action, defaultActionName) { (action,
name) =>
- action.create(name, defaultAction)
+
+ val actionName = s"$packageName/alarm"
+ val readRunResult = wsk.action.invoke(actionName, parameters = Map(
+ "triggerName" -> triggerName.toJson,
+ "lifecycleEvent" -> "READ".toJson,
+ "authKey" -> wskProps.authKey.toJson
+ ))
+
+ withActivation(wsk.activation, readRunResult) {
+ activation =>
+ activation.response.success shouldBe true
+
+ inside(activation.response.result) {
+ case Some(result) =>
+ val config =
result.getFields("config").head.asInstanceOf[JsObject].fields
+
+ config should contain("minutes" -> minutes.toJson)
+ config should contain("startDate" ->
startDate.toJson)
+ config should contain("stopDate" ->
stopDate.toJson)
+ }
}
- assetHelper.withCleaner(wsk.rule, ruleName) { (rule, name) =>
- rule.create(name, trigger = triggerName, action =
defaultActionName)
+
+ val updatedMinutes = 2
+ val updatedStartDate = System.currentTimeMillis + (1000 * 20)
+ val updatedStopDate = updatedStartDate + (1000 * 10)
+
+ val updateRunAction = wsk.action.invoke(actionName, parameters =
Map(
+ "triggerName" -> triggerName.toJson,
+ "lifecycleEvent" -> "UPDATE".toJson,
+ "authKey" -> wskProps.authKey.toJson,
+ "minutes" -> updatedMinutes.toJson,
+ "startDate" -> updatedStartDate.toJson,
+ "stopDate" -> updatedStopDate.toJson
+ ))
+
+ withActivation(wsk.activation, updateRunAction) {
+ activation =>
+ activation.response.success shouldBe true
}
- println("waiting for start date")
- 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)
+ val runResult = wsk.action.invoke(actionName, parameters = Map(
+ "triggerName" -> triggerName.toJson,
+ "lifecycleEvent" -> "READ".toJson,
+ "authKey" -> wskProps.authKey.toJson
+ ))
- 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)
+ withActivation(wsk.activation, runResult) {
+ activation =>
+ activation.response.success shouldBe true
+
+ inside(activation.response.result) {
+ case Some(result) =>
+ val config =
result.getFields("config").head.asInstanceOf[JsObject].fields
+
+ config should contain("minutes" ->
updatedMinutes.toJson)
+ config should contain("startDate" ->
updatedStartDate.toJson)
+ config should contain("stopDate" ->
updatedStopDate.toJson)
+ }
+ }
}
}
diff --git a/tests/src/test/scala/system/packages/AlarmsFeedTests.scala
b/tests/src/test/scala/system/packages/AlarmsFeedTests.scala
index aa2e29d..bd0aa31 100644
--- a/tests/src/test/scala/system/packages/AlarmsFeedTests.scala
+++ b/tests/src/test/scala/system/packages/AlarmsFeedTests.scala
@@ -17,12 +17,12 @@
package system.packages
import org.junit.runner.RunWith
-import org.scalatest.FlatSpec
+import org.scalatest.{FlatSpec, Inside}
import org.scalatest.junit.JUnitRunner
import common._
import spray.json.DefaultJsonProtocol.IntJsonFormat
import spray.json.DefaultJsonProtocol.{LongJsonFormat, StringJsonFormat}
-import spray.json.pimpAny
+import spray.json.{JsObject, JsString, pimpAny}
/**
* Tests for alarms trigger service
@@ -37,7 +37,6 @@ class AlarmsFeedTests
val wsk = new Wsk
val defaultAction = Some(TestUtils.getTestActionFilename("hello.js"))
- val defaultActionName = "hello"
behavior of "Alarms trigger service"
@@ -46,6 +45,7 @@ class AlarmsFeedTests
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
@@ -58,21 +58,23 @@ class AlarmsFeedTests
(pkg, name) => pkg.bind("/whisk.system/alarms", name)
}
- // create whisk stuff
- val feedCreationResult = assetHelper.withCleaner(wsk.trigger,
triggerName) {
+ // create action
+ assetHelper.withCleaner(wsk.action, actionName) { (action, name) =>
+ action.create(name, defaultAction)
+ }
+
+ // create trigger with feed
+ assetHelper.withCleaner(wsk.trigger, triggerName) {
(trigger, name) =>
trigger.create(name, feed = Some(s"$packageName/alarm"),
parameters = Map(
"trigger_payload" -> "alarmTest".toJson,
"cron" -> "* * * * * *".toJson,
"maxTriggers" -> 3.toJson))
}
- feedCreationResult.stdout should include("ok")
- assetHelper.withCleaner(wsk.action, defaultActionName) { (action,
name) =>
- action.create(name, defaultAction)
- }
+ // create rule
assetHelper.withCleaner(wsk.rule, ruleName) { (rule, name) =>
- rule.create(name, trigger = triggerName, action =
defaultActionName)
+ rule.create(name, trigger = triggerName, action = actionName)
}
// get activation list of the trigger
@@ -99,7 +101,7 @@ class AlarmsFeedTests
(pkg, name) => pkg.bind("/whisk.system/alarms", name)
}
- // create whisk stuff
+ // 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(
@@ -128,7 +130,7 @@ class AlarmsFeedTests
(pkg, name) => pkg.bind("/whisk.system/alarms", name)
}
- // create whisk stuff
+ // 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(
@@ -159,7 +161,7 @@ class AlarmsFeedTests
val cron = System.currentTimeMillis
- // create whisk stuff
+ // 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(
@@ -189,7 +191,7 @@ class AlarmsFeedTests
(pkg, name) => pkg.bind("/whisk.system/alarms", name)
}
- // create whisk stuff
+ // 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(
@@ -221,7 +223,7 @@ class AlarmsFeedTests
val pastDate = System.currentTimeMillis - 5000
- // create whisk stuff
+ // 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(
@@ -253,7 +255,7 @@ class AlarmsFeedTests
val pastDate = System.currentTimeMillis - 5000
- // create whisk stuff
+ // 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(
@@ -286,7 +288,7 @@ class AlarmsFeedTests
val stopDate = System.currentTimeMillis + 5000
val startDate = stopDate
- // create whisk stuff
+ // 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(
@@ -317,7 +319,7 @@ class AlarmsFeedTests
(pkg, name) => pkg.bind("/whisk.system/alarms", name)
}
- // create whisk stuff
+ // 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(
@@ -346,7 +348,7 @@ class AlarmsFeedTests
(pkg, name) => pkg.bind("/whisk.system/alarms", name)
}
- // create whisk stuff
+ // 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(
@@ -357,4 +359,98 @@ class AlarmsFeedTests
feedCreationResult.stderr should include("the minutes parameter
must be an integer")
}
+
+ it should "return error message when alarms trigger update contains no
updatable parameters" in withAssetCleaner(wskprops) {
+ (wp, assetHelper) =>
+ implicit val wskProps = wp
+ 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 futureDate = System.currentTimeMillis + (1000 * 20)
+
+ // create trigger feed
+ println(s"Creating trigger: $triggerName")
+ assetHelper.withCleaner(wsk.trigger, triggerName) {
+ (trigger, name) =>
+ trigger.create(name, feed = Some(s"$packageName/once"),
parameters = Map(
+ "date" -> futureDate.toJson))
+ }
+
+ val actionName = s"$packageName/alarm"
+ val updatedStartDate = System.currentTimeMillis + (1000 * 20)
+ val updatedStopDate = updatedStartDate + (1000 * 10)
+
+ val updateRunAction = wsk.action.invoke(actionName, parameters =
Map(
+ "triggerName" -> triggerName.toJson,
+ "lifecycleEvent" -> "UPDATE".toJson,
+ "authKey" -> wskProps.authKey.toJson,
+ "startDate" -> updatedStartDate.toJson,
+ "stopDate" -> updatedStopDate.toJson
+ ))
+
+ withActivation(wsk.activation, updateRunAction) {
+ activation =>
+ activation.response.success shouldBe false
+ val error =
activation.response.result.get.fields("error").asJsObject
+ error.fields("error") shouldBe JsString("no updatable
parameters were specified")
+ }
+ }
+
+ it should "return error message when startDate is updated to be greater
than the stopDate" in withAssetCleaner(wskprops) {
+ (wp, assetHelper) =>
+ implicit val wskProps = wp
+ 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 minutes = 1
+ val startDate = System.currentTimeMillis + (1000 * 20)
+ val stopDate = startDate + (1000 * 10)
+
+ // create trigger feed
+ println(s"Creating trigger: $triggerName")
+ assetHelper.withCleaner(wsk.trigger, triggerName) {
+ (trigger, name) =>
+ trigger.create(name, feed =
Some(s"$packageName/interval"), parameters = Map(
+ "minutes" -> minutes.toJson,
+ "startDate" -> startDate.toJson,
+ "stopDate" -> stopDate.toJson))
+ }
+
+ val actionName = s"$packageName/alarm"
+ val updatedStartDate = System.currentTimeMillis + (1000 * 2000)
+
+ val updateRunAction = wsk.action.invoke(actionName, parameters =
Map(
+ "triggerName" -> triggerName.toJson,
+ "lifecycleEvent" -> "UPDATE".toJson,
+ "authKey" -> wskProps.authKey.toJson,
+ "startDate" -> updatedStartDate.toJson
+ ))
+
+ withActivation(wsk.activation, updateRunAction) {
+ activation =>
+ activation.response.success shouldBe false
+ val error =
activation.response.result.get.fields("error").asJsObject
+ error.fields("error") shouldBe JsString(s"startDate
parameter '${updatedStartDate}' must be less than the stopDate parameter
'${stopDate}'")
+ }
+ }
}
diff --git a/tests/src/test/scala/system/redundancy/AlarmsRedundancyTests.scala
b/tests/src/test/scala/system/redundancy/AlarmsRedundancyTests.scala
index aa08880..12e626e 100644
--- a/tests/src/test/scala/system/redundancy/AlarmsRedundancyTests.scala
+++ b/tests/src/test/scala/system/redundancy/AlarmsRedundancyTests.scala
@@ -53,7 +53,6 @@ class AlarmsRedundancyTests
var endpointPrefix =
s"https://$user:$password@$edgeHost/alarmstrigger/worker0/"
val defaultAction = Some(TestUtils.getTestActionFilename("hello.js"))
- val defaultActionName = "hello"
behavior of "Alarms redundancy tests"
@@ -62,6 +61,7 @@ class AlarmsRedundancyTests
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
@@ -74,20 +74,22 @@ class AlarmsRedundancyTests
(pkg, name) => pkg.bind("/whisk.system/alarms", name)
}
- // create whisk stuff
- val feedCreationResult = assetHelper.withCleaner(wsk.trigger,
triggerName) {
+ // create action
+ assetHelper.withCleaner(wsk.action, actionName) { (action, name) =>
+ action.create(name, defaultAction)
+ }
+
+ // create trigger feed
+ assetHelper.withCleaner(wsk.trigger, triggerName) {
(trigger, name) =>
trigger.create(name, feed = Some(s"$packageName/alarm"),
parameters = Map(
"trigger_payload" -> "alarmTest".toJson,
"cron" -> "* * * * * *".toJson))
}
- feedCreationResult.stdout should include("ok")
- assetHelper.withCleaner(wsk.action, defaultActionName) { (action,
name) =>
- action.create(name, defaultAction)
- }
+ // create rule
assetHelper.withCleaner(wsk.rule, ruleName) { (rule, name) =>
- rule.create(name, trigger = triggerName, action =
defaultActionName)
+ rule.create(name, trigger = triggerName, action = actionName)
}
println("waiting for triggers")
@@ -124,6 +126,7 @@ class AlarmsRedundancyTests
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
@@ -136,20 +139,22 @@ class AlarmsRedundancyTests
(pkg, name) => pkg.bind("/whisk.system/alarms", name)
}
- // create whisk stuff
- val feedCreationResult = assetHelper.withCleaner(wsk.trigger,
triggerName) {
+ // create action
+ assetHelper.withCleaner(wsk.action, actionName) { (action, name) =>
+ action.create(name, defaultAction)
+ }
+
+ // create trigger feed
+ assetHelper.withCleaner(wsk.trigger, triggerName) {
(trigger, name) =>
trigger.create(name, feed = Some(s"$packageName/alarm"),
parameters = Map(
"trigger_payload" -> "alarmTest".toJson,
"cron" -> "* * * * * *".toJson))
}
- feedCreationResult.stdout should include("ok")
- assetHelper.withCleaner(wsk.action, defaultActionName) { (action,
name) =>
- action.create(name, defaultAction)
- }
+ // create rule
assetHelper.withCleaner(wsk.rule, ruleName) { (rule, name) =>
- rule.create(name, trigger = triggerName, action =
defaultActionName)
+ rule.create(name, trigger = triggerName, action = actionName)
}
println("waiting for triggers")
----------------------------------------------------------------
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:
[email protected]
With regards,
Apache Git Services