You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@openwhisk.apache.org by ra...@apache.org on 2018/03/06 11:53:44 UTC

[incubator-openwhisk] branch master updated: Make ActivationId implementation leaner. (#3362)

This is an automated email from the ASF dual-hosted git repository.

rabbah pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/incubator-openwhisk.git


The following commit(s) were added to refs/heads/master by this push:
     new 9132ddf  Make ActivationId implementation leaner. (#3362)
9132ddf is described below

commit 9132ddf1ec9dacfc1d74f46b516138397018b327
Author: Markus Thömmes <ma...@me.com>
AuthorDate: Tue Mar 6 12:53:42 2018 +0100

    Make ActivationId implementation leaner. (#3362)
    
    * Rework activation id to ignore uuid semantics
    * Take out arg normalizer
    * Rename apply to generate for more explicitness
---
 .../scala/whisk/core/entity/ActivationId.scala     | 112 +++++++--------------
 .../scala/whisk/core/controller/Activations.scala  |  14 +--
 .../connector/tests/CompletionMessageTests.scala   |   6 +-
 .../logging/SplunkLogStoreTests.scala              |   2 +-
 .../test/DockerToActivationLogStoreTests.scala     |   8 +-
 .../containerpool/test/ContainerPoolTests.scala    |   2 +-
 .../containerpool/test/ContainerProxyTests.scala   |   2 +-
 .../actions/test/SequenceAccountingTests.scala     |   4 +-
 .../core/controller/test/ActivationsApiTests.scala |  74 ++++++++++----
 .../controller/test/ControllerTestCommon.scala     |   2 +-
 .../core/controller/test/TriggersApiTests.scala    |   4 +-
 .../core/controller/test/WebActionsApiTests.scala  |   4 +-
 .../whisk/core/database/test/RemoveLogsTests.scala |   4 +-
 .../whisk/core/entity/test/DatastoreTests.scala    |  12 +--
 .../scala/whisk/core/entity/test/SchemaTests.scala |  18 ++--
 .../scala/whisk/core/entity/test/ViewTests.scala   |  20 ++--
 .../whisk/core/entity/test/WhiskEntityTests.scala  |   4 +-
 .../loadBalancer/test/LoadBalancerDataTests.scala  |  10 +-
 18 files changed, 150 insertions(+), 152 deletions(-)

diff --git a/common/scala/src/main/scala/whisk/core/entity/ActivationId.scala b/common/scala/src/main/scala/whisk/core/entity/ActivationId.scala
index 0a1cb25..85c59be 100644
--- a/common/scala/src/main/scala/whisk/core/entity/ActivationId.scala
+++ b/common/scala/src/main/scala/whisk/core/entity/ActivationId.scala
@@ -17,18 +17,13 @@
 
 package whisk.core.entity
 
-import java.math.BigInteger
-
-import scala.language.postfixOps
-import scala.util.Failure
-import scala.util.Success
-import scala.util.Try
-
 import spray.json.DefaultJsonProtocol.StringJsonFormat
 import spray.json._
+import whisk.http.Messages
 
 import whisk.core.entity.size._
-import whisk.http.Messages
+
+import scala.util.{Failure, Success, Try}
 
 /**
  * An activation id, is a unique id assigned to activations (invoke action or fire trigger).
@@ -38,97 +33,64 @@ import whisk.http.Messages
  * The constructor is private so that argument requirements are checked and normalized
  * before creating a new instance.
  *
- * @param id the activation id, required not null
+ * @param asString the activation id
  */
-protected[whisk] class ActivationId private (private val id: java.util.UUID) extends AnyVal {
-  def asString = toString
-  override def toString = id.toString.replaceAll("-", "")
-  def toJsObject = JsObject("activationId" -> toString.toJson)
+protected[whisk] class ActivationId private (val asString: String) extends AnyVal {
+  override def toString: String = asString
+  def toJsObject: JsObject = JsObject("activationId" -> asString.toJson)
 }
 
-protected[core] object ActivationId extends ArgNormalizer[ActivationId] {
+protected[core] object ActivationId {
 
   protected[core] trait ActivationIdGenerator {
-    def make(): ActivationId = new ActivationId(UUIDs.randomUUID())
+    def make(): ActivationId = ActivationId.generate()
   }
 
-  /**
-   * Unapply method for convenience of case matching.
-   */
-  protected[core] def unapply(name: String): Option[ActivationId] = {
-    Try { ActivationId(name) } toOption
-  }
+  /** Checks if the current character is hexadecimal */
+  private def isHexadecimal(c: Char) = c.isDigit || c == 'a' || c == 'b' || c == 'c' || c == 'd' || c == 'e' || c == 'f'
 
   /**
-   * Creates an activation id from a java.util.UUID.
+   * Parses an activation id from a string.
    *
-   * @param uuid the activation id as UUID
+   * @param id the activation id as string
    * @return ActivationId instance
-   * @throws IllegalArgumentException is argument is not defined
    */
-  @throws[IllegalArgumentException]
-  private def apply(uuid: java.util.UUID): ActivationId = {
-    require(uuid != null, "argument undefined")
-    new ActivationId(uuid)
+  def parse(id: String): Try[ActivationId] = {
+    val length = id.length
+    if (length != 32) {
+      Failure(
+        new IllegalArgumentException(Messages.activationIdLengthError(SizeError("Activation id", length.B, 32.B))))
+    } else if (!id.forall(isHexadecimal)) {
+      Failure(new IllegalArgumentException(Messages.activationIdIllegal))
+    } else {
+      Success(new ActivationId(id))
+    }
   }
 
   /**
    * Generates a random activation id using java.util.UUID factory.
    *
+   * Uses fast path to generate the ActivationId without additional requirement checks.
+   *
    * @return new ActivationId
    */
-  protected[core] def apply(): ActivationId = new ActivationId(UUIDs.randomUUID())
+  protected[core] def generate(): ActivationId = new ActivationId(UUIDs.randomUUID().toString.filterNot(_ == '-'))
 
-  /**
-   * Overrides factory method so that string is not interpreted as number
-   * e.g., 2e11.
-   */
-  override protected[entity] def factory(s: String): ActivationId = {
-    serdes.read(JsString(s))
-  }
-
-  override protected[core] implicit val serdes = new RootJsonFormat[ActivationId] {
+  protected[core] implicit val serdes: RootJsonFormat[ActivationId] = new RootJsonFormat[ActivationId] {
     def write(d: ActivationId) = JsString(d.toString)
 
-    def read(value: JsValue) =
-      Try {
-        value match {
-          case JsString(s) => stringToActivationId(s)
-          case JsNumber(n) => bigIntToActivationId(n.toBigInt)
-          case _           => deserializationError(Messages.activationIdIllegal)
-        }
-      } match {
-        case Success(a)                                 => a
-        case Failure(DeserializationException(t, _, _)) => deserializationError(t)
-        case Failure(t)                                 => deserializationError(Messages.activationIdIllegal)
+    def read(value: JsValue): ActivationId = {
+      val parsed = value match {
+        case JsString(s) => ActivationId.parse(s)
+        case JsNumber(n) => ActivationId.parse(n.toString)
+        case _           => Failure(DeserializationException(Messages.activationIdIllegal))
       }
-  }
 
-  private def bigIntToActivationId(n: BigInt): ActivationId = {
-    // print the bigint using base 10 then convert to base 16
-    val bn = new BigInteger(n.bigInteger.toString(10), 16)
-    // mask out the upper 16 ints
-    val lb = bn.and(new BigInteger("f" * 16, 16))
-    // drop the lower 16 ints
-    val up = bn.shiftRight(16)
-    val uuid = new java.util.UUID(lb.longValue, up.longValue)
-    ActivationId(uuid)
-  }
-
-  private def stringToActivationId(s: String): ActivationId = {
-    if (!s.contains("-")) {
-      if (s.length == 32) {
-        val lb = new BigInteger(s.substring(0, 16), 16)
-        val up = new BigInteger(s.substring(16, 32), 16)
-        val uuid = new java.util.UUID(lb.longValue, up.longValue)
-        ActivationId(uuid)
-      } else
-        deserializationError {
-          Messages.activationIdLengthError(SizeError("Activation id", s.length.B, 32.B))
-        }
-    } else {
-      ActivationId(java.util.UUID.fromString(s))
+      parsed match {
+        case Success(aid)                         => aid
+        case Failure(t: IllegalArgumentException) => deserializationError(t.getMessage)
+        case Failure(_)                           => deserializationError(Messages.activationIdIllegal)
+      }
     }
-
   }
 }
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 6cc4ef7..3c57d0d 100644
--- a/core/controller/src/main/scala/whisk/core/controller/Activations.scala
+++ b/core/controller/src/main/scala/whisk/core/controller/Activations.scala
@@ -27,7 +27,6 @@ import akka.http.scaladsl.model.StatusCodes.BadRequest
 import akka.http.scaladsl.server.Directives
 import akka.http.scaladsl.unmarshalling._
 
-import spray.json._
 import spray.json.DefaultJsonProtocol.RootJsObjectFormat
 import whisk.common.TransactionId
 import whisk.core.containerpool.logging.LogStore
@@ -93,10 +92,10 @@ trait WhiskActivationsApi extends Directives with AuthenticatedRouteProvider wit
 
   /** Validated entity name as an ActivationId from the matched path segment. */
   protected override def entityname(n: String) = {
-    val activationId = Try { ActivationId(n) }
+    val activationId = ActivationId.parse(n)
     validate(activationId.isSuccess, activationId match {
-      case Failure(DeserializationException(t, _, _)) => t
-      case _                                          => Messages.activationIdIllegal
+      case Failure(t: IllegalArgumentException) => t.getMessage
+      case _                                    => Messages.activationIdIllegal
     }) & extract(_ => n)
   }
 
@@ -118,10 +117,11 @@ trait WhiskActivationsApi extends Directives with AuthenticatedRouteProvider wit
   /** Dispatches resource to the proper handler depending on context. */
   protected override def dispatchOp(user: Identity, op: Privilege, resource: Resource)(
     implicit transid: TransactionId) = {
-    resource.entity match {
-      case Some(ActivationId(id)) =>
+
+    resource.entity.flatMap(e => ActivationId.parse(e).toOption) match {
+      case Some(aid) =>
         op match {
-          case READ => fetch(user, resource.namespace, id)
+          case READ => fetch(user, resource.namespace, aid)
           case _    => reject // should not get here
         }
       case None =>
diff --git a/tests/src/test/scala/whisk/core/connector/tests/CompletionMessageTests.scala b/tests/src/test/scala/whisk/core/connector/tests/CompletionMessageTests.scala
index 7a50111..3a9a16e 100644
--- a/tests/src/test/scala/whisk/core/connector/tests/CompletionMessageTests.scala
+++ b/tests/src/test/scala/whisk/core/connector/tests/CompletionMessageTests.scala
@@ -45,7 +45,7 @@ class CompletionMessageTests extends FlatSpec with Matchers {
     namespace = EntityPath("ns"),
     name = EntityName("a"),
     Subject(),
-    activationId = ActivationId(),
+    activationId = ActivationId.generate(),
     start = Instant.now(),
     end = Instant.now(),
     response = ActivationResponse.success(Some(JsObject("res" -> JsNumber(1)))),
@@ -53,7 +53,7 @@ class CompletionMessageTests extends FlatSpec with Matchers {
     duration = Some(123))
 
   it should "serialize a left completion message" in {
-    val m = CompletionMessage(TransactionId.testing, Left(ActivationId()), InstanceId(0))
+    val m = CompletionMessage(TransactionId.testing, Left(ActivationId.generate()), InstanceId(0))
     m.serialize shouldBe JsObject(
       "transid" -> m.transid.toJson,
       "response" -> m.response.left.get.toJson,
@@ -69,7 +69,7 @@ class CompletionMessageTests extends FlatSpec with Matchers {
   }
 
   it should "deserialize a left completion message" in {
-    val m = CompletionMessage(TransactionId.testing, Left(ActivationId()), InstanceId(0))
+    val m = CompletionMessage(TransactionId.testing, Left(ActivationId.generate()), InstanceId(0))
     CompletionMessage.parse(m.serialize) shouldBe Success(m)
   }
 
diff --git a/tests/src/test/scala/whisk/core/containerpool/logging/SplunkLogStoreTests.scala b/tests/src/test/scala/whisk/core/containerpool/logging/SplunkLogStoreTests.scala
index 60213dc..86541ca 100644
--- a/tests/src/test/scala/whisk/core/containerpool/logging/SplunkLogStoreTests.scala
+++ b/tests/src/test/scala/whisk/core/containerpool/logging/SplunkLogStoreTests.scala
@@ -79,7 +79,7 @@ class SplunkLogStoreTests
     namespace = EntityPath("ns"),
     name = EntityName("a"),
     Subject(),
-    activationId = ActivationId(),
+    activationId = ActivationId.generate(),
     start = ZonedDateTime.parse(startTime).toInstant,
     end = ZonedDateTime.parse(endTime).toInstant,
     response = ActivationResponse.success(Some(JsObject("res" -> JsNumber(1)))),
diff --git a/tests/src/test/scala/whisk/core/containerpool/logging/test/DockerToActivationLogStoreTests.scala b/tests/src/test/scala/whisk/core/containerpool/logging/test/DockerToActivationLogStoreTests.scala
index dc46bff..ae5249e 100644
--- a/tests/src/test/scala/whisk/core/containerpool/logging/test/DockerToActivationLogStoreTests.scala
+++ b/tests/src/test/scala/whisk/core/containerpool/logging/test/DockerToActivationLogStoreTests.scala
@@ -44,7 +44,13 @@ class DockerToActivationLogStoreTests extends FlatSpec with Matchers with WskAct
   val exec = CodeExecAsString(RuntimeManifest("actionKind", ImageName("testImage")), "testCode", None)
   val action = ExecutableWhiskAction(user.namespace.toPath, EntityName("actionName"), exec)
   val activation =
-    WhiskActivation(user.namespace.toPath, action.name, user.subject, ActivationId(), Instant.EPOCH, Instant.EPOCH)
+    WhiskActivation(
+      user.namespace.toPath,
+      action.name,
+      user.subject,
+      ActivationId.generate(),
+      Instant.EPOCH,
+      Instant.EPOCH)
 
   def toByteString(logs: List[LogLine]) = logs.map(_.toJson.compactPrint).map(ByteString.apply)
 
diff --git a/tests/src/test/scala/whisk/core/containerpool/test/ContainerPoolTests.scala b/tests/src/test/scala/whisk/core/containerpool/test/ContainerPoolTests.scala
index 0b53103..ff6d49e 100644
--- a/tests/src/test/scala/whisk/core/containerpool/test/ContainerPoolTests.scala
+++ b/tests/src/test/scala/whisk/core/containerpool/test/ContainerPoolTests.scala
@@ -76,7 +76,7 @@ class ContainerPoolTests
       action.fullyQualifiedName(true),
       action.rev,
       Identity(Subject(), invocationNamespace, AuthKey(), Set()),
-      ActivationId(),
+      ActivationId.generate(),
       InstanceId(0),
       blocking = false,
       content = None)
diff --git a/tests/src/test/scala/whisk/core/containerpool/test/ContainerProxyTests.scala b/tests/src/test/scala/whisk/core/containerpool/test/ContainerProxyTests.scala
index b624a49..5a13084 100644
--- a/tests/src/test/scala/whisk/core/containerpool/test/ContainerProxyTests.scala
+++ b/tests/src/test/scala/whisk/core/containerpool/test/ContainerProxyTests.scala
@@ -96,7 +96,7 @@ class ContainerProxyTests
     action.fullyQualifiedName(true),
     action.rev,
     Identity(Subject(), invocationNamespace, AuthKey(), Set()),
-    ActivationId(),
+    ActivationId.generate(),
     InstanceId(0),
     blocking = false,
     content = None)
diff --git a/tests/src/test/scala/whisk/core/controller/actions/test/SequenceAccountingTests.scala b/tests/src/test/scala/whisk/core/controller/actions/test/SequenceAccountingTests.scala
index 7f2a13e..c7cf1c6 100644
--- a/tests/src/test/scala/whisk/core/controller/actions/test/SequenceAccountingTests.scala
+++ b/tests/src/test/scala/whisk/core/controller/actions/test/SequenceAccountingTests.scala
@@ -47,7 +47,7 @@ class SequenceAccountingTests extends FlatSpec with Matchers with WskActorSystem
     namespace = EntityPath("ns"),
     name = EntityName("a"),
     Subject(),
-    activationId = ActivationId(),
+    activationId = ActivationId.generate(),
     start = Instant.now(),
     end = Instant.now(),
     response = okRes2,
@@ -58,7 +58,7 @@ class SequenceAccountingTests extends FlatSpec with Matchers with WskActorSystem
     namespace = EntityPath("ns"),
     name = EntityName("a"),
     Subject(),
-    activationId = ActivationId(),
+    activationId = ActivationId.generate(),
     start = Instant.now(),
     end = Instant.now(),
     response = failedRes,
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 cf9303d..d01398f 100644
--- a/tests/src/test/scala/whisk/core/controller/test/ActivationsApiTests.scala
+++ b/tests/src/test/scala/whisk/core/controller/test/ActivationsApiTests.scala
@@ -82,14 +82,20 @@ class ActivationsApiTests extends ControllerTestCommon with WhiskActivationsApi
         EntityPath(creds1.subject.asString),
         aname(),
         creds1.subject,
-        ActivationId(),
+        ActivationId.generate(),
         start = Instant.now,
         end = Instant.now)
     } foreach { put(entityStore, _) }
 
     val actionName = aname()
     val activations = (1 to 2).map { i =>
-      WhiskActivation(namespace, actionName, creds.subject, ActivationId(), start = Instant.now, end = Instant.now)
+      WhiskActivation(
+        namespace,
+        actionName,
+        creds.subject,
+        ActivationId.generate(),
+        start = Instant.now,
+        end = Instant.now)
     }.toList
     activations foreach { put(activationStore, _) }
     waitOnView(activationStore, namespace.root, 2, WhiskActivation.view)
@@ -151,7 +157,7 @@ class ActivationsApiTests extends ControllerTestCommon with WhiskActivationsApi
         EntityPath(creds1.subject.asString),
         aname(),
         creds1.subject,
-        ActivationId(),
+        ActivationId.generate(),
         start = Instant.now,
         end = Instant.now)
     } foreach { put(entityStore, _) }
@@ -162,7 +168,7 @@ class ActivationsApiTests extends ControllerTestCommon with WhiskActivationsApi
         namespace,
         actionName,
         creds.subject,
-        ActivationId(),
+        ActivationId.generate(),
         start = Instant.now,
         end = Instant.now,
         response = ActivationResponse.success(Some(JsNumber(5))))
@@ -192,7 +198,7 @@ class ActivationsApiTests extends ControllerTestCommon with WhiskActivationsApi
         EntityPath(creds1.subject.asString),
         aname(),
         creds1.subject,
-        ActivationId(),
+        ActivationId.generate(),
         start = Instant.now,
         end = Instant.now)
     } foreach { put(activationStore, _) }
@@ -206,35 +212,35 @@ class ActivationsApiTests extends ControllerTestCommon with WhiskActivationsApi
         namespace,
         actionName,
         creds.subject,
-        ActivationId(),
+        ActivationId.generate(),
         start = now.plusSeconds(9),
         end = now.plusSeconds(9)),
       WhiskActivation(
         namespace,
         actionName,
         creds.subject,
-        ActivationId(),
+        ActivationId.generate(),
         start = now.plusSeconds(20),
         end = now.plusSeconds(20)), // should match
       WhiskActivation(
         namespace,
         actionName,
         creds.subject,
-        ActivationId(),
+        ActivationId.generate(),
         start = now.plusSeconds(10),
         end = now.plusSeconds(20)), // should match
       WhiskActivation(
         namespace,
         actionName,
         creds.subject,
-        ActivationId(),
+        ActivationId.generate(),
         start = now.plusSeconds(31),
         end = now.plusSeconds(31)),
       WhiskActivation(
         namespace,
         actionName,
         creds.subject,
-        ActivationId(),
+        ActivationId.generate(),
         start = now.plusSeconds(30),
         end = now.plusSeconds(30))) // should match
     activations foreach { put(activationStore, _) }
@@ -316,7 +322,7 @@ class ActivationsApiTests extends ControllerTestCommon with WhiskActivationsApi
         EntityPath(creds1.subject.asString),
         aname(),
         creds1.subject,
-        ActivationId(),
+        ActivationId.generate(),
         start = Instant.now,
         end = Instant.now)
     } foreach { put(activationStore, _) }
@@ -326,7 +332,7 @@ class ActivationsApiTests extends ControllerTestCommon with WhiskActivationsApi
         namespace,
         EntityName(s"xyz"),
         creds.subject,
-        ActivationId(),
+        ActivationId.generate(),
         start = Instant.now,
         end = Instant.now)
     }.toList
@@ -337,7 +343,7 @@ class ActivationsApiTests extends ControllerTestCommon with WhiskActivationsApi
         namespace,
         EntityName(s"xyz"),
         creds.subject,
-        ActivationId(),
+        ActivationId.generate(),
         start = Instant.now,
         end = Instant.now,
         annotations = Parameters("path", s"${namespace.asString}/pkg/xyz"))
@@ -416,7 +422,13 @@ class ActivationsApiTests extends ControllerTestCommon with WhiskActivationsApi
   it should "get activation by id" in {
     implicit val tid = transid()
     val activation =
-      WhiskActivation(namespace, aname(), creds.subject, ActivationId(), start = Instant.now, end = Instant.now)
+      WhiskActivation(
+        namespace,
+        aname(),
+        creds.subject,
+        ActivationId.generate(),
+        start = Instant.now,
+        end = Instant.now)
     put(activationStore, activation)
 
     Get(s"$collectionPath/${activation.activationId.asString}") ~> Route.seal(routes(creds)) ~> check {
@@ -443,7 +455,13 @@ class ActivationsApiTests extends ControllerTestCommon with WhiskActivationsApi
   it should "get activation result by id" in {
     implicit val tid = transid()
     val activation =
-      WhiskActivation(namespace, aname(), creds.subject, ActivationId(), start = Instant.now, end = Instant.now)
+      WhiskActivation(
+        namespace,
+        aname(),
+        creds.subject,
+        ActivationId.generate(),
+        start = Instant.now,
+        end = Instant.now)
     put(activationStore, activation)
 
     Get(s"$collectionPath/${activation.activationId.asString}/result") ~> Route.seal(routes(creds)) ~> check {
@@ -457,7 +475,13 @@ class ActivationsApiTests extends ControllerTestCommon with WhiskActivationsApi
   it should "get activation logs by id" in {
     implicit val tid = transid()
     val activation =
-      WhiskActivation(namespace, aname(), creds.subject, ActivationId(), start = Instant.now, end = Instant.now)
+      WhiskActivation(
+        namespace,
+        aname(),
+        creds.subject,
+        ActivationId.generate(),
+        start = Instant.now,
+        end = Instant.now)
     put(activationStore, activation)
 
     Get(s"$collectionPath/${activation.activationId.asString}/logs") ~> Route.seal(routes(creds)) ~> check {
@@ -471,7 +495,13 @@ class ActivationsApiTests extends ControllerTestCommon with WhiskActivationsApi
   it should "reject request to get invalid activation resource" in {
     implicit val tid = transid()
     val activation =
-      WhiskActivation(namespace, aname(), creds.subject, ActivationId(), start = Instant.now, end = Instant.now)
+      WhiskActivation(
+        namespace,
+        aname(),
+        creds.subject,
+        ActivationId.generate(),
+        start = Instant.now,
+        end = Instant.now)
     put(entityStore, activation)
 
     Get(s"$collectionPath/${activation.activationId.asString}/bogus") ~> Route.seal(routes(creds)) ~> check {
@@ -481,7 +511,7 @@ class ActivationsApiTests extends ControllerTestCommon with WhiskActivationsApi
 
   it should "reject get requests with invalid activation ids" in {
     implicit val tid = transid()
-    val activationId = ActivationId().toString
+    val activationId = ActivationId.generate().toString
     val tooshort = activationId.substring(0, 31)
     val toolong = activationId + "xxx"
     val malformed = tooshort + "z"
@@ -503,21 +533,21 @@ class ActivationsApiTests extends ControllerTestCommon with WhiskActivationsApi
 
   it should "reject request with put" in {
     implicit val tid = transid()
-    Put(s"$collectionPath/${ActivationId()}") ~> Route.seal(routes(creds)) ~> check {
+    Put(s"$collectionPath/${ActivationId.generate()}") ~> Route.seal(routes(creds)) ~> check {
       status should be(MethodNotAllowed)
     }
   }
 
   it should "reject request with post" in {
     implicit val tid = transid()
-    Post(s"$collectionPath/${ActivationId()}") ~> Route.seal(routes(creds)) ~> check {
+    Post(s"$collectionPath/${ActivationId.generate()}") ~> Route.seal(routes(creds)) ~> check {
       status should be(MethodNotAllowed)
     }
   }
 
   it should "reject request with delete" in {
     implicit val tid = transid()
-    Delete(s"$collectionPath/${ActivationId()}") ~> Route.seal(routes(creds)) ~> check {
+    Delete(s"$collectionPath/${ActivationId.generate()}") ~> Route.seal(routes(creds)) ~> check {
       status should be(MethodNotAllowed)
     }
   }
@@ -534,7 +564,7 @@ class ActivationsApiTests extends ControllerTestCommon with WhiskActivationsApi
         logging,
         materializer)
     implicit val tid = transid()
-    val entity = BadEntity(namespace, EntityName(ActivationId().toString))
+    val entity = BadEntity(namespace, EntityName(ActivationId.generate().toString))
     put(activationStore, entity)
 
     Get(s"$collectionPath/${entity.name}") ~> Route.seal(routes(creds)) ~> check {
diff --git a/tests/src/test/scala/whisk/core/controller/test/ControllerTestCommon.scala b/tests/src/test/scala/whisk/core/controller/test/ControllerTestCommon.scala
index ffedc81..e4d7904 100644
--- a/tests/src/test/scala/whisk/core/controller/test/ControllerTestCommon.scala
+++ b/tests/src/test/scala/whisk/core/controller/test/ControllerTestCommon.scala
@@ -79,7 +79,7 @@ protected trait ControllerTestCommon
 
   override val activationIdFactory = new ActivationId.ActivationIdGenerator() {
     // need a static activation id to test activations api
-    private val fixedId = ActivationId()
+    private val fixedId = ActivationId.generate()
     override def make = fixedId
   }
 
diff --git a/tests/src/test/scala/whisk/core/controller/test/TriggersApiTests.scala b/tests/src/test/scala/whisk/core/controller/test/TriggersApiTests.scala
index 44ab26b..9f79540 100644
--- a/tests/src/test/scala/whisk/core/controller/test/TriggersApiTests.scala
+++ b/tests/src/test/scala/whisk/core/controller/test/TriggersApiTests.scala
@@ -333,7 +333,7 @@ class TriggersApiTests extends ControllerTestCommon with WhiskTriggersApi {
       status should be(Accepted)
       val response = responseAs[JsObject]
       val JsString(id) = response.fields("activationId")
-      val activationId = ActivationId(id)
+      val activationId = ActivationId.parse(id).get
       response.fields("activationId") should not be None
 
       val activationDoc = DocId(WhiskEntity.qualifiedName(namespace, activationId))
@@ -358,7 +358,7 @@ class TriggersApiTests extends ControllerTestCommon with WhiskTriggersApi {
     Post(s"$collectionPath/${trigger.name}") ~> Route.seal(routes(creds)) ~> check {
       val response = responseAs[JsObject]
       val JsString(id) = response.fields("activationId")
-      val activationId = ActivationId(id)
+      val activationId = ActivationId.parse(id).get
       val activationDoc = DocId(WhiskEntity.qualifiedName(namespace, activationId))
       whisk.utils.retry({
         println(s"trying to delete async activation doc: '${activationDoc}'")
diff --git a/tests/src/test/scala/whisk/core/controller/test/WebActionsApiTests.scala b/tests/src/test/scala/whisk/core/controller/test/WebActionsApiTests.scala
index 2f47595..044ab53 100644
--- a/tests/src/test/scala/whisk/core/controller/test/WebActionsApiTests.scala
+++ b/tests/src/test/scala/whisk/core/controller/test/WebActionsApiTests.scala
@@ -262,7 +262,7 @@ trait WebActionsApiBaseTests extends ControllerTestCommon with BeforeAndAfterEac
         action.namespace,
         action.name,
         user.subject,
-        ActivationId(),
+        ActivationId.generate(),
         start = Instant.now,
         end = Instant.now,
         response = {
@@ -290,7 +290,7 @@ trait WebActionsApiBaseTests extends ControllerTestCommon with BeforeAndAfterEac
 
       Future.successful(Right(activation))
     } else if (failActivation == 1) {
-      Future.successful(Left(ActivationId()))
+      Future.successful(Left(ActivationId.generate()))
     } else {
       Future.failed(new IllegalStateException("bad activation"))
     }
diff --git a/tests/src/test/scala/whisk/core/database/test/RemoveLogsTests.scala b/tests/src/test/scala/whisk/core/database/test/RemoveLogsTests.scala
index a71240c..fc116d0 100644
--- a/tests/src/test/scala/whisk/core/database/test/RemoveLogsTests.scala
+++ b/tests/src/test/scala/whisk/core/database/test/RemoveLogsTests.scala
@@ -75,7 +75,7 @@ class RemoveLogsTests extends FlatSpec with DatabaseScriptTestUtils with StreamL
         namespace = EntityPath("testns1"),
         name = EntityName("testname1"),
         subject = Subject("test-sub1"),
-        activationId = ActivationId(),
+        activationId = ActivationId.generate(),
         start = Instant.now.minus(2, ChronoUnit.DAYS),
         end = Instant.now,
         logs = ActivationLogs(Vector("first line1", "second line1")))
@@ -84,7 +84,7 @@ class RemoveLogsTests extends FlatSpec with DatabaseScriptTestUtils with StreamL
         namespace = EntityPath("testns2"),
         name = EntityName("testname2"),
         subject = Subject("test-sub2"),
-        activationId = ActivationId(),
+        activationId = ActivationId.generate(),
         start = Instant.now,
         end = Instant.now,
         logs = ActivationLogs(Vector("first line2", "second line2")))
diff --git a/tests/src/test/scala/whisk/core/entity/test/DatastoreTests.scala b/tests/src/test/scala/whisk/core/entity/test/DatastoreTests.scala
index abf9e9f..ec4a998 100644
--- a/tests/src/test/scala/whisk/core/entity/test/DatastoreTests.scala
+++ b/tests/src/test/scala/whisk/core/entity/test/DatastoreTests.scala
@@ -134,8 +134,8 @@ class DatastoreTests
     implicit val tid = transid()
     implicit val basename = EntityName("create action blackbox")
     val activations = Seq(
-      WhiskActivation(namespace, aname, Subject(), ActivationId(), start = Instant.now, end = Instant.now),
-      WhiskActivation(namespace, aname, Subject(), ActivationId(), start = Instant.now, end = Instant.now))
+      WhiskActivation(namespace, aname, Subject(), ActivationId.generate(), start = Instant.now, end = Instant.now),
+      WhiskActivation(namespace, aname, Subject(), ActivationId.generate(), start = Instant.now, end = Instant.now))
     val docs = activations.map { entity =>
       putGetCheck(datastore, entity, WhiskActivation)
     }
@@ -149,7 +149,7 @@ class DatastoreTests
         namespace,
         aname,
         Subject(),
-        ActivationId(),
+        ActivationId.generate(),
         start = Instant.now,
         end = Instant.now,
         logs = ActivationLogs(Vector("Prote\u00EDna"))))
@@ -230,7 +230,7 @@ class DatastoreTests
     implicit val tid = transid()
     implicit val basename = EntityName("update activation")
     val activation =
-      WhiskActivation(namespace, aname, Subject(), ActivationId(), start = Instant.now, end = Instant.now)
+      WhiskActivation(namespace, aname, Subject(), ActivationId.generate(), start = Instant.now, end = Instant.now)
     val docinfo = putGetCheck(datastore, activation, WhiskActivation, false)._2.docinfo
     val revActivation = WhiskActivation(
       namespace,
@@ -277,7 +277,7 @@ class DatastoreTests
     implicit val tid = transid()
     implicit val basename = EntityName("create activation twice")
     val activation =
-      WhiskActivation(namespace, aname, Subject(), ActivationId(), start = Instant.now, end = Instant.now)
+      WhiskActivation(namespace, aname, Subject(), ActivationId.generate(), start = Instant.now, end = Instant.now)
     putGetCheck(datastore, activation, WhiskActivation)
     intercept[DocumentConflictException] {
       putGetCheck(datastore, activation, WhiskActivation)
@@ -325,7 +325,7 @@ class DatastoreTests
     implicit val tid = transid()
     implicit val basename = EntityName("delete activation twice")
     val activation =
-      WhiskActivation(namespace, aname, Subject(), ActivationId(), start = Instant.now, end = Instant.now)
+      WhiskActivation(namespace, aname, Subject(), ActivationId.generate(), start = Instant.now, end = Instant.now)
     val doc = putGetCheck(datastore, activation, WhiskActivation, false)._1
     assert(Await.result(WhiskActivation.del(datastore, doc), dbOpTimeout))
     intercept[NoDocumentException] {
diff --git a/tests/src/test/scala/whisk/core/entity/test/SchemaTests.scala b/tests/src/test/scala/whisk/core/entity/test/SchemaTests.scala
index b5cb9f4..daf8998 100644
--- a/tests/src/test/scala/whisk/core/entity/test/SchemaTests.scala
+++ b/tests/src/test/scala/whisk/core/entity/test/SchemaTests.scala
@@ -767,22 +767,22 @@ class SchemaTests extends FlatSpec with BeforeAndAfter with ExecHelpers with Mat
 
   it should "parse activation id as uuid" in {
     val id = "213174381920559471141441e1111111"
-    val aid = ActivationId.unapply(id)
-    assert(aid.isDefined)
+    val aid = ActivationId.parse(id)
+    assert(aid.isSuccess)
     assert(aid.get.toString == id)
   }
 
   it should "parse activation id as uuid when made up of no numbers" in {
     val id = "a" * 32
-    val aid = ActivationId.unapply(id)
-    assert(aid.isDefined)
+    val aid = ActivationId.parse(id)
+    assert(aid.isSuccess)
     assert(aid.get.toString == id)
   }
 
   it should "parse activation id as uuid when made up of no letters" in {
     val id = "1" * 32
-    val aid = ActivationId.unapply(id)
-    assert(aid.isDefined)
+    val aid = ActivationId.parse(id)
+    assert(aid.isSuccess)
     assert(aid.get.toString == id)
   }
 
@@ -795,7 +795,7 @@ class SchemaTests extends FlatSpec with BeforeAndAfter with ExecHelpers with Mat
 
   it should "not parse invalid activation id" in {
     val id = "213174381920559471141441e111111z"
-    assert(ActivationId.unapply(id).isEmpty)
+    assert(ActivationId.parse(id).isFailure)
     Try(ActivationId.serdes.read(JsString(id))) shouldBe Failure {
       DeserializationException(Messages.activationIdIllegal)
     }
@@ -803,7 +803,7 @@ class SchemaTests extends FlatSpec with BeforeAndAfter with ExecHelpers with Mat
 
   it should "not parse activation id if longer than uuid" in {
     val id = "213174381920559471141441e1111111abc"
-    assert(ActivationId.unapply(id).isEmpty)
+    assert(ActivationId.parse(id).isFailure)
     Try(ActivationId.serdes.read(JsString(id))) shouldBe Failure {
       DeserializationException(Messages.activationIdLengthError(SizeError("Activation id", id.length.B, 32.B)))
     }
@@ -811,7 +811,7 @@ class SchemaTests extends FlatSpec with BeforeAndAfter with ExecHelpers with Mat
 
   it should "not parse activation id if shorter than uuid" in {
     val id = "213174381920559471141441e1"
-    ActivationId.unapply(id) shouldBe empty
+    ActivationId.parse(id) shouldBe 'failure
     Try(ActivationId.serdes.read(JsString(id))) shouldBe Failure {
       DeserializationException(Messages.activationIdLengthError(SizeError("Activation id", id.length.B, 32.B)))
     }
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 d4e0b16..ef85ee4 100644
--- a/tests/src/test/scala/whisk/core/entity/test/ViewTests.scala
+++ b/tests/src/test/scala/whisk/core/entity/test/ViewTests.scala
@@ -312,11 +312,11 @@ class ViewTests
     // creates 5 entities in each namespace as follows:
     // - some activations in each namespace (some may have prescribed action name to query by name)
     implicit val entities = Seq(
-      WhiskActivation(namespace1, aname(), Subject(), ActivationId(), start = now, end = now),
-      WhiskActivation(namespace1, aname(), Subject(), ActivationId(), start = now, end = now),
-      WhiskActivation(namespace2, aname(), Subject(), ActivationId(), start = now, end = now),
-      WhiskActivation(namespace2, actionName, Subject(), ActivationId(), start = now, end = now),
-      WhiskActivation(namespace2, actionName, Subject(), ActivationId(), start = now, end = now))
+      WhiskActivation(namespace1, aname(), Subject(), ActivationId.generate(), start = now, end = now),
+      WhiskActivation(namespace1, aname(), Subject(), ActivationId.generate(), start = now, end = now),
+      WhiskActivation(namespace2, aname(), Subject(), ActivationId.generate(), start = now, end = now),
+      WhiskActivation(namespace2, actionName, Subject(), ActivationId.generate(), start = now, end = now),
+      WhiskActivation(namespace2, actionName, Subject(), ActivationId.generate(), start = now, end = now))
 
     entities foreach { put(activationStore, _) }
     waitOnView(activationStore, namespace1.root, 2, WhiskActivation.view)
@@ -344,33 +344,33 @@ class ViewTests
     val actionName = aname()
     val now = Instant.now(Clock.systemUTC())
     implicit val entities = Seq(
-      WhiskActivation(namespace1, actionName, Subject(), ActivationId(), start = now, end = now),
+      WhiskActivation(namespace1, actionName, Subject(), ActivationId.generate(), start = now, end = now),
       WhiskActivation(
         namespace1,
         actionName,
         Subject(),
-        ActivationId(),
+        ActivationId.generate(),
         start = now.plusSeconds(20),
         end = now.plusSeconds(20)),
       WhiskActivation(
         namespace1,
         actionName,
         Subject(),
-        ActivationId(),
+        ActivationId.generate(),
         start = now.plusSeconds(10),
         end = now.plusSeconds(20)),
       WhiskActivation(
         namespace1,
         actionName,
         Subject(),
-        ActivationId(),
+        ActivationId.generate(),
         start = now.plusSeconds(40),
         end = now.plusSeconds(20)),
       WhiskActivation(
         namespace1,
         actionName,
         Subject(),
-        ActivationId(),
+        ActivationId.generate(),
         start = now.plusSeconds(30),
         end = now.plusSeconds(20)))
 
diff --git a/tests/src/test/scala/whisk/core/entity/test/WhiskEntityTests.scala b/tests/src/test/scala/whisk/core/entity/test/WhiskEntityTests.scala
index 1812f5a..6918ea2 100644
--- a/tests/src/test/scala/whisk/core/entity/test/WhiskEntityTests.scala
+++ b/tests/src/test/scala/whisk/core/entity/test/WhiskEntityTests.scala
@@ -103,7 +103,7 @@ class WhiskEntityTests extends FlatSpec with ExecHelpers with Matchers {
   behavior of "WhiskActivation"
 
   it should "add and remove logs and preserve revision in the process" in {
-    val activation = WhiskActivation(namespace, name, Subject(), ActivationId(), Instant.now(), Instant.now())
+    val activation = WhiskActivation(namespace, name, Subject(), ActivationId.generate(), Instant.now(), Instant.now())
       .revision[WhiskActivation](revision)
     val logs = ActivationLogs(Vector("testlog"))
 
@@ -149,7 +149,7 @@ class WhiskEntityTests extends FlatSpec with ExecHelpers with Matchers {
     val action = WhiskAction(namespace, name, jsDefault("code"), Parameters())
     assertType(action, "action")
 
-    val activation = WhiskActivation(namespace, name, Subject(), ActivationId(), Instant.now(), Instant.now())
+    val activation = WhiskActivation(namespace, name, Subject(), ActivationId.generate(), Instant.now(), Instant.now())
     assertType(activation, "activation")
 
     val whiskPackage = WhiskPackage(namespace, name)
diff --git a/tests/src/test/scala/whisk/core/loadBalancer/test/LoadBalancerDataTests.scala b/tests/src/test/scala/whisk/core/loadBalancer/test/LoadBalancerDataTests.scala
index b60989a..5a4edb6 100644
--- a/tests/src/test/scala/whisk/core/loadBalancer/test/LoadBalancerDataTests.scala
+++ b/tests/src/test/scala/whisk/core/loadBalancer/test/LoadBalancerDataTests.scala
@@ -41,9 +41,9 @@ class LoadBalancerDataTests extends FlatSpec with Matchers with StreamLogging {
 
   val activationIdPromise = Promise[Either[ActivationId, WhiskActivation]]()
   val firstEntry: ActivationEntry =
-    ActivationEntry(ActivationId(), UUID(), InstanceId(0), emptyCancellable, activationIdPromise)
+    ActivationEntry(ActivationId.generate(), UUID(), InstanceId(0), emptyCancellable, activationIdPromise)
   val secondEntry: ActivationEntry =
-    ActivationEntry(ActivationId(), UUID(), InstanceId(1), emptyCancellable, activationIdPromise)
+    ActivationEntry(ActivationId.generate(), UUID(), InstanceId(1), emptyCancellable, activationIdPromise)
 
   val port = 2552
   val host = "127.0.0.1"
@@ -159,9 +159,9 @@ class LoadBalancerDataTests extends FlatSpec with Matchers with StreamLogging {
 
   it should "respond with different values accordingly" in {
 
-    val entry = ActivationEntry(ActivationId(), UUID(), InstanceId(1), emptyCancellable, activationIdPromise)
-    val entrySameInvokerAndNamespace = entry.copy(id = ActivationId())
-    val entrySameInvoker = entry.copy(id = ActivationId(), namespaceId = UUID())
+    val entry = ActivationEntry(ActivationId.generate(), UUID(), InstanceId(1), emptyCancellable, activationIdPromise)
+    val entrySameInvokerAndNamespace = entry.copy(id = ActivationId.generate())
+    val entrySameInvoker = entry.copy(id = ActivationId.generate(), namespaceId = UUID())
 
     val distributedLoadBalancerData = new DistributedLoadBalancerData()
     val localLoadBalancerData = new LocalLoadBalancerData()

-- 
To stop receiving notification emails like this one, please contact
rabbah@apache.org.