support disabling triggers (never delete triggers that won't fire) (#88)
diff --git a/gradle/wrapper/gradle-wrapper.jar b/gradle/wrapper/gradle-wrapper.jar
index deedc7f..2fddeb5 100644
--- a/gradle/wrapper/gradle-wrapper.jar
+++ b/gradle/wrapper/gradle-wrapper.jar
Binary files differ
diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties
index 76babd2..ac0c4b9 100644
--- a/gradle/wrapper/gradle-wrapper.properties
+++ b/gradle/wrapper/gradle-wrapper.properties
@@ -1,6 +1,6 @@
-#Sat Sep 17 00:27:09 CEST 2016
+#Fri Apr 21 22:50:39 EDT 2017
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists
-distributionUrl=https\://services.gradle.org/distributions/gradle-3.0-bin.zip
+distributionUrl=https\://services.gradle.org/distributions/gradle-3.3-bin.zip
diff --git a/gradlew b/gradlew
index 9aa616c..4453cce 100755
--- a/gradlew
+++ b/gradlew
@@ -1,4 +1,4 @@
-#!/usr/bin/env bash
+#!/usr/bin/env sh
##############################################################################
##
@@ -154,16 +154,19 @@
esac
fi
-# Split up the JVM_OPTS And GRADLE_OPTS values into an array, following the shell quoting and substitution rules
-function splitJvmOpts() {
- JVM_OPTS=("$@")
+# Escape application args
+save ( ) {
+ for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done
+ echo " "
}
-eval splitJvmOpts $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS
-JVM_OPTS[${#JVM_OPTS[*]}]="-Dorg.gradle.appname=$APP_BASE_NAME"
+APP_ARGS=$(save "$@")
+
+# Collect all arguments for the java command, following the shell quoting and substitution rules
+eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS"
# by default we should be in the correct project dir, but when run from Finder on Mac, the cwd is wrong
-if [[ "$(uname)" == "Darwin" ]] && [[ "$HOME" == "$PWD" ]]; then
+if [ "$(uname)" = "Darwin" ] && [ "$HOME" = "$PWD" ]; then
cd "$(dirname "$0")"
fi
-exec "$JAVACMD" "${JVM_OPTS[@]}" -classpath "$CLASSPATH" org.gradle.wrapper.GradleWrapperMain "$@"
+exec "$JAVACMD" "$@"
diff --git a/provider/lib/update.js b/provider/lib/update.js
index acb2658..dd5ad4a 100644
--- a/provider/lib/update.js
+++ b/provider/lib/update.js
@@ -50,8 +50,12 @@
// number of retries to create a trigger.
utils.createTrigger(trigger, utils.retryAttempts)
.then(newTrigger => {
- logger.info(method, 'Trigger was added and database is confirmed.', newTrigger.id);
+ newTrigger.status = {
+ 'active': true,
+ 'dateChanged': new Date().toISOString(),
+ };
utils.addTriggerToDB(newTrigger, res);
+ logger.info(method, 'Trigger was added and database is confirmed.', newTrigger.id);
}).catch(err => {
logger.error(method, 'Trigger', id, 'could not be created.', err);
utils.deleteTrigger(id);
diff --git a/provider/lib/utils.js b/provider/lib/utils.js
index 3023954..94af602 100644
--- a/provider/lib/utils.js
+++ b/provider/lib/utils.js
@@ -155,44 +155,44 @@
triggerDB.view('filters', 'only_triggers', {include_docs: true}, function(err, body) {
if (!err) {
body.rows.forEach(function(trigger) {
+ if (!trigger.doc.status || trigger.doc.status.active === true) {
+ //check if trigger still exists in whisk db
+ var triggerObj = that.parseQName(trigger.doc.id);
+ var host = 'https://' + routerHost + ':' + 443;
+ var triggerURL = host + '/api/v1/namespaces/' + triggerObj.namespace + '/triggers/' + triggerObj.name;
+ var auth = trigger.doc.apikey.split(':');
- //check if trigger still exists in whisk db
- var triggerObj = that.parseQName(trigger.doc.id);
- var host = 'https://' + routerHost +':'+ 443;
- var triggerURL = host + '/api/v1/namespaces/' + triggerObj.namespace + '/triggers/' + triggerObj.name;
- var auth = trigger.doc.apikey.split(':');
-
- logger.info(method, 'Checking if trigger', trigger.doc.id, 'still exists');
- request({
- method: 'get',
- url: triggerURL,
- auth: {
- user: auth[0],
- pass: auth[1]
- }
- }, function(error, response) {
- //delete from database if trigger no longer exists (404)
- if (!error && response.statusCode === 404) {
- logger.info(method, 'Trigger', trigger.doc.id, 'no longer exists');
- that.deleteTriggerFromDB(trigger.doc.id);
- }
- else {
- var cloudantTrigger = that.initTrigger(trigger.doc, trigger.doc.id);
-
- // check here for triggers left if none left end here, and don't create
- if (cloudantTrigger.maxTriggers === -1 || cloudantTrigger.triggersLeft > 0) {
+ logger.info(method, 'Checking if trigger', trigger.doc.id, 'still exists');
+ request({
+ method: 'get',
+ url: triggerURL,
+ auth: {
+ user: auth[0],
+ pass: auth[1]
+ }
+ }, function (error, response) {
+ //disable trigger in database if trigger is dead
+ if (!error && that.shouldDisableTrigger(response.statusCode)) {
+ var message = 'Automatically disabled after receiving a ' + response.statusCode + ' status code when re-creating the trigger';
+ that.disableTriggerInDB(trigger.doc.id, response.statusCode, message);
+ logger.error(method, 'trigger', trigger.doc.id, 'has been disabled due to status code:', response.statusCode);
+ }
+ else {
+ var cloudantTrigger = that.initTrigger(trigger.doc, trigger.doc.id);
that.createTrigger(cloudantTrigger, that.retryAttempts)
.then(newTrigger => {
logger.info(method, 'Trigger was added.', newTrigger.id);
}).catch(err => {
- //if feed was not recreated then delete from trigger database
- that.deleteTriggerFromDB(cloudantTrigger.id);
+ var message = 'Automatically disabled after receiving an exception when re-creating the trigger';
+ that.disableTriggerInDB(cloudantTrigger.id, undefined, message);
+ logger.error(method, 'Disabled trigger', cloudantTrigger.id, 'due to exception:', err);
});
- } else {
- logger.info(method, 'found a trigger with no triggers left to fire off.');
}
- }
- });
+ });
+ }
+ else {
+ logger.info(method, 'ignoring trigger', trigger.doc._id, 'since it is disabled.');
+ }
});
} else {
logger.error(method, 'could not get latest state from database');
@@ -201,20 +201,6 @@
};
- // Delete a trigger: stop listening for changes and remove it.
- this.deleteTrigger = function (id) {
- var method = 'deleteTrigger';
- var trigger = that.triggers[id];
- if (trigger) {
- logger.info(method, 'Stopped cloudant trigger', id, 'listening for changes in database', trigger.dbname);
- trigger.feed.stop();
- delete that.triggers[id];
- } else {
- logger.info(method, 'trigger', id, 'could not be found in the trigger list.');
- return false;
- }
- };
-
this.addTriggerToDB = function (trigger, res) {
var method = 'addTriggerToDB';
@@ -224,23 +210,63 @@
res.status(200).json(_.omit(trigger, 'feed'));
} else {
that.deleteTrigger(trigger.id);
- res.status(err.statusCode).json({error: 'Cloudant trigger cannot be created.'});
+ res.status(err.statusCode).json({error: 'Cloudant trigger cannot be created. ' + err});
}
});
};
+ this.shouldDisableTrigger = function (statusCode) {
+ return ((statusCode >= 400 && statusCode < 500) && [408, 429].indexOf(statusCode) === -1);
+ };
+
+ this.disableTriggerInDB = function (id, statusCode, message) {
+
+ var method = 'disableTriggerInDB';
+
+ triggerDB.get(id, function (err, existing) {
+ if (!err) {
+ if (!existing.status || existing.status.active === true) {
+ var updatedTrigger = existing;
+ var status = {
+ 'active': false,
+ 'dateChanged': new Date().toISOString(),
+ 'reason': {'kind': 'AUTO', 'statusCode': statusCode, 'message': message}
+ };
+ updatedTrigger.status = status;
+
+ triggerDB.insert(updatedTrigger, id, function (err) {
+ if (err) {
+ logger.error(method, 'there was an error while disabling', id, 'in database. ' + err);
+ }
+ else {
+ that.deleteTrigger(id);
+ logger.info(method, 'trigger', id, 'successfully disabled in database');
+ }
+ });
+ }
+ }
+ else {
+ if (err.statusCode === 404) {
+ logger.error(method, 'there was no trigger with id', id, 'in database.', err.error);
+ } else {
+ logger.error(method, 'there was an error while getting', id, 'from database', err);
+ }
+ }
+ });
+ };
+
this.deleteTriggerFromDB = function (id, res) {
var method = 'deleteTriggerFromDB';
- triggerDB.get(id, function(err, body) {
+ triggerDB.get(id, function(err, existing) {
if (!err) {
- triggerDB.destroy(body._id, body._rev, function(err) {
+ triggerDB.destroy(existing._id, existing._rev, function(err) {
if (err) {
- logger.error(method, 'there was an error while deleting', id, 'from database');
+ logger.error(method, 'there was an error while deleting', id, 'from database. ' + err);
if (res) {
- res.status(err.statusCode).json({ error: 'Cloudant data trigger ' + id + 'cannot be deleted.' } );
+ res.status(err.statusCode).json({ error: 'Cloudant data trigger ' + id + 'cannot be deleted. ' + err } );
}
} else {
that.deleteTrigger(id);
@@ -260,7 +286,7 @@
} else {
logger.error(method, 'there was an error while getting', id, 'from database', err);
if (res) {
- res.status(err.statusCode).json({ error: 'Cloudant data trigger ' + id + ' cannot be deleted.' } );
+ res.status(err.statusCode).json({ error: 'Cloudant data trigger ' + id + ' cannot be deleted. ' + err } );
}
}
}
@@ -268,6 +294,20 @@
};
+ // Delete a trigger: stop listening for changes and remove it.
+ this.deleteTrigger = function (id) {
+ var method = 'deleteTrigger';
+ var trigger = that.triggers[id];
+ if (trigger) {
+ logger.info(method, 'Stopped cloudant trigger', id, 'listening for changes in database', trigger.dbname);
+ trigger.feed.stop();
+ delete that.triggers[id];
+ } else {
+ logger.info(method, 'trigger', id, 'could not be found in the trigger list.');
+ return false;
+ }
+ };
+
this.fireTrigger = function (id, change) {
var method = 'fireTrigger';
@@ -287,6 +327,10 @@
that.postTrigger(dataTrigger, form, uri, auth, that.retryAttempts)
.then(triggerId => {
logger.info(method, 'Trigger', triggerId, 'was successfully fired');
+ if (dataTrigger.triggersLeft === 0) {
+ that.disableTriggerInDB(dataTrigger.id, undefined, 'Automatically disabled after reaching max triggers');
+ logger.error(method, 'no more triggers left, disabled', dataTrigger.id);
+ }
}).catch(err => {
logger.error(method, err);
});
@@ -310,10 +354,11 @@
logger.info(method, dataTrigger.id, 'http post request, STATUS:', response ? response.statusCode : response);
if (error || response.statusCode >= 400) {
logger.error(method, 'there was an error invoking', dataTrigger.id, response ? response.statusCode : error);
- if (!error && [408, 429, 500, 502, 503, 504].indexOf(response.statusCode) === -1) {
- //delete dead triggers
- that.deleteTriggerFromDB(dataTrigger.id);
- reject('Deleted dead trigger ' + dataTrigger.id);
+ if (!error && that.shouldDisableTrigger(response.statusCode)) {
+ //disable trigger
+ var message = 'Automatically disabled after receiving a ' + response.statusCode + ' status code when firing the trigger';
+ that.disableTriggerInDB(dataTrigger.id, response.statusCode, message);
+ reject('Disabled trigger ' + dataTrigger.id + ' due to status code: ' + response.statusCode);
}
else {
if (retryCount > 0) {
@@ -336,11 +381,6 @@
dataTrigger.triggersLeft--;
}
logger.info(method, 'fired', dataTrigger.id, dataTrigger.triggersLeft, 'triggers left');
-
- if (dataTrigger.triggersLeft === 0) {
- logger.info(method, 'no more triggers left, deleting', dataTrigger.id);
- that.deleteTriggerFromDB(dataTrigger.id);
- }
resolve(dataTrigger.id);
}
}
diff --git a/tests/build.gradle b/tests/build.gradle
index 87d3451..698277b 100644
--- a/tests/build.gradle
+++ b/tests/build.gradle
@@ -23,7 +23,7 @@
task testHealth(type: Test) {
systemProperty 'test.router', 'true'
- include 'system/packages/**'
+ include 'system/health/**'
}
dependencies {
diff --git a/tests/src/test/scala/catalog/CloudantUtil.java b/tests/src/test/scala/system/CloudantUtil.java
similarity index 99%
rename from tests/src/test/scala/catalog/CloudantUtil.java
rename to tests/src/test/scala/system/CloudantUtil.java
index 36a5b06..23ef659 100755
--- a/tests/src/test/scala/catalog/CloudantUtil.java
+++ b/tests/src/test/scala/system/CloudantUtil.java
@@ -13,7 +13,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-package catalog;
+package system;
import com.cloudant.client.api.CloudantClient;
import com.cloudant.client.api.Database;
diff --git a/tests/src/test/scala/system/packages/CloudantHealthFeedTests.scala b/tests/src/test/scala/system/health/CloudantHealthFeedTests.scala
similarity index 98%
rename from tests/src/test/scala/system/packages/CloudantHealthFeedTests.scala
rename to tests/src/test/scala/system/health/CloudantHealthFeedTests.scala
index f0a818a..48f3a76 100644
--- a/tests/src/test/scala/system/packages/CloudantHealthFeedTests.scala
+++ b/tests/src/test/scala/system/health/CloudantHealthFeedTests.scala
@@ -13,21 +13,20 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-package system.packages
+package system.health
import org.junit.runner.RunWith
import org.scalatest.FlatSpec
import org.scalatest.junit.JUnitRunner
-
-import catalog.CloudantUtil
import common.TestHelpers
import common.Wsk
+import common.WskActorSystem
import common.WskProps
import common.WskTestHelpers
import spray.json.DefaultJsonProtocol.IntJsonFormat
import spray.json.DefaultJsonProtocol.StringJsonFormat
import spray.json.pimpAny
-import common.WskActorSystem
+import system.CloudantUtil
/**
* Tests for Cloudant trigger service
@@ -43,7 +42,7 @@
val wsk = new Wsk
val myCloudantCreds = CloudantUtil.Credential.makeFromVCAPFile("cloudantNoSQLDB", this.getClass.getSimpleName)
- behavior of "Cloudant trigger service"
+ behavior of "Cloudant Health trigger service"
it should "bind cloudant package and fire changes trigger using changes feed" in withAssetCleaner(wskprops) {
(wp, assetHelper) =>
diff --git a/tests/src/test/scala/catalog/cloudant/CloudantAccountActionsTests.scala b/tests/src/test/scala/system/packages/CloudantAccountActionsTests.scala
similarity index 99%
rename from tests/src/test/scala/catalog/cloudant/CloudantAccountActionsTests.scala
rename to tests/src/test/scala/system/packages/CloudantAccountActionsTests.scala
index 95ff63b..6187f38 100644
--- a/tests/src/test/scala/catalog/cloudant/CloudantAccountActionsTests.scala
+++ b/tests/src/test/scala/system/packages/CloudantAccountActionsTests.scala
@@ -13,15 +13,15 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-package catalog.cloudant
+package system.packages
-import catalog.CloudantUtil
import common._
import org.junit.runner.RunWith
import org.scalatest.FlatSpec
import org.scalatest.junit.JUnitRunner
import spray.json.DefaultJsonProtocol.StringJsonFormat
import spray.json.{JsArray, JsNumber, JsString, JsValue, pimpAny}
+import system.CloudantUtil
import whisk.utils.JsHelpers
import scala.collection.mutable.HashSet
diff --git a/tests/src/test/scala/catalog/cloudant/CloudantBindingTests.scala b/tests/src/test/scala/system/packages/CloudantBindingTests.scala
similarity index 95%
rename from tests/src/test/scala/catalog/cloudant/CloudantBindingTests.scala
rename to tests/src/test/scala/system/packages/CloudantBindingTests.scala
index 175bbb0..c822586 100644
--- a/tests/src/test/scala/catalog/cloudant/CloudantBindingTests.scala
+++ b/tests/src/test/scala/system/packages/CloudantBindingTests.scala
@@ -13,20 +13,15 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-package catalog.cloudant
+package system.packages
+import common.{TestHelpers, Wsk, WskProps, WskTestHelpers}
import org.junit.runner.RunWith
import org.scalatest.FlatSpec
import org.scalatest.junit.JUnitRunner
-
-import catalog.CloudantUtil
-import common.TestHelpers
-import common.Wsk
-import common.WskProps
-import common.WskTestHelpers
import spray.json.DefaultJsonProtocol.StringJsonFormat
-import spray.json.JsObject
-import spray.json.pimpAny
+import spray.json.{JsObject, pimpAny}
+import system.CloudantUtil
@RunWith(classOf[JUnitRunner])
class CloudantBindingTests extends FlatSpec
diff --git a/tests/src/test/scala/catalog/cloudant/CloudantDatabaseActionsTests.scala b/tests/src/test/scala/system/packages/CloudantDatabaseActionsTests.scala
similarity index 98%
rename from tests/src/test/scala/catalog/cloudant/CloudantDatabaseActionsTests.scala
rename to tests/src/test/scala/system/packages/CloudantDatabaseActionsTests.scala
index 69b3875..1e8958d 100644
--- a/tests/src/test/scala/catalog/cloudant/CloudantDatabaseActionsTests.scala
+++ b/tests/src/test/scala/system/packages/CloudantDatabaseActionsTests.scala
@@ -13,19 +13,17 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-package catalog.cloudant
+package system.packages
import java.util.Date
-import catalog.CloudantUtil
-import catalog.CloudantUtil._
import common._
import org.junit.runner.RunWith
import org.scalatest.FlatSpec
import org.scalatest.junit.JUnitRunner
-import spray.json.DefaultJsonProtocol.StringJsonFormat
-import spray.json.DefaultJsonProtocol.ByteJsonFormat
+import spray.json.DefaultJsonProtocol.{ByteJsonFormat, StringJsonFormat}
import spray.json.{JsArray, JsBoolean, JsNumber, JsObject, JsString, pimpAny, pimpString}
+import system.CloudantUtil
import whisk.utils.JsHelpers
@RunWith(classOf[JUnitRunner])
@@ -412,9 +410,10 @@
activation.response.success shouldBe true
activation.response.result.get.fields.get("id") shouldBe defined
activation.response.result.get.fields.get("rev") shouldBe defined
+ activation.response.result.get.fields.get("rev") shouldBe defined
}
//Assert that document does not exist
- val getResponse = getDocument(credential, response.get("id").getAsString)
+ val getResponse = CloudantUtil.getDocument(credential, response.get("id").getAsString)
getResponse.get("error").getAsString shouldBe "not_found"
}
finally {
@@ -641,7 +640,7 @@
"dbname" -> credential.dbname.toJson))
}
//Create test design index doc
- val indexDesignDoc = CloudantUtil.createDesignFromFile(INDEX_DDOC_PATH).toString
+ val indexDesignDoc = CloudantUtil.createDesignFromFile(CloudantUtil.INDEX_DDOC_PATH).toString
val indexDocJSObj = indexDesignDoc.parseJson.asJsObject
println("Invoking the create-query-index action.")
@@ -717,7 +716,7 @@
"dbname" -> credential.dbname.toJson))
}
//Create test design index doc
- val indexDesignDoc = CloudantUtil.createDesignFromFile(INDEX_DDOC_PATH).toString
+ val indexDesignDoc = CloudantUtil.createDesignFromFile(CloudantUtil.INDEX_DDOC_PATH).toString
val response = CloudantUtil.createDocument(credential, indexDesignDoc)
response.get("ok").getAsString shouldBe "true"
@@ -838,7 +837,7 @@
response.get("ok").getAsString shouldBe "true"
//Create test design doc
- val designDoc = CloudantUtil.createDesignFromFile(VIEW_AND_SEARCH_DDOC_PATH).toString
+ val designDoc = CloudantUtil.createDesignFromFile(CloudantUtil.VIEW_AND_SEARCH_DDOC_PATH).toString
val getResponse = CloudantUtil.createDocument(credential, designDoc)
getResponse.get("ok").getAsString shouldBe "true"
@@ -889,7 +888,7 @@
response.get("ok").getAsString shouldBe "true"
//Create test design doc
- val designDoc = CloudantUtil.createDesignFromFile(VIEW_AND_SEARCH_DDOC_PATH).toString
+ val designDoc = CloudantUtil.createDesignFromFile(CloudantUtil.VIEW_AND_SEARCH_DDOC_PATH).toString
val getResponse = CloudantUtil.createDocument(credential, designDoc)
getResponse.get("ok").getAsString shouldBe "true"
@@ -936,7 +935,7 @@
response.get("ok").getAsString shouldBe "true"
//Create test design doc
- val designDoc = CloudantUtil.createDesignFromFile(VIEW_AND_SEARCH_DDOC_PATH).toString
+ val designDoc = CloudantUtil.createDesignFromFile(CloudantUtil.VIEW_AND_SEARCH_DDOC_PATH).toString
val getResponse = CloudantUtil.createDocument(credential, designDoc)
getResponse.get("ok").getAsString shouldBe "true"
@@ -985,7 +984,7 @@
response.get("ok").getAsString shouldBe "true"
//Create test design doc
- val designDoc = CloudantUtil.createDesignFromFile(VIEW_AND_SEARCH_DDOC_PATH).toString
+ val designDoc = CloudantUtil.createDesignFromFile(CloudantUtil.VIEW_AND_SEARCH_DDOC_PATH).toString
val getResponse = CloudantUtil.createDocument(credential, designDoc)
getResponse.get("ok").getAsString shouldBe "true"
@@ -1041,7 +1040,7 @@
val result = activation.response.result.get
result.fields.get("ok") shouldBe Some(JsBoolean(true))
}
- val getResponse = getDocument(credential, id)
+ val getResponse = CloudantUtil.getDocument(credential, id)
getResponse.get("error").getAsString shouldBe "not_found"
getResponse.get("reason").getAsString shouldBe "deleted"
}
@@ -1114,7 +1113,7 @@
"dbname" -> credential.dbname.toJson))
}
//Create test index
- val view = CloudantUtil.createDesignFromFile(VIEW_AND_SEARCH_DDOC_PATH)
+ val view = CloudantUtil.createDesignFromFile(CloudantUtil.VIEW_AND_SEARCH_DDOC_PATH)
val response = CloudantUtil.createDocument(credential, view.toString)
response.get("ok").getAsString shouldBe "true"
val id = response.get("id").getAsString
@@ -1129,7 +1128,7 @@
result.fields.get("ok") shouldBe Some(JsBoolean(true))
}
//Assert that view is deleted
- val getResponse = getDocument(credential, id)
+ val getResponse = CloudantUtil.getDocument(credential, id)
getResponse.get("views").toString shouldBe "{}"
}
finally {
@@ -1697,7 +1696,7 @@
val result = activation.response.result.get
result.fields.get("id") shouldBe Some(JsString(id))
}
- val docResponse = getDocument(credential, id)
+ val docResponse = CloudantUtil.getDocument(credential, id)
val updatedAttachment = docResponse.get("_attachments").getAsJsonObject.get(attachmentName).getAsJsonObject
getResponse.get("_attachments").getAsJsonObject.has(attachmentName) shouldBe true
attachment.get("revpos") should not be updatedAttachment.get("revpos")
@@ -1791,7 +1790,7 @@
activation.response.result.get.fields.get("rev") shouldBe defined
}
//Assert that attachment does not exist in doc
- val response = getDocument(credential, id).toString
+ val response = CloudantUtil.getDocument(credential, id).toString
val docJSObject = response.parseJson.asJsObject
docJSObject.fields.get("_attachments") should not be defined
}
diff --git a/tests/src/test/scala/catalog/cloudant/CloudantFeedTests.scala b/tests/src/test/scala/system/packages/CloudantFeedTests.scala
similarity index 94%
rename from tests/src/test/scala/catalog/cloudant/CloudantFeedTests.scala
rename to tests/src/test/scala/system/packages/CloudantFeedTests.scala
index b497775..e1c6543 100644
--- a/tests/src/test/scala/catalog/cloudant/CloudantFeedTests.scala
+++ b/tests/src/test/scala/system/packages/CloudantFeedTests.scala
@@ -13,22 +13,16 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-package catalog.cloudant
+package system.packages
+import common.TestUtils.ANY_ERROR_EXIT
+import common._
import org.junit.runner.RunWith
import org.scalatest.FlatSpec
import org.scalatest.junit.JUnitRunner
-
-import catalog.CloudantUtil
-import common.TestHelpers
-import common.Wsk
-import common.WskProps
-import common.WskTestHelpers
-import spray.json.DefaultJsonProtocol.IntJsonFormat
-import spray.json.DefaultJsonProtocol.StringJsonFormat
+import spray.json.DefaultJsonProtocol.{IntJsonFormat, StringJsonFormat}
import spray.json.pimpAny
-import common.WskActorSystem
-import common.TestUtils.ANY_ERROR_EXIT
+import system.CloudantUtil
/**
* Tests for Cloudant trigger service
@@ -236,7 +230,7 @@
}
- it should "only invoke as many times as specified" in withAssetCleaner(wskprops) {
+ it should "should disable after reaching max triggers" in withAssetCleaner(wskprops) {
(wp, assetHelper) =>
implicit val wskprops = wp // shadow global props and make implicit
val triggerName = s"dummyCloudantTrigger-${System.currentTimeMillis}"
@@ -267,18 +261,24 @@
}
feedCreationResult.stdout should include("ok")
- // Create 2 test docs in cloudant and assert that document was inserted successfully
+ // Create test docs in cloudant and assert that document was inserted successfully
println("Creating a test doc-1 in the cloudant")
val response1 = CloudantUtil.createDocument(myCloudantCreds, "{\"test\":\"test_doc_1\"}")
response1.get("ok").getAsString() should be("true")
+
+ println("Checking for activations")
+ val activations = wsk.activation.pollFor(N = 2, Some(triggerName), retries = 5).length
+ println(s"Found activation size (should be exactly 1): $activations")
+ activations should be(1)
+
println("Creating a test doc-2 in the cloudant")
val response2 = CloudantUtil.createDocument(myCloudantCreds, "{\"test\":\"test_doc_2\"}")
response2.get("ok").getAsString() should be("true")
- println("Checking for activations")
- val activations = wsk.activation.pollFor(N = 2, Some(triggerName)).length
- println(s"Found activation size (should be exactly 1): $activations")
- activations should be(1)
+ println("No activations should be created for test_doc_2 since trigger is disabled")
+ val newactivations = wsk.activation.pollFor(N = 2, Some(triggerName), retries = 5).length
+ println(s"Activation size should still be one: $newactivations")
+ newactivations should be(1)
} finally {
CloudantUtil.unsetUp(myCloudantCreds)
diff --git a/tests/src/test/scala/catalog/cloudant/CloudantTriggerPersistencyTest.scala b/tests/src/test/scala/system/packages/CloudantTriggerPersistencyTest.scala
similarity index 92%
rename from tests/src/test/scala/catalog/cloudant/CloudantTriggerPersistencyTest.scala
rename to tests/src/test/scala/system/packages/CloudantTriggerPersistencyTest.scala
index 853a3fb..40790c6 100644
--- a/tests/src/test/scala/catalog/cloudant/CloudantTriggerPersistencyTest.scala
+++ b/tests/src/test/scala/system/packages/CloudantTriggerPersistencyTest.scala
@@ -13,22 +13,15 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-package catalog.cloudant
+package system.packages
+import common._
import org.junit.runner.RunWith
import org.scalatest.FlatSpec
import org.scalatest.junit.JUnitRunner
-
-import catalog.CloudantUtil
-import common.TestHelpers
-import common.Wsk
-import common.WskProps
-import common.WhiskProperties
-import common.WskTestHelpers
-import spray.json.DefaultJsonProtocol.IntJsonFormat
-import spray.json.DefaultJsonProtocol.StringJsonFormat
+import spray.json.DefaultJsonProtocol.{IntJsonFormat, StringJsonFormat}
import spray.json.pimpAny
-import common.WskActorSystem
+import system.CloudantUtil
/**
* Tests for Cloudant trigger service