This is an automated email from the ASF dual-hosted git repository. dubeejw pushed a commit to branch master in repository https://gitbox.apache.org/repos/asf/incubator-openwhisk-runtime-swift.git
The following commit(s) were added to refs/heads/master by this push: new 193e197 remove swift:3 runtime (#8) 193e197 is described below commit 193e1978e728aea848e6b177b06b587cd65994f2 Author: Carlos Santana <csantan...@gmail.com> AuthorDate: Thu Nov 30 21:08:08 2017 -0500 remove swift:3 runtime (#8) - remove swift:3 runtime, added kafkas in ansible hosts, remove swift:3 tests --- ansible/environments/local/group_vars/all | 2 +- ansible/environments/local/hosts | 7 +- core/swift3.1.1Action/build.gradle | 27 -- .../epilogue.swift | 0 .../spm-build/_Whisk.swift | 0 .../spm-build/_WhiskJSONUtils.swift | 0 .../swift3runner.py | 0 core/swift3Action/Dockerfile | 68 ---- core/swift3Action/build.gradle | 13 - core/swift3Action/buildandrecord.py | 76 ----- core/swift3Action/spm-build/Package.swift | 28 -- settings.gradle | 1 - .../Swift311ActionContainerTests.scala | 334 ++++++++++++++++++- .../Swift3ActionContainerTests.scala | 363 --------------------- tools/travis/build.sh | 2 +- tools/travis/publish.sh | 4 +- 16 files changed, 338 insertions(+), 587 deletions(-) diff --git a/ansible/environments/local/group_vars/all b/ansible/environments/local/group_vars/all index 307c06d..5d6a325 100755 --- a/ansible/environments/local/group_vars/all +++ b/ansible/environments/local/group_vars/all @@ -38,7 +38,7 @@ runtimes_manifest: - kind: "swift:3" image: name: "swift3action" - deprecated: false + deprecated: true - kind: "swift:3.1.1" default: true image: diff --git a/ansible/environments/local/hosts b/ansible/environments/local/hosts index c99f195..4715e55 100644 --- a/ansible/environments/local/hosts +++ b/ansible/environments/local/hosts @@ -9,8 +9,11 @@ ansible ansible_connection=local [controllers] controller0 ansible_host=172.17.0.1 ansible_connection=local -[kafka] -172.17.0.1 ansible_host=172.17.0.1 ansible_connection=local +[kafkas] +kafka0 ansible_host=172.17.0.1 ansible_connection=local + +[zookeepers:children] +kafkas [invokers] invoker0 ansible_host=172.17.0.1 ansible_connection=local diff --git a/core/swift3.1.1Action/build.gradle b/core/swift3.1.1Action/build.gradle index d26283e..c977a30 100755 --- a/core/swift3.1.1Action/build.gradle +++ b/core/swift3.1.1Action/build.gradle @@ -1,10 +1,6 @@ ext.dockerImageName = 'action-swift-v3.1.1' apply from: '../../gradle/docker.gradle' distDocker.dependsOn 'copyProxy' -distDocker.dependsOn 'copyEpilogue' -distDocker.dependsOn 'copySwiftRunner' -distDocker.dependsOn 'copyWhisk' -distDocker.dependsOn 'copyWhiskJsonUtils' distDocker.finalizedBy('cleanup') task copyProxy(type: Copy) { @@ -12,30 +8,7 @@ task copyProxy(type: Copy) { into './actionproxy.py' } -task copyEpilogue(type: Copy) { - from '../swift3Action/epilogue.swift' - into '.' -} - -task copySwiftRunner(type: Copy) { - from '../swift3Action/swift3runner.py' - into '.' -} - -task copyWhisk(type: Copy) { - from '../swift3Action/spm-build/_Whisk.swift' - into './spm-build' -} - -task copyWhiskJsonUtils(type: Copy) { - from '../swift3Action/spm-build/_WhiskJSONUtils.swift' - into './spm-build' -} - task cleanup(type: Delete) { delete 'actionproxy.py' - delete 'epilogue.swift' delete 'swift3runner.py' - delete 'spm-build/_Whisk.swift' - delete 'spm-build/_WhiskJSONUtils.swift' } diff --git a/core/swift3Action/epilogue.swift b/core/swift3.1.1Action/epilogue.swift similarity index 100% rename from core/swift3Action/epilogue.swift rename to core/swift3.1.1Action/epilogue.swift diff --git a/core/swift3Action/spm-build/_Whisk.swift b/core/swift3.1.1Action/spm-build/_Whisk.swift similarity index 100% rename from core/swift3Action/spm-build/_Whisk.swift rename to core/swift3.1.1Action/spm-build/_Whisk.swift diff --git a/core/swift3Action/spm-build/_WhiskJSONUtils.swift b/core/swift3.1.1Action/spm-build/_WhiskJSONUtils.swift similarity index 100% rename from core/swift3Action/spm-build/_WhiskJSONUtils.swift rename to core/swift3.1.1Action/spm-build/_WhiskJSONUtils.swift diff --git a/core/swift3Action/swift3runner.py b/core/swift3.1.1Action/swift3runner.py similarity index 100% rename from core/swift3Action/swift3runner.py rename to core/swift3.1.1Action/swift3runner.py diff --git a/core/swift3Action/Dockerfile b/core/swift3Action/Dockerfile deleted file mode 100644 index aa766d4..0000000 --- a/core/swift3Action/Dockerfile +++ /dev/null @@ -1,68 +0,0 @@ -# Dockerfile for swift actions, overrides and extends ActionRunner from actionProxy -# This Dockerfile is partially based on: https://github.com/swiftdocker/docker-swift/ -FROM buildpack-deps:trusty - -ENV DEBIAN_FRONTEND noninteractive - -# Upgrade and install basic Python dependencies -RUN apt-get -y purge \ - && apt-get -y update \ - && apt-get -y install --fix-missing python2.7 python-gevent python-flask \ -\ -# Upgrade and install Swift dependencies - && apt-get -y install --fix-missing build-essential curl wget libicu-dev \ -\ -# Install zip for compiling Swift actions - && apt-get -y install zip \ -\ -# Clean up - && apt-get clean - -# Install clang manually, since SPM wants at least Clang 3-6 -RUN cd / &&\ -(curl -L -k http://llvm.org/releases/3.6.2/clang+llvm-3.6.2-x86_64-linux-gnu-ubuntu-14.04.tar.xz | tar xJ) &&\ -cp -r /clang+llvm-3.6.2-x86_64-linux-gnu-ubuntu-14.04/* /usr/ &&\ -rm -rf /clang+llvm-3.6.2-x86_64-linux-gnu-ubuntu-14.04 - -RUN update-alternatives --install /usr/bin/g++ g++ /usr/bin/clang++ 20 -RUN update-alternatives --install /usr/bin/gcc gcc /usr/bin/clang 20 - -# Install Swift keys -RUN wget --no-verbose -O - https://swift.org/keys/all-keys.asc | gpg --import - && \ - gpg --keyserver hkp://pool.sks-keyservers.net --refresh-keys Swift - -# Install Swift Ubuntu 14.04 Snapshot -#https://swift.org/builds/swift-3.0.1-release/ubuntu1404/swift-3.0.1-RELEASE/swift-3.0.1-RELEASE-ubuntu14.04.tar.gz - -ENV SWIFT_VERSION 3.0.2 -ENV SWIFT_RELEASE_TYPE RELEASE -ENV SWIFT_PLATFORM ubuntu14.04 - -RUN SWIFT_ARCHIVE_NAME=swift-$SWIFT_VERSION-$SWIFT_RELEASE_TYPE-$SWIFT_PLATFORM && \ - SWIFT_URL=https://swift.org/builds/swift-$SWIFT_VERSION-$(echo "$SWIFT_RELEASE_TYPE" | tr '[:upper:]' '[:lower:]')/$(echo "$SWIFT_PLATFORM" | tr -d .)/swift-$SWIFT_VERSION-$SWIFT_RELEASE_TYPE/$SWIFT_ARCHIVE_NAME.tar.gz && \ - echo $SWIFT_URL && \ - wget --no-verbose $SWIFT_URL && \ - wget --no-verbose $SWIFT_URL.sig && \ - gpg --verify $SWIFT_ARCHIVE_NAME.tar.gz.sig && \ - tar -xzf $SWIFT_ARCHIVE_NAME.tar.gz --directory / --strip-components=1 && \ - rm -rf $SWIFT_ARCHIVE_NAME* /tmp/* /var/tmp/* - -# Add the action proxy -RUN mkdir -p /actionProxy -ADD actionproxy.py /actionProxy - -# Add files needed to build and run action -RUN mkdir -p /swift3Action -ADD epilogue.swift /swift3Action -ADD buildandrecord.py /swift3Action -ADD swift3runner.py /swift3Action -ADD spm-build /swift3Action/spm-build - - -# Build kitura net -RUN touch /swift3Action/spm-build/main.swift -RUN python /swift3Action/buildandrecord.py && rm /swift3Action/spm-build/.build/release/Action -#RUN cd /swift3Action/spm-build; swift build -c release; rm /swift3Action/spm-build/.build/release/Action -ENV FLASK_PROXY_PORT 8080 - -CMD ["/bin/bash", "-c", "cd /swift3Action && PYTHONIOENCODING='utf-8' python -u swift3runner.py"] \ No newline at end of file diff --git a/core/swift3Action/build.gradle b/core/swift3Action/build.gradle deleted file mode 100644 index 0148e31..0000000 --- a/core/swift3Action/build.gradle +++ /dev/null @@ -1,13 +0,0 @@ -ext.dockerImageName = 'swift3action' -apply from: '../../gradle/docker.gradle' -distDocker.dependsOn 'copyProxy' -distDocker.finalizedBy('rmProxy') - -task copyProxy(type: Copy) { - from '../actionProxy/actionproxy.py' - into './actionproxy.py' -} - -task rmProxy(type: Delete) { - delete 'actionproxy.py' -} diff --git a/core/swift3Action/buildandrecord.py b/core/swift3Action/buildandrecord.py deleted file mode 100644 index c83c024..0000000 --- a/core/swift3Action/buildandrecord.py +++ /dev/null @@ -1,76 +0,0 @@ -"""Python to generate build script. - -/* - * 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. - */ -""" -from __future__ import print_function -import os -import sys -from subprocess import check_output - -# Settings -COMPILE_PREFIX = "/usr/bin/swiftc -module-name Action " -LINKER_PREFIX = "/usr/bin/swiftc -Xlinker '-rpath=$ORIGIN' " \ - "'-L/swift3Action/spm-build/.build/release' " \ - "-o '/swift3Action/spm-build/.build/release/Action'" -GENERATED_BUILD_SCRIPT = "/swift3Action/spm-build/swiftbuildandlink.sh" -SPM_DIRECTORY = "/swift3Action/spm-build" -BUILD_COMMAND = ["swift", "build", "-v", "-c", "release"] - -# Build Swift package and capture step trace -print("Building action") -out = check_output(BUILD_COMMAND, cwd=SPM_DIRECTORY) -print("action built. Decoding compile and link commands") - -# Look for compile and link commands in step trace -compileCommand = None -linkCommand = None - -buildInstructions = out.decode("utf-8").splitlines() - -for instruction in buildInstructions: - if instruction.startswith(COMPILE_PREFIX): - compileCommand = instruction - - # add flag to quiet warnings - compileCommand += " -suppress-warnings" - - elif instruction.startswith(LINKER_PREFIX): - linkCommand = instruction - -# Create build script if found, exit otherwise -if compileCommand is not None and linkCommand is not None: - print("Success, command and link commands found.") - with open(GENERATED_BUILD_SCRIPT, "a") as buildScript: - buildScript.write("#!/bin/bash\n") - buildScript.write("echo \"Compiling\"\n") - buildScript.write("%s\n" % compileCommand) - buildScript.write("swiftStatus=$?\n") - buildScript.write("echo swiftc status is $swiftStatus\n") - buildScript.write("if [[ \"$swiftStatus\" -eq \"0\" ]]; then\n") - buildScript.write("echo \"Linking\"\n") - buildScript.write("%s\n" % linkCommand) - buildScript.write("else\n") - buildScript.write(">&2 echo \"Action did not compile\"\n") - buildScript.write("exit 1\n") - buildScript.write("fi") - - os.chmod(GENERATED_BUILD_SCRIPT, 0o777) - sys.exit(0) -else: - print("Cannot generate build script: compile or link command not found") - sys.exit(1) diff --git a/core/swift3Action/spm-build/Package.swift b/core/swift3Action/spm-build/Package.swift deleted file mode 100644 index 64268c2..0000000 --- a/core/swift3Action/spm-build/Package.swift +++ /dev/null @@ -1,28 +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. - */ - -import PackageDescription - -let package = Package( - name: "Action", - dependencies: [ - .Package(url: "https://github.com/IBM-Swift/CCurl.git", "0.2.3"), - .Package(url: "https://github.com/IBM-Swift/Kitura-net.git", "1.0.1"), - .Package(url: "https://github.com/IBM-Swift/SwiftyJSON.git", "14.2.0"), - .Package(url: "https://github.com/csantanapr/swift-watson-sdk.git", "0.4.1") - ] -) diff --git a/settings.gradle b/settings.gradle index f9536a8..a0f56d4 100644 --- a/settings.gradle +++ b/settings.gradle @@ -8,7 +8,6 @@ include 'whisktests'; project(':whisktests').projectDir = new File(owDirectory, include 'tests' -include 'core:swift3Action' include 'core:swift3.1.1Action' rootProject.name = 'runtime-swift' diff --git a/tests/src/test/scala/actionContainers/Swift311ActionContainerTests.scala b/tests/src/test/scala/actionContainers/Swift311ActionContainerTests.scala index e5c248d..058ef75 100644 --- a/tests/src/test/scala/actionContainers/Swift311ActionContainerTests.scala +++ b/tests/src/test/scala/actionContainers/Swift311ActionContainerTests.scala @@ -17,14 +17,68 @@ package runtime.actionContainers +import java.io.File + import org.junit.runner.RunWith import org.scalatest.junit.JUnitRunner +import ActionContainer.withContainer +import common.WskActorSystem +import spray.json.JsObject +import spray.json.JsString +import common.TestUtils + @RunWith(classOf[JUnitRunner]) -class Swift311ActionContainerTests extends Swift3ActionContainerTests { - override lazy val swiftContainerImageName = "action-swift-v3.1.1" +class Swift3ActionContainerTests extends BasicActionRunnerTests with WskActorSystem { + + // note: "out" will likely not be empty in some swift build as the compiler + // prints status messages and there doesn't seem to be a way to quiet them + val enforceEmptyOutputStream = false + lazy val swiftContainerImageName = "action-swift-v3.1.1" + lazy val envCode = makeEnvCode("ProcessInfo.processInfo") + + def makeEnvCode(processInfo: String) = (""" + |func main(args: [String: Any]) -> [String: Any] { + | let env = """ + processInfo + """.environment + | var a = "???" + | var b = "???" + | var c = "???" + | var d = "???" + | var e = "???" + | var f = "???" + | if let v : String = env["__OW_API_HOST"] { + | a = "\(v)" + | } + | if let v : String = env["__OW_API_KEY"] { + | b = "\(v)" + | } + | if let v : String = env["__OW_NAMESPACE"] { + | c = "\(v)" + | } + | if let v : String = env["__OW_ACTION_NAME"] { + | d = "\(v)" + | } + | if let v : String = env["__OW_ACTIVATION_ID"] { + | e = "\(v)" + | } + | if let v : String = env["__OW_DEADLINE"] { + | f = "\(v)" + | } + | return ["api_host": a, "api_key": b, "namespace": c, "action_name": d, "activation_id": e, "deadline": f] + |} + """).stripMargin - override lazy val watsonCode = """ + lazy val errorCode = """ + | // You need an indirection, or swiftc detects the div/0 + | // at compile-time. Smart. + | func div(x: Int, y: Int) -> Int { + | return x/y + | } + | func main(args: [String: Any]) -> [String: Any] { + | return [ "divBy0": div(x:5, y:0) ] + | } + """.stripMargin + lazy val watsonCode = """ | import AlchemyDataNewsV1 | import ConversationV1 | import DiscoveryV1 @@ -41,5 +95,277 @@ class Swift311ActionContainerTests extends Swift3ActionContainerTests { | return ["message": "I compiled and was able to import Watson SDKs"] | } """.stripMargin - override lazy val swiftBinaryName = "helloSwift311.zip" + lazy val swiftBinaryName = "helloSwift311.zip" + + // Helpers specific to swift actions + override def withActionContainer(env: Map[String, String] = Map.empty)(code: ActionContainer => Unit) = { + withContainer(swiftContainerImageName, env)(code) + } + + behavior of swiftContainerImageName + + // remove this test: it will not even compile under Swift 3 anymore + // so it should not be possible to write an action that does not return + // a [String:Any] + /*testNotReturningJson( + """ + |func main(args: [String: Any]) -> String { + | return "not a json object" + |} + """.stripMargin) + */ + + testEcho(Seq { + ( + "swift", + """ + | import Foundation + | + | extension FileHandle : TextOutputStream { + | public func write(_ string: String) { + | guard let data = string.data(using: .utf8) else { return } + | self.write(data) + | } + | } + | + | func main(args: [String: Any]) -> [String: Any] { + | print("hello stdout") + | var standardError = FileHandle.standardError + | print("hello stderr", to: &standardError) + | return args + | } + """.stripMargin) + }) + + testUnicode(Seq { + ( + "swift", + """ + | func main(args: [String: Any]) -> [String: Any] { + | if let str = args["delimiter"] as? String { + | let msg = "\(str) ☃ \(str)" + | print(msg) + | return [ "winter" : msg ] + | } else { + | return [ "error" : "no delimiter" ] + | } + | } + """.stripMargin.trim) + }) + + testEnv(Seq { + ("swift", envCode) + }, enforceEmptyOutputStream) + + it should "support actions using non-default entry points" in { + withActionContainer() { c => + val code = """ + | func niam(args: [String: Any]) -> [String: Any] { + | return [ "result": "it works" ] + | } + |""".stripMargin + + val (initCode, initRes) = c.init(initPayload(code, main = "niam")) + initCode should be(200) + + val (_, runRes) = c.run(runPayload(JsObject())) + runRes.get.fields.get("result") shouldBe Some(JsString("it works")) + } + } + + it should "return some error on action error" in { + val (out, err) = withActionContainer() { c => + val code = errorCode + + val (initCode, _) = c.init(initPayload(code)) + initCode should be(200) + + val (runCode, runRes) = c.run(runPayload(JsObject())) + runCode should be(502) + + runRes shouldBe defined + runRes.get.fields.get("error") shouldBe defined + } + + checkStreams(out, err, { + case (o, e) => + if (enforceEmptyOutputStream) o shouldBe empty + e shouldBe empty + }) + } + + it should "log compilation errors" in { + val (out, err) = withActionContainer() { c => + val code = """ + | 10 PRINT "Hello!" + | 20 GOTO 10 + """.stripMargin + + val (initCode, _) = c.init(initPayload(code)) + initCode should not be (200) + } + + checkStreams(out, err, { + case (o, e) => + if (enforceEmptyOutputStream) o shouldBe empty + e.toLowerCase should include("error") + }) + } + + it should "support application errors" in { + val (out, err) = withActionContainer() { c => + val code = """ + | func main(args: [String: Any]) -> [String: Any] { + | return [ "error": "sorry" ] + | } + """.stripMargin + + val (initCode, _) = c.init(initPayload(code)) + initCode should be(200) + + val (runCode, runRes) = c.run(runPayload(JsObject())) + runCode should be(200) // action writer returning an error is OK + + runRes shouldBe defined + runRes should be(Some(JsObject("error" -> JsString("sorry")))) + } + + checkStreams(out, err, { + case (o, e) => + if (enforceEmptyOutputStream) o shouldBe empty + e shouldBe empty + }) + } + + it should "support support multiple files in a zip file" in { + val zip = new File(TestUtils.getTestActionFilename("multiSwift.zip")).toPath + val code = ResourceHelpers.readAsBase64(zip) + + val (out, err) = withActionContainer() { c => + val (initCode, initRes) = c.init(initPayload(code)) + initCode should be(200) + + val args = JsObject() + val (runCode, runRes) = c.run(runPayload(args)) + + runCode should be(200) + runRes.get shouldBe JsObject("greeting" -> (JsString("Hello stranger!"))) + } + + checkStreams(out, err, { + case (o, e) => + if (enforceEmptyOutputStream) o shouldBe empty + e shouldBe empty + }) + } + + it should "support pre-compiled binary in a zip file" in { + val zip = new File(TestUtils.getTestActionFilename(swiftBinaryName)).toPath + val code = ResourceHelpers.readAsBase64(zip) + + val (out, err) = withActionContainer() { c => + val (initCode, initRes) = c.init(initPayload(code)) + initCode should be(200) + + val args = JsObject() + val (runCode, runRes) = c.run(runPayload(args)) + + runCode should be(200) + runRes.get shouldBe JsObject("greeting" -> (JsString("Hello stranger!"))) + } + + checkStreams(out, err, { + case (o, e) => + if (enforceEmptyOutputStream) o shouldBe empty + e shouldBe empty + }) + } + + it should "properly use KituraNet and Dispatch" in { + val (out, err) = withActionContainer() { c => + val code = """ + | import KituraNet + | import Foundation + | import Dispatch + | func main(args:[String: Any]) -> [String:Any] { + | let retries = 3 + | var resp = [String:Any]() + | var attempts = 0 + | if let url = args["getUrl"] as? String { + | while attempts < retries { + | let group = DispatchGroup() + | let queue = DispatchQueue.global(qos: .default) + | group.enter() + | queue.async { + | HTTP.get(url, callback: { response in + | if let response = response { + | do { + | var jsonData = Data() + | try response.readAllData(into: &jsonData) + | if let dic = WhiskJsonUtils.jsonDataToDictionary(jsonData: jsonData) { + | resp = dic + | } else { + | resp = ["error":"response from server is not JSON"] + | } + | } catch { + | resp["error"] = error.localizedDescription + | } + | } + | group.leave() + | }) + | } + | switch group.wait(timeout: DispatchTime.distantFuture) { + | case DispatchTimeoutResult.success: + | resp["attempts"] = attempts + | return resp + | case DispatchTimeoutResult.timedOut: + | attempts = attempts + 1 + | } + | } + | } + | return ["status":"Exceeded \(retries) attempts, aborting."] + | } + """.stripMargin + + val (initCode, _) = c.init(initPayload(code)) + + initCode should be(200) + + val argss = List(JsObject("getUrl" -> JsString("https://openwhisk.ng.bluemix.net/api/v1"))) + + for (args <- argss) { + val (runCode, out) = c.run(runPayload(args)) + runCode should be(200) + } + } + + // in side try catch finally print (out file) + // in catch block an error has occurred, get docker logs and print + // throw + + checkStreams(out, err, { + case (o, e) => + if (enforceEmptyOutputStream) o shouldBe empty + e shouldBe empty + }) + } + + it should "make Watson SDKs available to action authors" in { + val (out, err) = withActionContainer() { c => + val code = watsonCode + + val (initCode, _) = c.init(initPayload(code)) + + initCode should be(200) + + val (runCode, out) = c.run(runPayload(JsObject())) + runCode should be(200) + } + + checkStreams(out, err, { + case (o, e) => + if (enforceEmptyOutputStream) o shouldBe empty + e shouldBe empty + }) + } } diff --git a/tests/src/test/scala/actionContainers/Swift3ActionContainerTests.scala b/tests/src/test/scala/actionContainers/Swift3ActionContainerTests.scala deleted file mode 100644 index 435d07e..0000000 --- a/tests/src/test/scala/actionContainers/Swift3ActionContainerTests.scala +++ /dev/null @@ -1,363 +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 org.junit.runner.RunWith -import org.scalatest.junit.JUnitRunner - -import ActionContainer.withContainer -import common.WskActorSystem -import spray.json.JsObject -import spray.json.JsString -import common.TestUtils - -@RunWith(classOf[JUnitRunner]) -class Swift3ActionContainerTests extends BasicActionRunnerTests with WskActorSystem { - - // note: "out" will likely not be empty in some swift build as the compiler - // prints status messages and there doesn't seem to be a way to quiet them - val enforceEmptyOutputStream = false - lazy val swiftContainerImageName = "swift3action" - lazy val envCode = makeEnvCode("ProcessInfo.processInfo") - - def makeEnvCode(processInfo: String) = (""" - |func main(args: [String: Any]) -> [String: Any] { - | let env = """ + processInfo + """.environment - | var a = "???" - | var b = "???" - | var c = "???" - | var d = "???" - | var e = "???" - | var f = "???" - | if let v : String = env["__OW_API_HOST"] { - | a = "\(v)" - | } - | if let v : String = env["__OW_API_KEY"] { - | b = "\(v)" - | } - | if let v : String = env["__OW_NAMESPACE"] { - | c = "\(v)" - | } - | if let v : String = env["__OW_ACTION_NAME"] { - | d = "\(v)" - | } - | if let v : String = env["__OW_ACTIVATION_ID"] { - | e = "\(v)" - | } - | if let v : String = env["__OW_DEADLINE"] { - | f = "\(v)" - | } - | return ["api_host": a, "api_key": b, "namespace": c, "action_name": d, "activation_id": e, "deadline": f] - |} - """).stripMargin - - lazy val errorCode = """ - | // You need an indirection, or swiftc detects the div/0 - | // at compile-time. Smart. - | func div(x: Int, y: Int) -> Int { - | return x/y - | } - | func main(args: [String: Any]) -> [String: Any] { - | return [ "divBy0": div(x:5, y:0) ] - | } - """.stripMargin - lazy val watsonCode = """ - | import RestKit - | import WeatherCompanyData - | import AlchemyVision - | - | func main(args: [String:Any]) -> [String:Any] { - | return ["message": "I compiled and was able to import Watson SDKs"] - | } - """.stripMargin - lazy val swiftBinaryName = "helloSwift3.zip" - - // Helpers specific to swift actions - override def withActionContainer(env: Map[String, String] = Map.empty)(code: ActionContainer => Unit) = { - withContainer(swiftContainerImageName, env)(code) - } - - behavior of swiftContainerImageName - - // remove this test: it will not even compile under Swift 3 anymore - // so it should not be possible to write an action that does not return - // a [String:Any] - /*testNotReturningJson( - """ - |func main(args: [String: Any]) -> String { - | return "not a json object" - |} - """.stripMargin) - */ - - testEcho(Seq { - ( - "swift", - """ - | import Foundation - | - | extension FileHandle : TextOutputStream { - | public func write(_ string: String) { - | guard let data = string.data(using: .utf8) else { return } - | self.write(data) - | } - | } - | - | func main(args: [String: Any]) -> [String: Any] { - | print("hello stdout") - | var standardError = FileHandle.standardError - | print("hello stderr", to: &standardError) - | return args - | } - """.stripMargin) - }) - - testUnicode(Seq { - ( - "swift", - """ - | func main(args: [String: Any]) -> [String: Any] { - | if let str = args["delimiter"] as? String { - | let msg = "\(str) ☃ \(str)" - | print(msg) - | return [ "winter" : msg ] - | } else { - | return [ "error" : "no delimiter" ] - | } - | } - """.stripMargin.trim) - }) - - testEnv(Seq { - ("swift", envCode) - }, enforceEmptyOutputStream) - - it should "support actions using non-default entry points" in { - withActionContainer() { c => - val code = """ - | func niam(args: [String: Any]) -> [String: Any] { - | return [ "result": "it works" ] - | } - |""".stripMargin - - val (initCode, initRes) = c.init(initPayload(code, main = "niam")) - initCode should be(200) - - val (_, runRes) = c.run(runPayload(JsObject())) - runRes.get.fields.get("result") shouldBe Some(JsString("it works")) - } - } - - it should "return some error on action error" in { - val (out, err) = withActionContainer() { c => - val code = errorCode - - val (initCode, _) = c.init(initPayload(code)) - initCode should be(200) - - val (runCode, runRes) = c.run(runPayload(JsObject())) - runCode should be(502) - - runRes shouldBe defined - runRes.get.fields.get("error") shouldBe defined - } - - checkStreams(out, err, { - case (o, e) => - if (enforceEmptyOutputStream) o shouldBe empty - e shouldBe empty - }) - } - - it should "log compilation errors" in { - val (out, err) = withActionContainer() { c => - val code = """ - | 10 PRINT "Hello!" - | 20 GOTO 10 - """.stripMargin - - val (initCode, _) = c.init(initPayload(code)) - initCode should not be (200) - } - - checkStreams(out, err, { - case (o, e) => - if (enforceEmptyOutputStream) o shouldBe empty - e.toLowerCase should include("error") - }) - } - - it should "support application errors" in { - val (out, err) = withActionContainer() { c => - val code = """ - | func main(args: [String: Any]) -> [String: Any] { - | return [ "error": "sorry" ] - | } - """.stripMargin - - val (initCode, _) = c.init(initPayload(code)) - initCode should be(200) - - val (runCode, runRes) = c.run(runPayload(JsObject())) - runCode should be(200) // action writer returning an error is OK - - runRes shouldBe defined - runRes should be(Some(JsObject("error" -> JsString("sorry")))) - } - - checkStreams(out, err, { - case (o, e) => - if (enforceEmptyOutputStream) o shouldBe empty - e shouldBe empty - }) - } - - it should "support support multiple files in a zip file" in { - val zip = new File(TestUtils.getTestActionFilename("multiSwift.zip")).toPath - val code = ResourceHelpers.readAsBase64(zip) - - val (out, err) = withActionContainer() { c => - val (initCode, initRes) = c.init(initPayload(code)) - initCode should be(200) - - val args = JsObject() - val (runCode, runRes) = c.run(runPayload(args)) - - runCode should be(200) - runRes.get shouldBe JsObject("greeting" -> (JsString("Hello stranger!"))) - } - - checkStreams(out, err, { - case (o, e) => - if (enforceEmptyOutputStream) o shouldBe empty - e shouldBe empty - }) - } - - it should "support pre-compiled binary in a zip file" in { - val zip = new File(TestUtils.getTestActionFilename(swiftBinaryName)).toPath - val code = ResourceHelpers.readAsBase64(zip) - - val (out, err) = withActionContainer() { c => - val (initCode, initRes) = c.init(initPayload(code)) - initCode should be(200) - - val args = JsObject() - val (runCode, runRes) = c.run(runPayload(args)) - - runCode should be(200) - runRes.get shouldBe JsObject("greeting" -> (JsString("Hello stranger!"))) - } - - checkStreams(out, err, { - case (o, e) => - if (enforceEmptyOutputStream) o shouldBe empty - e shouldBe empty - }) - } - - it should "properly use KituraNet and Dispatch" in { - val (out, err) = withActionContainer() { c => - val code = """ - | import KituraNet - | import Foundation - | import Dispatch - | func main(args:[String: Any]) -> [String:Any] { - | let retries = 3 - | var resp = [String:Any]() - | var attempts = 0 - | if let url = args["getUrl"] as? String { - | while attempts < retries { - | let group = DispatchGroup() - | let queue = DispatchQueue.global(qos: .default) - | group.enter() - | queue.async { - | HTTP.get(url, callback: { response in - | if let response = response { - | do { - | var jsonData = Data() - | try response.readAllData(into: &jsonData) - | if let dic = WhiskJsonUtils.jsonDataToDictionary(jsonData: jsonData) { - | resp = dic - | } else { - | resp = ["error":"response from server is not JSON"] - | } - | } catch { - | resp["error"] = error.localizedDescription - | } - | } - | group.leave() - | }) - | } - | switch group.wait(timeout: DispatchTime.distantFuture) { - | case DispatchTimeoutResult.success: - | resp["attempts"] = attempts - | return resp - | case DispatchTimeoutResult.timedOut: - | attempts = attempts + 1 - | } - | } - | } - | return ["status":"Exceeded \(retries) attempts, aborting."] - | } - """.stripMargin - - val (initCode, _) = c.init(initPayload(code)) - - initCode should be(200) - - val argss = List(JsObject("getUrl" -> JsString("https://openwhisk.ng.bluemix.net/api/v1"))) - - for (args <- argss) { - val (runCode, out) = c.run(runPayload(args)) - runCode should be(200) - } - } - - // in side try catch finally print (out file) - // in catch block an error has occurred, get docker logs and print - // throw - - checkStreams(out, err, { - case (o, e) => - if (enforceEmptyOutputStream) o shouldBe empty - e shouldBe empty - }) - } - - it should "make Watson SDKs available to action authors" in { - val (out, err) = withActionContainer() { c => - val code = watsonCode - - val (initCode, _) = c.init(initPayload(code)) - - initCode should be(200) - - val (runCode, out) = c.run(runPayload(JsObject())) - runCode should be(200) - } - - checkStreams(out, err, { - case (o, e) => - if (enforceEmptyOutputStream) o shouldBe empty - e shouldBe empty - }) - } -} diff --git a/tools/travis/build.sh b/tools/travis/build.sh index 608a15d..1ac1e5a 100755 --- a/tools/travis/build.sh +++ b/tools/travis/build.sh @@ -14,7 +14,7 @@ IMAGE_PREFIX="testing" # Build runtime cd $ROOTDIR TERM=dumb ./gradlew \ -:core:swift3Action:distDocker :core:swift3.1.1Action:distDocker \ +:core:swift3.1.1Action:distDocker \ -PdockerImagePrefix=${IMAGE_PREFIX} diff --git a/tools/travis/publish.sh b/tools/travis/publish.sh index f997078..979089a 100755 --- a/tools/travis/publish.sh +++ b/tools/travis/publish.sh @@ -13,9 +13,7 @@ IMAGE_PREFIX=$1 RUNTIME_VERSION=$2 IMAGE_TAG=$3 -if [ ${RUNTIME_VERSION} == "3" ]; then - RUNTIME="swift3Action" -elif [ ${RUNTIME_VERSION} == "3.1.1" ]; then +if [ ${RUNTIME_VERSION} == "3.1.1" ]; then RUNTIME="swift3.1.1Action" fi -- To stop receiving notification emails like this one, please contact ['"commits@openwhisk.apache.org" <commits@openwhisk.apache.org>'].