diff --git a/.travis.yml b/.travis.yml index c387cf7..bdc9c4a 100644 --- a/.travis.yml +++ b/.travis.yml @@ -16,7 +16,7 @@ # sudo: required -group: deprecated-2017Q3 +dist: xenial language: scala scala: - 2.12.7 @@ -41,7 +41,7 @@ deploy: all_branches: true repo: apache/openwhisk-runtime-dotnet - provider: script - script: "./tools/travis/publish.sh openwhisk 2.2 nightly" + script: "./tools/travis/publish.sh openwhisk 2.2 nightly && ./tools/travis/publish.sh openwhisk 3.0 nightly" on: branch: master repo: apache/openwhisk-runtime-dotnet diff --git a/README.md b/README.md index 6e87b8a..a529e1f 100644 --- a/README.md +++ b/README.md @@ -23,157 +23,15 @@ [![Build Status](https://travis-ci.org/apache/openwhisk-runtime-dotnet.svg?branch=master)](https://travis-ci.org/apache/openwhisk-runtime-dotnet) ## Changelogs -- [.NET Core 2.2 CHANGELOG.md](core/dotnet2.2/CHANGELOG.md) - - -## Quick .NET Core Action -A .NET Core action is a .NET Core class library with a method called `Main` that has the exact signature as follows: - -```csharp -public Newtonsoft.Json.Linq.JObject Main(Newtonsoft.Json.Linq.JObject); -``` - -In order to compile, test and archive .NET Core projects, you must have the [.NET Core SDK](https://www.microsoft.com/net/download) installed locally and the environment variable `DOTNET_HOME` set to the location where the `dotnet` executable can be found. - -For example, create a C# project called `Apache.OpenWhisk.Example.Dotnet`: - -```bash -dotnet new classlib -n Apache.OpenWhisk.Example.Dotnet -lang C# -cd Apache.OpenWhisk.Example.Dotnet -``` - -Install the [Newtonsoft.Json](https://www.newtonsoft.com/json) NuGet package as follows: - -```bash -dotnet add package Newtonsoft.Json -v 12.0.1 -``` - -Now create a file called `Hello.cs` with the following content: - -```csharp -using System; -using Newtonsoft.Json.Linq; - -namespace Apache.OpenWhisk.Example.Dotnet -{ - public class Hello - { - public JObject Main(JObject args) - { - string name = "stranger"; - if (args.ContainsKey("name")) { - name = args["name"].ToString(); - } - JObject message = new JObject(); - message.Add("greeting", new JValue($"Hello, {name}!")); - return (message); - } - } -} -``` - -Publish the project as follows: - -```bash -dotnet publish -c Release -o out -``` - -Zip the published files as follows: -```bash -cd out -zip -r -0 helloDotNet.bin * -``` - -You need to specify the name of the function handler using `--main` argument. -The value for `main` needs to be in the following format: -`{Assembly}::{Class Full Name}::{Method}`, e.q., -`Apache.OpenWhisk.Example.Dotnet::Apache.OpenWhisk.Example.Dotnet.Hello::Main` - -### Create the .NET Core Action -To use on a deployment of OpenWhisk that contains the runtime as a kind: -```bash -wsk action update helloDotNet helloDotNet.bin --main Apache.OpenWhisk.Example.Dotnet::Apache.OpenWhisk.Example.Dotnet.Hello::Main --kind dotnet:2.2 -``` - -### Invoke the .NET Core Action -Action invocation is the same for .NET Core actions as it is for Swift and JavaScript actions: - -```bash -wsk action invoke --result helloDotNet --param name World -``` - -```json - { - "greeting": "Hello World!" - } -``` - -## Local development -```bash -./gradlew core:dotnet2.2:distDocker -``` -This will produce the image `whisk/action-dotnet-v2.2` - -Build and Push image -```bash -docker login -./gradlew core:action-dotnet-v2.2:distDocker -PdockerImagePrefix=$prefix-user -PdockerRegistry=docker.io -``` - -Deploy OpenWhisk using ansible environment that contains the kind `dotnet:2.2` -Assuming you have OpenWhisk already deploy localy and `OPENWHISK_HOME` pointing to root directory of OpenWhisk core repository. - -Set `ROOTDIR` to the root directory of this repository. - -Redeploy OpenWhisk -```bash -cd $OPENWHISK_HOME/ansible -ANSIBLE_CMD="ansible-playbook -i ${ROOTDIR}/ansible/environments/local" -$ANSIBLE_CMD setup.yml -$ANSIBLE_CMD couchdb.yml -$ANSIBLE_CMD initdb.yml -$ANSIBLE_CMD wipe.yml -$ANSIBLE_CMD openwhisk.yml -``` - -Or you can use `wskdev` and create a soft link to the target ansible environment, for example: -``` -ln -s ${ROOTDIR}/ansible/environments/local ${OPENWHISK_HOME}/ansible/environments/local-dotnet -wskdev fresh -t local-dotnet -``` - -### Testing -Install dependencies from the root directory on $OPENWHISK_HOME repository -```bash -pushd $OPENWHISK_HOME -./gradlew install -podd $OPENWHISK_HOME -``` +- [.NET Core 2.2 CHANGELOG.md](core/dotnet2.2/CHANGELOG.md) +- [.NET Core 3.0 CHANGELOG.md](core/dotnet3.0/CHANGELOG.md) -Using gradle to run all tests -```bash -./gradlew :tests:test -``` -Using gradle to run some tests -```bash -./gradlew :tests:test --tests *ActionContainerTests* -``` -Using IntelliJ: -- Import project as gradle project. -- Make sure working directory is root of the project/repo +## Quick Start Guides -#### Using container image to test -To use as docker action push to your own dockerhub account -```bash -docker tag whisk/action-dotnet-v2.2 $user_prefix/action-dotnet-v2.2 -docker push $user_prefix/action-dotnet-v2.2 -``` -Then create the action using your the image from dockerhub -```bash -wsk action update helloDotNet helloDotNet.bin --main Apache.OpenWhisk.Example.Dotnet::Apache.OpenWhisk.Example.Dotnet.Hello::Main --docker $user_prefix/action-dotnet-v2.2 -``` -The `$user_prefix` is usually your dockerhub user id. +- [.NET Core 2.2](core/dotnet2.2/QUICKSTART.md) +- [.NET Core 3.0](core/dotnet3.0/QUICKSTART.md) # License + [Apache 2.0](LICENSE.txt) diff --git a/core/dotnet2.2/CHANGELOG.md b/core/dotnet2.2/CHANGELOG.md index dc50cac..c530536 100644 --- a/core/dotnet2.2/CHANGELOG.md +++ b/core/dotnet2.2/CHANGELOG.md @@ -20,6 +20,6 @@ # .NET Core 2.2 OpenWhisk Runtime Container -## 1.13 (next Apache release) +## 1.13 Changes: - Initial release diff --git a/core/dotnet2.2/Dockerfile b/core/dotnet2.2/Dockerfile index 21b9816..70f1067 100644 --- a/core/dotnet2.2/Dockerfile +++ b/core/dotnet2.2/Dockerfile @@ -15,7 +15,7 @@ # limitations under the License. # -FROM microsoft/dotnet:2.2-sdk-alpine AS build +FROM mcr.microsoft.com/dotnet/core/sdk:2.2-alpine AS build WORKDIR /app COPY proxy/Apache.OpenWhisk.Runtime.Common/*.csproj ./Apache.OpenWhisk.Runtime.Common/ @@ -26,9 +26,9 @@ RUN dotnet restore COPY proxy/Apache.OpenWhisk.Runtime.Common/. ./Apache.OpenWhisk.Runtime.Common/ COPY proxy/Apache.OpenWhisk.Runtime.Dotnet.Minimal/. ./Apache.OpenWhisk.Runtime.Dotnet.Minimal/ WORKDIR /app/Apache.OpenWhisk.Runtime.Dotnet.Minimal -RUN dotnet publish -c Release -r alpine.3.7-x64 -o out +RUN dotnet publish -c Release -r alpine.3.9-x64 -o out -FROM microsoft/dotnet:2.2-runtime-alpine AS runtime +FROM mcr.microsoft.com/dotnet/core/runtime:2.2-alpine AS runtime WORKDIR /app COPY --from=build /app/Apache.OpenWhisk.Runtime.Dotnet.Minimal/out ./ ENV ASPNETCORE_URLS http://+:8080 diff --git a/core/dotnet2.2/QUICKSTART.md b/core/dotnet2.2/QUICKSTART.md new file mode 100644 index 0000000..7b67b54 --- /dev/null +++ b/core/dotnet2.2/QUICKSTART.md @@ -0,0 +1,192 @@ + + +# Quick .NET Core 2.2 Action + +A .NET Core action is a .NET Core class library with a method called `Main` that has the exact signature as follows: + +```csharp +public Newtonsoft.Json.Linq.JObject Main(Newtonsoft.Json.Linq.JObject); +``` + +In order to compile, test and archive .NET Core projects, you must have the [.NET Core SDK](https://www.microsoft.com/net/download) installed locally and the environment variable `DOTNET_HOME` set to the location where the `dotnet` executable can be found. + +For example, create a C# project called `Apache.OpenWhisk.Example.Dotnet`: + +```bash +dotnet new classlib -n Apache.OpenWhisk.Example.Dotnet -lang C# -f netstandard2.0 +cd Apache.OpenWhisk.Example.Dotnet +``` + +Install the [Newtonsoft.Json](https://www.newtonsoft.com/json) NuGet package as follows: + +```bash +dotnet add package Newtonsoft.Json -v 12.0.2 +``` + +Now create a file called `Hello.cs` with the following content: + +```csharp +using System; +using Newtonsoft.Json.Linq; + +namespace Apache.OpenWhisk.Example.Dotnet +{ + public class Hello + { + public JObject Main(JObject args) + { + string name = "stranger"; + if (args.ContainsKey("name")) { + name = args["name"].ToString(); + } + JObject message = new JObject(); + message.Add("greeting", new JValue($"Hello, {name}!")); + return (message); + } + } +} +``` + +Publish the project as follows: + +```bash +dotnet publish -c Release -o out +``` + +Zip the published files as follows: + +```bash +cd out +zip -r -0 helloDotNet.zip * +``` + +You need to specify the name of the function handler using `--main` argument. +The value for `main` needs to be in the following format: +`{Assembly}::{Class Full Name}::{Method}`, e.q., +`Apache.OpenWhisk.Example.Dotnet::Apache.OpenWhisk.Example.Dotnet.Hello::Main` + +## Create the .NET Core Action + +To use on a deployment of OpenWhisk that contains the runtime as a kind: + +```bash +wsk action update helloDotNet helloDotNet.zip --main Apache.OpenWhisk.Example.Dotnet::Apache.OpenWhisk.Example.Dotnet.Hello::Main --kind dotnet:2.2 +``` + +## Invoke the .NET Core Action + +Action invocation is the same for .NET Core actions as it is for Swift and JavaScript actions: + +```bash +wsk action invoke --result helloDotNet --param name World +``` + +```json + { + "greeting": "Hello World!" + } +``` + +## Local Development + +```bash +./gradlew core:dotnet2.2:distDocker +``` + +This will produce the image `whisk/action-dotnet-v2.2` + +Build and Push image + +```bash +docker login +./gradlew core:action-dotnet-v2.2:distDocker -PdockerImagePrefix=$prefix-user -PdockerRegistry=docker.io +``` + +Deploy OpenWhisk using ansible environment that contains the kind `dotnet:2.2` +Assuming you have OpenWhisk already deploy localy and `OPENWHISK_HOME` pointing to root directory of OpenWhisk core repository. + +Set `ROOTDIR` to the root directory of this repository. + +Redeploy OpenWhisk + +```bash +cd $OPENWHISK_HOME/ansible +ANSIBLE_CMD="ansible-playbook -i ${ROOTDIR}/ansible/environments/local" +$ANSIBLE_CMD setup.yml +$ANSIBLE_CMD couchdb.yml +$ANSIBLE_CMD initdb.yml +$ANSIBLE_CMD wipe.yml +$ANSIBLE_CMD openwhisk.yml +``` + +Or you can use `wskdev` and create a soft link to the target ansible environment, for example: + +```bash +ln -s ${ROOTDIR}/ansible/environments/local ${OPENWHISK_HOME}/ansible/environments/local-dotnet +wskdev fresh -t local-dotnet +``` + +### Testing + +Install dependencies from the root directory on $OPENWHISK_HOME repository + +```bash +pushd $OPENWHISK_HOME +./gradlew install +podd $OPENWHISK_HOME +``` + +Using gradle to run all tests + +```bash +./gradlew :tests:test +``` + +Using gradle to run some tests + +```bash +./gradlew :tests:test --tests DotNet2_2ActionContainerTests +``` + +Using IntelliJ: + +- Import project as gradle project. +- Make sure working directory is root of the project/repo + +#### Using Container Image To Test + +To use as docker action push to your own dockerhub account + +```bash +docker tag whisk/action-dotnet-v2.2 $user_prefix/action-dotnet-v2.2 +docker push $user_prefix/action-dotnet-v2.2 +``` + +Then create the action using your the image from dockerhub + +```bash +wsk action update helloDotNet helloDotNet.zip --main Apache.OpenWhisk.Example.Dotnet::Apache.OpenWhisk.Example.Dotnet.Hello::Main --docker $user_prefix/action-dotnet-v2.2 +``` + +The `$user_prefix` is usually your dockerhub user id. + +# License + +[Apache 2.0](../../LICENSE.txt) diff --git a/core/dotnet2.2/proxy/Apache.OpenWhisk.Runtime.Common/Apache.OpenWhisk.Runtime.Common.csproj b/core/dotnet2.2/proxy/Apache.OpenWhisk.Runtime.Common/Apache.OpenWhisk.Runtime.Common.csproj index d667e84..ff84a8d 100644 --- a/core/dotnet2.2/proxy/Apache.OpenWhisk.Runtime.Common/Apache.OpenWhisk.Runtime.Common.csproj +++ b/core/dotnet2.2/proxy/Apache.OpenWhisk.Runtime.Common/Apache.OpenWhisk.Runtime.Common.csproj @@ -28,7 +28,7 @@ 2.2.0 - 12.0.1 + 12.0.2 diff --git a/core/dotnet2.2/proxy/Apache.OpenWhisk.Runtime.Dotnet.Minimal/Apache.OpenWhisk.Runtime.Dotnet.Minimal.csproj b/core/dotnet2.2/proxy/Apache.OpenWhisk.Runtime.Dotnet.Minimal/Apache.OpenWhisk.Runtime.Dotnet.Minimal.csproj index ce08efe..2d3a42a 100644 --- a/core/dotnet2.2/proxy/Apache.OpenWhisk.Runtime.Dotnet.Minimal/Apache.OpenWhisk.Runtime.Dotnet.Minimal.csproj +++ b/core/dotnet2.2/proxy/Apache.OpenWhisk.Runtime.Dotnet.Minimal/Apache.OpenWhisk.Runtime.Dotnet.Minimal.csproj @@ -21,20 +21,8 @@ netcoreapp2.2 - - - 2.2.0 - - - 2.2.0 - - - 12.0.1 - - - - + diff --git a/core/dotnet3.0/CHANGELOG.md b/core/dotnet3.0/CHANGELOG.md new file mode 100644 index 0000000..9339dd7 --- /dev/null +++ b/core/dotnet3.0/CHANGELOG.md @@ -0,0 +1,25 @@ + + +# .NET Core 3.0 OpenWhisk Runtime Container + + +## 1.14 (next Apache release) +Changes: +- Initial release diff --git a/core/dotnet3.0/Dockerfile b/core/dotnet3.0/Dockerfile new file mode 100644 index 0000000..9e9576f --- /dev/null +++ b/core/dotnet3.0/Dockerfile @@ -0,0 +1,36 @@ +# +# 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 mcr.microsoft.com/dotnet/core/sdk:3.0-alpine AS build + +WORKDIR /app +COPY proxy/Apache.OpenWhisk.Runtime.Common/*.csproj ./Apache.OpenWhisk.Runtime.Common/ +COPY proxy/Apache.OpenWhisk.Runtime.Dotnet.Minimal/*.csproj ./Apache.OpenWhisk.Runtime.Dotnet.Minimal/ +COPY proxy/openwhisk-runtime-dotnet.sln ./openwhisk-runtime-dotnet.sln +RUN dotnet restore + +COPY proxy/Apache.OpenWhisk.Runtime.Common/. ./Apache.OpenWhisk.Runtime.Common/ +COPY proxy/Apache.OpenWhisk.Runtime.Dotnet.Minimal/. ./Apache.OpenWhisk.Runtime.Dotnet.Minimal/ +WORKDIR /app/Apache.OpenWhisk.Runtime.Dotnet.Minimal +RUN dotnet publish -c Release -r alpine.3.9-x64 -o out + +FROM mcr.microsoft.com/dotnet/core/runtime:3.0-alpine AS runtime +WORKDIR /app +COPY --from=build /app/Apache.OpenWhisk.Runtime.Dotnet.Minimal/out ./ +ENV ASPNETCORE_URLS http://+:8080 +EXPOSE 8080/tcp +ENTRYPOINT ["dotnet", "Apache.OpenWhisk.Runtime.Dotnet.Minimal.dll"] diff --git a/core/dotnet3.0/QUICKSTART.md b/core/dotnet3.0/QUICKSTART.md new file mode 100644 index 0000000..c8e720f --- /dev/null +++ b/core/dotnet3.0/QUICKSTART.md @@ -0,0 +1,192 @@ + + +# Quick .NET Core 3.0 Action + +A .NET Core action is a .NET Core class library with a method called `Main` that has the exact signature as follows: + +```csharp +public Newtonsoft.Json.Linq.JObject Main(Newtonsoft.Json.Linq.JObject); +``` + +In order to compile, test and archive .NET Core projects, you must have the [.NET Core SDK](https://www.microsoft.com/net/download) installed locally and the environment variable `DOTNET_HOME` set to the location where the `dotnet` executable can be found. + +For example, create a C# project called `Apache.OpenWhisk.Example.Dotnet`: + +```bash +dotnet new classlib -n Apache.OpenWhisk.Example.Dotnet -lang C# -f netstandard2.1 +cd Apache.OpenWhisk.Example.Dotnet +``` + +Install the [Newtonsoft.Json](https://www.newtonsoft.com/json) NuGet package as follows: + +```bash +dotnet add package Newtonsoft.Json -v 12.0.2 +``` + +Now create a file called `Hello.cs` with the following content: + +```csharp +using System; +using Newtonsoft.Json.Linq; + +namespace Apache.OpenWhisk.Example.Dotnet +{ + public class Hello + { + public JObject Main(JObject args) + { + string name = "stranger"; + if (args.ContainsKey("name")) { + name = args["name"].ToString(); + } + JObject message = new JObject(); + message.Add("greeting", new JValue($"Hello, {name}!")); + return (message); + } + } +} +``` + +Publish the project as follows: + +```bash +dotnet publish -c Release -o out +``` + +Zip the published files as follows: + +```bash +cd out +zip -r -0 helloDotNet.zip * +``` + +You need to specify the name of the function handler using `--main` argument. +The value for `main` needs to be in the following format: +`{Assembly}::{Class Full Name}::{Method}`, e.q., +`Apache.OpenWhisk.Example.Dotnet::Apache.OpenWhisk.Example.Dotnet.Hello::Main` + +## Create the .NET Core Action + +To use on a deployment of OpenWhisk that contains the runtime as a kind: + +```bash +wsk action update helloDotNet helloDotNet.zip --main Apache.OpenWhisk.Example.Dotnet::Apache.OpenWhisk.Example.Dotnet.Hello::Main --kind dotnet:3.0 +``` + +## Invoke the .NET Core Action + +Action invocation is the same for .NET Core actions as it is for Swift and JavaScript actions: + +```bash +wsk action invoke --result helloDotNet --param name World +``` + +```json + { + "greeting": "Hello World!" + } +``` + +## Local Development + +```bash +./gradlew core:dotnet3.0:distDocker +``` + +This will produce the image `whisk/action-dotnet-v3.0` + +Build and Push image + +```bash +docker login +./gradlew core:action-dotnet-v3.0:distDocker -PdockerImagePrefix=$prefix-user -PdockerRegistry=docker.io +``` + +Deploy OpenWhisk using ansible environment that contains the kind `dotnet:3.0` +Assuming you have OpenWhisk already deploy localy and `OPENWHISK_HOME` pointing to root directory of OpenWhisk core repository. + +Set `ROOTDIR` to the root directory of this repository. + +Redeploy OpenWhisk + +```bash +cd $OPENWHISK_HOME/ansible +ANSIBLE_CMD="ansible-playbook -i ${ROOTDIR}/ansible/environments/local" +$ANSIBLE_CMD setup.yml +$ANSIBLE_CMD couchdb.yml +$ANSIBLE_CMD initdb.yml +$ANSIBLE_CMD wipe.yml +$ANSIBLE_CMD openwhisk.yml +``` + +Or you can use `wskdev` and create a soft link to the target ansible environment, for example: + +```bash +ln -s ${ROOTDIR}/ansible/environments/local ${OPENWHISK_HOME}/ansible/environments/local-dotnet +wskdev fresh -t local-dotnet +``` + +### Testing + +Install dependencies from the root directory on $OPENWHISK_HOME repository + +```bash +pushd $OPENWHISK_HOME +./gradlew install +podd $OPENWHISK_HOME +``` + +Using gradle to run all tests + +```bash +./gradlew :tests:test +``` + +Using gradle to run some tests + +```bash +./gradlew :tests:test --tests DotNet3_0ActionContainerTests +``` + +Using IntelliJ: + +- Import project as gradle project. +- Make sure working directory is root of the project/repo + +#### Using Container Image To Test + +To use as docker action push to your own dockerhub account + +```bash +docker tag whisk/action-dotnet-v3.0 $user_prefix/action-dotnet-v3.0 +docker push $user_prefix/action-dotnet-v3.0 +``` + +Then create the action using your the image from dockerhub + +```bash +wsk action update helloDotNet helloDotNet.zip --main Apache.OpenWhisk.Example.Dotnet::Apache.OpenWhisk.Example.Dotnet.Hello::Main --docker $user_prefix/action-dotnet-v3.0 +``` + +The `$user_prefix` is usually your dockerhub user id. + +# License + +[Apache 2.0](../../LICENSE.txt) diff --git a/core/dotnet3.0/build.gradle b/core/dotnet3.0/build.gradle new file mode 100644 index 0000000..3d62aac --- /dev/null +++ b/core/dotnet3.0/build.gradle @@ -0,0 +1,20 @@ +/* + * 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. + */ + +ext.dockerImageName = 'action-dotnet-v3.0' + +apply from: '../../gradle/docker.gradle' diff --git a/core/dotnet3.0/proxy/Apache.OpenWhisk.Runtime.Common/Apache.OpenWhisk.Runtime.Common.csproj b/core/dotnet3.0/proxy/Apache.OpenWhisk.Runtime.Common/Apache.OpenWhisk.Runtime.Common.csproj new file mode 100644 index 0000000..db2338b --- /dev/null +++ b/core/dotnet3.0/proxy/Apache.OpenWhisk.Runtime.Common/Apache.OpenWhisk.Runtime.Common.csproj @@ -0,0 +1,35 @@ + + + + + netcoreapp3.0 + + + + + 2.2.0 + + + 2.2.0 + + + 12.0.2 + + + + diff --git a/core/dotnet3.0/proxy/Apache.OpenWhisk.Runtime.Common/HttpResponseExtension.cs b/core/dotnet3.0/proxy/Apache.OpenWhisk.Runtime.Common/HttpResponseExtension.cs new file mode 100644 index 0000000..4f63bd0 --- /dev/null +++ b/core/dotnet3.0/proxy/Apache.OpenWhisk.Runtime.Common/HttpResponseExtension.cs @@ -0,0 +1,43 @@ +/* + * 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. + */ + +using System.Text; +using System.Threading.Tasks; +using Microsoft.AspNetCore.Http; +using Newtonsoft.Json; +using Newtonsoft.Json.Linq; + +namespace Apache.OpenWhisk.Runtime.Common +{ + public static class HttpResponseExtension + { + public static async Task WriteResponse(this HttpResponse response, int code, string content) + { + byte[] bytes = Encoding.UTF8.GetBytes(content); + response.ContentLength = bytes.Length; + response.StatusCode = code; + await response.WriteAsync(content); + } + + public static async Task WriteError(this HttpResponse response, string errorMessage) + { + JObject message = new JObject {{"error", new JValue(errorMessage)}}; + await WriteResponse(response, 502, JsonConvert.SerializeObject(message)); + } + + } +} diff --git a/core/dotnet3.0/proxy/Apache.OpenWhisk.Runtime.Common/Init.cs b/core/dotnet3.0/proxy/Apache.OpenWhisk.Runtime.Common/Init.cs new file mode 100644 index 0000000..f5d9489 --- /dev/null +++ b/core/dotnet3.0/proxy/Apache.OpenWhisk.Runtime.Common/Init.cs @@ -0,0 +1,178 @@ +/* + * 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. + */ + +using System; +using System.IO; +using System.Reflection; +using System.Threading; +using System.Threading.Tasks; +using Microsoft.AspNetCore.Http; +using Newtonsoft.Json.Linq; + +namespace Apache.OpenWhisk.Runtime.Common +{ + public class Init + { + private readonly SemaphoreSlim _initSemaphoreSlim = new SemaphoreSlim(1, 1); + + public bool Initialized { get; private set; } + private Type Type { get; set; } + private MethodInfo Method { get; set; } + private ConstructorInfo Constructor { get; set; } + + public Init() + { + Initialized = false; + Type = null; + Method = null; + Constructor = null; + } + + public async Task HandleRequest(HttpContext httpContext) + { + await _initSemaphoreSlim.WaitAsync(); + try + { + if (Initialized) + { + await httpContext.Response.WriteError("Cannot initialize the action more than once."); + Console.Error.WriteLine("Cannot initialize the action more than once."); + return (new Run(Type, Method, Constructor)); + } + + string body = await new StreamReader(httpContext.Request.Body).ReadToEndAsync(); + JObject inputObject = JObject.Parse(body); + if (!inputObject.ContainsKey("value")) + { + await httpContext.Response.WriteError("Missing main/no code to execute."); + return (null); + } + + JToken message = inputObject["value"]; + + if (message["main"] == null || message["binary"] == null || message["code"] == null) + { + await httpContext.Response.WriteError("Missing main/no code to execute."); + return (null); + } + + string main = message["main"].ToString(); + + bool binary = message["binary"].ToObject(); + + if (!binary) + { + await httpContext.Response.WriteError("code must be binary (zip file)."); + return (null); + } + + string[] mainParts = main.Split("::"); + if (mainParts.Length != 3) + { + await httpContext.Response.WriteError("main required format is \"Assembly::Type::Function\"."); + return (null); + } + + string base64Zip = message["code"].ToString(); + string tempPath = Path.Combine(Environment.CurrentDirectory, Guid.NewGuid().ToString()); + string tempFile = Path.GetTempFileName(); + await File.WriteAllBytesAsync(tempFile, Convert.FromBase64String(base64Zip)); + try + { + System.IO.Compression.ZipFile.ExtractToDirectory(tempFile, tempPath); + } + catch (Exception) + { + await httpContext.Response.WriteError("Unable to decompress package."); + return (null); + } + finally + { + File.Delete(tempFile); + } + + Environment.CurrentDirectory = tempPath; + + string assemblyFile = $"{mainParts[0]}.dll"; + + string assemblyPath = Path.Combine(tempPath, assemblyFile); + + if (!File.Exists(assemblyPath)) + { + await httpContext.Response.WriteError($"Unable to locate requested assembly (\"{assemblyFile}\")."); + return (null); + } + + try + { + Assembly assembly = Assembly.LoadFrom(assemblyPath); + Type = assembly.GetType(mainParts[1]); + if (Type == null) + { + await httpContext.Response.WriteError($"Unable to locate requested type (\"{mainParts[1]}\")."); + return (null); + } + Method = Type.GetMethod(mainParts[2]); + Constructor = Type.GetConstructor(Type.EmptyTypes); + } + catch (Exception ex) + { + Console.Error.WriteLine(ex.ToString()); + await httpContext.Response.WriteError(ex.Message +#if DEBUG + + ", " + ex.StackTrace +#endif + ); + return (null); + } + + if (Method == null) + { + await httpContext.Response.WriteError($"Unable to locate requested method (\"{mainParts[2]}\")."); + return (null); + } + + if (Constructor == null) + { + await httpContext.Response.WriteError($"Unable to locate appropriate constructor for (\"{mainParts[1]}\")."); + return (null); + } + + Initialized = true; + + await httpContext.Response.WriteResponse(200, "OK"); + + return (new Run(Type, Method, Constructor)); + } + catch (Exception ex) + { + Console.Error.WriteLine(ex.StackTrace); + await httpContext.Response.WriteError(ex.Message +#if DEBUG + + ", " + ex.StackTrace +#endif + ); + Startup.WriteLogMarkers(); + return (null); + } + finally + { + _initSemaphoreSlim.Release(); + } + } + } +} diff --git a/core/dotnet3.0/proxy/Apache.OpenWhisk.Runtime.Common/Run.cs b/core/dotnet3.0/proxy/Apache.OpenWhisk.Runtime.Common/Run.cs new file mode 100644 index 0000000..1ee35bb --- /dev/null +++ b/core/dotnet3.0/proxy/Apache.OpenWhisk.Runtime.Common/Run.cs @@ -0,0 +1,109 @@ +/* + * 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. + */ + +using System; +using System.IO; +using System.Reflection; +using System.Threading.Tasks; +using Microsoft.AspNetCore.Http; +using Newtonsoft.Json.Linq; + +namespace Apache.OpenWhisk.Runtime.Common +{ + public class Run + { + private readonly Type _type; + private readonly MethodInfo _method; + private readonly ConstructorInfo _constructor; + + public Run(Type type, MethodInfo method, ConstructorInfo constructor) + { + _type = type; + _method = method; + _constructor = constructor; + } + + public async Task HandleRequest(HttpContext httpContext) + { + if (_type == null || _method == null || _constructor == null) + { + await httpContext.Response.WriteError("Cannot invoke an uninitialized action."); + return; + } + + try + { + string body = await new StreamReader(httpContext.Request.Body).ReadToEndAsync(); + + JObject inputObject = string.IsNullOrEmpty(body) ? null : JObject.Parse(body); + + JObject valObject = null; + + if (inputObject != null) + { + valObject = inputObject["value"] as JObject; + foreach (JToken token in inputObject.Children()) + { + try + { + if (token.Path.Equals("value", StringComparison.InvariantCultureIgnoreCase)) + continue; + string envKey = $"__OW_{token.Path.ToUpperInvariant()}"; + string envVal = token.First.ToString(); + Environment.SetEnvironmentVariable(envKey, envVal); + //Console.WriteLine($"Set environment variable \"{envKey}\" to \"{envVal}\"."); + } + catch (Exception) + { + await Console.Error.WriteLineAsync( + $"Unable to set environment variable for the \"{token.Path}\" token."); + } + } + } + + object owObject = _constructor.Invoke(new object[] { }); + + try + { + JObject output = (JObject) _method.Invoke(owObject, new object[] {valObject}); + + if (output == null) + { + await httpContext.Response.WriteError("The action returned null"); + Console.Error.WriteLine("The action returned null"); + return; + } + + await httpContext.Response.WriteResponse(200, output.ToString()); + } + catch (Exception ex) + { + Console.Error.WriteLine(ex.StackTrace); + await httpContext.Response.WriteError(ex.Message +#if DEBUG + + ", " + ex.StackTrace +#endif + ); + } + } + finally + { + Startup.WriteLogMarkers(); + } + } + } +} diff --git a/core/dotnet3.0/proxy/Apache.OpenWhisk.Runtime.Common/Startup.cs b/core/dotnet3.0/proxy/Apache.OpenWhisk.Runtime.Common/Startup.cs new file mode 100644 index 0000000..f11760c --- /dev/null +++ b/core/dotnet3.0/proxy/Apache.OpenWhisk.Runtime.Common/Startup.cs @@ -0,0 +1,69 @@ +/* + * 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. + */ + +using System; +using System.Threading.Tasks; +using Microsoft.AspNetCore.Builder; +using Microsoft.AspNetCore.Http; +using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.Logging; + +namespace Apache.OpenWhisk.Runtime.Common +{ + public class Startup + { + public static void WriteLogMarkers() + { + Console.WriteLine("XXX_THE_END_OF_A_WHISK_ACTIVATION_XXX"); + Console.Error.WriteLine("XXX_THE_END_OF_A_WHISK_ACTIVATION_XXX"); + } + + public void Configure(IApplicationBuilder app) + { + PathString initPath = new PathString("/init"); + PathString runPath = new PathString("/run"); + Init init = new Init(); + Run run = null; + app.Run(async (httpContext) => + { + if (httpContext.Request.Path.Equals(initPath)) + { + run = await init.HandleRequest(httpContext); + return; + } + + if (httpContext.Request.Path.Equals(runPath)) + { + if (!init.Initialized) + { + await httpContext.Response.WriteError("Cannot invoke an uninitialized action."); + return; + } + + if (run == null) + { + await httpContext.Response.WriteError("Cannot invoke an uninitialized action."); + return; + } + + await run.HandleRequest(httpContext); + } + } + ); + } + } +} diff --git a/core/dotnet3.0/proxy/Apache.OpenWhisk.Runtime.Dotnet.Minimal/Apache.OpenWhisk.Runtime.Dotnet.Minimal.csproj b/core/dotnet3.0/proxy/Apache.OpenWhisk.Runtime.Dotnet.Minimal/Apache.OpenWhisk.Runtime.Dotnet.Minimal.csproj new file mode 100644 index 0000000..452115d --- /dev/null +++ b/core/dotnet3.0/proxy/Apache.OpenWhisk.Runtime.Dotnet.Minimal/Apache.OpenWhisk.Runtime.Dotnet.Minimal.csproj @@ -0,0 +1,28 @@ + + + + + Exe + netcoreapp3.0 + + + + + + + diff --git a/core/dotnet3.0/proxy/Apache.OpenWhisk.Runtime.Dotnet.Minimal/Program.cs b/core/dotnet3.0/proxy/Apache.OpenWhisk.Runtime.Dotnet.Minimal/Program.cs new file mode 100644 index 0000000..0eca9fa --- /dev/null +++ b/core/dotnet3.0/proxy/Apache.OpenWhisk.Runtime.Dotnet.Minimal/Program.cs @@ -0,0 +1,44 @@ +/* + * 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. + */ + +using System; +using Apache.OpenWhisk.Runtime.Common; +using Microsoft.AspNetCore; +using Microsoft.AspNetCore.Hosting; +using Microsoft.Extensions.Logging; + +namespace Apache.OpenWhisk.Runtime.Dotnet.Minimal +{ + class Program + { + static void Main(string[] args) + { + CreateWebHostBuilder(args).Build().Run(); + } + + public static IWebHostBuilder CreateWebHostBuilder(string[] args) => + WebHost.CreateDefaultBuilder(args) + .ConfigureLogging((hostingContext, logging) => + { + logging.ClearProviders(); + }) + .SuppressStatusMessages(true) + .UseStartup(); + + } +} + diff --git a/core/dotnet3.0/proxy/build.gradle b/core/dotnet3.0/proxy/build.gradle new file mode 100644 index 0000000..6a5d94e --- /dev/null +++ b/core/dotnet3.0/proxy/build.gradle @@ -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. + */ + +plugins { + id "net.karlmartens.dotnet" version "0.2.20" +} + +repositories { + mavenCentral() +} + +dotnet { + configuration 'Release' +} diff --git a/core/dotnet3.0/proxy/gradle/wrapper/gradle-wrapper.jar b/core/dotnet3.0/proxy/gradle/wrapper/gradle-wrapper.jar new file mode 100644 index 0000000..f6b961f Binary files /dev/null and b/core/dotnet3.0/proxy/gradle/wrapper/gradle-wrapper.jar differ diff --git a/core/dotnet3.0/proxy/gradle/wrapper/gradle-wrapper.properties b/core/dotnet3.0/proxy/gradle/wrapper/gradle-wrapper.properties new file mode 100644 index 0000000..d475d27 --- /dev/null +++ b/core/dotnet3.0/proxy/gradle/wrapper/gradle-wrapper.properties @@ -0,0 +1,21 @@ +# +# 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. +# +distributionBase=GRADLE_USER_HOME +distributionPath=wrapper/dists +zipStoreBase=GRADLE_USER_HOME +zipStorePath=wrapper/dists +distributionUrl=https\://services.gradle.org/distributions/gradle-5.5.1-bin.zip diff --git a/core/dotnet3.0/proxy/gradlew b/core/dotnet3.0/proxy/gradlew new file mode 100644 index 0000000..d4ee78f --- /dev/null +++ b/core/dotnet3.0/proxy/gradlew @@ -0,0 +1,188 @@ +#!/usr/bin/env sh + +# +# Copyright 2015 the original author or authors. +# +# Licensed 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. +# + +############################################################################## +## +## Gradle start up script for UN*X +## +############################################################################## + +# Attempt to set APP_HOME +# Resolve links: $0 may be a link +PRG="$0" +# Need this for relative symlinks. +while [ -h "$PRG" ] ; do + ls=`ls -ld "$PRG"` + link=`expr "$ls" : '.*-> \(.*\)$'` + if expr "$link" : '/.*' > /dev/null; then + PRG="$link" + else + PRG=`dirname "$PRG"`"/$link" + fi +done +SAVED="`pwd`" +cd "`dirname \"$PRG\"`/" >/dev/null +APP_HOME="`pwd -P`" +cd "$SAVED" >/dev/null + +APP_NAME="Gradle" +APP_BASE_NAME=`basename "$0"` + +# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. +DEFAULT_JVM_OPTS='-Dfile.encoding=UTF-8' + +# Use the maximum available, or set MAX_FD != -1 to use that value. +MAX_FD="maximum" + +warn () { + echo "$*" +} + +die () { + echo + echo "$*" + echo + exit 1 +} + +# OS specific support (must be 'true' or 'false'). +cygwin=false +msys=false +darwin=false +nonstop=false +case "`uname`" in + CYGWIN* ) + cygwin=true + ;; + Darwin* ) + darwin=true + ;; + MINGW* ) + msys=true + ;; + NONSTOP* ) + nonstop=true + ;; +esac + +CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar + +# Determine the Java command to use to start the JVM. +if [ -n "$JAVA_HOME" ] ; then + if [ -x "$JAVA_HOME/jre/sh/java" ] ; then + # IBM's JDK on AIX uses strange locations for the executables + JAVACMD="$JAVA_HOME/jre/sh/java" + else + JAVACMD="$JAVA_HOME/bin/java" + fi + if [ ! -x "$JAVACMD" ] ; then + die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME + +Please set the JAVA_HOME variable in your environment to match the +location of your Java installation." + fi +else + JAVACMD="java" + which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. + +Please set the JAVA_HOME variable in your environment to match the +location of your Java installation." +fi + +# Increase the maximum file descriptors if we can. +if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then + MAX_FD_LIMIT=`ulimit -H -n` + if [ $? -eq 0 ] ; then + if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then + MAX_FD="$MAX_FD_LIMIT" + fi + ulimit -n $MAX_FD + if [ $? -ne 0 ] ; then + warn "Could not set maximum file descriptor limit: $MAX_FD" + fi + else + warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT" + fi +fi + +# For Darwin, add options to specify how the application appears in the dock +if $darwin; then + GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\"" +fi + +# For Cygwin, switch paths to Windows format before running java +if $cygwin ; then + APP_HOME=`cygpath --path --mixed "$APP_HOME"` + CLASSPATH=`cygpath --path --mixed "$CLASSPATH"` + JAVACMD=`cygpath --unix "$JAVACMD"` + + # We build the pattern for arguments to be converted via cygpath + ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null` + SEP="" + for dir in $ROOTDIRSRAW ; do + ROOTDIRS="$ROOTDIRS$SEP$dir" + SEP="|" + done + OURCYGPATTERN="(^($ROOTDIRS))" + # Add a user-defined pattern to the cygpath arguments + if [ "$GRADLE_CYGPATTERN" != "" ] ; then + OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)" + fi + # Now convert the arguments - kludge to limit ourselves to /bin/sh + i=0 + for arg in "$@" ; do + CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -` + CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option + + if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition + eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"` + else + eval `echo args$i`="\"$arg\"" + fi + i=$((i+1)) + done + case $i in + (0) set -- ;; + (1) set -- "$args0" ;; + (2) set -- "$args0" "$args1" ;; + (3) set -- "$args0" "$args1" "$args2" ;; + (4) set -- "$args0" "$args1" "$args2" "$args3" ;; + (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;; + (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;; + (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;; + (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;; + (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;; + esac +fi + +# Escape application args +save () { + for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done + echo " " +} +APP_ARGS=$(save "$@") + +# Collect all arguments for the java command, following the shell quoting and substitution rules +eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS" + +# by default we should be in the correct project dir, but when run from Finder on Mac, the cwd is wrong +if [ "$(uname)" = "Darwin" ] && [ "$HOME" = "$PWD" ]; then + cd "$(dirname "$0")" +fi + +exec "$JAVACMD" "$@" diff --git a/core/dotnet3.0/proxy/gradlew.bat b/core/dotnet3.0/proxy/gradlew.bat new file mode 100644 index 0000000..ad0ff10 --- /dev/null +++ b/core/dotnet3.0/proxy/gradlew.bat @@ -0,0 +1,100 @@ +@rem +@rem Copyright 2015 the original author or authors. +@rem +@rem Licensed under the Apache License, Version 2.0 (the "License"); +@rem you may not use this file except in compliance with the License. +@rem You may obtain a copy of the License at +@rem +@rem http://www.apache.org/licenses/LICENSE-2.0 +@rem +@rem Unless required by applicable law or agreed to in writing, software +@rem distributed under the License is distributed on an "AS IS" BASIS, +@rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +@rem See the License for the specific language governing permissions and +@rem limitations under the License. +@rem + +@if "%DEBUG%" == "" @echo off +@rem ########################################################################## +@rem +@rem Gradle startup script for Windows +@rem +@rem ########################################################################## + +@rem Set local scope for the variables with windows NT shell +if "%OS%"=="Windows_NT" setlocal + +set DIRNAME=%~dp0 +if "%DIRNAME%" == "" set DIRNAME=. +set APP_BASE_NAME=%~n0 +set APP_HOME=%DIRNAME% + +@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. +set DEFAULT_JVM_OPTS=-Dfile.encoding=UTF-8 + +@rem Find java.exe +if defined JAVA_HOME goto findJavaFromJavaHome + +set JAVA_EXE=java.exe +%JAVA_EXE% -version >NUL 2>&1 +if "%ERRORLEVEL%" == "0" goto init + +echo. +echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. +echo. +echo Please set the JAVA_HOME variable in your environment to match the +echo location of your Java installation. + +goto fail + +:findJavaFromJavaHome +set JAVA_HOME=%JAVA_HOME:"=% +set JAVA_EXE=%JAVA_HOME%/bin/java.exe + +if exist "%JAVA_EXE%" goto init + +echo. +echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% +echo. +echo Please set the JAVA_HOME variable in your environment to match the +echo location of your Java installation. + +goto fail + +:init +@rem Get command-line arguments, handling Windows variants + +if not "%OS%" == "Windows_NT" goto win9xME_args + +:win9xME_args +@rem Slurp the command line arguments. +set CMD_LINE_ARGS= +set _SKIP=2 + +:win9xME_args_slurp +if "x%~1" == "x" goto execute + +set CMD_LINE_ARGS=%* + +:execute +@rem Setup the command line + +set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar + +@rem Execute Gradle +"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS% + +:end +@rem End local scope for the variables with windows NT shell +if "%ERRORLEVEL%"=="0" goto mainEnd + +:fail +rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of +rem the _cmd.exe /c_ return code! +if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1 +exit /b 1 + +:mainEnd +if "%OS%"=="Windows_NT" endlocal + +:omega diff --git a/core/dotnet3.0/proxy/openwhisk-runtime-dotnet.sln b/core/dotnet3.0/proxy/openwhisk-runtime-dotnet.sln new file mode 100644 index 0000000..25e60cc --- /dev/null +++ b/core/dotnet3.0/proxy/openwhisk-runtime-dotnet.sln @@ -0,0 +1,39 @@ +Microsoft Visual Studio Solution File, Format Version 12.00 + +# +# 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. +# + +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Apache.OpenWhisk.Runtime.Dotnet.Minimal", "Apache.OpenWhisk.Runtime.Dotnet.Minimal\Apache.OpenWhisk.Runtime.Dotnet.Minimal.csproj", "{F76F51C9-EB3B-4D4C-89C0-A71E0BEF88DC}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Apache.OpenWhisk.Runtime.Common", "Apache.OpenWhisk.Runtime.Common\Apache.OpenWhisk.Runtime.Common.csproj", "{26ADD70B-3101-4943-982C-16D380D4B044}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Any CPU = Debug|Any CPU + Release|Any CPU = Release|Any CPU + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {F76F51C9-EB3B-4D4C-89C0-A71E0BEF88DC}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {F76F51C9-EB3B-4D4C-89C0-A71E0BEF88DC}.Debug|Any CPU.Build.0 = Debug|Any CPU + {F76F51C9-EB3B-4D4C-89C0-A71E0BEF88DC}.Release|Any CPU.ActiveCfg = Release|Any CPU + {F76F51C9-EB3B-4D4C-89C0-A71E0BEF88DC}.Release|Any CPU.Build.0 = Release|Any CPU + {26ADD70B-3101-4943-982C-16D380D4B044}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {26ADD70B-3101-4943-982C-16D380D4B044}.Debug|Any CPU.Build.0 = Debug|Any CPU + {26ADD70B-3101-4943-982C-16D380D4B044}.Release|Any CPU.ActiveCfg = Release|Any CPU + {26ADD70B-3101-4943-982C-16D380D4B044}.Release|Any CPU.Build.0 = Release|Any CPU + EndGlobalSection +EndGlobal diff --git a/settings.gradle b/settings.gradle index c7465fe..d787614 100644 --- a/settings.gradle +++ b/settings.gradle @@ -16,11 +16,15 @@ */ include ':tests' -include ':tests:dotnet' +include ':tests:dotnet2.2' +include ':tests:dotnet3.0' include ':core:dotnet2.2' include ':core:dotnet2.2:proxy' +include ':core:dotnet3.0' +include ':core:dotnet3.0:proxy' + rootProject.name = 'runtime-dotnet' gradle.ext.openwhisk = [ diff --git a/tests/build.gradle b/tests/build.gradle index 2b8c6ce..2cfb28f 100644 --- a/tests/build.gradle +++ b/tests/build.gradle @@ -43,5 +43,6 @@ tasks.withType(ScalaCompile) { } compileTestScala { - dependsOn ':tests:dotnet:prepare' + dependsOn ':tests:dotnet2.2:prepare' + dependsOn ':tests:dotnet3.0:prepare' } diff --git a/tests/dotnet/Apache.OpenWhisk.Tests.Dotnet/Apache.OpenWhisk.Tests.Dotnet.csproj b/tests/dotnet2.2/Apache.OpenWhisk.Tests.Dotnet/Apache.OpenWhisk.Tests.Dotnet.csproj similarity index 91% rename from tests/dotnet/Apache.OpenWhisk.Tests.Dotnet/Apache.OpenWhisk.Tests.Dotnet.csproj rename to tests/dotnet2.2/Apache.OpenWhisk.Tests.Dotnet/Apache.OpenWhisk.Tests.Dotnet.csproj index 2777248..05df906 100644 --- a/tests/dotnet/Apache.OpenWhisk.Tests.Dotnet/Apache.OpenWhisk.Tests.Dotnet.csproj +++ b/tests/dotnet2.2/Apache.OpenWhisk.Tests.Dotnet/Apache.OpenWhisk.Tests.Dotnet.csproj @@ -24,4 +24,9 @@ + + + + + diff --git a/tests/dotnet/build.gradle b/tests/dotnet2.2/build.gradle similarity index 97% rename from tests/dotnet/build.gradle rename to tests/dotnet2.2/build.gradle index 5efdad1..377f659 100644 --- a/tests/dotnet/build.gradle +++ b/tests/dotnet2.2/build.gradle @@ -42,7 +42,7 @@ task prepare_zip(type: Zip, dependsOn: prepare_distro) { from file('build/dist/out') include '*' include '**/**' - archiveName 'dotnettests.zip' + archiveName 'dotnettests2.2.zip' destinationDir(file('../src/test/resources')) } diff --git a/tests/dotnet/openwhisk-tests-dotnet.sln b/tests/dotnet2.2/openwhisk-tests-dotnet.sln similarity index 100% rename from tests/dotnet/openwhisk-tests-dotnet.sln rename to tests/dotnet2.2/openwhisk-tests-dotnet.sln diff --git a/tests/dotnet3.0/Apache.OpenWhisk.Tests.Dotnet/Apache.OpenWhisk.Tests.Dotnet.csproj b/tests/dotnet3.0/Apache.OpenWhisk.Tests.Dotnet/Apache.OpenWhisk.Tests.Dotnet.csproj new file mode 100644 index 0000000..ddc5679 --- /dev/null +++ b/tests/dotnet3.0/Apache.OpenWhisk.Tests.Dotnet/Apache.OpenWhisk.Tests.Dotnet.csproj @@ -0,0 +1,32 @@ + + + + + netstandard2.1 + + + + + + + + + + + + diff --git a/tests/dotnet3.0/build.gradle b/tests/dotnet3.0/build.gradle new file mode 100644 index 0000000..8c2e65e --- /dev/null +++ b/tests/dotnet3.0/build.gradle @@ -0,0 +1,51 @@ +/* + * 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. + */ + +plugins { + id "net.karlmartens.dotnet" version "0.2.20" +} + +repositories { + mavenCentral() +} + +dotnet { + configuration 'Release' +} + +task prepare_distro(dependsOn: distribution) { + doLast { + copy { + from tarTree(resources.gzip(file('build/dist/netstandard2.1.tar.gz'))) + into file('build/dist/out') + } + delete file('build/dist/netstandard2.1.tar.gz') + } +} + +task prepare_zip(type: Zip, dependsOn: prepare_distro) { + from file('build/dist/out') + include '*' + include '**/**' + archiveName 'dotnettests3.0.zip' + destinationDir(file('../src/test/resources')) +} + +task prepare(type: Delete, dependsOn: prepare_zip) { + delete getProject().getBuildDir().toPath().toFile() + followSymlinks = true +} diff --git a/tests/dotnet3.0/openwhisk-tests-dotnet.sln b/tests/dotnet3.0/openwhisk-tests-dotnet.sln new file mode 100644 index 0000000..0f4ec0d --- /dev/null +++ b/tests/dotnet3.0/openwhisk-tests-dotnet.sln @@ -0,0 +1,33 @@ +Microsoft Visual Studio Solution File, Format Version 12.00 + +# +# 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. +# + +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Apache.OpenWhisk.Tests.Dotnet", "Apache.OpenWhisk.Tests.Dotnet\Apache.OpenWhisk.Tests.Dotnet.csproj", "{4DA37A8E-7505-4C51-8C75-B18BDA45392C}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Any CPU = Debug|Any CPU + Release|Any CPU = Release|Any CPU + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {4DA37A8E-7505-4C51-8C75-B18BDA45392C}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {4DA37A8E-7505-4C51-8C75-B18BDA45392C}.Debug|Any CPU.Build.0 = Debug|Any CPU + {4DA37A8E-7505-4C51-8C75-B18BDA45392C}.Release|Any CPU.ActiveCfg = Release|Any CPU + {4DA37A8E-7505-4C51-8C75-B18BDA45392C}.Release|Any CPU.Build.0 = Release|Any CPU + EndGlobalSection +EndGlobal diff --git a/tests/dotnet/Apache.OpenWhisk.Tests.Dotnet/AltEcho.cs b/tests/dotnetshared/AltEcho.cs similarity index 100% rename from tests/dotnet/Apache.OpenWhisk.Tests.Dotnet/AltEcho.cs rename to tests/dotnetshared/AltEcho.cs diff --git a/tests/dotnet/Apache.OpenWhisk.Tests.Dotnet/Echo.cs b/tests/dotnetshared/Echo.cs similarity index 100% rename from tests/dotnet/Apache.OpenWhisk.Tests.Dotnet/Echo.cs rename to tests/dotnetshared/Echo.cs diff --git a/tests/dotnet/Apache.OpenWhisk.Tests.Dotnet/Environment.cs b/tests/dotnetshared/Environment.cs similarity index 100% rename from tests/dotnet/Apache.OpenWhisk.Tests.Dotnet/Environment.cs rename to tests/dotnetshared/Environment.cs diff --git a/tests/dotnet/Apache.OpenWhisk.Tests.Dotnet/Error.cs b/tests/dotnetshared/Error.cs similarity index 78% rename from tests/dotnet/Apache.OpenWhisk.Tests.Dotnet/Error.cs rename to tests/dotnetshared/Error.cs index f98068f..7492475 100644 --- a/tests/dotnet/Apache.OpenWhisk.Tests.Dotnet/Error.cs +++ b/tests/dotnetshared/Error.cs @@ -16,6 +16,8 @@ */ using Newtonsoft.Json.Linq; +using System.Runtime.Versioning; +using System.Reflection; namespace Apache.OpenWhisk.Tests.Dotnet { @@ -24,7 +26,12 @@ public class Error public JObject Main(JObject args) { JObject message = new JObject(); - message.Add("error", new JValue("This action is unhappy.")); + var framework = Assembly + .GetEntryAssembly()? + .GetCustomAttribute()? + .FrameworkName; + + message.Add("error", new JValue(framework)); return (message); } } diff --git a/tests/dotnet/Apache.OpenWhisk.Tests.Dotnet/Exception.cs b/tests/dotnetshared/Exception.cs similarity index 100% rename from tests/dotnet/Apache.OpenWhisk.Tests.Dotnet/Exception.cs rename to tests/dotnetshared/Exception.cs diff --git a/tests/dotnet/Apache.OpenWhisk.Tests.Dotnet/NonEmptyConstructor.cs b/tests/dotnetshared/NonEmptyConstructor.cs similarity index 100% rename from tests/dotnet/Apache.OpenWhisk.Tests.Dotnet/NonEmptyConstructor.cs rename to tests/dotnetshared/NonEmptyConstructor.cs diff --git a/tests/dotnet/Apache.OpenWhisk.Tests.Dotnet/Nuller.cs b/tests/dotnetshared/Nuller.cs similarity index 100% rename from tests/dotnet/Apache.OpenWhisk.Tests.Dotnet/Nuller.cs rename to tests/dotnetshared/Nuller.cs diff --git a/tests/dotnet/Apache.OpenWhisk.Tests.Dotnet/Unicode.cs b/tests/dotnetshared/Unicode.cs similarity index 100% rename from tests/dotnet/Apache.OpenWhisk.Tests.Dotnet/Unicode.cs rename to tests/dotnetshared/Unicode.cs diff --git a/tests/src/test/scala/actionContainers/DotNetActionContainerTests.scala b/tests/src/test/scala/actionContainers/DotNet2_2ActionContainerTests.scala similarity index 96% rename from tests/src/test/scala/actionContainers/DotNetActionContainerTests.scala rename to tests/src/test/scala/actionContainers/DotNet2_2ActionContainerTests.scala index 6dfa575..6f84f75 100644 --- a/tests/src/test/scala/actionContainers/DotNetActionContainerTests.scala +++ b/tests/src/test/scala/actionContainers/DotNet2_2ActionContainerTests.scala @@ -25,8 +25,8 @@ import actionContainers.ActionContainer.withContainer import java.nio.file.Paths @RunWith(classOf[JUnitRunner]) -class DotNetActionContainerTests extends BasicActionRunnerTests with WskActorSystem { - val functionb64 = ResourceHelpers.readAsBase64(Paths.get(getClass.getResource("/dotnettests.zip").getPath)) +class DotNet2_2ActionContainerTests extends BasicActionRunnerTests with WskActorSystem { + val functionb64 = ResourceHelpers.readAsBase64(Paths.get(getClass.getResource("/dotnettests2.2.zip").getPath)) // Helpers specific to java actions override def withActionContainer(env: Map[String, String] = Map.empty)( @@ -110,7 +110,10 @@ class DotNetActionContainerTests extends BasicActionRunnerTests with WskActorSys runCode should be(200) runRes shouldBe defined - runRes.get.fields.get("error") shouldBe defined + + runRes should { + be(Some(JsObject("error" -> JsString(".NETCoreApp,Version=v2.2")))) + } } checkStreams(out, err, { diff --git a/tests/src/test/scala/actionContainers/DotNet3_0ActionContainerTests.scala b/tests/src/test/scala/actionContainers/DotNet3_0ActionContainerTests.scala new file mode 100644 index 0000000..ec937ab --- /dev/null +++ b/tests/src/test/scala/actionContainers/DotNet3_0ActionContainerTests.scala @@ -0,0 +1,225 @@ +/* + * 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 actionContainers + +import org.junit.runner.RunWith +import org.scalatest.junit.JUnitRunner +import common.WskActorSystem +import spray.json._ +import actionContainers.ActionContainer.withContainer +import java.nio.file.Paths + +@RunWith(classOf[JUnitRunner]) +class DotNet3_0ActionContainerTests extends BasicActionRunnerTests with WskActorSystem { + val functionb64 = ResourceHelpers.readAsBase64(Paths.get(getClass.getResource("/dotnettests3.0.zip").getPath)) + + // Helpers specific to java actions + override def withActionContainer(env: Map[String, String] = Map.empty)( + code: ActionContainer => Unit): (String, String) = withContainer("action-dotnet-v3.0", env)(code) + + behavior of "dotnet action" + + override val testNoSourceOrExec = { + TestConfig("") + } + + override val testNotReturningJson = { + // skip this test since and add own below (see Nuller) + TestConfig("", skipTest = true) + } + + override val testEnv = { + TestConfig(functionb64, main = "Apache.OpenWhisk.Tests.Dotnet::Apache.OpenWhisk.Tests.Dotnet.Environment::Main") + } + + override val testEcho = { + TestConfig(functionb64, main = "Apache.OpenWhisk.Tests.Dotnet::Apache.OpenWhisk.Tests.Dotnet.AltEcho::Main") + } + + val testEchoNoWrite = { + TestConfig(functionb64, main = "Apache.OpenWhisk.Tests.Dotnet::Apache.OpenWhisk.Tests.Dotnet.Echo::Main") + } + + override val testUnicode = { + TestConfig(functionb64, main = "Apache.OpenWhisk.Tests.Dotnet::Apache.OpenWhisk.Tests.Dotnet.Unicode::Main") + } + + override val testInitCannotBeCalledMoreThanOnce = testEchoNoWrite + + override val testEntryPointOtherThanMain = testEchoNoWrite + + override val testLargeInput = testEchoNoWrite + + it should "fail to initialize with bad archive" in { + val (out, err) = withActionContainer() { c => + val brokenArchive = ("NOTAVALIDZIPFILE") + + val (initCode, initRes) = + c.init(initPayload(brokenArchive, "Apache.OpenWhisk.Tests.Dotnet::Apache.OpenWhisk.Tests.Dotnet.Invalid::Main")) + initCode should not be (200) + + initRes shouldBe defined + + initRes should { + be(Some(JsObject("error" -> JsString("Unable to decompress package.")))) + } + } + } + + it should "return some error on action error" in { + val (out, err) = withActionContainer() { c => + val (initCode, _) = + c.init(initPayload(functionb64, "Apache.OpenWhisk.Tests.Dotnet::Apache.OpenWhisk.Tests.Dotnet.Exception::Main")) + initCode should be(200) + + val (runCode, runRes) = c.run(runPayload(JsObject.empty)) + runCode should not be (200) + + runRes shouldBe defined + runRes.get.fields.get("error") shouldBe defined + } + + checkStreams(out, err, { + case (o, e) => + (o + e).toLowerCase should include("exception") + }) + } + + it should "support application errors" in { + val (out, err) = withActionContainer() { c => + val (initCode, _) = + c.init(initPayload(functionb64, "Apache.OpenWhisk.Tests.Dotnet::Apache.OpenWhisk.Tests.Dotnet.Error::Main")) + initCode should be(200) + + val (runCode, runRes) = c.run(runPayload(JsObject.empty)) + runCode should be(200) + + runRes shouldBe defined + + runRes should { + be(Some(JsObject("error" -> JsString(".NETCoreApp,Version=v3.0")))) + } + } + + checkStreams(out, err, { + case (o, e) => + o shouldBe empty + e shouldBe empty + }) + } + + it should "fails on invalid assembly reference" in { + val (out, err) = withActionContainer() { c => + val (initCode, initRes) = c.init( + initPayload(functionb64, "Apache.OpenWhisk.Tests.Dotnet.DoesntExist::Apache.OpenWhisk.Tests.Dotnet.Echo::Main")) + initCode should be(502) + + initRes shouldBe defined + + initRes should { + be( + Some(JsObject("error" -> JsString( + "Unable to locate requested assembly (\"Apache.OpenWhisk.Tests.Dotnet.DoesntExist.dll\").")))) + } + } + } + + it should "fails on invalid type reference" in { + val (out, err) = withActionContainer() { c => + val (initCode, initRes) = + c.init(initPayload(functionb64, "Apache.OpenWhisk.Tests.Dotnet::Apache.OpenWhisk.Tests.Dotnet.FakeType::Main")) + initCode should be(502) + + initRes should { + be( + Some(JsObject( + "error" -> JsString("Unable to locate requested type (\"Apache.OpenWhisk.Tests.Dotnet.FakeType\").")))) + } + } + } + + it should "fails on invalid method reference" in { + val (out, err) = withActionContainer() { c => + val (initCode, initRes) = c.init( + initPayload(functionb64, "Apache.OpenWhisk.Tests.Dotnet::Apache.OpenWhisk.Tests.Dotnet.Echo::FakeMethod")) + initCode should be(502) + + initRes should { + be(Some(JsObject("error" -> JsString("Unable to locate requested method (\"FakeMethod\").")))) + } + } + } + + it should "fails on type with no empty constructor" in { + val (out, err) = withActionContainer() { c => + val (initCode, initRes) = c.init( + initPayload( + functionb64, + "Apache.OpenWhisk.Tests.Dotnet::Apache.OpenWhisk.Tests.Dotnet.NonEmptyConstructor::Main")) + initCode should be(502) + + initRes should { + be( + Some(JsObject("error" -> JsString( + "Unable to locate appropriate constructor for (\"Apache.OpenWhisk.Tests.Dotnet.NonEmptyConstructor\").")))) + } + } + } + + it should "validate main string format 1" in { + val (out, err) = withActionContainer() { c => + val (initCode, initRes) = c.init(initPayload(functionb64, "Apache.OpenWhisk.Tests.Dotnet")) + initCode should not be (200) + + initRes should { + be(Some(JsObject("error" -> JsString("main required format is \"Assembly::Type::Function\".")))) + } + } + } + + it should "validate main string format 2" in { + val (out, err) = withActionContainer() { c => + val (initCode, initRes) = + c.init(initPayload(functionb64, "Apache.OpenWhisk.Tests.Dotnet::Apache.OpenWhisk.Tests.Dotnet.Echo")) + initCode should not be (200) + + initRes should { + be(Some(JsObject("error" -> JsString("main required format is \"Assembly::Type::Function\".")))) + } + } + } + + it should "enforce that the user returns an object" in { + val (out, err) = withActionContainer() { c => + val (initCode, _) = + c.init(initPayload(functionb64, "Apache.OpenWhisk.Tests.Dotnet::Apache.OpenWhisk.Tests.Dotnet.Nuller::Main")) + initCode should be(200) + + val (runCode, runRes) = c.run(runPayload(JsObject.empty)) + runCode should not be (200) + + runRes shouldBe defined + runRes.get.fields.get("error") shouldBe defined + } + + checkStreams(out, err, { + case (o, e) => + (o + e).toLowerCase should include("the action returned null") + }) + } +} diff --git a/tools/travis/build.sh b/tools/travis/build.sh index c75ab77..14db490 100755 --- a/tools/travis/build.sh +++ b/tools/travis/build.sh @@ -36,15 +36,15 @@ curl -fsSL https://get.docker.com -o get-docker.sh sudo sh get-docker.sh docker version -# Upgrade dpkg avoid problems installing dotnet 2.2 +# Upgrade dpkg avoid problems installing dotnet 3.0 # https://github.com/travis-ci/travis-ci/issues/9361#issuecomment-408431262 sudo apt-get install -y --force-yes -q -qq dpkg # Install dotnet -wget -q https://packages.microsoft.com/config/ubuntu/14.04/packages-microsoft-prod.deb +wget -q https://packages.microsoft.com/config/ubuntu/16.04/packages-microsoft-prod.deb sudo dpkg -i packages-microsoft-prod.deb sudo apt-get install -y apt-transport-https sudo apt-get -y update -qq -sudo apt-get install -y dotnet-sdk-2.2 +sudo apt-get install -y dotnet-sdk-3.0 # Build OpenWhisk deps before we run tests cd $WHISKDIR