cbickel closed pull request #2760: Add new design docs that remove older views
that are no longer necessary
URL: https://github.com/apache/incubator-openwhisk/pull/2760
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/ansible/files/whisks_design_document_for_activations_db_filters_v2.json
b/ansible/files/whisks_design_document_for_activations_db_filters_v2.json
new file mode 100644
index 0000000000..14eb0b0a8e
--- /dev/null
+++ b/ansible/files/whisks_design_document_for_activations_db_filters_v2.json
@@ -0,0 +1,9 @@
+{
+ "_id": "_design/whisks-filters.v2",
+ "language": "javascript",
+ "views": {
+ "activations": {
+ "map": "function (doc) {\n var PATHSEP = \"/\";\n var isActivation =
function (doc) { return (doc.activationId !== undefined) };\n var summarize =
function (doc) {\n var endtime = doc.end !== 0 ? doc.end : undefined;\n
return {\n namespace: doc.namespace,\n name: doc.name,\n
version: doc.version,\n publish: doc.publish,\n annotations:
doc.annotations,\n activationId: doc.activationId,\n start:
doc.start,\n end: endtime,\n duration: endtime !== undefined ?
endtime - doc.start : undefined,\n cause: doc.cause,\n
statusCode: (endtime !== undefined && doc.response !== undefined &&
doc.response.statusCode !== undefined) ? doc.response.statusCode : undefined\n
}\n };\n\n var pathFilter = function(doc) {\n for (i = 0; i <
doc.annotations.length; i++) {\n var a = doc.annotations[i];\n if
(a.key == \"path\") try {\n var p = a.value.split(PATHSEP);\n
if (p.length == 3) {\n return p[1] + PATHSEP + doc.name;\n
} else return doc.name;\n } catch (e) {\n return doc.name;\n
}\n }\n return doc.name;\n }\n\n if (isActivation(doc)) try {\n var
value = summarize(doc)\n emit([doc.namespace+PATHSEP+pathFilter(doc),
doc.start], value);\n } catch (e) {}\n}\n"
+ }
+ }
+}
diff --git a/ansible/files/whisks_design_document_for_activations_db_v2.json
b/ansible/files/whisks_design_document_for_activations_db_v2.json
new file mode 100644
index 0000000000..be57879f8e
--- /dev/null
+++ b/ansible/files/whisks_design_document_for_activations_db_v2.json
@@ -0,0 +1,9 @@
+{
+ "_id": "_design/whisks.v2",
+ "language": "javascript",
+ "views": {
+ "activations": {
+ "map": "function (doc) {\n var PATHSEP = \"/\";\n var isActivation =
function (doc) { return (doc.activationId !== undefined) };\n var summarize =
function (doc) {\n var endtime = doc.end !== 0 ? doc.end : undefined;\n
return {\n namespace: doc.namespace,\n name: doc.name,\n
version: doc.version,\n publish: doc.publish,\n annotations:
doc.annotations,\n activationId: doc.activationId,\n start:
doc.start,\n end: endtime,\n duration: endtime !== undefined ?
endtime - doc.start : undefined,\n cause: doc.cause,\n
statusCode: (endtime !== undefined && doc.response !== undefined &&
doc.response.statusCode !== undefined) ? doc.response.statusCode : undefined\n
}\n };\n\n if (isActivation(doc)) try {\n var value = summarize(doc)\n
emit([doc.namespace, doc.start], value);\n } catch (e) {}\n}\n"
+ }
+ }
+}
diff --git a/ansible/files/whisks_design_document_for_entities_db_v2.json
b/ansible/files/whisks_design_document_for_entities_db_v2.json
new file mode 100644
index 0000000000..97ed91c4bd
--- /dev/null
+++ b/ansible/files/whisks_design_document_for_entities_db_v2.json
@@ -0,0 +1,21 @@
+{
+ "_id": "_design/whisks.v2",
+ "language": "javascript",
+ "views": {
+ "rules": {
+ "map": "function (doc) {\n var PATHSEP = \"/\";\n var isRule =
function (doc) { return (doc.trigger !== undefined) };\n if (isRule(doc)) try
{\n var ns = doc.namespace.split(PATHSEP);\n var root = ns[0];\n var
date = doc.updated;\n var value = {\n namespace: doc.namespace,\n
name: doc.name,\n version: doc.version,\n publish: doc.publish,\n
annotations: doc.annotations\n };\n emit([doc.namespace, date],
value);\n if (root !== doc.namespace) {\n emit([root, date], value);\n
}\n } catch (e) {}\n}"
+ },
+ "all": {
+ "map": "function (doc) {\n var PATHSEP = \"/\";\n\n var isPackage =
function (doc) { return (doc.binding !== undefined) };\n var isAction =
function (doc) { return (doc.exec !== undefined) };\n var isTrigger = function
(doc) { return (doc.exec === undefined && doc.binding === undefined &&
doc.parameters !== undefined) };\n var isRule = function (doc) { return
(doc.trigger !== undefined) };\n \n var collection = function (doc) {\n if
(isPackage(doc)) return \"packages\";\n if (isAction(doc)) return
\"actions\";\n if (isTrigger(doc)) return \"triggers\";\n if
(isRule(doc)) return \"rules\";\n return undefined;\n };\n\n try {\n
var type = collection(doc);\n if (type !== undefined) {\n var ns =
doc.namespace.split(PATHSEP);\n var root = ns[0];\n var date =
doc.updated;\n var value = {\n collection: type,\n
namespace: doc.namespace,\n name: doc.name,\n version:
doc.version,\n publish: doc.publish,\n annotations:
doc.annotations\n };\n if (isPackage(doc)) {\n value.binding =
Object.keys(doc.binding).length !== 0;\n }\n emit([root, date],
value);\n }\n } catch (e) {}\n}"
+ },
+ "packages": {
+ "map": "function (doc) {\n var isPackage = function (doc) { return
(doc.binding !== undefined) };\n if (isPackage(doc)) try {\n var date =
doc.updated;\n emit([doc.namespace, date], {\n namespace:
doc.namespace,\n name: doc.name,\n version: doc.version,\n
publish: doc.publish,\n annotations: doc.annotations,\n binding:
Object.keys(doc.binding).length !== 0\n });\n } catch (e) {}\n}"
+ },
+ "actions": {
+ "map": "function (doc) {\n var PATHSEP = \"/\";\n var isAction =
function (doc) { return (doc.exec !== undefined) };\n if (isAction(doc)) try
{\n var ns = doc.namespace.split(PATHSEP);\n var root = ns[0];\n var
date = doc.updated;\n var value = {\n namespace: doc.namespace,\n
name: doc.name,\n version: doc.version,\n publish: doc.publish,\n
annotations: doc.annotations\n };\n emit([doc.namespace, date],
value);\n if (root !== doc.namespace) {\n emit([root, date], value);\n
}\n } catch (e) {}\n}"
+ },
+ "triggers": {
+ "map": "function (doc) {\n var PATHSEP = \"/\";\n var isTrigger =
function (doc) { return (doc.exec === undefined && doc.binding === undefined &&
doc.parameters !== undefined) };\n if (isTrigger(doc)) try {\n var ns =
doc.namespace.split(PATHSEP);\n var root = ns[0];\n var date =
doc.updated;\n var value = {\n namespace: doc.namespace,\n name:
doc.name,\n version: doc.version,\n publish: doc.publish,\n
annotations: doc.annotations\n };\n emit([doc.namespace, date], value);\n
if (root !== doc.namespace) {\n emit([root, date], value);\n }\n }
catch (e) {}\n}"
+ }
+ }
+}
\ No newline at end of file
diff --git a/ansible/group_vars/all b/ansible/group_vars/all
index d7dfae9c83..79642fed01 100644
--- a/ansible/group_vars/all
+++ b/ansible/group_vars/all
@@ -198,7 +198,10 @@ db:
- whisk.system
whisk:
actions: "{{ db_prefix }}whisks"
+ actions_ddoc: "whisks"
activations: "{{ db_prefix }}activations"
+ activations_ddoc: "whisks"
+ activations_filter_ddoc: "whisks"
auth: "{{ db_prefix }}subjects"
apigateway:
diff --git a/ansible/roles/controller/tasks/deploy.yml
b/ansible/roles/controller/tasks/deploy.yml
index d128053f2a..c669395dcb 100644
--- a/ansible/roles/controller/tasks/deploy.yml
+++ b/ansible/roles/controller/tasks/deploy.yml
@@ -60,9 +60,12 @@
"DB_PORT": "{{ db_port }}"
"DB_USERNAME": "{{ db_username }}"
"DB_PASSWORD": "{{ db_password }}"
- "DB_WHISK_ACTIONS": "{{ db.whisk.actions }}"
"DB_WHISK_AUTHS": "{{ db.whisk.auth }}"
+ "DB_WHISK_ACTIONS": "{{ db.whisk.actions }}"
"DB_WHISK_ACTIVATIONS": "{{ db.whisk.activations }}"
+ "DB_WHISK_ACTIONS_DDOC": "{{ db.whisk.actions_ddoc }}"
+ "DB_WHISK_ACTIVATIONS_DDOC": "{{ db.whisk.activations_ddoc }}"
+ "DB_WHISK_ACTIVATIONS_FILTER_DDOC": "{{ db.whisk.activations_filter_ddoc
}}"
"LIMITS_ACTIONS_INVOKES_PERMINUTE": "{{ limits.invocationsPerMinute }}"
"LIMITS_ACTIONS_INVOKES_CONCURRENT": "{{ limits.concurrentInvocations }}"
diff --git a/ansible/roles/invoker/tasks/deploy.yml
b/ansible/roles/invoker/tasks/deploy.yml
index 2b8dc7cbb0..b7d9fc2c2f 100644
--- a/ansible/roles/invoker/tasks/deploy.yml
+++ b/ansible/roles/invoker/tasks/deploy.yml
@@ -129,6 +129,9 @@
-e DB_PASSWORD='{{ db_password }}'
-e DB_WHISK_ACTIONS='{{ db.whisk.actions }}'
-e DB_WHISK_ACTIVATIONS='{{ db.whisk.activations }}'
+ -e DB_WHISK_ACTIONS_DDOC='{{ db.whisk.actions_ddoc }}'
+ -e DB_WHISK_ACTIVATIONS_DDOC='{{ db.whisk.activations_ddoc }}'
+ -e DB_WHISK_ACTIVATIONS_FILTER_DDOC='{{
db.whisk.activations_filter_ddoc }}'
-e WHISK_API_HOST_PROTO='{{ whisk_api_host_proto | default('https') }}'
-e WHISK_API_HOST_PORT='{{ whisk_api_host_port | default('443') }}'
-e WHISK_API_HOST_NAME='{{ whisk_api_host_name |
default(groups['edge'] | first) }}'
diff --git a/ansible/tasks/recreateViews.yml b/ansible/tasks/recreateViews.yml
index e953320a59..682ca94e39 100644
--- a/ansible/tasks/recreateViews.yml
+++ b/ansible/tasks/recreateViews.yml
@@ -7,6 +7,7 @@
doc: "{{ lookup('file', '{{ item }}') }}"
with_items:
- "{{ openwhisk_home
}}/ansible/files/whisks_design_document_for_actions_db.json"
+ - "{{ openwhisk_home
}}/ansible/files/whisks_design_document_for_entities_db_v2.json"
- "{{ openwhisk_home }}/ansible/files/filter_design_document.json"
- include: db/recreateDoc.yml
@@ -15,6 +16,8 @@
doc: "{{ lookup('file', '{{ item }}') }}"
with_items:
- "{{ openwhisk_home
}}/ansible/files/whisks_design_document_for_activations_db.json"
+ - "{{ openwhisk_home
}}/ansible/files/whisks_design_document_for_activations_db_v2.json"
+ - "{{ openwhisk_home
}}/ansible/files/whisks_design_document_for_activations_db_filters_v2.json"
- "{{ openwhisk_home }}/ansible/files/filter_design_document.json"
- "{{ openwhisk_home
}}/ansible/files/activations_design_document_for_activations_db.json"
- "{{ openwhisk_home
}}/ansible/files/logCleanup_design_document_for_activations_db.json"
diff --git a/ansible/templates/whisk.properties.j2
b/ansible/templates/whisk.properties.j2
index e23e624879..2c1d644cfb 100644
--- a/ansible/templates/whisk.properties.j2
+++ b/ansible/templates/whisk.properties.j2
@@ -87,9 +87,12 @@ db.port={{ db_port }}
db.username={{ db_username }}
db.password={{ db_password }}
db.prefix={{ db_prefix }}
+db.whisk.auths={{ db.whisk.auth }}
db.whisk.actions={{ db.whisk.actions }}
db.whisk.activations={{ db.whisk.activations }}
-db.whisk.auths={{ db.whisk.auth }}
+db.whisk.actions.ddoc={{ db.whisk.actions_ddoc }}
+db.whisk.activations.ddoc={{ db.whisk.activations_ddoc }}
+db.whisk.activations.filter.ddoc={{ db.whisk.activations_filter_ddoc }}
apigw.auth.user={{apigw_auth_user}}
apigw.auth.pwd={{apigw_auth_pwd}}
diff --git a/common/scala/src/main/scala/whisk/core/WhiskConfig.scala
b/common/scala/src/main/scala/whisk/core/WhiskConfig.scala
index 56da847b5c..726d1bcabb 100644
--- a/common/scala/src/main/scala/whisk/core/WhiskConfig.scala
+++ b/common/scala/src/main/scala/whisk/core/WhiskConfig.scala
@@ -30,12 +30,13 @@ import whisk.common.{Config, Logging}
* a value, and whose values are default values. A null value in the Map means
there is
* no default value specified, so it must appear in the properties file.
* @param optionalProperties a set of optional properties (which may not be
defined).
- * @param whiskPropertiesFile a File object, the whisk.properties file, which
if given contains the property values.
+ * @param propertiesFile a File object, the whisk.properties file, which if
given contains the property values.
+ * @param env an optional environment to initialize from.
*/
class WhiskConfig(requiredProperties: Map[String, String],
optionalProperties: Set[String] = Set(),
propertiesFile: File = null,
- env: Map[String, String] = sys.env)(implicit val logging:
Logging)
+ env: Map[String, String] = sys.env)(implicit logging:
Logging)
extends Config(requiredProperties, optionalProperties)(env) {
/**
@@ -89,10 +90,10 @@ class WhiskConfig(requiredProperties: Map[String, String],
val dbProtocol = this(WhiskConfig.dbProtocol)
val dbHost = this(WhiskConfig.dbHost)
val dbPort = this(WhiskConfig.dbPort)
- val dbWhisk = this(WhiskConfig.dbWhisk)
+ val dbPrefix = this(WhiskConfig.dbPrefix)
val dbAuths = this(WhiskConfig.dbAuths)
+ val dbWhisk = this(WhiskConfig.dbWhisk)
val dbActivations = this(WhiskConfig.dbActivations)
- val dbPrefix = this(WhiskConfig.dbPrefix)
val mainDockerEndpoint = this(WhiskConfig.mainDockerEndpoint)
@@ -104,11 +105,15 @@ class WhiskConfig(requiredProperties: Map[String, String],
val actionSequenceLimit = this(WhiskConfig.actionSequenceMaxLimit)
val controllerSeedNodes = this(WhiskConfig.controllerSeedNodes)
val controllerLocalBookkeeping =
getAsBoolean(WhiskConfig.controllerLocalBookkeeping, false)
-
}
object WhiskConfig {
+ /**
+ * Reads a key from system environment as if it was part of WhiskConfig.
+ */
+ def readFromEnv(key: String): Option[String] = sys.env.get(asEnvVar(key))
+
private def whiskPropertiesFile: File = {
def propfile(dir: String, recurse: Boolean = false): File =
if (dir != null) {
@@ -153,10 +158,11 @@ object WhiskConfig {
}
}
- def asEnvVar(key: String): String =
+ def asEnvVar(key: String): String = {
if (key != null)
key.replace('.', '_').toUpperCase
else null
+ }
val servicePort = "port"
val dockerRegistry = "docker.registry"
@@ -170,10 +176,13 @@ object WhiskConfig {
val dbPort = "db.port"
val dbUsername = "db.username"
val dbPassword = "db.password"
- val dbWhisk = "db.whisk.actions"
- val dbAuths = "db.whisk.auths"
val dbPrefix = "db.prefix"
+ val dbAuths = "db.whisk.auths"
+ val dbWhisk = "db.whisk.actions"
val dbActivations = "db.whisk.activations"
+ val dbWhiskDesignDoc = "db.whisk.actions.ddoc"
+ val dbActivationsDesignDoc = "db.whisk.activations.ddoc"
+ val dbActivationsFilterDesignDoc = "db.whisk.activations.filter.ddoc"
// these are not private because they are needed
// in the invoker (they are part of the environment
diff --git a/common/scala/src/main/scala/whisk/core/entity/EntityPath.scala
b/common/scala/src/main/scala/whisk/core/entity/EntityPath.scala
index 26e1fb11c1..c4836c3881 100644
--- a/common/scala/src/main/scala/whisk/core/entity/EntityPath.scala
+++ b/common/scala/src/main/scala/whisk/core/entity/EntityPath.scala
@@ -43,6 +43,11 @@ protected[core] class EntityPath private (private val path:
Seq[String]) extends
def namespace: String = path.foldLeft("")((a, b) => if (a != "") a.trim +
EntityPath.PATHSEP + b.trim else b.trim)
/**
+ * @return number of parts in the path.
+ */
+ def segments = path.length
+
+ /**
* Adds segment to path.
*/
def addPath(e: EntityName) = EntityPath(path :+ e.name)
diff --git
a/common/scala/src/main/scala/whisk/core/entity/WhiskActivation.scala
b/common/scala/src/main/scala/whisk/core/entity/WhiskActivation.scala
index 3dca9c1e0b..4073093781 100644
--- a/common/scala/src/main/scala/whisk/core/entity/WhiskActivation.scala
+++ b/common/scala/src/main/scala/whisk/core/entity/WhiskActivation.scala
@@ -23,12 +23,13 @@ import scala.concurrent.Future
import scala.util.Try
import spray.json._
-import spray.json.DefaultJsonProtocol
import spray.json.DefaultJsonProtocol._
import whisk.common.TransactionId
import whisk.core.database.ArtifactStore
import whisk.core.database.DocumentFactory
import whisk.core.database.StaleParameter
+import whisk.core.WhiskConfig
+import whisk.core.WhiskConfig.{dbActivationsDesignDoc,
dbActivationsFilterDesignDoc}
/**
* A WhiskActivation provides an abstraction of the meta-data
@@ -77,8 +78,25 @@ case class WhiskActivation(namespace: EntityPath,
/** This the activation summary as computed by the database view. Strictly
used for testing. */
override def summaryAsJson = {
- val JsObject(fields) = super.summaryAsJson
- JsObject(fields + ("activationId" -> activationId.toJson))
+ import WhiskActivation.instantSerdes
+ val summary = JsObject(super.summaryAsJson.fields + ("activationId" ->
activationId.toJson))
+
+ def actionOrNot() = {
+ if (end != Instant.EPOCH) {
+ Map(
+ "end" -> end.toJson,
+ "duration" -> (duration getOrElse (end.toEpochMilli -
start.toEpochMilli)).toJson,
+ "statusCode" -> response.statusCode.toJson)
+ } else Map.empty
+ }
+
+ if (WhiskActivation.mainDdoc.endsWith(".v2")) {
+ JsObject(
+ summary.fields +
+ ("start" -> start.toJson) ++
+ cause.map(("cause" -> _.toJson)) ++
+ actionOrNot())
+ } else summary
}
def resultAsJson = response.result.toJson.asJsObject
@@ -94,8 +112,10 @@ case class WhiskActivation(namespace: EntityPath,
}
}
- def withoutLogsOrResult =
+ def withoutLogsOrResult = {
copy(response = response.withoutResult, logs =
ActivationLogs()).revision[WhiskActivation](rev)
+ }
+
def withoutLogs = copy(logs =
ActivationLogs()).revision[WhiskActivation](rev)
def withLogs(logs: ActivationLogs) = copy(logs =
logs).revision[WhiskActivation](rev)
}
@@ -119,6 +139,24 @@ object WhiskActivation
}
override val collectionName = "activations"
+
+ // FIXME: reading the design doc from sys.env instead of a canonical
property reader
+ // because WhiskConfig requires a logger, which requires an actor system,
neither of
+ // which are readily available here; rather than introduce significant
refactoring,
+ // defer this fix until WhiskConfig is refactored itself, which is planned
to introduce
+ // type safe properties
+ private val mainDdoc =
WhiskConfig.readFromEnv(dbActivationsDesignDoc).getOrElse("whisks")
+ private val filtersDdoc =
WhiskConfig.readFromEnv(dbActivationsFilterDesignDoc).getOrElse("whisks")
+
+ /** The main view for activations, keyed by namespace, sorted by date. */
+ override lazy val view = WhiskEntityQueries.view(mainDdoc, collectionName)
+
+ /**
+ * A view for activations in a namespace additionally keyed by action name
+ * (and package name if present) sorted by date.
+ */
+ private val filtersView = WhiskEntityQueries.view(filtersDdoc,
collectionName)
+
override implicit val serdes = jsonFormat13(WhiskActivation.apply)
// Caching activations doesn't make much sense in the common case as usually,
@@ -134,18 +172,18 @@ object WhiskActivation
*/
def listActivationsMatchingName(db: ArtifactStore[WhiskActivation],
namespace: EntityPath,
- name: EntityName,
+ path: EntityPath,
skip: Int,
limit: Int,
- docs: Boolean = false,
+ includeDocs: Boolean = false,
since: Option[Instant] = None,
upto: Option[Instant] = None,
stale: StaleParameter = StaleParameter.No)(
implicit transid: TransactionId): Future[Either[List[JsObject],
List[WhiskActivation]]] = {
- import WhiskEntityQueries._
- val convert = if (docs) Some((o: JsObject) => Try { serdes.read(o) }) else
None
- val startKey = List(namespace.addPath(name).asString, since map {
_.toEpochMilli } getOrElse 0)
- val endKey = List(namespace.addPath(name).asString, upto map {
_.toEpochMilli } getOrElse TOP, TOP)
- query(db, viewname(collectionName), startKey, endKey, skip, limit, reduce
= false, stale, convert)
+ import WhiskEntityQueries.TOP
+ val convert = if (includeDocs) Some((o: JsObject) => Try { serdes.read(o)
}) else None
+ val startKey = List(namespace.addPath(path).asString, since map {
_.toEpochMilli } getOrElse 0)
+ val endKey = List(namespace.addPath(path).asString, upto map {
_.toEpochMilli } getOrElse TOP, TOP)
+ query(db, filtersView, startKey, endKey, skip, limit, reduce = false,
stale, convert)
}
}
diff --git a/common/scala/src/main/scala/whisk/core/entity/WhiskStore.scala
b/common/scala/src/main/scala/whisk/core/entity/WhiskStore.scala
index df8d1fe3dd..28addc238a 100644
--- a/common/scala/src/main/scala/whisk/core/entity/WhiskStore.scala
+++ b/common/scala/src/main/scala/whisk/core/entity/WhiskStore.scala
@@ -22,7 +22,6 @@ import java.time.Instant
import scala.concurrent.Future
import scala.language.postfixOps
import scala.util.Try
-
import akka.actor.ActorSystem
import akka.stream.ActorMaterializer
import spray.json.JsObject
@@ -40,6 +39,8 @@ import whisk.core.WhiskConfig.dbProtocol
import whisk.core.WhiskConfig.dbProvider
import whisk.core.WhiskConfig.dbUsername
import whisk.core.WhiskConfig.dbWhisk
+import whisk.core.WhiskConfig.dbWhiskDesignDoc
+import whisk.core.WhiskConfig.dbActivationsDesignDoc
import whisk.core.database.ArtifactStore
import whisk.core.database.ArtifactStoreProvider
import whisk.core.database.DocumentRevisionProvider
@@ -111,7 +112,8 @@ object WhiskEntityStore {
dbPassword -> null,
dbHost -> null,
dbPort -> null,
- dbWhisk -> null)
+ dbWhisk -> null,
+ dbWhiskDesignDoc -> null)
def datastore(config: WhiskConfig)(implicit system: ActorSystem, logging:
Logging, materializer: ActorMaterializer) =
SpiLoader
@@ -129,13 +131,26 @@ object WhiskActivationStore {
dbPassword -> null,
dbHost -> null,
dbPort -> null,
- dbActivations -> null)
+ dbActivations -> null,
+ dbActivationsDesignDoc -> null)
def datastore(config: WhiskConfig)(implicit system: ActorSystem, logging:
Logging, materializer: ActorMaterializer) =
SpiLoader.get[ArtifactStoreProvider].makeStore[WhiskActivation](config,
_.dbActivations, true)
}
/**
+ * A class to type the design doc and view within a database.
+ *
+ * @param ddoc the design document
+ * @param view the view name within the design doc
+ */
+protected[core] class View(ddoc: String, view: String) {
+
+ /** The name of the table to query. */
+ val name = s"$ddoc/$view"
+}
+
+/**
* This object provides some utilities that query the whisk datastore.
* The datastore is assumed to have views (pre-computed joins or indexes)
* for each of the whisk collection types. Entities may be queries by
@@ -169,14 +184,23 @@ object WhiskActivationStore {
*/
object WhiskEntityQueries {
val TOP = "\ufff0"
- val WHISKVIEW = "whisks"
- val ALL = "all"
+
+ /** The design document to use for queries. */
+ // FIXME: reading the design doc from sys.env instead of a canonical
property reader
+ // because WhiskConfig requires a logger, which requires an actor system,
neither of
+ // which are readily available here; rather than introduce significant
refactoring,
+ // defer this fix until WhiskConfig is refactored itself, which is planned
to introduce
+ // type safe properties
+ val designDoc = WhiskConfig.readFromEnv(dbWhiskDesignDoc).getOrElse("whisks")
+
+ /** The view name for the collection, within the design document. */
+ def view(ddoc: String = designDoc, collection: String) = new View(ddoc,
collection)
/**
- * Determines the view name for the collection. There are two cases: a view
- * that is namespace specific, or namespace agnostic..
+ * Name of view in design-doc that lists all entities in that views
regardless of types.
+ * This is uses in the namespace API, and also in tests to check
preconditions.
*/
- def viewname(collection: String): String = s"$WHISKVIEW/$collection"
+ val viewAll: View = view(collection = "all")
/**
* Queries the datastore for all entities in a namespace, and converts the
list of entities
@@ -191,7 +215,7 @@ object WhiskEntityQueries {
implicit val ec = db.executionContext
val startKey = List(namespace.asString)
val endKey = List(namespace.asString, TOP)
- db.query(viewname(ALL), startKey, endKey, 0, 0, includeDocs, descending =
true, reduce = false, stale = stale) map {
+ db.query(viewAll.name, startKey, endKey, 0, 0, includeDocs, descending =
true, reduce = false, stale = stale) map {
_ map { row =>
val value = row.fields("value").asJsObject
val JsString(collection) = value.fields("collection")
@@ -206,6 +230,9 @@ trait WhiskEntityQueries[T] {
val serdes: RootJsonFormat[T]
import WhiskEntityQueries._
+ /** The view name for the collection, within the design document. */
+ lazy val view: View = WhiskEntityQueries.view(collection = collectionName)
+
/**
* Queries the datastore for records from a specific collection (i.e., type)
matching
* the given path (which should be one namespace, or namespace + package
name).
@@ -225,12 +252,12 @@ trait WhiskEntityQueries[T] {
val convert = if (includeDocs) Some((o: JsObject) => Try { serdes.read(o)
}) else None
val startKey = List(path.asString, since map { _.toEpochMilli } getOrElse
0)
val endKey = List(path.asString, upto map { _.toEpochMilli } getOrElse
TOP, TOP)
- query(db, viewname(collectionName), startKey, endKey, skip, limit, reduce
= false, stale, convert)
+ query(db, view, startKey, endKey, skip, limit, reduce = false, stale,
convert)
}
protected[entity] def query[A <: WhiskEntity](
db: ArtifactStore[A],
- view: String,
+ view: View,
startKey: List[Any],
endKey: List[Any],
skip: Int,
@@ -240,7 +267,7 @@ trait WhiskEntityQueries[T] {
convert: Option[JsObject => Try[T]])(implicit transid: TransactionId):
Future[Either[List[JsObject], List[T]]] = {
implicit val ec = db.executionContext
val includeDocs = convert.isDefined
- db.query(view, startKey, endKey, skip, limit, includeDocs, true, reduce,
stale) map { rows =>
+ db.query(view.name, startKey, endKey, skip, limit, includeDocs, true,
reduce, stale) map { rows =>
convert map { fn =>
Right(rows flatMap { row =>
fn(row.fields("doc").asJsObject) toOption
diff --git a/common/scala/src/main/scala/whisk/http/ErrorResponse.scala
b/common/scala/src/main/scala/whisk/http/ErrorResponse.scala
index 09c3bfe74f..719a6c578e 100644
--- a/common/scala/src/main/scala/whisk/http/ErrorResponse.scala
+++ b/common/scala/src/main/scala/whisk/http/ErrorResponse.scala
@@ -113,8 +113,7 @@ object Messages {
val abnormalInitialization = "The action did not initialize and exited
unexpectedly."
val abnormalRun = "The action did not produce a valid response and exited
unexpectedly."
val memoryExhausted = "The action exhausted its memory and was aborted."
- def badEntityName(value: String) = s"Parameter is not a valid value for a
entity name: $value"
- def badNamespace(value: String) = s"Parameter is not a valid value for a
namespace: $value"
+ def badNameFilter(value: String) = s"Parameter may be a 'simple' name or
'package-name/simple' name: $value"
def badEpoch(value: String) = s"Parameter is not a valid value for epoch
seconds: $value"
/** Error message for size conformance. */
diff --git
a/core/controller/src/main/scala/whisk/core/controller/Activations.scala
b/core/controller/src/main/scala/whisk/core/controller/Activations.scala
index 0d7dbbc652..0403d1c03f 100644
--- a/core/controller/src/main/scala/whisk/core/controller/Activations.scala
+++ b/core/controller/src/main/scala/whisk/core/controller/Activations.scala
@@ -43,6 +43,25 @@ import whisk.http.Messages
object WhiskActivationsApi {
protected[core] val maxActivationLimit = 200
+
+ /** Custom unmarshaller for query parameters "name" into valid
package/action name path. */
+ private implicit val stringToRestrictedEntityPath: Unmarshaller[String,
Option[EntityPath]] =
+ Unmarshaller.strict[String, Option[EntityPath]] { value =>
+ Try { EntityPath(value) } match {
+ case Success(e) if e.segments <= 2 => Some(e)
+ case _ if value.trim.isEmpty => None
+ case _ => throw new
IllegalArgumentException(Messages.badNameFilter(value))
+ }
+ }
+
+ /** Custom unmarshaller for query parameters "since" and "upto" into a valid
Instant. */
+ private implicit val stringToInstantDeserializer: Unmarshaller[String,
Instant] =
+ Unmarshaller.strict[String, Instant] { value =>
+ Try { Instant.ofEpochMilli(value.toLong) } match {
+ case Success(e) => e
+ case Failure(t) => throw new
IllegalArgumentException(Messages.badEpoch(value))
+ }
+ }
}
/** A trait implementing the activations API. */
@@ -118,24 +137,27 @@ trait WhiskActivationsApi extends Directives with
AuthenticatedRouteProvider wit
* - 500 Internal Server Error
*/
private def list(namespace: EntityPath)(implicit transid: TransactionId) = {
+ import WhiskActivationsApi.stringToRestrictedEntityPath
+ import WhiskActivationsApi.stringToInstantDeserializer
+
parameter(
'skip ? 0,
'limit ? collection.listLimit,
'count ? false,
'docs ? false,
- 'name.as[EntityName] ?,
+ 'name.as[Option[EntityPath]] ?,
'since.as[Instant] ?,
'upto.as[Instant] ?) { (skip, limit, count, docs, name, since, upto) =>
val cappedLimit = if (limit == 0) WhiskActivationsApi.maxActivationLimit
else limit
// regardless of limit, cap at maxActivationLimit (200) records, client
must paginate
if (cappedLimit <= WhiskActivationsApi.maxActivationLimit) {
- val activations = name match {
+ val activations = name.flatten match {
case Some(action) =>
WhiskActivation.listActivationsMatchingName(
activationStore,
namespace,
- action,
+ action.last.toPath,
skip,
cappedLimit,
docs,
@@ -215,31 +237,4 @@ trait WhiskActivationsApi extends Directives with
AuthenticatedRouteProvider wit
docid,
(activation: WhiskActivation) =>
logStore.fetchLogs(activation).map(_.toJsonObject))
}
-
- /** Custom unmarshaller for query parameters "name" into valid entity name.
*/
- private implicit val stringToEntityName: Unmarshaller[String, EntityName] =
- Unmarshaller.strict[String, EntityName] { value =>
- Try { EntityName(value) } match {
- case Success(e) => e
- case Failure(t) => throw new
IllegalArgumentException(Messages.badEntityName(value))
- }
- }
-
- /** Custom unmarshaller for query parameters "name" into valid namespace. */
- private implicit val stringToNamespace: Unmarshaller[String, EntityPath] =
- Unmarshaller.strict[String, EntityPath] { value =>
- Try { EntityPath(value) } match {
- case Success(e) => e
- case Failure(t) => throw new
IllegalArgumentException(Messages.badNamespace(value))
- }
- }
-
- /** Custom unmarshaller for query parameters "since" and "upto" into a valid
Instant. */
- private implicit val stringToInstantDeserializer: Unmarshaller[String,
Instant] =
- Unmarshaller.strict[String, Instant] { value =>
- Try { Instant.ofEpochMilli(value.toLong) } match {
- case Success(e) => e
- case Failure(t) => throw new
IllegalArgumentException(Messages.badEpoch(value))
- }
- }
}
diff --git a/core/invoker/src/main/scala/whisk/core/invoker/Invoker.scala
b/core/invoker/src/main/scala/whisk/core/invoker/Invoker.scala
index 8c57206204..192100dcf5 100644
--- a/core/invoker/src/main/scala/whisk/core/invoker/Invoker.scala
+++ b/core/invoker/src/main/scala/whisk/core/invoker/Invoker.scala
@@ -137,19 +137,22 @@ object Invoker {
if (invokerName.trim.isEmpty) {
abort("Invoker name can't be empty to use dynamicId assignment.")
}
+
logger.info(this, s"invokerReg: creating zkClient to
${config.zookeeperHost}")
val retryPolicy = new RetryUntilElapsed(5000, 500) // retry at 500ms
intervals until 5 seconds have elapsed
val zkClient = CuratorFrameworkFactory.newClient(config.zookeeperHost,
retryPolicy)
zkClient.start()
- zkClient.blockUntilConnected();
+ zkClient.blockUntilConnected()
logger.info(this, "invokerReg: connected to zookeeper")
+
val myIdPath = "/invokers/idAssignment/mapping/" + invokerName
val assignedId = Option(zkClient.checkExists().forPath(myIdPath))
match {
case None =>
- // path doesn't exist ==> no previous mapping for this invoker
+ // path doesn't exist -> no previous mapping for this invoker
logger.info(this, s"invokerReg: no prior assignment of id for
invoker $invokerName")
val idCounter = new SharedCount(zkClient,
"/invokers/idAssignment/counter", 0)
idCounter.start()
+
def assignId(): Int = {
val current = idCounter.getVersionedValue()
if (idCounter.trySetCount(current, current.getValue() + 1)) {
@@ -158,22 +161,26 @@ object Invoker {
assignId()
}
}
+
val newId = assignId()
idCounter.close()
zkClient.create().creatingParentContainersIfNeeded().forPath(myIdPath,
BigInt(newId).toByteArray)
logger.info(this, s"invokerReg: invoker ${invokerName} was
assigned invokerId ${newId}")
newId
+
case Some(_) =>
- // path already exists ==> there is a previous mapping for this
invoker we should use
+ // path already exists -> there is a previous mapping for this
invoker we should use
val rawOldId = zkClient.getData().forPath(myIdPath)
val oldId = BigInt(rawOldId).intValue
logger.info(this, s"invokerReg: invoker ${invokerName} was
assigned its previous invokerId ${oldId}")
oldId
}
+
zkClient.close()
assignedId
}
- val invokerInstance = InstanceId(assignedInvokerId);
+
+ val invokerInstance = InstanceId(assignedInvokerId)
val msgProvider = SpiLoader.get[MessagingProvider]
val producer = msgProvider.getProducer(config, ec)
val invoker = try {
diff --git
a/tests/src/test/scala/whisk/core/controller/test/ActivationsApiTests.scala
b/tests/src/test/scala/whisk/core/controller/test/ActivationsApiTests.scala
index 548c612f14..9f99eda515 100644
--- a/tests/src/test/scala/whisk/core/controller/test/ActivationsApiTests.scala
+++ b/tests/src/test/scala/whisk/core/controller/test/ActivationsApiTests.scala
@@ -80,7 +80,7 @@ class ActivationsApiTests extends ControllerTestCommon with
WhiskActivationsApi
WhiskActivation(namespace, actionName, creds.subject, ActivationId(),
start = Instant.now, end = Instant.now)
}.toList
activations foreach { put(activationStore, _) }
- waitOnView(activationStore, namespace.root, 2,
WhiskActivation.collectionName)
+ waitOnView(activationStore, namespace.root, 2, WhiskActivation.view)
whisk.utils.retry {
Get(s"$collectionPath") ~> Route.seal(routes(creds)) ~> check {
status should be(OK)
@@ -152,7 +152,7 @@ class ActivationsApiTests extends ControllerTestCommon with
WhiskActivationsApi
response = ActivationResponse.success(Some(JsNumber(5))))
}.toList
activations foreach { put(activationStore, _) }
- waitOnView(activationStore, namespace.root, 2,
WhiskActivation.collectionName)
+ waitOnView(activationStore, namespace.root, 2, WhiskActivation.view)
whisk.utils.retry {
Get(s"$collectionPath?docs=true") ~> Route.seal(routes(creds)) ~> check {
@@ -216,7 +216,7 @@ class ActivationsApiTests extends ControllerTestCommon with
WhiskActivationsApi
start = now.plusSeconds(30),
end = now.plusSeconds(20))) // should match
activations foreach { put(activationStore, _) }
- waitOnView(activationStore, namespace.root, activations.length,
WhiskActivation.collectionName)
+ waitOnView(activationStore, namespace.root, activations.length,
WhiskActivation.view)
// get between two time stamps
whisk.utils.retry {
@@ -267,6 +267,20 @@ class ActivationsApiTests extends ControllerTestCommon
with WhiskActivationsApi
}
//// GET /activations?name=xyz
+ it should "accept valid name parameters and reject invalid ones" in {
+ implicit val tid = transid()
+
+ Seq(("", OK), ("name=", OK), ("name=abc", OK), ("name=abc/xyz", OK),
("name=abc/xyz/123", BadRequest)).foreach {
+ case (p, s) =>
+ Get(s"$collectionPath?$p") ~> Route.seal(routes(creds)) ~> check {
+ status should be(s)
+ if (s == BadRequest) {
+ responseAs[String] should
include(Messages.badNameFilter(p.drop(5)))
+ }
+ }
+ }
+ }
+
it should "get summary activation by namespace and action name" in {
implicit val tid = transid()
@@ -292,18 +306,46 @@ class ActivationsApiTests extends ControllerTestCommon
with WhiskActivationsApi
end = Instant.now)
}.toList
activations foreach { put(activationStore, _) }
- waitOnView(activationStore, namespace.root, 2,
WhiskActivation.collectionName)
+
+ val activationsInPackage = (1 to 2).map { i =>
+ WhiskActivation(
+ namespace,
+ EntityName(s"xyz"),
+ creds.subject,
+ ActivationId(),
+ start = Instant.now,
+ end = Instant.now,
+ annotations = Parameters("path", s"${namespace.asString}/pkg/xyz"))
+ }.toList
+ activationsInPackage foreach { put(activationStore, _) }
+
+ waitOnView(activationStore, namespace.root, 4, WhiskActivation.view)
whisk.utils.retry {
Get(s"$collectionPath?name=xyz") ~> Route.seal(routes(creds)) ~> check {
status should be(OK)
val response = responseAs[List[JsObject]]
- activations.length should be(response.length)
- activations forall { a =>
+ val allActivations = activations ++ activationsInPackage
+ allActivations.length should be(response.length)
+ allActivations forall { a =>
response contains a.summaryAsJson
} should be(true)
}
}
+
+ // this is not yet ready, the v2 views must be activated
+ if (false) {
+ whisk.utils.retry {
+ Get(s"$collectionPath?name=pkg/xyz") ~> Route.seal(routes(creds)) ~>
check {
+ status should be(OK)
+ val response = responseAs[List[JsObject]]
+ activationsInPackage.length should be(response.length)
+ activationsInPackage forall { a =>
+ response contains a.summaryAsJson
+ } should be(true)
+ }
+ }
+ }
}
it should "reject activation list when limit is greater than maximum allowed
value" in {
@@ -311,8 +353,9 @@ class ActivationsApiTests extends ControllerTestCommon with
WhiskActivationsApi
val exceededMaxLimit = WhiskActivationsApi.maxActivationLimit + 1
val response = Get(s"$collectionPath?limit=$exceededMaxLimit") ~>
Route.seal(routes(creds)) ~> check {
val response = responseAs[String]
- response should include(
- Messages.maxActivationLimitExceeded(exceededMaxLimit,
WhiskActivationsApi.maxActivationLimit))
+ response should include {
+ Messages.maxActivationLimitExceeded(exceededMaxLimit,
WhiskActivationsApi.maxActivationLimit)
+ }
status should be(BadRequest)
}
}
diff --git a/tests/src/test/scala/whisk/core/database/test/DbUtils.scala
b/tests/src/test/scala/whisk/core/database/test/DbUtils.scala
index a01e04fd90..3c77f4e204 100644
--- a/tests/src/test/scala/whisk/core/database/test/DbUtils.scala
+++ b/tests/src/test/scala/whisk/core/database/test/DbUtils.scala
@@ -88,7 +88,7 @@ trait DbUtils extends TransactionCounter {
* where the step performs a direct db query to retrieve the view and check
the count
* matches the given value.
*/
- def waitOnView[Au](db: ArtifactStore[Au], namespace: EntityName, count: Int,
viewName: String)(
+ def waitOnView[Au](db: ArtifactStore[Au], namespace: EntityName, count: Int,
view: View)(
implicit context: ExecutionContext,
transid: TransactionId,
timeout: Duration) = {
@@ -96,11 +96,10 @@ trait DbUtils extends TransactionCounter {
() => {
val startKey = List(namespace.asString)
val endKey = List(namespace.asString, WhiskEntityQueries.TOP)
- db.query(WhiskEntityQueries.viewname(viewName), startKey, endKey, 0,
0, false, true, false, StaleParameter.No) map {
- l =>
- if (l.length != count) {
- throw RetryOp()
- } else true
+ db.query(view.name, startKey, endKey, 0, 0, false, true, false,
StaleParameter.No) map { l =>
+ if (l.length != count) {
+ throw RetryOp()
+ } else true
}
},
timeout)
diff --git a/tests/src/test/scala/whisk/core/entity/test/ViewTests.scala
b/tests/src/test/scala/whisk/core/entity/test/ViewTests.scala
index 234717047a..55b2e69c6a 100644
--- a/tests/src/test/scala/whisk/core/entity/test/ViewTests.scala
+++ b/tests/src/test/scala/whisk/core/entity/test/ViewTests.scala
@@ -94,7 +94,7 @@ class ViewTests
val result =
Await.result(listAllInNamespace(store, ns.root, false,
StaleParameter.No), dbOpTimeout).values.toList.flatten
val expected = entities filter { _.namespace.root.toPath == ns }
- result.length should be(expected.length)
+ result should have length expected.length
result should contain theSameElementsAs expected.map(_.summaryAsJson)
}
@@ -108,7 +108,7 @@ class ViewTests
.get
.map(e => e)
val expected = entities filter { _.namespace.root.toPath == ns }
- result.length should be(expected.length)
+ result should have length expected.length
result should contain theSameElementsAs expected.map(_.summaryAsJson)
}
@@ -120,10 +120,8 @@ class ViewTests
}
val expected = entities filter { !_.isInstanceOf[WhiskActivation] } filter
{ _.namespace.root.toPath == ns }
map.get(WhiskActivation.collectionName) should be(None)
- result.length should be(expected.length)
- expected forall { e =>
- result contains e.summaryAsJson
- } should be(true)
+ result should have length expected.length
+ result should contain theSameElementsAs expected.map(_.summaryAsJson)
}
def resolveListMethodForKind(kind: String) = kind match {
@@ -140,16 +138,13 @@ class ViewTests
f: (WhiskEntity) =>
Boolean)(implicit entities: Seq[WhiskEntity]) = {
implicit val tid = transid()
val q = resolveListMethodForKind(kind)
- val result = Await.result(q.listCollectionInNamespace(store, ns, 0, 0,
stale = StaleParameter.No) map {
- _.left.get.map(e => e)
- }, dbOpTimeout)
+ val result =
+ Await.result(q.listCollectionInNamespace(store, ns, 0, 0, stale =
StaleParameter.No).map(_.left.get), dbOpTimeout)
val expected = entities filter { e =>
f(e) && e.namespace.root.toPath == ns
}
- result.length should be(expected.length)
- expected forall { e =>
- result contains e.summaryAsJson
- } should be(true)
+ result should have length expected.length
+ result should contain theSameElementsAs expected.map(_.summaryAsJson)
}
def getKindInNamespaceWithDoc[T](ns: EntityPath, kind: String, f:
(WhiskEntity) => Boolean)(
@@ -158,17 +153,14 @@ class ViewTests
val q = resolveListMethodForKind(kind)
val result =
Await.result(
- q.listCollectionInNamespace(entityStore, ns, 0, 0, includeDocs = true,
stale = StaleParameter.No) map {
- _.right.get
- },
+ q.listCollectionInNamespace(entityStore, ns, 0, 0, includeDocs = true,
stale = StaleParameter.No)
+ .map(_.right.get),
dbOpTimeout)
val expected = entities filter { e =>
f(e) && e.namespace.root.toPath == ns
}
- result.length should be(expected.length)
- expected forall { e =>
- result contains e
- } should be(true)
+ result should have length expected.length
+ result should contain theSameElementsAs expected
}
def getKindInNamespaceByName[Au <: WhiskEntity](store: ArtifactStore[Au],
@@ -180,18 +172,14 @@ class ViewTests
implicit val tid = transid()
val q = resolveListMethodForKind(kind)
val result =
- Await.result(q.listCollectionInNamespace(store, ns.addPath(name), 0, 0,
stale = StaleParameter.No) map {
- _.left.get map { e =>
- e
- }
- }, dbOpTimeout)
+ Await.result(
+ q.listCollectionInNamespace(store, ns.addPath(name), 0, 0, stale =
StaleParameter.No).map(_.left.get),
+ dbOpTimeout)
val expected = entities filter { e =>
f(e) && e.namespace.root.toPath == ns
}
- result.length should be(expected.length)
- expected forall { e =>
- result contains e.summaryAsJson
- } should be(true)
+ result should have length expected.length
+ result should contain theSameElementsAs expected.map(_.summaryAsJson)
}
def getActivationsInNamespaceByName(store: ArtifactStore[WhiskActivation],
@@ -200,36 +188,30 @@ class ViewTests
f: (WhiskEntity) => Boolean)(implicit
entities: Seq[WhiskEntity]) = {
implicit val tid = transid()
val result =
- Await.result(WhiskActivation.listActivationsMatchingName(store, ns,
name, 0, 0, stale = StaleParameter.No) map {
- _.left.get map { e =>
- e
- }
- }, dbOpTimeout)
+ Await.result(
+ WhiskActivation
+ .listActivationsMatchingName(store, ns, name.toPath, 0, 0, stale =
StaleParameter.No)
+ .map(_.left.get),
+ dbOpTimeout)
val expected = entities filter { e =>
f(e) && e.namespace.root.toPath == ns
}
- result.length should be(expected.length)
- expected forall { e =>
- result contains e.summaryAsJson
- } should be(true)
+ result should have length expected.length
+ result should contain theSameElementsAs expected.map(_.summaryAsJson)
}
def getKindInPackage(ns: EntityPath, kind: String, f: (WhiskEntity) =>
Boolean)(
implicit entities: Seq[WhiskEntity]) = {
implicit val tid = transid()
val q = resolveListMethodForKind(kind)
- val result = Await.result(q.listCollectionInNamespace(entityStore, ns, 0,
0, stale = StaleParameter.No) map {
- _.left.get map { e =>
- e
- }
- }, dbOpTimeout)
+ val result = Await.result(
+ q.listCollectionInNamespace(entityStore, ns, 0, 0, stale =
StaleParameter.No).map(_.left.get),
+ dbOpTimeout)
val expected = entities filter { e =>
f(e) && e.namespace == ns
}
- result.length should be(expected.length)
- expected forall { e =>
- result contains e.summaryAsJson
- } should be(true)
+ result should have length expected.length
+ result should contain theSameElementsAs expected.map(_.summaryAsJson)
}
def getActivationsInNamespaceByNameSortedByDate(store:
ArtifactStore[WhiskActivation],
@@ -244,16 +226,13 @@ class ViewTests
implicit val tid = transid()
val result = Await.result(
WhiskActivation
- .listActivationsMatchingName(store, ns, name, skip, count, false,
start, end, StaleParameter.No) map {
- _.left.get map { e =>
- e
- }
- },
+ .listActivationsMatchingName(store, ns, name.toPath, skip, count,
false, start, end, StaleParameter.No)
+ .map(_.left.get),
dbOpTimeout)
val expected = entities filter { e =>
f(e) && e.namespace.root.toPath == ns
} sortBy { case (e: WhiskActivation) => e.start.toEpochMilli; case _ => 0
} map { _.summaryAsJson }
- result.length should be(expected.length)
+ result should have length expected.length
result should be(expected reverse)
}
@@ -306,8 +285,8 @@ class ViewTests
WhiskPackage(namespace2, aname(), Some(Binding(namespace1.root,
aname()))))
entities foreach { put(entityStore, _) }
- waitOnView(entityStore, namespace1.root, 15, WhiskEntityQueries.ALL)
- waitOnView(entityStore, namespace2.root, 14, WhiskEntityQueries.ALL)
+ waitOnView(entityStore, namespace1.root, 15, WhiskEntityQueries.viewAll)
+ waitOnView(entityStore, namespace2.root, 14, WhiskEntityQueries.viewAll)
getAllInNamespace(entityStore, namespace1)
getKindInNamespace(entityStore, namespace1, "actions", {
@@ -375,8 +354,8 @@ class ViewTests
WhiskActivation(namespace2, actionName, Subject(), ActivationId(), start
= now, end = now))
entities foreach { put(activationStore, _) }
- waitOnView(activationStore, namespace1.root, 2,
WhiskActivation.collectionName)
- waitOnView(activationStore, namespace2.root, 3,
WhiskActivation.collectionName)
+ waitOnView(activationStore, namespace1.root, 2, WhiskActivation.view)
+ waitOnView(activationStore, namespace2.root, 3, WhiskActivation.view)
getAllActivationsInNamespace(activationStore, namespace1)
getKindInNamespace(activationStore, namespace1, "activations", {
@@ -431,7 +410,7 @@ class ViewTests
end = now.plusSeconds(20)))
entities foreach { put(activationStore, _) }
- waitOnView(activationStore, namespace1.root, entities.length,
WhiskActivation.collectionName)
+ waitOnView(activationStore, namespace1.root, entities.length,
WhiskActivation.view)
getActivationsInNamespaceByNameSortedByDate(
activationStore,
@@ -472,7 +451,7 @@ class ViewTests
Seq(WhiskAction(namespace1, aname(), jsDefault("??")),
WhiskAction(namespace1, aname(), jsDefault("??")))
entities foreach { put(entityStore, _) }
- waitOnView(entityStore, namespace1.root, entities.length,
WhiskEntityQueries.ALL)
+ waitOnView(entityStore, namespace1.root, entities.length,
WhiskEntityQueries.viewAll)
getKindInNamespaceWithDoc[WhiskAction](namespace1, "actions", {
case (e: WhiskAction) => true
case (_) => false
----------------------------------------------------------------
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