rabbah closed pull request #3109: Add binary, image, and main properties to 
WhiskActionMetaData
URL: https://github.com/apache/incubator-openwhisk/pull/3109
 
 
   

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/common/scala/src/main/scala/whisk/core/entity/Exec.scala 
b/common/scala/src/main/scala/whisk/core/entity/Exec.scala
index bf066f6e71..8f318129d0 100644
--- a/common/scala/src/main/scala/whisk/core/entity/Exec.scala
+++ b/common/scala/src/main/scala/whisk/core/entity/Exec.scala
@@ -95,9 +95,23 @@ sealed abstract class CodeExec[+T <% SizeConversion] extends 
Exec {
 
 sealed abstract class ExecMetaData extends ExecMetaDataBase {
 
+  /** An entrypoint (typically name of 'main' function). 'None' means a 
default value will be used. */
+  val entryPoint: Option[String]
+
+  /** The runtime image (either built-in or a public image). */
+  val image: ImageName
+
   /** Indicates if a container image is required from the registry to execute 
the action. */
   val pull: Boolean
 
+  /**
+   * Indicates whether the code is stored in a text-readable or binary format.
+   * The binary bit may be read from the database but currently it is always 
computed
+   * when the "code" is moved to an attachment this may get changed to avoid 
recomputing
+   * the binary property.
+   */
+  val binary: Boolean
+
   override def size = 0.B
 }
 
@@ -114,8 +128,12 @@ protected[core] case class CodeExecAsString(manifest: 
RuntimeManifest,
   override def codeAsJson = JsString(code)
 }
 
-protected[core] case class CodeExecMetaDataAsString(manifest: RuntimeManifest) 
extends ExecMetaData {
+protected[core] case class CodeExecMetaDataAsString(manifest: RuntimeManifest,
+                                                    override val binary: 
Boolean = false,
+                                                    override val entryPoint: 
Option[String])
+    extends ExecMetaData {
   override val kind = manifest.kind
+  override val image = manifest.image
   override val deprecated = manifest.deprecated.getOrElse(false)
   override val pull = false
 }
@@ -144,8 +162,12 @@ protected[core] case class CodeExecAsAttachment(manifest: 
RuntimeManifest,
   }
 }
 
-protected[core] case class CodeExecMetaDataAsAttachment(manifest: 
RuntimeManifest) extends ExecMetaData {
+protected[core] case class CodeExecMetaDataAsAttachment(manifest: 
RuntimeManifest,
+                                                        override val binary: 
Boolean = false,
+                                                        override val 
entryPoint: Option[String])
+    extends ExecMetaData {
   override val kind = manifest.kind
+  override val image = manifest.image
   override val deprecated = manifest.deprecated.getOrElse(false)
   override val pull = false
 }
@@ -168,7 +190,11 @@ protected[core] case class BlackBoxExec(override val 
image: ImageName,
   override def size = super.size + image.publicImageName.sizeInBytes
 }
 
-protected[core] case class BlackBoxExecMetaData(val native: Boolean) extends 
ExecMetaData {
+protected[core] case class BlackBoxExecMetaData(override val image: ImageName,
+                                                override val entryPoint: 
Option[String],
+                                                val native: Boolean,
+                                                override val binary: Boolean = 
false)
+    extends ExecMetaData {
   override val kind = ExecMetaDataBase.BLACKBOX
   override val deprecated = false
   override val pull = !native
@@ -334,21 +360,24 @@ protected[core] object ExecMetaDataBase extends 
ArgNormalizer[ExecMetaDataBase]
 
     override def write(e: ExecMetaDataBase) = e match {
       case c: CodeExecMetaDataAsString =>
-        val base = Map("kind" -> JsString(c.kind))
-        JsObject(base)
+        val base = Map("kind" -> JsString(c.kind), "binary" -> 
JsBoolean(c.binary))
+        val main = c.entryPoint.map("main" -> JsString(_))
+        JsObject(base ++ main)
 
       case a: CodeExecMetaDataAsAttachment =>
         val base =
-          Map("kind" -> JsString(a.kind))
-        JsObject(base)
+          Map("kind" -> JsString(a.kind), "binary" -> JsBoolean(a.binary))
+        val main = a.entryPoint.map("main" -> JsString(_))
+        JsObject(base ++ main)
 
       case s @ SequenceExecMetaData(comp) =>
         JsObject("kind" -> JsString(s.kind), "components" -> 
comp.map(_.qualifiedNameWithLeadingSlash).toJson)
 
       case b: BlackBoxExecMetaData =>
         val base =
-          Map("kind" -> JsString(b.kind))
-        JsObject(base)
+          Map("kind" -> JsString(b.kind), "image" -> 
JsString(b.image.publicImageName), "binary" -> JsBoolean(b.binary))
+        val main = b.entryPoint.map("main" -> JsString(_))
+        JsObject(base ++ main)
     }
 
     override def read(v: JsValue) = {
@@ -368,6 +397,11 @@ protected[core] object ExecMetaDataBase extends 
ArgNormalizer[ExecMetaDataBase]
         case None => None
       }
 
+      lazy val binary: Boolean = obj.fields.get("binary") match {
+        case Some(JsBoolean(b)) => b
+        case _                  => throw new 
DeserializationException("'binary' must be a boolean defined in 'exec'")
+      }
+
       kind match {
         case ExecMetaDataBase.SEQUENCE =>
           val comp: Vector[FullyQualifiedEntityName] = 
obj.fields.get("components") match {
@@ -385,7 +419,7 @@ protected[core] object ExecMetaDataBase extends 
ArgNormalizer[ExecMetaDataBase]
                 s"'image' must be a string defined in 'exec' for 
'${Exec.BLACKBOX}' actions")
           }
           val native = execManifests.skipDockerPull(image)
-          BlackBoxExecMetaData(native)
+          BlackBoxExecMetaData(image, optMainField, native, binary)
 
         case _ =>
           // map "default" virtual runtime versions to the currently blessed 
actual runtime version
@@ -396,10 +430,16 @@ protected[core] object ExecMetaDataBase extends 
ArgNormalizer[ExecMetaDataBase]
 
           manifest.attached
             .map { a =>
-              CodeExecMetaDataAsAttachment(manifest)
+              val main = optMainField.orElse {
+                if (manifest.requireMain.exists(identity)) {
+                  throw new DeserializationException(s"'main' must be a string 
defined in 'exec' for '$kind' actions")
+                } else None
+              }
+
+              CodeExecMetaDataAsAttachment(manifest, binary, main)
             }
             .getOrElse {
-              CodeExecMetaDataAsString(manifest)
+              CodeExecMetaDataAsString(manifest, binary, optMainField)
             }
       }
     }
diff --git 
a/tests/src/test/scala/whisk/core/controller/test/ActionsApiTests.scala 
b/tests/src/test/scala/whisk/core/controller/test/ActionsApiTests.scala
index 3696063942..b2d60d12fa 100644
--- a/tests/src/test/scala/whisk/core/controller/test/ActionsApiTests.scala
+++ b/tests/src/test/scala/whisk/core/controller/test/ActionsApiTests.scala
@@ -159,26 +159,136 @@ class ActionsApiTests extends ControllerTestCommon with 
WhiskActionsApi {
     }
   }
 
+  def getExecPermutations() = {
+    implicit val tid = transid()
+
+    // BlackBox: binary: true, main: bbMain
+    val bbAction1 = WhiskAction(namespace, aname(), bb("bb", "RHViZWU=", 
Some("bbMain")))
+    val bbAction1Content = Map("exec" -> Map(
+      "kind" -> Exec.BLACKBOX,
+      "code" -> "RHViZWU=",
+      "image" -> "bb",
+      "main" -> "bbMain")).toJson.asJsObject
+    val bbAction1ExecMetaData = blackBoxMetaData("bb", Some("bbMain"), true)
+
+    // BlackBox: binary: false, main: bbMain
+    val bbAction2 = WhiskAction(namespace, aname(), bb("bb", "", 
Some("bbMain")))
+    val bbAction2Content =
+      Map("exec" -> Map("kind" -> Exec.BLACKBOX, "code" -> "", "image" -> 
"bb", "main" -> "bbMain")).toJson.asJsObject
+    val bbAction2ExecMetaData = blackBoxMetaData("bb", Some("bbMain"), false)
+
+    // BlackBox: binary: true, no main
+    val bbAction3 = WhiskAction(namespace, aname(), bb("bb", "RHViZWU="))
+    val bbAction3Content =
+      Map("exec" -> Map("kind" -> Exec.BLACKBOX, "code" -> "RHViZWU=", "image" 
-> "bb")).toJson.asJsObject
+    val bbAction3ExecMetaData = blackBoxMetaData("bb", None, true)
+
+    // BlackBox: binary: false, no main
+    val bbAction4 = WhiskAction(namespace, aname(), bb("bb", ""))
+    val bbAction4Content = Map("exec" -> Map("kind" -> Exec.BLACKBOX, "code" 
-> "", "image" -> "bb")).toJson.asJsObject
+    val bbAction4ExecMetaData = blackBoxMetaData("bb", None, false)
+
+    // Attachment: binary: true, main: javaMain
+    val javaAction1 = WhiskAction(namespace, aname(), javaDefault("RHViZWU=", 
Some("javaMain")))
+    val javaAction1Content =
+      Map("exec" -> Map("kind" -> JAVA_DEFAULT, "code" -> "RHViZWU=", "main" 
-> "javaMain")).toJson.asJsObject
+    val javaAction1ExecMetaData = javaMetaData(Some("javaMain"), true)
+
+    // String: binary: true, main: jsMain
+    val jsAction1 = WhiskAction(namespace, aname(), jsDefault("RHViZWU=", 
Some("jsMain")))
+    val jsAction1Content =
+      Map("exec" -> Map("kind" -> NODEJS6, "code" -> "RHViZWU=", "main" -> 
"jsMain")).toJson.asJsObject
+    val jsAction1ExecMetaData = js6MetaData(Some("jsMain"), true)
+
+    // String: binary: false, main: jsMain
+    val jsAction2 = WhiskAction(namespace, aname(), jsDefault("", 
Some("jsMain")))
+    val jsAction2Content = Map("exec" -> Map("kind" -> NODEJS6, "code" -> "", 
"main" -> "jsMain")).toJson.asJsObject
+    val jsAction2ExecMetaData = js6MetaData(Some("jsMain"), false)
+
+    // String: binary: true, no main
+    val jsAction3 = WhiskAction(namespace, aname(), jsDefault("RHViZWU="))
+    val jsAction3Content = Map("exec" -> Map("kind" -> NODEJS6, "code" -> 
"RHViZWU=")).toJson.asJsObject
+    val jsAction3ExecMetaData = js6MetaData(None, true)
+
+    // String: binary: false, no main
+    val jsAction4 = WhiskAction(namespace, aname(), jsDefault(""))
+    val jsAction4Content = Map("exec" -> Map("kind" -> NODEJS6, "code" -> 
"")).toJson.asJsObject
+    val jsAction4ExecMetaData = js6MetaData(None, false)
+
+    // Sequence
+    val component = WhiskAction(namespace, aname(), jsDefault("??"))
+    put(entityStore, component)
+    val components = 
Vector(s"/$namespace/${component.name}").map(stringToFullyQualifiedName(_))
+    val seqAction = WhiskAction(namespace, aname(), sequence(components), 
seqParameters(components))
+    val seqActionContent = JsObject(
+      "exec" -> JsObject("kind" -> "sequence".toJson, "components" -> 
JsArray(s"/$namespace/${component.name}".toJson)))
+    val seqActionExecMetaData = sequenceMetaData(components)
+
+    Seq(
+      (bbAction1, bbAction1Content, bbAction1ExecMetaData),
+      (bbAction2, bbAction2Content, bbAction2ExecMetaData),
+      (bbAction3, bbAction3Content, bbAction3ExecMetaData),
+      (bbAction4, bbAction4Content, bbAction4ExecMetaData),
+      (javaAction1, javaAction1Content, javaAction1ExecMetaData),
+      (jsAction1, jsAction1Content, jsAction1ExecMetaData),
+      (jsAction2, jsAction2Content, jsAction2ExecMetaData),
+      (jsAction3, jsAction3Content, jsAction3ExecMetaData),
+      (jsAction4, jsAction4Content, jsAction4ExecMetaData),
+      (seqAction, seqActionContent, seqActionExecMetaData))
+  }
+
   it should "get action using code query parameter" in {
     implicit val tid = transid()
-    val action = WhiskAction(namespace, aname(), jsDefault("??"), 
Parameters("x", "b"))
 
-    put(entityStore, action)
+    getExecPermutations.foreach {
+      case (action, content, execMetaData) =>
+        val expectedWhiskAction = WhiskAction(
+          action.namespace,
+          action.name,
+          action.exec,
+          action.parameters,
+          action.limits,
+          action.version,
+          action.publish,
+          action.annotations ++ Parameters(WhiskAction.execFieldName, 
action.exec.kind))
 
-    Get(s"$collectionPath/${action.name}?code=false") ~> 
Route.seal(routes(creds)) ~> check {
-      status should be(OK)
-      val response = responseAs[JsObject]
-      response.fields("exec").asJsObject.fields should not(contain key "code")
-      responseAs[WhiskActionMetaData] shouldBe a[WhiskActionMetaData]
-    }
+        val expectedWhiskActionMetaData = WhiskActionMetaData(
+          action.namespace,
+          action.name,
+          execMetaData,
+          action.parameters,
+          action.limits,
+          action.version,
+          action.publish,
+          action.annotations ++ Parameters(WhiskActionMetaData.execFieldName, 
action.exec.kind))
 
-    Seq(s"$collectionPath/${action.name}", 
s"$collectionPath/${action.name}?code=true").foreach { path =>
-      Get(path) ~> Route.seal(routes(creds)) ~> check {
-        status should be(OK)
-        val response = responseAs[JsObject]
-        response.fields("exec").asJsObject.fields("code") should 
be("??".toJson)
-        responseAs[WhiskAction] shouldBe a[WhiskAction]
-      }
+        Put(s"$collectionPath/${action.name}", content) ~> 
Route.seal(routes(creds)) ~> check {
+          status should be(OK)
+          val response = responseAs[WhiskAction]
+          response should be(expectedWhiskAction)
+        }
+
+        Get(s"$collectionPath/${action.name}?code=false") ~> 
Route.seal(routes(creds)) ~> check {
+          status should be(OK)
+          val responseJson = responseAs[JsObject]
+          responseJson.fields("exec").asJsObject.fields should not(contain key 
"code")
+          val response = responseAs[WhiskActionMetaData]
+          response should be(expectedWhiskActionMetaData)
+        }
+
+        Seq(s"$collectionPath/${action.name}", 
s"$collectionPath/${action.name}?code=true").foreach { path =>
+          Get(path) ~> Route.seal(routes(creds)) ~> check {
+            status should be(OK)
+            val response = responseAs[WhiskAction]
+            response should be(expectedWhiskAction)
+          }
+        }
+
+        Delete(s"$collectionPath/${action.name}") ~> Route.seal(routes(creds)) 
~> check {
+          status should be(OK)
+          val response = responseAs[WhiskAction]
+          response should be(expectedWhiskAction)
+        }
     }
   }
 
@@ -423,7 +533,8 @@ class ActionsApiTests extends ControllerTestCommon with 
WhiskActionsApi {
   }
 
   private implicit val fqnSerdes = FullyQualifiedEntityName.serdes
-  private def seqParameters(seq: Vector[FullyQualifiedEntityName]) = 
Parameters("_actions", seq.toJson)
+  private def seqParameters(seq: Vector[FullyQualifiedEntityName]) =
+    Parameters("_actions", seq.map("/" + _.asString).toJson)
 
   // this test is sneaky; the installation of the sequence is done directly in 
the db
   // and api checks are skipped
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 57c8401a08..2bcfe9122f 100644
--- a/tests/src/test/scala/whisk/core/controller/test/WebActionsApiTests.scala
+++ b/tests/src/test/scala/whisk/core/controller/test/WebActionsApiTests.scala
@@ -190,7 +190,7 @@ trait WebActionsApiBaseTests extends ControllerTestCommon 
with BeforeAndAfterEac
         WhiskActionMetaData(
           actionName.path,
           actionName.name,
-          js6MetaData(),
+          js6MetaData(binary = false),
           defaultActionParameters,
           annotations = {
             if (actionName.name.asString.startsWith("export_")) {
diff --git a/tests/src/test/scala/whisk/core/entity/test/ExecHelpers.scala 
b/tests/src/test/scala/whisk/core/entity/test/ExecHelpers.scala
index c0f4ea873d..688fcd5b7e 100644
--- a/tests/src/test/scala/whisk/core/entity/test/ExecHelpers.scala
+++ b/tests/src/test/scala/whisk/core/entity/test/ExecHelpers.scala
@@ -68,9 +68,11 @@ trait ExecHelpers extends Matchers with WskActorSystem with 
StreamLogging {
     js6(code, main)
   }
 
-  protected def js6MetaData(main: Option[String] = None) = {
+  protected def js6MetaData(main: Option[String] = None, binary: Boolean) = {
     CodeExecMetaDataAsString(
-      RuntimeManifest(NODEJS6, imagename(NODEJS6), default = Some(true), 
deprecated = Some(false)))
+      RuntimeManifest(NODEJS6, imagename(NODEJS6), default = Some(true), 
deprecated = Some(false)),
+      binary,
+      main.map(_.trim))
   }
 
   protected def javaDefault(code: String, main: Option[String] = None) = {
@@ -80,6 +82,12 @@ trait ExecHelpers extends Matchers with WskActorSystem with 
StreamLogging {
     CodeExecAsAttachment(manifest, attachment, main.map(_.trim))
   }
 
+  protected def javaMetaData(main: Option[String] = None, binary: Boolean) = {
+    val manifest = 
ExecManifest.runtimesManifest.resolveDefaultRuntime(JAVA_DEFAULT).get
+
+    CodeExecMetaDataAsAttachment(manifest, binary, main.map(_.trim))
+  }
+
   protected def swift(code: String, main: Option[String] = None) = {
     CodeExecAsString(RuntimeManifest(SWIFT, imagename(SWIFT), deprecated = 
Some(true)), trim(code), main.map(_.trim))
   }
@@ -94,9 +102,15 @@ trait ExecHelpers extends Matchers with WskActorSystem with 
StreamLogging {
 
   protected def sequence(components: Vector[FullyQualifiedEntityName]) = 
SequenceExec(components)
 
+  protected def sequenceMetaData(components: Vector[FullyQualifiedEntityName]) 
= SequenceExecMetaData(components)
+
   protected def bb(image: String) = 
BlackBoxExec(ExecManifest.ImageName(trim(image)), None, None, false)
 
   protected def bb(image: String, code: String, main: Option[String] = None) = 
{
     BlackBoxExec(ExecManifest.ImageName(trim(image)), 
Some(trim(code)).filter(_.nonEmpty), main, false)
   }
+
+  protected def blackBoxMetaData(image: String, main: Option[String] = None, 
binary: Boolean) = {
+    BlackBoxExecMetaData(ExecManifest.ImageName(trim(image)), main, false, 
binary)
+  }
 }


 

----------------------------------------------------------------
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:
us...@infra.apache.org


With regards,
Apache Git Services

Reply via email to