You are viewing a plain text version of this content. The canonical link for it is here.
Posted to issues@openwhisk.apache.org by GitBox <gi...@apache.org> on 2018/03/28 02:41:07 UTC

[GitHub] csantanapr closed pull request #31: update npm openwhisk to 3.14.0

csantanapr closed pull request #31: update npm openwhisk to 3.14.0
URL: https://github.com/apache/incubator-openwhisk-runtime-nodejs/pull/31
 
 
   

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/core/nodejs6Action/CHANGELOG.md b/core/nodejs6Action/CHANGELOG.md
index 079a4a2..16ceabb 100644
--- a/core/nodejs6Action/CHANGELOG.md
+++ b/core/nodejs6Action/CHANGELOG.md
@@ -1,5 +1,10 @@
 # NodeJS 6 OpenWhisk Runtime Container
 
+## 1.7.0
+Change: Update npm openwhisk package
+
+- [openwhisk v3.14.0](https://www.npmjs.com/package/openwhisk) - JavaScript client library for the OpenWhisk platform. Provides a wrapper around the OpenWhisk APIs.
+
 ## 1.6.0
 Change: Update npm openwhisk package
 
diff --git a/core/nodejs6Action/Dockerfile b/core/nodejs6Action/Dockerfile
index f8eef8c..9e6b834 100644
--- a/core/nodejs6Action/Dockerfile
+++ b/core/nodejs6Action/Dockerfile
@@ -46,7 +46,7 @@ nano@6.2.0 \
 node-uuid@1.4.7 \
 nodemailer@2.6.4 \
 oauth2-server@2.4.1 \
-openwhisk@3.13.1 \
+openwhisk@3.14.0 \
 pkgcloud@1.4.0 \
 process@0.11.9 \
 pug@">=2.0.0-beta6 <2.0.1" \
diff --git a/core/nodejs8Action/CHANGELOG.md b/core/nodejs8Action/CHANGELOG.md
index 2ad64e9..e1b2d11 100644
--- a/core/nodejs8Action/CHANGELOG.md
+++ b/core/nodejs8Action/CHANGELOG.md
@@ -1,5 +1,12 @@
 # NodeJS 8 OpenWhisk Runtime Container
 
+## 1.4.0
+Change: Update nodejs and openwhisk npm package
+
+Node version = 8.10.0
+
+- [openwhisk v3.14.0](https://www.npmjs.com/package/openwhisk) - JavaScript client library for the OpenWhisk platform. Provides a wrapper around the OpenWhisk APIs.
+
 ## 1.3.0
 Change: Update npm openwhisk package
 
diff --git a/core/nodejs8Action/Dockerfile b/core/nodejs8Action/Dockerfile
index 43eafae..31dea72 100644
--- a/core/nodejs8Action/Dockerfile
+++ b/core/nodejs8Action/Dockerfile
@@ -1,4 +1,4 @@
-FROM node:8.9.3
+FROM node:8.10.0
 RUN apt-get update && apt-get install -y \
     imagemagick \
     unzip \
diff --git a/core/nodejs8Action/package.json b/core/nodejs8Action/package.json
index 7eab06b..9eb2d84 100644
--- a/core/nodejs8Action/package.json
+++ b/core/nodejs8Action/package.json
@@ -8,7 +8,7 @@
   },
   "license": "Apache-2.0",
   "dependencies": {
-    "openwhisk": "3.13.1",
+    "openwhisk": "3.14.0",
     "body-parser": "1.18.2",
     "express": "4.16.2"
   }
diff --git a/tests/src/test/scala/actionContainers/ActionContainer.scala b/tests/src/test/scala/actionContainers/ActionContainer.scala
deleted file mode 100644
index 56aa131..0000000
--- a/tests/src/test/scala/actionContainers/ActionContainer.scala
+++ /dev/null
@@ -1,174 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements.  See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License.  You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package runtime.actionContainers
-
-import java.io.ByteArrayOutputStream
-import java.io.File
-import java.io.PrintWriter
-
-import scala.concurrent.Await
-import scala.concurrent.ExecutionContext.Implicits.global
-import scala.concurrent.Future
-import scala.concurrent.blocking
-import scala.concurrent.duration.Duration
-import scala.concurrent.duration.DurationInt
-import scala.language.postfixOps
-import scala.sys.process.ProcessLogger
-import scala.sys.process.stringToProcess
-import scala.util.Random
-
-import org.apache.commons.lang3.StringUtils
-import org.scalatest.FlatSpec
-import org.scalatest.Matchers
-
-import akka.actor.ActorSystem
-import common.WhiskProperties
-import spray.json._
-import whisk.core.entity.Exec
-
-/**
- * For testing convenience, this interface abstracts away the REST calls to a
- * container as blocking method calls of this interface.
- */
-trait ActionContainer {
-  def init(value: JsValue): (Int, Option[JsObject])
-  def run(value: JsValue): (Int, Option[JsObject])
-}
-
-trait ActionProxyContainerTestUtils extends FlatSpec with Matchers {
-  import ActionContainer.{filterSentinel, sentinel}
-
-  def initPayload(code: String, main: String = "main") = {
-    JsObject(
-      "value" -> JsObject(
-        "code" -> { if (code != null) JsString(code) else JsNull },
-        "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()))
-  }
-
-  def checkStreams(out: String, err: String, additionalCheck: (String, String) => Unit, sentinelCount: Int = 1) = {
-    withClue("expected number of stdout sentinels") {
-      sentinelCount shouldBe StringUtils.countMatches(out, sentinel)
-    }
-    withClue("expected number of stderr sentinels") {
-      sentinelCount shouldBe StringUtils.countMatches(err, sentinel)
-    }
-
-    val (o, e) = (filterSentinel(out), filterSentinel(err))
-    o should not include (sentinel)
-    e should not include (sentinel)
-    additionalCheck(o, e)
-  }
-}
-
-object ActionContainer {
-  private lazy val dockerBin: String = {
-    List("/usr/bin/docker", "/usr/local/bin/docker")
-      .find { bin =>
-        new File(bin).isFile()
-      }
-      .getOrElse(???) // This fails if the docker binary couldn't be located.
-  }
-
-  private lazy val dockerCmd: String = {
-    val version = WhiskProperties.getProperty("whisk.version.name")
-    // Check if we are running on docker-machine env.
-    val hostStr = if (version.toLowerCase().contains("mac")) {
-      s" --host tcp://${WhiskProperties.getMainDockerEndpoint()} "
-    } else {
-      " "
-    }
-    s"$dockerBin $hostStr"
-  }
-
-  private def docker(command: String): String = s"$dockerCmd $command"
-
-  // Runs a process asynchronously. Returns a future with (exitCode,stdout,stderr)
-  private def proc(cmd: String): Future[(Int, String, String)] = Future {
-    blocking {
-      val out = new ByteArrayOutputStream
-      val err = new ByteArrayOutputStream
-      val outW = new PrintWriter(out)
-      val errW = new PrintWriter(err)
-      val v = cmd ! (ProcessLogger(outW.println, errW.println))
-      outW.close()
-      errW.close()
-      (v, out.toString, err.toString)
-    }
-  }
-
-  // Tying it all together, we have a method that runs docker, waits for
-  // completion for some time then returns the exit code, the output stream
-  // and the error stream.
-  private def awaitDocker(cmd: String, t: Duration): (Int, String, String) = {
-    Await.result(proc(docker(cmd)), t)
-  }
-
-  // Filters out the sentinel markers inserted by the container (see relevant private code in Invoker.scala)
-  val sentinel = "XXX_THE_END_OF_A_WHISK_ACTIVATION_XXX"
-  def filterSentinel(str: String) = str.replaceAll(sentinel, "").trim
-
-  def withContainer(imageName: String, environment: Map[String, String] = Map.empty)(code: ActionContainer => Unit)(
-    implicit actorSystem: ActorSystem): (String, String) = {
-    val rand = { val r = Random.nextInt; if (r < 0) -r else r }
-    val name = imageName.toLowerCase.replaceAll("""[^a-z]""", "") + rand
-    val envArgs = environment.toSeq.map {
-      case (k, v) => s"-e ${k}=${v}"
-    } mkString (" ")
-
-    // We create the container...
-    val runOut = awaitDocker(s"run --name $name $envArgs -d $imageName", 10 seconds)
-    assert(runOut._1 == 0, "'docker run' did not exit with 0: " + runOut)
-
-    // ...find out its IP address...
-    val ipOut = awaitDocker(s"""inspect --format '{{.NetworkSettings.IPAddress}}' $name""", 10 seconds)
-    assert(ipOut._1 == 0, "'docker inspect did not exit with 0")
-    val ip = ipOut._2.replaceAll("""[^0-9.]""", "")
-
-    // ...we create an instance of the mock container interface...
-    val mock = new ActionContainer {
-      def init(value: JsValue) = syncPost(ip, 8080, "/init", value)
-      def run(value: JsValue) = syncPost(ip, 8080, "/run", value)
-    }
-
-    try {
-      // ...and finally run the code with it.
-      code(mock)
-      // I'm told this is good for the logs.
-      Thread.sleep(100)
-      val (_, out, err) = awaitDocker(s"logs $name", 10 seconds)
-      (out, err)
-    } finally {
-      awaitDocker(s"kill $name", 10 seconds)
-      awaitDocker(s"rm $name", 10 seconds)
-    }
-  }
-
-  private def syncPost(host: String, port: Int, endPoint: String, content: JsValue): (Int, Option[JsObject]) = {
-    whisk.core.containerpool.HttpUtils.post(host, port, endPoint, content)
-  }
-
-  private class ActionContainerImpl() extends ActionContainer {
-    override def init(value: JsValue) = ???
-    override def run(value: JsValue) = ???
-  }
-}
diff --git a/tests/src/test/scala/actionContainers/ActionProxyContainerTests.scala b/tests/src/test/scala/actionContainers/ActionProxyContainerTests.scala
deleted file mode 100644
index 1471d12..0000000
--- a/tests/src/test/scala/actionContainers/ActionProxyContainerTests.scala
+++ /dev/null
@@ -1,348 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements.  See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License.  You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package runtime.actionContainers
-
-import java.io.File
-import java.util.Base64
-
-import org.apache.commons.io.FileUtils
-import org.junit.runner.RunWith
-import org.scalatest.junit.JUnitRunner
-
-import ActionContainer.withContainer
-import common.TestUtils
-import common.WskActorSystem
-import spray.json.DefaultJsonProtocol._
-import spray.json._
-
-@RunWith(classOf[JUnitRunner])
-class ActionProxyContainerTests extends BasicActionRunnerTests with WskActorSystem {
-
-  override def withActionContainer(env: Map[String, String] = Map.empty)(code: ActionContainer => Unit) = {
-    withContainer("dockerskeleton", env)(code)
-  }
-
-  val codeNotReturningJson = """
-           |#!/bin/sh
-           |echo not a json object
-        """.stripMargin.trim
-
-  /** Standard code samples, should print 'hello' to stdout and echo the input args. */
-  val stdCodeSamples = {
-    val bash = """
-                |#!/bin/bash
-                |echo 'hello stdout'
-                |echo 'hello stderr' 1>&2
-                |if [[ -z $1 || $1 == '{}' ]]; then
-                |   echo '{ "msg": "Hello from bash script!" }'
-                |else
-                |   echo $1 # echo the arguments back as the result
-                |fi
-            """.stripMargin.trim
-
-    val python = """
-                |#!/usr/bin/env python
-                |from __future__ import print_function
-                |import sys
-                |print('hello stdout')
-                |print('hello stderr', file=sys.stderr)
-                |print(sys.argv[1])
-            """.stripMargin.trim
-
-    val perl = """
-                |#!/usr/bin/env perl
-                |print STDOUT "hello stdout\n";
-                |print STDERR "hello stderr\n";
-                |print $ARGV[0];
-            """.stripMargin.trim
-
-    // excluding perl as it not installed in alpine based image
-    Seq(("bash", bash), ("python", python))
-  }
-
-  val stdUnicodeSamples = {
-    // python 3 in base image
-    val python = """
-                |#!/usr/bin/env python
-                |import json, sys
-                |j = json.loads(sys.argv[1])
-                |sep = j["delimiter"]
-                |s = sep + " ☃ " + sep
-                |print(s)
-                |print(json.dumps({"winter": s}))
-            """.stripMargin.trim
-
-    Seq(("python", python))
-  }
-
-  /** Standard code samples, should print 'hello' to stdout and echo the input args. */
-  val stdEnvSamples = {
-    val bash = """
-                |#!/bin/bash
-                |echo "{ \
-                |\"api_host\": \"$__OW_API_HOST\", \"api_key\": \"$__OW_API_KEY\", \
-                |\"namespace\": \"$__OW_NAMESPACE\", \"action_name\": \"$__OW_ACTION_NAME\", \
-                |\"activation_id\": \"$__OW_ACTIVATION_ID\", \"deadline\": \"$__OW_DEADLINE\" }"
-            """.stripMargin.trim
-
-    val python =
-      """
-                |#!/usr/bin/env python
-                |import os
-                |
-                |print('{ "api_host": "%s", "api_key": "%s", "namespace": "%s", "action_name" : "%s", "activation_id": "%s", "deadline": "%s" }' % (
-                |  os.environ['__OW_API_HOST'], os.environ['__OW_API_KEY'],
-                |  os.environ['__OW_NAMESPACE'], os.environ['__OW_ACTION_NAME'],
-                |  os.environ['__OW_ACTIVATION_ID'], os.environ['__OW_DEADLINE']))
-            """.stripMargin.trim
-
-    val perl =
-      """
-                |#!/usr/bin/env perl
-                |$a = $ENV{'__OW_API_HOST'};
-                |$b = $ENV{'__OW_API_KEY'};
-                |$c = $ENV{'__OW_NAMESPACE'};
-                |$d = $ENV{'__OW_ACTION_NAME'};
-                |$e = $ENV{'__OW_ACTIVATION_ID'};
-                |$f = $ENV{'__OW_DEADLINE'};
-                |print "{ \"api_host\": \"$a\", \"api_key\": \"$b\", \"namespace\": \"$c\", \"action_name\": \"$d\", \"activation_id\": \"$e\", \"deadline\": \"$f\" }";
-            """.stripMargin.trim
-
-    // excluding perl as it not installed in alpine based image
-    Seq(("bash", bash), ("python", python))
-  }
-
-  behavior of "openwhisk/dockerskeleton"
-
-  it should "run sample without init" in {
-    val (out, err) = withActionContainer() { c =>
-      val (runCode, out) = c.run(JsObject())
-      runCode should be(200)
-      out should be(Some(JsObject("error" -> JsString("This is a stub action. Replace it with custom logic."))))
-    }
-
-    checkStreams(out, err, {
-      case (o, _) => o should include("This is a stub action")
-    })
-  }
-
-  it should "run sample with 'null' init" in {
-    val (out, err) = withActionContainer() { c =>
-      val (initCode, _) = c.init(initPayload(null))
-      initCode should be(200)
-
-      val (runCode, out) = c.run(JsObject())
-      runCode should be(200)
-      out should be(Some(JsObject("error" -> JsString("This is a stub action. Replace it with custom logic."))))
-    }
-
-    checkStreams(out, err, {
-      case (o, _) => o should include("This is a stub action")
-    })
-  }
-
-  it should "run sample with init that does nothing" in {
-    val (out, err) = withActionContainer() { c =>
-      val (initCode, _) = c.init(JsObject())
-      initCode should be(200)
-      val (runCode, out) = c.run(JsObject())
-      runCode should be(200)
-      out should be(Some(JsObject("error" -> JsString("This is a stub action. Replace it with custom logic."))))
-    }
-
-    checkStreams(out, err, {
-      case (o, _) => o should include("This is a stub action")
-    })
-  }
-
-  it should "respond with 404 for bad run argument" in {
-    val (out, err) = withActionContainer() { c =>
-      val (runCode, out) = c.run(runPayload(JsString("A")))
-      runCode should be(404)
-    }
-
-    checkStreams(out, err, {
-      case (o, e) =>
-        o shouldBe empty
-        e shouldBe empty
-    })
-  }
-
-  it should "fail to run a bad script" in {
-    val (out, err) = withActionContainer() { c =>
-      val (initCode, _) = c.init(initPayload(""))
-      initCode should be(200)
-      val (runCode, out) = c.run(JsNull)
-      runCode should be(502)
-      out should be(Some(JsObject("error" -> JsString("The action did not return a dictionary."))))
-    }
-
-    checkStreams(out, err, {
-      case (o, _) => o should include("error")
-    })
-  }
-
-  it should "extract and run a compatible zip exec" in {
-    val zip = FileUtils.readFileToByteArray(new File(TestUtils.getTestActionFilename("blackbox.zip")))
-    val contents = Base64.getEncoder.encodeToString(zip)
-
-    val (out, err) = withActionContainer() { c =>
-      val (initCode, err) =
-        c.init(JsObject("value" -> JsObject("code" -> JsString(contents), "binary" -> JsBoolean(true))))
-      initCode should be(200)
-      val (runCode, out) = c.run(JsObject())
-      runCode should be(200)
-      out.get should be(JsObject("msg" -> JsString("hello zip")))
-    }
-
-    checkStreams(out, err, {
-      case (o, e) =>
-        o shouldBe "This is an example zip used with the docker skeleton action."
-        e shouldBe empty
-    })
-  }
-
-  testNotReturningJson(codeNotReturningJson, checkResultInLogs = true)
-  testEcho(stdCodeSamples)
-  testUnicode(stdUnicodeSamples)
-  testEnv(stdEnvSamples)
-}
-
-trait BasicActionRunnerTests extends ActionProxyContainerTestUtils {
-  def withActionContainer(env: Map[String, String] = Map.empty)(code: ActionContainer => Unit): (String, String)
-
-  /**
-   * Runs tests for actions which do not return a dictionary and confirms expected error messages.
-   * @param codeNotReturningJson code to execute, should not return a JSON object
-   * @param checkResultInLogs should be true iff the result of the action is expected to appear in stdout or stderr
-   */
-  def testNotReturningJson(codeNotReturningJson: String, checkResultInLogs: Boolean = true) = {
-    it should "run and report an error for script not returning a json object" in {
-      val (out, err) = withActionContainer() { c =>
-        val (initCode, _) = c.init(initPayload(codeNotReturningJson))
-        initCode should be(200)
-        val (runCode, out) = c.run(JsObject())
-        runCode should be(502)
-        out should be(Some(JsObject("error" -> JsString("The action did not return a dictionary."))))
-      }
-
-      checkStreams(out, err, {
-        case (o, e) =>
-          if (checkResultInLogs) {
-            (o + e) should include("not a json object")
-          } else {
-            o shouldBe empty
-            e shouldBe empty
-          }
-      })
-    }
-  }
-
-  /**
-   * Runs tests for code samples which are expected to echo the input arguments
-   * and print hello [stdout, stderr].
-   */
-  def testEcho(stdCodeSamples: Seq[(String, String)]) = {
-    stdCodeSamples.foreach { s =>
-      it should s"run a ${s._1} script" in {
-        val argss = List(
-          JsObject("string" -> JsString("hello")),
-          JsObject("string" -> JsString("❄ ☃ ❄")),
-          JsObject("numbers" -> JsArray(JsNumber(42), JsNumber(1))),
-          // JsObject("boolean" -> JsBoolean(true)), // fails with swift3 returning boolean: 1
-          JsObject("object" -> JsObject("a" -> JsString("A"))))
-
-        val (out, err) = withActionContainer() { c =>
-          val (initCode, _) = c.init(initPayload(s._2))
-          initCode should be(200)
-
-          for (args <- argss) {
-            val (runCode, out) = c.run(runPayload(args))
-            runCode should be(200)
-            out should be(Some(args))
-          }
-        }
-
-        checkStreams(out, err, {
-          case (o, e) =>
-            o should include("hello stdout")
-            e should include("hello stderr")
-        }, argss.length)
-      }
-    }
-  }
-
-  def testUnicode(stdUnicodeSamples: Seq[(String, String)]) = {
-    stdUnicodeSamples.foreach { s =>
-      it should s"run a ${s._1} action and handle unicode in source, input params, logs, and result" in {
-        val (out, err) = withActionContainer() { c =>
-          val (initCode, _) = c.init(initPayload(s._2))
-          initCode should be(200)
-
-          val (runCode, runRes) = c.run(runPayload(JsObject("delimiter" -> JsString("❄"))))
-          runRes.get.fields.get("winter") shouldBe Some(JsString("❄ ☃ ❄"))
-        }
-
-        checkStreams(out, err, {
-          case (o, _) =>
-            o.toLowerCase should include("❄ ☃ ❄")
-        })
-      }
-    }
-  }
-
-  /** Runs tests for code samples which are expected to return the expected standard environment {auth, edge}. */
-  def testEnv(stdEnvSamples: Seq[(String, String)],
-              enforceEmptyOutputStream: Boolean = true,
-              enforceEmptyErrorStream: Boolean = true) = {
-    stdEnvSamples.foreach { s =>
-      it should s"run a ${s._1} script and confirm expected environment variables" in {
-        val props = Seq(
-          "api_host" -> "xyz",
-          "api_key" -> "abc",
-          "namespace" -> "zzz",
-          "action_name" -> "xxx",
-          "activation_id" -> "iii",
-          "deadline" -> "123")
-        val env = props.map { case (k, v) => s"__OW_${k.toUpperCase()}" -> v }
-
-        val (out, err) = withActionContainer(env.take(1).toMap) { c =>
-          val (initCode, _) = c.init(initPayload(s._2))
-          initCode should be(200)
-
-          val (runCode, out) = c.run(runPayload(JsObject(), Some(props.toMap.toJson.asJsObject)))
-          runCode should be(200)
-          out shouldBe defined
-          props.map {
-            case (k, v) =>
-              withClue(k) {
-                out.get.fields(k) shouldBe JsString(v)
-              }
-
-          }
-        }
-
-        checkStreams(out, err, {
-          case (o, e) =>
-            if (enforceEmptyOutputStream) o shouldBe empty
-            if (enforceEmptyErrorStream) e shouldBe empty
-        })
-      }
-    }
-  }
-}
diff --git a/tests/src/test/scala/actionContainers/ResourceHelpers.scala b/tests/src/test/scala/actionContainers/ResourceHelpers.scala
deleted file mode 100644
index 08f46e4..0000000
--- a/tests/src/test/scala/actionContainers/ResourceHelpers.scala
+++ /dev/null
@@ -1,190 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements.  See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License.  You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package runtime.actionContainers
-
-import java.net.URI
-import java.net.URLClassLoader
-import java.nio.file.Files
-import java.nio.file.Path
-import java.nio.file.Paths
-import java.nio.file.SimpleFileVisitor
-import java.nio.file.FileVisitResult
-import java.nio.file.FileSystems
-import java.nio.file.attribute.BasicFileAttributes
-import java.nio.charset.StandardCharsets
-import java.util.Base64
-
-import javax.tools.ToolProvider
-
-import collection.JavaConverters._
-
-/**
- * A collection of utility objects to create ephemeral action resources based
- *  on file contents.
- */
-object ResourceHelpers {
-
-  /** Creates a zip file based on the contents of a top-level directory. */
-  object ZipBuilder {
-    def mkBase64Zip(sources: Seq[(Seq[String], String)]): String = {
-      val (tmpDir, _) = writeSourcesToTempDirectory(sources)
-      val archive = makeZipFromDir(tmpDir)
-      readAsBase64(archive)
-    }
-  }
-
-  /**
-   * A convenience object to compile and package Java sources into a JAR, and to
-   * encode that JAR as a base 64 string. The compilation options include the
-   * current classpath, which is why Google GSON is readily available (though not
-   * packaged in the JAR).
-   */
-  object JarBuilder {
-    def mkBase64Jar(sources: Seq[(Seq[String], String)]): String = {
-      // Note that this pipeline doesn't delete any of the temporary files.
-      val binDir = compile(sources)
-      val jarPath = makeJarFromDir(binDir)
-      val base64 = readAsBase64(jarPath)
-      base64
-    }
-
-    def mkBase64Jar(source: (Seq[String], String)): String = {
-      mkBase64Jar(Seq(source))
-    }
-
-    private def compile(sources: Seq[(Seq[String], String)]): Path = {
-      require(!sources.isEmpty)
-
-      // The absolute paths of the source file
-      val (srcDir, srcAbsPaths) = writeSourcesToTempDirectory(sources)
-
-      // A temporary directory for the destination files.
-      val binDir = Files.createTempDirectory("bin").toAbsolutePath()
-
-      // Preparing the compiler
-      val compiler = ToolProvider.getSystemJavaCompiler()
-      val fileManager = compiler.getStandardFileManager(null, null, StandardCharsets.UTF_8)
-
-      // Collecting all files to be compiled
-      val compUnit = fileManager.getJavaFileObjectsFromFiles(srcAbsPaths.map(_.toFile).asJava)
-
-      // Setting the options
-      val compOptions = Seq("-d", binDir.toAbsolutePath().toString(), "-classpath", buildClassPath())
-      val compTask = compiler.getTask(null, fileManager, null, compOptions.asJava, null, compUnit)
-
-      // ...and off we go.
-      compTask.call()
-
-      binDir
-    }
-
-    private def buildClassPath(): String = {
-      val bcp = System.getProperty("java.class.path")
-
-      val list = this.getClass().getClassLoader() match {
-        case ucl: URLClassLoader =>
-          bcp :: ucl.getURLs().map(_.getFile().toString()).toList
-
-        case _ =>
-          List(bcp)
-      }
-
-      list.mkString(System.getProperty("path.separator"))
-    }
-  }
-
-  /**
-   * Creates a temporary directory and reproduces the desired file structure
-   * in it. Returns the path of the temporary directory and the path of each
-   * file as represented in it.
-   */
-  private def writeSourcesToTempDirectory(sources: Seq[(Seq[String], String)]): (Path, Seq[Path]) = {
-    // A temporary directory for the source files.
-    val srcDir = Files.createTempDirectory("src").toAbsolutePath()
-
-    val srcAbsPaths = for ((sourceName, sourceContent) <- sources) yield {
-      // The relative path of the source file
-      val srcRelPath = Paths.get(sourceName.head, sourceName.tail: _*)
-      // The absolute path of the source file
-      val srcAbsPath = srcDir.resolve(srcRelPath)
-      // Create parent directories if needed.
-      Files.createDirectories(srcAbsPath.getParent)
-      // Writing contents
-      Files.write(srcAbsPath, sourceContent.getBytes(StandardCharsets.UTF_8))
-
-      srcAbsPath
-    }
-
-    (srcDir, srcAbsPaths)
-  }
-
-  private def makeZipFromDir(dir: Path): Path = makeArchiveFromDir(dir, ".zip")
-
-  private def makeJarFromDir(dir: Path): Path = makeArchiveFromDir(dir, ".jar")
-
-  /**
-   * Compresses all files beyond a directory into a zip file.
-   * Note that Jar files are just zip files.
-   */
-  private def makeArchiveFromDir(dir: Path, extension: String): Path = {
-    // Any temporary file name for the archive.
-    val arPath = Files.createTempFile("output", extension).toAbsolutePath()
-
-    // We "mount" it as a filesystem, so we can just copy files into it.
-    val dstUri = new URI("jar:" + arPath.toUri().getScheme(), arPath.toAbsolutePath().toString(), null)
-    // OK, that's a hack. Doing this because newFileSystem wants to create that file.
-    arPath.toFile().delete()
-    val fs = FileSystems.newFileSystem(dstUri, Map(("create" -> "true")).asJava)
-
-    // Traversing all files in the bin directory...
-    Files.walkFileTree(
-      dir,
-      new SimpleFileVisitor[Path]() {
-        override def visitFile(path: Path, attributes: BasicFileAttributes) = {
-          // The path relative to the src dir
-          val relPath = dir.relativize(path)
-
-          // The corresponding path in the zip
-          val arRelPath = fs.getPath(relPath.toString())
-
-          // If this file is not top-level in the src dir...
-          if (relPath.getParent() != null) {
-            // ...create the directory structure if it doesn't exist.
-            if (!Files.exists(arRelPath.getParent())) {
-              Files.createDirectories(arRelPath.getParent())
-            }
-          }
-
-          // Finally we can copy that file.
-          Files.copy(path, arRelPath)
-
-          FileVisitResult.CONTINUE
-        }
-      })
-
-    fs.close()
-
-    arPath
-  }
-
-  /** Reads the contents of a (possibly binary) file into a base64-encoded String */
-  def readAsBase64(path: Path): String = {
-    val encoder = Base64.getEncoder()
-    new String(encoder.encode(Files.readAllBytes(path)), StandardCharsets.UTF_8)
-  }
-}
diff --git a/tests/src/test/scala/runtime/actionContainers/NodeJs6ActionContainerTests.scala b/tests/src/test/scala/runtime/actionContainers/NodeJs6ActionContainerTests.scala
new file mode 100644
index 0000000..78f064e
--- /dev/null
+++ b/tests/src/test/scala/runtime/actionContainers/NodeJs6ActionContainerTests.scala
@@ -0,0 +1,28 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package runtime.actionContainers
+
+import org.junit.runner.RunWith
+import org.scalatest.junit.JUnitRunner
+
+@RunWith(classOf[JUnitRunner])
+class NodeJs6ActionContainerTests extends NodeJsActionContainerTests {
+
+  override lazy val nodejsContainerImageName = "nodejs6action"
+
+}
diff --git a/tests/src/test/scala/actionContainers/NodeJs8ActionContainerTests.scala b/tests/src/test/scala/runtime/actionContainers/NodeJs8ActionContainerTests.scala
similarity index 98%
rename from tests/src/test/scala/actionContainers/NodeJs8ActionContainerTests.scala
rename to tests/src/test/scala/runtime/actionContainers/NodeJs8ActionContainerTests.scala
index 8727a7f..ec57018 100644
--- a/tests/src/test/scala/actionContainers/NodeJs8ActionContainerTests.scala
+++ b/tests/src/test/scala/runtime/actionContainers/NodeJs8ActionContainerTests.scala
@@ -15,7 +15,7 @@
  * limitations under the License.
  */
 
-package actionContainers
+package runtime.actionContainers
 
 import org.junit.runner.RunWith
 import org.scalatest.junit.JUnitRunner
diff --git a/tests/src/test/scala/actionContainers/NodeJsActionContainerTests.scala b/tests/src/test/scala/runtime/actionContainers/NodeJsActionContainerTests.scala
similarity index 98%
rename from tests/src/test/scala/actionContainers/NodeJsActionContainerTests.scala
rename to tests/src/test/scala/runtime/actionContainers/NodeJsActionContainerTests.scala
index be45a52..8898e22 100644
--- a/tests/src/test/scala/actionContainers/NodeJsActionContainerTests.scala
+++ b/tests/src/test/scala/runtime/actionContainers/NodeJsActionContainerTests.scala
@@ -15,19 +15,15 @@
  * limitations under the License.
  */
 
-package actionContainers
-
-import org.junit.runner.RunWith
-import org.scalatest.junit.JUnitRunner
-
-import ActionContainer.withContainer
-import ResourceHelpers.ZipBuilder
+package runtime.actionContainers
 
 import common.WskActorSystem
+import actionContainers.{ActionContainer, BasicActionRunnerTests}
+import actionContainers.ActionContainer.withContainer
+import actionContainers.ResourceHelpers.ZipBuilder
 import spray.json._
 
-@RunWith(classOf[JUnitRunner])
-class NodeJsActionContainerTests extends BasicActionRunnerTests with WskActorSystem {
+abstract class NodeJsActionContainerTests extends BasicActionRunnerTests with WskActorSystem {
 
   lazy val nodejsContainerImageName = "nodejs6action"
 


 

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


With regards,
Apache Git Services