Flatten Exec hiearchy (#1911)

* Remove unused script name variable for node js actions.

* Allow zip action without checking the kind - let backend determine if supported or not.

* Flatten exec hierarchy to remove unnecessary distinctions.
diff --git a/tests/src/actionContainers/ActionContainer.scala b/tests/src/actionContainers/ActionContainer.scala
index 8324e71..fe68ff8 100644
--- a/tests/src/actionContainers/ActionContainer.scala
+++ b/tests/src/actionContainers/ActionContainer.scala
@@ -31,16 +31,14 @@
 import scala.util.Random
 import scala.util.Try
 
+import org.apache.commons.lang3.StringUtils
 import org.scalatest.FlatSpec
 import org.scalatest.Matchers
-import akka.actor.ActorSystem
 
+import akka.actor.ActorSystem
 import common.WhiskProperties
-import spray.json.JsObject
-import spray.json.JsString
-import spray.json.JsValue
-import spray.json.pimpString
-import org.apache.commons.lang3.StringUtils
+import spray.json._
+import whisk.core.entity.Exec
 
 /**
  * For testing convenience, this interface abstracts away the REST calls to a
@@ -54,7 +52,13 @@
 trait ActionProxyContainerTestUtils extends FlatSpec with Matchers {
     import ActionContainer.{ filterSentinel, sentinel }
 
-    def initPayload(code: String, main: String = "main") = JsObject("value" -> JsObject("code" -> JsString(code), "main" -> JsString(main)))
+    def initPayload(code: String, main: String = "main") = {
+        JsObject("value" -> JsObject(
+            "code" -> JsString(code),
+            "main" -> JsString(main),
+            "binary" -> JsBoolean(Exec.isBinaryCode(code))))
+    }
+
     def runPayload(args: JsValue, other: Option[JsObject] = None) = {
         JsObject(Map("value" -> args) ++ (other map { _.fields } getOrElse Map()))
     }
@@ -155,13 +159,12 @@
 
     private def syncPost(host: String, port: Int, endPoint: String, content: JsValue)(
         implicit actorSystem: ActorSystem): (Int, Option[JsObject]) = {
-        import whisk.core.container.AkkaHttpUtils
-
-        import akka.http.scaladsl.model._
-        import akka.http.scaladsl.marshalling._
-        import akka.http.scaladsl.unmarshalling._
         import akka.http.scaladsl.marshallers.sprayjson.SprayJsonSupport._
+        import akka.http.scaladsl.marshalling._
+        import akka.http.scaladsl.model._
+        import akka.http.scaladsl.unmarshalling._
         import akka.stream.ActorMaterializer
+        import whisk.core.container.AkkaHttpUtils
 
         implicit val materializer = ActorMaterializer()
 
diff --git a/tests/src/actionContainers/NodeJs6ActionContainerTests.scala b/tests/src/actionContainers/NodeJs6ActionContainerTests.scala
index 7b7992f..212d18d 100644
--- a/tests/src/actionContainers/NodeJs6ActionContainerTests.scala
+++ b/tests/src/actionContainers/NodeJs6ActionContainerTests.scala
@@ -16,8 +16,6 @@
 
 package actionContainers
 
-import whisk.core.entity.NodeJS6Exec
-
 import org.junit.runner.RunWith
 import org.scalatest.junit.JUnitRunner
 
@@ -29,8 +27,6 @@
 
     override lazy val nodejsContainerImageName = "nodejs6action"
 
-    override def exec(code: String) = NodeJS6Exec(code, None)
-
     behavior of nodejsContainerImageName
 
     it should "support default function parameters" in {
diff --git a/tests/src/actionContainers/NodeJsActionContainerTests.scala b/tests/src/actionContainers/NodeJsActionContainerTests.scala
index 20f7d7a..041bf2c 100644
--- a/tests/src/actionContainers/NodeJsActionContainerTests.scala
+++ b/tests/src/actionContainers/NodeJsActionContainerTests.scala
@@ -18,8 +18,6 @@
 import org.junit.runner.RunWith
 import org.scalatest.junit.JUnitRunner
 
-import whisk.core.entity.{ NodeJSAbstractExec, NodeJSExec }
-
 import ActionContainer.withContainer
 import ResourceHelpers.ZipBuilder
 
@@ -37,18 +35,6 @@
 
     def withNodeJsContainer(code: ActionContainer => Unit) = withActionContainer()(code)
 
-    def exec(code: String): NodeJSAbstractExec = NodeJSExec(code, None)
-
-    override def initPayload(code: String, main: String = "main") = {
-        val e = exec(code)
-        JsObject(
-            "value" -> JsObject(
-                "name" -> JsString("dummyAction"),
-                "code" -> JsString(e.code),
-                "binary" -> JsBoolean(e.binary),
-                "main" -> JsString(main)))
-    }
-
     behavior of nodejsContainerImageName
 
     testNotReturningJson(
diff --git a/tests/src/whisk/core/entity/test/SchemaTests.scala b/tests/src/whisk/core/entity/test/SchemaTests.scala
index 86f9f84..4cb0c7d 100644
--- a/tests/src/whisk/core/entity/test/SchemaTests.scala
+++ b/tests/src/whisk/core/entity/test/SchemaTests.scala
@@ -161,14 +161,14 @@
     behavior of "EntityName"
 
     it should "accept well formed names" in {
-        val paths = Seq("a", "a b", "a@b.c", "_a", "_", "_ _", "a0", "a 0", "a.0", "a@@", "0", "0.0", "0.0.0", "0a", "0.a", "a"*EntityName.ENTITY_NAME_MAX_LENGTH)
+        val paths = Seq("a", "a b", "a@b.c", "_a", "_", "_ _", "a0", "a 0", "a.0", "a@@", "0", "0.0", "0.0.0", "0a", "0.a", "a" * EntityName.ENTITY_NAME_MAX_LENGTH)
         paths.foreach { n =>
             assert(EntityName(n).toString == n)
         }
     }
 
     it should "reject malformed names" in {
-        val paths = Seq(null, "", " ", " xxx", "xxx ", "/", " /", "/ ", "0 ", "_ ", "a  ", "a \t", "a\n", "a"*(EntityName.ENTITY_NAME_MAX_LENGTH+1))
+        val paths = Seq(null, "", " ", " xxx", "xxx ", "/", " /", "/ ", "0 ", "_ ", "a  ", "a \t", "a\n", "a" * (EntityName.ENTITY_NAME_MAX_LENGTH + 1))
         paths.foreach {
             p => an[IllegalArgumentException] should be thrownBy EntityName(p)
         }
@@ -320,6 +320,7 @@
             JsObject("kind" -> "nodejs".toJson, "code" -> "js1".toJson, "binary" -> false.toJson),
             JsObject("kind" -> "nodejs".toJson, "code" -> "js2".toJson, "binary" -> false.toJson, "foo" -> "bar".toJson),
             JsObject("kind" -> "swift".toJson, "code" -> "swift1".toJson, "binary" -> false.toJson),
+            JsObject("kind" -> "swift:3".toJson, "code" -> b64Body.toJson, "binary" -> true.toJson),
             JsObject("kind" -> "nodejs".toJson, "code" -> b64Body.toJson, "binary" -> true.toJson))
 
         val execs = json.map { e => Exec.serdes.read(e) }
@@ -327,7 +328,8 @@
         assert(execs(0) == Exec.js("js1") && json(0).compactPrint == Exec.js("js1").toString)
         assert(execs(1) == Exec.js("js2") && json(1).compactPrint != Exec.js("js2").toString) // ignores unknown properties
         assert(execs(2) == Exec.swift("swift1") && json(2).compactPrint == Exec.swift("swift1").toString)
-        assert(execs(3) == Exec.js(b64Body) && json(3).compactPrint == Exec.js(b64Body).toString)
+        assert(execs(3) == Exec.swift3(b64Body) && json(3).compactPrint == Exec.swift3(b64Body).toString)
+        assert(execs(4) == Exec.js(b64Body) && json(4).compactPrint == Exec.js(b64Body).toString)
     }
 
     it should "properly deserialize and reserialize JSON blackbox" in {
@@ -381,11 +383,11 @@
     }
 
     it should "serialize to json" in {
-        val execs = Seq(Exec.bb("container"), Exec.js("js"), Exec.js("js"), Exec.swift("swft")).map { _.toString }
+        val execs = Seq(Exec.bb("container"), Exec.js("js"), Exec.js("js"), Exec.swift("swift")).map { _.toString }
         assert(execs(0) == JsObject("kind" -> "blackbox".toJson, "image" -> "container".toJson, "binary" -> false.toJson).compactPrint)
         assert(execs(1) == JsObject("kind" -> "nodejs".toJson, "code" -> "js".toJson, "binary" -> false.toJson).compactPrint)
         assert(execs(2) == JsObject("kind" -> "nodejs".toJson, "code" -> "js".toJson, "binary" -> false.toJson).compactPrint)
-        assert(execs(3) == JsObject("kind" -> "swift".toJson, "code" -> "swft".toJson, "binary" -> false.toJson).compactPrint)
+        assert(execs(3) == JsObject("kind" -> "swift".toJson, "code" -> "swift".toJson, "binary" -> false.toJson).compactPrint)
     }
 
     behavior of "Parameter"