From a42b62c2a3631e524c6b2c2295f4b183883381cc Mon Sep 17 00:00:00 2001 From: Matthew Gilliard Date: Wed, 10 Jan 2018 14:07:10 +0000 Subject: [PATCH 001/310] Updates for headers being removed and placed into ENV vars --- .../com/fnproject/fn/runtime/EntryPoint.java | 2 +- .../fnproject/fn/runtime/HttpEventCodec.java | 17 +++++-- .../fn/runtime/HttpEventCodecTest.java | 51 ++++++++++++++----- 3 files changed, 52 insertions(+), 18 deletions(-) diff --git a/runtime/src/main/java/com/fnproject/fn/runtime/EntryPoint.java b/runtime/src/main/java/com/fnproject/fn/runtime/EntryPoint.java index e5aa1265..6c5856a7 100644 --- a/runtime/src/main/java/com/fnproject/fn/runtime/EntryPoint.java +++ b/runtime/src/main/java/com/fnproject/fn/runtime/EntryPoint.java @@ -67,7 +67,7 @@ public int run(Map env, InputStream functionInput, OutputStream EventCodec codec; if (format != null && format.equalsIgnoreCase("http")) { - codec = new HttpEventCodec(functionInput, functionOutput); + codec = new HttpEventCodec(env, functionInput, functionOutput); } else if (format == null || format.equalsIgnoreCase("default")) { codec = new DefaultEventCodec(env, functionInput, functionOutput); } else { diff --git a/runtime/src/main/java/com/fnproject/fn/runtime/HttpEventCodec.java b/runtime/src/main/java/com/fnproject/fn/runtime/HttpEventCodec.java index 3c78a6ee..8ec9e398 100644 --- a/runtime/src/main/java/com/fnproject/fn/runtime/HttpEventCodec.java +++ b/runtime/src/main/java/com/fnproject/fn/runtime/HttpEventCodec.java @@ -38,8 +38,11 @@ public class HttpEventCodec implements EventCodec { private final SessionOutputBuffer sob; private final HttpMessageParser parser; + private final Map env; - HttpEventCodec(InputStream input, OutputStream output) { + HttpEventCodec(Map env, InputStream input, OutputStream output) { + + this.env = env; SessionInputBufferImpl sib = new SessionInputBufferImpl(new HttpTransportMetricsImpl(), 65535); sib.bind(Objects.requireNonNull(input)); @@ -56,6 +59,14 @@ private static String requiredHeader(HttpRequest req, String id) { return Optional.ofNullable(req.getFirstHeader(id)).map(Header::getValue).orElseThrow(() -> new FunctionInputHandlingException("Incoming HTTP frame is missing required header: " + id)); } + private String getRequiredEnv(String name) { + String val = env.get(name); + if (val == null) { + throw new FunctionInputHandlingException("Required environment variable " + name + " is not set - are you running a function outside of fn run?"); + } + return val; + } + @Override public final Optional readEvent() { @@ -79,8 +90,8 @@ public final Optional readEvent() { } else { bodyStream = new ByteArrayInputStream(new byte[]{}); } - String appName = requiredHeader(req, "fn_app_name"); - String route = requiredHeader(req, "fn_path"); + String appName = getRequiredEnv("FN_APP_NAME"); + String route = getRequiredEnv("FN_PATH"); String method = requiredHeader(req, "fn_method"); String requestUrl = requiredHeader(req, "fn_request_url"); diff --git a/runtime/src/test/java/com/fnproject/fn/runtime/HttpEventCodecTest.java b/runtime/src/test/java/com/fnproject/fn/runtime/HttpEventCodecTest.java index 7bed3d44..0f06c49b 100644 --- a/runtime/src/test/java/com/fnproject/fn/runtime/HttpEventCodecTest.java +++ b/runtime/src/test/java/com/fnproject/fn/runtime/HttpEventCodecTest.java @@ -44,20 +44,24 @@ public class HttpEventCodecTest { "Accept-Encoding: gzip\n" + "User-Agent: useragent\n" + "Fn_Request_url: http//localhost:8080/r/testapp/test\n" + - "Fn_Path: /test2\n" + "Fn_Method: GET\n" + "Content-Length: 0\n" + - "Fn_App_name: testapp\n" + "Fn_Call_Id: task-id2\n" + "Myconfig: fooconfig\n\n"; private final Map emptyConfig = new HashMap<>(); + private final Map env() { + HashMap env = new HashMap<>(); + env.put("FN_APP_NAME", "testapp"); + env.put("FN_PATH", "/test"); + return env; + } @Test public void testParsingSimpleHttpRequestWithFnHeadersAndBody() { ByteArrayInputStream bis = new ByteArrayInputStream(postReq.getBytes()); ByteArrayOutputStream bos = new ByteArrayOutputStream(); - HttpEventCodec httpEventCodec = new HttpEventCodec(bis, bos); + HttpEventCodec httpEventCodec = new HttpEventCodec(env(), bis, bos); InputEvent event = httpEventCodec.readEvent().get(); isExpectedPostEvent(event); @@ -77,7 +81,7 @@ public void shouldReadMultipleRequestsOnSameStream() { ByteArrayInputStream bis = new ByteArrayInputStream(input); ByteArrayOutputStream bos = new ByteArrayOutputStream(); - HttpEventCodec httpEventCodec = new HttpEventCodec(bis, bos); + HttpEventCodec httpEventCodec = new HttpEventCodec(env(), bis, bos); InputEvent postEvent = httpEventCodec.readEvent().get(); isExpectedPostEvent(postEvent); @@ -94,7 +98,7 @@ public void shouldReadMultipleRequestsOnSameStream() { @Test public void shouldRejectInvalidHttpRequest() { try { - HttpEventCodec httpEventCodec = new HttpEventCodec(asStream("NOT_HTTP " + getReq), nullOut); + HttpEventCodec httpEventCodec = new HttpEventCodec(env(), asStream("NOT_HTTP " + getReq), nullOut); httpEventCodec.readEvent(); fail(); @@ -106,12 +110,10 @@ public void shouldRejectInvalidHttpRequest() { @Test public void shouldRejectMissingHttpHeaders() { - Map requiredHeaders = new HashMap<>(); + Map requiredHeaders = new HashMap<>(); requiredHeaders.put("fn_request_url", "request_url"); - requiredHeaders.put("fn_path", "/route"); requiredHeaders.put("fn_method", "GET"); - requiredHeaders.put("fn_app_name", "app_name"); for (String key : requiredHeaders.keySet()) { Map newMap = new HashMap<>(requiredHeaders); @@ -119,21 +121,42 @@ public void shouldRejectMissingHttpHeaders() { String req = "GET / HTTP/1.1\n" + newMap.entrySet().stream().map(e -> e.getKey() + ": " + e.getValue()).collect(Collectors.joining("\n")) + "\n\n"; try { - HttpEventCodec httpEventCodec = new HttpEventCodec(asStream(req), nullOut); + HttpEventCodec httpEventCodec = new HttpEventCodec(env(), asStream(req), nullOut); httpEventCodec.readEvent(); fail("Should fail with header missing:" + key); } catch (FunctionInputHandlingException e) { assertThat(e).hasMessageMatching("Incoming HTTP frame is missing required header: " + key); } } + } + + @Test + public void shouldRejectMissingEnv() { + Map requiredEnv = new HashMap<>(); + + requiredEnv.put("FN_PATH", "/route"); + requiredEnv.put("FN_APP_NAME", "app_name"); + for (String key : requiredEnv.keySet()) { + Map newMap = new HashMap<>(requiredEnv); + newMap.remove(key); + + try { + ByteArrayInputStream bis = new ByteArrayInputStream(postReq.getBytes()); + HttpEventCodec httpEventCodec = new HttpEventCodec(newMap, bis, nullOut); + httpEventCodec.readEvent(); + fail("Should fail with header missing:" + key); + } catch (FunctionInputHandlingException e) { + assertThat(e).hasMessageMatching("Required environment variable " + key + " is not set - are you running a function outside of fn run\\?"); + } + } } @Test public void shouldSerializeSimpleSuccessfulEvent() throws Exception{ ByteArrayOutputStream bos = new ByteArrayOutputStream(); - HttpEventCodec httpEventCodec = new HttpEventCodec(nullIn,bos); + HttpEventCodec httpEventCodec = new HttpEventCodec(env(), nullIn, bos); OutputEvent outEvent = OutputEvent.fromBytes("Hello".getBytes(),OutputEvent.SUCCESS,"text/plain"); httpEventCodec.writeEvent(outEvent); @@ -172,7 +195,7 @@ private static String body(String httpResponse) { public void shouldSerializeSuccessfulEventWithHeaders() throws Exception{ ByteArrayOutputStream bos = new ByteArrayOutputStream(); - HttpEventCodec httpEventCodec = new HttpEventCodec(nullIn,bos); + HttpEventCodec httpEventCodec = new HttpEventCodec(env(), nullIn, bos); Map hs = new HashMap<>(); hs.put("foo", "bar"); hs.put("Content-Type", "application/octet-stream"); // ignored @@ -194,7 +217,7 @@ public void shouldSerializeSuccessfulEventWithHeaders() throws Exception{ public void shouldSerializeSimpleFailedEvent() throws Exception{ ByteArrayOutputStream bos = new ByteArrayOutputStream(); - HttpEventCodec httpEventCodec = new HttpEventCodec(nullIn,bos); + HttpEventCodec httpEventCodec = new HttpEventCodec(env(), nullIn, bos); OutputEvent outEvent = OutputEvent.fromBytes("Hello".getBytes(), OutputEvent.FAILURE,"text/plain"); httpEventCodec.writeEvent(outEvent); @@ -211,7 +234,7 @@ public void shouldSerializeSimpleFailedEvent() throws Exception{ public void shouldSerializeFailedEventWithHeaders() throws Exception{ ByteArrayOutputStream bos = new ByteArrayOutputStream(); - HttpEventCodec httpEventCodec = new HttpEventCodec(nullIn,bos); + HttpEventCodec httpEventCodec = new HttpEventCodec(env(), nullIn,bos); Map hs = new HashMap<>(); hs.put("foo", "bar"); hs.put("Content-Type", "application/octet-stream"); // ignored @@ -236,7 +259,7 @@ private InputStream asStream(String sin) { private void isExpectedGetEvent(InputEvent getEvent) { assertThat(getEvent.getAppName()).isEqualTo("testapp"); assertThat(getEvent.getMethod()).isEqualTo("GET"); - assertThat(getEvent.getRoute()).isEqualTo("/test2"); + assertThat(getEvent.getRoute()).isEqualTo("/test"); assertThat(getEvent.getHeaders().getAll()) .contains(headerEntry("Accept-Encoding", "gzip"), From 7ac184b0e37b65ef28d4609e78ba4d6d611b0fd4 Mon Sep 17 00:00:00 2001 From: CI Date: Thu, 11 Jan 2018 23:11:05 +0000 Subject: [PATCH 002/310] fn-java-fdk: post-1.0.56 version bump [skip ci] --- release.version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/release.version b/release.version index ed453e69..9f1a8647 100644 --- a/release.version +++ b/release.version @@ -1 +1 @@ -1.0.56 +1.0.57 From fabd0fe3529b53fa08f6c94f8b698b292e8d6a75 Mon Sep 17 00:00:00 2001 From: Jaroslav Tulach Date: Tue, 6 Feb 2018 19:54:29 +0100 Subject: [PATCH 003/310] Use < and > inside of {@code} Javadoc section --- api/src/main/java/com/fnproject/fn/api/TypeWrapper.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/api/src/main/java/com/fnproject/fn/api/TypeWrapper.java b/api/src/main/java/com/fnproject/fn/api/TypeWrapper.java index f453892d..d757c411 100644 --- a/api/src/main/java/com/fnproject/fn/api/TypeWrapper.java +++ b/api/src/main/java/com/fnproject/fn/api/TypeWrapper.java @@ -11,11 +11,11 @@ public interface TypeWrapper { * * For example, take the following classes: *
{@code
-     * class GenericParent<T> {
+     * class GenericParent {
      *   public void someMethod(T t) { // do something with t }
      * }
      *
-     * class ConcreteClass extends GenericParent<String> { }
+     * class ConcreteClass extends GenericParent { }
      * }
* * A {@link TypeWrapper} representing the first argument of {@code someMethod} would return {@code String.class} From 1b972480529bb2921591474ed83881c2f33ffbbf Mon Sep 17 00:00:00 2001 From: Owen Cliffe Date: Wed, 28 Feb 2018 18:00:00 +0000 Subject: [PATCH 004/310] adding gradle build example --- .gitignore | 4 ++- examples/README.md | 3 ++ examples/gradle-build/.dockerignore | 4 +++ examples/gradle-build/Dockerfile | 20 ++++++++++++ examples/gradle-build/README.md | 14 ++++++++ examples/gradle-build/build.gradle | 32 +++++++++++++++++++ examples/gradle-build/func.yaml | 4 +++ .../java/com/example/fn/HelloFunction.java | 10 ++++++ .../com/example/fn/HelloFunctionTest.java | 22 +++++++++++++ 9 files changed, 112 insertions(+), 1 deletion(-) create mode 100644 examples/gradle-build/.dockerignore create mode 100644 examples/gradle-build/Dockerfile create mode 100644 examples/gradle-build/README.md create mode 100644 examples/gradle-build/build.gradle create mode 100644 examples/gradle-build/func.yaml create mode 100644 examples/gradle-build/src/main/java/com/example/fn/HelloFunction.java create mode 100644 examples/gradle-build/src/test/java/com/example/fn/HelloFunctionTest.java diff --git a/.gitignore b/.gitignore index f93517a1..1fff5367 100644 --- a/.gitignore +++ b/.gitignore @@ -9,4 +9,6 @@ target/ logs/ /headrevtag.txt *.bak -*.versionsBackup \ No newline at end of file +*.versionsBackup +.gradle +examples/gradle-build/build diff --git a/examples/README.md b/examples/README.md index 4600bd90..4995a246 100644 --- a/examples/README.md +++ b/examples/README.md @@ -34,3 +34,6 @@ access to data entering the `fn` Java FDK. This example showcases the Fn Flow asynchronous execution API, by creating a workflow that takes an image and asynchronously generates three thumbnails for it, then uploads them to an object storage. + +## 5. Gradle build +This shows how to use Gradle to build functions using the Java FDK. diff --git a/examples/gradle-build/.dockerignore b/examples/gradle-build/.dockerignore new file mode 100644 index 00000000..531da109 --- /dev/null +++ b/examples/gradle-build/.dockerignore @@ -0,0 +1,4 @@ +.gradle +.idea +.git +build \ No newline at end of file diff --git a/examples/gradle-build/Dockerfile b/examples/gradle-build/Dockerfile new file mode 100644 index 00000000..859cc232 --- /dev/null +++ b/examples/gradle-build/Dockerfile @@ -0,0 +1,20 @@ +FROM gradle:4.5.1-jdk8 as build-stage +WORKDIR /function +# needed for gradle? +USER root +ENV GRADLE_USER_HOME /function/.gradle + +# Code build +# Copy any build files into the build container and build +COPY *.gradle /function/ +RUN ["gradle", "-s", "--no-daemon","--console","plain","cacheDeps"] + +# Copies build source into build container +COPY src /function/src + +RUN ["gradle", "-s", "--no-daemon","--console","plain","build"] +# Container build +FROM fnproject/fn-java-fdk:1.0.56 +WORKDIR /function +COPY --from=build-stage /function/build/libs/*.jar /function/build/deps/*.jar /function/app/ +CMD ["com.example.fn.HelloFunction::handleRequest"] diff --git a/examples/gradle-build/README.md b/examples/gradle-build/README.md new file mode 100644 index 00000000..269072c7 --- /dev/null +++ b/examples/gradle-build/README.md @@ -0,0 +1,14 @@ +# Fn Gradle + Java fdk example + +Fn uses Maven by default for builds. This is an example that uses Fn's `docker` runtime format to build a Java function using the [Fn Java FDK](https://github.com/fnproject/fdk-java). + +The example consists of a `Dockerfile` that builds the function using gradle and copies the function's dependencies to `build/deps` and a func.yaml that uses that `Dockerfile` to build the function. + +Note that FDK versions are hard-coded in this example, you may need to update them manually to more recent version. + +Key points: + +* [Dockerfile](Dockerfile) - contains the containerised docker build (based on dockerhub library/gradle images) and image build - this includes the gradle invocation +* The `cacheDeps` task in `build.gradle` is invoked within the Dockerfile - The task pulls down dependencies into the container gradle cache to speed up docker builds. +* The `copyDeps` task in `build.gradle` copies the functions compile deps +* This uses JDK 8 by default - you can change this to Java 9 by changing : `FROM gradle:4.5.1-jdk8 as build-stage` to `FROM gradle:4.5.1-jdk9 as build-stage` and `FROM fnproject/fn-java-fdk:1.0.56` to `FROM fnproject/fn-java-fdk:jdk9-1.0.56` \ No newline at end of file diff --git a/examples/gradle-build/build.gradle b/examples/gradle-build/build.gradle new file mode 100644 index 00000000..c15e3fc0 --- /dev/null +++ b/examples/gradle-build/build.gradle @@ -0,0 +1,32 @@ +apply plugin: 'java' + +ext { + fdkVersion = '1.0.56' +} + +repositories { + mavenCentral() + maven { + url 'https://dl.bintray.com/fnproject/fnproject' + } +} + +dependencies { + runtime "com.fnproject.fn:api:$fdkVersion" + // runtime "com.fnproject.fn:runtime:$fdkVersion" // this is optional and included with its deps in the base image to reduce layer size + + testCompile "junit:junit:4.12" + testCompile "com.fnproject.fn:testing:$fdkVersion" +} + +task cacheDeps(type: Exec) { + configurations.testRuntime.files + commandLine 'echo', 'Downloaded all dependencies' +} + +task copyDeps(type: Copy) { + from configurations.compile + into "${project.buildDir}/deps" +} + +build.dependsOn copyDeps diff --git a/examples/gradle-build/func.yaml b/examples/gradle-build/func.yaml new file mode 100644 index 00000000..2f82680d --- /dev/null +++ b/examples/gradle-build/func.yaml @@ -0,0 +1,4 @@ +name: gradle_build +version: 0.0.3 +runtime: docker +format: http diff --git a/examples/gradle-build/src/main/java/com/example/fn/HelloFunction.java b/examples/gradle-build/src/main/java/com/example/fn/HelloFunction.java new file mode 100644 index 00000000..8aa7fef7 --- /dev/null +++ b/examples/gradle-build/src/main/java/com/example/fn/HelloFunction.java @@ -0,0 +1,10 @@ +package com.example.fn; + +public class HelloFunction { + + public String handleRequest(String input) { + String name = (input == null || input.isEmpty()) ? "world" : input; + return "Hello, " + name + "!"; + } + +} \ No newline at end of file diff --git a/examples/gradle-build/src/test/java/com/example/fn/HelloFunctionTest.java b/examples/gradle-build/src/test/java/com/example/fn/HelloFunctionTest.java new file mode 100644 index 00000000..e6b7a5e3 --- /dev/null +++ b/examples/gradle-build/src/test/java/com/example/fn/HelloFunctionTest.java @@ -0,0 +1,22 @@ +package com.example.fn; + +import com.fnproject.fn.testing.*; +import org.junit.*; + +import static org.junit.Assert.*; + +public class HelloFunctionTest { + + @Rule + public final FnTestingRule testing = FnTestingRule.createDefault(); + + @Test + public void shouldReturnGreeting() { + testing.givenEvent().enqueue(); + testing.thenRun(HelloFunction.class, "handleRequest"); + + FnResult result = testing.getOnlyResult(); + assertEquals("Hello, world!", result.getBodyAsString()); + } + +} \ No newline at end of file From 053c1152962fc826b1caca7452e50df888fbee96 Mon Sep 17 00:00:00 2001 From: Jaroslav Tulach Date: Wed, 28 Feb 2018 19:11:59 +0100 Subject: [PATCH 005/310] Make sure nobody can subclass Flows class --- api/pom.xml | 8 +++++++ .../java/com/fnproject/fn/api/flow/Flows.java | 4 +++- .../com/fnproject/fn/api/flow/FlowsTest.java | 23 +++++++++++++++++++ 3 files changed, 34 insertions(+), 1 deletion(-) create mode 100644 api/src/test/java/com/fnproject/fn/api/flow/FlowsTest.java diff --git a/api/pom.xml b/api/pom.xml index 71190839..9a1d4998 100644 --- a/api/pom.xml +++ b/api/pom.xml @@ -32,4 +32,12 @@ + + + junit + junit + 4.12 + test + + diff --git a/api/src/main/java/com/fnproject/fn/api/flow/Flows.java b/api/src/main/java/com/fnproject/fn/api/flow/Flows.java index 4df4f51a..c71b58d4 100644 --- a/api/src/main/java/com/fnproject/fn/api/flow/Flows.java +++ b/api/src/main/java/com/fnproject/fn/api/flow/Flows.java @@ -8,7 +8,9 @@ /** * Fn Flow API entry point class - this provides access to the current {@link Flow} for the current function invocation. */ -public class Flows { +public final class Flows { + private Flows() { + } private static FlowSource flowSource; diff --git a/api/src/test/java/com/fnproject/fn/api/flow/FlowsTest.java b/api/src/test/java/com/fnproject/fn/api/flow/FlowsTest.java new file mode 100644 index 00000000..d8d51d5e --- /dev/null +++ b/api/src/test/java/com/fnproject/fn/api/flow/FlowsTest.java @@ -0,0 +1,23 @@ +package com.fnproject.fn.api.flow; + +import java.lang.reflect.Modifier; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertTrue; +import org.junit.Test; + +public class FlowsTest { + public FlowsTest() { + } + + /** People shall not be allowed to create subclasses of {@code Flow}: + *
+    * static class MyFlows extends Flows {
+    * }
+    * 
+ */ + @Test + public void dontSubclassFlows() { + assertTrue("Flows is final", Modifier.isFinal(Flows.class.getModifiers())); + assertEquals("No visible constructors", 0, Flows.class.getConstructors().length); + } +} From fbb59a5850f6c5870fd9b0a21df73e4408f9a9ab Mon Sep 17 00:00:00 2001 From: Owen Cliffe Date: Thu, 1 Mar 2018 15:08:44 +0000 Subject: [PATCH 006/310] Ign test tweaks, easier local running --- .circleci/config.yml | 5 ++++- build-image/Dockerfile | 2 +- build-image/Dockerfile-jdk9 | 1 + build-image/cache-deps.sh | 10 +++++++++- build-image/docker-build.sh | 7 ++++++- build-image/pom.xml | 3 ++- integration-tests/README.md | 6 ++++-- integration-tests/run-local.sh | 2 +- integration-tests/smoke-test.sh | 2 +- 9 files changed, 29 insertions(+), 9 deletions(-) diff --git a/.circleci/config.yml b/.circleci/config.yml index b509d952..def24eec 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -48,7 +48,10 @@ jobs: - run: name: Login to Docker - command: docker login -u $DOCKER_USER -p $DOCKER_PASS + command: | + if [[ "${CIRCLE_BRANCH}" == "master" && -z "${CIRCLE_PR_REPONAME}" ]]; then + docker login -u $DOCKER_USER -p $DOCKER_PASS + fi - run: name: Build fn-java-fdk Docker build image diff --git a/build-image/Dockerfile b/build-image/Dockerfile index 003c4107..38424406 100644 --- a/build-image/Dockerfile +++ b/build-image/Dockerfile @@ -1,5 +1,5 @@ FROM maven:3-jdk-8-slim - +ARG FN_REPO_URL ADD pom.xml /tmp/cache-deps/pom.xml ADD cache-deps.sh /tmp/cache-deps/cache-deps.sh ADD src /tmp/cache-deps/src diff --git a/build-image/Dockerfile-jdk9 b/build-image/Dockerfile-jdk9 index db4b8917..c6396862 100644 --- a/build-image/Dockerfile-jdk9 +++ b/build-image/Dockerfile-jdk9 @@ -1,4 +1,5 @@ FROM maven:3-jdk-9-slim +ARG FN_REPO_URL ADD pom.xml /tmp/cache-deps/pom.xml ADD cache-deps.sh /tmp/cache-deps/cache-deps.sh diff --git a/build-image/cache-deps.sh b/build-image/cache-deps.sh index c3a31654..4a8a7eeb 100755 --- a/build-image/cache-deps.sh +++ b/build-image/cache-deps.sh @@ -1,4 +1,12 @@ #!/bin/bash -ex -cd /tmp/cache-deps && mvn test package dependency:copy-dependencies -Dmaven.repo.local=/usr/share/maven/ref/repository -Dmdep.prependGroupId=true -DoutputDirectory=target +set -x +set -e + +if [ -n "$FN_REPO_URL" ]; then + REPO_DFN="-Dfn.repo.url=$FN_REPO_URL" +fi + + +cd /tmp/cache-deps && mvn test package dependency:copy-dependencies -Dmaven.repo.local=/usr/share/maven/ref/repository -Dmdep.prependGroupId=true -DoutputDirectory=target $REPO_DFN cd / && rm -fr /tmp/cache-deps diff --git a/build-image/docker-build.sh b/build-image/docker-build.sh index 494b2cd7..d5dc37b1 100755 --- a/build-image/docker-build.sh +++ b/build-image/docker-build.sh @@ -3,5 +3,10 @@ cd /tmp/staging-repository && python -mSimpleHTTPServer 18080 1>>/tmp/http-logs 2>&1 & SRV_PROCESS=$! -docker build $* +if [ -n "$DOCKER_LOCALHOST" ]; then + REPO_ENV="--build-arg FN_REPO_URL=http://$DOCKER_LOCALHOST:18080" +fi + +docker build $REPO_ENV $* + kill $SRV_PROCESS diff --git a/build-image/pom.xml b/build-image/pom.xml index 6ae2415e..474548d4 100644 --- a/build-image/pom.xml +++ b/build-image/pom.xml @@ -8,6 +8,7 @@ UTF-8 1.0.0-SNAPSHOT + http://172.17.0.1:18080 @@ -64,7 +65,7 @@ fn-maven-releases - http://172.17.0.1:18080 + ${fn.repo.url} diff --git a/integration-tests/README.md b/integration-tests/README.md index 07dde6f2..0d13256d 100644 --- a/integration-tests/README.md +++ b/integration-tests/README.md @@ -33,19 +33,21 @@ To run locally you will need to deploy the fn artifacts to a local repository: (in top-level dir) ```bash export REPOSITORY_LOCATION=/tmp/staging-repository +# on OSX: +export DOCKER_LOCALHOST=docker.for.mac.localhost mvn deploy -DaltDeploymentRepository=localStagingDir::default::file://"$REPOSITORY_LOCATION" ``` You may also want to/need build local copies of the build images: ```bash -cd build-images +cd build-image ./docker-build.sh -t fnproject/fn-java-fdk-build . -./docker-build.sh -f Dockerfile-jdk9 -t fnproject/fn-java-fdk-build:jdk9-latest . ``` and runtime images: ``` +cd runtime docker build -t fnproject/fn-java-fdk . docker build -f Dockerfile-jdk9 -t fnproject/fn-java-fdk:jdk9-latest . ``` diff --git a/integration-tests/run-local.sh b/integration-tests/run-local.sh index 06d01bf0..ec73332e 100755 --- a/integration-tests/run-local.sh +++ b/integration-tests/run-local.sh @@ -47,7 +47,7 @@ docker pull $FUNCTIONS_DOCKER_IMAGE FUNCTIONS_CONTAINER_ID=$( docker run -d \ - -p 8080 \ + -p 8080:8080 \ -v /var/run/docker.sock:/var/run/docker.sock \ --name functions-$SUFFIX \ -e FN_LOG_LEVEL=debug \ diff --git a/integration-tests/smoke-test.sh b/integration-tests/smoke-test.sh index 324b895a..234b5185 100755 --- a/integration-tests/smoke-test.sh +++ b/integration-tests/smoke-test.sh @@ -35,7 +35,7 @@ fi [[ -n "$PRE_BUILD_HOOK" ]] && $PRE_BUILD_HOOK -fn build --no-cache >build-output 2>&1 || { +fn -v build --no-cache >build-output 2>&1 || { echo "Test function build failed:" cat build-output exit 1 From 1e5112244cb50a911b1176a66c793b5b0ed42795 Mon Sep 17 00:00:00 2001 From: Owen Cliffe Date: Thu, 1 Mar 2018 15:12:36 +0000 Subject: [PATCH 007/310] indent in circle file --- .circleci/config.yml | 6 +++--- integration-tests/main/test-1-jdk8/pom.xml | 2 +- integration-tests/main/test-1/pom.xml | 2 +- integration-tests/main/test-2/func.yaml | 2 +- integration-tests/main/test-2/pom.xml | 2 +- integration-tests/main/test-4/pom.xml | 2 +- integration-tests/main/test-5/pom.xml | 2 +- integration-tests/main/test-6/pom.xml | 2 +- 8 files changed, 10 insertions(+), 10 deletions(-) diff --git a/.circleci/config.yml b/.circleci/config.yml index def24eec..7188b583 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -49,9 +49,9 @@ jobs: - run: name: Login to Docker command: | - if [[ "${CIRCLE_BRANCH}" == "master" && -z "${CIRCLE_PR_REPONAME}" ]]; then - docker login -u $DOCKER_USER -p $DOCKER_PASS - fi + if [[ "${CIRCLE_BRANCH}" == "master" && -z "${CIRCLE_PR_REPONAME}" ]]; then + docker login -u $DOCKER_USER -p $DOCKER_PASS + fi - run: name: Build fn-java-fdk Docker build image diff --git a/integration-tests/main/test-1-jdk8/pom.xml b/integration-tests/main/test-1-jdk8/pom.xml index 37f78c46..0931458a 100644 --- a/integration-tests/main/test-1-jdk8/pom.xml +++ b/integration-tests/main/test-1-jdk8/pom.xml @@ -58,7 +58,7 @@ fn-maven-releases - https://dl.bintray.com/fnproject/fnproject + http://172.17.0.2:18080 diff --git a/integration-tests/main/test-1/pom.xml b/integration-tests/main/test-1/pom.xml index 37f78c46..0931458a 100644 --- a/integration-tests/main/test-1/pom.xml +++ b/integration-tests/main/test-1/pom.xml @@ -58,7 +58,7 @@ fn-maven-releases - https://dl.bintray.com/fnproject/fnproject + http://172.17.0.2:18080 diff --git a/integration-tests/main/test-2/func.yaml b/integration-tests/main/test-2/func.yaml index 38e48a45..9f3f83c2 100644 --- a/integration-tests/main/test-2/func.yaml +++ b/integration-tests/main/test-2/func.yaml @@ -1,5 +1,5 @@ name: fn-test/test-2 -version: 0.0.1 +version: 0.0.2 runtime: java9 cmd: com.fnproject.fn.integration.test2.PlainFunction::handleRequest format: http diff --git a/integration-tests/main/test-2/pom.xml b/integration-tests/main/test-2/pom.xml index da270e30..41d41303 100644 --- a/integration-tests/main/test-2/pom.xml +++ b/integration-tests/main/test-2/pom.xml @@ -56,7 +56,7 @@ fn-maven-releases - https://dl.bintray.com/fnproject/fnproject + http://172.17.0.2:18080 diff --git a/integration-tests/main/test-4/pom.xml b/integration-tests/main/test-4/pom.xml index 380c0d33..160bd7f6 100644 --- a/integration-tests/main/test-4/pom.xml +++ b/integration-tests/main/test-4/pom.xml @@ -69,7 +69,7 @@ fn-maven-releases - https://dl.bintray.com/fnproject/fnproject + http://172.17.0.2:18080 diff --git a/integration-tests/main/test-5/pom.xml b/integration-tests/main/test-5/pom.xml index 400510fc..88d2f385 100644 --- a/integration-tests/main/test-5/pom.xml +++ b/integration-tests/main/test-5/pom.xml @@ -58,7 +58,7 @@ fn-maven-releases - https://dl.bintray.com/fnproject/fnproject + http://172.17.0.2:18080 diff --git a/integration-tests/main/test-6/pom.xml b/integration-tests/main/test-6/pom.xml index bacc9706..93966e79 100644 --- a/integration-tests/main/test-6/pom.xml +++ b/integration-tests/main/test-6/pom.xml @@ -58,7 +58,7 @@ fn-maven-releases - https://dl.bintray.com/fnproject/fnproject + http://172.17.0.2:18080 From a6d7fcfb9d457b0c972854dafca9737e266de630 Mon Sep 17 00:00:00 2001 From: Owen Cliffe Date: Thu, 1 Mar 2018 15:55:14 +0000 Subject: [PATCH 008/310] revert broken poms, add name to funcs --- integration-tests/main/test-1-jdk8/func.yaml | 1 + integration-tests/main/test-1-jdk8/pom.xml | 2 +- integration-tests/main/test-1/func.yaml | 3 ++- integration-tests/main/test-1/pom.xml | 2 +- integration-tests/main/test-2/func.yaml | 2 +- integration-tests/main/test-2/pom.xml | 2 +- integration-tests/main/test-4/func.yaml | 1 + integration-tests/main/test-4/pom.xml | 2 +- integration-tests/main/test-5/func.yaml | 1 + integration-tests/main/test-5/pom.xml | 2 +- integration-tests/main/test-6/func.yaml | 1 + integration-tests/main/test-6/pom.xml | 2 +- 12 files changed, 13 insertions(+), 8 deletions(-) diff --git a/integration-tests/main/test-1-jdk8/func.yaml b/integration-tests/main/test-1-jdk8/func.yaml index 5e89d168..43b2d3a1 100644 --- a/integration-tests/main/test-1-jdk8/func.yaml +++ b/integration-tests/main/test-1-jdk8/func.yaml @@ -3,3 +3,4 @@ runtime: java8 cmd: com.fnproject.fn.integration.test_1.CompleterFunction::handleRequest format: http timeout: 120 +name: test-1-jdk8 \ No newline at end of file diff --git a/integration-tests/main/test-1-jdk8/pom.xml b/integration-tests/main/test-1-jdk8/pom.xml index 0931458a..37f78c46 100644 --- a/integration-tests/main/test-1-jdk8/pom.xml +++ b/integration-tests/main/test-1-jdk8/pom.xml @@ -58,7 +58,7 @@ fn-maven-releases - http://172.17.0.2:18080 + https://dl.bintray.com/fnproject/fnproject diff --git a/integration-tests/main/test-1/func.yaml b/integration-tests/main/test-1/func.yaml index 72fbe623..81f45b5c 100644 --- a/integration-tests/main/test-1/func.yaml +++ b/integration-tests/main/test-1/func.yaml @@ -1,4 +1,5 @@ -version: 0.0.1 +name: test-1 +version: 0.0.5 runtime: java cmd: com.fnproject.fn.integration.test_1.CompleterFunction::handleRequest format: http diff --git a/integration-tests/main/test-1/pom.xml b/integration-tests/main/test-1/pom.xml index 0931458a..37f78c46 100644 --- a/integration-tests/main/test-1/pom.xml +++ b/integration-tests/main/test-1/pom.xml @@ -58,7 +58,7 @@ fn-maven-releases - http://172.17.0.2:18080 + https://dl.bintray.com/fnproject/fnproject diff --git a/integration-tests/main/test-2/func.yaml b/integration-tests/main/test-2/func.yaml index 9f3f83c2..dfa380dd 100644 --- a/integration-tests/main/test-2/func.yaml +++ b/integration-tests/main/test-2/func.yaml @@ -1,4 +1,4 @@ -name: fn-test/test-2 +name: test-2 version: 0.0.2 runtime: java9 cmd: com.fnproject.fn.integration.test2.PlainFunction::handleRequest diff --git a/integration-tests/main/test-2/pom.xml b/integration-tests/main/test-2/pom.xml index 41d41303..da270e30 100644 --- a/integration-tests/main/test-2/pom.xml +++ b/integration-tests/main/test-2/pom.xml @@ -56,7 +56,7 @@ fn-maven-releases - http://172.17.0.2:18080 + https://dl.bintray.com/fnproject/fnproject diff --git a/integration-tests/main/test-4/func.yaml b/integration-tests/main/test-4/func.yaml index 376d0467..d7e5fee1 100644 --- a/integration-tests/main/test-4/func.yaml +++ b/integration-tests/main/test-4/func.yaml @@ -6,3 +6,4 @@ build: -Dmdep.prependGroupId=true -DoutputDirectory=target format: http timeout: 120 +name: test-4 diff --git a/integration-tests/main/test-4/pom.xml b/integration-tests/main/test-4/pom.xml index 160bd7f6..380c0d33 100644 --- a/integration-tests/main/test-4/pom.xml +++ b/integration-tests/main/test-4/pom.xml @@ -69,7 +69,7 @@ fn-maven-releases - http://172.17.0.2:18080 + https://dl.bintray.com/fnproject/fnproject diff --git a/integration-tests/main/test-5/func.yaml b/integration-tests/main/test-5/func.yaml index a5886022..1fa56725 100644 --- a/integration-tests/main/test-5/func.yaml +++ b/integration-tests/main/test-5/func.yaml @@ -3,3 +3,4 @@ runtime: java9 cmd: com.fnproject.fn.integration.test_5.CompleterFunction::handleRequest format: http timeout: 120 +name: test-5 \ No newline at end of file diff --git a/integration-tests/main/test-5/pom.xml b/integration-tests/main/test-5/pom.xml index 88d2f385..400510fc 100644 --- a/integration-tests/main/test-5/pom.xml +++ b/integration-tests/main/test-5/pom.xml @@ -58,7 +58,7 @@ fn-maven-releases - http://172.17.0.2:18080 + https://dl.bintray.com/fnproject/fnproject diff --git a/integration-tests/main/test-6/func.yaml b/integration-tests/main/test-6/func.yaml index a0cf97fe..0178652a 100644 --- a/integration-tests/main/test-6/func.yaml +++ b/integration-tests/main/test-6/func.yaml @@ -3,3 +3,4 @@ runtime: java9 cmd: com.fnproject.fn.integration.test_6.CompleterFunction::handleRequest format: http timeout: 120 +name: test-6 \ No newline at end of file diff --git a/integration-tests/main/test-6/pom.xml b/integration-tests/main/test-6/pom.xml index 93966e79..bacc9706 100644 --- a/integration-tests/main/test-6/pom.xml +++ b/integration-tests/main/test-6/pom.xml @@ -58,7 +58,7 @@ fn-maven-releases - http://172.17.0.2:18080 + https://dl.bintray.com/fnproject/fnproject From 78a616fb917cdd37700c978d6b3b64074880233b Mon Sep 17 00:00:00 2001 From: Owen Cliffe Date: Thu, 1 Mar 2018 16:09:44 +0000 Subject: [PATCH 009/310] Update func.yaml fix func.yaml version [skip ci] --- integration-tests/main/test-2/func.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/integration-tests/main/test-2/func.yaml b/integration-tests/main/test-2/func.yaml index dfa380dd..aec91b13 100644 --- a/integration-tests/main/test-2/func.yaml +++ b/integration-tests/main/test-2/func.yaml @@ -1,5 +1,5 @@ name: test-2 -version: 0.0.2 +version: 0.0.1 runtime: java9 cmd: com.fnproject.fn.integration.test2.PlainFunction::handleRequest format: http From 430a485d1af5934b9b0fa6edd5cde5275a541a0a Mon Sep 17 00:00:00 2001 From: CI Date: Thu, 1 Mar 2018 18:03:26 +0000 Subject: [PATCH 010/310] fn-java-fdk: post-1.0.57 version bump [skip ci] --- release.version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/release.version b/release.version index 9f1a8647..3a90b246 100644 --- a/release.version +++ b/release.version @@ -1 +1 @@ -1.0.57 +1.0.58 From 40926dabed3799a66c5929d9ce3044c34393b4d3 Mon Sep 17 00:00:00 2001 From: CI Date: Fri, 2 Mar 2018 10:27:50 +0000 Subject: [PATCH 011/310] fn-java-fdk: post-1.0.58 version bump [skip ci] --- release.version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/release.version b/release.version index 3a90b246..c3ccccfa 100644 --- a/release.version +++ b/release.version @@ -1 +1 @@ -1.0.58 +1.0.59 From 03598f761d927f106de45d8f6fc3318e595b6fd8 Mon Sep 17 00:00:00 2001 From: Jaroslav Tulach Date: Mon, 5 Mar 2018 19:20:20 +0100 Subject: [PATCH 012/310] Checking the public signatures of the API classes against the current API snapshot --- api/pom.xml | 17 ++ api/src/main/api/snapshot.sigfile | 467 ++++++++++++++++++++++++++++++ 2 files changed, 484 insertions(+) create mode 100644 api/src/main/api/snapshot.sigfile diff --git a/api/pom.xml b/api/pom.xml index 9a1d4998..224d57d5 100644 --- a/api/pom.xml +++ b/api/pom.xml @@ -30,6 +30,23 @@ + + org.netbeans.tools + sigtest-maven-plugin + 1.0 + + + + check + + + + + src/main/api/snapshot.sigfile + strictcheck + com.fnproject.fn.api,com.fnproject.fn.api.exception,com.fnproject.fn.api.flow + + diff --git a/api/src/main/api/snapshot.sigfile b/api/src/main/api/snapshot.sigfile new file mode 100644 index 00000000..1f743e18 --- /dev/null +++ b/api/src/main/api/snapshot.sigfile @@ -0,0 +1,467 @@ +#Signature file v4.1 +#Version 1.0.0-SNAPSHOT + +CLSS public abstract interface !annotation com.fnproject.fn.api.FnConfiguration + anno 0 java.lang.annotation.Retention(java.lang.annotation.RetentionPolicy value=RUNTIME) + anno 0 java.lang.annotation.Target(java.lang.annotation.ElementType[] value=[METHOD]) +intf java.lang.annotation.Annotation + +CLSS public abstract interface com.fnproject.fn.api.FunctionInvoker +meth public abstract java.util.Optional tryInvoke(com.fnproject.fn.api.InvocationContext,com.fnproject.fn.api.InputEvent) + +CLSS public final com.fnproject.fn.api.Headers +meth public com.fnproject.fn.api.Headers withHeader(java.lang.String,java.lang.String) +meth public java.util.Map getAll() +meth public java.util.Optional get(java.lang.String) +meth public static com.fnproject.fn.api.Headers emptyHeaders() +meth public static com.fnproject.fn.api.Headers fromMap(java.util.Map) +supr java.lang.Object +hfds headers + +CLSS public abstract interface !annotation com.fnproject.fn.api.InputBinding + anno 0 java.lang.annotation.Retention(java.lang.annotation.RetentionPolicy value=RUNTIME) + anno 0 java.lang.annotation.Target(java.lang.annotation.ElementType[] value=[PARAMETER]) +intf java.lang.annotation.Annotation +meth public abstract java.lang.Class coercion() + +CLSS public abstract interface com.fnproject.fn.api.InputCoercion<%0 extends java.lang.Object> +meth public abstract java.util.Optional<{com.fnproject.fn.api.InputCoercion%0}> tryCoerceParam(com.fnproject.fn.api.InvocationContext,int,com.fnproject.fn.api.InputEvent,com.fnproject.fn.api.MethodWrapper) + +CLSS public abstract interface com.fnproject.fn.api.InputEvent +intf java.io.Closeable +meth public abstract <%0 extends java.lang.Object> {%%0} consumeBody(java.util.function.Function) +meth public abstract com.fnproject.fn.api.Headers getHeaders() +meth public abstract com.fnproject.fn.api.QueryParameters getQueryParameters() +meth public abstract java.lang.String getAppName() +meth public abstract java.lang.String getMethod() +meth public abstract java.lang.String getRequestUrl() +meth public abstract java.lang.String getRoute() + +CLSS public abstract interface com.fnproject.fn.api.InvocationContext +meth public abstract com.fnproject.fn.api.RuntimeContext getRuntimeContext() +meth public abstract void addListener(com.fnproject.fn.api.InvocationListener) + +CLSS public abstract interface com.fnproject.fn.api.InvocationListener +intf java.util.EventListener +meth public abstract void onFailure() +meth public abstract void onSuccess() + +CLSS public abstract interface com.fnproject.fn.api.MethodWrapper +meth public abstract com.fnproject.fn.api.TypeWrapper getParamType(int) +meth public abstract com.fnproject.fn.api.TypeWrapper getReturnType() +meth public abstract java.lang.Class getTargetClass() +meth public abstract java.lang.reflect.Method getTargetMethod() +meth public int getParameterCount() +meth public java.lang.String getLongName() + +CLSS public abstract interface !annotation com.fnproject.fn.api.OutputBinding + anno 0 java.lang.annotation.Retention(java.lang.annotation.RetentionPolicy value=RUNTIME) + anno 0 java.lang.annotation.Target(java.lang.annotation.ElementType[] value=[METHOD]) +intf java.lang.annotation.Annotation +meth public abstract java.lang.Class coercion() + +CLSS public abstract interface com.fnproject.fn.api.OutputCoercion +meth public abstract java.util.Optional wrapFunctionResult(com.fnproject.fn.api.InvocationContext,com.fnproject.fn.api.MethodWrapper,java.lang.Object) + +CLSS public abstract interface com.fnproject.fn.api.OutputEvent +fld public final static int FAILURE = 500 +fld public final static int SUCCESS = 200 +meth public abstract com.fnproject.fn.api.Headers getHeaders() +meth public abstract int getStatusCode() +meth public abstract java.util.Optional getContentType() +meth public abstract void writeToOutput(java.io.OutputStream) throws java.io.IOException +meth public boolean isSuccess() +meth public static com.fnproject.fn.api.OutputEvent emptyResult(int) +meth public static com.fnproject.fn.api.OutputEvent fromBytes(byte[],int,java.lang.String) +meth public static com.fnproject.fn.api.OutputEvent fromBytes(byte[],int,java.lang.String,com.fnproject.fn.api.Headers) + +CLSS public abstract interface com.fnproject.fn.api.QueryParameters +meth public abstract java.util.List getValues(java.lang.String) +meth public abstract java.util.Map> getAll() +meth public abstract java.util.Optional get(java.lang.String) + +CLSS public abstract interface com.fnproject.fn.api.RuntimeContext +meth public abstract <%0 extends java.lang.Object> java.util.Optional<{%%0}> getAttribute(java.lang.String,java.lang.Class<{%%0}>) +meth public abstract com.fnproject.fn.api.MethodWrapper getMethod() +meth public abstract java.util.List getInputCoercions(com.fnproject.fn.api.MethodWrapper,int) +meth public abstract java.util.List getOutputCoercions(java.lang.reflect.Method) +meth public abstract java.util.Map getConfiguration() +meth public abstract java.util.Optional getInvokeInstance() +meth public abstract java.util.Optional getConfigurationByKey(java.lang.String) +meth public abstract void addInputCoercion(com.fnproject.fn.api.InputCoercion) +meth public abstract void addOutputCoercion(com.fnproject.fn.api.OutputCoercion) +meth public abstract void setAttribute(java.lang.String,java.lang.Object) +meth public abstract void setInvoker(com.fnproject.fn.api.FunctionInvoker) + +CLSS public abstract interface com.fnproject.fn.api.TypeWrapper +meth public abstract java.lang.Class getParameterClass() + +CLSS public com.fnproject.fn.api.exception.FunctionConfigurationException +cons public init(java.lang.String) +cons public init(java.lang.String,java.lang.Throwable) +supr com.fnproject.fn.api.exception.FunctionLoadException + +CLSS public com.fnproject.fn.api.exception.FunctionInputHandlingException +cons public init(java.lang.String) +cons public init(java.lang.String,java.lang.Throwable) +supr java.lang.RuntimeException + +CLSS public abstract com.fnproject.fn.api.exception.FunctionLoadException +cons public init(java.lang.String) +cons public init(java.lang.String,java.lang.Throwable) +supr java.lang.RuntimeException + +CLSS public com.fnproject.fn.api.exception.FunctionOutputHandlingException +cons public init(java.lang.String) +cons public init(java.lang.String,java.lang.Exception) +supr java.lang.RuntimeException + +CLSS public abstract interface com.fnproject.fn.api.flow.Flow +innr public final static !enum FlowState +intf java.io.Serializable +meth public <%0 extends java.io.Serializable, %1 extends java.lang.Object> com.fnproject.fn.api.flow.FlowFuture<{%%0}> invokeFunction(java.lang.String,{%%1},java.lang.Class<{%%0}>) +meth public <%0 extends java.lang.Object> com.fnproject.fn.api.flow.FlowFuture invokeFunction(java.lang.String,{%%0}) +meth public abstract !varargs com.fnproject.fn.api.flow.FlowFuture anyOf(com.fnproject.fn.api.flow.FlowFuture[]) +meth public abstract !varargs com.fnproject.fn.api.flow.FlowFuture allOf(com.fnproject.fn.api.flow.FlowFuture[]) +meth public abstract <%0 extends java.io.Serializable, %1 extends java.lang.Object> com.fnproject.fn.api.flow.FlowFuture<{%%0}> invokeFunction(java.lang.String,com.fnproject.fn.api.flow.HttpMethod,com.fnproject.fn.api.Headers,{%%1},java.lang.Class<{%%0}>) +meth public abstract <%0 extends java.lang.Object> com.fnproject.fn.api.flow.FlowFuture invokeFunction(java.lang.String,com.fnproject.fn.api.flow.HttpMethod,com.fnproject.fn.api.Headers,{%%0}) +meth public abstract <%0 extends java.lang.Object> com.fnproject.fn.api.flow.FlowFuture<{%%0}> completedValue({%%0}) +meth public abstract <%0 extends java.lang.Object> com.fnproject.fn.api.flow.FlowFuture<{%%0}> createFlowFuture() +meth public abstract <%0 extends java.lang.Object> com.fnproject.fn.api.flow.FlowFuture<{%%0}> failedFuture(java.lang.Throwable) +meth public abstract <%0 extends java.lang.Object> com.fnproject.fn.api.flow.FlowFuture<{%%0}> supply(com.fnproject.fn.api.flow.Flows$SerCallable<{%%0}>) +meth public abstract com.fnproject.fn.api.flow.Flow addTerminationHook(com.fnproject.fn.api.flow.Flows$SerConsumer) +meth public abstract com.fnproject.fn.api.flow.FlowFuture invokeFunction(java.lang.String,com.fnproject.fn.api.flow.HttpMethod,com.fnproject.fn.api.Headers,byte[]) +meth public abstract com.fnproject.fn.api.flow.FlowFuture delay(long,java.util.concurrent.TimeUnit) +meth public abstract com.fnproject.fn.api.flow.FlowFuture supply(com.fnproject.fn.api.flow.Flows$SerRunnable) +meth public com.fnproject.fn.api.flow.FlowFuture invokeFunction(java.lang.String,com.fnproject.fn.api.flow.HttpMethod) +meth public com.fnproject.fn.api.flow.FlowFuture invokeFunction(java.lang.String,com.fnproject.fn.api.flow.HttpMethod,com.fnproject.fn.api.Headers) + +CLSS public final static !enum com.fnproject.fn.api.flow.Flow$FlowState + outer com.fnproject.fn.api.flow.Flow +fld public final static com.fnproject.fn.api.flow.Flow$FlowState CANCELLED +fld public final static com.fnproject.fn.api.flow.Flow$FlowState FAILED +fld public final static com.fnproject.fn.api.flow.Flow$FlowState KILLED +fld public final static com.fnproject.fn.api.flow.Flow$FlowState SUCCEEDED +fld public final static com.fnproject.fn.api.flow.Flow$FlowState UNKNOWN +meth public static com.fnproject.fn.api.flow.Flow$FlowState valueOf(java.lang.String) +meth public static com.fnproject.fn.api.flow.Flow$FlowState[] values() +supr java.lang.Enum + +CLSS public com.fnproject.fn.api.flow.FlowCompletionException +cons public init(java.lang.String) +cons public init(java.lang.String,java.lang.Throwable) +cons public init(java.lang.Throwable) +supr java.lang.RuntimeException + +CLSS public abstract interface com.fnproject.fn.api.flow.FlowFuture<%0 extends java.lang.Object> +intf java.io.Serializable +meth public abstract <%0 extends java.lang.Object, %1 extends java.lang.Object> com.fnproject.fn.api.flow.FlowFuture<{%%1}> thenCombine(com.fnproject.fn.api.flow.FlowFuture,com.fnproject.fn.api.flow.Flows$SerBiFunction) +meth public abstract <%0 extends java.lang.Object> com.fnproject.fn.api.flow.FlowFuture thenAcceptBoth(com.fnproject.fn.api.flow.FlowFuture<{%%0}>,com.fnproject.fn.api.flow.Flows$SerBiConsumer<{com.fnproject.fn.api.flow.FlowFuture%0},{%%0}>) +meth public abstract <%0 extends java.lang.Object> com.fnproject.fn.api.flow.FlowFuture<{%%0}> applyToEither(com.fnproject.fn.api.flow.FlowFuture,com.fnproject.fn.api.flow.Flows$SerFunction<{com.fnproject.fn.api.flow.FlowFuture%0},{%%0}>) +meth public abstract <%0 extends java.lang.Object> com.fnproject.fn.api.flow.FlowFuture<{%%0}> handle(com.fnproject.fn.api.flow.Flows$SerBiFunction) +meth public abstract <%0 extends java.lang.Object> com.fnproject.fn.api.flow.FlowFuture<{%%0}> thenApply(com.fnproject.fn.api.flow.Flows$SerFunction<{com.fnproject.fn.api.flow.FlowFuture%0},{%%0}>) +meth public abstract <%0 extends java.lang.Object> com.fnproject.fn.api.flow.FlowFuture<{%%0}> thenCompose(com.fnproject.fn.api.flow.Flows$SerFunction<{com.fnproject.fn.api.flow.FlowFuture%0},com.fnproject.fn.api.flow.FlowFuture<{%%0}>>) +meth public abstract boolean cancel() +meth public abstract boolean complete({com.fnproject.fn.api.flow.FlowFuture%0}) +meth public abstract boolean completeExceptionally(java.lang.Throwable) +meth public abstract com.fnproject.fn.api.flow.FlowFuture acceptEither(com.fnproject.fn.api.flow.FlowFuture,com.fnproject.fn.api.flow.Flows$SerConsumer<{com.fnproject.fn.api.flow.FlowFuture%0}>) +meth public abstract com.fnproject.fn.api.flow.FlowFuture thenAccept(com.fnproject.fn.api.flow.Flows$SerConsumer<{com.fnproject.fn.api.flow.FlowFuture%0}>) +meth public abstract com.fnproject.fn.api.flow.FlowFuture thenRun(com.fnproject.fn.api.flow.Flows$SerRunnable) +meth public abstract com.fnproject.fn.api.flow.FlowFuture<{com.fnproject.fn.api.flow.FlowFuture%0}> exceptionally(com.fnproject.fn.api.flow.Flows$SerFunction) +meth public abstract com.fnproject.fn.api.flow.FlowFuture<{com.fnproject.fn.api.flow.FlowFuture%0}> exceptionallyCompose(com.fnproject.fn.api.flow.Flows$SerFunction>) +meth public abstract com.fnproject.fn.api.flow.FlowFuture<{com.fnproject.fn.api.flow.FlowFuture%0}> whenComplete(com.fnproject.fn.api.flow.Flows$SerBiConsumer<{com.fnproject.fn.api.flow.FlowFuture%0},java.lang.Throwable>) +meth public abstract {com.fnproject.fn.api.flow.FlowFuture%0} get() +meth public abstract {com.fnproject.fn.api.flow.FlowFuture%0} get(long,java.util.concurrent.TimeUnit) throws java.util.concurrent.TimeoutException +meth public abstract {com.fnproject.fn.api.flow.FlowFuture%0} getNow({com.fnproject.fn.api.flow.FlowFuture%0}) + +CLSS public final com.fnproject.fn.api.flow.Flows +innr public abstract interface static FlowSource +innr public abstract interface static SerBiConsumer +innr public abstract interface static SerBiFunction +innr public abstract interface static SerCallable +innr public abstract interface static SerConsumer +innr public abstract interface static SerFunction +innr public abstract interface static SerRunnable +innr public abstract interface static SerSupplier +meth public static com.fnproject.fn.api.flow.Flow currentFlow() +meth public static com.fnproject.fn.api.flow.Flows$FlowSource getCurrentFlowSource() +meth public static void setCurrentFlowSource(com.fnproject.fn.api.flow.Flows$FlowSource) +supr java.lang.Object +hfds flowSource + +CLSS public abstract interface static com.fnproject.fn.api.flow.Flows$FlowSource + outer com.fnproject.fn.api.flow.Flows +meth public abstract com.fnproject.fn.api.flow.Flow currentFlow() + +CLSS public abstract interface static com.fnproject.fn.api.flow.Flows$SerBiConsumer<%0 extends java.lang.Object, %1 extends java.lang.Object> + outer com.fnproject.fn.api.flow.Flows + anno 0 java.lang.FunctionalInterface() +intf java.io.Serializable +intf java.util.function.BiConsumer<{com.fnproject.fn.api.flow.Flows$SerBiConsumer%0},{com.fnproject.fn.api.flow.Flows$SerBiConsumer%1}> + +CLSS public abstract interface static com.fnproject.fn.api.flow.Flows$SerBiFunction<%0 extends java.lang.Object, %1 extends java.lang.Object, %2 extends java.lang.Object> + outer com.fnproject.fn.api.flow.Flows + anno 0 java.lang.FunctionalInterface() +intf java.io.Serializable +intf java.util.function.BiFunction<{com.fnproject.fn.api.flow.Flows$SerBiFunction%0},{com.fnproject.fn.api.flow.Flows$SerBiFunction%1},{com.fnproject.fn.api.flow.Flows$SerBiFunction%2}> + +CLSS public abstract interface static com.fnproject.fn.api.flow.Flows$SerCallable<%0 extends java.lang.Object> + outer com.fnproject.fn.api.flow.Flows + anno 0 java.lang.FunctionalInterface() +intf java.io.Serializable +intf java.util.concurrent.Callable<{com.fnproject.fn.api.flow.Flows$SerCallable%0}> + +CLSS public abstract interface static com.fnproject.fn.api.flow.Flows$SerConsumer<%0 extends java.lang.Object> + outer com.fnproject.fn.api.flow.Flows + anno 0 java.lang.FunctionalInterface() +intf java.io.Serializable +intf java.util.function.Consumer<{com.fnproject.fn.api.flow.Flows$SerConsumer%0}> + +CLSS public abstract interface static com.fnproject.fn.api.flow.Flows$SerFunction<%0 extends java.lang.Object, %1 extends java.lang.Object> + outer com.fnproject.fn.api.flow.Flows + anno 0 java.lang.FunctionalInterface() +intf java.io.Serializable +intf java.util.function.Function<{com.fnproject.fn.api.flow.Flows$SerFunction%0},{com.fnproject.fn.api.flow.Flows$SerFunction%1}> + +CLSS public abstract interface static com.fnproject.fn.api.flow.Flows$SerRunnable + outer com.fnproject.fn.api.flow.Flows + anno 0 java.lang.FunctionalInterface() +intf java.io.Serializable +intf java.lang.Runnable + +CLSS public abstract interface static com.fnproject.fn.api.flow.Flows$SerSupplier<%0 extends java.lang.Object> + outer com.fnproject.fn.api.flow.Flows + anno 0 java.lang.FunctionalInterface() +intf java.io.Serializable +intf java.util.function.Supplier<{com.fnproject.fn.api.flow.Flows$SerSupplier%0}> + +CLSS public com.fnproject.fn.api.flow.FunctionInvocationException +cons public init(com.fnproject.fn.api.flow.HttpResponse) +meth public com.fnproject.fn.api.flow.HttpResponse getFunctionResponse() +supr java.lang.RuntimeException +hfds functionResponse + +CLSS public com.fnproject.fn.api.flow.FunctionInvokeFailedException +cons public init(java.lang.String) +supr com.fnproject.fn.api.flow.PlatformException + +CLSS public com.fnproject.fn.api.flow.FunctionTimeoutException +cons public init(java.lang.String) +supr com.fnproject.fn.api.flow.PlatformException + +CLSS public final !enum com.fnproject.fn.api.flow.HttpMethod +fld public final static com.fnproject.fn.api.flow.HttpMethod DELETE +fld public final static com.fnproject.fn.api.flow.HttpMethod GET +fld public final static com.fnproject.fn.api.flow.HttpMethod HEAD +fld public final static com.fnproject.fn.api.flow.HttpMethod OPTIONS +fld public final static com.fnproject.fn.api.flow.HttpMethod PATCH +fld public final static com.fnproject.fn.api.flow.HttpMethod POST +fld public final static com.fnproject.fn.api.flow.HttpMethod PUT +meth public java.lang.String toString() +meth public static com.fnproject.fn.api.flow.HttpMethod valueOf(java.lang.String) +meth public static com.fnproject.fn.api.flow.HttpMethod[] values() +supr java.lang.Enum +hfds verb + +CLSS public abstract interface com.fnproject.fn.api.flow.HttpRequest +meth public abstract byte[] getBodyAsBytes() +meth public abstract com.fnproject.fn.api.Headers getHeaders() +meth public abstract com.fnproject.fn.api.flow.HttpMethod getMethod() + +CLSS public abstract interface com.fnproject.fn.api.flow.HttpResponse +meth public abstract byte[] getBodyAsBytes() +meth public abstract com.fnproject.fn.api.Headers getHeaders() +meth public abstract int getStatusCode() + +CLSS public com.fnproject.fn.api.flow.InvalidStageResponseException +cons public init(java.lang.String) +supr com.fnproject.fn.api.flow.PlatformException + +CLSS public com.fnproject.fn.api.flow.LambdaSerializationException +cons public init(java.lang.String) +cons public init(java.lang.String,java.lang.Exception) +supr com.fnproject.fn.api.flow.FlowCompletionException + +CLSS public com.fnproject.fn.api.flow.PlatformException +cons public init(java.lang.String) +cons public init(java.lang.String,java.lang.Throwable) +cons public init(java.lang.Throwable) +meth public java.lang.Throwable fillInStackTrace() +supr com.fnproject.fn.api.flow.FlowCompletionException + +CLSS public com.fnproject.fn.api.flow.ResultSerializationException +cons public init(java.lang.String,java.lang.Throwable) +supr com.fnproject.fn.api.flow.FlowCompletionException + +CLSS public com.fnproject.fn.api.flow.StageInvokeFailedException +cons public init(java.lang.String) +supr com.fnproject.fn.api.flow.PlatformException + +CLSS public com.fnproject.fn.api.flow.StageLostException +cons public init(java.lang.String) +supr com.fnproject.fn.api.flow.PlatformException + +CLSS public com.fnproject.fn.api.flow.StageTimeoutException +cons public init(java.lang.String) +supr com.fnproject.fn.api.flow.PlatformException + +CLSS public final com.fnproject.fn.api.flow.WrappedFunctionException +cons public init(java.lang.Throwable) +intf java.io.Serializable +meth public java.lang.Class getOriginalExceptionType() +supr java.lang.RuntimeException +hfds originalExceptionType + +CLSS public abstract interface java.io.Closeable +intf java.lang.AutoCloseable +meth public abstract void close() throws java.io.IOException + +CLSS public abstract interface java.io.Serializable + +CLSS public abstract interface java.lang.AutoCloseable +meth public abstract void close() throws java.lang.Exception + +CLSS public abstract interface java.lang.Comparable<%0 extends java.lang.Object> +meth public abstract int compareTo({java.lang.Comparable%0}) + +CLSS public abstract java.lang.Enum<%0 extends java.lang.Enum<{java.lang.Enum%0}>> +cons protected init(java.lang.String,int) +intf java.io.Serializable +intf java.lang.Comparable<{java.lang.Enum%0}> +meth protected final java.lang.Object clone() throws java.lang.CloneNotSupportedException +meth protected final void finalize() +meth public final boolean equals(java.lang.Object) +meth public final int compareTo({java.lang.Enum%0}) +meth public final int hashCode() +meth public final int ordinal() +meth public final java.lang.Class<{java.lang.Enum%0}> getDeclaringClass() +meth public final java.lang.String name() +meth public java.lang.String toString() +meth public static <%0 extends java.lang.Enum<{%%0}>> {%%0} valueOf(java.lang.Class<{%%0}>,java.lang.String) +supr java.lang.Object +hfds name,ordinal + +CLSS public java.lang.Exception +cons protected init(java.lang.String,java.lang.Throwable,boolean,boolean) +cons public init() +cons public init(java.lang.String) +cons public init(java.lang.String,java.lang.Throwable) +cons public init(java.lang.Throwable) +supr java.lang.Throwable +hfds serialVersionUID + +CLSS public abstract interface !annotation java.lang.FunctionalInterface + anno 0 java.lang.annotation.Documented() + anno 0 java.lang.annotation.Retention(java.lang.annotation.RetentionPolicy value=RUNTIME) + anno 0 java.lang.annotation.Target(java.lang.annotation.ElementType[] value=[TYPE]) +intf java.lang.annotation.Annotation + +CLSS public java.lang.Object +cons public init() +meth protected java.lang.Object clone() throws java.lang.CloneNotSupportedException +meth protected void finalize() throws java.lang.Throwable +meth public boolean equals(java.lang.Object) +meth public final java.lang.Class getClass() +meth public final void notify() +meth public final void notifyAll() +meth public final void wait() throws java.lang.InterruptedException +meth public final void wait(long) throws java.lang.InterruptedException +meth public final void wait(long,int) throws java.lang.InterruptedException +meth public int hashCode() +meth public java.lang.String toString() + +CLSS public abstract interface java.lang.Runnable + anno 0 java.lang.FunctionalInterface() +meth public abstract void run() + +CLSS public java.lang.RuntimeException +cons protected init(java.lang.String,java.lang.Throwable,boolean,boolean) +cons public init() +cons public init(java.lang.String) +cons public init(java.lang.String,java.lang.Throwable) +cons public init(java.lang.Throwable) +supr java.lang.Exception +hfds serialVersionUID + +CLSS public java.lang.Throwable +cons protected init(java.lang.String,java.lang.Throwable,boolean,boolean) +cons public init() +cons public init(java.lang.String) +cons public init(java.lang.String,java.lang.Throwable) +cons public init(java.lang.Throwable) +intf java.io.Serializable +meth public final java.lang.Throwable[] getSuppressed() +meth public final void addSuppressed(java.lang.Throwable) +meth public java.lang.StackTraceElement[] getStackTrace() +meth public java.lang.String getLocalizedMessage() +meth public java.lang.String getMessage() +meth public java.lang.String toString() +meth public java.lang.Throwable fillInStackTrace() +meth public java.lang.Throwable getCause() +meth public java.lang.Throwable initCause(java.lang.Throwable) +meth public void printStackTrace() +meth public void printStackTrace(java.io.PrintStream) +meth public void printStackTrace(java.io.PrintWriter) +meth public void setStackTrace(java.lang.StackTraceElement[]) +supr java.lang.Object +hfds CAUSE_CAPTION,EMPTY_THROWABLE_ARRAY,NULL_CAUSE_MESSAGE,SELF_SUPPRESSION_MESSAGE,SUPPRESSED_CAPTION,SUPPRESSED_SENTINEL,UNASSIGNED_STACK,backtrace,cause,detailMessage,serialVersionUID,stackTrace,suppressedExceptions +hcls PrintStreamOrWriter,SentinelHolder,WrappedPrintStream,WrappedPrintWriter + +CLSS public abstract interface java.lang.annotation.Annotation +meth public abstract boolean equals(java.lang.Object) +meth public abstract int hashCode() +meth public abstract java.lang.Class annotationType() +meth public abstract java.lang.String toString() + +CLSS public abstract interface !annotation java.lang.annotation.Documented + anno 0 java.lang.annotation.Documented() + anno 0 java.lang.annotation.Retention(java.lang.annotation.RetentionPolicy value=RUNTIME) + anno 0 java.lang.annotation.Target(java.lang.annotation.ElementType[] value=[ANNOTATION_TYPE]) +intf java.lang.annotation.Annotation + +CLSS public abstract interface !annotation java.lang.annotation.Retention + anno 0 java.lang.annotation.Documented() + anno 0 java.lang.annotation.Retention(java.lang.annotation.RetentionPolicy value=RUNTIME) + anno 0 java.lang.annotation.Target(java.lang.annotation.ElementType[] value=[ANNOTATION_TYPE]) +intf java.lang.annotation.Annotation +meth public abstract java.lang.annotation.RetentionPolicy value() + +CLSS public abstract interface !annotation java.lang.annotation.Target + anno 0 java.lang.annotation.Documented() + anno 0 java.lang.annotation.Retention(java.lang.annotation.RetentionPolicy value=RUNTIME) + anno 0 java.lang.annotation.Target(java.lang.annotation.ElementType[] value=[ANNOTATION_TYPE]) +intf java.lang.annotation.Annotation +meth public abstract java.lang.annotation.ElementType[] value() + +CLSS public abstract interface java.util.EventListener + +CLSS public abstract interface java.util.concurrent.Callable<%0 extends java.lang.Object> + anno 0 java.lang.FunctionalInterface() +meth public abstract {java.util.concurrent.Callable%0} call() throws java.lang.Exception + +CLSS public abstract interface java.util.function.BiConsumer<%0 extends java.lang.Object, %1 extends java.lang.Object> + anno 0 java.lang.FunctionalInterface() +meth public abstract void accept({java.util.function.BiConsumer%0},{java.util.function.BiConsumer%1}) +meth public java.util.function.BiConsumer<{java.util.function.BiConsumer%0},{java.util.function.BiConsumer%1}> andThen(java.util.function.BiConsumer) + +CLSS public abstract interface java.util.function.BiFunction<%0 extends java.lang.Object, %1 extends java.lang.Object, %2 extends java.lang.Object> + anno 0 java.lang.FunctionalInterface() +meth public <%0 extends java.lang.Object> java.util.function.BiFunction<{java.util.function.BiFunction%0},{java.util.function.BiFunction%1},{%%0}> andThen(java.util.function.Function) +meth public abstract {java.util.function.BiFunction%2} apply({java.util.function.BiFunction%0},{java.util.function.BiFunction%1}) + +CLSS public abstract interface java.util.function.Consumer<%0 extends java.lang.Object> + anno 0 java.lang.FunctionalInterface() +meth public abstract void accept({java.util.function.Consumer%0}) +meth public java.util.function.Consumer<{java.util.function.Consumer%0}> andThen(java.util.function.Consumer) + +CLSS public abstract interface java.util.function.Function<%0 extends java.lang.Object, %1 extends java.lang.Object> + anno 0 java.lang.FunctionalInterface() +meth public <%0 extends java.lang.Object> java.util.function.Function<{%%0},{java.util.function.Function%1}> compose(java.util.function.Function) +meth public <%0 extends java.lang.Object> java.util.function.Function<{java.util.function.Function%0},{%%0}> andThen(java.util.function.Function) +meth public abstract {java.util.function.Function%1} apply({java.util.function.Function%0}) +meth public static <%0 extends java.lang.Object> java.util.function.Function<{%%0},{%%0}> identity() + +CLSS public abstract interface java.util.function.Supplier<%0 extends java.lang.Object> + anno 0 java.lang.FunctionalInterface() +meth public abstract {java.util.function.Supplier%0} get() + From 52ac503f0e3619d8974c4bba31dffa1aaccabe4f Mon Sep 17 00:00:00 2001 From: CI Date: Mon, 5 Mar 2018 23:50:58 +0000 Subject: [PATCH 013/310] fn-java-fdk: post-1.0.59 version bump [skip ci] --- release.version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/release.version b/release.version index c3ccccfa..4bf1778f 100644 --- a/release.version +++ b/release.version @@ -1 +1 @@ -1.0.59 +1.0.60 From 4ba4f265adfb3fd5e0756bc1d7f4a6ab1c5a7247 Mon Sep 17 00:00:00 2001 From: Owen Cliffe Date: Thu, 7 Jun 2018 11:07:44 +0100 Subject: [PATCH 014/310] Updating docs to reflect new CLI syntax (#138) * Updating docs to reflect new CLI syntax * Missed a few --- README.md | 2 +- docs/ExtendingDataBinding.md | 2 +- docs/FnFlowsUserGuide.md | 4 ++-- examples/async-thumbnails/README.md | 8 ++++---- examples/async-thumbnails/run.sh | 8 ++++---- examples/async-thumbnails/setup/setup.sh | 18 +++++++++--------- examples/qr-code/README.md | 4 ++-- examples/regex-query/README.md | 4 ++-- examples/string-reverse/README.md | 4 ++-- integration-tests/main/test-5/expected.sh | 6 +++--- integration-tests/main/test-6/expected.sh | 6 +++--- integration-tests/main/test-7/delete.sh | 2 +- integration-tests/run-all-tests.sh | 2 +- integration-tests/smoke-test.sh | 14 +++++++------- 14 files changed, 42 insertions(+), 42 deletions(-) diff --git a/README.md b/README.md index 81eb9874..7ee76718 100644 --- a/README.md +++ b/README.md @@ -195,7 +195,7 @@ $ fn start Then in your original terminal create an app: ```bash -$ fn apps create java-app +$ fn create app java-app Successfully created app: java-app ``` diff --git a/docs/ExtendingDataBinding.md b/docs/ExtendingDataBinding.md index bc8195c9..26a8a2d2 100644 --- a/docs/ExtendingDataBinding.md +++ b/docs/ExtendingDataBinding.md @@ -19,7 +19,7 @@ First of all, let's create a new function project. If you haven't done it alread ```shell $ fn start & -$ fn apps create java-app +$ fn create app java-app Successfully created app: java-app ``` diff --git a/docs/FnFlowsUserGuide.md b/docs/FnFlowsUserGuide.md index 91ed4ca4..9e9c5562 100644 --- a/docs/FnFlowsUserGuide.md +++ b/docs/FnFlowsUserGuide.md @@ -166,7 +166,7 @@ path: /primes Create your app and deploy your function: ``` -$ fn apps create flows-example +$ fn create app flows-example Successfully created app: flows-example $ fn deploy --app flows-example @@ -178,7 +178,7 @@ Configure your function to talk to the local flow service endpoint: ``` $ DOCKER_LOCALHOST=$(docker inspect --type container -f '{{.NetworkSettings.Gateway}}' functions) -$ fn apps config set flows-example COMPLETER_BASE_URL "http://$DOCKER_LOCALHOST:8081" +$ fn config app flows-example COMPLETER_BASE_URL "http://$DOCKER_LOCALHOST:8081" ``` ### Run your Flow function diff --git a/examples/async-thumbnails/README.md b/examples/async-thumbnails/README.md index 10616498..543a8651 100644 --- a/examples/async-thumbnails/README.md +++ b/examples/async-thumbnails/README.md @@ -54,7 +54,7 @@ $ fn build Create a route to host the function: ```bash -$ fn routes create myapp /async-thumbnails +$ fn create route myapp /async-thumbnails ``` Configure the app. In order to do this you must determine the IP address of the @@ -68,11 +68,11 @@ $ docker inspect --type container -f '{{range .NetworkSettings.Networks}}{{.IPAd and then use it as the storage host: ```bash -$ fn routes config set myapp /async-thumbnails OBJECT_STORAGE_URL http://172.17.0.4:9000 +$ fn config route myapp /async-thumbnails OBJECT_STORAGE_URL http://172.17.0.4:9000 myapp /async-thumbnails updated OBJECT_STORAGE_URL with http://172.17.0.4:9000 -$ fn routes config set myapp /async-thumbnails OBJECT_STORAGE_ACCESS alpha +$ fn config route myapp /async-thumbnails OBJECT_STORAGE_ACCESS alpha myapp /async-thumbnails updated OBJECT_STORAGE_ACCESS with alpha -$ fn routes config set myapp /async-thumbnails OBJECT_STORAGE_SECRET betabetabetabeta +$ fn config route myapp /async-thumbnails OBJECT_STORAGE_SECRET betabetabetabeta myapp /async-thumbnails updated OBJECT_STORAGE_SECRET with betabetabetabeta ``` diff --git a/examples/async-thumbnails/run.sh b/examples/async-thumbnails/run.sh index 76315c0f..d8576a57 100755 --- a/examples/async-thumbnails/run.sh +++ b/examples/async-thumbnails/run.sh @@ -2,12 +2,12 @@ fn build -fn routes create myapp /async-thumbnails +fn create route myapp /async-thumbnails STORAGE_SERVER_IP=`docker inspect --type container -f '{{range .NetworkSettings.Networks}}{{.IPAddress}}{{end}}' example-storage-server` -fn routes config set myapp /async-thumbnails OBJECT_STORAGE_URL http://${STORAGE_SERVER_IP}:9000 -fn routes config set myapp /async-thumbnails OBJECT_STORAGE_ACCESS alpha -fn routes config set myapp /async-thumbnails OBJECT_STORAGE_SECRET betabetabetabeta +fn config route myapp /async-thumbnails OBJECT_STORAGE_URL http://${STORAGE_SERVER_IP}:9000 +fn config route set myapp /async-thumbnails OBJECT_STORAGE_ACCESS alpha +fn config route set myapp /async-thumbnails OBJECT_STORAGE_SECRET betabetabetabeta curl -X POST --data-binary @test-image.png -H "Content-type: application/octet-stream" "http://localhost:8080/r/myapp/async-thumbnails" diff --git a/examples/async-thumbnails/setup/setup.sh b/examples/async-thumbnails/setup/setup.sh index 501c0e60..916a1dcf 100755 --- a/examples/async-thumbnails/setup/setup.sh +++ b/examples/async-thumbnails/setup/setup.sh @@ -82,14 +82,14 @@ fi COMPLETER_SERVER_IP=`docker inspect --type container -f '{{range .NetworkSettings.Networks}}{{.IPAddress}}{{end}}' flow-service` # Create app and routes -if [[ `fn apps list` == *"myapp"* ]]; then +if [[ `fn list apps` == *"myapp"* ]]; then echo "App myapp is already there." else - fn apps create myapp - fn apps config set myapp COMPLETER_BASE_URL http://10.167.103.193:8081 + fn create app myapp + fn config app myapp COMPLETER_BASE_URL http://10.167.103.193:8081 fi -if [[ `fn routes list myapp` == *"/resize128"* ]]; then +if [[ `fn list routes myapp` == *"/resize128"* ]]; then echo "Route /resize128 is already there." else # This works around proxy issues @@ -98,9 +98,9 @@ else --build-arg http_proxy=$http_proxy \ --build-arg https_proxy=$https_proxy \ . && \ - fn routes create myapp /resize128 + fn create route myapp /resize128 fi -if [[ `fn routes list myapp` == *"/resize256"* ]]; then +if [[ `fn list routes myapp` == *"/resize256"* ]]; then echo "Route /resize256 is already there." else # This works around proxy issues @@ -109,9 +109,9 @@ else --build-arg http_proxy=$http_proxy \ --build-arg https_proxy=$https_proxy \ . && \ - fn routes create myapp /resize256 + fn create route myapp /resize256 fi -if [[ `fn routes list myapp` == *"/resize512"* ]]; then +if [[ `fn list routes myapp` == *"/resize512"* ]]; then echo "Route /resize512 is already there." else # This works around proxy issues @@ -120,7 +120,7 @@ else --build-arg http_proxy=$http_proxy \ --build-arg https_proxy=$https_proxy \ . && \ - fn routes create myapp /resize512 + fn create route myapp /resize512 fi diff --git a/examples/qr-code/README.md b/examples/qr-code/README.md index d511c970..7cb3aaa1 100644 --- a/examples/qr-code/README.md +++ b/examples/qr-code/README.md @@ -31,8 +31,8 @@ $ fn build Create an app and route to host the function ```bash -$ fn apps create qr-app -$ fn routes create qr-app /qr +$ fn create app qr-app +$ fn create route qr-app /qr ``` Invoke the function to create a QR code diff --git a/examples/regex-query/README.md b/examples/regex-query/README.md index a9d67155..f7a21c6e 100644 --- a/examples/regex-query/README.md +++ b/examples/regex-query/README.md @@ -33,8 +33,8 @@ $ fn build Create an app and route to host the function ```bash -$ fn apps create regex-query -$ fn routes create regex-query /query +$ fn create app regex-query +$ fn create route regex-query /query ``` Invoke the function to perform a regex search diff --git a/examples/string-reverse/README.md b/examples/string-reverse/README.md index 9c52dae4..4ae5f707 100644 --- a/examples/string-reverse/README.md +++ b/examples/string-reverse/README.md @@ -31,8 +31,8 @@ $ fn build Create an app and route to host the function ```bash -$ fn apps create string-reverse-app -$ fn routes create string-reverse-app /reverse +$ fn create app string-reverse-app +$ fn create route string-reverse-app /reverse ``` Invoke the function to reverse a string diff --git a/integration-tests/main/test-5/expected.sh b/integration-tests/main/test-5/expected.sh index fd53afcd..432d3fb2 100755 --- a/integration-tests/main/test-5/expected.sh +++ b/integration-tests/main/test-5/expected.sh @@ -8,7 +8,7 @@ ATTEMPT=0 while [ ! -f "$FOUND_FILENAME" ] ; do sleep 1 - calls_found=`fn calls list "test-5" | grep "Status: success" | wc -l` + calls_found=`fn list calls "test-5" | grep "Status: success" | wc -l` echo "$calls_found successful function calls found" # TODO: Remove this check when `fn logs` becomes reliable @@ -17,11 +17,11 @@ do fi # TODO: Use this check instead when `fn logs` becomes reliable - # fn calls list "test-5" | while read k v + # fn list calls "test-5" | while read k v # do # if [[ "$k" = "ID:" ]]; then id="$v"; fi # if [[ -z "$k" ]]; then - # LOG=`fn logs get "test-5" "$id"` + # LOG=`fn get log "test-5" "$id"` # echo $LOG # if [[ $LOG == *"Ran the hook."* ]]; then # touch "$FOUND_FILENAME" diff --git a/integration-tests/main/test-6/expected.sh b/integration-tests/main/test-6/expected.sh index a7bc7275..0c45fa98 100755 --- a/integration-tests/main/test-6/expected.sh +++ b/integration-tests/main/test-6/expected.sh @@ -8,14 +8,14 @@ ATTEMPT=0 while [ ! -f "$FOUND_FILENAME" ] ; do sleep 1 - calls_found=`fn calls list "test-6" | grep "Status: success" | wc -l` + calls_found=`fn list calls "test-6" | grep "Status: success" | wc -l` echo "$calls_found successful function calls found" - fn calls list "test-6" | while read k v + fn list calls "test-6" | while read k v do if [[ "$k" = "ID:" ]]; then id="$v"; fi if [[ -z "$k" ]]; then - LOG=`fn logs get "test-6" "$id"` + LOG=`fn get log "test-6" "$id"` echo $LOG if [[ $LOG == *"Caught timeout"* ]]; then touch "$FOUND_FILENAME" diff --git a/integration-tests/main/test-7/delete.sh b/integration-tests/main/test-7/delete.sh index 75a939ed..5733a424 100644 --- a/integration-tests/main/test-7/delete.sh +++ b/integration-tests/main/test-7/delete.sh @@ -1,3 +1,3 @@ #!/bin/bash -ex -fn routes delete "$TESTNAME" /test-7 +fn delete route "$TESTNAME" /test-7 diff --git a/integration-tests/run-all-tests.sh b/integration-tests/run-all-tests.sh index 68a54511..edff3d5c 100755 --- a/integration-tests/run-all-tests.sh +++ b/integration-tests/run-all-tests.sh @@ -21,7 +21,7 @@ if [[ -z "${COMPLETER_BASE_URL+x}" ]]; then echo "Please set COMPLETER_BASE_URL" # ---------------------------------------------------------------------- printenv -fn apps list +fn list apps set +x diff --git a/integration-tests/smoke-test.sh b/integration-tests/smoke-test.sh index 234b5185..f0152f21 100755 --- a/integration-tests/smoke-test.sh +++ b/integration-tests/smoke-test.sh @@ -42,9 +42,9 @@ fn -v build --no-cache >build-output 2>&1 || { } if [ -f config ]; then - fn apps create "$TESTNAME" $(echo $(prefix_lines --config config)) + fn create app "$TESTNAME" $(echo $(prefix_lines --config config)) else - fn apps create "$TESTNAME" + fn create app "$TESTNAME" fi if [[ -x deploy.sh ]] @@ -56,8 +56,8 @@ fi [[ -n "$POST_CONFIGURE_HOOK" ]] && $POST_CONFIGURE_HOOK -fn apps inspect "$TESTNAME" -[[ -x route-create.sh ]] || fn routes inspect "$TESTNAME" "$TESTNAME" +fn inspect app "$TESTNAME" +[[ -x route-create.sh ]] || fn inspect route "$TESTNAME" "$TESTNAME" if [[ -x run-test.sh ]] then @@ -74,13 +74,13 @@ else fi set +x -fn calls list "$TESTNAME" | while read k v +fn list calls "$TESTNAME" | while read k v do echo "$k $v" if [[ "$k" = "ID:" ]]; then id="$v"; fi if [[ -z "$k" ]]; then echo '[[[' - fn logs get "$TESTNAME" "$id" + fn get log "$TESTNAME" "$id" echo ']]]' echo fi @@ -92,4 +92,4 @@ if [[ -x delete.sh ]] then ./delete.sh fi -fn apps delete "$TESTNAME" +fn delete app "$TESTNAME" From 22b574b7253588ecb2531bbdb6e0d3f6d0f26e81 Mon Sep 17 00:00:00 2001 From: CI Date: Thu, 7 Jun 2018 10:24:51 +0000 Subject: [PATCH 015/310] fn-java-fdk: post-1.0.60 version bump [skip ci] --- release.version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/release.version b/release.version index 4bf1778f..9972f124 100644 --- a/release.version +++ b/release.version @@ -1 +1 @@ -1.0.60 +1.0.61 From 7d8d534af6c6c2a149ed99c0cd8b7eae4b82d4b3 Mon Sep 17 00:00:00 2001 From: Owen Cliffe Date: Sun, 10 Jun 2018 13:06:58 +0100 Subject: [PATCH 016/310] remove printenv --- integration-tests/run-all-tests.sh | 1 - 1 file changed, 1 deletion(-) diff --git a/integration-tests/run-all-tests.sh b/integration-tests/run-all-tests.sh index edff3d5c..d39bf820 100755 --- a/integration-tests/run-all-tests.sh +++ b/integration-tests/run-all-tests.sh @@ -20,7 +20,6 @@ if [[ -z "${COMPLETER_BASE_URL+x}" ]]; then echo "Please set COMPLETER_BASE_URL" # Run each smoke-test in parallel # ---------------------------------------------------------------------- -printenv fn list apps set +x From 35c45e0616f4efece4b5662c149ec18a7087fbd5 Mon Sep 17 00:00:00 2001 From: Owen Cliffe Date: Sun, 10 Jun 2018 13:16:10 +0100 Subject: [PATCH 017/310] manual version bump --- release.version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/release.version b/release.version index 9972f124..7eeb2c76 100644 --- a/release.version +++ b/release.version @@ -1 +1 @@ -1.0.61 +1.0.62 From 8dc474267c759533cc338948c3c557f3ef93300a Mon Sep 17 00:00:00 2001 From: CI Date: Sun, 10 Jun 2018 12:26:23 +0000 Subject: [PATCH 018/310] fn-java-fdk: post-1.0.62 version bump [skip ci] --- release.version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/release.version b/release.version index 7eeb2c76..32c4ece7 100644 --- a/release.version +++ b/release.version @@ -1 +1 @@ -1.0.62 +1.0.63 From dc78855e11df9563eca92b141a54a6a034567d3d Mon Sep 17 00:00:00 2001 From: "A. PerCova" Date: Mon, 11 Jun 2018 18:20:42 -0500 Subject: [PATCH 019/310] Update FN container name (#139) [skip ci] Update FN container name from functions to fnserver at grabbing internal docker network IP --- docs/FnFlowsUserGuide.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/FnFlowsUserGuide.md b/docs/FnFlowsUserGuide.md index 9e9c5562..06204842 100644 --- a/docs/FnFlowsUserGuide.md +++ b/docs/FnFlowsUserGuide.md @@ -60,7 +60,7 @@ $ fn start Similarly, start the Flows server server and point it at the functions server API URL: ``` -$ DOCKER_LOCALHOST=$(docker inspect --type container -f '{{.NetworkSettings.Gateway}}' functions) +$ DOCKER_LOCALHOST=$(docker inspect --type container -f '{{.NetworkSettings.Gateway}}' fnserver) $ docker run --rm \ -p 8081:8081 \ From 5d6593583aeb91a8a8542b666d17cc8332f06e47 Mon Sep 17 00:00:00 2001 From: Matthew Gilliard Date: Tue, 3 Jul 2018 12:51:47 +0200 Subject: [PATCH 020/310] Updated dependency versions to reduce security problems (#143) Using snyk.io tools we found several dependencies had security vulnerabilities and could be updated. This does not remove all of them, but the remaining CVEs are in transitive dependencies brought in by 3rd party code. CVEs remain in: async-thumbnails example (low priority to fix) through - minio - wiremock fn-spring-cloud-function through - spring-cloud-function-context Additional changes were needed to adjust for API changes in updated dependencies: async-thumbnails example: - new minio client uses chunked file uploads so assertions needed changing fn-spring-cloud-function: - Several breaking API changes, and it seems now that Consumer behaviour is broken. --- examples/async-thumbnails/pom.xml | 4 ++-- .../fn/examples/ThumbnailsFunctionTest.java | 8 +++---- examples/regex-query/pom.xml | 2 +- fn-spring-cloud-function/pom.xml | 9 +++++++- .../function/SpringCloudFunctionInvoker.java | 2 +- .../function/SpringCloudFunctionLoader.java | 16 +++++++------- .../functions/SpringCloudConsumer.java | 2 +- .../functions/SpringCloudFunction.java | 2 +- .../function/functions/SpringCloudMethod.java | 2 +- .../functions/SpringCloudSupplier.java | 3 +-- .../function/SimpleFunctionInspector.java | 13 ++++++------ ...ngCloudFunctionInvokerIntegrationTest.java | 18 ++++++++++------ .../SpringCloudFunctionLoaderTest.java | 21 ++++++++++--------- .../function/testfns/EmptyFunctionConfig.java | 7 +------ .../function/testfns/FunctionConfig.java | 13 +++++++++--- pom.xml | 2 +- 16 files changed, 70 insertions(+), 54 deletions(-) diff --git a/examples/async-thumbnails/pom.xml b/examples/async-thumbnails/pom.xml index e554bee8..bc9ac761 100644 --- a/examples/async-thumbnails/pom.xml +++ b/examples/async-thumbnails/pom.xml @@ -28,7 +28,7 @@ io.minio minio - 3.0.5 + 3.0.12 com.fnproject.fn @@ -46,7 +46,7 @@ com.github.tomakehurst wiremock - 2.7.1 + 2.18.0 diff --git a/examples/async-thumbnails/src/test/java/com/fnproject/fn/examples/ThumbnailsFunctionTest.java b/examples/async-thumbnails/src/test/java/com/fnproject/fn/examples/ThumbnailsFunctionTest.java index 675ca691..b28e09e3 100644 --- a/examples/async-thumbnails/src/test/java/com/fnproject/fn/examples/ThumbnailsFunctionTest.java +++ b/examples/async-thumbnails/src/test/java/com/fnproject/fn/examples/ThumbnailsFunctionTest.java @@ -42,10 +42,10 @@ public void testThumbnail() { testing.thenRun(ThumbnailsFunction.class, "handleRequest"); // Check the final image uploads were performed - mockServer.verify(1, putRequestedFor(urlMatching("/alpha/.*\\.png")).withRequestBody(equalTo("testing"))); - mockServer.verify(1, putRequestedFor(urlMatching("/alpha/.*\\.png")).withRequestBody(equalTo("128"))); - mockServer.verify(1, putRequestedFor(urlMatching("/alpha/.*\\.png")).withRequestBody(equalTo("256"))); - mockServer.verify(1, putRequestedFor(urlMatching("/alpha/.*\\.png")).withRequestBody(equalTo("512"))); + mockServer.verify(putRequestedFor(urlMatching("/alpha/.*\\.png")).withRequestBody(containing("testing"))); + mockServer.verify(putRequestedFor(urlMatching("/alpha/.*\\.png")).withRequestBody(containing("128"))); + mockServer.verify(putRequestedFor(urlMatching("/alpha/.*\\.png")).withRequestBody(containing("256"))); + mockServer.verify(putRequestedFor(urlMatching("/alpha/.*\\.png")).withRequestBody(containing("512"))); mockServer.verify(4, putRequestedFor(urlMatching(".*"))); } diff --git a/examples/regex-query/pom.xml b/examples/regex-query/pom.xml index 23961362..78ad1d1f 100644 --- a/examples/regex-query/pom.xml +++ b/examples/regex-query/pom.xml @@ -7,7 +7,7 @@ UTF-8 1.0.0-SNAPSHOT - 2.8.9 + 2.9.6 com.fnproject.fn.examples diff --git a/fn-spring-cloud-function/pom.xml b/fn-spring-cloud-function/pom.xml index 97130c81..1fcb852a 100644 --- a/fn-spring-cloud-function/pom.xml +++ b/fn-spring-cloud-function/pom.xml @@ -13,7 +13,7 @@ UTF-8 - 1.0.0.M1 + 1.0.0.M6 @@ -70,6 +70,13 @@ test + + commons-logging + commons-logging + 1.1.1 + test + + com.github.stefanbirkner system-rules diff --git a/fn-spring-cloud-function/src/main/java/com/fnproject/springframework/function/SpringCloudFunctionInvoker.java b/fn-spring-cloud-function/src/main/java/com/fnproject/springframework/function/SpringCloudFunctionInvoker.java index bca11b33..4f850dcf 100644 --- a/fn-spring-cloud-function/src/main/java/com/fnproject/springframework/function/SpringCloudFunctionInvoker.java +++ b/fn-spring-cloud-function/src/main/java/com/fnproject/springframework/function/SpringCloudFunctionInvoker.java @@ -145,7 +145,7 @@ private Flux convertToFlux(Object[] params) { } @Override - public void close() throws IOException { + public void close() { applicationContext.close(); } } diff --git a/fn-spring-cloud-function/src/main/java/com/fnproject/springframework/function/SpringCloudFunctionLoader.java b/fn-spring-cloud-function/src/main/java/com/fnproject/springframework/function/SpringCloudFunctionLoader.java index 5090a595..e6a2209c 100644 --- a/fn-spring-cloud-function/src/main/java/com/fnproject/springframework/function/SpringCloudFunctionLoader.java +++ b/fn-spring-cloud-function/src/main/java/com/fnproject/springframework/function/SpringCloudFunctionLoader.java @@ -6,8 +6,8 @@ import com.fnproject.springframework.function.functions.SpringCloudMethod; import com.fnproject.springframework.function.functions.SpringCloudSupplier; import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.cloud.function.context.FunctionInspector; -import org.springframework.cloud.function.core.FunctionCatalog; +import org.springframework.cloud.function.context.FunctionCatalog; +import org.springframework.cloud.function.context.catalog.FunctionInspector; import reactor.core.publisher.Flux; import java.util.function.Consumer; @@ -67,24 +67,24 @@ void loadFunction() { private void loadSpringCloudFunctionFromEnvVars() { String functionName = System.getenv(ENV_VAR_FUNCTION_NAME); if (functionName != null) { - function = this.catalog.lookupFunction(functionName); + function = this.catalog.lookup(Function.class, functionName); } String consumerName = System.getenv(ENV_VAR_CONSUMER_NAME); if (consumerName != null) { - consumer = this.catalog.lookupConsumer(consumerName); + consumer = this.catalog.lookup(Consumer.class, consumerName); } String supplierName = System.getenv(ENV_VAR_SUPPLIER_NAME); if (supplierName != null) { - supplier = this.catalog.lookupSupplier(supplierName); + supplier = this.catalog.lookup(Supplier.class, supplierName); } } private void loadSpringCloudFunctionFromDefaults() { - function = this.catalog.lookupFunction(DEFAULT_FUNCTION_BEAN); - consumer = this.catalog.lookupConsumer(DEFAULT_CONSUMER_BEAN); - supplier = this.catalog.lookupSupplier(DEFAULT_SUPPLIER_BEAN); + function = this.catalog.lookup(Function.class, DEFAULT_FUNCTION_BEAN); + consumer = this.catalog.lookup(Consumer.class, DEFAULT_CONSUMER_BEAN); + supplier = this.catalog.lookup(Supplier.class, DEFAULT_SUPPLIER_BEAN); } diff --git a/fn-spring-cloud-function/src/main/java/com/fnproject/springframework/function/functions/SpringCloudConsumer.java b/fn-spring-cloud-function/src/main/java/com/fnproject/springframework/function/functions/SpringCloudConsumer.java index bc702a16..720f58ae 100644 --- a/fn-spring-cloud-function/src/main/java/com/fnproject/springframework/function/functions/SpringCloudConsumer.java +++ b/fn-spring-cloud-function/src/main/java/com/fnproject/springframework/function/functions/SpringCloudConsumer.java @@ -2,7 +2,7 @@ import com.fnproject.fn.api.TypeWrapper; import com.fnproject.springframework.function.SimpleTypeWrapper; -import org.springframework.cloud.function.context.FunctionInspector; +import org.springframework.cloud.function.context.catalog.FunctionInspector; import reactor.core.publisher.Flux; import java.util.function.Consumer; diff --git a/fn-spring-cloud-function/src/main/java/com/fnproject/springframework/function/functions/SpringCloudFunction.java b/fn-spring-cloud-function/src/main/java/com/fnproject/springframework/function/functions/SpringCloudFunction.java index e7cc1bd5..8d1592a4 100644 --- a/fn-spring-cloud-function/src/main/java/com/fnproject/springframework/function/functions/SpringCloudFunction.java +++ b/fn-spring-cloud-function/src/main/java/com/fnproject/springframework/function/functions/SpringCloudFunction.java @@ -1,6 +1,6 @@ package com.fnproject.springframework.function.functions; -import org.springframework.cloud.function.context.FunctionInspector; +import org.springframework.cloud.function.context.catalog.FunctionInspector; import reactor.core.publisher.Flux; import java.util.function.Consumer; diff --git a/fn-spring-cloud-function/src/main/java/com/fnproject/springframework/function/functions/SpringCloudMethod.java b/fn-spring-cloud-function/src/main/java/com/fnproject/springframework/function/functions/SpringCloudMethod.java index 77f8bb08..e2daffcc 100644 --- a/fn-spring-cloud-function/src/main/java/com/fnproject/springframework/function/functions/SpringCloudMethod.java +++ b/fn-spring-cloud-function/src/main/java/com/fnproject/springframework/function/functions/SpringCloudMethod.java @@ -3,7 +3,7 @@ import com.fnproject.fn.api.MethodWrapper; import com.fnproject.fn.api.TypeWrapper; import com.fnproject.springframework.function.SimpleTypeWrapper; -import org.springframework.cloud.function.context.FunctionInspector; +import org.springframework.cloud.function.context.catalog.FunctionInspector; import reactor.core.publisher.Flux; import java.lang.reflect.Method; diff --git a/fn-spring-cloud-function/src/main/java/com/fnproject/springframework/function/functions/SpringCloudSupplier.java b/fn-spring-cloud-function/src/main/java/com/fnproject/springframework/function/functions/SpringCloudSupplier.java index 182d708b..52554b44 100644 --- a/fn-spring-cloud-function/src/main/java/com/fnproject/springframework/function/functions/SpringCloudSupplier.java +++ b/fn-spring-cloud-function/src/main/java/com/fnproject/springframework/function/functions/SpringCloudSupplier.java @@ -2,10 +2,9 @@ import com.fnproject.fn.api.TypeWrapper; import com.fnproject.springframework.function.SimpleTypeWrapper; -import org.springframework.cloud.function.context.FunctionInspector; +import org.springframework.cloud.function.context.catalog.FunctionInspector; import reactor.core.publisher.Flux; -import java.util.function.Consumer; import java.util.function.Supplier; /** diff --git a/fn-spring-cloud-function/src/test/java/com/fnproject/springframework/function/SimpleFunctionInspector.java b/fn-spring-cloud-function/src/test/java/com/fnproject/springframework/function/SimpleFunctionInspector.java index 22e301e9..9e52b6f1 100644 --- a/fn-spring-cloud-function/src/test/java/com/fnproject/springframework/function/SimpleFunctionInspector.java +++ b/fn-spring-cloud-function/src/test/java/com/fnproject/springframework/function/SimpleFunctionInspector.java @@ -1,13 +1,19 @@ package com.fnproject.springframework.function; import net.jodah.typetools.TypeResolver; -import org.springframework.cloud.function.context.FunctionInspector; +import org.springframework.cloud.function.context.FunctionRegistration; +import org.springframework.cloud.function.context.catalog.FunctionInspector; import java.util.function.Consumer; import java.util.function.Function; import java.util.function.Supplier; public class SimpleFunctionInspector implements FunctionInspector { + @Override + public FunctionRegistration getRegistration(Object function) { + return null; + } + @Override public boolean isMessage(Object function) { throw new IllegalStateException("Not implemented"); @@ -53,11 +59,6 @@ public Class getOutputWrapper(Object function) { throw new IllegalStateException("Not implemented"); } - @Override - public Object convert(Object function, String value) { - throw new IllegalStateException("Not implemented"); - } - @Override public String getName(Object function) { return function.toString(); diff --git a/fn-spring-cloud-function/src/test/java/com/fnproject/springframework/function/SpringCloudFunctionInvokerIntegrationTest.java b/fn-spring-cloud-function/src/test/java/com/fnproject/springframework/function/SpringCloudFunctionInvokerIntegrationTest.java index 131e77ef..29b82965 100644 --- a/fn-spring-cloud-function/src/test/java/com/fnproject/springframework/function/SpringCloudFunctionInvokerIntegrationTest.java +++ b/fn-spring-cloud-function/src/test/java/com/fnproject/springframework/function/SpringCloudFunctionInvokerIntegrationTest.java @@ -3,6 +3,7 @@ import com.fnproject.fn.testing.FnTestingRule; import com.fnproject.springframework.function.testfns.EmptyFunctionConfig; import com.fnproject.springframework.function.testfns.FunctionConfig; +import org.junit.Ignore; import org.junit.Rule; import org.junit.Test; import org.junit.contrib.java.lang.system.EnvironmentVariables; @@ -21,7 +22,7 @@ public class SpringCloudFunctionInvokerIntegrationTest { public final EnvironmentVariables environmentVariables = new EnvironmentVariables(); @Test - public void shouldInvokeFunction() throws IOException { + public void shouldInvokeFunction() { fnRule.givenEvent().withBody("HELLO").enqueue(); fnRule.thenRun(FunctionConfig.class, "handleRequest"); @@ -30,18 +31,23 @@ public void shouldInvokeFunction() throws IOException { } @Test - public void shouldInvokeConsumer() throws IOException { + @Ignore("Consumer behaviour seems broken in this release of Spring Cloud Function") + // NB the problem is that FluxConsumer is not a subclass of j.u.f.Consumer, but _is_ + // a subclass of j.u.f.Function. + // Effectively a Consumer is treated as a Function which means when we lookup + // by env var name "consumer", we don't find a j.u.f.Consumer, so we fall back to the default + // behaviour which is to invoke the bean named "function" + public void shouldInvokeConsumer() { environmentVariables.set(SpringCloudFunctionLoader.ENV_VAR_CONSUMER_NAME, "consumer"); - String consumerInput = "consumer input"; - fnRule.givenEvent().withBody(consumerInput).enqueue(); + fnRule.givenEvent().withBody("consumer input").enqueue(); fnRule.thenRun(FunctionConfig.class, "handleRequest"); - assertThat(fnRule.getStdErrAsString()).contains(consumerInput); + assertThat(fnRule.getStdErrAsString()).contains("consumer input"); } @Test - public void shouldInvokeSupplier() throws IOException { + public void shouldInvokeSupplier() { environmentVariables.set(SpringCloudFunctionLoader.ENV_VAR_SUPPLIER_NAME, "supplier"); fnRule.givenEvent().enqueue(); diff --git a/fn-spring-cloud-function/src/test/java/com/fnproject/springframework/function/SpringCloudFunctionLoaderTest.java b/fn-spring-cloud-function/src/test/java/com/fnproject/springframework/function/SpringCloudFunctionLoaderTest.java index 9ce1049c..6e2bbf02 100644 --- a/fn-spring-cloud-function/src/test/java/com/fnproject/springframework/function/SpringCloudFunctionLoaderTest.java +++ b/fn-spring-cloud-function/src/test/java/com/fnproject/springframework/function/SpringCloudFunctionLoaderTest.java @@ -8,7 +8,7 @@ import org.junit.runner.RunWith; import org.mockito.Mock; import org.mockito.junit.MockitoJUnitRunner; -import org.springframework.cloud.function.core.FunctionCatalog; +import org.springframework.cloud.function.context.catalog.InMemoryFunctionCatalog; import java.util.function.Consumer; import java.util.function.Function; @@ -24,8 +24,9 @@ public class SpringCloudFunctionLoaderTest { public final EnvironmentVariables environmentVariables = new EnvironmentVariables(); private SpringCloudFunctionLoader loader; + @Mock - private FunctionCatalog catalog; + private InMemoryFunctionCatalog catalog; @Before public void setUp() { @@ -34,9 +35,7 @@ public void setUp() { } private void setUpCatalogToReturnNullForLookupByDefault() { - when(catalog.lookupFunction(any())).thenReturn(null); - when(catalog.lookupConsumer(any())).thenReturn(null); - when(catalog.lookupSupplier(any())).thenReturn(null); + when(catalog.lookup(any(), any())).thenReturn(null); } @Test @@ -49,7 +48,8 @@ public void shouldLoadFunctionBeanCalledFunction() { @Test public void shouldLoadConsumerBeanCalledConsumerIfFunctionNotAvailable() { - Consumer consumer = (x) -> {}; + Consumer consumer = (x) -> { + }; stubCatalogToReturnConsumer(consumer); assertThat(getDiscoveredFunction().getTargetClass()).isEqualTo(consumer.getClass()); @@ -80,7 +80,8 @@ public void shouldLoadUserSpecifiedSupplierInEnvVarOverDefaultFunction() { @Test public void shouldLoadUserSpecifiedConsumerInEnvVarOverDefaultFunction() { String beanName = "myConsumer"; - Consumer consumer = (x) -> {}; + Consumer consumer = (x) -> { + }; Function function = (x) -> x; setConsumerEnvVar(beanName); @@ -104,15 +105,15 @@ public void shouldLoadUserSpecifiedFunctionInEnvVarOverDefaultFunction() { } private void stubCatalogToReturnFunction(String beanName, Function function) { - when(catalog.lookupFunction(beanName)).thenReturn(function); + when(catalog.lookup(Function.class, beanName)).thenReturn(function); } private void stubCatalogToReturnConsumer(String beanName, Consumer consumer) { - when(catalog.lookupConsumer(beanName)).thenReturn(consumer); + when(catalog.lookup(Consumer.class, beanName)).thenReturn(consumer); } private void stubCatalogToReturnSupplier(String beanName, Supplier supplier) { - when(catalog.lookupSupplier(beanName)).thenReturn(supplier); + when(catalog.lookup(Supplier.class, beanName)).thenReturn(supplier); } private void stubCatalogToReturnSupplier(Supplier supplier) { diff --git a/fn-spring-cloud-function/src/test/java/com/fnproject/springframework/function/testfns/EmptyFunctionConfig.java b/fn-spring-cloud-function/src/test/java/com/fnproject/springframework/function/testfns/EmptyFunctionConfig.java index a6444bc2..8ac2c7ff 100644 --- a/fn-spring-cloud-function/src/test/java/com/fnproject/springframework/function/testfns/EmptyFunctionConfig.java +++ b/fn-spring-cloud-function/src/test/java/com/fnproject/springframework/function/testfns/EmptyFunctionConfig.java @@ -3,15 +3,10 @@ import com.fnproject.fn.api.FnConfiguration; import com.fnproject.fn.api.RuntimeContext; import com.fnproject.springframework.function.SpringCloudFunctionInvoker; -import org.springframework.cloud.function.context.ContextFunctionCatalogAutoConfiguration; -import org.springframework.context.annotation.Bean; +import org.springframework.cloud.function.context.config.ContextFunctionCatalogAutoConfiguration; import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.Import; -import java.util.function.Consumer; -import java.util.function.Function; -import java.util.function.Supplier; - @Configuration @Import(ContextFunctionCatalogAutoConfiguration.class) public class EmptyFunctionConfig { diff --git a/fn-spring-cloud-function/src/test/java/com/fnproject/springframework/function/testfns/FunctionConfig.java b/fn-spring-cloud-function/src/test/java/com/fnproject/springframework/function/testfns/FunctionConfig.java index c5d4d21a..46646665 100644 --- a/fn-spring-cloud-function/src/test/java/com/fnproject/springframework/function/testfns/FunctionConfig.java +++ b/fn-spring-cloud-function/src/test/java/com/fnproject/springframework/function/testfns/FunctionConfig.java @@ -3,7 +3,7 @@ import com.fnproject.fn.api.FnConfiguration; import com.fnproject.fn.api.RuntimeContext; import com.fnproject.springframework.function.SpringCloudFunctionInvoker; -import org.springframework.cloud.function.context.ContextFunctionCatalogAutoConfiguration; +import org.springframework.cloud.function.context.config.ContextFunctionCatalogAutoConfiguration; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.Import; @@ -15,11 +15,14 @@ @Configuration @Import(ContextFunctionCatalogAutoConfiguration.class) public class FunctionConfig { + @FnConfiguration public static void configure(RuntimeContext ctx) { ctx.setInvoker(new SpringCloudFunctionInvoker(FunctionConfig.class)); } - public void handleRequest() { } + + public void handleRequest() { + } @Bean public Supplier supplier() { @@ -28,6 +31,7 @@ public Supplier supplier() { @Bean public Consumer consumer() { + System.out.println("LOADED"); return System.out::println; } @@ -35,13 +39,16 @@ public Consumer consumer() { public Function function() { return String::toLowerCase; } + @Bean public Function upperCaseFunction() { return String::toUpperCase; } @Bean - public String notAFunction() { return "NotAFunction"; } + public String notAFunction() { + return "NotAFunction"; + } // Empty entrypoint that isn't used but necessary for the EntryPoint. Our invoker ignores this and loads our own // function to invoke diff --git a/pom.xml b/pom.xml index 837a23bc..486db5a1 100644 --- a/pom.xml +++ b/pom.xml @@ -22,7 +22,7 @@ 0.7.9 1.7.25 2.5 - 2.8.7 + 2.9.6 2.8.47 3.6.2 4.4.6 From 481ed02788670b0650d24e58737c37984df482f5 Mon Sep 17 00:00:00 2001 From: CI Date: Tue, 3 Jul 2018 11:01:54 +0000 Subject: [PATCH 021/310] fn-java-fdk: post-1.0.63 version bump [skip ci] --- release.version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/release.version b/release.version index 32c4ece7..e1d2f8b7 100644 --- a/release.version +++ b/release.version @@ -1 +1 @@ -1.0.63 +1.0.64 From f6fc0917778d1eaa669a7d44f8c97b32d2dcd0f0 Mon Sep 17 00:00:00 2001 From: Sven Ruppert Date: Mon, 23 Jul 2018 15:02:17 +0200 Subject: [PATCH 022/310] preparations for the junit5 module - separation of the junit4 and junit5 code into different modules. - core module to share code between different TDD frameworks --- _archive/pom.xml | 19 +++ _archive/testing-junit4/pom.xml | 15 +++ build_in_docker.sh | 2 + examples/async-thumbnails/pom.xml | 8 +- examples/regex-query/pom.xml | 8 +- fn-spring-cloud-function/pom.xml | 8 +- pom.xml | 2 + testing-core/pom.xml | 36 ++++++ .../fnproject/fn/testing/FnEventBuilder.java | 26 ++-- .../fn/testing/FnFunctionStubBuilder.java | 10 +- .../fn/testing/FnHttpEventBuilder.java | 0 .../com/fnproject/fn/testing/FnResult.java | 0 .../fn/testing/FnTestingClassLoader.java | 0 .../fnproject/fn/testing/FunctionError.java | 0 .../fnproject/fn/testing/HeaderWriter.java | 0 .../fnproject/fn/testing/InMemCompleter.java | 0 .../fnproject/fn/testing/PlatformError.java | 0 .../fnproject/fn/testing/ResultException.java | 0 testing-junit4/pom.xml | 41 ++++++ .../fn/testing/FnEventBuilderJUnit4.java | 5 + .../testing/FnFunctionStubBuilderJUnit4.java | 9 ++ .../fnproject/fn/testing/FnTestingRule.java | 8 +- .../fn/testing/ExerciseEverything.java | 3 +- .../fn/testing/FnTestingRuleFlowsTest.java | 121 +++++++++--------- .../fn/testing/FnTestingRuleTest.java | 111 ++++++++-------- .../fnproject/fn/testing/IntegrationTest.java | 9 +- .../fn/testing/MultipleEventsTest.java | 6 +- .../fn/testing/WhenCompleteTest.java | 6 +- testing/pom.xml | 10 ++ 29 files changed, 316 insertions(+), 147 deletions(-) create mode 100644 _archive/pom.xml create mode 100644 _archive/testing-junit4/pom.xml create mode 100644 build_in_docker.sh create mode 100644 testing-core/pom.xml rename {testing => testing-core}/src/main/java/com/fnproject/fn/testing/FnEventBuilder.java (79%) rename {testing => testing-core}/src/main/java/com/fnproject/fn/testing/FnFunctionStubBuilder.java (92%) rename {testing => testing-core}/src/main/java/com/fnproject/fn/testing/FnHttpEventBuilder.java (100%) rename {testing => testing-core}/src/main/java/com/fnproject/fn/testing/FnResult.java (100%) rename {testing => testing-core}/src/main/java/com/fnproject/fn/testing/FnTestingClassLoader.java (100%) rename {testing => testing-core}/src/main/java/com/fnproject/fn/testing/FunctionError.java (100%) rename {testing => testing-core}/src/main/java/com/fnproject/fn/testing/HeaderWriter.java (100%) rename {testing => testing-core}/src/main/java/com/fnproject/fn/testing/InMemCompleter.java (100%) rename {testing => testing-core}/src/main/java/com/fnproject/fn/testing/PlatformError.java (100%) rename {testing => testing-core}/src/main/java/com/fnproject/fn/testing/ResultException.java (100%) create mode 100644 testing-junit4/pom.xml create mode 100644 testing-junit4/src/main/java/com/fnproject/fn/testing/FnEventBuilderJUnit4.java create mode 100644 testing-junit4/src/main/java/com/fnproject/fn/testing/FnFunctionStubBuilderJUnit4.java rename {testing => testing-junit4}/src/main/java/com/fnproject/fn/testing/FnTestingRule.java (99%) rename {testing/src/test/java => testing-junit4/src/test/java/junit}/com/fnproject/fn/testing/ExerciseEverything.java (99%) rename {testing/src/test/java => testing-junit4/src/test/java/junit}/com/fnproject/fn/testing/FnTestingRuleFlowsTest.java (79%) rename {testing/src/test/java => testing-junit4/src/test/java/junit}/com/fnproject/fn/testing/FnTestingRuleTest.java (68%) rename {testing/src/test/java => testing-junit4/src/test/java/junit}/com/fnproject/fn/testing/IntegrationTest.java (75%) rename {testing/src/test/java => testing-junit4/src/test/java/junit}/com/fnproject/fn/testing/MultipleEventsTest.java (95%) rename {testing/src/test/java => testing-junit4/src/test/java/junit}/com/fnproject/fn/testing/WhenCompleteTest.java (83%) diff --git a/_archive/pom.xml b/_archive/pom.xml new file mode 100644 index 00000000..bb07b648 --- /dev/null +++ b/_archive/pom.xml @@ -0,0 +1,19 @@ + + + + fdk + com.fnproject.fn + 1.0.0-SNAPSHOT + + 4.0.0 + + _archive + pom + + testing-junit4 + + + + \ No newline at end of file diff --git a/_archive/testing-junit4/pom.xml b/_archive/testing-junit4/pom.xml new file mode 100644 index 00000000..ebdae363 --- /dev/null +++ b/_archive/testing-junit4/pom.xml @@ -0,0 +1,15 @@ + + + + _archive + com.fnproject.fn + 1.0.0-SNAPSHOT + + 4.0.0 + + _archive-testing-junit4 + + + \ No newline at end of file diff --git a/build_in_docker.sh b/build_in_docker.sh new file mode 100644 index 00000000..c9f5aee9 --- /dev/null +++ b/build_in_docker.sh @@ -0,0 +1,2 @@ +#!/usr/bin/env bash +docker run --rm --name compile -v "$(pwd)":/usr/src/mymaven -w /usr/src/mymaven svenruppert/maven-3.5-jdk-08 mvn clean install diff --git a/examples/async-thumbnails/pom.xml b/examples/async-thumbnails/pom.xml index e554bee8..2eb23031 100644 --- a/examples/async-thumbnails/pom.xml +++ b/examples/async-thumbnails/pom.xml @@ -32,7 +32,13 @@ com.fnproject.fn - testing + testing-core + ${fnproject.version} + test + + + com.fnproject.fn + testing-junit4 ${fnproject.version} test diff --git a/examples/regex-query/pom.xml b/examples/regex-query/pom.xml index 23961362..46dc034f 100644 --- a/examples/regex-query/pom.xml +++ b/examples/regex-query/pom.xml @@ -33,7 +33,13 @@ com.fnproject.fn - testing + testing-core + ${fnproject.version} + test + + + com.fnproject.fn + testing-junit4 ${fnproject.version} test diff --git a/fn-spring-cloud-function/pom.xml b/fn-spring-cloud-function/pom.xml index 97130c81..5d59e718 100644 --- a/fn-spring-cloud-function/pom.xml +++ b/fn-spring-cloud-function/pom.xml @@ -44,7 +44,13 @@ com.fnproject.fn - testing + testing-core + ${project.version} + test + + + com.fnproject.fn + testing-junit4 ${project.version} test diff --git a/pom.xml b/pom.xml index 837a23bc..eb1cd0d5 100644 --- a/pom.xml +++ b/pom.xml @@ -12,6 +12,8 @@ api runtime fn-spring-cloud-function + testing-core + testing-junit4 testing examples integration-tests diff --git a/testing-core/pom.xml b/testing-core/pom.xml new file mode 100644 index 00000000..3ad3aac8 --- /dev/null +++ b/testing-core/pom.xml @@ -0,0 +1,36 @@ + + + + fdk + com.fnproject.fn + 1.0.0-SNAPSHOT + + 4.0.0 + + testing-core + + + + + + com.fnproject.fn + runtime + ${project.version} + + + junit + junit + ${junit.version} + + + org.assertj + assertj-core + ${assertj-core.version} + test + + + + + \ No newline at end of file diff --git a/testing/src/main/java/com/fnproject/fn/testing/FnEventBuilder.java b/testing-core/src/main/java/com/fnproject/fn/testing/FnEventBuilder.java similarity index 79% rename from testing/src/main/java/com/fnproject/fn/testing/FnEventBuilder.java rename to testing-core/src/main/java/com/fnproject/fn/testing/FnEventBuilder.java index 1dce2476..fe5809df 100644 --- a/testing/src/main/java/com/fnproject/fn/testing/FnEventBuilder.java +++ b/testing-core/src/main/java/com/fnproject/fn/testing/FnEventBuilder.java @@ -5,7 +5,7 @@ /** * Builder for function input events */ -public interface FnEventBuilder { +public interface FnEventBuilder { /** * Add a header to the input with a variable number of values; duplicate headers will be overwritten @@ -14,7 +14,7 @@ public interface FnEventBuilder { * @param value header value(s) * @return an event builder */ - FnEventBuilder withHeader(String key, String value); + FnEventBuilder withHeader(String key, String value); /** * Set the body of the request by providing an InputStream @@ -25,7 +25,7 @@ public interface FnEventBuilder { * @param contentLength how long the body is supposed to be * @return an event builder */ - FnEventBuilder withBody(InputStream body, int contentLength); + FnEventBuilder withBody(InputStream body, int contentLength); /** * Set the body of the request as a byte array @@ -33,7 +33,7 @@ public interface FnEventBuilder { * @param body the bytes of the body * @return an event builder */ - FnEventBuilder withBody(byte[] body); + FnEventBuilder withBody(byte[] body); /** * Set the body of the request as a String @@ -41,7 +41,7 @@ public interface FnEventBuilder { * @param body the String of the body * @return an event builder */ - FnEventBuilder withBody(String body); + FnEventBuilder withBody(String body); /** * Set the app name associated with the call @@ -49,7 +49,7 @@ public interface FnEventBuilder { * @param appName the app name * @return an event builder */ - FnEventBuilder withAppName(String appName); + FnEventBuilder withAppName(String appName); /** * Set the fn route associated with the call @@ -57,7 +57,7 @@ public interface FnEventBuilder { * @param route the route * @return an event builder */ - FnEventBuilder withRoute(String route); + FnEventBuilder withRoute(String route); /** * Set the HTTP method of the incoming request @@ -65,7 +65,7 @@ public interface FnEventBuilder { * @param method an HTTP method * @return an event builder */ - FnEventBuilder withMethod(String method); + FnEventBuilder withMethod(String method); /** * Set the request URL of the incoming event @@ -73,7 +73,7 @@ public interface FnEventBuilder { * @param requestUrl the request URL * @return an event builder */ - FnEventBuilder withRequestUrl(String requestUrl); + FnEventBuilder withRequestUrl(String requestUrl); /** * Add a query parameter to the request URL @@ -82,7 +82,7 @@ public interface FnEventBuilder { * @param value - non URL encoded value * @return an event builder */ - FnEventBuilder withQueryParameter(String key, String value); + FnEventBuilder withQueryParameter(String key, String value); /** * Consume the builder and enqueue this event to be passed into the function when it is run @@ -90,7 +90,8 @@ public interface FnEventBuilder { * @return The original testing rule. The builder is consumed. * @throws IllegalStateException if this event has already been enqueued and the event input can only be read once. */ - FnTestingRule enqueue(); +// FnTestingRule enqueue(); + T enqueue(); /** * Consume the builder and enqueue multiple copies of this event. @@ -102,5 +103,6 @@ public interface FnEventBuilder { * @return The original testing rule. The builder is consumed. * @throws IllegalStateException if the body cannot be read multiple times. */ - FnTestingRule enqueue(int n); +// FnTestingRule enqueue(int n); + T enqueue(int n); } diff --git a/testing/src/main/java/com/fnproject/fn/testing/FnFunctionStubBuilder.java b/testing-core/src/main/java/com/fnproject/fn/testing/FnFunctionStubBuilder.java similarity index 92% rename from testing/src/main/java/com/fnproject/fn/testing/FnFunctionStubBuilder.java rename to testing-core/src/main/java/com/fnproject/fn/testing/FnFunctionStubBuilder.java index 9ed01e45..c2403659 100644 --- a/testing/src/main/java/com/fnproject/fn/testing/FnFunctionStubBuilder.java +++ b/testing-core/src/main/java/com/fnproject/fn/testing/FnFunctionStubBuilder.java @@ -3,14 +3,14 @@ /** * A builder for constructing stub external functions */ -public interface FnFunctionStubBuilder { +public interface FnFunctionStubBuilder { /** * Consume the builder and stub the function to return the provided byte array * * @param result A byte array returned by the function * @return The original testing rule (usually {@link FnTestingRule}. The builder is consumed. */ - FnTestingRule withResult(byte[] result); + T withResult(byte[] result); /** * Consume the builder and stub the function to throw an error when it is invoked: this simulates a failure of the @@ -18,7 +18,7 @@ public interface FnFunctionStubBuilder { * * @return The original testing rule (usually {@link FnTestingRule}. The builder is consumed. */ - FnTestingRule withFunctionError(); + T withFunctionError(); /** * Consume the builder and stub the function to throw a platform error, this simulates a failure of the Fn Flow @@ -26,7 +26,7 @@ public interface FnFunctionStubBuilder { * * @return The original testing rule (usually {@link FnTestingRule}. The builder is consumed. */ - FnTestingRule withPlatformError(); + T withPlatformError(); /** * Consume the builder and stub the function to perform some action; the action is an implementation of the @@ -39,7 +39,7 @@ public interface FnFunctionStubBuilder { * @param f an action to apply when this function is invoked * @return The original testing rule (usually {@link FnTestingRule}. The builder is consumed. */ - FnTestingRule withAction(ExternalFunctionAction f); + T withAction(ExternalFunctionAction f); /** * Represents the calling interface of an external function. It takes a byte[] as input, diff --git a/testing/src/main/java/com/fnproject/fn/testing/FnHttpEventBuilder.java b/testing-core/src/main/java/com/fnproject/fn/testing/FnHttpEventBuilder.java similarity index 100% rename from testing/src/main/java/com/fnproject/fn/testing/FnHttpEventBuilder.java rename to testing-core/src/main/java/com/fnproject/fn/testing/FnHttpEventBuilder.java diff --git a/testing/src/main/java/com/fnproject/fn/testing/FnResult.java b/testing-core/src/main/java/com/fnproject/fn/testing/FnResult.java similarity index 100% rename from testing/src/main/java/com/fnproject/fn/testing/FnResult.java rename to testing-core/src/main/java/com/fnproject/fn/testing/FnResult.java diff --git a/testing/src/main/java/com/fnproject/fn/testing/FnTestingClassLoader.java b/testing-core/src/main/java/com/fnproject/fn/testing/FnTestingClassLoader.java similarity index 100% rename from testing/src/main/java/com/fnproject/fn/testing/FnTestingClassLoader.java rename to testing-core/src/main/java/com/fnproject/fn/testing/FnTestingClassLoader.java diff --git a/testing/src/main/java/com/fnproject/fn/testing/FunctionError.java b/testing-core/src/main/java/com/fnproject/fn/testing/FunctionError.java similarity index 100% rename from testing/src/main/java/com/fnproject/fn/testing/FunctionError.java rename to testing-core/src/main/java/com/fnproject/fn/testing/FunctionError.java diff --git a/testing/src/main/java/com/fnproject/fn/testing/HeaderWriter.java b/testing-core/src/main/java/com/fnproject/fn/testing/HeaderWriter.java similarity index 100% rename from testing/src/main/java/com/fnproject/fn/testing/HeaderWriter.java rename to testing-core/src/main/java/com/fnproject/fn/testing/HeaderWriter.java diff --git a/testing/src/main/java/com/fnproject/fn/testing/InMemCompleter.java b/testing-core/src/main/java/com/fnproject/fn/testing/InMemCompleter.java similarity index 100% rename from testing/src/main/java/com/fnproject/fn/testing/InMemCompleter.java rename to testing-core/src/main/java/com/fnproject/fn/testing/InMemCompleter.java diff --git a/testing/src/main/java/com/fnproject/fn/testing/PlatformError.java b/testing-core/src/main/java/com/fnproject/fn/testing/PlatformError.java similarity index 100% rename from testing/src/main/java/com/fnproject/fn/testing/PlatformError.java rename to testing-core/src/main/java/com/fnproject/fn/testing/PlatformError.java diff --git a/testing/src/main/java/com/fnproject/fn/testing/ResultException.java b/testing-core/src/main/java/com/fnproject/fn/testing/ResultException.java similarity index 100% rename from testing/src/main/java/com/fnproject/fn/testing/ResultException.java rename to testing-core/src/main/java/com/fnproject/fn/testing/ResultException.java diff --git a/testing-junit4/pom.xml b/testing-junit4/pom.xml new file mode 100644 index 00000000..ad21faff --- /dev/null +++ b/testing-junit4/pom.xml @@ -0,0 +1,41 @@ + + + + fdk + com.fnproject.fn + 1.0.0-SNAPSHOT + + 4.0.0 + + testing-junit4 + + + + com.fnproject.fn + testing-core + ${project.version} + + + + com.fnproject.fn + runtime + ${project.version} + + + + junit + junit + ${junit.version} + + + org.assertj + assertj-core + ${assertj-core.version} + test + + + + + \ No newline at end of file diff --git a/testing-junit4/src/main/java/com/fnproject/fn/testing/FnEventBuilderJUnit4.java b/testing-junit4/src/main/java/com/fnproject/fn/testing/FnEventBuilderJUnit4.java new file mode 100644 index 00000000..80a2312d --- /dev/null +++ b/testing-junit4/src/main/java/com/fnproject/fn/testing/FnEventBuilderJUnit4.java @@ -0,0 +1,5 @@ +package com.fnproject.fn.testing; + +public interface FnEventBuilderJUnit4 extends FnEventBuilder { + +} diff --git a/testing-junit4/src/main/java/com/fnproject/fn/testing/FnFunctionStubBuilderJUnit4.java b/testing-junit4/src/main/java/com/fnproject/fn/testing/FnFunctionStubBuilderJUnit4.java new file mode 100644 index 00000000..aff322b9 --- /dev/null +++ b/testing-junit4/src/main/java/com/fnproject/fn/testing/FnFunctionStubBuilderJUnit4.java @@ -0,0 +1,9 @@ +package com.fnproject.fn.testing; + +public interface FnFunctionStubBuilderJUnit4 extends FnFunctionStubBuilder { + + + + + +} diff --git a/testing/src/main/java/com/fnproject/fn/testing/FnTestingRule.java b/testing-junit4/src/main/java/com/fnproject/fn/testing/FnTestingRule.java similarity index 99% rename from testing/src/main/java/com/fnproject/fn/testing/FnTestingRule.java rename to testing-junit4/src/main/java/com/fnproject/fn/testing/FnTestingRule.java index 77daf715..d4bd9871 100644 --- a/testing/src/main/java/com/fnproject/fn/testing/FnTestingRule.java +++ b/testing-junit4/src/main/java/com/fnproject/fn/testing/FnTestingRule.java @@ -191,7 +191,7 @@ public Statement apply(Statement base, Description description) { * * @return a new event builder */ - public FnEventBuilder givenEvent() { + public FnEventBuilderJUnit4 givenEvent() { return new DefaultFnEventBuilder(); } @@ -388,8 +388,8 @@ public int getStatus() { } - public FnFunctionStubBuilder givenFn(String id) { - return new FnFunctionStubBuilder() { + public FnFunctionStubBuilderJUnit4 givenFn(String id) { + return new FnFunctionStubBuilderJUnit4() { @Override public FnTestingRule withResult(byte[] result) { return withAction((body) -> result); @@ -432,7 +432,7 @@ private interface FnFunctionStub { /** * Builds a mocked input event into the function runtime */ - private class DefaultFnEventBuilder implements FnEventBuilder { + private class DefaultFnEventBuilder implements FnEventBuilderJUnit4 { FnHttpEventBuilder builder = new FnHttpEventBuilder().withMethod("GET") .withAppName("appName") diff --git a/testing/src/test/java/com/fnproject/fn/testing/ExerciseEverything.java b/testing-junit4/src/test/java/junit/com/fnproject/fn/testing/ExerciseEverything.java similarity index 99% rename from testing/src/test/java/com/fnproject/fn/testing/ExerciseEverything.java rename to testing-junit4/src/test/java/junit/com/fnproject/fn/testing/ExerciseEverything.java index 1d4ce58e..0d559fea 100644 --- a/testing/src/test/java/com/fnproject/fn/testing/ExerciseEverything.java +++ b/testing-junit4/src/test/java/junit/com/fnproject/fn/testing/ExerciseEverything.java @@ -1,9 +1,8 @@ -package com.fnproject.fn.testing; +package junit.com.fnproject.fn.testing; import com.fnproject.fn.api.Headers; import com.fnproject.fn.api.InputEvent; import com.fnproject.fn.api.flow.*; -import com.fnproject.fn.runtime.flow.HttpClient; import org.apache.commons.io.IOUtils; import org.apache.commons.io.output.TeeOutputStream; diff --git a/testing/src/test/java/com/fnproject/fn/testing/FnTestingRuleFlowsTest.java b/testing-junit4/src/test/java/junit/com/fnproject/fn/testing/FnTestingRuleFlowsTest.java similarity index 79% rename from testing/src/test/java/com/fnproject/fn/testing/FnTestingRuleFlowsTest.java rename to testing-junit4/src/test/java/junit/com/fnproject/fn/testing/FnTestingRuleFlowsTest.java index 00849159..3217179e 100644 --- a/testing/src/test/java/com/fnproject/fn/testing/FnTestingRuleFlowsTest.java +++ b/testing-junit4/src/test/java/junit/com/fnproject/fn/testing/FnTestingRuleFlowsTest.java @@ -1,8 +1,10 @@ -package com.fnproject.fn.testing; +package junit.com.fnproject.fn.testing; import com.fnproject.fn.api.Headers; import com.fnproject.fn.api.RuntimeContext; import com.fnproject.fn.api.flow.*; +import com.fnproject.fn.testing.FnTestingRule; +import org.assertj.core.api.Assertions; import org.junit.*; import java.io.Serializable; @@ -11,7 +13,6 @@ import java.util.concurrent.CancellationException; import java.util.concurrent.CompletableFuture; -import static org.assertj.core.api.Assertions.assertThat; public class FnTestingRuleFlowsTest { private static final int HTTP_OK = 200; @@ -78,8 +79,8 @@ public void completedValue() { fn.thenRun(TestFn.class, "completedValue"); - assertThat(fn.getOnlyResult().getStatus()).isEqualTo(200); - assertThat(result).isEqualTo(Result.CompletedValue); + Assertions.assertThat(fn.getOnlyResult().getStatus()).isEqualTo(200); + Assertions.assertThat(result).isEqualTo(Result.CompletedValue); } @Test @@ -88,8 +89,8 @@ public void supply() { fn.thenRun(TestFn.class, "supply"); - assertThat(fn.getOnlyResult().getStatus()).isEqualTo(HTTP_OK); - assertThat(result).isEqualTo(Result.Supply); + Assertions.assertThat(fn.getOnlyResult().getStatus()).isEqualTo(HTTP_OK); + Assertions.assertThat(result).isEqualTo(Result.Supply); } @Test @@ -98,8 +99,8 @@ public void allOf() { fn.thenRun(TestFn.class, "allOf"); - assertThat(fn.getOnlyResult().getStatus()).isEqualTo(HTTP_OK); - assertThat(result).isEqualTo(Result.AllOf); + Assertions.assertThat(fn.getOnlyResult().getStatus()).isEqualTo(HTTP_OK); + Assertions.assertThat(result).isEqualTo(Result.AllOf); } @@ -109,8 +110,8 @@ public void anyOf() { fn.thenRun(TestFn.class, "anyOf"); - assertThat(fn.getOnlyResult().getStatus()).isEqualTo(HTTP_OK); - assertThat(result).isEqualTo(Result.AnyOf); + Assertions.assertThat(fn.getOnlyResult().getStatus()).isEqualTo(HTTP_OK); + Assertions.assertThat(result).isEqualTo(Result.AnyOf); } @Test() @@ -121,9 +122,9 @@ public void nestedThenCompose() { fn.thenRun(Loop.class, "repeat"); - assertThat(fn.getOnlyResult().getStatus()).isEqualTo(HTTP_OK); - assertThat(fn.getOnlyResult().getBodyAsString()) - .isEqualTo(String.join("", Collections.nCopies(Loop.COUNT, "hello world"))); + Assertions.assertThat(fn.getOnlyResult().getStatus()).isEqualTo(HTTP_OK); + Assertions.assertThat(fn.getOnlyResult().getBodyAsString()) + .isEqualTo(String.join("", Collections.nCopies(Loop.COUNT, "hello world"))); } @Test @@ -134,8 +135,8 @@ public void invokeFunctionWithResult() { fn.thenRun(TestFn.class, "invokeFunctionEcho"); - assertThat(fn.getOnlyResult().getStatus()).isEqualTo(HTTP_OK); - assertThat(result).isEqualTo(Result.InvokeFunctionFixed); + Assertions.assertThat(fn.getOnlyResult().getStatus()).isEqualTo(HTTP_OK); + Assertions.assertThat(result).isEqualTo(Result.InvokeFunctionFixed); } @@ -153,8 +154,8 @@ public void invokeJsonFunction() { fn.thenRun(TestFn.class, "invokeJsonFunction"); - assertThat(fn.getOnlyResult().getStatus()).isEqualTo(HTTP_OK); - assertThat(count).isEqualTo(1); + Assertions.assertThat(fn.getOnlyResult().getStatus()).isEqualTo(HTTP_OK); + Assertions.assertThat(count).isEqualTo(1); } @Test @@ -165,8 +166,8 @@ public void invokeFunctionWithFunctionError() { fn.thenRun(TestFn.class, "invokeFunctionError"); - assertThat(fn.getOnlyResult().getStatus()).isEqualTo(HTTP_OK); - assertThat(result).isEqualTo(Result.Exceptionally); + Assertions.assertThat(fn.getOnlyResult().getStatus()).isEqualTo(HTTP_OK); + Assertions.assertThat(result).isEqualTo(Result.Exceptionally); isInstanceOfAny(exception, FunctionInvocationException.class); } @@ -176,10 +177,10 @@ public void invokeFunctionWithFailedFuture() { fn.thenRun(TestFn.class, "failedFuture"); - assertThat(fn.getOnlyResult().getStatus()).isEqualTo(HTTP_OK); - assertThat(result).isEqualTo(Result.Exceptionally); - assertThat(exception).isInstanceOf(RuntimeException.class); - assertThat(exception).hasMessage("failedFuture"); + Assertions.assertThat(fn.getOnlyResult().getStatus()).isEqualTo(HTTP_OK); + Assertions.assertThat(result).isEqualTo(Result.Exceptionally); + Assertions.assertThat(exception).isInstanceOf(RuntimeException.class); + Assertions.assertThat(exception).hasMessage("failedFuture"); } @Test @@ -190,8 +191,8 @@ public void invokeFunctionWithPlatformError() { fn.thenRun(TestFn.class, "invokeFunctionError"); - assertThat(fn.getOnlyResult().getStatus()).isEqualTo(HTTP_OK); - assertThat(result).isEqualTo(Result.Exceptionally); + Assertions.assertThat(fn.getOnlyResult().getStatus()).isEqualTo(HTTP_OK); + Assertions.assertThat(result).isEqualTo(Result.Exceptionally); isInstanceOfAny(exception, PlatformException.class); } @@ -203,8 +204,8 @@ public void invokeFunctionWithAction() { fn.thenRun(TestFn.class, "invokeFunctionEcho"); - assertThat(fn.getOnlyResult().getStatus()).isEqualTo(HTTP_OK); - assertThat(result).isEqualTo(Result.InvokeFunctionEcho); + Assertions.assertThat(fn.getOnlyResult().getStatus()).isEqualTo(HTTP_OK); + Assertions.assertThat(result).isEqualTo(Result.InvokeFunctionEcho); } @Test @@ -213,8 +214,8 @@ public void completingExceptionally() { fn.thenRun(TestFn.class, "completeExceptionally"); - assertThat(fn.getOnlyResult().getStatus()).isEqualTo(HTTP_OK); - assertThat(result).isEqualTo(Result.Exceptionally); + Assertions.assertThat(fn.getOnlyResult().getStatus()).isEqualTo(HTTP_OK); + Assertions.assertThat(result).isEqualTo(Result.Exceptionally); } @Test @@ -223,8 +224,8 @@ public void completingExceptionallyWhenErrorIsThrownEarlyInGraph() { fn.thenRun(TestFn.class, "completeExceptionallyEarly"); - assertThat(fn.getOnlyResult().getStatus()).isEqualTo(HTTP_OK); - assertThat(result).isEqualTo(Result.Exceptionally); + Assertions.assertThat(fn.getOnlyResult().getStatus()).isEqualTo(HTTP_OK); + Assertions.assertThat(result).isEqualTo(Result.Exceptionally); } @Test @@ -233,9 +234,9 @@ public void cancelledFutureCompletesExceptionally() { fn.thenRun(TestFn.class, "cancelFuture"); - assertThat(fn.getOnlyResult().getStatus()).isEqualTo(HTTP_OK); - assertThat(result).isEqualTo(Result.Exceptionally); - assertThat(exception).isInstanceOf(CancellationException.class); + Assertions.assertThat(fn.getOnlyResult().getStatus()).isEqualTo(HTTP_OK); + Assertions.assertThat(result).isEqualTo(Result.Exceptionally); + Assertions.assertThat(exception).isInstanceOf(CancellationException.class); } @Test @@ -244,10 +245,10 @@ public void completeFutureExceptionallyWithCustomException() { fn.thenRun(TestFn.class, "completeFutureExceptionally"); - assertThat(fn.getOnlyResult().getStatus()).isEqualTo(HTTP_OK); - assertThat(result).isEqualTo(Result.Exceptionally); - assertThat(exception).isInstanceOf(RuntimeException.class); - assertThat(exception.getMessage()).isEqualTo("Custom exception"); + Assertions.assertThat(fn.getOnlyResult().getStatus()).isEqualTo(HTTP_OK); + Assertions.assertThat(result).isEqualTo(Result.Exceptionally); + Assertions.assertThat(exception).isInstanceOf(RuntimeException.class); + Assertions.assertThat(exception.getMessage()).isEqualTo("Custom exception"); } @Test @@ -256,8 +257,8 @@ public void completedFutureCompletesNormally() { fn.thenRun(TestFn.class, "completeFuture"); - assertThat(fn.getOnlyResult().getStatus()).isEqualTo(HTTP_OK); - assertThat(result).isEqualTo(Result.CompletedValue); + Assertions.assertThat(fn.getOnlyResult().getStatus()).isEqualTo(HTTP_OK); + Assertions.assertThat(result).isEqualTo(Result.CompletedValue); } @Test @@ -266,8 +267,8 @@ public void uncompletedFutureCanBeCompleted() { fn.thenRun(TestFn.class, "createFlowFuture"); - assertThat(fn.getOnlyResult().getStatus()).isEqualTo(HTTP_OK); - assertThat(result).isEqualTo(Result.CompletedValue); + Assertions.assertThat(fn.getOnlyResult().getStatus()).isEqualTo(HTTP_OK); + Assertions.assertThat(result).isEqualTo(Result.CompletedValue); } @Test @@ -277,8 +278,8 @@ public void shouldLogMessagesToStdErrToPlatformStdErr() { fn.thenRun(TestFn.class, "logToStdErrInContinuation"); - assertThat(fn.getOnlyResult().getStatus()).isEqualTo(HTTP_OK); - assertThat(fn.getStdErrAsString()).contains("TestFn logging: 1"); + Assertions.assertThat(fn.getOnlyResult().getStatus()).isEqualTo(HTTP_OK); + Assertions.assertThat(fn.getStdErrAsString()).contains("TestFn logging: 1"); } @Test @@ -288,8 +289,8 @@ public void shouldLogMessagesToStdOutToPlatformStdErr() { fn.thenRun(TestFn.class, "logToStdOutInContinuation"); - assertThat(fn.getOnlyResult().getStatus()).isEqualTo(HTTP_OK); - assertThat(fn.getStdErrAsString()).contains("TestFn logging: 1"); + Assertions.assertThat(fn.getOnlyResult().getStatus()).isEqualTo(HTTP_OK); + Assertions.assertThat(fn.getStdErrAsString()).contains("TestFn logging: 1"); } @@ -299,9 +300,9 @@ public void shouldHandleMultipleEventsForFunctionWithoutInput() { fn.thenRun(TestFn.class, "anyOf"); - assertThat(fn.getResults().get(0).getStatus()).isEqualTo(HTTP_OK); - assertThat(fn.getResults().get(1).getStatus()).isEqualTo(HTTP_OK); - assertThat(result).isEqualTo(Result.AnyOf); + Assertions.assertThat(fn.getResults().get(0).getStatus()).isEqualTo(HTTP_OK); + Assertions.assertThat(fn.getResults().get(1).getStatus()).isEqualTo(HTTP_OK); + Assertions.assertThat(result).isEqualTo(Result.AnyOf); } @Test @@ -310,8 +311,8 @@ public void exceptionallyComposeHandle() { fn.thenRun(TestFn.class, "exceptionallyComposeHandle"); - assertThat(fn.getOnlyResult().getStatus()).isEqualTo(HTTP_OK); - assertThat(count).isEqualTo(2); + Assertions.assertThat(fn.getOnlyResult().getStatus()).isEqualTo(HTTP_OK); + Assertions.assertThat(count).isEqualTo(2); } @@ -321,8 +322,8 @@ public void exceptionallyComposePassThru() { fn.givenEvent().enqueue(); fn.thenRun(TestFn.class, "exceptionallyComposePassThru"); - assertThat(fn.getOnlyResult().getStatus()).isEqualTo(HTTP_OK); - assertThat(count).isEqualTo(1); + Assertions.assertThat(fn.getOnlyResult().getStatus()).isEqualTo(HTTP_OK); + Assertions.assertThat(count).isEqualTo(1); } @@ -331,8 +332,8 @@ public void exceptionallyComposeThrowsError() { fn.givenEvent().enqueue(); fn.thenRun(TestFn.class, "exceptionallyComposeThrowsError"); - assertThat(fn.getOnlyResult().getStatus()).isEqualTo(HTTP_OK); - assertThat(count).isEqualTo(1); + Assertions.assertThat(fn.getOnlyResult().getStatus()).isEqualTo(HTTP_OK); + Assertions.assertThat(count).isEqualTo(1); } @@ -346,8 +347,8 @@ public void shouldHandleMultipleEventsForFunctionWithInput() { fn.thenRun(Loop.class, "repeat"); for (int i = 0; i < bodies.length; i++) { - assertThat(fn.getResults().get(i).getBodyAsString()) - .isEqualTo(String.join("", Collections.nCopies(Loop.COUNT, bodies[i]))); + Assertions.assertThat(fn.getResults().get(i).getBodyAsString()) + .isEqualTo(String.join("", Collections.nCopies(Loop.COUNT, bodies[i]))); } } @@ -356,15 +357,15 @@ public void shouldRunShutdownHooksInTest() { fn.givenEvent().enqueue(); fn.thenRun(TestFn.class, "terminationHooks"); - assertThat(fn.getOnlyResult().getStatus()).isEqualTo(200); + Assertions.assertThat(fn.getOnlyResult().getStatus()).isEqualTo(200); - assertThat(result).isEqualTo(Result.TerminationHookRun); + Assertions.assertThat(result).isEqualTo(Result.TerminationHookRun); } // Due to the alien nature of the stored exception, we supply a helper to assert isInstanceOfAny void isInstanceOfAny(Object o, Class... cs) { - assertThat(o).isNotNull(); + Assertions.assertThat(o).isNotNull(); ClassLoader loader = o.getClass().getClassLoader(); for (Class c : cs) { try { diff --git a/testing/src/test/java/com/fnproject/fn/testing/FnTestingRuleTest.java b/testing-junit4/src/test/java/junit/com/fnproject/fn/testing/FnTestingRuleTest.java similarity index 68% rename from testing/src/test/java/com/fnproject/fn/testing/FnTestingRuleTest.java rename to testing-junit4/src/test/java/junit/com/fnproject/fn/testing/FnTestingRuleTest.java index d46b8689..40755524 100644 --- a/testing/src/test/java/com/fnproject/fn/testing/FnTestingRuleTest.java +++ b/testing-junit4/src/test/java/junit/com/fnproject/fn/testing/FnTestingRuleTest.java @@ -1,9 +1,12 @@ -package com.fnproject.fn.testing; +package junit.com.fnproject.fn.testing; import com.fnproject.fn.api.InputEvent; import com.fnproject.fn.api.OutputEvent; import com.fnproject.fn.api.RuntimeContext; +import com.fnproject.fn.testing.FnResult; +import com.fnproject.fn.testing.FnTestingRule; import org.apache.commons.io.IOUtils; +import org.assertj.core.api.Assertions; import org.junit.Before; import org.junit.Rule; import org.junit.Test; @@ -24,8 +27,8 @@ public class FnTestingRuleTest { public static List capturedBodies = new ArrayList<>(); @Rule - public FnTestingRule fn = FnTestingRule.createDefault(); - private final String exampleBaseUrl = "http://www.example.com"; + public FnTestingRule fn = FnTestingRule.createDefault(); + private final String exampleBaseUrl = "http://www.example.com"; @Before public void reset() { @@ -90,7 +93,7 @@ public void shouldSetEnvironmentInsideFnScope() { fn.thenRun(FnTestingRuleTest.TestFn.class, "copyConfiguration"); - assertThat(configuration).containsEntry("CONFIG_FOO", "BAR"); + Assertions.assertThat(configuration).containsEntry("CONFIG_FOO", "BAR"); } @@ -101,7 +104,7 @@ public void shouldCleanEnvironmentOfSpecialVarsInsideFnScope() { fn.thenRun(FnTestingRuleTest.TestFn.class, "copyConfiguration"); - assertThat(configuration).doesNotContainKeys("APP_NAME", "ROUTE", "METHOD", "REQUEST_URL"); + Assertions.assertThat(configuration).doesNotContainKeys("APP_NAME", "ROUTE", "METHOD", "REQUEST_URL"); } @@ -111,8 +114,8 @@ public void shouldHandleErrors() { fn.thenRun(FnTestingRuleTest.TestFn.class, "err"); - assertThat(fn.getOnlyResult().getStatus()).isEqualTo(500); - assertThat(fn.getStdErrAsString()).contains("An error occurred in function: ERR"); + Assertions.assertThat(fn.getOnlyResult().getStatus()).isEqualTo(500); + Assertions.assertThat(fn.getStdErrAsString()).contains("An error occurred in function: ERR"); } @@ -123,7 +126,7 @@ public void configShouldNotOverrideIntrinsicHeaders() { fn.thenRun(FnTestingRuleTest.TestFn.class, "copyInputEvent"); - assertThat(inEvent.getAppName()).isEqualTo("appName"); + Assertions.assertThat(inEvent.getAppName()).isEqualTo("appName"); } @@ -136,7 +139,7 @@ public void configShouldBeCaptitalisedAndReplacedWithUnderscores() {// Basic tes fn.thenRun(FnTestingRuleTest.TestFn.class, "copyConfiguration"); - assertThat(configuration).containsEntry("SOME_KEY_WITH_DASHES", "some-value"); + Assertions.assertThat(configuration).containsEntry("SOME_KEY_WITH_DASHES", "some-value"); } @@ -151,10 +154,10 @@ public void shouldSetArgsInFirstEvent() { fn.thenRun(FnTestingRuleTest.TestFn.class, "copyInputEvent"); - assertThat(inEvent.getAppName()).isEqualTo("TEST_APP"); - assertThat(inEvent.getRoute()).isEqualTo("/myroute"); - assertThat(inEvent.getMethod()).isEqualTo("PUT"); - assertThat(inEvent.getRequestUrl()).isEqualTo("http://example.com/mytest"); + Assertions.assertThat(inEvent.getAppName()).isEqualTo("TEST_APP"); + Assertions.assertThat(inEvent.getRoute()).isEqualTo("/myroute"); + Assertions.assertThat(inEvent.getMethod()).isEqualTo("PUT"); + Assertions.assertThat(inEvent.getRequestUrl()).isEqualTo("http://example.com/mytest"); } @@ -179,17 +182,17 @@ public void shouldSendEventDataToSDKInputEvent() { fn.thenRun(TestFn.class, "captureInput"); FnResult result = fn.getOnlyResult(); - assertThat(result.getBodyAsString()).isEmpty(); - assertThat(result.getHeaders().getAll()).contains(headerEntry("Content-length", "0")); - assertThat(result.getStatus()).isEqualTo(200); + Assertions.assertThat(result.getBodyAsString()).isEmpty(); + Assertions.assertThat(result.getHeaders().getAll()).contains(headerEntry("Content-length", "0")); + Assertions.assertThat(result.getStatus()).isEqualTo(200); InputEvent event = capturedInputs.get(0); - assertThat(event.getAppName()).isEqualTo(APP_NAME); - assertThat(event.getHeaders().getAll()) - .contains(headerEntry("FOO", "BAR, BAZ")) - .contains(headerEntry("FEH", "")); - assertThat(event.getMethod()).isEqualTo(METHOD); - assertThat(capturedBodies.get(0)).isEqualTo("Body".getBytes()); + Assertions.assertThat(event.getAppName()).isEqualTo(APP_NAME); + Assertions.assertThat(event.getHeaders().getAll()) + .contains(headerEntry("FOO", "BAR, BAZ")) + .contains(headerEntry("FEH", "")); + Assertions.assertThat(event.getMethod()).isEqualTo(METHOD); + Assertions.assertThat(capturedBodies.get(0)).isEqualTo("Body".getBytes()); } @@ -218,27 +221,27 @@ public void shouldEnqueueMultipleDistinctEvents() { fn.thenRun(TestFn.class, "captureInput"); FnResult result = fn.getResults().get(0); - assertThat(result.getBodyAsString()).isEmpty(); - assertThat(result.getHeaders().getAll()).contains(headerEntry("Content-length", "0")); - assertThat(result.getStatus()).isEqualTo(200); + Assertions.assertThat(result.getBodyAsString()).isEmpty(); + Assertions.assertThat(result.getHeaders().getAll()).contains(headerEntry("Content-length", "0")); + Assertions.assertThat(result.getStatus()).isEqualTo(200); InputEvent event = capturedInputs.get(0); - assertThat(event.getAppName()).isEqualTo("alpha"); - assertThat(event.getHeaders().getAll()).contains(headerEntry("FOO", "BAR")); - assertThat(event.getMethod()).isEqualTo("POST"); - assertThat(capturedBodies.get(0)).isEqualTo("Body".getBytes()); + Assertions.assertThat(event.getAppName()).isEqualTo("alpha"); + Assertions.assertThat(event.getHeaders().getAll()).contains(headerEntry("FOO", "BAR")); + Assertions.assertThat(event.getMethod()).isEqualTo("POST"); + Assertions.assertThat(capturedBodies.get(0)).isEqualTo("Body".getBytes()); FnResult result2 = fn.getResults().get(1); - assertThat(result2.getBodyAsString()).isEmpty(); - assertThat(result2.getHeaders().getAll()).contains(headerEntry("Content-length", "0")); - assertThat(result2.getStatus()).isEqualTo(200); + Assertions.assertThat(result2.getBodyAsString()).isEmpty(); + Assertions.assertThat(result2.getHeaders().getAll()).contains(headerEntry("Content-length", "0")); + Assertions.assertThat(result2.getStatus()).isEqualTo(200); InputEvent event2 = capturedInputs.get(1); - assertThat(event2.getAppName()).isEqualTo("alpha"); - assertThat(event2.getHeaders().getAll()).contains(headerEntry("FOO2", "BAR2")); - assertThat(event2.getMethod()).isEqualTo("PUT"); - assertThat(capturedBodies.get(1)).isEqualTo("Body2".getBytes()); + Assertions.assertThat(event2.getAppName()).isEqualTo("alpha"); + Assertions.assertThat(event2.getHeaders().getAll()).contains(headerEntry("FOO2", "BAR2")); + Assertions.assertThat(event2.getMethod()).isEqualTo("PUT"); + Assertions.assertThat(capturedBodies.get(1)).isEqualTo("Body2".getBytes()); } @@ -256,14 +259,14 @@ public void shouldEnqueueMultipleIdenticalEvents() { fn.thenRun(TestFn.class, "echoInput"); List results = fn.getResults(); - assertThat(results).hasSize(10); + Assertions.assertThat(results).hasSize(10); results.forEach((r) -> { - assertThat(r.getStatus()).isEqualTo(200); - assertThat(r.getHeaders().getAll()) - .contains(headerEntry("Content-Type", "application/octet-stream")) - .contains(headerEntry("Content-length", String.valueOf("Body".getBytes().length))); + Assertions.assertThat(r.getStatus()).isEqualTo(200); + Assertions.assertThat(r.getHeaders().getAll()) + .contains(headerEntry("Content-Type", "application/octet-stream")) + .contains(headerEntry("Content-length", String.valueOf("Body".getBytes().length))); }); } @@ -296,10 +299,10 @@ public void shouldEnqueuIndependentEventsWithInputStreams() { fn.thenRun(TestFn.class, "echoInput"); List results = fn.getResults(); - assertThat(results).hasSize(2); + Assertions.assertThat(results).hasSize(2); - assertThat(results.get(0).getBodyAsString()).isEqualTo("Body"); - assertThat(results.get(1).getBodyAsString()).isEqualTo("Body1"); + Assertions.assertThat(results.get(0).getBodyAsString()).isEqualTo("Body"); + Assertions.assertThat(results.get(1).getBodyAsString()).isEqualTo("Body1"); } @Test @@ -308,8 +311,8 @@ public void shouldHandleBodyAsInputStream() { fn.thenRun(TestFn.class, "captureInput"); - assertThat(fn.getOnlyResult().getStatus()).isEqualTo(200); - assertThat(capturedBodies.get(0)).isEqualTo("FOO".getBytes()); + Assertions.assertThat(fn.getOnlyResult().getStatus()).isEqualTo(200); + Assertions.assertThat(capturedBodies.get(0)).isEqualTo("FOO".getBytes()); } @Test @@ -320,7 +323,7 @@ public void shouldLeaveQueryParamtersOffIfNotSpecified() { .enqueue(); fn.thenRun(TestFn.class, "copyInputEvent"); - assertThat(inEvent.getRequestUrl()).isEqualTo(baseUrl); + Assertions.assertThat(inEvent.getRequestUrl()).isEqualTo(baseUrl); } @Test @@ -331,8 +334,8 @@ public void shouldPrependQuestionMarkForFirstQueryParam() { .withQueryParameter("var", "val") .enqueue(); fn.thenRun(TestFn.class, "copyInputEvent"); - assertThat(fn.getOnlyResult().getStatus()).isEqualTo(200); - assertThat(inEvent.getRequestUrl()).isEqualTo(baseUrl + "?var=val"); + Assertions.assertThat(fn.getOnlyResult().getStatus()).isEqualTo(200); + Assertions.assertThat(inEvent.getRequestUrl()).isEqualTo(baseUrl + "?var=val"); } @Test @@ -345,7 +348,7 @@ public void shouldHandleMultipleQueryParameters() { .enqueue(); fn.thenRun(TestFn.class, "copyInputEvent"); - assertThat(inEvent.getRequestUrl()).isEqualTo(baseUrl + "?var1=val1&var2=val2"); + Assertions.assertThat(inEvent.getRequestUrl()).isEqualTo(baseUrl + "?var1=val1&var2=val2"); } @Test @@ -358,7 +361,7 @@ public void shouldHandleMultipleQueryParametersWithSameKey() { .enqueue(); fn.thenRun(TestFn.class, "copyInputEvent"); - assertThat(inEvent.getRequestUrl()).isEqualTo(baseUrl + "?var=val1&var=val2"); + Assertions.assertThat(inEvent.getRequestUrl()).isEqualTo(baseUrl + "?var=val1&var=val2"); } @Test @@ -369,7 +372,7 @@ public void shouldUrlEncodeQueryParameterKey() { .enqueue(); fn.thenRun(TestFn.class, "copyInputEvent"); - assertThat(inEvent.getRequestUrl()).isEqualTo(exampleBaseUrl + "?%26=val"); + Assertions.assertThat(inEvent.getRequestUrl()).isEqualTo(exampleBaseUrl + "?%26=val"); } @Test @@ -380,7 +383,7 @@ public void shouldHandleQueryParametersWithSpaces() { .enqueue(); fn.thenRun(TestFn.class, "copyInputEvent"); - assertThat(inEvent.getRequestUrl()).isEqualTo(exampleBaseUrl + "?my+var=this+val"); + Assertions.assertThat(inEvent.getRequestUrl()).isEqualTo(exampleBaseUrl + "?my+var=this+val"); } @Test @@ -392,7 +395,7 @@ public void shouldUrlEncodeQueryParameterValue() { .enqueue(); fn.thenRun(TestFn.class, "copyInputEvent"); - assertThat(inEvent.getRequestUrl()).isEqualTo(baseUrl + "?var=%26"); + Assertions.assertThat(inEvent.getRequestUrl()).isEqualTo(baseUrl + "?var=%26"); } private static Map.Entry headerEntry(String key, String value) { diff --git a/testing/src/test/java/com/fnproject/fn/testing/IntegrationTest.java b/testing-junit4/src/test/java/junit/com/fnproject/fn/testing/IntegrationTest.java similarity index 75% rename from testing/src/test/java/com/fnproject/fn/testing/IntegrationTest.java rename to testing-junit4/src/test/java/junit/com/fnproject/fn/testing/IntegrationTest.java index 4de9171d..add9b478 100644 --- a/testing/src/test/java/com/fnproject/fn/testing/IntegrationTest.java +++ b/testing-junit4/src/test/java/junit/com/fnproject/fn/testing/IntegrationTest.java @@ -1,5 +1,8 @@ -package com.fnproject.fn.testing; +package junit.com.fnproject.fn.testing; +import com.fnproject.fn.testing.FnTestingRule; +import com.fnproject.fn.testing.FunctionError; +import org.assertj.core.api.Assertions; import org.junit.Rule; import org.junit.Test; @@ -30,7 +33,7 @@ public void runIntegrationTests() { .thenRun(ExerciseEverything.class, "handleRequest"); - assertThat(fn.getResults().get(0).getBodyAsString()) - .endsWith("Everything worked\n"); + Assertions.assertThat(fn.getResults().get(0).getBodyAsString()) + .endsWith("Everything worked\n"); } } diff --git a/testing/src/test/java/com/fnproject/fn/testing/MultipleEventsTest.java b/testing-junit4/src/test/java/junit/com/fnproject/fn/testing/MultipleEventsTest.java similarity index 95% rename from testing/src/test/java/com/fnproject/fn/testing/MultipleEventsTest.java rename to testing-junit4/src/test/java/junit/com/fnproject/fn/testing/MultipleEventsTest.java index 4622b44b..5c06937f 100644 --- a/testing/src/test/java/com/fnproject/fn/testing/MultipleEventsTest.java +++ b/testing-junit4/src/test/java/junit/com/fnproject/fn/testing/MultipleEventsTest.java @@ -1,7 +1,9 @@ -package com.fnproject.fn.testing; +package junit.com.fnproject.fn.testing; import com.fnproject.fn.api.flow.Flow; import com.fnproject.fn.api.flow.Flows; +import com.fnproject.fn.testing.FnTestingRule; +import org.assertj.core.api.Assertions; import org.junit.Rule; import org.junit.Test; @@ -105,7 +107,7 @@ public void OverlappingFlowInvocationsShouldWork() { fn.thenRun(TestFn.class, "handleRequest"); - assertThat(success).isTrue(); + Assertions.assertThat(success).isTrue(); } } diff --git a/testing/src/test/java/com/fnproject/fn/testing/WhenCompleteTest.java b/testing-junit4/src/test/java/junit/com/fnproject/fn/testing/WhenCompleteTest.java similarity index 83% rename from testing/src/test/java/com/fnproject/fn/testing/WhenCompleteTest.java rename to testing-junit4/src/test/java/junit/com/fnproject/fn/testing/WhenCompleteTest.java index 7e44c78c..141534ae 100644 --- a/testing/src/test/java/com/fnproject/fn/testing/WhenCompleteTest.java +++ b/testing-junit4/src/test/java/junit/com/fnproject/fn/testing/WhenCompleteTest.java @@ -1,6 +1,8 @@ -package com.fnproject.fn.testing; +package junit.com.fnproject.fn.testing; import com.fnproject.fn.api.flow.Flows; +import com.fnproject.fn.testing.FnTestingRule; +import org.assertj.core.api.Assertions; import org.junit.Rule; import org.junit.Test; @@ -32,7 +34,7 @@ public void OverlappingFlowInvocationsShouldWork() { fn.thenRun(TestFn.class, "handleRequest"); - assertThat(cas.get()).isEqualTo(2); + Assertions.assertThat(cas.get()).isEqualTo(2); } } diff --git a/testing/pom.xml b/testing/pom.xml index 567b31ff..10aa0498 100644 --- a/testing/pom.xml +++ b/testing/pom.xml @@ -22,6 +22,16 @@ runtime ${project.version} + + + com.fnproject.fn + testing-core + ${project.version} + + + + + junit junit From 9e189d83b01a94e2b86808ed2ed85c58b2366e91 Mon Sep 17 00:00:00 2001 From: Sven Ruppert Date: Mon, 23 Jul 2018 15:07:15 +0200 Subject: [PATCH 023/310] cleaning of unused folders/modules --- _archive/pom.xml | 19 ------------------- _archive/testing-junit4/pom.xml | 15 --------------- 2 files changed, 34 deletions(-) delete mode 100644 _archive/pom.xml delete mode 100644 _archive/testing-junit4/pom.xml diff --git a/_archive/pom.xml b/_archive/pom.xml deleted file mode 100644 index bb07b648..00000000 --- a/_archive/pom.xml +++ /dev/null @@ -1,19 +0,0 @@ - - - - fdk - com.fnproject.fn - 1.0.0-SNAPSHOT - - 4.0.0 - - _archive - pom - - testing-junit4 - - - - \ No newline at end of file diff --git a/_archive/testing-junit4/pom.xml b/_archive/testing-junit4/pom.xml deleted file mode 100644 index ebdae363..00000000 --- a/_archive/testing-junit4/pom.xml +++ /dev/null @@ -1,15 +0,0 @@ - - - - _archive - com.fnproject.fn - 1.0.0-SNAPSHOT - - 4.0.0 - - _archive-testing-junit4 - - - \ No newline at end of file From 92ec0b761e469c572c3c69627aabd70e54ba8e0c Mon Sep 17 00:00:00 2001 From: Sven Ruppert Date: Mon, 23 Jul 2018 15:45:39 +0200 Subject: [PATCH 024/310] fixed deps in build-image module --- build-image/pom.xml | 8 +++++++- .../src/test/java/com/example/fn/HelloFunctionTest.java | 6 ++++-- 2 files changed, 11 insertions(+), 3 deletions(-) diff --git a/build-image/pom.xml b/build-image/pom.xml index 474548d4..c423d383 100644 --- a/build-image/pom.xml +++ b/build-image/pom.xml @@ -25,7 +25,13 @@ com.fnproject.fn - testing + testing-core + ${fnproject.version} + test + + + com.fnproject.fn + testing-junit4 ${fnproject.version} test diff --git a/build-image/src/test/java/com/example/fn/HelloFunctionTest.java b/build-image/src/test/java/com/example/fn/HelloFunctionTest.java index e6b7a5e3..ee9f2a1f 100644 --- a/build-image/src/test/java/com/example/fn/HelloFunctionTest.java +++ b/build-image/src/test/java/com/example/fn/HelloFunctionTest.java @@ -1,7 +1,9 @@ package com.example.fn; -import com.fnproject.fn.testing.*; -import org.junit.*; +import com.fnproject.fn.testing.FnResult; +import com.fnproject.fn.testing.FnTestingRule; +import org.junit.Rule; +import org.junit.Test; import static org.junit.Assert.*; From 60fe6803e825451e83827b21ce664ead56909d1d Mon Sep 17 00:00:00 2001 From: Sven Ruppert Date: Mon, 23 Jul 2018 15:57:15 +0200 Subject: [PATCH 025/310] fixed integration-tests examples --- integration-tests/main/test-1-jdk8/pom.xml | 8 +++++++- integration-tests/main/test-1/pom.xml | 8 +++++++- integration-tests/main/test-2/pom.xml | 8 +++++++- .../com/fnproject/fn/integration/test2/PlainFunction.java | 2 -- integration-tests/main/test-4/pom.xml | 8 +++++++- .../com/fnproject/fn/integration/ExerciseEverything.java | 2 -- integration-tests/main/test-5/pom.xml | 8 +++++++- integration-tests/main/test-6/pom.xml | 8 +++++++- 8 files changed, 42 insertions(+), 10 deletions(-) diff --git a/integration-tests/main/test-1-jdk8/pom.xml b/integration-tests/main/test-1-jdk8/pom.xml index 37f78c46..3d635ea1 100644 --- a/integration-tests/main/test-1-jdk8/pom.xml +++ b/integration-tests/main/test-1-jdk8/pom.xml @@ -21,7 +21,13 @@ com.fnproject.fn - testing + testing-core + ${fnproject.version} + test + + + com.fnproject.fn + testing-junit4 ${fnproject.version} test diff --git a/integration-tests/main/test-1/pom.xml b/integration-tests/main/test-1/pom.xml index 37f78c46..3d635ea1 100644 --- a/integration-tests/main/test-1/pom.xml +++ b/integration-tests/main/test-1/pom.xml @@ -21,7 +21,13 @@ com.fnproject.fn - testing + testing-core + ${fnproject.version} + test + + + com.fnproject.fn + testing-junit4 ${fnproject.version} test diff --git a/integration-tests/main/test-2/pom.xml b/integration-tests/main/test-2/pom.xml index da270e30..85b1e46b 100644 --- a/integration-tests/main/test-2/pom.xml +++ b/integration-tests/main/test-2/pom.xml @@ -19,7 +19,13 @@ com.fnproject.fn - testing + testing-core + ${fnproject.version} + test + + + com.fnproject.fn + testing-junit4 ${fnproject.version} test diff --git a/integration-tests/main/test-2/src/main/java/com/fnproject/fn/integration/test2/PlainFunction.java b/integration-tests/main/test-2/src/main/java/com/fnproject/fn/integration/test2/PlainFunction.java index 7ff61897..32261f2f 100644 --- a/integration-tests/main/test-2/src/main/java/com/fnproject/fn/integration/test2/PlainFunction.java +++ b/integration-tests/main/test-2/src/main/java/com/fnproject/fn/integration/test2/PlainFunction.java @@ -1,7 +1,5 @@ package com.fnproject.fn.integration.test2; -import com.fnproject.fn.api.*; - public class PlainFunction { private String greeting; diff --git a/integration-tests/main/test-4/pom.xml b/integration-tests/main/test-4/pom.xml index 380c0d33..8fa85122 100644 --- a/integration-tests/main/test-4/pom.xml +++ b/integration-tests/main/test-4/pom.xml @@ -27,7 +27,13 @@ com.fnproject.fn - testing + testing-core + ${fnproject.version} + test + + + com.fnproject.fn + testing-junit4 ${fnproject.version} test diff --git a/integration-tests/main/test-4/src/main/java/com/fnproject/fn/integration/ExerciseEverything.java b/integration-tests/main/test-4/src/main/java/com/fnproject/fn/integration/ExerciseEverything.java index b11c1a20..b95f4399 100644 --- a/integration-tests/main/test-4/src/main/java/com/fnproject/fn/integration/ExerciseEverything.java +++ b/integration-tests/main/test-4/src/main/java/com/fnproject/fn/integration/ExerciseEverything.java @@ -2,7 +2,6 @@ import com.fnproject.fn.api.Headers; import com.fnproject.fn.api.InputEvent; -import com.fnproject.fn.api.flow.*; import org.apache.commons.io.IOUtils; import org.apache.commons.io.output.TeeOutputStream; @@ -12,7 +11,6 @@ import java.io.PrintStream; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; -import java.util.*; import java.util.stream.Collectors; @SuppressWarnings("unused") diff --git a/integration-tests/main/test-5/pom.xml b/integration-tests/main/test-5/pom.xml index 400510fc..66d43389 100644 --- a/integration-tests/main/test-5/pom.xml +++ b/integration-tests/main/test-5/pom.xml @@ -21,7 +21,13 @@ com.fnproject.fn - testing + testing-core + ${fnproject.version} + test + + + com.fnproject.fn + testing-junit4 ${fnproject.version} test diff --git a/integration-tests/main/test-6/pom.xml b/integration-tests/main/test-6/pom.xml index bacc9706..c6ea212b 100644 --- a/integration-tests/main/test-6/pom.xml +++ b/integration-tests/main/test-6/pom.xml @@ -21,7 +21,13 @@ com.fnproject.fn - testing + testing-core + ${fnproject.version} + test + + + com.fnproject.fn + testing-junit4 ${fnproject.version} test From 5d588df7db905a1ec39b5e9eb6e55221c5dcf50c Mon Sep 17 00:00:00 2001 From: Sven Ruppert Date: Mon, 23 Jul 2018 16:16:32 +0200 Subject: [PATCH 026/310] fixed deps in build-image module --- integration-tests/main/test-2/pom.xml | 2 -- .../fn/integration/test2/PlainFunction.java | 3 +++ integration-tests/main/test-4/pom.xml | 2 -- .../fn/integration/ExerciseEverything.java | 14 ++++++++------ 4 files changed, 11 insertions(+), 10 deletions(-) diff --git a/integration-tests/main/test-2/pom.xml b/integration-tests/main/test-2/pom.xml index 85b1e46b..d37a302d 100644 --- a/integration-tests/main/test-2/pom.xml +++ b/integration-tests/main/test-2/pom.xml @@ -21,13 +21,11 @@ com.fnproject.fn testing-core ${fnproject.version} - test com.fnproject.fn testing-junit4 ${fnproject.version} - test junit diff --git a/integration-tests/main/test-2/src/main/java/com/fnproject/fn/integration/test2/PlainFunction.java b/integration-tests/main/test-2/src/main/java/com/fnproject/fn/integration/test2/PlainFunction.java index 32261f2f..60aeff69 100644 --- a/integration-tests/main/test-2/src/main/java/com/fnproject/fn/integration/test2/PlainFunction.java +++ b/integration-tests/main/test-2/src/main/java/com/fnproject/fn/integration/test2/PlainFunction.java @@ -1,5 +1,8 @@ package com.fnproject.fn.integration.test2; +import com.fnproject.fn.api.FnConfiguration; +import com.fnproject.fn.api.RuntimeContext; + public class PlainFunction { private String greeting; diff --git a/integration-tests/main/test-4/pom.xml b/integration-tests/main/test-4/pom.xml index 8fa85122..fa753b39 100644 --- a/integration-tests/main/test-4/pom.xml +++ b/integration-tests/main/test-4/pom.xml @@ -29,13 +29,11 @@ com.fnproject.fn testing-core ${fnproject.version} - test com.fnproject.fn testing-junit4 ${fnproject.version} - test junit diff --git a/integration-tests/main/test-4/src/main/java/com/fnproject/fn/integration/ExerciseEverything.java b/integration-tests/main/test-4/src/main/java/com/fnproject/fn/integration/ExerciseEverything.java index b95f4399..2d1cff36 100644 --- a/integration-tests/main/test-4/src/main/java/com/fnproject/fn/integration/ExerciseEverything.java +++ b/integration-tests/main/test-4/src/main/java/com/fnproject/fn/integration/ExerciseEverything.java @@ -2,6 +2,7 @@ import com.fnproject.fn.api.Headers; import com.fnproject.fn.api.InputEvent; +import com.fnproject.fn.api.flow.*; import org.apache.commons.io.IOUtils; import org.apache.commons.io.output.TeeOutputStream; @@ -11,17 +12,18 @@ import java.io.PrintStream; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; +import java.util.*; import java.util.stream.Collectors; @SuppressWarnings("unused") public class ExerciseEverything { - private boolean okay = true; - private ByteArrayOutputStream bos = new ByteArrayOutputStream(); - private PrintStream out = new PrintStream(new TeeOutputStream(System.err, bos)); - private String testSelector = null; - private InputEvent inputEvent; - private List failures = new ArrayList<>(); + private boolean okay = true; + private ByteArrayOutputStream bos = new ByteArrayOutputStream(); + private PrintStream out = new PrintStream(new TeeOutputStream(System.err, bos)); + private String testSelector = null; + private InputEvent inputEvent; + private List failures = new ArrayList<>(); @Test(1) @Test.Expect("completed value") From 79a3d87981d76b0ad7379b4978d48b755b57d476 Mon Sep 17 00:00:00 2001 From: Sven Ruppert Date: Fri, 27 Jul 2018 16:28:40 +0200 Subject: [PATCH 027/310] deactivated integration-test 3 and 7 - cycle dependency to cli --- .../com/fnproject/fn/api/flow/FlowFuture.java | 1 - .../com/fnproject/fn/api/flow/FlowsTest.java | 4 +- .../fn/examples/ThumbnailsFunctionTest.java | 131 +++++++++--------- .../com/example/fn/HelloFunctionTest.java | 3 - .../java/com/fnproject/fn/examples/QRGen.java | 1 - .../function/SpringCloudFunctionInvoker.java | 7 +- .../functions/SpringCloudFunction.java | 1 - .../functions/SpringCloudSupplier.java | 1 - .../function/testfns/EmptyFunctionConfig.java | 5 - .../{main => _archive}/test-3/.gitignore | 0 .../{main => _archive}/test-3/expected | 0 .../{main => _archive}/test-3/input | 0 .../{main => _archive}/test-3/pre-test.sh | 0 .../{main => _archive}/test-7/delete.sh | 0 .../{main => _archive}/test-7/deploy.sh | 0 .../{main => _archive}/test-7/expected | 0 .../{main => _archive}/test-7/pre-test.sh | 0 .../{main => _archive}/test-7/run-test.sh | 0 pom.xml | 5 +- .../fn/runtime/DefaultMethodWrapper.java | 2 +- .../com/fnproject/fn/runtime/EntryPoint.java | 3 +- .../fn/runtime/FunctionConfigurer.java | 4 +- .../fn/runtime/FunctionRuntimeContext.java | 30 +--- .../fn/runtime/MethodFunctionInvoker.java | 2 +- .../fn/runtime/MethodTypeWrapper.java | 2 +- .../fn/runtime/QueryParametersParser.java | 2 +- .../fnproject/fn/runtime/flow/APIModel.java | 2 +- .../runtime/flow/FlowContinuationInvoker.java | 3 +- .../runtime/flow/RemoteBlobStoreClient.java | 1 - .../fn/runtime/DefaultEventCodecTest.java | 2 +- .../fn/runtime/JacksonCoercionTest.java | 5 +- .../fn/runtime/MethodWrapperTests.java | 1 - .../fn/runtime/QueryParametersParserTest.java | 5 +- .../flow/FlowsContinuationInvokerTest.java | 5 +- .../CustomDataBindingFnInputOutput.java | 2 +- .../CustomDataBindingFnWithAnnotation.java | 2 - ...mDataBindingFnWithAnnotationAndConfig.java | 3 +- .../CustomDataBindingFnWithConfig.java | 1 - .../CustomDataBindingFnWithDudCoercion.java | 1 - ...tomDataBindingFnWithMultipleCoercions.java | 3 +- ...ustomDataBindingFnWithNoUserCoersions.java | 2 +- ...stomOutputDataBindingFnWithAnnotation.java | 2 +- .../CustomOutputDataBindingFnWithConfig.java | 3 +- ...tomOutputDataBindingFnWithDudCoercion.java | 3 +- ...putDataBindingFnWithMultipleCoercions.java | 2 +- ...utputDataBindingFnWithNoUserCoercions.java | 2 +- .../TestFnWithConfigurationMethods.java | 2 +- .../fn/testing/FnTestingClassLoader.java | 1 - .../fnproject/fn/testing/FnTestingRule.java | 37 +---- .../fn/testing/FnTestingRuleFlowsTest.java | 5 +- .../fn/testing/FnTestingRuleTest.java | 2 - .../fnproject/fn/testing/IntegrationTest.java | 2 - .../fn/testing/MultipleEventsTest.java | 2 - .../fn/testing/WhenCompleteTest.java | 2 - 54 files changed, 117 insertions(+), 190 deletions(-) rename integration-tests/{main => _archive}/test-3/.gitignore (100%) rename integration-tests/{main => _archive}/test-3/expected (100%) rename integration-tests/{main => _archive}/test-3/input (100%) rename integration-tests/{main => _archive}/test-3/pre-test.sh (100%) rename integration-tests/{main => _archive}/test-7/delete.sh (100%) rename integration-tests/{main => _archive}/test-7/deploy.sh (100%) rename integration-tests/{main => _archive}/test-7/expected (100%) rename integration-tests/{main => _archive}/test-7/pre-test.sh (100%) rename integration-tests/{main => _archive}/test-7/run-test.sh (100%) diff --git a/api/src/main/java/com/fnproject/fn/api/flow/FlowFuture.java b/api/src/main/java/com/fnproject/fn/api/flow/FlowFuture.java index da3d5e60..6dd82fdb 100644 --- a/api/src/main/java/com/fnproject/fn/api/flow/FlowFuture.java +++ b/api/src/main/java/com/fnproject/fn/api/flow/FlowFuture.java @@ -1,7 +1,6 @@ package com.fnproject.fn.api.flow; import java.io.Serializable; -import java.util.concurrent.CompletableFuture; import java.util.concurrent.CompletionStage; import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeoutException; diff --git a/api/src/test/java/com/fnproject/fn/api/flow/FlowsTest.java b/api/src/test/java/com/fnproject/fn/api/flow/FlowsTest.java index d8d51d5e..aed5b7eb 100644 --- a/api/src/test/java/com/fnproject/fn/api/flow/FlowsTest.java +++ b/api/src/test/java/com/fnproject/fn/api/flow/FlowsTest.java @@ -1,9 +1,11 @@ package com.fnproject.fn.api.flow; +import org.junit.Test; + import java.lang.reflect.Modifier; + import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertTrue; -import org.junit.Test; public class FlowsTest { public FlowsTest() { diff --git a/examples/async-thumbnails/src/test/java/com/fnproject/fn/examples/ThumbnailsFunctionTest.java b/examples/async-thumbnails/src/test/java/com/fnproject/fn/examples/ThumbnailsFunctionTest.java index 675ca691..a360d866 100644 --- a/examples/async-thumbnails/src/test/java/com/fnproject/fn/examples/ThumbnailsFunctionTest.java +++ b/examples/async-thumbnails/src/test/java/com/fnproject/fn/examples/ThumbnailsFunctionTest.java @@ -1,6 +1,5 @@ package com.fnproject.fn.examples; -import com.fnproject.fn.examples.ThumbnailsFunction; import com.fnproject.fn.testing.FnTestingRule; import com.github.tomakehurst.wiremock.client.WireMock; import com.github.tomakehurst.wiremock.junit.WireMockRule; @@ -11,91 +10,91 @@ public class ThumbnailsFunctionTest { - @Rule - public final FnTestingRule testing = FnTestingRule.createDefault(); + @Rule + public final FnTestingRule testing = FnTestingRule.createDefault(); - @Rule - public final WireMockRule mockServer = new WireMockRule(0); + @Rule + public final WireMockRule mockServer = new WireMockRule(0); - @Test - public void testThumbnail() { - testing + @Test + public void testThumbnail() { + testing - .setConfig("OBJECT_STORAGE_URL", "http://localhost:" + mockServer.port()) - .setConfig("OBJECT_STORAGE_ACCESS", "alpha") - .setConfig("OBJECT_STORAGE_SECRET", "betabetabetabeta") + .setConfig("OBJECT_STORAGE_URL", "http://localhost:" + mockServer.port()) + .setConfig("OBJECT_STORAGE_ACCESS", "alpha") + .setConfig("OBJECT_STORAGE_SECRET", "betabetabetabeta") - .givenFn("myapp/resize128") - .withAction((data) -> "128".getBytes()) - .givenFn("myapp/resize256") - .withAction((data) -> "256".getBytes()) - .givenFn("myapp/resize512") - .withAction((data) -> "512".getBytes()) + .givenFn("myapp/resize128") + .withAction((data) -> "128".getBytes()) + .givenFn("myapp/resize256") + .withAction((data) -> "256".getBytes()) + .givenFn("myapp/resize512") + .withAction((data) -> "512".getBytes()) - .givenEvent() - .withBody("testing".getBytes()) - .enqueue(); + .givenEvent() + .withBody("testing".getBytes()) + .enqueue(); - // Mock the http endpoint - mockMinio(); + // Mock the http endpoint + mockMinio(); - testing.thenRun(ThumbnailsFunction.class, "handleRequest"); + testing.thenRun(ThumbnailsFunction.class, "handleRequest"); - // Check the final image uploads were performed - mockServer.verify(1, putRequestedFor(urlMatching("/alpha/.*\\.png")).withRequestBody(equalTo("testing"))); - mockServer.verify(1, putRequestedFor(urlMatching("/alpha/.*\\.png")).withRequestBody(equalTo("128"))); - mockServer.verify(1, putRequestedFor(urlMatching("/alpha/.*\\.png")).withRequestBody(equalTo("256"))); - mockServer.verify(1, putRequestedFor(urlMatching("/alpha/.*\\.png")).withRequestBody(equalTo("512"))); - mockServer.verify(4, putRequestedFor(urlMatching(".*"))); - } + // Check the final image uploads were performed + mockServer.verify(1, putRequestedFor(urlMatching("/alpha/.*\\.png")).withRequestBody(equalTo("testing"))); + mockServer.verify(1, putRequestedFor(urlMatching("/alpha/.*\\.png")).withRequestBody(equalTo("128"))); + mockServer.verify(1, putRequestedFor(urlMatching("/alpha/.*\\.png")).withRequestBody(equalTo("256"))); + mockServer.verify(1, putRequestedFor(urlMatching("/alpha/.*\\.png")).withRequestBody(equalTo("512"))); + mockServer.verify(4, putRequestedFor(urlMatching(".*"))); + } - @Test - public void anExternalFunctionFailure() { - testing - .setConfig("OBJECT_STORAGE_URL", "http://localhost:" + mockServer.port()) - .setConfig("OBJECT_STORAGE_ACCESS", "alpha") - .setConfig("OBJECT_STORAGE_SECRET", "betabetabetabeta") + @Test + public void anExternalFunctionFailure() { + testing + .setConfig("OBJECT_STORAGE_URL", "http://localhost:" + mockServer.port()) + .setConfig("OBJECT_STORAGE_ACCESS", "alpha") + .setConfig("OBJECT_STORAGE_SECRET", "betabetabetabeta") - .givenFn("myapp/resize128") - .withResult("128".getBytes()) - .givenFn("myapp/resize256") - .withResult("256".getBytes()) - .givenFn("myapp/resize512") - .withFunctionError() + .givenFn("myapp/resize128") + .withResult("128".getBytes()) + .givenFn("myapp/resize256") + .withResult("256".getBytes()) + .givenFn("myapp/resize512") + .withFunctionError() - .givenEvent() - .withBody("testing".getBytes()) - .enqueue(); + .givenEvent() + .withBody("testing".getBytes()) + .enqueue(); - // Mock the http endpoint - mockMinio(); + // Mock the http endpoint + mockMinio(); - testing.thenRun(ThumbnailsFunction.class, "handleRequest"); + testing.thenRun(ThumbnailsFunction.class, "handleRequest"); - // Confirm that one image upload didn't happen - mockServer.verify(0, putRequestedFor(urlMatching("/alpha/.*\\.png")).withRequestBody(equalTo("512"))); + // Confirm that one image upload didn't happen + mockServer.verify(0, putRequestedFor(urlMatching("/alpha/.*\\.png")).withRequestBody(equalTo("512"))); - mockServer.verify(3, putRequestedFor(urlMatching(".*"))); + mockServer.verify(3, putRequestedFor(urlMatching(".*"))); - } + } - private void mockMinio() { + private void mockMinio() { - mockServer.stubFor(get(urlMatching("/alpha.*")) - .willReturn(aResponse().withBody( - "\n" + - "\n" + - " alpha\n" + - " \n" + - " 0\n" + - " 100\n" + - " false\n" + - ""))); + mockServer.stubFor(get(urlMatching("/alpha.*")) + .willReturn(aResponse().withBody( + "\n" + + "\n" + + " alpha\n" + + " \n" + + " 0\n" + + " 100\n" + + " false\n" + + ""))); - mockServer.stubFor(WireMock.head(urlMatching("/alpha.*")).willReturn(aResponse().withStatus(200))); + mockServer.stubFor(WireMock.head(urlMatching("/alpha.*")).willReturn(aResponse().withStatus(200))); - mockServer.stubFor(WireMock.put(urlMatching(".*")).willReturn(aResponse().withStatus(200))); + mockServer.stubFor(WireMock.put(urlMatching(".*")).willReturn(aResponse().withStatus(200))); - } + } } diff --git a/examples/gradle-build/src/test/java/com/example/fn/HelloFunctionTest.java b/examples/gradle-build/src/test/java/com/example/fn/HelloFunctionTest.java index e6b7a5e3..bd46e52d 100644 --- a/examples/gradle-build/src/test/java/com/example/fn/HelloFunctionTest.java +++ b/examples/gradle-build/src/test/java/com/example/fn/HelloFunctionTest.java @@ -1,8 +1,5 @@ package com.example.fn; -import com.fnproject.fn.testing.*; -import org.junit.*; - import static org.junit.Assert.*; public class HelloFunctionTest { diff --git a/examples/qr-code/src/main/java/com/fnproject/fn/examples/QRGen.java b/examples/qr-code/src/main/java/com/fnproject/fn/examples/QRGen.java index a95caa3d..f1ea1fbc 100644 --- a/examples/qr-code/src/main/java/com/fnproject/fn/examples/QRGen.java +++ b/examples/qr-code/src/main/java/com/fnproject/fn/examples/QRGen.java @@ -6,7 +6,6 @@ import net.glxn.qrgen.core.image.ImageType; import net.glxn.qrgen.javase.QRCode; -import java.io.*; import java.net.MalformedURLException; public class QRGen { diff --git a/fn-spring-cloud-function/src/main/java/com/fnproject/springframework/function/SpringCloudFunctionInvoker.java b/fn-spring-cloud-function/src/main/java/com/fnproject/springframework/function/SpringCloudFunctionInvoker.java index bca11b33..5182abc8 100644 --- a/fn-spring-cloud-function/src/main/java/com/fnproject/springframework/function/SpringCloudFunctionInvoker.java +++ b/fn-spring-cloud-function/src/main/java/com/fnproject/springframework/function/SpringCloudFunctionInvoker.java @@ -1,11 +1,6 @@ package com.fnproject.springframework.function; -import com.fnproject.fn.api.FunctionInvoker; -import com.fnproject.fn.api.InputEvent; -import com.fnproject.fn.api.InvocationContext; -import com.fnproject.fn.api.MethodWrapper; -import com.fnproject.fn.api.OutputEvent; -import com.fnproject.fn.api.RuntimeContext; +import com.fnproject.fn.api.*; import com.fnproject.fn.api.exception.FunctionInputHandlingException; import com.fnproject.fn.api.exception.FunctionOutputHandlingException; import com.fnproject.springframework.function.functions.SpringCloudMethod; diff --git a/fn-spring-cloud-function/src/main/java/com/fnproject/springframework/function/functions/SpringCloudFunction.java b/fn-spring-cloud-function/src/main/java/com/fnproject/springframework/function/functions/SpringCloudFunction.java index e7cc1bd5..b826cb84 100644 --- a/fn-spring-cloud-function/src/main/java/com/fnproject/springframework/function/functions/SpringCloudFunction.java +++ b/fn-spring-cloud-function/src/main/java/com/fnproject/springframework/function/functions/SpringCloudFunction.java @@ -3,7 +3,6 @@ import org.springframework.cloud.function.context.FunctionInspector; import reactor.core.publisher.Flux; -import java.util.function.Consumer; import java.util.function.Function; /** diff --git a/fn-spring-cloud-function/src/main/java/com/fnproject/springframework/function/functions/SpringCloudSupplier.java b/fn-spring-cloud-function/src/main/java/com/fnproject/springframework/function/functions/SpringCloudSupplier.java index 182d708b..03fae76b 100644 --- a/fn-spring-cloud-function/src/main/java/com/fnproject/springframework/function/functions/SpringCloudSupplier.java +++ b/fn-spring-cloud-function/src/main/java/com/fnproject/springframework/function/functions/SpringCloudSupplier.java @@ -5,7 +5,6 @@ import org.springframework.cloud.function.context.FunctionInspector; import reactor.core.publisher.Flux; -import java.util.function.Consumer; import java.util.function.Supplier; /** diff --git a/fn-spring-cloud-function/src/test/java/com/fnproject/springframework/function/testfns/EmptyFunctionConfig.java b/fn-spring-cloud-function/src/test/java/com/fnproject/springframework/function/testfns/EmptyFunctionConfig.java index a6444bc2..35630007 100644 --- a/fn-spring-cloud-function/src/test/java/com/fnproject/springframework/function/testfns/EmptyFunctionConfig.java +++ b/fn-spring-cloud-function/src/test/java/com/fnproject/springframework/function/testfns/EmptyFunctionConfig.java @@ -4,14 +4,9 @@ import com.fnproject.fn.api.RuntimeContext; import com.fnproject.springframework.function.SpringCloudFunctionInvoker; import org.springframework.cloud.function.context.ContextFunctionCatalogAutoConfiguration; -import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.Import; -import java.util.function.Consumer; -import java.util.function.Function; -import java.util.function.Supplier; - @Configuration @Import(ContextFunctionCatalogAutoConfiguration.class) public class EmptyFunctionConfig { diff --git a/integration-tests/main/test-3/.gitignore b/integration-tests/_archive/test-3/.gitignore similarity index 100% rename from integration-tests/main/test-3/.gitignore rename to integration-tests/_archive/test-3/.gitignore diff --git a/integration-tests/main/test-3/expected b/integration-tests/_archive/test-3/expected similarity index 100% rename from integration-tests/main/test-3/expected rename to integration-tests/_archive/test-3/expected diff --git a/integration-tests/main/test-3/input b/integration-tests/_archive/test-3/input similarity index 100% rename from integration-tests/main/test-3/input rename to integration-tests/_archive/test-3/input diff --git a/integration-tests/main/test-3/pre-test.sh b/integration-tests/_archive/test-3/pre-test.sh similarity index 100% rename from integration-tests/main/test-3/pre-test.sh rename to integration-tests/_archive/test-3/pre-test.sh diff --git a/integration-tests/main/test-7/delete.sh b/integration-tests/_archive/test-7/delete.sh similarity index 100% rename from integration-tests/main/test-7/delete.sh rename to integration-tests/_archive/test-7/delete.sh diff --git a/integration-tests/main/test-7/deploy.sh b/integration-tests/_archive/test-7/deploy.sh similarity index 100% rename from integration-tests/main/test-7/deploy.sh rename to integration-tests/_archive/test-7/deploy.sh diff --git a/integration-tests/main/test-7/expected b/integration-tests/_archive/test-7/expected similarity index 100% rename from integration-tests/main/test-7/expected rename to integration-tests/_archive/test-7/expected diff --git a/integration-tests/main/test-7/pre-test.sh b/integration-tests/_archive/test-7/pre-test.sh similarity index 100% rename from integration-tests/main/test-7/pre-test.sh rename to integration-tests/_archive/test-7/pre-test.sh diff --git a/integration-tests/main/test-7/run-test.sh b/integration-tests/_archive/test-7/run-test.sh similarity index 100% rename from integration-tests/main/test-7/run-test.sh rename to integration-tests/_archive/test-7/run-test.sh diff --git a/pom.xml b/pom.xml index eb1cd0d5..9bf34830 100644 --- a/pom.xml +++ b/pom.xml @@ -11,12 +11,13 @@ api runtime - fn-spring-cloud-function testing-core testing-junit4 testing - examples integration-tests + + fn-spring-cloud-function + examples diff --git a/runtime/src/main/java/com/fnproject/fn/runtime/DefaultMethodWrapper.java b/runtime/src/main/java/com/fnproject/fn/runtime/DefaultMethodWrapper.java index 8d81dd47..20fc0f97 100644 --- a/runtime/src/main/java/com/fnproject/fn/runtime/DefaultMethodWrapper.java +++ b/runtime/src/main/java/com/fnproject/fn/runtime/DefaultMethodWrapper.java @@ -1,7 +1,7 @@ package com.fnproject.fn.runtime; -import com.fnproject.fn.api.TypeWrapper; import com.fnproject.fn.api.MethodWrapper; +import com.fnproject.fn.api.TypeWrapper; import java.lang.reflect.Method; import java.util.Arrays; diff --git a/runtime/src/main/java/com/fnproject/fn/runtime/EntryPoint.java b/runtime/src/main/java/com/fnproject/fn/runtime/EntryPoint.java index 6c5856a7..834273ee 100644 --- a/runtime/src/main/java/com/fnproject/fn/runtime/EntryPoint.java +++ b/runtime/src/main/java/com/fnproject/fn/runtime/EntryPoint.java @@ -6,7 +6,8 @@ import com.fnproject.fn.api.exception.FunctionInputHandlingException; import com.fnproject.fn.api.exception.FunctionLoadException; import com.fnproject.fn.api.exception.FunctionOutputHandlingException; -import com.fnproject.fn.runtime.exception.*; +import com.fnproject.fn.runtime.exception.InternalFunctionInvocationException; +import com.fnproject.fn.runtime.exception.InvalidEntryPointException; import java.io.IOException; import java.io.InputStream; diff --git a/runtime/src/main/java/com/fnproject/fn/runtime/FunctionConfigurer.java b/runtime/src/main/java/com/fnproject/fn/runtime/FunctionConfigurer.java index e61934ab..6a80408b 100644 --- a/runtime/src/main/java/com/fnproject/fn/runtime/FunctionConfigurer.java +++ b/runtime/src/main/java/com/fnproject/fn/runtime/FunctionConfigurer.java @@ -7,7 +7,9 @@ import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; import java.lang.reflect.Modifier; -import java.util.*; +import java.util.Arrays; +import java.util.Comparator; +import java.util.Optional; /** * Loads function entry points based on their class name and method name creating a {@link FunctionRuntimeContext} diff --git a/runtime/src/main/java/com/fnproject/fn/runtime/FunctionRuntimeContext.java b/runtime/src/main/java/com/fnproject/fn/runtime/FunctionRuntimeContext.java index 1425b7f0..83623335 100644 --- a/runtime/src/main/java/com/fnproject/fn/runtime/FunctionRuntimeContext.java +++ b/runtime/src/main/java/com/fnproject/fn/runtime/FunctionRuntimeContext.java @@ -1,24 +1,11 @@ package com.fnproject.fn.runtime; -import com.fnproject.fn.api.FunctionInvoker; -import com.fnproject.fn.api.InputBinding; -import com.fnproject.fn.api.InputCoercion; -import com.fnproject.fn.api.InputEvent; -import com.fnproject.fn.api.InvocationContext; -import com.fnproject.fn.api.MethodWrapper; -import com.fnproject.fn.api.OutputBinding; -import com.fnproject.fn.api.OutputCoercion; -import com.fnproject.fn.api.OutputEvent; -import com.fnproject.fn.api.RuntimeContext; -import com.fnproject.fn.runtime.coercion.ByteArrayCoercion; -import com.fnproject.fn.runtime.coercion.InputEventCoercion; -import com.fnproject.fn.runtime.coercion.OutputEventCoercion; -import com.fnproject.fn.runtime.coercion.StringCoercion; -import com.fnproject.fn.runtime.coercion.VoidCoercion; -import com.fnproject.fn.runtime.coercion.jackson.JacksonCoercion; -import com.fnproject.fn.runtime.exception.FunctionClassInstantiationException; +import com.fnproject.fn.api.*; import com.fnproject.fn.api.exception.FunctionConfigurationException; import com.fnproject.fn.api.exception.FunctionInputHandlingException; +import com.fnproject.fn.runtime.coercion.*; +import com.fnproject.fn.runtime.coercion.jackson.JacksonCoercion; +import com.fnproject.fn.runtime.exception.FunctionClassInstantiationException; import com.fnproject.fn.runtime.flow.FlowContinuationInvoker; import java.lang.annotation.Annotation; @@ -26,14 +13,7 @@ import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; import java.lang.reflect.Modifier; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.HashMap; -import java.util.LinkedList; -import java.util.List; -import java.util.Map; -import java.util.Objects; -import java.util.Optional; +import java.util.*; public class FunctionRuntimeContext implements RuntimeContext { diff --git a/runtime/src/main/java/com/fnproject/fn/runtime/MethodFunctionInvoker.java b/runtime/src/main/java/com/fnproject/fn/runtime/MethodFunctionInvoker.java index 30f95986..0f46d749 100644 --- a/runtime/src/main/java/com/fnproject/fn/runtime/MethodFunctionInvoker.java +++ b/runtime/src/main/java/com/fnproject/fn/runtime/MethodFunctionInvoker.java @@ -3,8 +3,8 @@ import com.fnproject.fn.api.*; import com.fnproject.fn.api.exception.FunctionInputHandlingException; -import com.fnproject.fn.runtime.exception.InternalFunctionInvocationException; import com.fnproject.fn.api.exception.FunctionOutputHandlingException; +import com.fnproject.fn.runtime.exception.InternalFunctionInvocationException; import java.lang.reflect.InvocationTargetException; import java.util.Optional; diff --git a/runtime/src/main/java/com/fnproject/fn/runtime/MethodTypeWrapper.java b/runtime/src/main/java/com/fnproject/fn/runtime/MethodTypeWrapper.java index e7743a72..aff98db4 100644 --- a/runtime/src/main/java/com/fnproject/fn/runtime/MethodTypeWrapper.java +++ b/runtime/src/main/java/com/fnproject/fn/runtime/MethodTypeWrapper.java @@ -1,7 +1,7 @@ package com.fnproject.fn.runtime; -import com.fnproject.fn.api.TypeWrapper; import com.fnproject.fn.api.MethodWrapper; +import com.fnproject.fn.api.TypeWrapper; import net.jodah.typetools.TypeResolver; import java.lang.reflect.ParameterizedType; diff --git a/runtime/src/main/java/com/fnproject/fn/runtime/QueryParametersParser.java b/runtime/src/main/java/com/fnproject/fn/runtime/QueryParametersParser.java index 3c1d8f9b..7e73af2f 100644 --- a/runtime/src/main/java/com/fnproject/fn/runtime/QueryParametersParser.java +++ b/runtime/src/main/java/com/fnproject/fn/runtime/QueryParametersParser.java @@ -4,9 +4,9 @@ import java.io.UnsupportedEncodingException; import java.net.URLDecoder; +import java.util.AbstractMap.SimpleImmutableEntry; import java.util.*; import java.util.Map.Entry; -import java.util.AbstractMap.SimpleImmutableEntry; import java.util.stream.Collectors; import static java.util.stream.Collectors.mapping; diff --git a/runtime/src/main/java/com/fnproject/fn/runtime/flow/APIModel.java b/runtime/src/main/java/com/fnproject/fn/runtime/flow/APIModel.java index eea809a9..c5cb2b1b 100644 --- a/runtime/src/main/java/com/fnproject/fn/runtime/flow/APIModel.java +++ b/runtime/src/main/java/com/fnproject/fn/runtime/flow/APIModel.java @@ -5,8 +5,8 @@ import com.fasterxml.jackson.annotation.JsonTypeInfo; import com.fasterxml.jackson.annotation.JsonUnwrapped; import com.fnproject.fn.api.Headers; -import com.fnproject.fn.api.flow.*; import com.fnproject.fn.api.exception.FunctionInputHandlingException; +import com.fnproject.fn.api.flow.*; import com.fnproject.fn.runtime.exception.PlatformCommunicationException; import org.apache.commons.io.IOUtils; diff --git a/runtime/src/main/java/com/fnproject/fn/runtime/flow/FlowContinuationInvoker.java b/runtime/src/main/java/com/fnproject/fn/runtime/flow/FlowContinuationInvoker.java index 81d12f1a..d0dd3443 100644 --- a/runtime/src/main/java/com/fnproject/fn/runtime/flow/FlowContinuationInvoker.java +++ b/runtime/src/main/java/com/fnproject/fn/runtime/flow/FlowContinuationInvoker.java @@ -1,12 +1,11 @@ package com.fnproject.fn.runtime.flow; import com.fasterxml.jackson.core.JsonProcessingException; -import com.fasterxml.jackson.databind.ObjectMapper; import com.fnproject.fn.api.*; +import com.fnproject.fn.api.exception.FunctionInputHandlingException; import com.fnproject.fn.api.flow.Flow; import com.fnproject.fn.api.flow.Flows; import com.fnproject.fn.api.flow.PlatformException; -import com.fnproject.fn.api.exception.FunctionInputHandlingException; import com.fnproject.fn.runtime.exception.InternalFunctionInvocationException; import com.fnproject.fn.runtime.exception.PlatformCommunicationException; diff --git a/runtime/src/main/java/com/fnproject/fn/runtime/flow/RemoteBlobStoreClient.java b/runtime/src/main/java/com/fnproject/fn/runtime/flow/RemoteBlobStoreClient.java index 18f0d644..b4274d93 100644 --- a/runtime/src/main/java/com/fnproject/fn/runtime/flow/RemoteBlobStoreClient.java +++ b/runtime/src/main/java/com/fnproject/fn/runtime/flow/RemoteBlobStoreClient.java @@ -1,6 +1,5 @@ package com.fnproject.fn.runtime.flow; -import com.fasterxml.jackson.databind.ObjectMapper; import com.fnproject.fn.runtime.exception.PlatformCommunicationException; import java.io.IOException; diff --git a/runtime/src/test/java/com/fnproject/fn/runtime/DefaultEventCodecTest.java b/runtime/src/test/java/com/fnproject/fn/runtime/DefaultEventCodecTest.java index d7a501a7..b7992114 100644 --- a/runtime/src/test/java/com/fnproject/fn/runtime/DefaultEventCodecTest.java +++ b/runtime/src/test/java/com/fnproject/fn/runtime/DefaultEventCodecTest.java @@ -1,8 +1,8 @@ package com.fnproject.fn.runtime; -import com.fnproject.fn.api.exception.FunctionInputHandlingException; import com.fnproject.fn.api.InputEvent; import com.fnproject.fn.api.OutputEvent; +import com.fnproject.fn.api.exception.FunctionInputHandlingException; import org.apache.commons.io.input.NullInputStream; import org.apache.commons.io.output.NullOutputStream; import org.junit.Test; diff --git a/runtime/src/test/java/com/fnproject/fn/runtime/JacksonCoercionTest.java b/runtime/src/test/java/com/fnproject/fn/runtime/JacksonCoercionTest.java index 28124dbb..8b62f975 100644 --- a/runtime/src/test/java/com/fnproject/fn/runtime/JacksonCoercionTest.java +++ b/runtime/src/test/java/com/fnproject/fn/runtime/JacksonCoercionTest.java @@ -9,7 +9,10 @@ import org.junit.Test; import java.io.ByteArrayInputStream; -import java.util.*; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Optional; public class JacksonCoercionTest { diff --git a/runtime/src/test/java/com/fnproject/fn/runtime/MethodWrapperTests.java b/runtime/src/test/java/com/fnproject/fn/runtime/MethodWrapperTests.java index 2d4cca57..fb0c6b17 100644 --- a/runtime/src/test/java/com/fnproject/fn/runtime/MethodWrapperTests.java +++ b/runtime/src/test/java/com/fnproject/fn/runtime/MethodWrapperTests.java @@ -8,7 +8,6 @@ import java.util.Arrays; import java.util.Collection; import java.util.List; -import java.util.function.Function; import static org.assertj.core.api.Assertions.assertThat; diff --git a/runtime/src/test/java/com/fnproject/fn/runtime/QueryParametersParserTest.java b/runtime/src/test/java/com/fnproject/fn/runtime/QueryParametersParserTest.java index 2714b449..60d73543 100644 --- a/runtime/src/test/java/com/fnproject/fn/runtime/QueryParametersParserTest.java +++ b/runtime/src/test/java/com/fnproject/fn/runtime/QueryParametersParserTest.java @@ -3,7 +3,10 @@ import com.fnproject.fn.api.QueryParameters; import org.junit.Test; -import java.util.*; +import java.util.Collections; +import java.util.HashMap; +import java.util.List; +import java.util.Map; import static org.assertj.core.api.Assertions.assertThat; diff --git a/runtime/src/test/java/com/fnproject/fn/runtime/flow/FlowsContinuationInvokerTest.java b/runtime/src/test/java/com/fnproject/fn/runtime/flow/FlowsContinuationInvokerTest.java index 389d4e34..99685e6c 100644 --- a/runtime/src/test/java/com/fnproject/fn/runtime/flow/FlowsContinuationInvokerTest.java +++ b/runtime/src/test/java/com/fnproject/fn/runtime/flow/FlowsContinuationInvokerTest.java @@ -3,10 +3,10 @@ import com.fasterxml.jackson.core.JsonProcessingException; import com.fasterxml.jackson.databind.ObjectMapper; import com.fnproject.fn.api.*; +import com.fnproject.fn.api.exception.FunctionInputHandlingException; import com.fnproject.fn.api.flow.*; import com.fnproject.fn.runtime.QueryParametersImpl; import com.fnproject.fn.runtime.ReadOnceInputEvent; -import com.fnproject.fn.api.exception.FunctionInputHandlingException; import com.fnproject.fn.runtime.exception.InternalFunctionInvocationException; import org.junit.After; import org.junit.Before; @@ -15,9 +15,6 @@ import org.junit.rules.ExpectedException; import java.io.*; -import java.io.IOException; -import java.io.InputStream; -import java.io.Serializable; import java.lang.reflect.Method; import java.util.*; diff --git a/runtime/src/test/java/com/fnproject/fn/runtime/testfns/CustomDataBindingFnInputOutput.java b/runtime/src/test/java/com/fnproject/fn/runtime/testfns/CustomDataBindingFnInputOutput.java index b4df6eb0..a5813281 100644 --- a/runtime/src/test/java/com/fnproject/fn/runtime/testfns/CustomDataBindingFnInputOutput.java +++ b/runtime/src/test/java/com/fnproject/fn/runtime/testfns/CustomDataBindingFnInputOutput.java @@ -1,9 +1,9 @@ package com.fnproject.fn.runtime.testfns; +import com.fnproject.fn.api.FnConfiguration; import com.fnproject.fn.api.RuntimeContext; import com.fnproject.fn.runtime.testfns.coercions.StringReversalCoercion; import com.fnproject.fn.runtime.testfns.coercions.StringUpperCaseCoercion; -import com.fnproject.fn.api.FnConfiguration; public class CustomDataBindingFnInputOutput { diff --git a/runtime/src/test/java/com/fnproject/fn/runtime/testfns/CustomDataBindingFnWithAnnotation.java b/runtime/src/test/java/com/fnproject/fn/runtime/testfns/CustomDataBindingFnWithAnnotation.java index 990642a3..a6116aee 100644 --- a/runtime/src/test/java/com/fnproject/fn/runtime/testfns/CustomDataBindingFnWithAnnotation.java +++ b/runtime/src/test/java/com/fnproject/fn/runtime/testfns/CustomDataBindingFnWithAnnotation.java @@ -1,8 +1,6 @@ package com.fnproject.fn.runtime.testfns; import com.fnproject.fn.api.InputBinding; - - import com.fnproject.fn.runtime.testfns.coercions.StringReversalCoercion; public class CustomDataBindingFnWithAnnotation { diff --git a/runtime/src/test/java/com/fnproject/fn/runtime/testfns/CustomDataBindingFnWithAnnotationAndConfig.java b/runtime/src/test/java/com/fnproject/fn/runtime/testfns/CustomDataBindingFnWithAnnotationAndConfig.java index a85d9c91..59691b8d 100644 --- a/runtime/src/test/java/com/fnproject/fn/runtime/testfns/CustomDataBindingFnWithAnnotationAndConfig.java +++ b/runtime/src/test/java/com/fnproject/fn/runtime/testfns/CustomDataBindingFnWithAnnotationAndConfig.java @@ -1,9 +1,8 @@ package com.fnproject.fn.runtime.testfns; -import com.fnproject.fn.api.RuntimeContext; import com.fnproject.fn.api.FnConfiguration; import com.fnproject.fn.api.InputBinding; - +import com.fnproject.fn.api.RuntimeContext; import com.fnproject.fn.runtime.testfns.coercions.StringReversalCoercion; import com.fnproject.fn.runtime.testfns.coercions.StringUpperCaseCoercion; diff --git a/runtime/src/test/java/com/fnproject/fn/runtime/testfns/CustomDataBindingFnWithConfig.java b/runtime/src/test/java/com/fnproject/fn/runtime/testfns/CustomDataBindingFnWithConfig.java index 7c5b1e75..5117d0ed 100644 --- a/runtime/src/test/java/com/fnproject/fn/runtime/testfns/CustomDataBindingFnWithConfig.java +++ b/runtime/src/test/java/com/fnproject/fn/runtime/testfns/CustomDataBindingFnWithConfig.java @@ -1,7 +1,6 @@ package com.fnproject.fn.runtime.testfns; import com.fnproject.fn.api.FnConfiguration; - import com.fnproject.fn.api.RuntimeContext; import com.fnproject.fn.runtime.testfns.coercions.StringReversalCoercion; diff --git a/runtime/src/test/java/com/fnproject/fn/runtime/testfns/CustomDataBindingFnWithDudCoercion.java b/runtime/src/test/java/com/fnproject/fn/runtime/testfns/CustomDataBindingFnWithDudCoercion.java index 1ccf8281..9e13224c 100644 --- a/runtime/src/test/java/com/fnproject/fn/runtime/testfns/CustomDataBindingFnWithDudCoercion.java +++ b/runtime/src/test/java/com/fnproject/fn/runtime/testfns/CustomDataBindingFnWithDudCoercion.java @@ -2,7 +2,6 @@ import com.fnproject.fn.api.FnConfiguration; import com.fnproject.fn.api.RuntimeContext; - import com.fnproject.fn.runtime.testfns.coercions.DudCoercion; import com.fnproject.fn.runtime.testfns.coercions.StringReversalCoercion; diff --git a/runtime/src/test/java/com/fnproject/fn/runtime/testfns/CustomDataBindingFnWithMultipleCoercions.java b/runtime/src/test/java/com/fnproject/fn/runtime/testfns/CustomDataBindingFnWithMultipleCoercions.java index 9b881a88..cb7d35db 100644 --- a/runtime/src/test/java/com/fnproject/fn/runtime/testfns/CustomDataBindingFnWithMultipleCoercions.java +++ b/runtime/src/test/java/com/fnproject/fn/runtime/testfns/CustomDataBindingFnWithMultipleCoercions.java @@ -1,8 +1,7 @@ package com.fnproject.fn.runtime.testfns; -import com.fnproject.fn.api.RuntimeContext; import com.fnproject.fn.api.FnConfiguration; - +import com.fnproject.fn.api.RuntimeContext; import com.fnproject.fn.runtime.testfns.coercions.StringReversalCoercion; import com.fnproject.fn.runtime.testfns.coercions.StringUpperCaseCoercion; diff --git a/runtime/src/test/java/com/fnproject/fn/runtime/testfns/CustomDataBindingFnWithNoUserCoersions.java b/runtime/src/test/java/com/fnproject/fn/runtime/testfns/CustomDataBindingFnWithNoUserCoersions.java index 9dad4a3d..e94b28c6 100644 --- a/runtime/src/test/java/com/fnproject/fn/runtime/testfns/CustomDataBindingFnWithNoUserCoersions.java +++ b/runtime/src/test/java/com/fnproject/fn/runtime/testfns/CustomDataBindingFnWithNoUserCoersions.java @@ -1,7 +1,7 @@ package com.fnproject.fn.runtime.testfns; -import com.fnproject.fn.api.RuntimeContext; import com.fnproject.fn.api.FnConfiguration; +import com.fnproject.fn.api.RuntimeContext; public class CustomDataBindingFnWithNoUserCoersions { diff --git a/runtime/src/test/java/com/fnproject/fn/runtime/testfns/CustomOutputDataBindingFnWithAnnotation.java b/runtime/src/test/java/com/fnproject/fn/runtime/testfns/CustomOutputDataBindingFnWithAnnotation.java index 089b461d..738ff335 100644 --- a/runtime/src/test/java/com/fnproject/fn/runtime/testfns/CustomOutputDataBindingFnWithAnnotation.java +++ b/runtime/src/test/java/com/fnproject/fn/runtime/testfns/CustomOutputDataBindingFnWithAnnotation.java @@ -1,7 +1,7 @@ package com.fnproject.fn.runtime.testfns; -import com.fnproject.fn.runtime.testfns.coercions.StringReversalCoercion; import com.fnproject.fn.api.OutputBinding; +import com.fnproject.fn.runtime.testfns.coercions.StringReversalCoercion; public class CustomOutputDataBindingFnWithAnnotation { diff --git a/runtime/src/test/java/com/fnproject/fn/runtime/testfns/CustomOutputDataBindingFnWithConfig.java b/runtime/src/test/java/com/fnproject/fn/runtime/testfns/CustomOutputDataBindingFnWithConfig.java index ce8dbc75..63af1473 100644 --- a/runtime/src/test/java/com/fnproject/fn/runtime/testfns/CustomOutputDataBindingFnWithConfig.java +++ b/runtime/src/test/java/com/fnproject/fn/runtime/testfns/CustomOutputDataBindingFnWithConfig.java @@ -1,8 +1,7 @@ package com.fnproject.fn.runtime.testfns; -import com.fnproject.fn.api.RuntimeContext; import com.fnproject.fn.api.FnConfiguration; - +import com.fnproject.fn.api.RuntimeContext; import com.fnproject.fn.runtime.testfns.coercions.StringReversalCoercion; diff --git a/runtime/src/test/java/com/fnproject/fn/runtime/testfns/CustomOutputDataBindingFnWithDudCoercion.java b/runtime/src/test/java/com/fnproject/fn/runtime/testfns/CustomOutputDataBindingFnWithDudCoercion.java index b4963004..072e23c9 100644 --- a/runtime/src/test/java/com/fnproject/fn/runtime/testfns/CustomOutputDataBindingFnWithDudCoercion.java +++ b/runtime/src/test/java/com/fnproject/fn/runtime/testfns/CustomOutputDataBindingFnWithDudCoercion.java @@ -1,8 +1,7 @@ package com.fnproject.fn.runtime.testfns; -import com.fnproject.fn.api.RuntimeContext; import com.fnproject.fn.api.FnConfiguration; - +import com.fnproject.fn.api.RuntimeContext; import com.fnproject.fn.runtime.testfns.coercions.DudCoercion; import com.fnproject.fn.runtime.testfns.coercions.StringReversalCoercion; diff --git a/runtime/src/test/java/com/fnproject/fn/runtime/testfns/CustomOutputDataBindingFnWithMultipleCoercions.java b/runtime/src/test/java/com/fnproject/fn/runtime/testfns/CustomOutputDataBindingFnWithMultipleCoercions.java index 9f194366..8b2f36d5 100644 --- a/runtime/src/test/java/com/fnproject/fn/runtime/testfns/CustomOutputDataBindingFnWithMultipleCoercions.java +++ b/runtime/src/test/java/com/fnproject/fn/runtime/testfns/CustomOutputDataBindingFnWithMultipleCoercions.java @@ -1,7 +1,7 @@ package com.fnproject.fn.runtime.testfns; -import com.fnproject.fn.api.RuntimeContext; import com.fnproject.fn.api.FnConfiguration; +import com.fnproject.fn.api.RuntimeContext; import com.fnproject.fn.runtime.testfns.coercions.StringReversalCoercion; import com.fnproject.fn.runtime.testfns.coercions.StringUpperCaseCoercion; diff --git a/runtime/src/test/java/com/fnproject/fn/runtime/testfns/CustomOutputDataBindingFnWithNoUserCoercions.java b/runtime/src/test/java/com/fnproject/fn/runtime/testfns/CustomOutputDataBindingFnWithNoUserCoercions.java index c62934d1..39b1ec80 100644 --- a/runtime/src/test/java/com/fnproject/fn/runtime/testfns/CustomOutputDataBindingFnWithNoUserCoercions.java +++ b/runtime/src/test/java/com/fnproject/fn/runtime/testfns/CustomOutputDataBindingFnWithNoUserCoercions.java @@ -1,7 +1,7 @@ package com.fnproject.fn.runtime.testfns; -import com.fnproject.fn.api.RuntimeContext; import com.fnproject.fn.api.FnConfiguration; +import com.fnproject.fn.api.RuntimeContext; public class CustomOutputDataBindingFnWithNoUserCoercions { diff --git a/runtime/src/test/java/com/fnproject/fn/runtime/testfns/TestFnWithConfigurationMethods.java b/runtime/src/test/java/com/fnproject/fn/runtime/testfns/TestFnWithConfigurationMethods.java index 3c69ac64..a6e28862 100644 --- a/runtime/src/test/java/com/fnproject/fn/runtime/testfns/TestFnWithConfigurationMethods.java +++ b/runtime/src/test/java/com/fnproject/fn/runtime/testfns/TestFnWithConfigurationMethods.java @@ -1,7 +1,7 @@ package com.fnproject.fn.runtime.testfns; -import com.fnproject.fn.api.RuntimeContext; import com.fnproject.fn.api.FnConfiguration; +import com.fnproject.fn.api.RuntimeContext; import java.util.Map; diff --git a/testing-core/src/main/java/com/fnproject/fn/testing/FnTestingClassLoader.java b/testing-core/src/main/java/com/fnproject/fn/testing/FnTestingClassLoader.java index ba3dc085..ca6dffcd 100644 --- a/testing-core/src/main/java/com/fnproject/fn/testing/FnTestingClassLoader.java +++ b/testing-core/src/main/java/com/fnproject/fn/testing/FnTestingClassLoader.java @@ -1,7 +1,6 @@ package com.fnproject.fn.testing; import com.fnproject.fn.runtime.EntryPoint; -import com.fnproject.fn.runtime.flow.CompleterClient; import com.fnproject.fn.runtime.flow.CompleterClientFactory; import com.fnproject.fn.runtime.flow.FlowRuntimeGlobals; import org.apache.commons.io.IOUtils; diff --git a/testing-junit4/src/main/java/com/fnproject/fn/testing/FnTestingRule.java b/testing-junit4/src/main/java/com/fnproject/fn/testing/FnTestingRule.java index d4bd9871..df4a7ff6 100644 --- a/testing-junit4/src/main/java/com/fnproject/fn/testing/FnTestingRule.java +++ b/testing-junit4/src/main/java/com/fnproject/fn/testing/FnTestingRule.java @@ -6,46 +6,19 @@ import com.fnproject.fn.api.InputEvent; import com.fnproject.fn.api.OutputEvent; import com.fnproject.fn.api.QueryParameters; -import com.fnproject.fn.api.flow.Flow; -import com.fnproject.fn.api.flow.FlowCompletionException; -import com.fnproject.fn.api.flow.FunctionInvocationException; -import com.fnproject.fn.api.flow.HttpMethod; -import com.fnproject.fn.api.flow.PlatformException; -import com.fnproject.fn.runtime.flow.APIModel; -import com.fnproject.fn.runtime.flow.BlobResponse; -import com.fnproject.fn.runtime.flow.BlobStoreClient; -import com.fnproject.fn.runtime.flow.CodeLocation; -import com.fnproject.fn.runtime.flow.CompleterClient; -import com.fnproject.fn.runtime.flow.CompleterClientFactory; -import com.fnproject.fn.runtime.flow.CompletionId; -import com.fnproject.fn.runtime.flow.DefaultHttpResponse; -import com.fnproject.fn.runtime.flow.FlowContinuationInvoker; -import com.fnproject.fn.runtime.flow.FlowId; +import com.fnproject.fn.api.flow.*; +import com.fnproject.fn.runtime.flow.*; import org.apache.commons.io.IOUtils; import org.apache.commons.io.output.TeeOutputStream; import org.apache.http.HttpResponse; import org.apache.http.NoHttpResponseException; -import org.apache.http.impl.io.ContentLengthInputStream; -import org.apache.http.impl.io.DefaultHttpResponseParser; -import org.apache.http.impl.io.HttpTransportMetricsImpl; -import org.apache.http.impl.io.IdentityInputStream; -import org.apache.http.impl.io.SessionInputBufferImpl; +import org.apache.http.impl.io.*; import org.junit.rules.TestRule; import org.junit.runner.Description; import org.junit.runners.model.Statement; -import java.io.ByteArrayInputStream; -import java.io.ByteArrayOutputStream; -import java.io.InputStream; -import java.io.PrintStream; -import java.io.SequenceInputStream; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.HashMap; -import java.util.HashSet; -import java.util.List; -import java.util.Map; -import java.util.Set; +import java.io.*; +import java.util.*; import java.util.concurrent.CompletableFuture; import static com.fnproject.fn.runtime.flow.RemoteFlowApiClient.CONTENT_TYPE_HEADER; diff --git a/testing-junit4/src/test/java/junit/com/fnproject/fn/testing/FnTestingRuleFlowsTest.java b/testing-junit4/src/test/java/junit/com/fnproject/fn/testing/FnTestingRuleFlowsTest.java index 3217179e..a3a5b982 100644 --- a/testing-junit4/src/test/java/junit/com/fnproject/fn/testing/FnTestingRuleFlowsTest.java +++ b/testing-junit4/src/test/java/junit/com/fnproject/fn/testing/FnTestingRuleFlowsTest.java @@ -5,7 +5,10 @@ import com.fnproject.fn.api.flow.*; import com.fnproject.fn.testing.FnTestingRule; import org.assertj.core.api.Assertions; -import org.junit.*; +import org.junit.Assert; +import org.junit.Before; +import org.junit.Rule; +import org.junit.Test; import java.io.Serializable; import java.util.Arrays; diff --git a/testing-junit4/src/test/java/junit/com/fnproject/fn/testing/FnTestingRuleTest.java b/testing-junit4/src/test/java/junit/com/fnproject/fn/testing/FnTestingRuleTest.java index 40755524..35d303f8 100644 --- a/testing-junit4/src/test/java/junit/com/fnproject/fn/testing/FnTestingRuleTest.java +++ b/testing-junit4/src/test/java/junit/com/fnproject/fn/testing/FnTestingRuleTest.java @@ -17,8 +17,6 @@ import java.io.InputStream; import java.util.*; -import static org.assertj.core.api.Assertions.assertThat; - public class FnTestingRuleTest { public static Map configuration; diff --git a/testing-junit4/src/test/java/junit/com/fnproject/fn/testing/IntegrationTest.java b/testing-junit4/src/test/java/junit/com/fnproject/fn/testing/IntegrationTest.java index add9b478..2582d470 100644 --- a/testing-junit4/src/test/java/junit/com/fnproject/fn/testing/IntegrationTest.java +++ b/testing-junit4/src/test/java/junit/com/fnproject/fn/testing/IntegrationTest.java @@ -6,8 +6,6 @@ import org.junit.Rule; import org.junit.Test; -import static org.assertj.core.api.Assertions.assertThat; - public class IntegrationTest { @Rule diff --git a/testing-junit4/src/test/java/junit/com/fnproject/fn/testing/MultipleEventsTest.java b/testing-junit4/src/test/java/junit/com/fnproject/fn/testing/MultipleEventsTest.java index 5c06937f..bd494797 100644 --- a/testing-junit4/src/test/java/junit/com/fnproject/fn/testing/MultipleEventsTest.java +++ b/testing-junit4/src/test/java/junit/com/fnproject/fn/testing/MultipleEventsTest.java @@ -9,8 +9,6 @@ import java.util.concurrent.Semaphore; -import static org.assertj.core.api.Assertions.assertThat; - public class MultipleEventsTest { @Rule public FnTestingRule fn = FnTestingRule.createDefault(); diff --git a/testing-junit4/src/test/java/junit/com/fnproject/fn/testing/WhenCompleteTest.java b/testing-junit4/src/test/java/junit/com/fnproject/fn/testing/WhenCompleteTest.java index 141534ae..2f87670f 100644 --- a/testing-junit4/src/test/java/junit/com/fnproject/fn/testing/WhenCompleteTest.java +++ b/testing-junit4/src/test/java/junit/com/fnproject/fn/testing/WhenCompleteTest.java @@ -8,8 +8,6 @@ import java.util.concurrent.atomic.AtomicInteger; -import static org.assertj.core.api.Assertions.assertThat; - public class WhenCompleteTest { @Rule public FnTestingRule fn = FnTestingRule.createDefault(); From e2cbfe36cb1659f52ec1257311be63308c0d5db1 Mon Sep 17 00:00:00 2001 From: CI Date: Mon, 30 Jul 2018 13:13:03 +0000 Subject: [PATCH 028/310] fn-java-fdk: post-1.0.64 version bump [skip ci] --- release.version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/release.version b/release.version index e1d2f8b7..7b8d6b72 100644 --- a/release.version +++ b/release.version @@ -1 +1 @@ -1.0.64 +1.0.65 From 6d5484ba90fcfc7fdd12b54fef02726b28378b87 Mon Sep 17 00:00:00 2001 From: Sven Ruppert Date: Tue, 31 Jul 2018 07:07:20 +0200 Subject: [PATCH 029/310] pom.xml files - refactoring --- api/pom.xml | 14 -- build-image/pom.xml | 4 +- examples/async-thumbnails/pom.xml | 2 + examples/pom.xml | 5 - examples/regex-query/pom.xml | 2 + examples/string-reverse/pom.xml | 2 + fn-spring-cloud-function/pom.xml | 10 - pom.xml | 382 +++++++++++++++++++++--------- runtime/pom.xml | 25 -- testing-core/pom.xml | 14 -- testing-junit4/pom.xml | 12 +- testing/pom.xml | 29 --- 12 files changed, 279 insertions(+), 222 deletions(-) diff --git a/api/pom.xml b/api/pom.xml index 224d57d5..2e6a8778 100644 --- a/api/pom.xml +++ b/api/pom.xml @@ -9,10 +9,6 @@ 4.0.0 - - UTF-8 - - api @@ -20,7 +16,6 @@ org.apache.maven.plugins maven-javadoc-plugin - 3.0.0-M1 attach-javadocs @@ -33,7 +28,6 @@ org.netbeans.tools sigtest-maven-plugin - 1.0 @@ -49,12 +43,4 @@ - - - junit - junit - 4.12 - test - - diff --git a/build-image/pom.xml b/build-image/pom.xml index c423d383..8a1196f6 100644 --- a/build-image/pom.xml +++ b/build-image/pom.xml @@ -7,6 +7,8 @@ UTF-8 + UTF-8 + 1.0.0-SNAPSHOT http://172.17.0.1:18080 @@ -47,7 +49,7 @@ org.apache.maven.plugins maven-compiler-plugin - 3.3 + 3.7.0 1.8 1.8 diff --git a/examples/async-thumbnails/pom.xml b/examples/async-thumbnails/pom.xml index c1c5b041..09d9f31c 100644 --- a/examples/async-thumbnails/pom.xml +++ b/examples/async-thumbnails/pom.xml @@ -6,6 +6,8 @@ UTF-8 + UTF-8 + 1.0.0-SNAPSHOT 2.8.47 diff --git a/examples/pom.xml b/examples/pom.xml index 219291f4..c00977ea 100644 --- a/examples/pom.xml +++ b/examples/pom.xml @@ -13,10 +13,6 @@ 1.0.0-SNAPSHOT - - UTF-8 - - string-reverse regex-query @@ -31,7 +27,6 @@ org.apache.maven.plugins maven-deploy-plugin - 2.8.2 true diff --git a/examples/regex-query/pom.xml b/examples/regex-query/pom.xml index 11d406d8..667400ad 100644 --- a/examples/regex-query/pom.xml +++ b/examples/regex-query/pom.xml @@ -6,6 +6,8 @@ UTF-8 + UTF-8 + 1.0.0-SNAPSHOT 2.9.6 diff --git a/examples/string-reverse/pom.xml b/examples/string-reverse/pom.xml index 4c380ea1..e299d510 100644 --- a/examples/string-reverse/pom.xml +++ b/examples/string-reverse/pom.xml @@ -7,6 +7,8 @@ UTF-8 + UTF-8 + com.fnproject.fn.examples diff --git a/fn-spring-cloud-function/pom.xml b/fn-spring-cloud-function/pom.xml index dc7e77c3..c2e553a5 100644 --- a/fn-spring-cloud-function/pom.xml +++ b/fn-spring-cloud-function/pom.xml @@ -12,7 +12,6 @@ fn-spring-cloud-function - UTF-8 1.0.0.M6 @@ -21,7 +20,6 @@ com.fnproject.fn api - ${project.version} @@ -39,47 +37,39 @@ net.jodah typetools - 0.5.0 com.fnproject.fn testing-core - ${project.version} test com.fnproject.fn testing-junit4 - ${project.version} test - org.mockito mockito-core - ${mockito.version} test org.assertj assertj-core - ${assertj-core.version} test junit junit - ${junit.version} test commons-logging commons-logging - 1.1.1 test diff --git a/pom.xml b/pom.xml index 81b17e4c..d8af32ad 100644 --- a/pom.xml +++ b/pom.xml @@ -1,118 +1,274 @@ - 4.0.0 - - fdk - com.fnproject.fn - pom - 1.0.0-SNAPSHOT - - api - runtime - testing-core - testing-junit4 - testing - integration-tests - - fn-spring-cloud-function - examples - - - - UTF-8 - 0.7.9 - 1.7.25 - 2.5 - 2.9.6 - 2.8.47 - 3.6.2 - 4.4.6 - - 1.16.0 - 4.12 - - - + xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> + 4.0.0 + + fdk + com.fnproject.fn + pom + 1.0.0-SNAPSHOT + + + + api + runtime + testing-core + testing-junit4 + testing + integration-tests + + fn-spring-cloud-function + examples + + + + UTF-8 + UTF-8 + + + + 0.8.1 + 4.12 + 2.8.47 + 3.6.2 + 1.4.0 + + 1.7.25 + + 2.5 + 2.9.6 + 4.4.6 + + 1.16.0 + + + + + + + + + com.fnproject.fn + api + ${project.version} + + + com.fnproject.fn + runtime + ${project.version} + + + com.fnproject.fn + testing-core + ${project.version} + + + com.fnproject.fn + testing-junit4 + ${project.version} + + + + com.fasterxml.jackson.core + jackson-databind + ${jackson.version} + + + org.apache.httpcomponents + httpcore + ${httpcore.version} + + + org.apache.httpcomponents + httpmime + 4.5.3 + + + commons-io + commons-io + ${commons-io.version} + + + commons-logging + commons-logging + 1.1.1 + + + net.jodah + typetools + 0.5.0 + + + + + org.mockito + mockito-core + ${mockito.version} + test + + + org.assertj + assertj-core + ${assertj-core.version} + test + + + junit + junit + ${junit.version} + test + + + + + + + + junit + junit + test + + + org.assertj + assertj-core + test + + + + + + + + org.apache.maven.plugins + maven-javadoc-plugin + 3.0.0 + + + org.apache.maven.plugins + maven-deploy-plugin + 2.8.2 + + + maven-dependency-plugin + 3.1.1 + + + org.netbeans.tools + sigtest-maven-plugin + 1.0 + + + org.pitest + pitest-maven + ${pitest.version} + + + + + + org.apache.maven.plugins + maven-compiler-plugin + 3.6.1 + + javac-with-errorprone + true + 1.8 + 1.8 + + + + org.codehaus.plexus + plexus-compiler-javac-errorprone + 2.8.4 + + + com.google.errorprone + error_prone_core + 2.3.1 + + + + + org.apache.maven.plugins + maven-source-plugin + 3.0.0 + + + attach-sources + + jar + + + + + + org.jacoco + jacoco-maven-plugin + ${jacoco.version} + + + prepare-agent + + prepare-agent + + + + report + prepare-package + + report + + + + post-unit-test + test + + report + + + + + target/jacoco.exec + + target/jacoco-ut + + + + + + + org.pitest + pitest-maven + ${pitest.version} + + + + + + com.spotify + dockerfile-maven-extension + 1.3.1 + + + + + + + + _qm-qs + + false + + - - org.apache.maven.plugins - maven-compiler-plugin - 3.6.1 - - javac-with-errorprone - true - 1.8 - 1.8 - - - - org.codehaus.plexus - plexus-compiler-javac-errorprone - 2.8 - - - com.google.errorprone - error_prone_core - 2.0.21 - - - - - org.apache.maven.plugins - maven-source-plugin - 3.0.0 - - - attach-sources - - jar - - - - - - org.jacoco - jacoco-maven-plugin - ${jacoco.version} - - - prepare-agent - - prepare-agent - - - - report - prepare-package - - report - - - - post-unit-test - test - - report - - - - - target/jacoco.exec - - target/jacoco-ut - - - - + + org.codehaus.mojo + versions-maven-plugin + 2.5 + - - - com.spotify - dockerfile-maven-extension - 1.3.1 - - - + + + diff --git a/runtime/pom.xml b/runtime/pom.xml index 89800faa..f02159c9 100644 --- a/runtime/pom.xml +++ b/runtime/pom.xml @@ -11,67 +11,43 @@ runtime - - UTF-8 - - - com.fnproject.fn api - ${project.version} - com.fasterxml.jackson.core jackson-databind - ${jackson.version} - org.apache.httpcomponents httpcore - ${httpcore.version} commons-io commons-io - ${commons-io.version} net.jodah typetools - 0.5.0 org.mockito mockito-core - ${mockito.version} test - org.assertj assertj-core - ${assertj-core.version} test - - - junit - junit - 4.12 - test - - org.apache.httpcomponents httpmime - 4.5.3 test @@ -81,7 +57,6 @@ maven-dependency-plugin - 3.0.1 copy-dependencies diff --git a/testing-core/pom.xml b/testing-core/pom.xml index 3ad3aac8..62f22357 100644 --- a/testing-core/pom.xml +++ b/testing-core/pom.xml @@ -11,24 +11,10 @@ testing-core - - com.fnproject.fn runtime - ${project.version} - - - junit - junit - ${junit.version} - - - org.assertj - assertj-core - ${assertj-core.version} - test diff --git a/testing-junit4/pom.xml b/testing-junit4/pom.xml index ad21faff..61f4d5be 100644 --- a/testing-junit4/pom.xml +++ b/testing-junit4/pom.xml @@ -15,27 +15,17 @@ com.fnproject.fn testing-core - ${project.version} - com.fnproject.fn runtime - ${project.version} junit junit - ${junit.version} - - - org.assertj - assertj-core - ${assertj-core.version} - test + compile - \ No newline at end of file diff --git a/testing/pom.xml b/testing/pom.xml index 10aa0498..41d1c188 100644 --- a/testing/pom.xml +++ b/testing/pom.xml @@ -11,37 +11,14 @@ testing - - UTF-8 - 1.2.2 - - com.fnproject.fn runtime - ${project.version} - com.fnproject.fn testing-core - ${project.version} - - - - - - - junit - junit - ${junit.version} - - - org.assertj - assertj-core - ${assertj-core.version} - test @@ -50,7 +27,6 @@ org.apache.maven.plugins maven-javadoc-plugin - 3.0.0-M1 attach-javadocs @@ -60,11 +36,6 @@ - - org.pitest - pitest-maven - ${pitest.version} - From 39c820c7fed0b353a0d4ab612d944d69334544ee Mon Sep 17 00:00:00 2001 From: Sven Ruppert Date: Mon, 6 Aug 2018 12:55:16 +0200 Subject: [PATCH 030/310] switched all versions to the latest available in maven central --- fn-spring-cloud-function/pom.xml | 6 +++--- pom.xml | 12 ++++++------ 2 files changed, 9 insertions(+), 9 deletions(-) diff --git a/fn-spring-cloud-function/pom.xml b/fn-spring-cloud-function/pom.xml index c2e553a5..9acec1ba 100644 --- a/fn-spring-cloud-function/pom.xml +++ b/fn-spring-cloud-function/pom.xml @@ -12,7 +12,7 @@ fn-spring-cloud-function - 1.0.0.M6 + 1.0.0.RELEASE @@ -31,7 +31,7 @@ io.projectreactor reactor-core - 3.0.7.RELEASE + 3.2.0.M3 @@ -76,7 +76,7 @@ com.github.stefanbirkner system-rules - 1.16.0 + 1.18.0 test diff --git a/pom.xml b/pom.xml index d8af32ad..bce90991 100644 --- a/pom.xml +++ b/pom.xml @@ -30,15 +30,15 @@ 0.8.1 4.12 - 2.8.47 - 3.6.2 + 2.21.0 + 3.10.0 1.4.0 1.7.25 - 2.5 + 2.6 2.9.6 - 4.4.6 + 4.4.10 1.16.0 @@ -82,7 +82,7 @@ org.apache.httpcomponents httpmime - 4.5.3 + 4.5.6 commons-io @@ -92,7 +92,7 @@ commons-logging commons-logging - 1.1.1 + 1.2 net.jodah From 98bb080389d3dcc9511f2a12b688b1e2c7cc8192 Mon Sep 17 00:00:00 2001 From: Sven Ruppert Date: Mon, 6 Aug 2018 12:57:51 +0200 Subject: [PATCH 031/310] switched all plugin-versions to the latest available in maven central --- build-image/pom.xml | 2 +- pom.xml | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/build-image/pom.xml b/build-image/pom.xml index 8a1196f6..3bc1baa3 100644 --- a/build-image/pom.xml +++ b/build-image/pom.xml @@ -49,7 +49,7 @@ org.apache.maven.plugins maven-compiler-plugin - 3.7.0 + 3.8.0 1.8 1.8 diff --git a/pom.xml b/pom.xml index bce90991..1d0ce8fd 100644 --- a/pom.xml +++ b/pom.xml @@ -142,7 +142,7 @@ org.apache.maven.plugins maven-javadoc-plugin - 3.0.0 + 3.0.1 org.apache.maven.plugins @@ -169,7 +169,7 @@ org.apache.maven.plugins maven-compiler-plugin - 3.6.1 + 3.8.0 javac-with-errorprone true @@ -192,7 +192,7 @@ org.apache.maven.plugins maven-source-plugin - 3.0.0 + 3.0.1 attach-sources @@ -248,7 +248,7 @@ com.spotify dockerfile-maven-extension - 1.3.1 + 1.4.3 From 98c30849f9e6839e93fd69d9dd2eb11781cf67b5 Mon Sep 17 00:00:00 2001 From: Sven Ruppert Date: Mon, 6 Aug 2018 12:58:30 +0200 Subject: [PATCH 032/310] removed comment --- pom.xml | 1 - 1 file changed, 1 deletion(-) diff --git a/pom.xml b/pom.xml index 1d0ce8fd..40aecf46 100644 --- a/pom.xml +++ b/pom.xml @@ -27,7 +27,6 @@ UTF-8 - 0.8.1 4.12 2.21.0 From 7b977eebf01bff0bd9d33d858687690f24b3dcbc Mon Sep 17 00:00:00 2001 From: Sven Ruppert Date: Mon, 6 Aug 2018 13:03:43 +0200 Subject: [PATCH 033/310] will make the google compiler happy... --- .../java/com/fnproject/fn/runtime/MethodWrapperTests.java | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/runtime/src/test/java/com/fnproject/fn/runtime/MethodWrapperTests.java b/runtime/src/test/java/com/fnproject/fn/runtime/MethodWrapperTests.java index fb0c6b17..37218dec 100644 --- a/runtime/src/test/java/com/fnproject/fn/runtime/MethodWrapperTests.java +++ b/runtime/src/test/java/com/fnproject/fn/runtime/MethodWrapperTests.java @@ -1,6 +1,7 @@ package com.fnproject.fn.runtime; import com.fnproject.fn.api.MethodWrapper; +import org.assertj.core.api.AbstractIntegerAssert; import org.junit.Test; import org.junit.runner.RunWith; import org.junit.runners.Parameterized; @@ -34,8 +35,9 @@ public void testMethodParameterHasExpectedType() throws NoSuchMethodException { if (parameterIndex >= 0) { assertThat(method.getParamType(parameterIndex).getParameterClass()).isEqualTo(expectedType); } else { - assertThat(parameterIndex).isEqualTo(-1) - .withFailMessage("You can only use non negative parameter indices or -1 to represent return value in this test suite"); + AbstractIntegerAssert withFailMessage = assertThat(parameterIndex) + .isEqualTo(-1) + .withFailMessage("You can only use non negative parameter indices or -1 to represent return value in this test suite"); assertThat(method.getReturnType().getParameterClass()).isEqualTo(expectedType); } } From dad6469557dbf26dc1dfa00a67221676c978a200 Mon Sep 17 00:00:00 2001 From: CI Date: Mon, 6 Aug 2018 11:42:06 +0000 Subject: [PATCH 034/310] fn-java-fdk: post-1.0.65 version bump [skip ci] --- release.version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/release.version b/release.version index 7b8d6b72..7f2b1404 100644 --- a/release.version +++ b/release.version @@ -1 +1 @@ -1.0.65 +1.0.66 From 0b7d2e602a32f17f115cfa285168f39e781872f0 Mon Sep 17 00:00:00 2001 From: Owen Cliffe Date: Wed, 19 Sep 2018 14:04:09 +0100 Subject: [PATCH 035/310] Add Unix Stream codec, Split flow from FDK, update integration tests (#150) * http input codec * add jetty-core and UDS deps * PoC jetty core UDS event codec * revise FDK contract for initial relase, split flow from fn, support new unix domain socket contract * First pass of refactor * added annotations for for features to support flow * moving flow feature to runtime package * rename flow testing and add docs, fix race in Stream testing * fixing failing tests * Update to reflect FN_ID * more integration test fixing * fix up format name * first stab at home-grown UDS implementation * docker build fix * UDS rework, remove old UDS dep and test new one * adjust permissions on file on start * new integration tests * simlify build and integration tests, add tests for http-stream * fix ci * typo * make igntests standalone * itests run 1.8 * fix itest result * env for itests * add createDir * test failures in circle * fix test interference * Use standard properties in fdk tests, fix versions in itests * hmm no entropy on circle boxes :) * use consistent properties for versions everywhere * add waits for start * this time with feeling * diagnosing timeout * close input, try more aggressive testing * C errors * fixing up accept and twiddling with integration test start * set DOCKER_LOCALHOST * integration test fixing/finessing * cludge docker localhost * no_proxy messing * set fnserver IP correctly * typo * nits in C code * review nits * more C fix nits * Make mandatory headers mandatory again * minus comment * remove Content-Length from stripped input * fix call test --- .circleci/config.yml | 98 +--- .circleci/install-go.sh | 32 -- .circleci/update-versions.sh | 7 +- api/pom.xml | 12 + api/src/main/api/snapshot.sigfile | 306 ++-------- .../java/com/fnproject/fn/api/FnFeature.java | 21 + .../com/fnproject/fn/api/FunctionInvoker.java | 16 + .../java/com/fnproject/fn/api/Headers.java | 245 ++++++-- .../java/com/fnproject/fn/api/InputEvent.java | 30 +- .../com/fnproject/fn/api/OutputEvent.java | 102 ++-- .../com/fnproject/fn/api/QueryParameters.java | 2 +- .../com/fnproject/fn/api/RuntimeContext.java | 32 +- .../com/fnproject/fn/api/RuntimeFeature.java | 17 + .../api/httpgateway/HTTPGatewayRequest.java | 25 + .../fn/api/httpgateway/HTTPResponse.java | 26 + .../com/fnproject/fn/api/HeadersTest.java | 31 ++ build-image/docker-build.sh | 21 +- build-image/pom.xml | 8 +- build.sh | 35 ++ docs/FAQ.md | 6 +- docs/FnFlowsAdvancedTopics.md | 5 + docs/FnFlowsUserGuide.md | 16 + docs/TestingFunctions.md | 40 +- examples/async-thumbnails/pom.xml | 21 +- .../fn/examples/ThumbnailsFunction.java | 3 + .../fn/examples/ThumbnailsFunctionTest.java | 94 ++-- examples/gradle-build/README.md | 2 +- examples/qr-code/pom.xml | 8 +- examples/regex-query/pom.xml | 8 +- .../fn/examples/RegexQueryTests.java | 2 - examples/string-reverse/pom.xml | 2 +- flow-api/pom.xml | 61 ++ flow-api/src/main/api/snapshot.sigfile | 343 ++++++++++++ .../java/com/fnproject/fn/api/flow/Flow.java | 14 +- .../fn/api/flow/FlowCompletionException.java | 0 .../com/fnproject/fn/api/flow/FlowFuture.java | 0 .../java/com/fnproject/fn/api/flow/Flows.java | 5 +- .../api/flow/FunctionInvocationException.java | 0 .../flow/FunctionInvokeFailedException.java | 0 .../fn/api/flow/FunctionTimeoutException.java | 0 .../com/fnproject/fn/api/flow/HttpMethod.java | 0 .../fnproject/fn/api/flow/HttpRequest.java | 0 .../fnproject/fn/api/flow/HttpResponse.java | 0 .../flow/InvalidStageResponseException.java | 0 .../flow/LambdaSerializationException.java | 0 .../fn/api/flow/PlatformException.java | 0 .../flow/ResultSerializationException.java | 0 .../api/flow/StageInvokeFailedException.java | 0 .../fn/api/flow/StageLostException.java | 0 .../fn/api/flow/StageTimeoutException.java | 0 .../fn/api/flow/WrappedFunctionException.java | 0 .../fnproject/fn/api/flow/package-info.java | 0 .../com/fnproject/fn/api/flow/FlowsTest.java | 0 flow-runtime/pom.xml | 76 +++ .../fnproject/fn/runtime/flow/APIModel.java | 0 .../fn/runtime/flow/BlobResponse.java | 0 .../fn/runtime/flow/BlobStoreClient.java | 0 .../fn/runtime/flow/CodeLocation.java | 0 .../fn/runtime/flow/CompleterClient.java | 0 .../runtime/flow/CompleterClientFactory.java | 0 .../fn/runtime/flow/CompletionId.java | 0 .../fn/runtime/flow/DefaultHttpResponse.java | 0 .../fn/runtime/flow/EntityReader.java | 0 .../runtime/flow/FlowContinuationInvoker.java | 15 +- .../fn/runtime/flow/FlowFeature.java | 38 ++ .../fn/runtime/flow/FlowFutureSource.java | 0 .../com/fnproject/fn/runtime/flow/FlowId.java | 0 .../fn/runtime/flow/FlowRuntimeGlobals.java | 0 .../fnproject/fn/runtime/flow/HttpClient.java | 0 .../fnproject/fn/runtime/flow/JsonInvoke.java | 2 +- .../runtime/flow/RemoteBlobStoreClient.java | 0 .../fnproject/fn/runtime/flow/RemoteFlow.java | 0 .../fn/runtime/flow/RemoteFlowApiClient.java | 21 +- .../flow/FlowsContinuationInvokerTest.java | 208 +++---- .../runtime/flow/RemoteFlowApiClientTest.java | 1 + .../fn/runtime/flow/TestBlobStore.java | 0 .../testing/flowtestfns}/FnFlowsFunction.java | 5 +- flow-testing/pom.xml | 78 +++ .../fn/testing/flow/FlowTesting.java | 237 ++++++++ .../testing/flow}/FnFunctionStubBuilder.java | 13 +- .../fn/testing/flow}/InMemCompleter.java | 55 +- .../fn/testing/flow}/ResultException.java | 2 +- .../testing/flow}/FnTestingRuleFlowsTest.java | 73 +-- .../fn/testing/flow/IntegrationTest.java | 42 ++ .../fn/testing/flow}/MultipleEventsTest.java | 7 +- .../fn/testing/flow}/WhenCompleteTest.java | 7 +- .../flowtestfns}/ExerciseEverything.java | 27 +- .../function/SpringCloudFunctionFeature.java | 21 + ...ngCloudFunctionInvokerIntegrationTest.java | 4 +- .../function/testfns/EmptyFunctionConfig.java | 10 +- .../function/testfns/FunctionConfig.java | 8 +- integration-tests/.gitignore | 5 - integration-tests/README.md | 29 +- integration-tests/_archive/test-3/.gitignore | 3 - integration-tests/_archive/test-3/expected | 1 - integration-tests/_archive/test-3/input | 1 - integration-tests/_archive/test-3/pre-test.sh | 6 - integration-tests/_archive/test-7/delete.sh | 3 - integration-tests/_archive/test-7/deploy.sh | 3 - integration-tests/_archive/test-7/expected | 1 - integration-tests/_archive/test-7/pre-test.sh | 6 - integration-tests/_archive/test-7/run-test.sh | 3 - .../flowAllFeatures}/README.md | 0 .../flowAllFeatures}/func.yaml | 9 +- .../test-4 => funcs/flowAllFeatures}/pom.xml | 15 +- .../fn/integration/ExerciseEverything.java | 13 +- .../com/fnproject/fn/integration/Test.java | 0 .../test-1 => funcs/flowBasic}/func.yaml | 7 +- .../test-1-jdk8 => funcs/flowBasic}/pom.xml | 22 +- .../integration/test_1/CompleterFunction.java | 3 + .../flowBasicJDK8}/func.yaml | 7 +- .../test-1 => funcs/flowBasicJDK8}/pom.xml | 21 +- .../integration/test_1/CompleterFunction.java | 3 + .../test-5 => funcs/flowExitHooks}/func.yaml | 7 +- .../test-5 => funcs/flowExitHooks}/pom.xml | 14 +- .../integration/test_5/CompleterFunction.java | 45 ++ .../test-6 => funcs/flowTimeouts}/func.yaml | 7 +- .../test-6 => funcs/flowTimeouts}/pom.xml | 13 +- .../integration/test_6/CompleterFunction.java | 11 +- .../test-2 => funcs/simpleFunc}/func.yaml | 7 +- .../{main/test-2 => funcs/simpleFunc}/pom.xml | 8 +- .../fn/integration/test2/PlainFunction.java | 0 .../integration/test2/PlainFunctionTest.java | 0 integration-tests/lib.sh | 48 -- integration-tests/main/test-1-jdk8/config | 1 - integration-tests/main/test-1-jdk8/expected | 1 - integration-tests/main/test-1-jdk8/input | 1 - integration-tests/main/test-1/config | 1 - integration-tests/main/test-1/expected | 1 - integration-tests/main/test-1/input | 1 - integration-tests/main/test-2/config | 1 - integration-tests/main/test-2/expected | 1 - integration-tests/main/test-2/input | 0 .../main/test-4/Dockerfile.custom | 4 - integration-tests/main/test-4/config | 1 - integration-tests/main/test-4/expected.sh | 3 - integration-tests/main/test-4/input | 1 - integration-tests/main/test-4/pre-test.sh | 5 - integration-tests/main/test-5/config | 1 - integration-tests/main/test-5/expected.sh | 39 -- integration-tests/main/test-5/input | 0 .../integration/test_5/CompleterFunction.java | 14 - integration-tests/main/test-6/config | 1 - integration-tests/main/test-6/expected.sh | 32 -- integration-tests/main/test-6/input | 0 integration-tests/pom.xml | 34 +- integration-tests/post-configure-hook.sh | 18 - integration-tests/pre-build-hook.sh | 31 -- integration-tests/run-all-tests.sh | 99 ---- integration-tests/run-local.sh | 139 ----- integration-tests/run-remote.sh | 39 -- integration-tests/run_tests_ci.sh | 94 ++++ integration-tests/smoke-test.sh | 95 ---- .../integrationtest/IntegrationTestRule.java | 347 ++++++++++++ .../fn/integrationtest/FlowTest.java | 101 ++++ .../fn/integrationtest/FunctionsTest.java | 54 ++ pom.xml | 495 +++++++++-------- runtime/Dockerfile | 3 +- runtime/Dockerfile-jdk9 | 4 +- runtime/pom.xml | 21 + runtime/src/main/c/.gitignore | 4 + runtime/src/main/c/CMakeLists.txt | 10 + runtime/src/main/c/Dockerfile-buildimage | 8 + runtime/src/main/c/README.md | 19 + runtime/src/main/c/buildit.sh | 14 + runtime/src/main/c/rebuild_so.sh | 10 + runtime/src/main/c/unix_socket.c | 521 ++++++++++++++++++ .../fn/runtime/DefaultEventCodec.java | 46 +- .../com/fnproject/fn/runtime/EntryPoint.java | 105 ++-- .../com/fnproject/fn/runtime/EventCodec.java | 34 +- .../fnproject/fn/runtime/FunctionLoader.java | 2 + .../fn/runtime/FunctionRuntimeContext.java | 44 +- .../fnproject/fn/runtime/HTTPStreamCodec.java | 327 +++++++++++ .../fnproject/fn/runtime/HttpEventCodec.java | 67 ++- .../fn/runtime/ReadOnceInputEvent.java | 67 +-- .../runtime/coercion/ByteArrayCoercion.java | 2 +- .../fn/runtime/coercion/StringCoercion.java | 2 +- .../fn/runtime/coercion/VoidCoercion.java | 2 +- .../coercion/jackson/JacksonCoercion.java | 2 +- .../exception/FunctionIOException.java | 20 + .../FunctionInitializationException.java | 23 + .../InternalFunctionInvocationException.java | 2 +- .../PlatformCommunicationException.java | 3 + .../QueryParametersImpl.java | 9 +- .../QueryParametersParser.java | 2 +- .../fn/runtime/ntv/UnixServerSocket.java | 62 +++ .../fnproject/fn/runtime/ntv/UnixSocket.java | 321 +++++++++++ .../fn/runtime/ntv/UnixSocketException.java | 18 + .../fn/runtime/ntv/UnixSocketNative.java | 58 ++ .../fn/runtime/ConfigurationMethodsTest.java | 66 +-- .../fnproject/fn/runtime/DataBindingTest.java | 48 +- .../fn/runtime/DefaultEventCodecTest.java | 46 +- .../fn/runtime/EndToEndInvokeTest.java | 138 ++--- .../fn/runtime/ErrorMessagesTest.java | 16 +- .../fnproject/fn/runtime/FnTestHarness.java | 380 ++++--------- ...sts.java => FunctionConstructionTest.java} | 26 +- .../fn/runtime/HTTPStreamCodecTest.java | 329 +++++++++++ .../fnproject/fn/runtime/HeaderBuilder.java | 8 +- .../fn/runtime/HttpEventCodecTest.java | 158 ++---- .../fn/runtime/JacksonCoercionTest.java | 5 +- .../fn/runtime/QueryParametersParserTest.java | 1 + .../fnproject/fn/runtime/flow/FlowsTest.java | 280 ---------- .../fn/runtime/ntv/UnixSocketNativeTest.java | 469 ++++++++++++++++ .../fn/runtime/ntv/UnixSocketTest.java | 93 ++++ .../coercions/StringReversalCoercion.java | 2 +- .../coercions/StringUpperCaseCoercion.java | 2 +- .../fnproject/fn/testing/FnEventBuilder.java | 45 +- .../fn/testing/FnHttpEventBuilder.java | 163 +----- .../com/fnproject/fn/testing/FnResult.java | 23 +- .../fn/testing/FnTestingClassLoader.java | 26 +- testing-junit4/pom.xml | 5 + .../testing/FnFunctionStubBuilderJUnit4.java | 9 - .../fnproject/fn/testing/FnTestingRule.java | 436 +++++---------- .../fn/testing/FnTestingRuleFeature.java | 26 + .../fn/testing/FnTestingRuleTest.java | 340 ++++++++++++ .../fn/testing/FnTestingRuleTest.java | 402 -------------- .../fnproject/fn/testing/IntegrationTest.java | 37 -- 217 files changed, 6310 insertions(+), 3723 deletions(-) delete mode 100755 .circleci/install-go.sh create mode 100644 api/src/main/java/com/fnproject/fn/api/FnFeature.java create mode 100644 api/src/main/java/com/fnproject/fn/api/RuntimeFeature.java create mode 100644 api/src/main/java/com/fnproject/fn/api/httpgateway/HTTPGatewayRequest.java create mode 100644 api/src/main/java/com/fnproject/fn/api/httpgateway/HTTPResponse.java create mode 100644 api/src/test/java/com/fnproject/fn/api/HeadersTest.java create mode 100755 build.sh create mode 100644 flow-api/pom.xml create mode 100644 flow-api/src/main/api/snapshot.sigfile rename {api => flow-api}/src/main/java/com/fnproject/fn/api/flow/Flow.java (95%) rename {api => flow-api}/src/main/java/com/fnproject/fn/api/flow/FlowCompletionException.java (100%) rename {api => flow-api}/src/main/java/com/fnproject/fn/api/flow/FlowFuture.java (100%) rename {api => flow-api}/src/main/java/com/fnproject/fn/api/flow/Flows.java (94%) rename {api => flow-api}/src/main/java/com/fnproject/fn/api/flow/FunctionInvocationException.java (100%) rename {api => flow-api}/src/main/java/com/fnproject/fn/api/flow/FunctionInvokeFailedException.java (100%) rename {api => flow-api}/src/main/java/com/fnproject/fn/api/flow/FunctionTimeoutException.java (100%) rename {api => flow-api}/src/main/java/com/fnproject/fn/api/flow/HttpMethod.java (100%) rename {api => flow-api}/src/main/java/com/fnproject/fn/api/flow/HttpRequest.java (100%) rename {api => flow-api}/src/main/java/com/fnproject/fn/api/flow/HttpResponse.java (100%) rename {api => flow-api}/src/main/java/com/fnproject/fn/api/flow/InvalidStageResponseException.java (100%) rename {api => flow-api}/src/main/java/com/fnproject/fn/api/flow/LambdaSerializationException.java (100%) rename {api => flow-api}/src/main/java/com/fnproject/fn/api/flow/PlatformException.java (100%) rename {api => flow-api}/src/main/java/com/fnproject/fn/api/flow/ResultSerializationException.java (100%) rename {api => flow-api}/src/main/java/com/fnproject/fn/api/flow/StageInvokeFailedException.java (100%) rename {api => flow-api}/src/main/java/com/fnproject/fn/api/flow/StageLostException.java (100%) rename {api => flow-api}/src/main/java/com/fnproject/fn/api/flow/StageTimeoutException.java (100%) rename {api => flow-api}/src/main/java/com/fnproject/fn/api/flow/WrappedFunctionException.java (100%) rename {api => flow-api}/src/main/java/com/fnproject/fn/api/flow/package-info.java (100%) rename {api => flow-api}/src/test/java/com/fnproject/fn/api/flow/FlowsTest.java (100%) create mode 100644 flow-runtime/pom.xml rename {runtime => flow-runtime}/src/main/java/com/fnproject/fn/runtime/flow/APIModel.java (100%) rename {runtime => flow-runtime}/src/main/java/com/fnproject/fn/runtime/flow/BlobResponse.java (100%) rename {runtime => flow-runtime}/src/main/java/com/fnproject/fn/runtime/flow/BlobStoreClient.java (100%) rename {runtime => flow-runtime}/src/main/java/com/fnproject/fn/runtime/flow/CodeLocation.java (100%) rename {runtime => flow-runtime}/src/main/java/com/fnproject/fn/runtime/flow/CompleterClient.java (100%) rename {runtime => flow-runtime}/src/main/java/com/fnproject/fn/runtime/flow/CompleterClientFactory.java (100%) rename {runtime => flow-runtime}/src/main/java/com/fnproject/fn/runtime/flow/CompletionId.java (100%) rename {runtime => flow-runtime}/src/main/java/com/fnproject/fn/runtime/flow/DefaultHttpResponse.java (100%) rename {runtime => flow-runtime}/src/main/java/com/fnproject/fn/runtime/flow/EntityReader.java (100%) rename {runtime => flow-runtime}/src/main/java/com/fnproject/fn/runtime/flow/FlowContinuationInvoker.java (97%) create mode 100644 flow-runtime/src/main/java/com/fnproject/fn/runtime/flow/FlowFeature.java rename {runtime => flow-runtime}/src/main/java/com/fnproject/fn/runtime/flow/FlowFutureSource.java (100%) rename {runtime => flow-runtime}/src/main/java/com/fnproject/fn/runtime/flow/FlowId.java (100%) rename {runtime => flow-runtime}/src/main/java/com/fnproject/fn/runtime/flow/FlowRuntimeGlobals.java (100%) rename {runtime => flow-runtime}/src/main/java/com/fnproject/fn/runtime/flow/HttpClient.java (100%) rename {runtime => flow-runtime}/src/main/java/com/fnproject/fn/runtime/flow/JsonInvoke.java (97%) rename {runtime => flow-runtime}/src/main/java/com/fnproject/fn/runtime/flow/RemoteBlobStoreClient.java (100%) rename {runtime => flow-runtime}/src/main/java/com/fnproject/fn/runtime/flow/RemoteFlow.java (100%) rename {runtime => flow-runtime}/src/main/java/com/fnproject/fn/runtime/flow/RemoteFlowApiClient.java (96%) rename {runtime => flow-runtime}/src/test/java/com/fnproject/fn/runtime/flow/FlowsContinuationInvokerTest.java (76%) rename {runtime => flow-runtime}/src/test/java/com/fnproject/fn/runtime/flow/RemoteFlowApiClientTest.java (99%) rename {runtime => flow-runtime}/src/test/java/com/fnproject/fn/runtime/flow/TestBlobStore.java (100%) rename {runtime/src/test/java/com/fnproject/fn/runtime/testfns => flow-runtime/src/test/java/com/fnproject/fn/testing/flowtestfns}/FnFlowsFunction.java (83%) create mode 100644 flow-testing/pom.xml create mode 100644 flow-testing/src/main/java/com/fnproject/fn/testing/flow/FlowTesting.java rename {testing-core/src/main/java/com/fnproject/fn/testing => flow-testing/src/main/java/com/fnproject/fn/testing/flow}/FnFunctionStubBuilder.java (81%) rename {testing-core/src/main/java/com/fnproject/fn/testing => flow-testing/src/main/java/com/fnproject/fn/testing/flow}/InMemCompleter.java (94%) rename {testing-core/src/main/java/com/fnproject/fn/testing => flow-testing/src/main/java/com/fnproject/fn/testing/flow}/ResultException.java (89%) rename {testing-junit4/src/test/java/junit/com/fnproject/fn/testing => flow-testing/src/test/java/com/fnproject/fn/testing/flow}/FnTestingRuleFlowsTest.java (94%) create mode 100644 flow-testing/src/test/java/com/fnproject/fn/testing/flow/IntegrationTest.java rename {testing-junit4/src/test/java/junit/com/fnproject/fn/testing => flow-testing/src/test/java/com/fnproject/fn/testing/flow}/MultipleEventsTest.java (94%) rename {testing-junit4/src/test/java/junit/com/fnproject/fn/testing => flow-testing/src/test/java/com/fnproject/fn/testing/flow}/WhenCompleteTest.java (81%) rename {testing-junit4/src/test/java/junit/com/fnproject/fn/testing => flow-testing/src/test/java/com/fnproject/fn/testing/flowtestfns}/ExerciseEverything.java (95%) create mode 100644 fn-spring-cloud-function/src/main/java/com/fnproject/springframework/function/SpringCloudFunctionFeature.java delete mode 100644 integration-tests/.gitignore delete mode 100644 integration-tests/_archive/test-3/.gitignore delete mode 100644 integration-tests/_archive/test-3/expected delete mode 100644 integration-tests/_archive/test-3/input delete mode 100755 integration-tests/_archive/test-3/pre-test.sh delete mode 100644 integration-tests/_archive/test-7/delete.sh delete mode 100755 integration-tests/_archive/test-7/deploy.sh delete mode 100644 integration-tests/_archive/test-7/expected delete mode 100755 integration-tests/_archive/test-7/pre-test.sh delete mode 100755 integration-tests/_archive/test-7/run-test.sh rename integration-tests/{main/test-4 => funcs/flowAllFeatures}/README.md (100%) rename integration-tests/{main/test-4 => funcs/flowAllFeatures}/func.yaml (74%) rename integration-tests/{main/test-4 => funcs/flowAllFeatures}/pom.xml (85%) rename integration-tests/{main/test-4 => funcs/flowAllFeatures}/src/main/java/com/fnproject/fn/integration/ExerciseEverything.java (96%) rename integration-tests/{main/test-4 => funcs/flowAllFeatures}/src/main/java/com/fnproject/fn/integration/Test.java (100%) rename integration-tests/{main/test-1 => funcs/flowBasic}/func.yaml (57%) rename integration-tests/{main/test-1-jdk8 => funcs/flowBasic}/pom.xml (72%) rename integration-tests/{main/test-1-jdk8 => funcs/flowBasic}/src/main/java/com/fnproject/fn/integration/test_1/CompleterFunction.java (76%) rename integration-tests/{main/test-1-jdk8 => funcs/flowBasicJDK8}/func.yaml (56%) rename integration-tests/{main/test-1 => funcs/flowBasicJDK8}/pom.xml (72%) rename integration-tests/{main/test-1 => funcs/flowBasicJDK8}/src/main/java/com/fnproject/fn/integration/test_1/CompleterFunction.java (76%) rename integration-tests/{main/test-5 => funcs/flowExitHooks}/func.yaml (56%) rename integration-tests/{main/test-5 => funcs/flowExitHooks}/pom.xml (84%) create mode 100644 integration-tests/funcs/flowExitHooks/src/main/java/com/fnproject/fn/integration/test_5/CompleterFunction.java rename integration-tests/{main/test-6 => funcs/flowTimeouts}/func.yaml (56%) rename integration-tests/{main/test-6 => funcs/flowTimeouts}/pom.xml (85%) rename integration-tests/{main/test-6 => funcs/flowTimeouts}/src/main/java/com/fnproject/fn/integration/test_6/CompleterFunction.java (67%) rename integration-tests/{main/test-2 => funcs/simpleFunc}/func.yaml (52%) rename integration-tests/{main/test-2 => funcs/simpleFunc}/pom.xml (90%) rename integration-tests/{main/test-2 => funcs/simpleFunc}/src/main/java/com/fnproject/fn/integration/test2/PlainFunction.java (100%) rename integration-tests/{main/test-2 => funcs/simpleFunc}/src/test/java/com/fnproject/fn/integration/test2/PlainFunctionTest.java (100%) delete mode 100644 integration-tests/lib.sh delete mode 100644 integration-tests/main/test-1-jdk8/config delete mode 100644 integration-tests/main/test-1-jdk8/expected delete mode 100644 integration-tests/main/test-1-jdk8/input delete mode 100644 integration-tests/main/test-1/config delete mode 100644 integration-tests/main/test-1/expected delete mode 100644 integration-tests/main/test-1/input delete mode 100644 integration-tests/main/test-2/config delete mode 100644 integration-tests/main/test-2/expected delete mode 100644 integration-tests/main/test-2/input delete mode 100644 integration-tests/main/test-4/Dockerfile.custom delete mode 100644 integration-tests/main/test-4/config delete mode 100755 integration-tests/main/test-4/expected.sh delete mode 100644 integration-tests/main/test-4/input delete mode 100755 integration-tests/main/test-4/pre-test.sh delete mode 100644 integration-tests/main/test-5/config delete mode 100755 integration-tests/main/test-5/expected.sh delete mode 100644 integration-tests/main/test-5/input delete mode 100644 integration-tests/main/test-5/src/main/java/com/fnproject/fn/integration/test_5/CompleterFunction.java delete mode 100644 integration-tests/main/test-6/config delete mode 100755 integration-tests/main/test-6/expected.sh delete mode 100644 integration-tests/main/test-6/input delete mode 100755 integration-tests/post-configure-hook.sh delete mode 100755 integration-tests/pre-build-hook.sh delete mode 100755 integration-tests/run-all-tests.sh delete mode 100755 integration-tests/run-local.sh delete mode 100755 integration-tests/run-remote.sh create mode 100755 integration-tests/run_tests_ci.sh delete mode 100755 integration-tests/smoke-test.sh create mode 100644 integration-tests/src/main/java/com/fnproject/fn/integrationtest/IntegrationTestRule.java create mode 100644 integration-tests/src/test/java/com/fnproject/fn/integrationtest/FlowTest.java create mode 100644 integration-tests/src/test/java/com/fnproject/fn/integrationtest/FunctionsTest.java create mode 100644 runtime/src/main/c/.gitignore create mode 100644 runtime/src/main/c/CMakeLists.txt create mode 100644 runtime/src/main/c/Dockerfile-buildimage create mode 100644 runtime/src/main/c/README.md create mode 100755 runtime/src/main/c/buildit.sh create mode 100755 runtime/src/main/c/rebuild_so.sh create mode 100644 runtime/src/main/c/unix_socket.c create mode 100644 runtime/src/main/java/com/fnproject/fn/runtime/HTTPStreamCodec.java create mode 100644 runtime/src/main/java/com/fnproject/fn/runtime/exception/FunctionIOException.java create mode 100644 runtime/src/main/java/com/fnproject/fn/runtime/exception/FunctionInitializationException.java rename runtime/src/main/java/com/fnproject/fn/runtime/{ => httpgateway}/QueryParametersImpl.java (76%) rename runtime/src/main/java/com/fnproject/fn/runtime/{ => httpgateway}/QueryParametersParser.java (97%) create mode 100644 runtime/src/main/java/com/fnproject/fn/runtime/ntv/UnixServerSocket.java create mode 100644 runtime/src/main/java/com/fnproject/fn/runtime/ntv/UnixSocket.java create mode 100644 runtime/src/main/java/com/fnproject/fn/runtime/ntv/UnixSocketException.java create mode 100644 runtime/src/main/java/com/fnproject/fn/runtime/ntv/UnixSocketNative.java rename runtime/src/test/java/com/fnproject/fn/runtime/{FunctionConstructionTests.java => FunctionConstructionTest.java} (83%) create mode 100644 runtime/src/test/java/com/fnproject/fn/runtime/HTTPStreamCodecTest.java delete mode 100644 runtime/src/test/java/com/fnproject/fn/runtime/flow/FlowsTest.java create mode 100644 runtime/src/test/java/com/fnproject/fn/runtime/ntv/UnixSocketNativeTest.java create mode 100644 runtime/src/test/java/com/fnproject/fn/runtime/ntv/UnixSocketTest.java delete mode 100644 testing-junit4/src/main/java/com/fnproject/fn/testing/FnFunctionStubBuilderJUnit4.java create mode 100644 testing-junit4/src/main/java/com/fnproject/fn/testing/FnTestingRuleFeature.java create mode 100644 testing-junit4/src/test/java/com/fnproject/fn/testing/FnTestingRuleTest.java delete mode 100644 testing-junit4/src/test/java/junit/com/fnproject/fn/testing/FnTestingRuleTest.java delete mode 100644 testing-junit4/src/test/java/junit/com/fnproject/fn/testing/IntegrationTest.java diff --git a/.circleci/config.yml b/.circleci/config.yml index 7188b583..23fe9b7a 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -2,17 +2,24 @@ version: 2 jobs: build: working_directory: ~/fn-java-fdk - machine: - java: - version: oraclejdk8 + machine: true environment: # store_artifacts doesn't shell substitute so the variable # definitions are duplicated in those steps too. FDK_ARTIFACT_DIR: /tmp/artifacts/fdk TEST_ARTIFACT_DIR: /tmp/artifacts/tests - STAGING_DIR: /tmp/staging-repository + REPOSITORY_LOCATION: /tmp/staging_repo steps: - checkout + - run: + name: Update Docker to latest + command: ./.circleci/install-docker.sh + - run: + name: Install fn binary (as it is needed for the integration tests) + command: ./.circleci/install-fn.sh + - run: + name: Install junit-merge + command: npm install -g junit-merge - run: name: Set release to latest branch version command: | @@ -22,83 +29,22 @@ jobs: name: Determine the release version command: ./.circleci/update-versions.sh - run: - name: Build and deploy locally + name: Build and Test FDK command: | - rm -rf $STAGING_DIR - mkdir -p $STAGING_DIR - mvn deploy -DaltDeploymentRepository=localStagingDir::default::file://"$STAGING_DIR" - - store_test_results: - path: runtime/target/surefire-reports - - store_test_results: - path: testing/target/surefire-reports - + export FN_FDK_VERSION=$(cat ./release.version) + ./build.sh - run: - name: Copy FDK artifacts to upload folder + name: Run integration tests command: | - mkdir -p "$FDK_ARTIFACT_DIR" - cp -a api/target/*.jar "$FDK_ARTIFACT_DIR" - cp -a runtime/target/*.jar "$FDK_ARTIFACT_DIR" - - store_artifacts: - name: Upload FDK artifacts - path: /tmp/artifacts/fdk - - - run: - name: Update Docker to latest - command: ./.circleci/install-docker.sh - + export FN_JAVA_FDK_VERSION=$(cat release.version) + ./integration-tests/run_tests_ci.sh + timeout: 1200 - run: name: Login to Docker command: | if [[ "${CIRCLE_BRANCH}" == "master" && -z "${CIRCLE_PR_REPONAME}" ]]; then docker login -u $DOCKER_USER -p $DOCKER_PASS fi - - - run: - name: Build fn-java-fdk Docker build image - command: | - cd build-image - ./docker-build.sh -t fnproject/fn-java-fdk-build:$(cat ../release.version) . - - - run: - name: Build fn-java-fdk-jdk9 Docker build image - command: | - cd build-image - ./docker-build.sh -f Dockerfile-jdk9 -t fnproject/fn-java-fdk-build:jdk9-$(cat ../release.version) . - - run: - name: Build fn-java-fdk Docker runtime image - command: | - cd runtime - docker build -t fnproject/fn-java-fdk:$(cat ../release.version) . - - - run: - name: Build fn-java-fdk-jdk9 Docker runtime image - command: | - cd runtime - docker build -f Dockerfile-jdk9 -t fnproject/fn-java-fdk:jdk9-$(cat ../release.version) . - - - run: - name: Install fn binary (as it is needed for the integration tests) - command: ./.circleci/install-fn.sh - - - run: - name: Run integration tests - command: REPOSITORY_LOCATION="$STAGING_DIR" FN_JAVA_FDK_VERSION=$(cat release.version) ./integration-tests/run-local.sh - timeout: 1200 - - - run: - name: Copy integration test results to test artifact dir - command: | - mkdir -p "$TEST_ARTIFACT_DIR" - for test_dir in ./integration-tests/main/test-*; do - test_name="$(basename "$test_dir")" - mkdir "${TEST_ARTIFACT_DIR}/${test_name}" - cp -a $(find "$test_dir" -maxdepth 1 -type f) "${TEST_ARTIFACT_DIR}/${test_name}" - done - find "${TEST_ARTIFACT_DIR}" - when: always - - store_artifacts: - name: Upload integration test results to artifacts - path: /tmp/artifacts/tests - deploy: name: Release new version command: | @@ -108,4 +54,12 @@ jobs: git branch --set-upstream-to=origin/${CIRCLE_BRANCH} ${CIRCLE_BRANCH} ./.circleci/release.sh fi + - run: + name: Gather test results + when: always + command: | + junit-merge $(find . -wholename "*/target/surefire-reports/*.xml") --createDir -o test_results/merged_results.xml + - store_test_results: + when: always + path: test_results diff --git a/.circleci/install-go.sh b/.circleci/install-go.sh deleted file mode 100755 index b61512dc..00000000 --- a/.circleci/install-go.sh +++ /dev/null @@ -1,32 +0,0 @@ -#!/usr/bin/env bash - -: ${GOVERSION:=1.8.3} -: ${OS:=linux} -: ${ARCH:=amd64} - -set -ex - -go version -go env GOROOT - -# Remove previous Go version -sudo rm -rf /usr/local/go - -# Install Go -BUILD_DIR="/tmp/go-${GOVERSION}.${OS}.${ARCH}" -mkdir -p "$BUILD_DIR" -pushd "$BUILD_DIR" - wget https://storage.googleapis.com/golang/go${GOVERSION}.${OS}-${ARCH}.tar.gz - sudo tar -C /usr/local -xzf go${GOVERSION}.${OS}-${ARCH}.tar.gz - go get -u github.com/golang/dep/... -popd - -mkdir -p "${GOPATH}/bin" - -# Install Glide -if ! type glide 2>&1 > /dev/null; then - curl https://glide.sh/get | sh -fi - -go version -go env GOROOT diff --git a/.circleci/update-versions.sh b/.circleci/update-versions.sh index 1490bd2e..394a3b76 100755 --- a/.circleci/update-versions.sh +++ b/.circleci/update-versions.sh @@ -1,4 +1,9 @@ #!/bin/bash +# +# this is instead for the maven release plugin (which sucks) - this sets the versions across the project before a build +# for branch builds these are ignored (nothing is deployed) +# For master releases this sets the latest version that this branch would be released as +# release_version=$(cat release.version) if [[ $release_version =~ ^[0-9]+\.[0-9]+\.[0-9]+$ ]] ; then @@ -14,6 +19,6 @@ mvn versions:set -D newVersion=${release_version} versions:update-child-modules # We need to replace the example dependency versions also # (sed syntax for portability between MacOS and gnu) find . -name pom.xml | - xargs -n 1 sed -i.bak -e "s|.*|${release_version}|" + xargs -n 1 sed -i.bak -e "s|.*|${release_version}|" find . -name pom.xml.bak -delete diff --git a/api/pom.xml b/api/pom.xml index 2e6a8778..2bc26b02 100644 --- a/api/pom.xml +++ b/api/pom.xml @@ -11,6 +11,18 @@ api + + + junit + junit + test + + + org.assertj + assertj-core + test + + diff --git a/api/src/main/api/snapshot.sigfile b/api/src/main/api/snapshot.sigfile index 1f743e18..73833a22 100644 --- a/api/src/main/api/snapshot.sigfile +++ b/api/src/main/api/snapshot.sigfile @@ -6,17 +6,43 @@ CLSS public abstract interface !annotation com.fnproject.fn.api.FnConfiguration anno 0 java.lang.annotation.Target(java.lang.annotation.ElementType[] value=[METHOD]) intf java.lang.annotation.Annotation +CLSS public abstract interface !annotation com.fnproject.fn.api.FnFeature + anno 0 java.lang.annotation.Retention(java.lang.annotation.RetentionPolicy value=RUNTIME) + anno 0 java.lang.annotation.Target(java.lang.annotation.ElementType[] value=[TYPE]) +intf java.lang.annotation.Annotation +meth public abstract java.lang.Class value() + CLSS public abstract interface com.fnproject.fn.api.FunctionInvoker +innr public final static !enum Phase meth public abstract java.util.Optional tryInvoke(com.fnproject.fn.api.InvocationContext,com.fnproject.fn.api.InputEvent) +CLSS public final static !enum com.fnproject.fn.api.FunctionInvoker$Phase + outer com.fnproject.fn.api.FunctionInvoker +fld public final static com.fnproject.fn.api.FunctionInvoker$Phase Call +fld public final static com.fnproject.fn.api.FunctionInvoker$Phase PreCall +meth public static com.fnproject.fn.api.FunctionInvoker$Phase valueOf(java.lang.String) +meth public static com.fnproject.fn.api.FunctionInvoker$Phase[] values() +supr java.lang.Enum + CLSS public final com.fnproject.fn.api.Headers -meth public com.fnproject.fn.api.Headers withHeader(java.lang.String,java.lang.String) -meth public java.util.Map getAll() +intf java.io.Serializable +meth public !varargs com.fnproject.fn.api.Headers addHeader(java.lang.String,java.lang.String,java.lang.String[]) +meth public !varargs com.fnproject.fn.api.Headers setHeader(java.lang.String,java.lang.String,java.lang.String[]) +meth public boolean equals(java.lang.Object) +meth public com.fnproject.fn.api.Headers removeHeader(java.lang.String) +meth public com.fnproject.fn.api.Headers setHeader(java.lang.String,java.util.Collection) +meth public int hashCode() +meth public java.lang.String toString() +meth public java.util.Collection keys() +meth public java.util.List getAllValues(java.lang.String) +meth public java.util.Map> asMap() meth public java.util.Optional get(java.lang.String) meth public static com.fnproject.fn.api.Headers emptyHeaders() meth public static com.fnproject.fn.api.Headers fromMap(java.util.Map) +meth public static com.fnproject.fn.api.Headers fromMultiHeaderMap(java.util.Map>) +meth public static java.lang.String canonicalKey(java.lang.String) supr java.lang.Object -hfds headers +hfds emptyHeaders,headerName,headers CLSS public abstract interface !annotation com.fnproject.fn.api.InputBinding anno 0 java.lang.annotation.Retention(java.lang.annotation.RetentionPolicy value=RUNTIME) @@ -31,11 +57,8 @@ CLSS public abstract interface com.fnproject.fn.api.InputEvent intf java.io.Closeable meth public abstract <%0 extends java.lang.Object> {%%0} consumeBody(java.util.function.Function) meth public abstract com.fnproject.fn.api.Headers getHeaders() -meth public abstract com.fnproject.fn.api.QueryParameters getQueryParameters() -meth public abstract java.lang.String getAppName() -meth public abstract java.lang.String getMethod() -meth public abstract java.lang.String getRequestUrl() -meth public abstract java.lang.String getRoute() +meth public abstract java.lang.String getCallID() +meth public abstract java.time.Instant getDeadline() CLSS public abstract interface com.fnproject.fn.api.InvocationContext meth public abstract com.fnproject.fn.api.RuntimeContext getRuntimeContext() @@ -64,16 +87,27 @@ CLSS public abstract interface com.fnproject.fn.api.OutputCoercion meth public abstract java.util.Optional wrapFunctionResult(com.fnproject.fn.api.InvocationContext,com.fnproject.fn.api.MethodWrapper,java.lang.Object) CLSS public abstract interface com.fnproject.fn.api.OutputEvent -fld public final static int FAILURE = 500 -fld public final static int SUCCESS = 200 +innr public final static !enum Status meth public abstract com.fnproject.fn.api.Headers getHeaders() -meth public abstract int getStatusCode() +meth public abstract com.fnproject.fn.api.OutputEvent$Status getStatus() meth public abstract java.util.Optional getContentType() meth public abstract void writeToOutput(java.io.OutputStream) throws java.io.IOException meth public boolean isSuccess() -meth public static com.fnproject.fn.api.OutputEvent emptyResult(int) -meth public static com.fnproject.fn.api.OutputEvent fromBytes(byte[],int,java.lang.String) -meth public static com.fnproject.fn.api.OutputEvent fromBytes(byte[],int,java.lang.String,com.fnproject.fn.api.Headers) +meth public static com.fnproject.fn.api.OutputEvent emptyResult(com.fnproject.fn.api.OutputEvent$Status) +meth public static com.fnproject.fn.api.OutputEvent fromBytes(byte[],com.fnproject.fn.api.OutputEvent$Status,java.lang.String) +meth public static com.fnproject.fn.api.OutputEvent fromBytes(byte[],com.fnproject.fn.api.OutputEvent$Status,java.lang.String,com.fnproject.fn.api.Headers) + +CLSS public final static !enum com.fnproject.fn.api.OutputEvent$Status + outer com.fnproject.fn.api.OutputEvent +fld public final static com.fnproject.fn.api.OutputEvent$Status FunctionError +fld public final static com.fnproject.fn.api.OutputEvent$Status FunctionTimeout +fld public final static com.fnproject.fn.api.OutputEvent$Status InternalError +fld public final static com.fnproject.fn.api.OutputEvent$Status Success +meth public int getCode() +meth public static com.fnproject.fn.api.OutputEvent$Status valueOf(java.lang.String) +meth public static com.fnproject.fn.api.OutputEvent$Status[] values() +supr java.lang.Enum +hfds code CLSS public abstract interface com.fnproject.fn.api.QueryParameters meth public abstract java.util.List getValues(java.lang.String) @@ -83,15 +117,21 @@ meth public abstract java.util.Optional get(java.lang.String) CLSS public abstract interface com.fnproject.fn.api.RuntimeContext meth public abstract <%0 extends java.lang.Object> java.util.Optional<{%%0}> getAttribute(java.lang.String,java.lang.Class<{%%0}>) meth public abstract com.fnproject.fn.api.MethodWrapper getMethod() +meth public abstract java.lang.String getAppID() +meth public abstract java.lang.String getFunctionID() meth public abstract java.util.List getInputCoercions(com.fnproject.fn.api.MethodWrapper,int) meth public abstract java.util.List getOutputCoercions(java.lang.reflect.Method) meth public abstract java.util.Map getConfiguration() meth public abstract java.util.Optional getInvokeInstance() meth public abstract java.util.Optional getConfigurationByKey(java.lang.String) meth public abstract void addInputCoercion(com.fnproject.fn.api.InputCoercion) +meth public abstract void addInvoker(com.fnproject.fn.api.FunctionInvoker,com.fnproject.fn.api.FunctionInvoker$Phase) meth public abstract void addOutputCoercion(com.fnproject.fn.api.OutputCoercion) meth public abstract void setAttribute(java.lang.String,java.lang.Object) -meth public abstract void setInvoker(com.fnproject.fn.api.FunctionInvoker) +meth public void setInvoker(com.fnproject.fn.api.FunctionInvoker) + +CLSS public abstract interface com.fnproject.fn.api.RuntimeFeature +meth public abstract void initialize(com.fnproject.fn.api.RuntimeContext) CLSS public abstract interface com.fnproject.fn.api.TypeWrapper meth public abstract java.lang.Class getParameterClass() @@ -116,202 +156,6 @@ cons public init(java.lang.String) cons public init(java.lang.String,java.lang.Exception) supr java.lang.RuntimeException -CLSS public abstract interface com.fnproject.fn.api.flow.Flow -innr public final static !enum FlowState -intf java.io.Serializable -meth public <%0 extends java.io.Serializable, %1 extends java.lang.Object> com.fnproject.fn.api.flow.FlowFuture<{%%0}> invokeFunction(java.lang.String,{%%1},java.lang.Class<{%%0}>) -meth public <%0 extends java.lang.Object> com.fnproject.fn.api.flow.FlowFuture invokeFunction(java.lang.String,{%%0}) -meth public abstract !varargs com.fnproject.fn.api.flow.FlowFuture anyOf(com.fnproject.fn.api.flow.FlowFuture[]) -meth public abstract !varargs com.fnproject.fn.api.flow.FlowFuture allOf(com.fnproject.fn.api.flow.FlowFuture[]) -meth public abstract <%0 extends java.io.Serializable, %1 extends java.lang.Object> com.fnproject.fn.api.flow.FlowFuture<{%%0}> invokeFunction(java.lang.String,com.fnproject.fn.api.flow.HttpMethod,com.fnproject.fn.api.Headers,{%%1},java.lang.Class<{%%0}>) -meth public abstract <%0 extends java.lang.Object> com.fnproject.fn.api.flow.FlowFuture invokeFunction(java.lang.String,com.fnproject.fn.api.flow.HttpMethod,com.fnproject.fn.api.Headers,{%%0}) -meth public abstract <%0 extends java.lang.Object> com.fnproject.fn.api.flow.FlowFuture<{%%0}> completedValue({%%0}) -meth public abstract <%0 extends java.lang.Object> com.fnproject.fn.api.flow.FlowFuture<{%%0}> createFlowFuture() -meth public abstract <%0 extends java.lang.Object> com.fnproject.fn.api.flow.FlowFuture<{%%0}> failedFuture(java.lang.Throwable) -meth public abstract <%0 extends java.lang.Object> com.fnproject.fn.api.flow.FlowFuture<{%%0}> supply(com.fnproject.fn.api.flow.Flows$SerCallable<{%%0}>) -meth public abstract com.fnproject.fn.api.flow.Flow addTerminationHook(com.fnproject.fn.api.flow.Flows$SerConsumer) -meth public abstract com.fnproject.fn.api.flow.FlowFuture invokeFunction(java.lang.String,com.fnproject.fn.api.flow.HttpMethod,com.fnproject.fn.api.Headers,byte[]) -meth public abstract com.fnproject.fn.api.flow.FlowFuture delay(long,java.util.concurrent.TimeUnit) -meth public abstract com.fnproject.fn.api.flow.FlowFuture supply(com.fnproject.fn.api.flow.Flows$SerRunnable) -meth public com.fnproject.fn.api.flow.FlowFuture invokeFunction(java.lang.String,com.fnproject.fn.api.flow.HttpMethod) -meth public com.fnproject.fn.api.flow.FlowFuture invokeFunction(java.lang.String,com.fnproject.fn.api.flow.HttpMethod,com.fnproject.fn.api.Headers) - -CLSS public final static !enum com.fnproject.fn.api.flow.Flow$FlowState - outer com.fnproject.fn.api.flow.Flow -fld public final static com.fnproject.fn.api.flow.Flow$FlowState CANCELLED -fld public final static com.fnproject.fn.api.flow.Flow$FlowState FAILED -fld public final static com.fnproject.fn.api.flow.Flow$FlowState KILLED -fld public final static com.fnproject.fn.api.flow.Flow$FlowState SUCCEEDED -fld public final static com.fnproject.fn.api.flow.Flow$FlowState UNKNOWN -meth public static com.fnproject.fn.api.flow.Flow$FlowState valueOf(java.lang.String) -meth public static com.fnproject.fn.api.flow.Flow$FlowState[] values() -supr java.lang.Enum - -CLSS public com.fnproject.fn.api.flow.FlowCompletionException -cons public init(java.lang.String) -cons public init(java.lang.String,java.lang.Throwable) -cons public init(java.lang.Throwable) -supr java.lang.RuntimeException - -CLSS public abstract interface com.fnproject.fn.api.flow.FlowFuture<%0 extends java.lang.Object> -intf java.io.Serializable -meth public abstract <%0 extends java.lang.Object, %1 extends java.lang.Object> com.fnproject.fn.api.flow.FlowFuture<{%%1}> thenCombine(com.fnproject.fn.api.flow.FlowFuture,com.fnproject.fn.api.flow.Flows$SerBiFunction) -meth public abstract <%0 extends java.lang.Object> com.fnproject.fn.api.flow.FlowFuture thenAcceptBoth(com.fnproject.fn.api.flow.FlowFuture<{%%0}>,com.fnproject.fn.api.flow.Flows$SerBiConsumer<{com.fnproject.fn.api.flow.FlowFuture%0},{%%0}>) -meth public abstract <%0 extends java.lang.Object> com.fnproject.fn.api.flow.FlowFuture<{%%0}> applyToEither(com.fnproject.fn.api.flow.FlowFuture,com.fnproject.fn.api.flow.Flows$SerFunction<{com.fnproject.fn.api.flow.FlowFuture%0},{%%0}>) -meth public abstract <%0 extends java.lang.Object> com.fnproject.fn.api.flow.FlowFuture<{%%0}> handle(com.fnproject.fn.api.flow.Flows$SerBiFunction) -meth public abstract <%0 extends java.lang.Object> com.fnproject.fn.api.flow.FlowFuture<{%%0}> thenApply(com.fnproject.fn.api.flow.Flows$SerFunction<{com.fnproject.fn.api.flow.FlowFuture%0},{%%0}>) -meth public abstract <%0 extends java.lang.Object> com.fnproject.fn.api.flow.FlowFuture<{%%0}> thenCompose(com.fnproject.fn.api.flow.Flows$SerFunction<{com.fnproject.fn.api.flow.FlowFuture%0},com.fnproject.fn.api.flow.FlowFuture<{%%0}>>) -meth public abstract boolean cancel() -meth public abstract boolean complete({com.fnproject.fn.api.flow.FlowFuture%0}) -meth public abstract boolean completeExceptionally(java.lang.Throwable) -meth public abstract com.fnproject.fn.api.flow.FlowFuture acceptEither(com.fnproject.fn.api.flow.FlowFuture,com.fnproject.fn.api.flow.Flows$SerConsumer<{com.fnproject.fn.api.flow.FlowFuture%0}>) -meth public abstract com.fnproject.fn.api.flow.FlowFuture thenAccept(com.fnproject.fn.api.flow.Flows$SerConsumer<{com.fnproject.fn.api.flow.FlowFuture%0}>) -meth public abstract com.fnproject.fn.api.flow.FlowFuture thenRun(com.fnproject.fn.api.flow.Flows$SerRunnable) -meth public abstract com.fnproject.fn.api.flow.FlowFuture<{com.fnproject.fn.api.flow.FlowFuture%0}> exceptionally(com.fnproject.fn.api.flow.Flows$SerFunction) -meth public abstract com.fnproject.fn.api.flow.FlowFuture<{com.fnproject.fn.api.flow.FlowFuture%0}> exceptionallyCompose(com.fnproject.fn.api.flow.Flows$SerFunction>) -meth public abstract com.fnproject.fn.api.flow.FlowFuture<{com.fnproject.fn.api.flow.FlowFuture%0}> whenComplete(com.fnproject.fn.api.flow.Flows$SerBiConsumer<{com.fnproject.fn.api.flow.FlowFuture%0},java.lang.Throwable>) -meth public abstract {com.fnproject.fn.api.flow.FlowFuture%0} get() -meth public abstract {com.fnproject.fn.api.flow.FlowFuture%0} get(long,java.util.concurrent.TimeUnit) throws java.util.concurrent.TimeoutException -meth public abstract {com.fnproject.fn.api.flow.FlowFuture%0} getNow({com.fnproject.fn.api.flow.FlowFuture%0}) - -CLSS public final com.fnproject.fn.api.flow.Flows -innr public abstract interface static FlowSource -innr public abstract interface static SerBiConsumer -innr public abstract interface static SerBiFunction -innr public abstract interface static SerCallable -innr public abstract interface static SerConsumer -innr public abstract interface static SerFunction -innr public abstract interface static SerRunnable -innr public abstract interface static SerSupplier -meth public static com.fnproject.fn.api.flow.Flow currentFlow() -meth public static com.fnproject.fn.api.flow.Flows$FlowSource getCurrentFlowSource() -meth public static void setCurrentFlowSource(com.fnproject.fn.api.flow.Flows$FlowSource) -supr java.lang.Object -hfds flowSource - -CLSS public abstract interface static com.fnproject.fn.api.flow.Flows$FlowSource - outer com.fnproject.fn.api.flow.Flows -meth public abstract com.fnproject.fn.api.flow.Flow currentFlow() - -CLSS public abstract interface static com.fnproject.fn.api.flow.Flows$SerBiConsumer<%0 extends java.lang.Object, %1 extends java.lang.Object> - outer com.fnproject.fn.api.flow.Flows - anno 0 java.lang.FunctionalInterface() -intf java.io.Serializable -intf java.util.function.BiConsumer<{com.fnproject.fn.api.flow.Flows$SerBiConsumer%0},{com.fnproject.fn.api.flow.Flows$SerBiConsumer%1}> - -CLSS public abstract interface static com.fnproject.fn.api.flow.Flows$SerBiFunction<%0 extends java.lang.Object, %1 extends java.lang.Object, %2 extends java.lang.Object> - outer com.fnproject.fn.api.flow.Flows - anno 0 java.lang.FunctionalInterface() -intf java.io.Serializable -intf java.util.function.BiFunction<{com.fnproject.fn.api.flow.Flows$SerBiFunction%0},{com.fnproject.fn.api.flow.Flows$SerBiFunction%1},{com.fnproject.fn.api.flow.Flows$SerBiFunction%2}> - -CLSS public abstract interface static com.fnproject.fn.api.flow.Flows$SerCallable<%0 extends java.lang.Object> - outer com.fnproject.fn.api.flow.Flows - anno 0 java.lang.FunctionalInterface() -intf java.io.Serializable -intf java.util.concurrent.Callable<{com.fnproject.fn.api.flow.Flows$SerCallable%0}> - -CLSS public abstract interface static com.fnproject.fn.api.flow.Flows$SerConsumer<%0 extends java.lang.Object> - outer com.fnproject.fn.api.flow.Flows - anno 0 java.lang.FunctionalInterface() -intf java.io.Serializable -intf java.util.function.Consumer<{com.fnproject.fn.api.flow.Flows$SerConsumer%0}> - -CLSS public abstract interface static com.fnproject.fn.api.flow.Flows$SerFunction<%0 extends java.lang.Object, %1 extends java.lang.Object> - outer com.fnproject.fn.api.flow.Flows - anno 0 java.lang.FunctionalInterface() -intf java.io.Serializable -intf java.util.function.Function<{com.fnproject.fn.api.flow.Flows$SerFunction%0},{com.fnproject.fn.api.flow.Flows$SerFunction%1}> - -CLSS public abstract interface static com.fnproject.fn.api.flow.Flows$SerRunnable - outer com.fnproject.fn.api.flow.Flows - anno 0 java.lang.FunctionalInterface() -intf java.io.Serializable -intf java.lang.Runnable - -CLSS public abstract interface static com.fnproject.fn.api.flow.Flows$SerSupplier<%0 extends java.lang.Object> - outer com.fnproject.fn.api.flow.Flows - anno 0 java.lang.FunctionalInterface() -intf java.io.Serializable -intf java.util.function.Supplier<{com.fnproject.fn.api.flow.Flows$SerSupplier%0}> - -CLSS public com.fnproject.fn.api.flow.FunctionInvocationException -cons public init(com.fnproject.fn.api.flow.HttpResponse) -meth public com.fnproject.fn.api.flow.HttpResponse getFunctionResponse() -supr java.lang.RuntimeException -hfds functionResponse - -CLSS public com.fnproject.fn.api.flow.FunctionInvokeFailedException -cons public init(java.lang.String) -supr com.fnproject.fn.api.flow.PlatformException - -CLSS public com.fnproject.fn.api.flow.FunctionTimeoutException -cons public init(java.lang.String) -supr com.fnproject.fn.api.flow.PlatformException - -CLSS public final !enum com.fnproject.fn.api.flow.HttpMethod -fld public final static com.fnproject.fn.api.flow.HttpMethod DELETE -fld public final static com.fnproject.fn.api.flow.HttpMethod GET -fld public final static com.fnproject.fn.api.flow.HttpMethod HEAD -fld public final static com.fnproject.fn.api.flow.HttpMethod OPTIONS -fld public final static com.fnproject.fn.api.flow.HttpMethod PATCH -fld public final static com.fnproject.fn.api.flow.HttpMethod POST -fld public final static com.fnproject.fn.api.flow.HttpMethod PUT -meth public java.lang.String toString() -meth public static com.fnproject.fn.api.flow.HttpMethod valueOf(java.lang.String) -meth public static com.fnproject.fn.api.flow.HttpMethod[] values() -supr java.lang.Enum -hfds verb - -CLSS public abstract interface com.fnproject.fn.api.flow.HttpRequest -meth public abstract byte[] getBodyAsBytes() -meth public abstract com.fnproject.fn.api.Headers getHeaders() -meth public abstract com.fnproject.fn.api.flow.HttpMethod getMethod() - -CLSS public abstract interface com.fnproject.fn.api.flow.HttpResponse -meth public abstract byte[] getBodyAsBytes() -meth public abstract com.fnproject.fn.api.Headers getHeaders() -meth public abstract int getStatusCode() - -CLSS public com.fnproject.fn.api.flow.InvalidStageResponseException -cons public init(java.lang.String) -supr com.fnproject.fn.api.flow.PlatformException - -CLSS public com.fnproject.fn.api.flow.LambdaSerializationException -cons public init(java.lang.String) -cons public init(java.lang.String,java.lang.Exception) -supr com.fnproject.fn.api.flow.FlowCompletionException - -CLSS public com.fnproject.fn.api.flow.PlatformException -cons public init(java.lang.String) -cons public init(java.lang.String,java.lang.Throwable) -cons public init(java.lang.Throwable) -meth public java.lang.Throwable fillInStackTrace() -supr com.fnproject.fn.api.flow.FlowCompletionException - -CLSS public com.fnproject.fn.api.flow.ResultSerializationException -cons public init(java.lang.String,java.lang.Throwable) -supr com.fnproject.fn.api.flow.FlowCompletionException - -CLSS public com.fnproject.fn.api.flow.StageInvokeFailedException -cons public init(java.lang.String) -supr com.fnproject.fn.api.flow.PlatformException - -CLSS public com.fnproject.fn.api.flow.StageLostException -cons public init(java.lang.String) -supr com.fnproject.fn.api.flow.PlatformException - -CLSS public com.fnproject.fn.api.flow.StageTimeoutException -cons public init(java.lang.String) -supr com.fnproject.fn.api.flow.PlatformException - -CLSS public final com.fnproject.fn.api.flow.WrappedFunctionException -cons public init(java.lang.Throwable) -intf java.io.Serializable -meth public java.lang.Class getOriginalExceptionType() -supr java.lang.RuntimeException -hfds originalExceptionType - CLSS public abstract interface java.io.Closeable intf java.lang.AutoCloseable meth public abstract void close() throws java.io.IOException @@ -350,12 +194,6 @@ cons public init(java.lang.Throwable) supr java.lang.Throwable hfds serialVersionUID -CLSS public abstract interface !annotation java.lang.FunctionalInterface - anno 0 java.lang.annotation.Documented() - anno 0 java.lang.annotation.Retention(java.lang.annotation.RetentionPolicy value=RUNTIME) - anno 0 java.lang.annotation.Target(java.lang.annotation.ElementType[] value=[TYPE]) -intf java.lang.annotation.Annotation - CLSS public java.lang.Object cons public init() meth protected java.lang.Object clone() throws java.lang.CloneNotSupportedException @@ -370,10 +208,6 @@ meth public final void wait(long,int) throws java.lang.InterruptedException meth public int hashCode() meth public java.lang.String toString() -CLSS public abstract interface java.lang.Runnable - anno 0 java.lang.FunctionalInterface() -meth public abstract void run() - CLSS public java.lang.RuntimeException cons protected init(java.lang.String,java.lang.Throwable,boolean,boolean) cons public init() @@ -435,33 +269,3 @@ meth public abstract java.lang.annotation.ElementType[] value() CLSS public abstract interface java.util.EventListener -CLSS public abstract interface java.util.concurrent.Callable<%0 extends java.lang.Object> - anno 0 java.lang.FunctionalInterface() -meth public abstract {java.util.concurrent.Callable%0} call() throws java.lang.Exception - -CLSS public abstract interface java.util.function.BiConsumer<%0 extends java.lang.Object, %1 extends java.lang.Object> - anno 0 java.lang.FunctionalInterface() -meth public abstract void accept({java.util.function.BiConsumer%0},{java.util.function.BiConsumer%1}) -meth public java.util.function.BiConsumer<{java.util.function.BiConsumer%0},{java.util.function.BiConsumer%1}> andThen(java.util.function.BiConsumer) - -CLSS public abstract interface java.util.function.BiFunction<%0 extends java.lang.Object, %1 extends java.lang.Object, %2 extends java.lang.Object> - anno 0 java.lang.FunctionalInterface() -meth public <%0 extends java.lang.Object> java.util.function.BiFunction<{java.util.function.BiFunction%0},{java.util.function.BiFunction%1},{%%0}> andThen(java.util.function.Function) -meth public abstract {java.util.function.BiFunction%2} apply({java.util.function.BiFunction%0},{java.util.function.BiFunction%1}) - -CLSS public abstract interface java.util.function.Consumer<%0 extends java.lang.Object> - anno 0 java.lang.FunctionalInterface() -meth public abstract void accept({java.util.function.Consumer%0}) -meth public java.util.function.Consumer<{java.util.function.Consumer%0}> andThen(java.util.function.Consumer) - -CLSS public abstract interface java.util.function.Function<%0 extends java.lang.Object, %1 extends java.lang.Object> - anno 0 java.lang.FunctionalInterface() -meth public <%0 extends java.lang.Object> java.util.function.Function<{%%0},{java.util.function.Function%1}> compose(java.util.function.Function) -meth public <%0 extends java.lang.Object> java.util.function.Function<{java.util.function.Function%0},{%%0}> andThen(java.util.function.Function) -meth public abstract {java.util.function.Function%1} apply({java.util.function.Function%0}) -meth public static <%0 extends java.lang.Object> java.util.function.Function<{%%0},{%%0}> identity() - -CLSS public abstract interface java.util.function.Supplier<%0 extends java.lang.Object> - anno 0 java.lang.FunctionalInterface() -meth public abstract {java.util.function.Supplier%0} get() - diff --git a/api/src/main/java/com/fnproject/fn/api/FnFeature.java b/api/src/main/java/com/fnproject/fn/api/FnFeature.java new file mode 100644 index 00000000..9d2e886d --- /dev/null +++ b/api/src/main/java/com/fnproject/fn/api/FnFeature.java @@ -0,0 +1,21 @@ +package com.fnproject.fn.api; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +/** + * Annotation to be used in user function classes to enable runtime-wide feature. + * + * Runtime features are initialized at the point that the function class is loaded but prior to the call chain. + */ +@Retention(RetentionPolicy.RUNTIME) +@Target(ElementType.TYPE) +public @interface FnFeature { + /** + * The feature class to load this must have a zero-arg public constructor + * @return feature class + */ + Class value(); +} diff --git a/api/src/main/java/com/fnproject/fn/api/FunctionInvoker.java b/api/src/main/java/com/fnproject/fn/api/FunctionInvoker.java index 7f1fa29a..70b9fd5d 100644 --- a/api/src/main/java/com/fnproject/fn/api/FunctionInvoker.java +++ b/api/src/main/java/com/fnproject/fn/api/FunctionInvoker.java @@ -6,6 +6,22 @@ * Handles the invocation of a given function call */ public interface FunctionInvoker { + /** + * Phase determines a loose ordering for invocation handler processing + * this should be used with {@link RuntimeContext#addInvoker(FunctionInvoker, Phase)} to add new invoke handlers to a runtime + */ + enum Phase { + /** + * The Pre-Call phase runs before the main function call, all {@link FunctionInvoker} handlers added at this phase are tried prior to calling the {@link Phase#Call} phase + * This phase is typically used for handlers that /may/ intercept the request based on request attributes + */ + PreCall, + /** + * The Call Phase indicates invokers that should handle call values - typically a given runtime will only be handled by one of these + */ + Call + } + /** * Optionally handles an invocation chain for this function *

diff --git a/api/src/main/java/com/fnproject/fn/api/Headers.java b/api/src/main/java/com/fnproject/fn/api/Headers.java index 2e069c03..6995c771 100644 --- a/api/src/main/java/com/fnproject/fn/api/Headers.java +++ b/api/src/main/java/com/fnproject/fn/api/Headers.java @@ -1,16 +1,59 @@ package com.fnproject.fn.api; +import java.io.Serializable; import java.util.*; +import java.util.regex.Pattern; +import java.util.stream.Stream; /** - * Represents the headers on an HTTP request or response. Multiple headers with the same key are collapsed into a single - * entry where the values are concatenated by commas as per the HTTP spec (RFC 7230). + * Represents a set of String-String[] header attributes, per HTTP headers. + *

+ * Internally header keys are always canonicalized using HTTP header conventions + *

+ * Headers objects are immutable + *

+ * Keys are are stored and compared in a case-insensitive way and are canonicalised according to RFC 7230 conventions such that : + * + *

    + *
  • a-header
  • + *
  • A-Header
  • + *
  • A-HeaDer
  • + *
+ * are all equivalent - keys are returned in the canonical form (lower cased except for leading characters) + * Where keys do not comply with HTTP header naming they are left as is. */ -public final class Headers { - private Map headers; +public final class Headers implements Serializable { + private static final Headers emptyHeaders = new Headers(Collections.emptyMap()); + private Map> headers; + + private Headers(Map> headersIn) { + this.headers = headersIn; + } + + private static Pattern headerName = Pattern.compile("[A-Za-z0-9!#%&'*+-.^_`|~]+"); + + + /** + * Calculates the canonical key (cf RFC 7230) for a header + *

+ * If the header contains invalid characters it returns the original header + * + * @param key the header key to canonicalise + * @return a canonical key or the original key if the input contains invalid character + */ + public static String canonicalKey(String key) { + if (!headerName.matcher(key).matches()) { + return key; + } + String parts[] = key.split("-", -1); + for (int i = 0; i < parts.length; i++) { + String p = parts[i]; + if (p.length() > 0) { + parts[i] = p.substring(0, 1).toUpperCase() + p.substring(1).toLowerCase(); + } + } + return String.join("-", parts); - private Headers(Map headers) { - this.headers = headers; } /** @@ -21,6 +64,23 @@ private Headers(Map headers) { * @return {@code Headers} built from headers map */ public static Headers fromMap(Map headers) { + Objects.requireNonNull(headers, "headersIn"); + Map> h = new HashMap<>(); + headers.forEach((k, v) -> h.put(canonicalKey(k), Collections.singletonList(v))); + return new Headers(Collections.unmodifiableMap(new HashMap<>(h))); + } + + /** + * Build a headers object from a map composed of (name, value) entries, we take a copy of the map and + * disallow any further modification + * + * @param headers underlying collection of header entries to copy + * @return {@code Headers} built from headers map + */ + public static Headers fromMultiHeaderMap(Map> headers) { + Map> hm = new HashMap<>(); + + headers.forEach((k, vs) -> hm.put(canonicalKey(k), new ArrayList<>(vs))); return new Headers(Collections.unmodifiableMap(new HashMap<>(Objects.requireNonNull(headers)))); } @@ -30,23 +90,112 @@ public static Headers fromMap(Map headers) { * @return empty headers */ public static Headers emptyHeaders() { - return new Headers(Collections.emptyMap()); + return emptyHeaders; } /** - * Creates a new headers object with the specified header added + * Creates a new headers object with the specified header added - if a header with the same key existed it the new value is appended + *

+ * This will overwrite an existing header with an exact name match * + * @param key new header key + * @param v1 new header value + * @param vs additional header values to set + * @return a new headers object with the specified header added + */ + public Headers addHeader(String key, String v1, String... vs) { + Objects.requireNonNull(key, "key"); + Objects.requireNonNull(key, "value"); + + String canonKey = canonicalKey(key); + + Map> nm = new HashMap<>(headers); + List current = nm.get(canonKey); + + if (current == null) { + List s = new ArrayList<>(); + s.add(v1); + s.addAll(Arrays.asList(vs)); + + nm.put(canonKey, Collections.unmodifiableList(s)); + } else { + List s = new ArrayList<>(current); + s.add(v1); + s.addAll(Arrays.asList(vs)); + nm.put(canonKey, Collections.unmodifiableList(s)); + } + return new Headers(nm); + + } + + /** + * Creates a new headers object with the specified header set - this overwrites any existin values + *

* This will overwrite an existing header with an exact name match + * * @param key new header key - * @param value new header value + * @param v1 new header value + * @param vs more header values to set * @return a new headers object with the specified header added */ - public Headers withHeader(String key, String value){ - Map newHeaders = new HashMap<>(); - newHeaders.putAll(getAll()); - newHeaders.put(key,value); - return new Headers(newHeaders); + public Headers setHeader(String key, String v1, String... vs) { + Objects.requireNonNull(key, "key"); + Objects.requireNonNull(v1, "v1"); + Stream.of(vs).forEach((v) -> Objects.requireNonNull(v, "vs")); + + Map> nm = new HashMap<>(headers); + List s = new ArrayList<>(); + s.add(v1); + s.addAll(Arrays.asList(vs)); + nm.put(canonicalKey(key), Collections.unmodifiableList(s)); + return new Headers(Collections.unmodifiableMap(nm)); + } + + + /** + * Creates a new headers object with the specified headers set - this overwrites any existin values + *

+ * This will overwrite an existing header with an exact name match + * + * @param key new header key + * @param vs header values to set + * @return a new headers object with the specified header added + */ + public Headers setHeader(String key, Collection vs) { + Objects.requireNonNull(key, "key"); + Objects.requireNonNull(vs, "vs"); + if (vs.size() == 0) { + throw new IllegalArgumentException("can't set keys to an empty list"); + } + vs.forEach((v) -> Objects.requireNonNull(v, "vs")); + + Map> nm = new HashMap<>(headers); + nm.put(canonicalKey(key), Collections.unmodifiableList(new ArrayList<>(vs))); + return new Headers(Collections.unmodifiableMap(nm)); + + } + + /** + * Creates a new headers object with the specified headers remove - this overwrites any existin values + *

+ * This will overwrite an existing header with an exact name match + * + * @param key new header key + * @return a new headers object with the specified header removed + */ + public Headers removeHeader(String key) { + Objects.requireNonNull(key, "key"); + + String canonKey = canonicalKey(key); + if (!headers.containsKey(canonKey)) { + return this; + } + + Map> nm = new HashMap<>(headers); + nm.remove(canonKey); + return new Headers(Collections.unmodifiableMap(nm)); + } /** @@ -54,19 +203,7 @@ public Headers withHeader(String key, String value){ * underscore and hyphen characters such that : "CONTENT_TYPE" and "Content-type" are equivalent. If no matching * header is found then {@code Optional.empty} is returned. *

- * Multiple headers are collapsed by {@code fn} into a single header entry delimited by commas (see - * RFC7230 Sec 3.2.2 for details), for example - * - *

-     *     Accept: text/html
-     *     Accept: text/plain
-     * 
- * - * is collapsed into - * - *
-     *     Accept: text/html, text/plain
-     * 
+ * When multiple headers are present then the first value is returned- see { #getAllValues(String key)} to get all values for a header * * @param key match key * @return a header matching key or empty if no header matches. @@ -74,20 +211,56 @@ public Headers withHeader(String key, String value){ */ public Optional get(String key) { Objects.requireNonNull(key, "Key cannot be null"); - return getAll().entrySet().stream() - .filter((e) -> e.getKey() - .replaceAll("-", "_") - .equalsIgnoreCase(key.replaceAll("-", "_"))) - .map(Map.Entry::getValue) - .findFirst(); + String canonKey = canonicalKey(key); + + return headers.entrySet().stream() + .filter((e) -> e.getKey() + .equals(canonKey)) + .map(Map.Entry::getValue) + .map((v) -> v.get(0)) + .findFirst(); + } + + /** + * Returns a collection of current header keys + * + * @return a collection of keys + */ + public Collection keys() { + return headers.keySet(); } /** - * The function invocation headers passed on the request + * Returns the headers as a map * - * @return a map of Invocation headers. + * @return a map of key-values */ - public Map getAll() { + public Map> asMap() { return headers; } + + public List getAllValues(String key) { + return headers.getOrDefault(key, Collections.emptyList()); + } + + public int hashCode() { + return headers.hashCode(); + } + + + public boolean equals(Object other) { + if (!(other instanceof Headers)) { + return false; + } + if (other == this) { + return true; + } + return headers.equals(((Headers) other).headers); + } + + @Override + public String toString() { + return Objects.toString(headers); + } + } diff --git a/api/src/main/java/com/fnproject/fn/api/InputEvent.java b/api/src/main/java/com/fnproject/fn/api/InputEvent.java index 2ecab8aa..9eeaf234 100644 --- a/api/src/main/java/com/fnproject/fn/api/InputEvent.java +++ b/api/src/main/java/com/fnproject/fn/api/InputEvent.java @@ -2,6 +2,8 @@ import java.io.Closeable; import java.io.InputStream; +import java.time.Instant; +import java.util.Date; import java.util.function.Function; public interface InputEvent extends Closeable { @@ -17,29 +19,21 @@ public interface InputEvent extends Closeable { */ T consumeBody(Function dest); - /** - * The application name associated with this function - * - * @return an application name - */ - String getAppName(); - /** - * @return The route (including preceding slash) of this function call - */ - String getRoute(); /** - * @return The full request URL of this function invocation + * return the current call ID for this event + * @return a call ID */ - String getRequestUrl(); + String getCallID(); + /** - * The HTTP method used to invoke this function + * The deadline by which this event should be processed - this is information and is intended to help you determine how long you should spend processing your event - if you exceed this deadline Fn will terminate your container. * - * @return an UpperCase HTTP method + * @return a deadline relative to the current system clock that the event must be processed by */ - String getMethod(); + Instant getDeadline(); /** @@ -49,11 +43,5 @@ public interface InputEvent extends Closeable { */ Headers getHeaders(); - /** - * The query parameters of the function invocation - * - * @return an immutable map of query parameters parsed from the request URL - */ - QueryParameters getQueryParameters(); } diff --git a/api/src/main/java/com/fnproject/fn/api/OutputEvent.java b/api/src/main/java/com/fnproject/fn/api/OutputEvent.java index ef13983c..6dcfa381 100644 --- a/api/src/main/java/com/fnproject/fn/api/OutputEvent.java +++ b/api/src/main/java/com/fnproject/fn/api/OutputEvent.java @@ -3,37 +3,71 @@ import java.io.IOException; import java.io.OutputStream; +import java.util.Objects; import java.util.Optional; /** * Wrapper for an outgoing fn event */ public interface OutputEvent { + + /** + * The outcome status of this function event + * This determines how the platform will reflect this error to the customer and how it will treat the container after an error + */ + enum Status { + /** + * The event was successfully processed + */ + Success(200), + /** + * The Function code raised unhandled exception + */ + FunctionError(502), + /** + * The Function code did not respond within a given timeout + */ + FunctionTimeout(504), + /** + * An internal error occurred in the FDK + */ + InternalError(500); + + private final int code; + + Status(int code) { + this.code = code; + } + + public int getCode() { + return this.code; + } + + } + + + /** - * Report the HTTP status code of this event. - * For default-format functions, this value is mapped into a success/failure value as follows: - * status codes in the range [100, 400) are considered successful; anything else is a failure. + * Report the outcome status code of this event. * - * @return the status code associated with this event + * @return the status associated with this event */ - int getStatusCode(); + Status getStatus(); - int SUCCESS = 200; - int FAILURE = 500; /** * Report the boolean success of this event. * For default-format functions, this is used to map the HTTP status code into a straight success/failure. + * * @return true if the output event results from a successful invocation. */ default boolean isSuccess() { - return 100 <= getStatusCode() && getStatusCode() < 400; + return getStatus() == Status.Success; } /** - * The indicative content type of the response. + * The content type of the response. *

- * This will only be used when the function format is HTTP * * @return The name of the content type. */ @@ -41,7 +75,7 @@ default boolean isSuccess() { /** * Any additional {@link Headers} that should be supplied along with the content - * + *

* These are only used when the function format is HTTP * * @return the headers to add @@ -51,8 +85,8 @@ default boolean isSuccess() { /** * Write the body of the output to a stream * - * @param out an outputstream to emit the body of the event - * @throws IOException OutputStream exceptions percolate up through this method + * @param out an outputstream to emit the body of the event + * @throws IOException OutputStream exceptions percolate up through this method */ void writeToOutput(OutputStream out) throws IOException; @@ -61,32 +95,33 @@ default boolean isSuccess() { * Create an output event from a byte array * * @param bytes the byte array to write to the output - * @param statusCode the status code to report + * @param status the status code to report * @param contentType the content type to present on HTTP responses * @return a new output event */ - static OutputEvent fromBytes(byte[] bytes, int statusCode, String contentType) { - return fromBytes(bytes, statusCode, contentType, Headers.emptyHeaders()); - } + static OutputEvent fromBytes(byte[] bytes, Status status, String contentType) { + return fromBytes(bytes, status, contentType, Headers.emptyHeaders()); + } /** * Create an output event from a byte array * * @param bytes the byte array to write to the output - * @param statusCode the HTTP status code of this event + * @param status the status code of this event * @param contentType the content type to present on HTTP responses * @param headers any additional headers to supply with HTTP responses * @return a new output event */ - static OutputEvent fromBytes(byte[] bytes, int statusCode, String contentType, Headers headers) { - if (statusCode < 100 || 600 <= statusCode) { - throw new IllegalArgumentException("Valid status codes must lie in the range [100, 599]"); - } + static OutputEvent fromBytes(final byte[] bytes, final Status status, final String contentType, final Headers headers) { + Objects.requireNonNull(bytes, "bytes"); + Objects.requireNonNull(status, "status"); + Objects.requireNonNull(headers, "headers"); + return new OutputEvent() { @Override - public int getStatusCode() { - return statusCode; + public Status getStatus() { + return status; } @Override @@ -95,7 +130,9 @@ public Optional getContentType() { } @Override - public Headers getHeaders() { return headers; } + public Headers getHeaders() { + return headers; + } @Override public void writeToOutput(OutputStream out) throws IOException { @@ -104,14 +141,13 @@ public void writeToOutput(OutputStream out) throws IOException { }; } - static OutputEvent emptyResult(int statusCode) { - if (statusCode < 100 || 600 <= statusCode) { - throw new IllegalArgumentException("Valid status codes must lie in the range [100, 599]"); - } + static OutputEvent emptyResult(final Status status) { + Objects.requireNonNull(status, "status"); + return new OutputEvent() { @Override - public int getStatusCode() { - return statusCode; + public Status getStatus() { + return status; } @Override @@ -120,7 +156,9 @@ public Optional getContentType() { } @Override - public Headers getHeaders() { return Headers.emptyHeaders(); } + public Headers getHeaders() { + return Headers.emptyHeaders(); + } @Override public void writeToOutput(OutputStream out) throws IOException { diff --git a/api/src/main/java/com/fnproject/fn/api/QueryParameters.java b/api/src/main/java/com/fnproject/fn/api/QueryParameters.java index 08514054..f0dacd05 100644 --- a/api/src/main/java/com/fnproject/fn/api/QueryParameters.java +++ b/api/src/main/java/com/fnproject/fn/api/QueryParameters.java @@ -7,7 +7,7 @@ /** * Wrapper for query parameters map parsed from the URL of a function invocation. */ -public interface QueryParameters { +public interface QueryParameters { /** * Find the first entry for {@code key} if it exists otherwise returns {@code Optional.empty} * diff --git a/api/src/main/java/com/fnproject/fn/api/RuntimeContext.java b/api/src/main/java/com/fnproject/fn/api/RuntimeContext.java index 865a6d10..08466cb7 100644 --- a/api/src/main/java/com/fnproject/fn/api/RuntimeContext.java +++ b/api/src/main/java/com/fnproject/fn/api/RuntimeContext.java @@ -13,6 +13,20 @@ * of a function; they will not change between multiple invocations of a hot function. */ public interface RuntimeContext { + + + /** + * The application ID of the application associated with this function + * @return an application ID + */ + String getAppID(); + + /** + * THe function ID of the function + * @return a function ID + */ + String getFunctionID(); + /** * Create an instance of the user specified class on which the target function to invoke is declared. * @@ -77,7 +91,7 @@ public interface RuntimeContext { * * @param targetMethod The user function method * @param param The index of the parameter - * @return a list of configured input coercions to apply to the given parameter + * @return a list of configured input coercions to apply to the given parameter */ List getInputCoercions(MethodWrapper targetMethod, int param); @@ -105,7 +119,21 @@ public interface RuntimeContext { * Set an {@link FunctionInvoker} for this function. The invoker will override * the built in function invoker, although the cloud threads invoker will still * have precedence so that cloud threads can be used from functions using custom invokers. + * * @param invoker The {@link FunctionInvoker} to add. + * @deprecated this is equivalent to {@link #addInvoker(FunctionInvoker, FunctionInvoker.Phase)} with a phase of {@link FunctionInvoker.Phase#Call} + */ + default void setInvoker(FunctionInvoker invoker) { + addInvoker(invoker, FunctionInvoker.Phase.Call); + } + + + /** + * Adds an FunctionInvoker handler to the runtime - new FunctionInvokers are added at the head of the specific phase they apply to so ordering may be important + * + * + * @param invoker an invoker to use to handle a given call + * @param phase the phase at which to add the invoke */ - void setInvoker(FunctionInvoker invoker); + void addInvoker(FunctionInvoker invoker, FunctionInvoker.Phase phase); } diff --git a/api/src/main/java/com/fnproject/fn/api/RuntimeFeature.java b/api/src/main/java/com/fnproject/fn/api/RuntimeFeature.java new file mode 100644 index 00000000..43365794 --- /dev/null +++ b/api/src/main/java/com/fnproject/fn/api/RuntimeFeature.java @@ -0,0 +1,17 @@ +package com.fnproject.fn.api; + +/** + * RuntimeFeatures are classes that configure the Fn Runtime prior to startup and can be loaded by annotating the function class with a {@link FnFeature} annotation + * Created on 10/09/2018. + *

+ * (c) 2018 Oracle Corporation + */ +public interface RuntimeFeature { + + /** + * Initialize the runtime context for this function + * + * @param context a runtime context to initalize + */ + void initialize(RuntimeContext context); +} diff --git a/api/src/main/java/com/fnproject/fn/api/httpgateway/HTTPGatewayRequest.java b/api/src/main/java/com/fnproject/fn/api/httpgateway/HTTPGatewayRequest.java new file mode 100644 index 00000000..bb00abb8 --- /dev/null +++ b/api/src/main/java/com/fnproject/fn/api/httpgateway/HTTPGatewayRequest.java @@ -0,0 +1,25 @@ +package com.fnproject.fn.api.httpgateway; + +import com.fnproject.fn.api.Headers; +import com.fnproject.fn.api.QueryParameters; + +import java.io.InputStream; +import java.util.function.Function; + +/** + * Created on 05/09/2018. + *

+ * (c) 2018 Oracle Corporation + */ +public interface HTTPGatewayRequest { + + String getMethod(); + + String getRequestURI(); + + Headers getHeaders(); + + QueryParameters getQueryParameters(); + + T consumeBody(Function dest); +} diff --git a/api/src/main/java/com/fnproject/fn/api/httpgateway/HTTPResponse.java b/api/src/main/java/com/fnproject/fn/api/httpgateway/HTTPResponse.java new file mode 100644 index 00000000..78052a7f --- /dev/null +++ b/api/src/main/java/com/fnproject/fn/api/httpgateway/HTTPResponse.java @@ -0,0 +1,26 @@ +package com.fnproject.fn.api.httpgateway; + +import com.fnproject.fn.api.Headers; + +import java.io.IOException; +import java.io.OutputStream; + +/** + * Created on 05/09/2018. + *

+ * (c) 2018 Oracle Corporation + */ +public interface HTTPResponse { + + int getStatusCode(); + + Headers getHeaders(); + + /** + * Write the body of the output to a stream + * + * @param out an outputstream to emit the body of the event + * @throws IOException OutputStream exceptions percolate up through this method + */ + void writeToOutput(OutputStream out) throws IOException; +} diff --git a/api/src/test/java/com/fnproject/fn/api/HeadersTest.java b/api/src/test/java/com/fnproject/fn/api/HeadersTest.java new file mode 100644 index 00000000..4ec75e23 --- /dev/null +++ b/api/src/test/java/com/fnproject/fn/api/HeadersTest.java @@ -0,0 +1,31 @@ +package com.fnproject.fn.api; + +import org.junit.Test; +import static org.assertj.core.api.Assertions.assertThat; + +/** + * Created on 10/09/2018. + *

+ * (c) 2018 Oracle Corporation + */ +public class HeadersTest { + + @Test + public void shouldCanonicalizeHeaders(){ + for (String[] v : new String[][] { + {"",""}, + {"a","A"}, + {"fn-ID-","Fn-Id-"}, + {"myHeader-VaLue","Myheader-Value"}, + {" Not a Header "," Not a Header "}, + {"-","-"}, + {"--","--"}, + {"a-","A-"}, + {"-a","-A"} + }){ + assertThat(Headers.canonicalKey(v[0])).isEqualTo(v[1]); + } + } + + +} diff --git a/build-image/docker-build.sh b/build-image/docker-build.sh index d5dc37b1..c8685a89 100755 --- a/build-image/docker-build.sh +++ b/build-image/docker-build.sh @@ -1,12 +1,21 @@ #!/bin/bash -ex +if [ -z ${REPOSITORY_LOCATION} ] ; then + echo no REPOSITORY_LOCATION set + exit 1; +fi -cd /tmp/staging-repository && python -mSimpleHTTPServer 18080 1>>/tmp/http-logs 2>&1 & -SRV_PROCESS=$! +docker rm -f fn_mvn_repo || true +docker run -d \ + -v "${REPOSITORY_LOCATION}":/repo:ro \ + -w /repo \ + --name fn_mvn_repo \ + python:2.7 \ + python -mSimpleHTTPServer 18080 -if [ -n "$DOCKER_LOCALHOST" ]; then - REPO_ENV="--build-arg FN_REPO_URL=http://$DOCKER_LOCALHOST:18080" -fi + +DOCKER_LOCALHOST=$(docker inspect --type container -f '{{.NetworkSettings.IPAddress}}' fn_mvn_repo) +REPO_ENV="--build-arg FN_REPO_URL=http://${DOCKER_LOCALHOST}:18080" docker build $REPO_ENV $* -kill $SRV_PROCESS +docker rm -f fn_mvn_repo \ No newline at end of file diff --git a/build-image/pom.xml b/build-image/pom.xml index 3bc1baa3..2a2e01cc 100644 --- a/build-image/pom.xml +++ b/build-image/pom.xml @@ -9,7 +9,7 @@ UTF-8 UTF-8 - 1.0.0-SNAPSHOT + 1.0.0-SNAPSHOT http://172.17.0.1:18080 @@ -23,18 +23,18 @@ com.fnproject.fn api - ${fnproject.version} + ${fdk.version} com.fnproject.fn testing-core - ${fnproject.version} + ${fdk.version} test com.fnproject.fn testing-junit4 - ${fnproject.version} + ${fdk.version} test diff --git a/build.sh b/build.sh new file mode 100755 index 00000000..466efad9 --- /dev/null +++ b/build.sh @@ -0,0 +1,35 @@ +#!/usr/bin/env bash + +set -e +set -x +mkdir -p /tmp/staging_repo +rm -rf /tmp/staging_repo/* + +BUILD_VERSION=${FN_FDK_VERSION:-1.0.0-SNAPSHOT} +export REPOSITORY_LOCATION=${REPOSITORY_LOCATION:-/tmp/staging_repo} + +( + runtime/src/main/c/rebuild_so.sh +) + +mvn -B deploy -DaltDeploymentRepository=localStagingDir::default::file://${REPOSITORY_LOCATION} + +( + cd build-image + ./docker-build.sh -t fnproject/fn-java-fdk-build:${BUILD_VERSION} . +) + +( + cd build-image + ./docker-build.sh -f Dockerfile-jdk9 -t fnproject/fn-java-fdk-build:jdk9-${BUILD_VERSION} . +) + +( + cd runtime + docker build -t fnproject/fn-java-fdk:${BUILD_VERSION} . +) + +( + cd runtime + docker build -f Dockerfile-jdk9 -t fnproject/fn-java-fdk:jdk9-${BUILD_VERSION} . +) diff --git a/docs/FAQ.md b/docs/FAQ.md index 375650b5..2477c4ab 100644 --- a/docs/FAQ.md +++ b/docs/FAQ.md @@ -12,11 +12,7 @@ The FDK is comprised of: - a build-time Docker image for repeatable builds. ### Is the FDK required in order to run Java on Fn? -No. You can still write Java functions on Fn without using the FDK. However using the FDK will make several things easier for you: - 1. A curated base image for Java 8 and Java 9 means that you don't have to build and maintain your own image. These images contain optimizations for quick JVM startup times. - 1. Accessing configuration from Fn is easy through FDK APIs. - 1. Input and output type coercion reduces the amount of serialization and formatting boilerplate that you have to write. - 1. A JUnit rule provides a realistic test harness for you to test your function in isolation. +Yes - The FDK implements the IO/contract with the FN service and is required to receive events from the platform ### What is Fn Flow? Fn Flow is a [Java API](https://github.com/fnproject/fn-java-fdk/blob/master/docs/FnFlowsUserGuide.md) and [corresponding service](https://github.com/fnproject/flow) that helps you create complex, long-running, fault-tolerant functions using a promises-style asynchronous API. Check out the [Fn Flow docs](https://github.com/fnproject/fn-java-fdk/blob/master/docs/FnFlowsUserGuide.md) for more information. diff --git a/docs/FnFlowsAdvancedTopics.md b/docs/FnFlowsAdvancedTopics.md index ac2f75a5..efd40e6d 100644 --- a/docs/FnFlowsAdvancedTopics.md +++ b/docs/FnFlowsAdvancedTopics.md @@ -61,6 +61,7 @@ An important consideration is that, if your lambda captures fields from your function class, then that class must also be Serializable: ```java +@FnFeature(FlowFeature.class) public class MyFunction{ private String config = "foo"; @@ -82,6 +83,7 @@ E.g. making `MyFunction` serializable will work as the function instance object will be captured alongside the lambda: ```java +@FnFeature(FlowFeature.class) public class MyFunction implements Serializable{ private String config = "foo"; @@ -104,6 +106,7 @@ prior to passing them, removing the need to make the function class serializable. For example: ```java +@FnFeature(FlowFeature.class) public class MyFunction{ private final Database db; // non-serializable object private final String config = "foo"; @@ -128,6 +131,7 @@ Alternatively, you can make non-serializable fields `transient` and construct them on the fly: ```java +@FnFeature(FlowFeature.class) public class MyFunction implements Serialiable{ private final transient Database db; // non-serializable object private final String config = "foo"; @@ -298,6 +302,7 @@ exception. E.g.: ```java +@FnFeature(FlowFeature.class) public class MyFunction{ public static class MyException extends RuntimeException{ public MyException(String message){ diff --git a/docs/FnFlowsUserGuide.md b/docs/FnFlowsUserGuide.md index 06204842..7cb4997b 100644 --- a/docs/FnFlowsUserGuide.md +++ b/docs/FnFlowsUserGuide.md @@ -99,6 +99,19 @@ func.yaml created ``` +### Add the Flow runtime to your function + +In your `pom.xml` add a depdendency on `flow-runtime` : + +```$ml + + com.fnproject.fn + flow-runtime + ${fdk.version} + + +``` + ### Create a Flow within your Function You will create a function that produces the nth prime number and then returns @@ -117,7 +130,10 @@ package com.example.fn; import com.fnproject.fn.api.flow.Flow; import com.fnproject.fn.api.flow.Flows; +import com.fnproject.fn.runtime.flow.FlowFeature; +import com.fnproject.fn.api.FnFeature; +@FnFeature(FlowFeature.class) public class PrimeFunction { public String handleRequest(int nth) { diff --git a/docs/TestingFunctions.md b/docs/TestingFunctions.md index ffabd74d..9127b16e 100644 --- a/docs/TestingFunctions.md +++ b/docs/TestingFunctions.md @@ -16,7 +16,7 @@ To import the testing library add the following dependency to your Maven project com.fnproject.fn testing - 1.0.0-SNAPSHOT + ${fdk.version} test ``` @@ -155,9 +155,33 @@ You can test that this is all handled correctly as follows: # Testing Fn Flows -You can use `FnTestingRule` to test [Fn Flows](FnFlowsUserGuide.md) within your functions. If flow stages are started by functions within `thenRun` then the testing rule will execute the stages of those flows locally, returning when all spawned flows are complete. +You can use `FlowTesting` to test [Fn Flows](FnFlowsUserGuide.md) within your functions. If flow stages are started by functions within `thenRun` then the testing rule will execute the stages of those flows locally, returning when all spawned flows are complete. -`FnTestingRule` supports mocking the behaviour of Fn functions invoked by the `invokeFunction()` API within flows. +Start by importing the `flow-testing` library into your functino in `test` scope: + +```xml + + com.fnproject.fn + flow-testing + ${fdk.version} + test + +``` + +Then create a `FlowTesting` field in your test class, passing the `FnTesting` rule as a parameter: + +```java +import com.fnproject.fn.testing.FnTestingRule; +import com.fnproject.fn.testing.flow.FlowTesting; + +public class FunctionTest { + @Rule + public final FnTestingRule testing = FnTestingRule.createDefault(); + + private final FlowTesting flowTesting = FlowTesting.create(testing); +``` + +`FlowTesting` supports mocking the behaviour of Fn functions invoked by the `invokeFunction()` API within flows. You can specify that the invocation a function returns a valid value (as a byte array): @@ -165,7 +189,7 @@ You can specify that the invocation a function returns a valid value (as a byte @Test public void callsRemoteFunctionWhichSucceeds() { - testing.givenFn("example/other-function").withResult("blah".getBytes()); + flowTesting.givenFn("example/other-function").withResult("blah".getBytes()); // ... @@ -178,8 +202,8 @@ Or you can specify that the invocation a function will cause a user error or a p @Test public void callsRemoteFunctionWhichCausesAnError() { - testing.givenFn("example/other-function").withFunctionError(); - testing.givenFn("example/other-function-2").withPlatformError(); + flowTesting.givenFn("example/other-function").withFunctionError(); + flowTesting.givenFn("example/other-function-2").withPlatformError(); // ... @@ -196,7 +220,7 @@ used to check some behavior: @Test public void callsRemoteFunction() { - testing.givenFn("example/other-function").withAction( (data) -> { called.set(true); return data; } ); + flowTesting.givenFn("example/other-function").withAction( (data) -> { called.set(true); return data; } ); called.set(false); @@ -221,7 +245,7 @@ If you need to share objects or static data between your test classes and your f ```java testing.addSharedClass(MyClassWithStaticState.class); // Shares only the specific class testing.addSharedPrefix("com.example.MyClassWithStaticState"); // Shares the class and anything under it - testing.addSharedPrefix("com.example.mysubpackage."); // Shares anyhting under a package + testing.addSharedPrefix("com.example.mysubpackage."); // Shares anything under a package ``` While it is possible, it is not generally correct to share the function class itself with the test Class Loader - doing so may result in unexpected (not representative of the real fn platform) initialisation of static fields on the class. With Flows sharing the test class may also result in concurrent access to static data (via `@FnConfiguration` methods). \ No newline at end of file diff --git a/examples/async-thumbnails/pom.xml b/examples/async-thumbnails/pom.xml index 09d9f31c..87aa5c34 100644 --- a/examples/async-thumbnails/pom.xml +++ b/examples/async-thumbnails/pom.xml @@ -8,7 +8,7 @@ UTF-8 UTF-8 - 1.0.0-SNAPSHOT + 1.0.0-SNAPSHOT 2.8.47 @@ -20,7 +20,12 @@ com.fnproject.fn api - ${fnproject.version} + ${fdk.version} + + + com.fnproject.fn + flow-runtime + ${fdk.version} commons-net @@ -35,13 +40,19 @@ com.fnproject.fn testing-core - ${fnproject.version} + ${fdk.version} + test + + + com.fnproject.fn + flow-testing + ${fdk.version} test com.fnproject.fn testing-junit4 - ${fnproject.version} + ${fdk.version} test @@ -63,7 +74,7 @@ org.apache.maven.plugins maven-compiler-plugin - 3.3 + 3.8.0 1.8 1.8 diff --git a/examples/async-thumbnails/src/main/java/com/fnproject/fn/examples/ThumbnailsFunction.java b/examples/async-thumbnails/src/main/java/com/fnproject/fn/examples/ThumbnailsFunction.java index 7ad601de..eb2cb4da 100644 --- a/examples/async-thumbnails/src/main/java/com/fnproject/fn/examples/ThumbnailsFunction.java +++ b/examples/async-thumbnails/src/main/java/com/fnproject/fn/examples/ThumbnailsFunction.java @@ -1,8 +1,10 @@ package com.fnproject.fn.examples; +import com.fnproject.fn.api.FnFeature; import com.fnproject.fn.api.Headers; import com.fnproject.fn.api.RuntimeContext; import com.fnproject.fn.api.flow.Flow; +import com.fnproject.fn.runtime.flow.FlowFeature; import com.fnproject.fn.api.flow.Flows; import com.fnproject.fn.api.flow.HttpMethod; import io.minio.MinioClient; @@ -10,6 +12,7 @@ import java.io.ByteArrayInputStream; import java.io.Serializable; +@FnFeature(FlowFeature.class) public class ThumbnailsFunction implements Serializable { private final String storageUrl; diff --git a/examples/async-thumbnails/src/test/java/com/fnproject/fn/examples/ThumbnailsFunctionTest.java b/examples/async-thumbnails/src/test/java/com/fnproject/fn/examples/ThumbnailsFunctionTest.java index b28e09e3..9c9fba43 100644 --- a/examples/async-thumbnails/src/test/java/com/fnproject/fn/examples/ThumbnailsFunctionTest.java +++ b/examples/async-thumbnails/src/test/java/com/fnproject/fn/examples/ThumbnailsFunctionTest.java @@ -1,7 +1,7 @@ package com.fnproject.fn.examples; -import com.fnproject.fn.examples.ThumbnailsFunction; import com.fnproject.fn.testing.FnTestingRule; +import com.fnproject.fn.testing.flow.FlowTesting; import com.github.tomakehurst.wiremock.client.WireMock; import com.github.tomakehurst.wiremock.junit.WireMockRule; import org.junit.Rule; @@ -12,37 +12,39 @@ public class ThumbnailsFunctionTest { @Rule - public final FnTestingRule testing = FnTestingRule.createDefault(); + public final FnTestingRule fn = FnTestingRule.createDefault(); + private final FlowTesting flow = FlowTesting.create(fn); @Rule public final WireMockRule mockServer = new WireMockRule(0); @Test public void testThumbnail() { - testing - - .setConfig("OBJECT_STORAGE_URL", "http://localhost:" + mockServer.port()) - .setConfig("OBJECT_STORAGE_ACCESS", "alpha") - .setConfig("OBJECT_STORAGE_SECRET", "betabetabetabeta") - - .givenFn("myapp/resize128") - .withAction((data) -> "128".getBytes()) - .givenFn("myapp/resize256") - .withAction((data) -> "256".getBytes()) - .givenFn("myapp/resize512") - .withAction((data) -> "512".getBytes()) - - .givenEvent() - .withBody("testing".getBytes()) - .enqueue(); + fn + .setConfig("OBJECT_STORAGE_URL", "http://localhost:" + mockServer.port()) + .setConfig("OBJECT_STORAGE_ACCESS", "alpha") + .setConfig("OBJECT_STORAGE_SECRET", "betabetabetabeta"); + + flow + .givenFn("myapp/resize128") + .withAction((data) -> "128".getBytes()) + .givenFn("myapp/resize256") + .withAction((data) -> "256".getBytes()) + .givenFn("myapp/resize512") + .withAction((data) -> "512".getBytes()); + + fn + .givenEvent() + .withBody("fn".getBytes()) + .enqueue(); // Mock the http endpoint mockMinio(); - testing.thenRun(ThumbnailsFunction.class, "handleRequest"); + fn.thenRun(ThumbnailsFunction.class, "handleRequest"); // Check the final image uploads were performed - mockServer.verify(putRequestedFor(urlMatching("/alpha/.*\\.png")).withRequestBody(containing("testing"))); + mockServer.verify(putRequestedFor(urlMatching("/alpha/.*\\.png")).withRequestBody(containing("fn"))); mockServer.verify(putRequestedFor(urlMatching("/alpha/.*\\.png")).withRequestBody(containing("128"))); mockServer.verify(putRequestedFor(urlMatching("/alpha/.*\\.png")).withRequestBody(containing("256"))); mockServer.verify(putRequestedFor(urlMatching("/alpha/.*\\.png")).withRequestBody(containing("512"))); @@ -51,26 +53,28 @@ public void testThumbnail() { @Test public void anExternalFunctionFailure() { - testing - .setConfig("OBJECT_STORAGE_URL", "http://localhost:" + mockServer.port()) - .setConfig("OBJECT_STORAGE_ACCESS", "alpha") - .setConfig("OBJECT_STORAGE_SECRET", "betabetabetabeta") - - .givenFn("myapp/resize128") - .withResult("128".getBytes()) - .givenFn("myapp/resize256") - .withResult("256".getBytes()) - .givenFn("myapp/resize512") - .withFunctionError() - - .givenEvent() - .withBody("testing".getBytes()) - .enqueue(); + fn + .setConfig("OBJECT_STORAGE_URL", "http://localhost:" + mockServer.port()) + .setConfig("OBJECT_STORAGE_ACCESS", "alpha") + .setConfig("OBJECT_STORAGE_SECRET", "betabetabetabeta"); + + flow + .givenFn("myapp/resize128") + .withResult("128".getBytes()) + .givenFn("myapp/resize256") + .withResult("256".getBytes()) + .givenFn("myapp/resize512") + .withFunctionError(); + + fn + .givenEvent() + .withBody("fn".getBytes()) + .enqueue(); // Mock the http endpoint mockMinio(); - testing.thenRun(ThumbnailsFunction.class, "handleRequest"); + fn.thenRun(ThumbnailsFunction.class, "handleRequest"); // Confirm that one image upload didn't happen mockServer.verify(0, putRequestedFor(urlMatching("/alpha/.*\\.png")).withRequestBody(equalTo("512"))); @@ -82,15 +86,15 @@ public void anExternalFunctionFailure() { private void mockMinio() { mockServer.stubFor(get(urlMatching("/alpha.*")) - .willReturn(aResponse().withBody( - "\n" + - "\n" + - " alpha\n" + - " \n" + - " 0\n" + - " 100\n" + - " false\n" + - ""))); + .willReturn(aResponse().withBody( + "\n" + + "\n" + + " alpha\n" + + " \n" + + " 0\n" + + " 100\n" + + " false\n" + + ""))); mockServer.stubFor(WireMock.head(urlMatching("/alpha.*")).willReturn(aResponse().withStatus(200))); diff --git a/examples/gradle-build/README.md b/examples/gradle-build/README.md index 269072c7..1b68ab3a 100644 --- a/examples/gradle-build/README.md +++ b/examples/gradle-build/README.md @@ -4,7 +4,7 @@ Fn uses Maven by default for builds. This is an example that uses Fn's `docker` The example consists of a `Dockerfile` that builds the function using gradle and copies the function's dependencies to `build/deps` and a func.yaml that uses that `Dockerfile` to build the function. -Note that FDK versions are hard-coded in this example, you may need to update them manually to more recent version. +Note that fdk.versions are hard-coded in this example, you may need to update them manually to more recent version. Key points: diff --git a/examples/qr-code/pom.xml b/examples/qr-code/pom.xml index e7941657..45e3c6f2 100644 --- a/examples/qr-code/pom.xml +++ b/examples/qr-code/pom.xml @@ -7,7 +7,7 @@ UTF-8 - 1.0.0-SNAPSHOT + 1.0.0-SNAPSHOT com.fnproject.fn.examples @@ -24,7 +24,7 @@ com.fnproject.fn api - ${fnproject.version} + ${fdk.version} @@ -36,7 +36,7 @@ com.fnproject.fn testing - ${fnproject.version} + ${fdk.version} test @@ -45,7 +45,7 @@ org.apache.maven.plugins maven-compiler-plugin - 3.3 + 3.8.0 1.8 1.8 diff --git a/examples/regex-query/pom.xml b/examples/regex-query/pom.xml index 667400ad..61b63c85 100644 --- a/examples/regex-query/pom.xml +++ b/examples/regex-query/pom.xml @@ -8,7 +8,7 @@ UTF-8 UTF-8 - 1.0.0-SNAPSHOT + 1.0.0-SNAPSHOT 2.9.6 @@ -36,13 +36,13 @@ com.fnproject.fn testing-core - ${fnproject.version} + ${fdk.version} test com.fnproject.fn testing-junit4 - ${fnproject.version} + ${fdk.version} test @@ -58,7 +58,7 @@ org.apache.maven.plugins maven-compiler-plugin - 3.3 + 3.8.0 1.8 1.8 diff --git a/examples/regex-query/src/test/java/com/fnproject/fn/examples/RegexQueryTests.java b/examples/regex-query/src/test/java/com/fnproject/fn/examples/RegexQueryTests.java index e5a44626..6ccdce56 100644 --- a/examples/regex-query/src/test/java/com/fnproject/fn/examples/RegexQueryTests.java +++ b/examples/regex-query/src/test/java/com/fnproject/fn/examples/RegexQueryTests.java @@ -15,7 +15,6 @@ public void matchingSingleCharacter() throws JSONException { String text = "a"; String regex = "."; fn.givenEvent() - .withMethod("POST") .withBody(String.format("{\"text\": \"%s\", \"regex\": \"%s\"}", text, regex)) .enqueue(); @@ -34,7 +33,6 @@ public void matchingSingleCharacterMultipleTimes() throws JSONException { String text = "abc"; String regex = "."; fn.givenEvent() - .withMethod("POST") .withBody(String.format("{\"text\": \"%s\", \"regex\": \"%s\"}", text, regex)) .enqueue(); diff --git a/examples/string-reverse/pom.xml b/examples/string-reverse/pom.xml index e299d510..296d9d7f 100644 --- a/examples/string-reverse/pom.xml +++ b/examples/string-reverse/pom.xml @@ -28,7 +28,7 @@ org.apache.maven.plugins maven-compiler-plugin - 3.3 + 3.8.0 1.8 1.8 diff --git a/flow-api/pom.xml b/flow-api/pom.xml new file mode 100644 index 00000000..b965bdb4 --- /dev/null +++ b/flow-api/pom.xml @@ -0,0 +1,61 @@ + + + + fdk + com.fnproject.fn + 1.0.0-SNAPSHOT + + 4.0.0 + + flow-api + + + com.fnproject.fn + api + + + junit + junit + test + + + org.assertj + assertj-core + test + + + + + + org.apache.maven.plugins + maven-javadoc-plugin + + + attach-javadocs + + jar + + + + + + org.netbeans.tools + sigtest-maven-plugin + + + + check + + + + + src/main/api/snapshot.sigfile + strictcheck + com.fnproject.fn.api.flow + + + + + diff --git a/flow-api/src/main/api/snapshot.sigfile b/flow-api/src/main/api/snapshot.sigfile new file mode 100644 index 00000000..9048991c --- /dev/null +++ b/flow-api/src/main/api/snapshot.sigfile @@ -0,0 +1,343 @@ +#Signature file v4.1 +#Version 1.0.0-SNAPSHOT + +CLSS public abstract interface com.fnproject.fn.api.flow.Flow +innr public final static !enum FlowState +intf java.io.Serializable +meth public <%0 extends java.io.Serializable, %1 extends java.lang.Object> com.fnproject.fn.api.flow.FlowFuture<{%%0}> invokeFunction(java.lang.String,{%%1},java.lang.Class<{%%0}>) +meth public <%0 extends java.lang.Object> com.fnproject.fn.api.flow.FlowFuture invokeFunction(java.lang.String,{%%0}) +meth public abstract !varargs com.fnproject.fn.api.flow.FlowFuture anyOf(com.fnproject.fn.api.flow.FlowFuture[]) +meth public abstract !varargs com.fnproject.fn.api.flow.FlowFuture allOf(com.fnproject.fn.api.flow.FlowFuture[]) +meth public abstract <%0 extends java.io.Serializable, %1 extends java.lang.Object> com.fnproject.fn.api.flow.FlowFuture<{%%0}> invokeFunction(java.lang.String,com.fnproject.fn.api.flow.HttpMethod,com.fnproject.fn.api.Headers,{%%1},java.lang.Class<{%%0}>) +meth public abstract <%0 extends java.lang.Object> com.fnproject.fn.api.flow.FlowFuture invokeFunction(java.lang.String,com.fnproject.fn.api.flow.HttpMethod,com.fnproject.fn.api.Headers,{%%0}) +meth public abstract <%0 extends java.lang.Object> com.fnproject.fn.api.flow.FlowFuture<{%%0}> completedValue({%%0}) +meth public abstract <%0 extends java.lang.Object> com.fnproject.fn.api.flow.FlowFuture<{%%0}> createFlowFuture() +meth public abstract <%0 extends java.lang.Object> com.fnproject.fn.api.flow.FlowFuture<{%%0}> failedFuture(java.lang.Throwable) +meth public abstract <%0 extends java.lang.Object> com.fnproject.fn.api.flow.FlowFuture<{%%0}> supply(com.fnproject.fn.api.flow.Flows$SerCallable<{%%0}>) +meth public abstract com.fnproject.fn.api.flow.Flow addTerminationHook(com.fnproject.fn.api.flow.Flows$SerConsumer) +meth public abstract com.fnproject.fn.api.flow.FlowFuture invokeFunction(java.lang.String,com.fnproject.fn.api.flow.HttpMethod,com.fnproject.fn.api.Headers,byte[]) +meth public abstract com.fnproject.fn.api.flow.FlowFuture delay(long,java.util.concurrent.TimeUnit) +meth public abstract com.fnproject.fn.api.flow.FlowFuture supply(com.fnproject.fn.api.flow.Flows$SerRunnable) +meth public com.fnproject.fn.api.flow.FlowFuture invokeFunction(java.lang.String,com.fnproject.fn.api.flow.HttpMethod) +meth public com.fnproject.fn.api.flow.FlowFuture invokeFunction(java.lang.String,com.fnproject.fn.api.flow.HttpMethod,com.fnproject.fn.api.Headers) + +CLSS public final static !enum com.fnproject.fn.api.flow.Flow$FlowState + outer com.fnproject.fn.api.flow.Flow +fld public final static com.fnproject.fn.api.flow.Flow$FlowState CANCELLED +fld public final static com.fnproject.fn.api.flow.Flow$FlowState FAILED +fld public final static com.fnproject.fn.api.flow.Flow$FlowState KILLED +fld public final static com.fnproject.fn.api.flow.Flow$FlowState SUCCEEDED +fld public final static com.fnproject.fn.api.flow.Flow$FlowState UNKNOWN +meth public static com.fnproject.fn.api.flow.Flow$FlowState valueOf(java.lang.String) +meth public static com.fnproject.fn.api.flow.Flow$FlowState[] values() +supr java.lang.Enum + +CLSS public com.fnproject.fn.api.flow.FlowCompletionException +cons public init(java.lang.String) +cons public init(java.lang.String,java.lang.Throwable) +cons public init(java.lang.Throwable) +supr java.lang.RuntimeException + +CLSS public abstract interface com.fnproject.fn.api.flow.FlowFuture<%0 extends java.lang.Object> +intf java.io.Serializable +meth public abstract <%0 extends java.lang.Object, %1 extends java.lang.Object> com.fnproject.fn.api.flow.FlowFuture<{%%1}> thenCombine(com.fnproject.fn.api.flow.FlowFuture,com.fnproject.fn.api.flow.Flows$SerBiFunction) +meth public abstract <%0 extends java.lang.Object> com.fnproject.fn.api.flow.FlowFuture thenAcceptBoth(com.fnproject.fn.api.flow.FlowFuture<{%%0}>,com.fnproject.fn.api.flow.Flows$SerBiConsumer<{com.fnproject.fn.api.flow.FlowFuture%0},{%%0}>) +meth public abstract <%0 extends java.lang.Object> com.fnproject.fn.api.flow.FlowFuture<{%%0}> applyToEither(com.fnproject.fn.api.flow.FlowFuture,com.fnproject.fn.api.flow.Flows$SerFunction<{com.fnproject.fn.api.flow.FlowFuture%0},{%%0}>) +meth public abstract <%0 extends java.lang.Object> com.fnproject.fn.api.flow.FlowFuture<{%%0}> handle(com.fnproject.fn.api.flow.Flows$SerBiFunction) +meth public abstract <%0 extends java.lang.Object> com.fnproject.fn.api.flow.FlowFuture<{%%0}> thenApply(com.fnproject.fn.api.flow.Flows$SerFunction<{com.fnproject.fn.api.flow.FlowFuture%0},{%%0}>) +meth public abstract <%0 extends java.lang.Object> com.fnproject.fn.api.flow.FlowFuture<{%%0}> thenCompose(com.fnproject.fn.api.flow.Flows$SerFunction<{com.fnproject.fn.api.flow.FlowFuture%0},com.fnproject.fn.api.flow.FlowFuture<{%%0}>>) +meth public abstract boolean cancel() +meth public abstract boolean complete({com.fnproject.fn.api.flow.FlowFuture%0}) +meth public abstract boolean completeExceptionally(java.lang.Throwable) +meth public abstract com.fnproject.fn.api.flow.FlowFuture acceptEither(com.fnproject.fn.api.flow.FlowFuture,com.fnproject.fn.api.flow.Flows$SerConsumer<{com.fnproject.fn.api.flow.FlowFuture%0}>) +meth public abstract com.fnproject.fn.api.flow.FlowFuture thenAccept(com.fnproject.fn.api.flow.Flows$SerConsumer<{com.fnproject.fn.api.flow.FlowFuture%0}>) +meth public abstract com.fnproject.fn.api.flow.FlowFuture thenRun(com.fnproject.fn.api.flow.Flows$SerRunnable) +meth public abstract com.fnproject.fn.api.flow.FlowFuture<{com.fnproject.fn.api.flow.FlowFuture%0}> exceptionally(com.fnproject.fn.api.flow.Flows$SerFunction) +meth public abstract com.fnproject.fn.api.flow.FlowFuture<{com.fnproject.fn.api.flow.FlowFuture%0}> exceptionallyCompose(com.fnproject.fn.api.flow.Flows$SerFunction>) +meth public abstract com.fnproject.fn.api.flow.FlowFuture<{com.fnproject.fn.api.flow.FlowFuture%0}> whenComplete(com.fnproject.fn.api.flow.Flows$SerBiConsumer<{com.fnproject.fn.api.flow.FlowFuture%0},java.lang.Throwable>) +meth public abstract {com.fnproject.fn.api.flow.FlowFuture%0} get() +meth public abstract {com.fnproject.fn.api.flow.FlowFuture%0} get(long,java.util.concurrent.TimeUnit) throws java.util.concurrent.TimeoutException +meth public abstract {com.fnproject.fn.api.flow.FlowFuture%0} getNow({com.fnproject.fn.api.flow.FlowFuture%0}) + +CLSS public final com.fnproject.fn.api.flow.Flows +innr public abstract interface static FlowSource +innr public abstract interface static SerBiConsumer +innr public abstract interface static SerBiFunction +innr public abstract interface static SerCallable +innr public abstract interface static SerConsumer +innr public abstract interface static SerFunction +innr public abstract interface static SerRunnable +innr public abstract interface static SerSupplier +meth public static com.fnproject.fn.api.flow.Flow currentFlow() +meth public static com.fnproject.fn.api.flow.Flows$FlowSource getCurrentFlowSource() +meth public static void setCurrentFlowSource(com.fnproject.fn.api.flow.Flows$FlowSource) +supr java.lang.Object +hfds flowSource + +CLSS public abstract interface static com.fnproject.fn.api.flow.Flows$FlowSource + outer com.fnproject.fn.api.flow.Flows +meth public abstract com.fnproject.fn.api.flow.Flow currentFlow() + +CLSS public abstract interface static com.fnproject.fn.api.flow.Flows$SerBiConsumer<%0 extends java.lang.Object, %1 extends java.lang.Object> + outer com.fnproject.fn.api.flow.Flows + anno 0 java.lang.FunctionalInterface() +intf java.io.Serializable +intf java.util.function.BiConsumer<{com.fnproject.fn.api.flow.Flows$SerBiConsumer%0},{com.fnproject.fn.api.flow.Flows$SerBiConsumer%1}> + +CLSS public abstract interface static com.fnproject.fn.api.flow.Flows$SerBiFunction<%0 extends java.lang.Object, %1 extends java.lang.Object, %2 extends java.lang.Object> + outer com.fnproject.fn.api.flow.Flows + anno 0 java.lang.FunctionalInterface() +intf java.io.Serializable +intf java.util.function.BiFunction<{com.fnproject.fn.api.flow.Flows$SerBiFunction%0},{com.fnproject.fn.api.flow.Flows$SerBiFunction%1},{com.fnproject.fn.api.flow.Flows$SerBiFunction%2}> + +CLSS public abstract interface static com.fnproject.fn.api.flow.Flows$SerCallable<%0 extends java.lang.Object> + outer com.fnproject.fn.api.flow.Flows + anno 0 java.lang.FunctionalInterface() +intf java.io.Serializable +intf java.util.concurrent.Callable<{com.fnproject.fn.api.flow.Flows$SerCallable%0}> + +CLSS public abstract interface static com.fnproject.fn.api.flow.Flows$SerConsumer<%0 extends java.lang.Object> + outer com.fnproject.fn.api.flow.Flows + anno 0 java.lang.FunctionalInterface() +intf java.io.Serializable +intf java.util.function.Consumer<{com.fnproject.fn.api.flow.Flows$SerConsumer%0}> + +CLSS public abstract interface static com.fnproject.fn.api.flow.Flows$SerFunction<%0 extends java.lang.Object, %1 extends java.lang.Object> + outer com.fnproject.fn.api.flow.Flows + anno 0 java.lang.FunctionalInterface() +intf java.io.Serializable +intf java.util.function.Function<{com.fnproject.fn.api.flow.Flows$SerFunction%0},{com.fnproject.fn.api.flow.Flows$SerFunction%1}> + +CLSS public abstract interface static com.fnproject.fn.api.flow.Flows$SerRunnable + outer com.fnproject.fn.api.flow.Flows + anno 0 java.lang.FunctionalInterface() +intf java.io.Serializable +intf java.lang.Runnable + +CLSS public abstract interface static com.fnproject.fn.api.flow.Flows$SerSupplier<%0 extends java.lang.Object> + outer com.fnproject.fn.api.flow.Flows + anno 0 java.lang.FunctionalInterface() +intf java.io.Serializable +intf java.util.function.Supplier<{com.fnproject.fn.api.flow.Flows$SerSupplier%0}> + +CLSS public com.fnproject.fn.api.flow.FunctionInvocationException +cons public init(com.fnproject.fn.api.flow.HttpResponse) +meth public com.fnproject.fn.api.flow.HttpResponse getFunctionResponse() +supr java.lang.RuntimeException +hfds functionResponse + +CLSS public com.fnproject.fn.api.flow.FunctionInvokeFailedException +cons public init(java.lang.String) +supr com.fnproject.fn.api.flow.PlatformException + +CLSS public com.fnproject.fn.api.flow.FunctionTimeoutException +cons public init(java.lang.String) +supr com.fnproject.fn.api.flow.PlatformException + +CLSS public final !enum com.fnproject.fn.api.flow.HttpMethod +fld public final static com.fnproject.fn.api.flow.HttpMethod DELETE +fld public final static com.fnproject.fn.api.flow.HttpMethod GET +fld public final static com.fnproject.fn.api.flow.HttpMethod HEAD +fld public final static com.fnproject.fn.api.flow.HttpMethod OPTIONS +fld public final static com.fnproject.fn.api.flow.HttpMethod PATCH +fld public final static com.fnproject.fn.api.flow.HttpMethod POST +fld public final static com.fnproject.fn.api.flow.HttpMethod PUT +meth public java.lang.String toString() +meth public static com.fnproject.fn.api.flow.HttpMethod valueOf(java.lang.String) +meth public static com.fnproject.fn.api.flow.HttpMethod[] values() +supr java.lang.Enum +hfds verb + +CLSS public abstract interface com.fnproject.fn.api.flow.HttpRequest +meth public abstract byte[] getBodyAsBytes() +meth public abstract com.fnproject.fn.api.Headers getHeaders() +meth public abstract com.fnproject.fn.api.flow.HttpMethod getMethod() + +CLSS public abstract interface com.fnproject.fn.api.flow.HttpResponse +meth public abstract byte[] getBodyAsBytes() +meth public abstract com.fnproject.fn.api.Headers getHeaders() +meth public abstract int getStatusCode() + +CLSS public com.fnproject.fn.api.flow.InvalidStageResponseException +cons public init(java.lang.String) +supr com.fnproject.fn.api.flow.PlatformException + +CLSS public com.fnproject.fn.api.flow.LambdaSerializationException +cons public init(java.lang.String) +cons public init(java.lang.String,java.lang.Exception) +supr com.fnproject.fn.api.flow.FlowCompletionException + +CLSS public com.fnproject.fn.api.flow.PlatformException +cons public init(java.lang.String) +cons public init(java.lang.String,java.lang.Throwable) +cons public init(java.lang.Throwable) +meth public java.lang.Throwable fillInStackTrace() +supr com.fnproject.fn.api.flow.FlowCompletionException + +CLSS public com.fnproject.fn.api.flow.ResultSerializationException +cons public init(java.lang.String,java.lang.Throwable) +supr com.fnproject.fn.api.flow.FlowCompletionException + +CLSS public com.fnproject.fn.api.flow.StageInvokeFailedException +cons public init(java.lang.String) +supr com.fnproject.fn.api.flow.PlatformException + +CLSS public com.fnproject.fn.api.flow.StageLostException +cons public init(java.lang.String) +supr com.fnproject.fn.api.flow.PlatformException + +CLSS public com.fnproject.fn.api.flow.StageTimeoutException +cons public init(java.lang.String) +supr com.fnproject.fn.api.flow.PlatformException + +CLSS public final com.fnproject.fn.api.flow.WrappedFunctionException +cons public init(java.lang.Throwable) +intf java.io.Serializable +meth public java.lang.Class getOriginalExceptionType() +supr java.lang.RuntimeException +hfds originalExceptionType + +CLSS public abstract interface java.io.Serializable + +CLSS public abstract interface java.lang.Comparable<%0 extends java.lang.Object> +meth public abstract int compareTo({java.lang.Comparable%0}) + +CLSS public abstract java.lang.Enum<%0 extends java.lang.Enum<{java.lang.Enum%0}>> +cons protected init(java.lang.String,int) +intf java.io.Serializable +intf java.lang.Comparable<{java.lang.Enum%0}> +meth protected final java.lang.Object clone() throws java.lang.CloneNotSupportedException +meth protected final void finalize() +meth public final boolean equals(java.lang.Object) +meth public final int compareTo({java.lang.Enum%0}) +meth public final int hashCode() +meth public final int ordinal() +meth public final java.lang.Class<{java.lang.Enum%0}> getDeclaringClass() +meth public final java.lang.String name() +meth public java.lang.String toString() +meth public static <%0 extends java.lang.Enum<{%%0}>> {%%0} valueOf(java.lang.Class<{%%0}>,java.lang.String) +supr java.lang.Object +hfds name,ordinal + +CLSS public java.lang.Exception +cons protected init(java.lang.String,java.lang.Throwable,boolean,boolean) +cons public init() +cons public init(java.lang.String) +cons public init(java.lang.String,java.lang.Throwable) +cons public init(java.lang.Throwable) +supr java.lang.Throwable +hfds serialVersionUID + +CLSS public abstract interface !annotation java.lang.FunctionalInterface + anno 0 java.lang.annotation.Documented() + anno 0 java.lang.annotation.Retention(java.lang.annotation.RetentionPolicy value=RUNTIME) + anno 0 java.lang.annotation.Target(java.lang.annotation.ElementType[] value=[TYPE]) +intf java.lang.annotation.Annotation + +CLSS public java.lang.Object +cons public init() +meth protected java.lang.Object clone() throws java.lang.CloneNotSupportedException +meth protected void finalize() throws java.lang.Throwable +meth public boolean equals(java.lang.Object) +meth public final java.lang.Class getClass() +meth public final void notify() +meth public final void notifyAll() +meth public final void wait() throws java.lang.InterruptedException +meth public final void wait(long) throws java.lang.InterruptedException +meth public final void wait(long,int) throws java.lang.InterruptedException +meth public int hashCode() +meth public java.lang.String toString() + +CLSS public abstract interface java.lang.Runnable + anno 0 java.lang.FunctionalInterface() +meth public abstract void run() + +CLSS public java.lang.RuntimeException +cons protected init(java.lang.String,java.lang.Throwable,boolean,boolean) +cons public init() +cons public init(java.lang.String) +cons public init(java.lang.String,java.lang.Throwable) +cons public init(java.lang.Throwable) +supr java.lang.Exception +hfds serialVersionUID + +CLSS public java.lang.Throwable +cons protected init(java.lang.String,java.lang.Throwable,boolean,boolean) +cons public init() +cons public init(java.lang.String) +cons public init(java.lang.String,java.lang.Throwable) +cons public init(java.lang.Throwable) +intf java.io.Serializable +meth public final java.lang.Throwable[] getSuppressed() +meth public final void addSuppressed(java.lang.Throwable) +meth public java.lang.StackTraceElement[] getStackTrace() +meth public java.lang.String getLocalizedMessage() +meth public java.lang.String getMessage() +meth public java.lang.String toString() +meth public java.lang.Throwable fillInStackTrace() +meth public java.lang.Throwable getCause() +meth public java.lang.Throwable initCause(java.lang.Throwable) +meth public void printStackTrace() +meth public void printStackTrace(java.io.PrintStream) +meth public void printStackTrace(java.io.PrintWriter) +meth public void setStackTrace(java.lang.StackTraceElement[]) +supr java.lang.Object +hfds CAUSE_CAPTION,EMPTY_THROWABLE_ARRAY,NULL_CAUSE_MESSAGE,SELF_SUPPRESSION_MESSAGE,SUPPRESSED_CAPTION,SUPPRESSED_SENTINEL,UNASSIGNED_STACK,backtrace,cause,detailMessage,serialVersionUID,stackTrace,suppressedExceptions +hcls PrintStreamOrWriter,SentinelHolder,WrappedPrintStream,WrappedPrintWriter + +CLSS public abstract interface java.lang.annotation.Annotation +meth public abstract boolean equals(java.lang.Object) +meth public abstract int hashCode() +meth public abstract java.lang.Class annotationType() +meth public abstract java.lang.String toString() + +CLSS public abstract interface !annotation java.lang.annotation.Documented + anno 0 java.lang.annotation.Documented() + anno 0 java.lang.annotation.Retention(java.lang.annotation.RetentionPolicy value=RUNTIME) + anno 0 java.lang.annotation.Target(java.lang.annotation.ElementType[] value=[ANNOTATION_TYPE]) +intf java.lang.annotation.Annotation + +CLSS public abstract interface !annotation java.lang.annotation.Retention + anno 0 java.lang.annotation.Documented() + anno 0 java.lang.annotation.Retention(java.lang.annotation.RetentionPolicy value=RUNTIME) + anno 0 java.lang.annotation.Target(java.lang.annotation.ElementType[] value=[ANNOTATION_TYPE]) +intf java.lang.annotation.Annotation +meth public abstract java.lang.annotation.RetentionPolicy value() + +CLSS public abstract interface !annotation java.lang.annotation.Target + anno 0 java.lang.annotation.Documented() + anno 0 java.lang.annotation.Retention(java.lang.annotation.RetentionPolicy value=RUNTIME) + anno 0 java.lang.annotation.Target(java.lang.annotation.ElementType[] value=[ANNOTATION_TYPE]) +intf java.lang.annotation.Annotation +meth public abstract java.lang.annotation.ElementType[] value() + +CLSS public abstract interface java.util.concurrent.Callable<%0 extends java.lang.Object> + anno 0 java.lang.FunctionalInterface() +meth public abstract {java.util.concurrent.Callable%0} call() throws java.lang.Exception + +CLSS public abstract interface java.util.function.BiConsumer<%0 extends java.lang.Object, %1 extends java.lang.Object> + anno 0 java.lang.FunctionalInterface() +meth public abstract void accept({java.util.function.BiConsumer%0},{java.util.function.BiConsumer%1}) +meth public java.util.function.BiConsumer<{java.util.function.BiConsumer%0},{java.util.function.BiConsumer%1}> andThen(java.util.function.BiConsumer) + +CLSS public abstract interface java.util.function.BiFunction<%0 extends java.lang.Object, %1 extends java.lang.Object, %2 extends java.lang.Object> + anno 0 java.lang.FunctionalInterface() +meth public <%0 extends java.lang.Object> java.util.function.BiFunction<{java.util.function.BiFunction%0},{java.util.function.BiFunction%1},{%%0}> andThen(java.util.function.Function) +meth public abstract {java.util.function.BiFunction%2} apply({java.util.function.BiFunction%0},{java.util.function.BiFunction%1}) + +CLSS public abstract interface java.util.function.Consumer<%0 extends java.lang.Object> + anno 0 java.lang.FunctionalInterface() +meth public abstract void accept({java.util.function.Consumer%0}) +meth public java.util.function.Consumer<{java.util.function.Consumer%0}> andThen(java.util.function.Consumer) + +CLSS public abstract interface java.util.function.Function<%0 extends java.lang.Object, %1 extends java.lang.Object> + anno 0 java.lang.FunctionalInterface() +meth public <%0 extends java.lang.Object> java.util.function.Function<{%%0},{java.util.function.Function%1}> compose(java.util.function.Function) +meth public <%0 extends java.lang.Object> java.util.function.Function<{java.util.function.Function%0},{%%0}> andThen(java.util.function.Function) +meth public abstract {java.util.function.Function%1} apply({java.util.function.Function%0}) +meth public static <%0 extends java.lang.Object> java.util.function.Function<{%%0},{%%0}> identity() + +CLSS public abstract interface java.util.function.Supplier<%0 extends java.lang.Object> + anno 0 java.lang.FunctionalInterface() +meth public abstract {java.util.function.Supplier%0} get() + diff --git a/api/src/main/java/com/fnproject/fn/api/flow/Flow.java b/flow-api/src/main/java/com/fnproject/fn/api/flow/Flow.java similarity index 95% rename from api/src/main/java/com/fnproject/fn/api/flow/Flow.java rename to flow-api/src/main/java/com/fnproject/fn/api/flow/Flow.java index 22ab2ed8..b366e361 100644 --- a/api/src/main/java/com/fnproject/fn/api/flow/Flow.java +++ b/flow-api/src/main/java/com/fnproject/fn/api/flow/Flow.java @@ -33,7 +33,7 @@ public interface Flow extends Serializable { *

* Function IDs should be of the form "APPID/path/in/app" (without leading slash) where APPID may either be a named application or ".", indicating the appID of the current (calling) function. * - * @param functionId Function ID of function to invoke - this should have the form APPNAME/FUNCTION_PATH (e.g. "myapp/path/to/function" or "./path/to/function"). + * @param functionId Function ID of function to invoke - this should be the function ID returned by `fn inspect function appName fnName` * @param method HTTP method to invoke function * @param headers Headers to add to the HTTP request representing the function invocation * @param data input data to function as a byte array - @@ -45,7 +45,7 @@ public interface Flow extends Serializable { * Invoke a function by ID with headers and an empty body *

* - * @param functionId Function ID of function to invoke - this should have the form APPNAME/FUNCTION_PATH (e.g. "myapp/path/to/function" or "./path/to/function"). + * @param functionId Function ID of function to invoke - this should be the function ID returned by `fn inspect function appName fnName` * @param method HTTP method to invoke function * @param headers Headers to add to the HTTP request representing the function invocation * @return a future which completes normally if the function succeeded and fails if it fails @@ -60,7 +60,7 @@ default FlowFuture invokeFunction(String functionId, HttpMethod me *

* This currently only maps to JSON via the default JSON mapper in the FDK * - * @param functionId Function ID of function to invoke - this should have the form APPNAME/FUNCTION_PATH (e.g. "myapp/path/to/function" or "./path/to/function"). + * @param functionId Function ID of function to invoke - this should be the function ID returned by `fn inspect function appName fnName` * @param input The input object to send to the function input * @param responseType The expected response type of the target function * @param The Response type @@ -77,7 +77,7 @@ default FlowFuture invokeFunction(String function *

* This currently only maps to JSON via the default JSON mapper in the FDK * - * @param functionId Function ID of function to invoke - this should have the form APPNAME/FUNCTION_PATH (e.g. "myapp/path/to/function" or "./path/to/function"). + * @param functionId Function ID of function to invoke - this should be the function ID returned by `fn inspect function appName fnName` * @param method the HTTP method to use for this call * @param headers additional HTTP headers to pass to this function - * @param input The input object to send to the function input @@ -98,7 +98,7 @@ default FlowFuture invokeFunction(String function *

* This currently only maps to JSON via the default JSON mapper in the FDK * - * @param functionId Function ID of function to invoke - this should have the form APPNAME/FUNCTION_PATH (e.g. "myapp/path/to/function" or "./path/to/function"). + * @param functionId Function ID of function to invoke - this should be the function ID returned by `fn inspect function appName fnName` * @param input The input object to send to the function input * @param The Input type of the function * @return a flow future that completes with the result of the function, or an error if the function invocation failed @@ -116,7 +116,7 @@ default FlowFuture invokeFunction(String functionId, U input) *

* This currently only maps to JSON via the default JSON mapper in the FDK * - * @param functionId Function ID of function to invoke - this should have the form APPNAME/FUNCTION_PATH (e.g. "myapp/path/to/function" or "./path/to/function"). + * @param functionId Function ID of function to invoke - this should be the function ID returned by `fn inspect function appName fnName` * @param method the HTTP method to use for this call * @param headers additional HTTP headers to pass to this function - * @param input The input object to send to the function input @@ -130,7 +130,7 @@ default FlowFuture invokeFunction(String functionId, U input) * Invoke a function by ID with no headers *

* - * @param functionId Function ID of function to invoke - this should have the form APPNAME/FUNCTION_PATH (e.g. "myapp/path/to/function" or "./path/to/function"). + * @param functionId Function ID of function to invoke - this should be the function ID returned by `fn inspect function appName fnName` * @param method HTTP method to invoke function * @return a future which completes normally if the function succeeded and fails if it fails * @see #invokeFunction(String, HttpMethod, Headers, byte[]) diff --git a/api/src/main/java/com/fnproject/fn/api/flow/FlowCompletionException.java b/flow-api/src/main/java/com/fnproject/fn/api/flow/FlowCompletionException.java similarity index 100% rename from api/src/main/java/com/fnproject/fn/api/flow/FlowCompletionException.java rename to flow-api/src/main/java/com/fnproject/fn/api/flow/FlowCompletionException.java diff --git a/api/src/main/java/com/fnproject/fn/api/flow/FlowFuture.java b/flow-api/src/main/java/com/fnproject/fn/api/flow/FlowFuture.java similarity index 100% rename from api/src/main/java/com/fnproject/fn/api/flow/FlowFuture.java rename to flow-api/src/main/java/com/fnproject/fn/api/flow/FlowFuture.java diff --git a/api/src/main/java/com/fnproject/fn/api/flow/Flows.java b/flow-api/src/main/java/com/fnproject/fn/api/flow/Flows.java similarity index 94% rename from api/src/main/java/com/fnproject/fn/api/flow/Flows.java rename to flow-api/src/main/java/com/fnproject/fn/api/flow/Flows.java index c71b58d4..5845671b 100644 --- a/api/src/main/java/com/fnproject/fn/api/flow/Flows.java +++ b/flow-api/src/main/java/com/fnproject/fn/api/flow/Flows.java @@ -1,5 +1,6 @@ package com.fnproject.fn.api.flow; + import java.io.Serializable; import java.util.Objects; import java.util.concurrent.Callable; @@ -19,7 +20,7 @@ private Flows() { * * @return the current supplier of the flow runtime */ - public static FlowSource getCurrentFlowSource() { + public static synchronized FlowSource getCurrentFlowSource() { return flowSource; } @@ -37,7 +38,7 @@ public interface FlowSource { * @return the current flow runtime */ public synchronized static Flow currentFlow() { - Objects.requireNonNull(flowSource, "Flows.flowSource is not set - Flows.currentFlow() should only be called from within a FaaS function invocation"); + Objects.requireNonNull(flowSource, "Flows.flowSource is not set - Flows.currentFlow() is the @FnFeature(FlowFeature.class) annotation set on your function?"); return flowSource.currentFlow(); } diff --git a/api/src/main/java/com/fnproject/fn/api/flow/FunctionInvocationException.java b/flow-api/src/main/java/com/fnproject/fn/api/flow/FunctionInvocationException.java similarity index 100% rename from api/src/main/java/com/fnproject/fn/api/flow/FunctionInvocationException.java rename to flow-api/src/main/java/com/fnproject/fn/api/flow/FunctionInvocationException.java diff --git a/api/src/main/java/com/fnproject/fn/api/flow/FunctionInvokeFailedException.java b/flow-api/src/main/java/com/fnproject/fn/api/flow/FunctionInvokeFailedException.java similarity index 100% rename from api/src/main/java/com/fnproject/fn/api/flow/FunctionInvokeFailedException.java rename to flow-api/src/main/java/com/fnproject/fn/api/flow/FunctionInvokeFailedException.java diff --git a/api/src/main/java/com/fnproject/fn/api/flow/FunctionTimeoutException.java b/flow-api/src/main/java/com/fnproject/fn/api/flow/FunctionTimeoutException.java similarity index 100% rename from api/src/main/java/com/fnproject/fn/api/flow/FunctionTimeoutException.java rename to flow-api/src/main/java/com/fnproject/fn/api/flow/FunctionTimeoutException.java diff --git a/api/src/main/java/com/fnproject/fn/api/flow/HttpMethod.java b/flow-api/src/main/java/com/fnproject/fn/api/flow/HttpMethod.java similarity index 100% rename from api/src/main/java/com/fnproject/fn/api/flow/HttpMethod.java rename to flow-api/src/main/java/com/fnproject/fn/api/flow/HttpMethod.java diff --git a/api/src/main/java/com/fnproject/fn/api/flow/HttpRequest.java b/flow-api/src/main/java/com/fnproject/fn/api/flow/HttpRequest.java similarity index 100% rename from api/src/main/java/com/fnproject/fn/api/flow/HttpRequest.java rename to flow-api/src/main/java/com/fnproject/fn/api/flow/HttpRequest.java diff --git a/api/src/main/java/com/fnproject/fn/api/flow/HttpResponse.java b/flow-api/src/main/java/com/fnproject/fn/api/flow/HttpResponse.java similarity index 100% rename from api/src/main/java/com/fnproject/fn/api/flow/HttpResponse.java rename to flow-api/src/main/java/com/fnproject/fn/api/flow/HttpResponse.java diff --git a/api/src/main/java/com/fnproject/fn/api/flow/InvalidStageResponseException.java b/flow-api/src/main/java/com/fnproject/fn/api/flow/InvalidStageResponseException.java similarity index 100% rename from api/src/main/java/com/fnproject/fn/api/flow/InvalidStageResponseException.java rename to flow-api/src/main/java/com/fnproject/fn/api/flow/InvalidStageResponseException.java diff --git a/api/src/main/java/com/fnproject/fn/api/flow/LambdaSerializationException.java b/flow-api/src/main/java/com/fnproject/fn/api/flow/LambdaSerializationException.java similarity index 100% rename from api/src/main/java/com/fnproject/fn/api/flow/LambdaSerializationException.java rename to flow-api/src/main/java/com/fnproject/fn/api/flow/LambdaSerializationException.java diff --git a/api/src/main/java/com/fnproject/fn/api/flow/PlatformException.java b/flow-api/src/main/java/com/fnproject/fn/api/flow/PlatformException.java similarity index 100% rename from api/src/main/java/com/fnproject/fn/api/flow/PlatformException.java rename to flow-api/src/main/java/com/fnproject/fn/api/flow/PlatformException.java diff --git a/api/src/main/java/com/fnproject/fn/api/flow/ResultSerializationException.java b/flow-api/src/main/java/com/fnproject/fn/api/flow/ResultSerializationException.java similarity index 100% rename from api/src/main/java/com/fnproject/fn/api/flow/ResultSerializationException.java rename to flow-api/src/main/java/com/fnproject/fn/api/flow/ResultSerializationException.java diff --git a/api/src/main/java/com/fnproject/fn/api/flow/StageInvokeFailedException.java b/flow-api/src/main/java/com/fnproject/fn/api/flow/StageInvokeFailedException.java similarity index 100% rename from api/src/main/java/com/fnproject/fn/api/flow/StageInvokeFailedException.java rename to flow-api/src/main/java/com/fnproject/fn/api/flow/StageInvokeFailedException.java diff --git a/api/src/main/java/com/fnproject/fn/api/flow/StageLostException.java b/flow-api/src/main/java/com/fnproject/fn/api/flow/StageLostException.java similarity index 100% rename from api/src/main/java/com/fnproject/fn/api/flow/StageLostException.java rename to flow-api/src/main/java/com/fnproject/fn/api/flow/StageLostException.java diff --git a/api/src/main/java/com/fnproject/fn/api/flow/StageTimeoutException.java b/flow-api/src/main/java/com/fnproject/fn/api/flow/StageTimeoutException.java similarity index 100% rename from api/src/main/java/com/fnproject/fn/api/flow/StageTimeoutException.java rename to flow-api/src/main/java/com/fnproject/fn/api/flow/StageTimeoutException.java diff --git a/api/src/main/java/com/fnproject/fn/api/flow/WrappedFunctionException.java b/flow-api/src/main/java/com/fnproject/fn/api/flow/WrappedFunctionException.java similarity index 100% rename from api/src/main/java/com/fnproject/fn/api/flow/WrappedFunctionException.java rename to flow-api/src/main/java/com/fnproject/fn/api/flow/WrappedFunctionException.java diff --git a/api/src/main/java/com/fnproject/fn/api/flow/package-info.java b/flow-api/src/main/java/com/fnproject/fn/api/flow/package-info.java similarity index 100% rename from api/src/main/java/com/fnproject/fn/api/flow/package-info.java rename to flow-api/src/main/java/com/fnproject/fn/api/flow/package-info.java diff --git a/api/src/test/java/com/fnproject/fn/api/flow/FlowsTest.java b/flow-api/src/test/java/com/fnproject/fn/api/flow/FlowsTest.java similarity index 100% rename from api/src/test/java/com/fnproject/fn/api/flow/FlowsTest.java rename to flow-api/src/test/java/com/fnproject/fn/api/flow/FlowsTest.java diff --git a/flow-runtime/pom.xml b/flow-runtime/pom.xml new file mode 100644 index 00000000..532686fe --- /dev/null +++ b/flow-runtime/pom.xml @@ -0,0 +1,76 @@ + + + + fdk + com.fnproject.fn + 1.0.0-SNAPSHOT + + 4.0.0 + + flow-runtime + + + + com.fnproject.fn + api + + + com.fnproject.fn + flow-api + + + + com.fnproject.fn + runtime + + + com.fnproject.fn + testing-junit4 + test + + + org.mockito + mockito-core + test + + + junit + junit + + + org.assertj + assertj-core + test + + + org.apache.httpcomponents + httpmime + test + + + + + + + + maven-dependency-plugin + + + copy-dependencies + package + + copy-dependencies + + + ${project.build.directory}/dependency + runtime + true + + + + + + + diff --git a/runtime/src/main/java/com/fnproject/fn/runtime/flow/APIModel.java b/flow-runtime/src/main/java/com/fnproject/fn/runtime/flow/APIModel.java similarity index 100% rename from runtime/src/main/java/com/fnproject/fn/runtime/flow/APIModel.java rename to flow-runtime/src/main/java/com/fnproject/fn/runtime/flow/APIModel.java diff --git a/runtime/src/main/java/com/fnproject/fn/runtime/flow/BlobResponse.java b/flow-runtime/src/main/java/com/fnproject/fn/runtime/flow/BlobResponse.java similarity index 100% rename from runtime/src/main/java/com/fnproject/fn/runtime/flow/BlobResponse.java rename to flow-runtime/src/main/java/com/fnproject/fn/runtime/flow/BlobResponse.java diff --git a/runtime/src/main/java/com/fnproject/fn/runtime/flow/BlobStoreClient.java b/flow-runtime/src/main/java/com/fnproject/fn/runtime/flow/BlobStoreClient.java similarity index 100% rename from runtime/src/main/java/com/fnproject/fn/runtime/flow/BlobStoreClient.java rename to flow-runtime/src/main/java/com/fnproject/fn/runtime/flow/BlobStoreClient.java diff --git a/runtime/src/main/java/com/fnproject/fn/runtime/flow/CodeLocation.java b/flow-runtime/src/main/java/com/fnproject/fn/runtime/flow/CodeLocation.java similarity index 100% rename from runtime/src/main/java/com/fnproject/fn/runtime/flow/CodeLocation.java rename to flow-runtime/src/main/java/com/fnproject/fn/runtime/flow/CodeLocation.java diff --git a/runtime/src/main/java/com/fnproject/fn/runtime/flow/CompleterClient.java b/flow-runtime/src/main/java/com/fnproject/fn/runtime/flow/CompleterClient.java similarity index 100% rename from runtime/src/main/java/com/fnproject/fn/runtime/flow/CompleterClient.java rename to flow-runtime/src/main/java/com/fnproject/fn/runtime/flow/CompleterClient.java diff --git a/runtime/src/main/java/com/fnproject/fn/runtime/flow/CompleterClientFactory.java b/flow-runtime/src/main/java/com/fnproject/fn/runtime/flow/CompleterClientFactory.java similarity index 100% rename from runtime/src/main/java/com/fnproject/fn/runtime/flow/CompleterClientFactory.java rename to flow-runtime/src/main/java/com/fnproject/fn/runtime/flow/CompleterClientFactory.java diff --git a/runtime/src/main/java/com/fnproject/fn/runtime/flow/CompletionId.java b/flow-runtime/src/main/java/com/fnproject/fn/runtime/flow/CompletionId.java similarity index 100% rename from runtime/src/main/java/com/fnproject/fn/runtime/flow/CompletionId.java rename to flow-runtime/src/main/java/com/fnproject/fn/runtime/flow/CompletionId.java diff --git a/runtime/src/main/java/com/fnproject/fn/runtime/flow/DefaultHttpResponse.java b/flow-runtime/src/main/java/com/fnproject/fn/runtime/flow/DefaultHttpResponse.java similarity index 100% rename from runtime/src/main/java/com/fnproject/fn/runtime/flow/DefaultHttpResponse.java rename to flow-runtime/src/main/java/com/fnproject/fn/runtime/flow/DefaultHttpResponse.java diff --git a/runtime/src/main/java/com/fnproject/fn/runtime/flow/EntityReader.java b/flow-runtime/src/main/java/com/fnproject/fn/runtime/flow/EntityReader.java similarity index 100% rename from runtime/src/main/java/com/fnproject/fn/runtime/flow/EntityReader.java rename to flow-runtime/src/main/java/com/fnproject/fn/runtime/flow/EntityReader.java diff --git a/runtime/src/main/java/com/fnproject/fn/runtime/flow/FlowContinuationInvoker.java b/flow-runtime/src/main/java/com/fnproject/fn/runtime/flow/FlowContinuationInvoker.java similarity index 97% rename from runtime/src/main/java/com/fnproject/fn/runtime/flow/FlowContinuationInvoker.java rename to flow-runtime/src/main/java/com/fnproject/fn/runtime/flow/FlowContinuationInvoker.java index d0dd3443..49656cb8 100644 --- a/runtime/src/main/java/com/fnproject/fn/runtime/flow/FlowContinuationInvoker.java +++ b/flow-runtime/src/main/java/com/fnproject/fn/runtime/flow/FlowContinuationInvoker.java @@ -31,6 +31,10 @@ public final class FlowContinuationInvoker implements FunctionInvoker { public static final String FLOW_ID_HEADER = "Fnproject-FlowId"; + public FlowContinuationInvoker(){ + + } + private static class URLCompleterClientFactory implements CompleterClientFactory { private final String completerBaseUrl; private transient CompleterClient completerClient; @@ -167,7 +171,7 @@ public synchronized Flow currentFlow() { @Override public synchronized Flow currentFlow() { if (runtime == null) { - String functionId = evt.getAppName() + evt.getRoute(); + String functionId = ctx.getRuntimeContext().getFunctionID(); CompleterClientFactory factory = getOrCreateCompleterClientFactory(completerBaseUrl); final FlowId flowId = factory.getCompleterClient().createFlow(functionId); runtime = new RemoteFlow(flowId); @@ -227,14 +231,9 @@ private ContinuationOutputEvent(boolean success, byte[] body) { this.body = body; } - /** - * The completer expects a 200 on the output event. - * - * @return - */ @Override - public int getStatusCode() { - return OutputEvent.SUCCESS; + public Status getStatus() { + return Status.Success; } diff --git a/flow-runtime/src/main/java/com/fnproject/fn/runtime/flow/FlowFeature.java b/flow-runtime/src/main/java/com/fnproject/fn/runtime/flow/FlowFeature.java new file mode 100644 index 00000000..27a79f0b --- /dev/null +++ b/flow-runtime/src/main/java/com/fnproject/fn/runtime/flow/FlowFeature.java @@ -0,0 +1,38 @@ +package com.fnproject.fn.runtime.flow; + +import com.fnproject.fn.api.FunctionInvoker; +import com.fnproject.fn.api.RuntimeContext; +import com.fnproject.fn.api.RuntimeFeature; + +/** + * + * The flow feature enables the Flow Client SDK and runtime behaviour in a Java function in order to use Flow in a function you must add the following to the function class: + * + * + * + * import com.fnproject.fn.api.FnFeature; + * import com.fnproject.fn.runtime.flow.FlowFeature; + * + * @FnFeature(FlowFeature.class) + * public class MyFunction { + * + * + * public void myFunction(String input){ + * Flows.currentFlow().... + * + * } + * } + * + * + * + * Created on 10/09/2018. + *

+ * (c) 2018 Oracle Corporation + */ +public class FlowFeature implements RuntimeFeature { + @Override + public void initialize(RuntimeContext context){ + FunctionInvoker invoker = new FlowContinuationInvoker(); + context.addInvoker(invoker,FunctionInvoker.Phase.PreCall); + } +} diff --git a/runtime/src/main/java/com/fnproject/fn/runtime/flow/FlowFutureSource.java b/flow-runtime/src/main/java/com/fnproject/fn/runtime/flow/FlowFutureSource.java similarity index 100% rename from runtime/src/main/java/com/fnproject/fn/runtime/flow/FlowFutureSource.java rename to flow-runtime/src/main/java/com/fnproject/fn/runtime/flow/FlowFutureSource.java diff --git a/runtime/src/main/java/com/fnproject/fn/runtime/flow/FlowId.java b/flow-runtime/src/main/java/com/fnproject/fn/runtime/flow/FlowId.java similarity index 100% rename from runtime/src/main/java/com/fnproject/fn/runtime/flow/FlowId.java rename to flow-runtime/src/main/java/com/fnproject/fn/runtime/flow/FlowId.java diff --git a/runtime/src/main/java/com/fnproject/fn/runtime/flow/FlowRuntimeGlobals.java b/flow-runtime/src/main/java/com/fnproject/fn/runtime/flow/FlowRuntimeGlobals.java similarity index 100% rename from runtime/src/main/java/com/fnproject/fn/runtime/flow/FlowRuntimeGlobals.java rename to flow-runtime/src/main/java/com/fnproject/fn/runtime/flow/FlowRuntimeGlobals.java diff --git a/runtime/src/main/java/com/fnproject/fn/runtime/flow/HttpClient.java b/flow-runtime/src/main/java/com/fnproject/fn/runtime/flow/HttpClient.java similarity index 100% rename from runtime/src/main/java/com/fnproject/fn/runtime/flow/HttpClient.java rename to flow-runtime/src/main/java/com/fnproject/fn/runtime/flow/HttpClient.java diff --git a/runtime/src/main/java/com/fnproject/fn/runtime/flow/JsonInvoke.java b/flow-runtime/src/main/java/com/fnproject/fn/runtime/flow/JsonInvoke.java similarity index 97% rename from runtime/src/main/java/com/fnproject/fn/runtime/flow/JsonInvoke.java rename to flow-runtime/src/main/java/com/fnproject/fn/runtime/flow/JsonInvoke.java index cfb21953..d6e20272 100644 --- a/runtime/src/main/java/com/fnproject/fn/runtime/flow/JsonInvoke.java +++ b/flow-runtime/src/main/java/com/fnproject/fn/runtime/flow/JsonInvoke.java @@ -73,7 +73,7 @@ public static FlowFuture invokeFunction(Flow flow, String func String inputString = getObjectMapper().writeValueAsString(input); Headers newHeaders; if (!headers.get("Content-type").isPresent()) { - newHeaders = headers.withHeader("Content-type", "application/json"); + newHeaders = headers.addHeader("Content-type", "application/json"); } else { newHeaders = headers; } diff --git a/runtime/src/main/java/com/fnproject/fn/runtime/flow/RemoteBlobStoreClient.java b/flow-runtime/src/main/java/com/fnproject/fn/runtime/flow/RemoteBlobStoreClient.java similarity index 100% rename from runtime/src/main/java/com/fnproject/fn/runtime/flow/RemoteBlobStoreClient.java rename to flow-runtime/src/main/java/com/fnproject/fn/runtime/flow/RemoteBlobStoreClient.java diff --git a/runtime/src/main/java/com/fnproject/fn/runtime/flow/RemoteFlow.java b/flow-runtime/src/main/java/com/fnproject/fn/runtime/flow/RemoteFlow.java similarity index 100% rename from runtime/src/main/java/com/fnproject/fn/runtime/flow/RemoteFlow.java rename to flow-runtime/src/main/java/com/fnproject/fn/runtime/flow/RemoteFlow.java diff --git a/runtime/src/main/java/com/fnproject/fn/runtime/flow/RemoteFlowApiClient.java b/flow-runtime/src/main/java/com/fnproject/fn/runtime/flow/RemoteFlowApiClient.java similarity index 96% rename from runtime/src/main/java/com/fnproject/fn/runtime/flow/RemoteFlowApiClient.java rename to flow-runtime/src/main/java/com/fnproject/fn/runtime/flow/RemoteFlowApiClient.java index 60c96a09..872b5653 100644 --- a/runtime/src/main/java/com/fnproject/fn/runtime/flow/RemoteFlowApiClient.java +++ b/flow-runtime/src/main/java/com/fnproject/fn/runtime/flow/RemoteFlowApiClient.java @@ -120,12 +120,7 @@ public CompletionId invokeFunction(FlowId flowId, String functionId, byte[] data httpReq.headers = new ArrayList<>(); - headers.getAll().forEach((k, v) -> { - APIModel.HTTPHeader h = new APIModel.HTTPHeader(); - h.key = k; - h.value = v; - httpReq.headers.add(h); - }); + headers.asMap().forEach((k, vs) -> vs.forEach(v -> httpReq.headers.add(APIModel.HTTPHeader.create(k, v)))); } httpReq.method = APIModel.HTTPMethod.fromFlow(method); @@ -153,9 +148,9 @@ public CompletionId completedValue(FlowId flowId, boolean success, Object value, APIModel.CompletionResult completionResult = new APIModel.CompletionResult(); completionResult.successful = success; - if(value instanceof RemoteFlow.RemoteFlowFuture) { + if (value instanceof RemoteFlow.RemoteFlowFuture) { APIModel.StageRefDatum stageRefDatum = new APIModel.StageRefDatum(); - stageRefDatum.stageId = ((RemoteFlow.RemoteFlowFuture)value).id(); + stageRefDatum.stageId = ((RemoteFlow.RemoteFlowFuture) value).id(); completionResult.result = stageRefDatum; } else { APIModel.Datum blobDatum = APIModel.datumFromJava(flowId, value, blobStoreClient); @@ -251,14 +246,14 @@ public Object waitForCompletion(FlowId flowId, CompletionId id, ClassLoader igno long remainingTimeout = Math.max(1, start + msTimeout - lastStart); try (HttpClient.HttpResponse response = - httpClient.execute(prepareGet(apiUrlBase + "/flows/" + flowId.getId() + "/stages/" + id.getId() + "/await?timeout_ms=" + remainingTimeout))) { + httpClient.execute(prepareGet(apiUrlBase + "/flows/" + flowId.getId() + "/stages/" + id.getId() + "/await?timeout_ms=" + remainingTimeout))) { if (response.getStatusCode() == 200) { APIModel.AwaitStageResponse resp = FlowRuntimeGlobals.getObjectMapper().readValue(response.getContentStream(), APIModel.AwaitStageResponse.class); if (resp.result.successful) { return resp.result.toJava(flowId, blobStoreClient, getClass().getClassLoader()); } else { - throw new FlowCompletionException((Throwable)resp.result.toJava(flowId, blobStoreClient, getClass().getClassLoader())); + throw new FlowCompletionException((Throwable) resp.result.toJava(flowId, blobStoreClient, getClass().getClassLoader())); } } else if (response.getStatusCode() == 408) { // do nothing go round again @@ -313,10 +308,10 @@ private static PlatformCommunicationException asError(HttpClient.HttpResponse re try { String body = response.entityAsString(); return new PlatformCommunicationException(String.format("Received unexpected response (%d) from " + - "Flow service: %s", response.getStatusCode(), body == null ? "Empty body" : body)); + "Flow service: %s", response.getStatusCode(), body == null ? "Empty body" : body)); } catch (IOException e) { return new PlatformCommunicationException(String.format("Received unexpected response (%d) from " + - "Flow service. Could not read body.", response.getStatusCode()), e); + "Flow service. Could not read body.", response.getStatusCode()), e); } } @@ -342,7 +337,7 @@ private static byte[] serializeClosure(Object data) { private CompletionId addStageWithClosure(APIModel.CompletionOperation operation, FlowId flowId, Serializable supplier, CodeLocation codeLocation, List deps) { byte[] serialized = serializeClosure(supplier); - BlobResponse blobResponse = blobStoreClient.writeBlob(flowId.getId(), serialized, CONTENT_TYPE_JAVA_OBJECT); + BlobResponse blobResponse = blobStoreClient.writeBlob(flowId.getId(), serialized, CONTENT_TYPE_JAVA_OBJECT); return addStage(operation, APIModel.Blob.fromBlobResponse(blobResponse), deps, flowId, codeLocation); diff --git a/runtime/src/test/java/com/fnproject/fn/runtime/flow/FlowsContinuationInvokerTest.java b/flow-runtime/src/test/java/com/fnproject/fn/runtime/flow/FlowsContinuationInvokerTest.java similarity index 76% rename from runtime/src/test/java/com/fnproject/fn/runtime/flow/FlowsContinuationInvokerTest.java rename to flow-runtime/src/test/java/com/fnproject/fn/runtime/flow/FlowsContinuationInvokerTest.java index 99685e6c..06f83d9b 100644 --- a/runtime/src/test/java/com/fnproject/fn/runtime/flow/FlowsContinuationInvokerTest.java +++ b/flow-runtime/src/test/java/com/fnproject/fn/runtime/flow/FlowsContinuationInvokerTest.java @@ -5,7 +5,6 @@ import com.fnproject.fn.api.*; import com.fnproject.fn.api.exception.FunctionInputHandlingException; import com.fnproject.fn.api.flow.*; -import com.fnproject.fn.runtime.QueryParametersImpl; import com.fnproject.fn.runtime.ReadOnceInputEvent; import com.fnproject.fn.runtime.exception.InternalFunctionInvocationException; import org.junit.After; @@ -16,6 +15,7 @@ import java.io.*; import java.lang.reflect.Method; +import java.time.Instant; import java.util.*; import static com.fnproject.fn.runtime.flow.FlowContinuationInvoker.FLOW_ID_HEADER; @@ -59,9 +59,9 @@ public void continuationInvokedWhenGraphHeaderPresent() throws IOException, Clas // Given InputEvent event = newRequest() - .withClosure((Flows.SerFunction) (x) -> x * 2) - .withJavaObjectArgs(10) - .asEvent(); + .withClosure((Flows.SerFunction) (x) -> x * 2) + .withJavaObjectArgs(10) + .asEvent(); // When Optional result = invoker.tryInvoke(new EmptyInvocationContext(), event); @@ -81,8 +81,8 @@ public void continuationNotInvokedWhenHeaderMissing() throws IOException, ClassN // Given InputEvent event = new InputEventBuilder() - .withBody("") - .build(); + .withBody("") + .build(); // When FlowContinuationInvoker invoker = new FlowContinuationInvoker(); @@ -99,8 +99,8 @@ public void failsIfArgMissing() throws IOException, ClassNotFoundException { // Given InputEvent event = newRequest() - .withClosure((Flows.SerFunction) (x) -> x * 2) - .asEvent(); + .withClosure((Flows.SerFunction) (x) -> x * 2) + .asEvent(); invoker.tryInvoke(new EmptyInvocationContext(), event); @@ -118,8 +118,8 @@ public void failsIfUnknownClosureType() { thrown.expect(FunctionInputHandlingException.class); // Given InputEvent event = newRequest() - .withClosure(new TestIf()) - .asEvent(); + .withClosure(new TestIf()) + .asEvent(); invoker.tryInvoke(new EmptyInvocationContext(), event); } @@ -140,25 +140,25 @@ private Tc(Serializable closure, Object result, Object... args) { } Tc[] cases = new Tc[]{ - new Tc((Flows.SerConsumer) (v) -> { - }, null, "hello"), - new Tc((Flows.SerBiFunction) (String::concat), "hello bob", "hello ", "bob"), - new Tc((Flows.SerBiConsumer) (a, b) -> { - }, null, "hello ", "bob"), - new Tc((Flows.SerFunction) (String::toUpperCase), "HELLO BOB", "hello bob"), - new Tc((Flows.SerRunnable) () -> { - }, null), - new Tc((Flows.SerCallable) () -> "hello", "hello"), - new Tc((Flows.SerSupplier) () -> "hello", "hello"), + new Tc((Flows.SerConsumer) (v) -> { + }, null, "hello"), + new Tc((Flows.SerBiFunction) (String::concat), "hello bob", "hello ", "bob"), + new Tc((Flows.SerBiConsumer) (a, b) -> { + }, null, "hello ", "bob"), + new Tc((Flows.SerFunction) (String::toUpperCase), "HELLO BOB", "hello bob"), + new Tc((Flows.SerRunnable) () -> { + }, null), + new Tc((Flows.SerCallable) () -> "hello", "hello"), + new Tc((Flows.SerSupplier) () -> "hello", "hello"), }; for (Tc tc : cases) { InputEvent event = newRequest() - .withClosure(tc.closure) - .withJavaObjectArgs(tc.args) - .asEvent(); + .withClosure(tc.closure) + .withJavaObjectArgs(tc.args) + .asEvent(); Optional result = invoker.tryInvoke(new EmptyInvocationContext(), event); assertThat(result).isPresent(); @@ -177,13 +177,13 @@ private Tc(Serializable closure, Object result, Object... args) { public void emptyValueCorrectlySerialized() throws IOException, ClassNotFoundException { // Given InputEvent event = newRequest() - .withClosure((Flows.SerConsumer) (x) -> { - if (x != null) { - throw new RuntimeException("Not Null"); - } - }) - .withEmptyDatumArg() - .asEvent(); + .withClosure((Flows.SerConsumer) (x) -> { + if (x != null) { + throw new RuntimeException("Not Null"); + } + }) + .withEmptyDatumArg() + .asEvent(); // When Optional result = invoker.tryInvoke(new EmptyInvocationContext(), event); @@ -199,8 +199,8 @@ public void emptyValueCorrectlySerialized() throws IOException, ClassNotFoundExc public void emptyValueCorrectlyDeSerialized() throws IOException, ClassNotFoundException { // Given InputEvent event = newRequest() - .withClosure((Flows.SerSupplier) () -> null) - .asEvent(); + .withClosure((Flows.SerSupplier) () -> null) + .asEvent(); // When Optional result = invoker.tryInvoke(new EmptyInvocationContext(), event); @@ -218,12 +218,12 @@ public void stageRefCorrectlyDeserialized() throws IOException, ClassNotFoundExc // Given InputEvent event = newRequest() - .withClosure((Flows.SerConsumer>) (x) -> { - assertThat(x).isNotNull(); - assertThat(((RemoteFlow.RemoteFlowFuture) x).id()).isEqualTo("newStage"); - }) - .withStageRefArg("newStage") - .asEvent(); + .withClosure((Flows.SerConsumer>) (x) -> { + assertThat(x).isNotNull(); + assertThat(((RemoteFlow.RemoteFlowFuture) x).id()).isEqualTo("newStage"); + }) + .withStageRefArg("newStage") + .asEvent(); // When Optional result = invoker.tryInvoke(new EmptyInvocationContext(), event); @@ -242,8 +242,8 @@ public void stageRefCorrectlySerialized() throws IOException, ClassNotFoundExcep // Given InputEvent event = newRequest() - .withClosure((Flows.SerSupplier>) () -> ff) - .asEvent(); + .withClosure((Flows.SerSupplier>) () -> ff) + .asEvent(); // When Optional result = invoker.tryInvoke(new EmptyInvocationContext(), event); @@ -263,11 +263,11 @@ public void stageRefCorrectlySerialized() throws IOException, ClassNotFoundExcep public void setsCurrentStageId() throws IOException, ClassNotFoundException { InputEvent event = newRequest() - .withClosure((Flows.SerRunnable) () -> { - assertThat(FlowRuntimeGlobals.getCurrentCompletionId()).contains(new CompletionId("myStage")); - }) - .withStageId("myStage") - .asEvent(); + .withClosure((Flows.SerRunnable) () -> { + assertThat(FlowRuntimeGlobals.getCurrentCompletionId()).contains(new CompletionId("myStage")); + }) + .withStageId("myStage") + .asEvent(); // When Optional result = invoker.tryInvoke(new EmptyInvocationContext(), event); @@ -284,13 +284,13 @@ public void httpRespToFn() throws Exception { // Given InputEvent event = newRequest() - .withClosure((Flows.SerConsumer) (x) -> { - assertThat(x.getBodyAsBytes()).isEqualTo("Hello".getBytes()); - assertThat(x.getStatusCode()).isEqualTo(201); - assertThat(x.getHeaders().get("Foo")).contains("Bar"); - }) - .withHttpRespArg(201, "Hello", APIModel.HTTPHeader.create("Foo", "Bar")) - .asEvent(); + .withClosure((Flows.SerConsumer) (x) -> { + assertThat(x.getBodyAsBytes()).isEqualTo("Hello".getBytes()); + assertThat(x.getStatusCode()).isEqualTo(201); + assertThat(x.getHeaders().get("Foo")).contains("Bar"); + }) + .withHttpRespArg(201, "Hello", APIModel.HTTPHeader.create("Foo", "Bar")) + .asEvent(); // When @@ -306,14 +306,14 @@ public void httpRespToFnWithError() throws Exception { // Given InputEvent event = newRequest() - .withClosure((Flows.SerConsumer) (e) -> { - HttpResponse x = e.getFunctionResponse(); - assertThat(x.getBodyAsBytes()).isEqualTo("Hello".getBytes()); - assertThat(x.getStatusCode()).isEqualTo(201); - assertThat(x.getHeaders().get("Foo")).contains("Bar"); - }) - .withHttpRespArg(false, 201, "Hello", APIModel.HTTPHeader.create("Foo", "Bar")) - .asEvent(); + .withClosure((Flows.SerConsumer) (e) -> { + HttpResponse x = e.getFunctionResponse(); + assertThat(x.getBodyAsBytes()).isEqualTo("Hello".getBytes()); + assertThat(x.getStatusCode()).isEqualTo(201); + assertThat(x.getHeaders().get("Foo")).contains("Bar"); + }) + .withHttpRespArg(false, 201, "Hello", APIModel.HTTPHeader.create("Foo", "Bar")) + .asEvent(); // When @@ -338,24 +338,24 @@ class TestCase { } } for (TestCase tc : new TestCase[]{ - new TestCase(APIModel.ErrorType.InvalidStageResponse, InvalidStageResponseException.class), - new TestCase(APIModel.ErrorType.FunctionInvokeFailed, FunctionInvokeFailedException.class), - new TestCase(APIModel.ErrorType.FunctionTimeout, FunctionTimeoutException.class), - new TestCase(APIModel.ErrorType.StageFailed, StageInvokeFailedException.class), - new TestCase(APIModel.ErrorType.StageTimeout, StageTimeoutException.class), - new TestCase(APIModel.ErrorType.StageLost, StageLostException.class) + new TestCase(APIModel.ErrorType.InvalidStageResponse, InvalidStageResponseException.class), + new TestCase(APIModel.ErrorType.FunctionInvokeFailed, FunctionInvokeFailedException.class), + new TestCase(APIModel.ErrorType.FunctionTimeout, FunctionTimeoutException.class), + new TestCase(APIModel.ErrorType.StageFailed, StageInvokeFailedException.class), + new TestCase(APIModel.ErrorType.StageTimeout, StageTimeoutException.class), + new TestCase(APIModel.ErrorType.StageLost, StageLostException.class) }) { Class type = tc.exceptionType; // Given InputEvent event = newRequest() - .withClosure((Flows.SerConsumer) (e) -> { + .withClosure((Flows.SerConsumer) (e) -> { - assertThat(e).hasMessage("My Error"); - assertThat(e).isInstanceOf(type); - }) - .withErrorBody(tc.errorType, "My Error") - .asEvent(); + assertThat(e).hasMessage("My Error"); + assertThat(e).isInstanceOf(type); + }) + .withErrorBody(tc.errorType, "My Error") + .asEvent(); // When @@ -373,8 +373,8 @@ class TestCase { public void functionInvocationExceptionThrownIfStageResultIsNotSerializable() { thrown.expect(ResultSerializationException.class); InputEvent event = newRequest() - .withClosure((Flows.SerSupplier) Object::new) - .asEvent(); + .withClosure((Flows.SerSupplier) Object::new) + .asEvent(); invoker.tryInvoke(new EmptyInvocationContext(), event); @@ -392,10 +392,10 @@ public void functionInvocationExceptionThrownIfStageThrowsException() { InputEvent event = newRequest() - .withClosure((Flows.SerRunnable) () -> { - throw new MyRuntimeException(); - }) - .asEvent(); + .withClosure((Flows.SerRunnable) () -> { + throw new MyRuntimeException(); + }) + .asEvent(); invoker.tryInvoke(new EmptyInvocationContext(), event); @@ -430,7 +430,7 @@ public FlowRequestBuilder withClosure(Serializable closure) { public FlowRequestBuilder withJavaObjectArgs(Object... args) { Arrays.stream(args).forEach((arg) -> - req.args.add(blobStore.withResult(flowId, arg, true))); + req.args.add(blobStore.withResult(flowId, arg, true))); return this; } @@ -446,10 +446,10 @@ public InputEvent asEvent() { System.err.println("Req:" + new String(body)); return new InputEventBuilder() - .withHeader(FLOW_ID_HEADER, flowId) - .withHeader("Content-type", "application/json") - .withBody(new ByteArrayInputStream(body)) - .build(); + .withHeader(FLOW_ID_HEADER, flowId) + .withHeader("Content-type", "application/json") + .withBody(new ByteArrayInputStream(body)) + .build(); } public FlowRequestBuilder withEmptyDatumArg() { @@ -547,43 +547,39 @@ public InputEventBuilder withBody(String body) { return this; } - private Map currentHeaders() { - return new HashMap<>(headers.getAll()); + private Map> currentHeaders() { + return new HashMap<>(headers.asMap()); } - public InputEventBuilder withHeaders(Map headers) { - Map updated = currentHeaders(); - updated.putAll(headers); - this.headers = Headers.fromMap(updated); - return this; - } public InputEventBuilder withHeader(String name, String value) { - Map updated = currentHeaders(); - updated.put(name, value); - this.headers = Headers.fromMap(updated); + this.headers = headers.setHeader(name,value); return this; } private String getHeader(String key) { - for (Map.Entry entry : currentHeaders().entrySet()) { - if (key.equalsIgnoreCase(entry.getKey())) { - return entry.getValue(); - } - } - return null; + return headers.get(key).orElse(null); } public InputEvent build() { return new ReadOnceInputEvent( - "", "", "", "", - body, - headers, new QueryParametersImpl()); + body, + headers, "callID",Instant.now()); } } class EmptyRuntimeContext implements RuntimeContext { + @Override + public String getAppID() { + return "appID"; + } + + @Override + public String getFunctionID() { + return "fnID"; + } + @Override public Optional getInvokeInstance() { return Optional.empty(); @@ -634,6 +630,12 @@ public void setInvoker(FunctionInvoker invoker) { throw new RuntimeException("You can't modify the empty runtime context in the tests, sorry."); } + @Override + public void addInvoker(FunctionInvoker invoker, FunctionInvoker.Phase phase) { + throw new RuntimeException("You can't modify the empty runtime context in the tests, sorry."); + + } + @Override public MethodWrapper getMethod() { return null; diff --git a/runtime/src/test/java/com/fnproject/fn/runtime/flow/RemoteFlowApiClientTest.java b/flow-runtime/src/test/java/com/fnproject/fn/runtime/flow/RemoteFlowApiClientTest.java similarity index 99% rename from runtime/src/test/java/com/fnproject/fn/runtime/flow/RemoteFlowApiClientTest.java rename to flow-runtime/src/test/java/com/fnproject/fn/runtime/flow/RemoteFlowApiClientTest.java index 3063a77e..1f76e0d8 100644 --- a/runtime/src/test/java/com/fnproject/fn/runtime/flow/RemoteFlowApiClientTest.java +++ b/flow-runtime/src/test/java/com/fnproject/fn/runtime/flow/RemoteFlowApiClientTest.java @@ -6,6 +6,7 @@ import com.fnproject.fn.api.flow.Flows; import com.fnproject.fn.api.flow.HttpMethod; import com.fnproject.fn.runtime.exception.PlatformCommunicationException; +import com.fnproject.fn.runtime.flow.*; import org.hamcrest.BaseMatcher; import org.hamcrest.Description; import org.junit.Before; diff --git a/runtime/src/test/java/com/fnproject/fn/runtime/flow/TestBlobStore.java b/flow-runtime/src/test/java/com/fnproject/fn/runtime/flow/TestBlobStore.java similarity index 100% rename from runtime/src/test/java/com/fnproject/fn/runtime/flow/TestBlobStore.java rename to flow-runtime/src/test/java/com/fnproject/fn/runtime/flow/TestBlobStore.java diff --git a/runtime/src/test/java/com/fnproject/fn/runtime/testfns/FnFlowsFunction.java b/flow-runtime/src/test/java/com/fnproject/fn/testing/flowtestfns/FnFlowsFunction.java similarity index 83% rename from runtime/src/test/java/com/fnproject/fn/runtime/testfns/FnFlowsFunction.java rename to flow-runtime/src/test/java/com/fnproject/fn/testing/flowtestfns/FnFlowsFunction.java index 59cc2de1..23ad312d 100644 --- a/runtime/src/test/java/com/fnproject/fn/runtime/testfns/FnFlowsFunction.java +++ b/flow-runtime/src/test/java/com/fnproject/fn/testing/flowtestfns/FnFlowsFunction.java @@ -1,10 +1,13 @@ -package com.fnproject.fn.runtime.testfns; +package com.fnproject.fn.testing.flowtestfns; +import com.fnproject.fn.api.FnFeature; import com.fnproject.fn.api.flow.Flow; import com.fnproject.fn.api.flow.Flows; +import com.fnproject.fn.runtime.flow.FlowFeature; import java.io.Serializable; +@FnFeature(FlowFeature.class) public class FnFlowsFunction implements Serializable { public static void usingFlows() { diff --git a/flow-testing/pom.xml b/flow-testing/pom.xml new file mode 100644 index 00000000..03d2d9a3 --- /dev/null +++ b/flow-testing/pom.xml @@ -0,0 +1,78 @@ + + + + fdk + com.fnproject.fn + 1.0.0-SNAPSHOT + + 4.0.0 + + flow-testing + + + com.fnproject.fn + testing-junit4 + + + com.fnproject.fn + flow-api + + + com.fnproject.fn + flow-runtime + + + com.fnproject.fn + runtime + + + junit + junit + compile + + + org.assertj + assertj-core + test + + + org.mockito + mockito-core + test + + + + + + org.apache.maven.plugins + maven-javadoc-plugin + + + attach-javadocs + + jar + + + + + + + + + + + + + + + + + + + + + + + diff --git a/flow-testing/src/main/java/com/fnproject/fn/testing/flow/FlowTesting.java b/flow-testing/src/main/java/com/fnproject/fn/testing/flow/FlowTesting.java new file mode 100644 index 00000000..c8dfa8d2 --- /dev/null +++ b/flow-testing/src/main/java/com/fnproject/fn/testing/flow/FlowTesting.java @@ -0,0 +1,237 @@ +package com.fnproject.fn.testing.flow; + +import com.fasterxml.jackson.core.JsonProcessingException; +import com.fasterxml.jackson.databind.ObjectMapper; +import com.fnproject.fn.api.Headers; +import com.fnproject.fn.api.InputEvent; +import com.fnproject.fn.api.flow.*; +import com.fnproject.fn.runtime.flow.*; +import com.fnproject.fn.testing.*; + +import java.io.PrintStream; +import java.lang.reflect.InvocationTargetException; +import java.util.*; +import java.util.concurrent.CompletableFuture; + +/** + * FlowTesting allows you to test Fn Flow functions by emulating the Fn Flow completer in a testing environment. + * + *

+ * * Created on 07/09/2018. + *

+ * (c) 2018 Oracle Corporation + */ +public class FlowTesting implements FnTestingRuleFeature { + private Map functionStubs = new HashMap<>(); + private static InMemCompleter completer = null; + private final FnTestingRule rule; + private static final ObjectMapper objectMapper = new ObjectMapper(); + + private FlowTesting(FnTestingRule rule) { + + this.rule = rule; + rule.addSharedClass(InMemCompleter.CompleterInvokeClient.class); + rule.addSharedClass(BlobStoreClient.class); + rule.addSharedClass(BlobResponse.class); + rule.addSharedClass(CompleterClientFactory.class); + rule.addSharedClass(CompleterClient.class); + rule.addSharedClass(CompletionId.class); + rule.addSharedClass(FlowId.class); + rule.addSharedClass(Flow.FlowState.class); + rule.addSharedClass(CodeLocation.class); + rule.addSharedClass(HttpMethod.class); + rule.addSharedClass(com.fnproject.fn.api.flow.HttpRequest.class); + rule.addSharedClass(com.fnproject.fn.api.flow.HttpResponse.class); + rule.addSharedClass(FlowCompletionException.class); + rule.addSharedClass(FunctionInvocationException.class); + rule.addSharedClass(PlatformException.class); + rule.addFeature(this); + } + + /** + * Create a Flow + * + * @param rule + * @return + */ + public static FlowTesting create(FnTestingRule rule) { + Objects.requireNonNull(rule, "rule"); + return new FlowTesting(rule); + } + + @Override + public void prepareTest(ClassLoader functionClassLoader, PrintStream stderr, String cls, String method) { + InMemCompleter.CompleterInvokeClient client = new TestRuleCompleterInvokeClient(functionClassLoader, stderr, cls, method); + InMemCompleter.FnInvokeClient fnInvokeClient = new TestRuleFnInvokeClient(); + + // The following must be a static: otherwise the factory (the lambda) will not be serializable. + completer = new InMemCompleter(client, fnInvokeClient); + + } + + @Override + public void prepareFunctionClassLoader(FnTestingClassLoader cl) { + setCompleterClient(cl, completer); + } + + @Override + public void afterTestComplete() { + completer.awaitTermination(); + } + + + private class TestRuleCompleterInvokeClient implements InMemCompleter.CompleterInvokeClient { + private final ClassLoader functionClassLoader; + private final PrintStream oldSystemErr; + private final String cls; + private final String method; + private final Set pool = new HashSet<>(); + + + private TestRuleCompleterInvokeClient(ClassLoader functionClassLoader, PrintStream oldSystemErr, String cls, String method) { + this.functionClassLoader = functionClassLoader; + this.oldSystemErr = oldSystemErr; + this.cls = cls; + this.method = method; + } + + + @Override + public APIModel.CompletionResult invokeStage(String fnId, FlowId flowId, CompletionId stageId, APIModel.Blob closure, List input) { + // Construct a new ClassLoader hierarchy with a copy of the statics embedded in the runtime. + // Initialise it appropriately. + FnTestingClassLoader fcl = new FnTestingClassLoader(functionClassLoader, rule.getSharedPrefixes()); + + + setCompleterClient(fcl, completer); + + + APIModel.InvokeStageRequest request = new APIModel.InvokeStageRequest(); + request.stageId = stageId.getId(); + request.flowId = flowId.getId(); + request.closure = closure; + request.args = input; + + String inputBody = null; + try { + inputBody = objectMapper.writeValueAsString(request); + } catch (JsonProcessingException e) { + throw new IllegalStateException("Invalid request"); + } + + // oldSystemErr.println("Body\n" + new String(inputBody)); + + InputEvent inputEvent = new FnHttpEventBuilder() + .withBody(inputBody) + .withHeader("Content-Type", "application/json") + .withHeader(FlowContinuationInvoker.FLOW_ID_HEADER, flowId.getId()).buildEvent(); + + Map mutableEnv = new HashMap<>(); + PrintStream functionErr = new PrintStream(oldSystemErr); + + // Do we want to capture IO from continuations on the main log stream? + // System.setOut(functionErr); + // System.setErr(functionErr); + + mutableEnv.putAll(rule.getConfig()); + mutableEnv.putAll(rule.getEventEnv()); + mutableEnv.put("FN_FORMAT", "http-stream"); + List output = new ArrayList<>(); + + + fcl.run( + mutableEnv, + new FnTestingRule.TestCodec(Collections.singletonList(inputEvent), output), + functionErr, + cls + "::" + method); + + FnResult out = output.get(0); + + APIModel.CompletionResult r; + try { + + APIModel.InvokeStageResponse response = objectMapper.readValue(out.getBodyAsBytes(), APIModel.InvokeStageResponse.class); + r = response.result; + + } catch (Exception e) { + oldSystemErr.println("Err\n" + e); + e.printStackTrace(oldSystemErr); + r = APIModel.CompletionResult.failure(APIModel.ErrorDatum.newError(APIModel.ErrorType.UnknownError, "Error reading fn Response:" + e.getMessage())); + } + + if (!r.successful) { + throw new ResultException(r.result); + } + return r; + + } + } + + private void setCompleterClient(FnTestingClassLoader cl, CompleterClientFactory completerClientFactory) { + try { + Class completerGlobals = cl.loadClass(FlowRuntimeGlobals.class.getName()); + completerGlobals.getMethod("setCompleterClientFactory", CompleterClientFactory.class).invoke(completerGlobals, completerClientFactory); + } catch (NoSuchMethodException | IllegalAccessException | InvocationTargetException | ClassNotFoundException | IllegalArgumentException e) { + throw new RuntimeException("Something broke in the reflective classloader", e); + } + } + + private interface FnFunctionStub { + com.fnproject.fn.api.flow.HttpResponse stubFunction(HttpMethod method, Headers headers, byte[] body); + } + + + public FnFunctionStubBuilder givenFn(String id) { + return new FnFunctionStubBuilder() { + @Override + public FlowTesting withResult(byte[] result) { + return withAction((body) -> result); + } + + @Override + public FlowTesting withFunctionError() { + return withAction((body) -> { + throw new FunctionError("simulated by testing platform"); + }); + } + + @Override + public FlowTesting withPlatformError() { + return withAction((body) -> { + throw new PlatformError("simulated by testing platform"); + }); + } + + @Override + public FlowTesting withAction(ExternalFunctionAction f) { + functionStubs.put(id, (HttpMethod method, Headers headers, byte[] body) -> { + try { + return new DefaultHttpResponse(200, Headers.emptyHeaders(), f.apply(body)); + } catch (FunctionError functionError) { + return new DefaultHttpResponse(500, Headers.emptyHeaders(), functionError.getMessage().getBytes()); + } catch (PlatformError platformError) { + throw new RuntimeException("Platform Error"); + } + }); + return FlowTesting.this; + } + }; + } + + private class TestRuleFnInvokeClient implements InMemCompleter.FnInvokeClient { + @Override + public CompletableFuture invokeFunction(String fnId, HttpMethod method, Headers headers, byte[] data) { + FnFunctionStub stub = functionStubs.computeIfAbsent(fnId, (k) -> { + throw new IllegalStateException("Function was invoked that had no definition: " + k + " defined functions are " + String.join(",",functionStubs.keySet())); + }); + + try { + return CompletableFuture.completedFuture(stub.stubFunction(method, headers, data)); + } catch (Exception e) { + CompletableFuture respFuture = new CompletableFuture<>(); + respFuture.completeExceptionally(e); + return respFuture; + } + } + } +} diff --git a/testing-core/src/main/java/com/fnproject/fn/testing/FnFunctionStubBuilder.java b/flow-testing/src/main/java/com/fnproject/fn/testing/flow/FnFunctionStubBuilder.java similarity index 81% rename from testing-core/src/main/java/com/fnproject/fn/testing/FnFunctionStubBuilder.java rename to flow-testing/src/main/java/com/fnproject/fn/testing/flow/FnFunctionStubBuilder.java index c2403659..c694be1f 100644 --- a/testing-core/src/main/java/com/fnproject/fn/testing/FnFunctionStubBuilder.java +++ b/flow-testing/src/main/java/com/fnproject/fn/testing/flow/FnFunctionStubBuilder.java @@ -1,4 +1,7 @@ -package com.fnproject.fn.testing; +package com.fnproject.fn.testing.flow; + +import com.fnproject.fn.testing.FunctionError; +import com.fnproject.fn.testing.PlatformError; /** * A builder for constructing stub external functions @@ -8,7 +11,7 @@ public interface FnFunctionStubBuilder { * Consume the builder and stub the function to return the provided byte array * * @param result A byte array returned by the function - * @return The original testing rule (usually {@link FnTestingRule}. The builder is consumed. + * @return The original testing rule (usually {@link FlowTesting}. The builder is consumed. */ T withResult(byte[] result); @@ -16,7 +19,7 @@ public interface FnFunctionStubBuilder { * Consume the builder and stub the function to throw an error when it is invoked: this simulates a failure of the * called function, e.g. if the external function threw an exception. * - * @return The original testing rule (usually {@link FnTestingRule}. The builder is consumed. + * @return The original testing rule (usually {@link FlowTesting}. The builder is consumed. */ T withFunctionError(); @@ -24,7 +27,7 @@ public interface FnFunctionStubBuilder { * Consume the builder and stub the function to throw a platform error, this simulates a failure of the Fn Flow * completions platform, and not any error of the user code. * - * @return The original testing rule (usually {@link FnTestingRule}. The builder is consumed. + * @return The original testing rule (usually {@link FlowTesting}. The builder is consumed. */ T withPlatformError(); @@ -37,7 +40,7 @@ public interface FnFunctionStubBuilder { * external state is accessed, a synchronization mechanism should be used. * * @param f an action to apply when this function is invoked - * @return The original testing rule (usually {@link FnTestingRule}. The builder is consumed. + * @return The original testing rule (usually {@link FlowTesting}. The builder is consumed. */ T withAction(ExternalFunctionAction f); diff --git a/testing-core/src/main/java/com/fnproject/fn/testing/InMemCompleter.java b/flow-testing/src/main/java/com/fnproject/fn/testing/flow/InMemCompleter.java similarity index 94% rename from testing-core/src/main/java/com/fnproject/fn/testing/InMemCompleter.java rename to flow-testing/src/main/java/com/fnproject/fn/testing/flow/InMemCompleter.java index 010b4fa1..c2c93649 100644 --- a/testing-core/src/main/java/com/fnproject/fn/testing/InMemCompleter.java +++ b/flow-testing/src/main/java/com/fnproject/fn/testing/flow/InMemCompleter.java @@ -1,4 +1,4 @@ -package com.fnproject.fn.testing; +package com.fnproject.fn.testing.flow; import com.fnproject.fn.api.Headers; import com.fnproject.fn.api.flow.*; @@ -570,37 +570,44 @@ private Stage addDelayStage(long delay) { private Stage addInvokeFunction(String functionId, HttpMethod method, Headers headers, byte[] data) { return addStage(new Stage(CompletableFuture.completedFuture(Collections.emptyList()), - (n, in) -> in.thenComposeAsync((ignored) -> { + (n, in) -> { + return in.thenComposeAsync((ignored) -> { - CompletionStage respFuture = fnInvokeClient.invokeFunction(functionId, method, headers, data); - return respFuture.thenApply((res) -> { - APIModel.HTTPResp apiResp = new APIModel.HTTPResp(); - apiResp.headers = res.getHeaders().getAll().entrySet() - .stream().map(e -> APIModel.HTTPHeader.create(e.getKey(), e.getValue())).collect(Collectors.toList()); + CompletionStage respFuture = fnInvokeClient.invokeFunction(functionId, method, headers, data); + return respFuture.thenApply((res) -> { + APIModel.HTTPResp apiResp = new APIModel.HTTPResp(); + List callHeaders = new ArrayList<>(); - BlobResponse blobResponse = writeBlob(flowId.getId(), res.getBodyAsBytes(), res.getHeaders().get("Content-type").orElse("application/octet-stream")); + for (Map.Entry> e : res.getHeaders().asMap().entrySet()) { + for (String v : e.getValue()) { + callHeaders.add(APIModel.HTTPHeader.create(e.getKey(), v)); + } + } + apiResp.headers = callHeaders; + BlobResponse blobResponse = writeBlob(flowId.getId(), res.getBodyAsBytes(), res.getHeaders().get("Content-type").orElse("application/octet-stream")); - apiResp.body = APIModel.Blob.fromBlobResponse(blobResponse); - apiResp.statusCode = res.getStatusCode(); + apiResp.body = APIModel.Blob.fromBlobResponse(blobResponse); + apiResp.statusCode = res.getStatusCode(); - APIModel.HTTPRespDatum datum = APIModel.HTTPRespDatum.create(apiResp); + APIModel.HTTPRespDatum datum = APIModel.HTTPRespDatum.create(apiResp); - if (apiResp.statusCode >= 200 && apiResp.statusCode < 400) { - return APIModel.CompletionResult.success(datum); - } else { - throw new ResultException(datum); - } + if (apiResp.statusCode >= 200 && apiResp.statusCode < 400) { + return APIModel.CompletionResult.success(datum); + } else { + throw new ResultException(datum); + } - }).exceptionally(e->{ - if (e.getCause() instanceof ResultException){ - throw (ResultException)e.getCause(); - }else{ - throw new ResultException(APIModel.ErrorDatum.newError(APIModel.ErrorType.FunctionInvokeFailed,e.getMessage())); - } - }); + }).exceptionally(e -> { + if (e.getCause() instanceof ResultException) { + throw (ResultException) e.getCause(); + } else { + throw new ResultException(APIModel.ErrorDatum.newError(APIModel.ErrorType.FunctionInvokeFailed, e.getMessage())); + } + }); - }, faasExecutor) + }, faasExecutor); + } )); } diff --git a/testing-core/src/main/java/com/fnproject/fn/testing/ResultException.java b/flow-testing/src/main/java/com/fnproject/fn/testing/flow/ResultException.java similarity index 89% rename from testing-core/src/main/java/com/fnproject/fn/testing/ResultException.java rename to flow-testing/src/main/java/com/fnproject/fn/testing/flow/ResultException.java index e2082b3c..be910af7 100644 --- a/testing-core/src/main/java/com/fnproject/fn/testing/ResultException.java +++ b/flow-testing/src/main/java/com/fnproject/fn/testing/flow/ResultException.java @@ -1,4 +1,4 @@ -package com.fnproject.fn.testing; +package com.fnproject.fn.testing.flow; import com.fnproject.fn.runtime.flow.APIModel; diff --git a/testing-junit4/src/test/java/junit/com/fnproject/fn/testing/FnTestingRuleFlowsTest.java b/flow-testing/src/test/java/com/fnproject/fn/testing/flow/FnTestingRuleFlowsTest.java similarity index 94% rename from testing-junit4/src/test/java/junit/com/fnproject/fn/testing/FnTestingRuleFlowsTest.java rename to flow-testing/src/test/java/com/fnproject/fn/testing/flow/FnTestingRuleFlowsTest.java index a3a5b982..cf7946ce 100644 --- a/testing-junit4/src/test/java/junit/com/fnproject/fn/testing/FnTestingRuleFlowsTest.java +++ b/flow-testing/src/test/java/com/fnproject/fn/testing/flow/FnTestingRuleFlowsTest.java @@ -1,8 +1,8 @@ -package junit.com.fnproject.fn.testing; +package com.fnproject.fn.testing.flow; -import com.fnproject.fn.api.Headers; -import com.fnproject.fn.api.RuntimeContext; +import com.fnproject.fn.api.*; import com.fnproject.fn.api.flow.*; +import com.fnproject.fn.runtime.flow.FlowFeature; import com.fnproject.fn.testing.FnTestingRule; import org.assertj.core.api.Assertions; import org.junit.Assert; @@ -18,11 +18,13 @@ public class FnTestingRuleFlowsTest { - private static final int HTTP_OK = 200; @Rule public FnTestingRule fn = FnTestingRule.createDefault(); + private FlowTesting flow = FlowTesting.create(fn); + + @FnFeature(FlowFeature.class) public static class Loop { public static int COUNT = 5; @@ -79,10 +81,9 @@ public void setup() { @Test public void completedValue() { fn.givenEvent().enqueue(); - fn.thenRun(TestFn.class, "completedValue"); - Assertions.assertThat(fn.getOnlyResult().getStatus()).isEqualTo(200); + Assertions.assertThat(fn.getOnlyResult().getStatus()).isEqualTo(OutputEvent.Status.Success); Assertions.assertThat(result).isEqualTo(Result.CompletedValue); } @@ -92,7 +93,7 @@ public void supply() { fn.thenRun(TestFn.class, "supply"); - Assertions.assertThat(fn.getOnlyResult().getStatus()).isEqualTo(HTTP_OK); + Assertions.assertThat(fn.getOnlyResult().getStatus()).isEqualTo(OutputEvent.Status.Success); Assertions.assertThat(result).isEqualTo(Result.Supply); } @@ -102,7 +103,7 @@ public void allOf() { fn.thenRun(TestFn.class, "allOf"); - Assertions.assertThat(fn.getOnlyResult().getStatus()).isEqualTo(HTTP_OK); + Assertions.assertThat(fn.getOnlyResult().getStatus()).isEqualTo(OutputEvent.Status.Success); Assertions.assertThat(result).isEqualTo(Result.AllOf); } @@ -113,7 +114,7 @@ public void anyOf() { fn.thenRun(TestFn.class, "anyOf"); - Assertions.assertThat(fn.getOnlyResult().getStatus()).isEqualTo(HTTP_OK); + Assertions.assertThat(fn.getOnlyResult().getStatus()).isEqualTo(OutputEvent.Status.Success); Assertions.assertThat(result).isEqualTo(Result.AnyOf); } @@ -125,7 +126,7 @@ public void nestedThenCompose() { fn.thenRun(Loop.class, "repeat"); - Assertions.assertThat(fn.getOnlyResult().getStatus()).isEqualTo(HTTP_OK); + Assertions.assertThat(fn.getOnlyResult().getStatus()).isEqualTo(OutputEvent.Status.Success); Assertions.assertThat(fn.getOnlyResult().getBodyAsString()) .isEqualTo(String.join("", Collections.nCopies(Loop.COUNT, "hello world"))); } @@ -133,12 +134,12 @@ public void nestedThenCompose() { @Test public void invokeFunctionWithResult() { fn.givenEvent().enqueue(); - fn.givenFn("user/echo") + flow.givenFn("user/echo") .withResult(Result.InvokeFunctionFixed.name().getBytes()); fn.thenRun(TestFn.class, "invokeFunctionEcho"); - Assertions.assertThat(fn.getOnlyResult().getStatus()).isEqualTo(HTTP_OK); + Assertions.assertThat(fn.getOnlyResult().getStatus()).isEqualTo(OutputEvent.Status.Success); Assertions.assertThat(result).isEqualTo(Result.InvokeFunctionFixed); } @@ -146,7 +147,7 @@ public void invokeFunctionWithResult() { @Test public void invokeJsonFunction() { fn.givenEvent().enqueue(); - fn.givenFn("user/json") + flow.givenFn("user/json") .withAction((ign) -> { if (new String(ign).equals("{\"foo\":\"bar\"}")) { return "{\"foo\":\"baz\"}".getBytes(); @@ -157,19 +158,19 @@ public void invokeJsonFunction() { fn.thenRun(TestFn.class, "invokeJsonFunction"); - Assertions.assertThat(fn.getOnlyResult().getStatus()).isEqualTo(HTTP_OK); + Assertions.assertThat(fn.getOnlyResult().getStatus()).isEqualTo(OutputEvent.Status.Success); Assertions.assertThat(count).isEqualTo(1); } @Test public void invokeFunctionWithFunctionError() { fn.givenEvent().enqueue(); - fn.givenFn("user/error") + flow.givenFn("user/error") .withFunctionError(); fn.thenRun(TestFn.class, "invokeFunctionError"); - Assertions.assertThat(fn.getOnlyResult().getStatus()).isEqualTo(HTTP_OK); + Assertions.assertThat(fn.getOnlyResult().getStatus()).isEqualTo(OutputEvent.Status.Success); Assertions.assertThat(result).isEqualTo(Result.Exceptionally); isInstanceOfAny(exception, FunctionInvocationException.class); } @@ -180,7 +181,7 @@ public void invokeFunctionWithFailedFuture() { fn.thenRun(TestFn.class, "failedFuture"); - Assertions.assertThat(fn.getOnlyResult().getStatus()).isEqualTo(HTTP_OK); + Assertions.assertThat(fn.getOnlyResult().getStatus()).isEqualTo(OutputEvent.Status.Success); Assertions.assertThat(result).isEqualTo(Result.Exceptionally); Assertions.assertThat(exception).isInstanceOf(RuntimeException.class); Assertions.assertThat(exception).hasMessage("failedFuture"); @@ -189,12 +190,12 @@ public void invokeFunctionWithFailedFuture() { @Test public void invokeFunctionWithPlatformError() { fn.givenEvent().enqueue(); - fn.givenFn("user/error") + flow.givenFn("user/error") .withPlatformError(); fn.thenRun(TestFn.class, "invokeFunctionError"); - Assertions.assertThat(fn.getOnlyResult().getStatus()).isEqualTo(HTTP_OK); + Assertions.assertThat(fn.getOnlyResult().getStatus()).isEqualTo(OutputEvent.Status.Success); Assertions.assertThat(result).isEqualTo(Result.Exceptionally); isInstanceOfAny(exception, PlatformException.class); } @@ -202,12 +203,12 @@ public void invokeFunctionWithPlatformError() { @Test public void invokeFunctionWithAction() { fn.givenEvent().enqueue(); - fn.givenFn("user/echo") + flow.givenFn("user/echo") .withAction((p) -> p); fn.thenRun(TestFn.class, "invokeFunctionEcho"); - Assertions.assertThat(fn.getOnlyResult().getStatus()).isEqualTo(HTTP_OK); + Assertions.assertThat(fn.getOnlyResult().getStatus()).isEqualTo(OutputEvent.Status.Success); Assertions.assertThat(result).isEqualTo(Result.InvokeFunctionEcho); } @@ -217,7 +218,7 @@ public void completingExceptionally() { fn.thenRun(TestFn.class, "completeExceptionally"); - Assertions.assertThat(fn.getOnlyResult().getStatus()).isEqualTo(HTTP_OK); + Assertions.assertThat(fn.getOnlyResult().getStatus()).isEqualTo(OutputEvent.Status.Success); Assertions.assertThat(result).isEqualTo(Result.Exceptionally); } @@ -227,7 +228,7 @@ public void completingExceptionallyWhenErrorIsThrownEarlyInGraph() { fn.thenRun(TestFn.class, "completeExceptionallyEarly"); - Assertions.assertThat(fn.getOnlyResult().getStatus()).isEqualTo(HTTP_OK); + Assertions.assertThat(fn.getOnlyResult().getStatus()).isEqualTo(OutputEvent.Status.Success); Assertions.assertThat(result).isEqualTo(Result.Exceptionally); } @@ -237,7 +238,7 @@ public void cancelledFutureCompletesExceptionally() { fn.thenRun(TestFn.class, "cancelFuture"); - Assertions.assertThat(fn.getOnlyResult().getStatus()).isEqualTo(HTTP_OK); + Assertions.assertThat(fn.getOnlyResult().getStatus()).isEqualTo(OutputEvent.Status.Success); Assertions.assertThat(result).isEqualTo(Result.Exceptionally); Assertions.assertThat(exception).isInstanceOf(CancellationException.class); } @@ -248,7 +249,7 @@ public void completeFutureExceptionallyWithCustomException() { fn.thenRun(TestFn.class, "completeFutureExceptionally"); - Assertions.assertThat(fn.getOnlyResult().getStatus()).isEqualTo(HTTP_OK); + Assertions.assertThat(fn.getOnlyResult().getStatus()).isEqualTo(OutputEvent.Status.Success); Assertions.assertThat(result).isEqualTo(Result.Exceptionally); Assertions.assertThat(exception).isInstanceOf(RuntimeException.class); Assertions.assertThat(exception.getMessage()).isEqualTo("Custom exception"); @@ -260,7 +261,7 @@ public void completedFutureCompletesNormally() { fn.thenRun(TestFn.class, "completeFuture"); - Assertions.assertThat(fn.getOnlyResult().getStatus()).isEqualTo(HTTP_OK); + Assertions.assertThat(fn.getOnlyResult().getStatus()).isEqualTo(OutputEvent.Status.Success); Assertions.assertThat(result).isEqualTo(Result.CompletedValue); } @@ -270,7 +271,7 @@ public void uncompletedFutureCanBeCompleted() { fn.thenRun(TestFn.class, "createFlowFuture"); - Assertions.assertThat(fn.getOnlyResult().getStatus()).isEqualTo(HTTP_OK); + Assertions.assertThat(fn.getOnlyResult().getStatus()).isEqualTo(OutputEvent.Status.Success); Assertions.assertThat(result).isEqualTo(Result.CompletedValue); } @@ -281,7 +282,7 @@ public void shouldLogMessagesToStdErrToPlatformStdErr() { fn.thenRun(TestFn.class, "logToStdErrInContinuation"); - Assertions.assertThat(fn.getOnlyResult().getStatus()).isEqualTo(HTTP_OK); + Assertions.assertThat(fn.getOnlyResult().getStatus()).isEqualTo(OutputEvent.Status.Success); Assertions.assertThat(fn.getStdErrAsString()).contains("TestFn logging: 1"); } @@ -292,7 +293,7 @@ public void shouldLogMessagesToStdOutToPlatformStdErr() { fn.thenRun(TestFn.class, "logToStdOutInContinuation"); - Assertions.assertThat(fn.getOnlyResult().getStatus()).isEqualTo(HTTP_OK); + Assertions.assertThat(fn.getOnlyResult().getStatus()).isEqualTo(OutputEvent.Status.Success); Assertions.assertThat(fn.getStdErrAsString()).contains("TestFn logging: 1"); } @@ -303,8 +304,8 @@ public void shouldHandleMultipleEventsForFunctionWithoutInput() { fn.thenRun(TestFn.class, "anyOf"); - Assertions.assertThat(fn.getResults().get(0).getStatus()).isEqualTo(HTTP_OK); - Assertions.assertThat(fn.getResults().get(1).getStatus()).isEqualTo(HTTP_OK); + Assertions.assertThat(fn.getResults().get(0).getStatus()).isEqualTo(OutputEvent.Status.Success); + Assertions.assertThat(fn.getResults().get(1).getStatus()).isEqualTo(OutputEvent.Status.Success); Assertions.assertThat(result).isEqualTo(Result.AnyOf); } @@ -314,7 +315,7 @@ public void exceptionallyComposeHandle() { fn.thenRun(TestFn.class, "exceptionallyComposeHandle"); - Assertions.assertThat(fn.getOnlyResult().getStatus()).isEqualTo(HTTP_OK); + Assertions.assertThat(fn.getOnlyResult().getStatus()).isEqualTo(OutputEvent.Status.Success); Assertions.assertThat(count).isEqualTo(2); } @@ -325,7 +326,7 @@ public void exceptionallyComposePassThru() { fn.givenEvent().enqueue(); fn.thenRun(TestFn.class, "exceptionallyComposePassThru"); - Assertions.assertThat(fn.getOnlyResult().getStatus()).isEqualTo(HTTP_OK); + Assertions.assertThat(fn.getOnlyResult().getStatus()).isEqualTo(OutputEvent.Status.Success); Assertions.assertThat(count).isEqualTo(1); } @@ -335,7 +336,7 @@ public void exceptionallyComposeThrowsError() { fn.givenEvent().enqueue(); fn.thenRun(TestFn.class, "exceptionallyComposeThrowsError"); - Assertions.assertThat(fn.getOnlyResult().getStatus()).isEqualTo(HTTP_OK); + Assertions.assertThat(fn.getOnlyResult().getStatus()).isEqualTo(OutputEvent.Status.Success); Assertions.assertThat(count).isEqualTo(1); } @@ -360,7 +361,7 @@ public void shouldRunShutdownHooksInTest() { fn.givenEvent().enqueue(); fn.thenRun(TestFn.class, "terminationHooks"); - Assertions.assertThat(fn.getOnlyResult().getStatus()).isEqualTo(200); + Assertions.assertThat(fn.getOnlyResult().getStatus()).isEqualTo(OutputEvent.Status.Success); Assertions.assertThat(result).isEqualTo(Result.TerminationHookRun); @@ -381,6 +382,7 @@ void isInstanceOfAny(Object o, Class... cs) { Assert.fail("Object " + o + "is not an instance of any of " + Arrays.toString(cs)); } + @FnFeature(FlowFeature.class) public static class TestFn { static Integer TO_ADD = null; @@ -388,6 +390,7 @@ public TestFn(RuntimeContext ctx) { TO_ADD = Integer.parseInt(ctx.getConfigurationByKey("ADD").orElse("-1")); } + public void completedValue() { Flows.currentFlow() .completedValue(Result.CompletedValue).thenAccept((r) -> result = r); diff --git a/flow-testing/src/test/java/com/fnproject/fn/testing/flow/IntegrationTest.java b/flow-testing/src/test/java/com/fnproject/fn/testing/flow/IntegrationTest.java new file mode 100644 index 00000000..61e86171 --- /dev/null +++ b/flow-testing/src/test/java/com/fnproject/fn/testing/flow/IntegrationTest.java @@ -0,0 +1,42 @@ +package com.fnproject.fn.testing.flow; + +import com.fnproject.fn.testing.FnTestingRule; +import com.fnproject.fn.testing.FunctionError; +import com.fnproject.fn.testing.flowtestfns.ExerciseEverything; +import org.assertj.core.api.Assertions; +import org.junit.Rule; +import org.junit.Test; + +public class IntegrationTest { + + @Rule + public FnTestingRule fn = FnTestingRule.createDefault(); + + public FlowTesting flow = FlowTesting.create(fn); + + @Test + public void runIntegrationTests() { + + flow.givenFn("testFunctionNonExistant") + .withFunctionError() + + .givenFn("testFunction") + .withAction((body) -> { + if (new String(body).equals("PASS")) { + return "okay".getBytes(); + } else { + throw new FunctionError("failed as demanded"); + } + }); + + fn + .givenEvent() + .withBody("") // or "1,5,6,32" to select a set of tests individually + .enqueue() + + .thenRun(ExerciseEverything.class, "handleRequest"); + + Assertions.assertThat(fn.getResults().get(0).getBodyAsString()) + .endsWith("Everything worked\n"); + } +} diff --git a/testing-junit4/src/test/java/junit/com/fnproject/fn/testing/MultipleEventsTest.java b/flow-testing/src/test/java/com/fnproject/fn/testing/flow/MultipleEventsTest.java similarity index 94% rename from testing-junit4/src/test/java/junit/com/fnproject/fn/testing/MultipleEventsTest.java rename to flow-testing/src/test/java/com/fnproject/fn/testing/flow/MultipleEventsTest.java index bd494797..a6b23eec 100644 --- a/testing-junit4/src/test/java/junit/com/fnproject/fn/testing/MultipleEventsTest.java +++ b/flow-testing/src/test/java/com/fnproject/fn/testing/flow/MultipleEventsTest.java @@ -1,7 +1,9 @@ -package junit.com.fnproject.fn.testing; +package com.fnproject.fn.testing.flow; +import com.fnproject.fn.api.FnFeature; import com.fnproject.fn.api.flow.Flow; import com.fnproject.fn.api.flow.Flows; +import com.fnproject.fn.runtime.flow.FlowFeature; import com.fnproject.fn.testing.FnTestingRule; import org.assertj.core.api.Assertions; import org.junit.Rule; @@ -13,10 +15,13 @@ public class MultipleEventsTest { @Rule public FnTestingRule fn = FnTestingRule.createDefault(); + public FlowTesting flow = FlowTesting.create(fn); + public static Semaphore oneGo = null; public static Semaphore twoGo = null; public static boolean success = false; + @FnFeature(FlowFeature.class) public static class TestFn { public void handleRequest(String s) { switch (s) { diff --git a/testing-junit4/src/test/java/junit/com/fnproject/fn/testing/WhenCompleteTest.java b/flow-testing/src/test/java/com/fnproject/fn/testing/flow/WhenCompleteTest.java similarity index 81% rename from testing-junit4/src/test/java/junit/com/fnproject/fn/testing/WhenCompleteTest.java rename to flow-testing/src/test/java/com/fnproject/fn/testing/flow/WhenCompleteTest.java index 2f87670f..d219061f 100644 --- a/testing-junit4/src/test/java/junit/com/fnproject/fn/testing/WhenCompleteTest.java +++ b/flow-testing/src/test/java/com/fnproject/fn/testing/flow/WhenCompleteTest.java @@ -1,6 +1,8 @@ -package junit.com.fnproject.fn.testing; +package com.fnproject.fn.testing.flow; +import com.fnproject.fn.api.FnFeature; import com.fnproject.fn.api.flow.Flows; +import com.fnproject.fn.runtime.flow.FlowFeature; import com.fnproject.fn.testing.FnTestingRule; import org.assertj.core.api.Assertions; import org.junit.Rule; @@ -11,9 +13,12 @@ public class WhenCompleteTest { @Rule public FnTestingRule fn = FnTestingRule.createDefault(); + private FlowTesting flow = FlowTesting.create(fn); public static AtomicInteger cas = new AtomicInteger(0); + + @FnFeature(FlowFeature.class) public static class TestFn { public void handleRequest() { Flows.currentFlow().completedValue(1) diff --git a/testing-junit4/src/test/java/junit/com/fnproject/fn/testing/ExerciseEverything.java b/flow-testing/src/test/java/com/fnproject/fn/testing/flowtestfns/ExerciseEverything.java similarity index 95% rename from testing-junit4/src/test/java/junit/com/fnproject/fn/testing/ExerciseEverything.java rename to flow-testing/src/test/java/com/fnproject/fn/testing/flowtestfns/ExerciseEverything.java index 0d559fea..8807dacc 100644 --- a/testing-junit4/src/test/java/junit/com/fnproject/fn/testing/ExerciseEverything.java +++ b/flow-testing/src/test/java/com/fnproject/fn/testing/flowtestfns/ExerciseEverything.java @@ -1,8 +1,8 @@ -package junit.com.fnproject.fn.testing; +package com.fnproject.fn.testing.flowtestfns; -import com.fnproject.fn.api.Headers; -import com.fnproject.fn.api.InputEvent; +import com.fnproject.fn.api.*; import com.fnproject.fn.api.flow.*; +import com.fnproject.fn.runtime.flow.FlowFeature; import org.apache.commons.io.IOUtils; import org.apache.commons.io.output.TeeOutputStream; @@ -18,8 +18,10 @@ import java.util.*; import java.util.stream.Collectors; +@FnFeature(FlowFeature.class) public class ExerciseEverything { + private boolean okay = true; private ByteArrayOutputStream bos = new ByteArrayOutputStream(); private PrintStream out = new PrintStream(new TeeOutputStream(System.err, bos)); @@ -130,24 +132,22 @@ public FlowFuture catchBubbledException(Flow fl) { @Test(11) @Test.Catch({FlowCompletionException.class, FunctionInvocationException.class}) public FlowFuture nonexistentExternalEvaluation(Flow fl) { - return fl.invokeFunction("nonexistent/nonexistent", HttpMethod.POST, Headers.emptyHeaders(), new byte[0]); + return fl.invokeFunction("testFunctionNonExistant", HttpMethod.POST, Headers.emptyHeaders(), new byte[0]); } @Test(12) @Test.Expect("okay") - public FlowFuture checkPassingExternalInvocation(Flow fl) { - return fl.invokeFunction(inputEvent.getAppName() + inputEvent.getRoute(), HttpMethod.POST, Headers.emptyHeaders(), "PASS".getBytes()) - .thenApply((resp) -> { - return resp.getStatusCode() != 200 ? "failure" : new String(resp.getBodyAsBytes()); - }); + public FlowFuture checkPassingInvocation(Flow fl) { + return fl.invokeFunction("testFunction", HttpMethod.POST, Headers.emptyHeaders(), "PASS".getBytes()) + .thenApply((resp) -> resp.getStatusCode() != 200 ? "failure" : new String(resp.getBodyAsBytes())); } // There is currently no way for a hot function to signal failure in the Fn platform. // This test will only work in default mode. @Test(13) @Test.Catch({FlowCompletionException.class, FunctionInvocationException.class}) - public FlowFuture checkFailingExternalInvocation(Flow fl) { - return fl.invokeFunction(inputEvent.getAppName() + inputEvent.getRoute(), HttpMethod.POST, Headers.emptyHeaders(), "FAIL".getBytes()); + public FlowFuture checkFailingInvocation(Flow fl) { + return fl.invokeFunction("testFunction", HttpMethod.POST, Headers.emptyHeaders(), "FAIL".getBytes()); } // This original version captures the RT, which captures the factory, which is not serializable @@ -366,6 +366,11 @@ public FlowFuture exceptionallyComposePropagateError(Flow fl) throws IOE private int id; + private final RuntimeContext runtimeContext; + + public ExerciseEverything(RuntimeContext rtc){ + this.runtimeContext = rtc; + } void fail() { if (!failures.contains(id)) { failures.add(id); diff --git a/fn-spring-cloud-function/src/main/java/com/fnproject/springframework/function/SpringCloudFunctionFeature.java b/fn-spring-cloud-function/src/main/java/com/fnproject/springframework/function/SpringCloudFunctionFeature.java new file mode 100644 index 00000000..87d51d4d --- /dev/null +++ b/fn-spring-cloud-function/src/main/java/com/fnproject/springframework/function/SpringCloudFunctionFeature.java @@ -0,0 +1,21 @@ +package com.fnproject.springframework.function; + +import com.fnproject.fn.api.FunctionInvoker; +import com.fnproject.fn.api.RuntimeContext; +import com.fnproject.fn.api.RuntimeFeature; + +/** + * + * The SpringCloudFunctionFeature enables a function to be run with a spring cloud function configuration + * + * Created on 10/09/2018. + *

+ * (c) 2018 Oracle Corporation + */ +public class SpringCloudFunctionFeature implements RuntimeFeature { + + @Override + public void initialize(RuntimeContext ctx) { + ctx.addInvoker(new SpringCloudFunctionInvoker(ctx.getMethod().getTargetClass()),FunctionInvoker.Phase.Call); + } +} diff --git a/fn-spring-cloud-function/src/test/java/com/fnproject/springframework/function/SpringCloudFunctionInvokerIntegrationTest.java b/fn-spring-cloud-function/src/test/java/com/fnproject/springframework/function/SpringCloudFunctionInvokerIntegrationTest.java index 29b82965..eb859b2e 100644 --- a/fn-spring-cloud-function/src/test/java/com/fnproject/springframework/function/SpringCloudFunctionInvokerIntegrationTest.java +++ b/fn-spring-cloud-function/src/test/java/com/fnproject/springframework/function/SpringCloudFunctionInvokerIntegrationTest.java @@ -65,7 +65,7 @@ public void shouldThrowFunctionLoadExceptionIfNoValidFunction() { int exitCode = fnRule.getLastExitCode(); - assertThat(exitCode).isEqualTo(2); + assertThat(exitCode).isEqualTo(1); assertThat(fnRule.getResults()).isEmpty(); // fails at init so no results. assertThat(fnRule.getStdErrAsString()).contains("No Spring Cloud Function found"); } @@ -78,7 +78,7 @@ public void noNPEifFunctionReturnsNull() { int exitCode = fnRule.getLastExitCode(); - assertThat(exitCode).isEqualTo(2); + assertThat(exitCode).isEqualTo(1); assertThat(fnRule.getResults()).isEmpty(); // fails at init so no results. assertThat(fnRule.getStdErrAsString()).contains("No Spring Cloud Function found"); } diff --git a/fn-spring-cloud-function/src/test/java/com/fnproject/springframework/function/testfns/EmptyFunctionConfig.java b/fn-spring-cloud-function/src/test/java/com/fnproject/springframework/function/testfns/EmptyFunctionConfig.java index 8ac2c7ff..0f650d22 100644 --- a/fn-spring-cloud-function/src/test/java/com/fnproject/springframework/function/testfns/EmptyFunctionConfig.java +++ b/fn-spring-cloud-function/src/test/java/com/fnproject/springframework/function/testfns/EmptyFunctionConfig.java @@ -1,7 +1,10 @@ package com.fnproject.springframework.function.testfns; import com.fnproject.fn.api.FnConfiguration; +import com.fnproject.fn.api.FnFeature; +import com.fnproject.fn.api.FunctionInvoker; import com.fnproject.fn.api.RuntimeContext; +import com.fnproject.springframework.function.SpringCloudFunctionFeature; import com.fnproject.springframework.function.SpringCloudFunctionInvoker; import org.springframework.cloud.function.context.config.ContextFunctionCatalogAutoConfiguration; import org.springframework.context.annotation.Configuration; @@ -9,11 +12,10 @@ @Configuration @Import(ContextFunctionCatalogAutoConfiguration.class) +@FnFeature(SpringCloudFunctionFeature.class) public class EmptyFunctionConfig { - @FnConfiguration - public static void configure(RuntimeContext ctx) { - ctx.setInvoker(new SpringCloudFunctionInvoker(EmptyFunctionConfig.class)); + + public void handleRequest() { } - public void handleRequest() { } } diff --git a/fn-spring-cloud-function/src/test/java/com/fnproject/springframework/function/testfns/FunctionConfig.java b/fn-spring-cloud-function/src/test/java/com/fnproject/springframework/function/testfns/FunctionConfig.java index 46646665..fb8dbeb7 100644 --- a/fn-spring-cloud-function/src/test/java/com/fnproject/springframework/function/testfns/FunctionConfig.java +++ b/fn-spring-cloud-function/src/test/java/com/fnproject/springframework/function/testfns/FunctionConfig.java @@ -1,7 +1,9 @@ package com.fnproject.springframework.function.testfns; import com.fnproject.fn.api.FnConfiguration; +import com.fnproject.fn.api.FnFeature; import com.fnproject.fn.api.RuntimeContext; +import com.fnproject.springframework.function.SpringCloudFunctionFeature; import com.fnproject.springframework.function.SpringCloudFunctionInvoker; import org.springframework.cloud.function.context.config.ContextFunctionCatalogAutoConfiguration; import org.springframework.context.annotation.Bean; @@ -14,13 +16,9 @@ @Configuration @Import(ContextFunctionCatalogAutoConfiguration.class) +@FnFeature(SpringCloudFunctionFeature.class) public class FunctionConfig { - @FnConfiguration - public static void configure(RuntimeContext ctx) { - ctx.setInvoker(new SpringCloudFunctionInvoker(FunctionConfig.class)); - } - public void handleRequest() { } diff --git a/integration-tests/.gitignore b/integration-tests/.gitignore deleted file mode 100644 index 9b3667f0..00000000 --- a/integration-tests/.gitignore +++ /dev/null @@ -1,5 +0,0 @@ -*/*/actual -*/*/build-output -*/*/success -*/*/failure -*/*/output diff --git a/integration-tests/README.md b/integration-tests/README.md index 0d13256d..6f4ad5b8 100644 --- a/integration-tests/README.md +++ b/integration-tests/README.md @@ -11,30 +11,15 @@ They should _not_ be used for: * extensive feature testing (use unit tests) * Performance/load testing -## Creating a new test - -Put main integration tests under main/test- - -the content of a test dir is a a typically a new function (containing func.yaml, pom.xml etc. ) - -create the following files: -* `input` : the input to pass to the deployed function -* `expected` : the verbatim expected result of the function -* `expected.sh` : a shell script that should succeed when the test passed - this is used in place of `expected` -* `config` : A newline seperated list of config variables to set on the function -* `pre-test.sh` a script that is run before the function is called (e.g. to call fn init to check bootstrapping) - - # Running locally -To run locally you will need to deploy the fn artifacts to a local repository: (in top-level dir) ```bash export REPOSITORY_LOCATION=/tmp/staging-repository # on OSX: -export DOCKER_LOCALHOST=docker.for.mac.localhost +export DOCKER_LOCALHOST=docker.for.mac.host.internal mvn deploy -DaltDeploymentRepository=localStagingDir::default::file://"$REPOSITORY_LOCATION" ``` @@ -55,16 +40,8 @@ docker build -f Dockerfile-jdk9 -t fnproject/fn-java-fdk:jdk9-latest . Finally you can run the integration tests: ```bash -./integration-tests/run-local.sh +./integration-tests/run_tests_ci.sh ``` -Note that these will update the pom files in the tests - don't check these in! - - -# Running against a remote environment -For running against a remote integration environment, configure - ~/.fn-token - ~/.fn-api-url - ~/.fn-flow-base-url -and run the `run-remote.sh` script. +This will start/stop fnserver and flow server \ No newline at end of file diff --git a/integration-tests/_archive/test-3/.gitignore b/integration-tests/_archive/test-3/.gitignore deleted file mode 100644 index a9c2e6bb..00000000 --- a/integration-tests/_archive/test-3/.gitignore +++ /dev/null @@ -1,3 +0,0 @@ -/func.yaml -/pom.xml -/src/ diff --git a/integration-tests/_archive/test-3/expected b/integration-tests/_archive/test-3/expected deleted file mode 100644 index fda590c7..00000000 --- a/integration-tests/_archive/test-3/expected +++ /dev/null @@ -1 +0,0 @@ -Hello, function! \ No newline at end of file diff --git a/integration-tests/_archive/test-3/input b/integration-tests/_archive/test-3/input deleted file mode 100644 index e2dbde09..00000000 --- a/integration-tests/_archive/test-3/input +++ /dev/null @@ -1 +0,0 @@ -function diff --git a/integration-tests/_archive/test-3/pre-test.sh b/integration-tests/_archive/test-3/pre-test.sh deleted file mode 100755 index 40f613f4..00000000 --- a/integration-tests/_archive/test-3/pre-test.sh +++ /dev/null @@ -1,6 +0,0 @@ -#!/usr/bin/env bash - -set -ex - -rm -rf Dockerfile func.yaml pom.xml src -FN_JAVA_FDK_VERSION=$(cat ../../../release.version) fn init --runtime=java9 --name app/test diff --git a/integration-tests/_archive/test-7/delete.sh b/integration-tests/_archive/test-7/delete.sh deleted file mode 100644 index 5733a424..00000000 --- a/integration-tests/_archive/test-7/delete.sh +++ /dev/null @@ -1,3 +0,0 @@ -#!/bin/bash -ex - -fn delete route "$TESTNAME" /test-7 diff --git a/integration-tests/_archive/test-7/deploy.sh b/integration-tests/_archive/test-7/deploy.sh deleted file mode 100755 index 515e2071..00000000 --- a/integration-tests/_archive/test-7/deploy.sh +++ /dev/null @@ -1,3 +0,0 @@ -#!/bin/bash -ex - -fn deploy --app "$TESTNAME" --local diff --git a/integration-tests/_archive/test-7/expected b/integration-tests/_archive/test-7/expected deleted file mode 100644 index 5dd01c17..00000000 --- a/integration-tests/_archive/test-7/expected +++ /dev/null @@ -1 +0,0 @@ -Hello, world! \ No newline at end of file diff --git a/integration-tests/_archive/test-7/pre-test.sh b/integration-tests/_archive/test-7/pre-test.sh deleted file mode 100755 index f4699600..00000000 --- a/integration-tests/_archive/test-7/pre-test.sh +++ /dev/null @@ -1,6 +0,0 @@ -#!/bin/bash -ex - -set -ex - -rm -rf Dockerfile func.yaml pom.xml src -FN_JAVA_FDK_VERSION=$(cat ../../../release.version) fn init --runtime=java --name app/hello diff --git a/integration-tests/_archive/test-7/run-test.sh b/integration-tests/_archive/test-7/run-test.sh deleted file mode 100755 index 0af4edc3..00000000 --- a/integration-tests/_archive/test-7/run-test.sh +++ /dev/null @@ -1,3 +0,0 @@ -#!/bin/bash -ex - -fn call "$TESTNAME" /test-7 > actual diff --git a/integration-tests/main/test-4/README.md b/integration-tests/funcs/flowAllFeatures/README.md similarity index 100% rename from integration-tests/main/test-4/README.md rename to integration-tests/funcs/flowAllFeatures/README.md diff --git a/integration-tests/main/test-4/func.yaml b/integration-tests/funcs/flowAllFeatures/func.yaml similarity index 74% rename from integration-tests/main/test-4/func.yaml rename to integration-tests/funcs/flowAllFeatures/func.yaml index d7e5fee1..9a41741c 100644 --- a/integration-tests/main/test-4/func.yaml +++ b/integration-tests/funcs/flowAllFeatures/func.yaml @@ -1,9 +1,10 @@ -version: 0.0.13 +schema_version: 20180708 +name: flowallfeatures +version: 0.0.15 runtime: java cmd: com.fnproject.fn.integration.ExerciseEverything::handleRequest +format: http-stream +timeout: 120 build: - mvn package dependency:copy-dependencies -DincludeScope=runtime -DskipTests=true -Dmdep.prependGroupId=true -DoutputDirectory=target -format: http -timeout: 120 -name: test-4 diff --git a/integration-tests/main/test-4/pom.xml b/integration-tests/funcs/flowAllFeatures/pom.xml similarity index 85% rename from integration-tests/main/test-4/pom.xml rename to integration-tests/funcs/flowAllFeatures/pom.xml index fa753b39..55361cbb 100644 --- a/integration-tests/main/test-4/pom.xml +++ b/integration-tests/funcs/flowAllFeatures/pom.xml @@ -5,7 +5,7 @@ 4.0.0 UTF-8 - 1.0.0-SNAPSHOT + 1.0.0-SNAPSHOT com.fnproject.fn integration-test-4 @@ -17,23 +17,28 @@ com.fnproject.fn api - ${fnproject.version} + ${fdk.version} com.fnproject.fn runtime - ${fnproject.version} + ${fdk.version} + + + com.fnproject.fn + flow-runtime + ${fdk.version} com.fnproject.fn testing-core - ${fnproject.version} + ${fdk.version} com.fnproject.fn testing-junit4 - ${fnproject.version} + ${fdk.version} junit diff --git a/integration-tests/main/test-4/src/main/java/com/fnproject/fn/integration/ExerciseEverything.java b/integration-tests/funcs/flowAllFeatures/src/main/java/com/fnproject/fn/integration/ExerciseEverything.java similarity index 96% rename from integration-tests/main/test-4/src/main/java/com/fnproject/fn/integration/ExerciseEverything.java rename to integration-tests/funcs/flowAllFeatures/src/main/java/com/fnproject/fn/integration/ExerciseEverything.java index 2d1cff36..55d12da3 100644 --- a/integration-tests/main/test-4/src/main/java/com/fnproject/fn/integration/ExerciseEverything.java +++ b/integration-tests/funcs/flowAllFeatures/src/main/java/com/fnproject/fn/integration/ExerciseEverything.java @@ -1,8 +1,11 @@ package com.fnproject.fn.integration; +import com.fnproject.fn.api.FnFeature; import com.fnproject.fn.api.Headers; import com.fnproject.fn.api.InputEvent; +import com.fnproject.fn.api.RuntimeContext; import com.fnproject.fn.api.flow.*; +import com.fnproject.fn.runtime.flow.FlowFeature; import org.apache.commons.io.IOUtils; import org.apache.commons.io.output.TeeOutputStream; @@ -16,6 +19,7 @@ import java.util.stream.Collectors; @SuppressWarnings("unused") +@FnFeature(FlowFeature.class) public class ExerciseEverything { private boolean okay = true; @@ -24,6 +28,11 @@ public class ExerciseEverything { private String testSelector = null; private InputEvent inputEvent; private List failures = new ArrayList<>(); + private final RuntimeContext runtimeContext; + + public ExerciseEverything(RuntimeContext runtimeContext) { + this.runtimeContext = runtimeContext; + } @Test(1) @Test.Expect("completed value") @@ -134,7 +143,7 @@ public FlowFuture nonexistentExternalEvaluation(Flow fl) { @Test(12) @Test.Expect("okay") public FlowFuture checkPassingExternalInvocation(Flow fl) { - return fl.invokeFunction(inputEvent.getAppName() + inputEvent.getRoute(), HttpMethod.POST, Headers.emptyHeaders(), "PASS".getBytes()) + return fl.invokeFunction(runtimeContext.getFunctionID(), HttpMethod.POST, Headers.emptyHeaders(), "PASS".getBytes()) .thenApply((resp) -> resp.getStatusCode() != 200 ? "failure" : new String(resp.getBodyAsBytes())); } @@ -143,7 +152,7 @@ public FlowFuture checkPassingExternalInvocation(Flow fl) { @Test(13) @Test.Catch({FlowCompletionException.class, FunctionInvocationException.class}) public FlowFuture checkFailingExternalInvocation(Flow fl) { - return fl.invokeFunction(inputEvent.getAppName() + inputEvent.getRoute(), HttpMethod.POST, Headers.emptyHeaders(), "FAIL".getBytes()); + return fl.invokeFunction(runtimeContext.getFunctionID(), HttpMethod.POST, Headers.emptyHeaders(), "FAIL".getBytes()); } @Test(14) diff --git a/integration-tests/main/test-4/src/main/java/com/fnproject/fn/integration/Test.java b/integration-tests/funcs/flowAllFeatures/src/main/java/com/fnproject/fn/integration/Test.java similarity index 100% rename from integration-tests/main/test-4/src/main/java/com/fnproject/fn/integration/Test.java rename to integration-tests/funcs/flowAllFeatures/src/main/java/com/fnproject/fn/integration/Test.java diff --git a/integration-tests/main/test-1/func.yaml b/integration-tests/funcs/flowBasic/func.yaml similarity index 57% rename from integration-tests/main/test-1/func.yaml rename to integration-tests/funcs/flowBasic/func.yaml index 81f45b5c..6022a127 100644 --- a/integration-tests/main/test-1/func.yaml +++ b/integration-tests/funcs/flowBasic/func.yaml @@ -1,6 +1,7 @@ -name: test-1 -version: 0.0.5 +schema_version: 20180708 +name: flowbasic +version: 0.0.7 runtime: java cmd: com.fnproject.fn.integration.test_1.CompleterFunction::handleRequest -format: http +format: http-stream timeout: 120 diff --git a/integration-tests/main/test-1-jdk8/pom.xml b/integration-tests/funcs/flowBasic/pom.xml similarity index 72% rename from integration-tests/main/test-1-jdk8/pom.xml rename to integration-tests/funcs/flowBasic/pom.xml index 3d635ea1..6cac356e 100644 --- a/integration-tests/main/test-1-jdk8/pom.xml +++ b/integration-tests/funcs/flowBasic/pom.xml @@ -5,7 +5,7 @@ 4.0.0 UTF-8 - 1.0.0-SNAPSHOT + 1.0.0-SNAPSHOT com.fnproject.fn integration-test-1 @@ -17,26 +17,14 @@ com.fnproject.fn api - ${fnproject.version} + ${fdk.version} com.fnproject.fn - testing-core - ${fnproject.version} - test - - - com.fnproject.fn - testing-junit4 - ${fnproject.version} - test - - - junit - junit - 4.12 - test + flow-runtime + ${fdk.version} + diff --git a/integration-tests/main/test-1-jdk8/src/main/java/com/fnproject/fn/integration/test_1/CompleterFunction.java b/integration-tests/funcs/flowBasic/src/main/java/com/fnproject/fn/integration/test_1/CompleterFunction.java similarity index 76% rename from integration-tests/main/test-1-jdk8/src/main/java/com/fnproject/fn/integration/test_1/CompleterFunction.java rename to integration-tests/funcs/flowBasic/src/main/java/com/fnproject/fn/integration/test_1/CompleterFunction.java index edd04e86..0740d8ba 100644 --- a/integration-tests/main/test-1-jdk8/src/main/java/com/fnproject/fn/integration/test_1/CompleterFunction.java +++ b/integration-tests/funcs/flowBasic/src/main/java/com/fnproject/fn/integration/test_1/CompleterFunction.java @@ -1,8 +1,11 @@ package com.fnproject.fn.integration.test_1; +import com.fnproject.fn.api.FnFeature; import com.fnproject.fn.api.flow.Flow; +import com.fnproject.fn.runtime.flow.FlowFeature; import com.fnproject.fn.api.flow.Flows; +@FnFeature(FlowFeature.class) public class CompleterFunction { public Integer handleRequest(String input) { diff --git a/integration-tests/main/test-1-jdk8/func.yaml b/integration-tests/funcs/flowBasicJDK8/func.yaml similarity index 56% rename from integration-tests/main/test-1-jdk8/func.yaml rename to integration-tests/funcs/flowBasicJDK8/func.yaml index 43b2d3a1..143565c7 100644 --- a/integration-tests/main/test-1-jdk8/func.yaml +++ b/integration-tests/funcs/flowBasicJDK8/func.yaml @@ -1,6 +1,7 @@ -version: 0.0.1 +schema_version: 20180708 +name: flowbasicj8 +version: 0.0.3 runtime: java8 cmd: com.fnproject.fn.integration.test_1.CompleterFunction::handleRequest -format: http +format: http-stream timeout: 120 -name: test-1-jdk8 \ No newline at end of file diff --git a/integration-tests/main/test-1/pom.xml b/integration-tests/funcs/flowBasicJDK8/pom.xml similarity index 72% rename from integration-tests/main/test-1/pom.xml rename to integration-tests/funcs/flowBasicJDK8/pom.xml index 3d635ea1..e674247f 100644 --- a/integration-tests/main/test-1/pom.xml +++ b/integration-tests/funcs/flowBasicJDK8/pom.xml @@ -5,7 +5,7 @@ 4.0.0 UTF-8 - 1.0.0-SNAPSHOT + 1.0.0-SNAPSHOT com.fnproject.fn integration-test-1 @@ -17,25 +17,12 @@ com.fnproject.fn api - ${fnproject.version} + ${fdk.version} com.fnproject.fn - testing-core - ${fnproject.version} - test - - - com.fnproject.fn - testing-junit4 - ${fnproject.version} - test - - - junit - junit - 4.12 - test + flow-runtime + ${fdk.version} diff --git a/integration-tests/main/test-1/src/main/java/com/fnproject/fn/integration/test_1/CompleterFunction.java b/integration-tests/funcs/flowBasicJDK8/src/main/java/com/fnproject/fn/integration/test_1/CompleterFunction.java similarity index 76% rename from integration-tests/main/test-1/src/main/java/com/fnproject/fn/integration/test_1/CompleterFunction.java rename to integration-tests/funcs/flowBasicJDK8/src/main/java/com/fnproject/fn/integration/test_1/CompleterFunction.java index edd04e86..0740d8ba 100644 --- a/integration-tests/main/test-1/src/main/java/com/fnproject/fn/integration/test_1/CompleterFunction.java +++ b/integration-tests/funcs/flowBasicJDK8/src/main/java/com/fnproject/fn/integration/test_1/CompleterFunction.java @@ -1,8 +1,11 @@ package com.fnproject.fn.integration.test_1; +import com.fnproject.fn.api.FnFeature; import com.fnproject.fn.api.flow.Flow; +import com.fnproject.fn.runtime.flow.FlowFeature; import com.fnproject.fn.api.flow.Flows; +@FnFeature(FlowFeature.class) public class CompleterFunction { public Integer handleRequest(String input) { diff --git a/integration-tests/main/test-5/func.yaml b/integration-tests/funcs/flowExitHooks/func.yaml similarity index 56% rename from integration-tests/main/test-5/func.yaml rename to integration-tests/funcs/flowExitHooks/func.yaml index 1fa56725..2a0161e8 100644 --- a/integration-tests/main/test-5/func.yaml +++ b/integration-tests/funcs/flowExitHooks/func.yaml @@ -1,6 +1,7 @@ -version: 0.0.1 +schema_version: 20180708 +name: flowexithooks +version: 0.0.3 runtime: java9 cmd: com.fnproject.fn.integration.test_5.CompleterFunction::handleRequest -format: http +format: http-stream timeout: 120 -name: test-5 \ No newline at end of file diff --git a/integration-tests/main/test-5/pom.xml b/integration-tests/funcs/flowExitHooks/pom.xml similarity index 84% rename from integration-tests/main/test-5/pom.xml rename to integration-tests/funcs/flowExitHooks/pom.xml index 66d43389..2b9bc0f7 100644 --- a/integration-tests/main/test-5/pom.xml +++ b/integration-tests/funcs/flowExitHooks/pom.xml @@ -5,7 +5,7 @@ 4.0.0 UTF-8 - 1.0.0-SNAPSHOT + 1.0.0-SNAPSHOT com.fnproject.fn integration-test-5 @@ -17,18 +17,24 @@ com.fnproject.fn api - ${fnproject.version} + ${fdk.version} + + + com.fnproject.fn + flow-runtime + ${fdk.version} + compile com.fnproject.fn testing-core - ${fnproject.version} + ${fdk.version} test com.fnproject.fn testing-junit4 - ${fnproject.version} + ${fdk.version} test diff --git a/integration-tests/funcs/flowExitHooks/src/main/java/com/fnproject/fn/integration/test_5/CompleterFunction.java b/integration-tests/funcs/flowExitHooks/src/main/java/com/fnproject/fn/integration/test_5/CompleterFunction.java new file mode 100644 index 00000000..57c0c0ce --- /dev/null +++ b/integration-tests/funcs/flowExitHooks/src/main/java/com/fnproject/fn/integration/test_5/CompleterFunction.java @@ -0,0 +1,45 @@ +package com.fnproject.fn.integration.test_5; + +import com.fnproject.fn.api.FnFeature; +import com.fnproject.fn.api.RuntimeContext; +import com.fnproject.fn.api.flow.Flow; +import com.fnproject.fn.api.flow.Flows; +import com.fnproject.fn.runtime.flow.FlowFeature; + +import java.io.Serializable; +import java.net.HttpURLConnection; +import java.net.URI; +import java.net.URL; + +@FnFeature(FlowFeature.class) +public class CompleterFunction implements Serializable { + + private final URL callbackURL; + + public CompleterFunction(RuntimeContext rtc) throws Exception { + callbackURL = URI.create(rtc.getConfigurationByKey("TERMINATION_HOOK_URL").orElseThrow(() -> new RuntimeException("No config set "))).toURL(); + } + + public Integer handleRequest(String input) { + Flow fl = Flows.currentFlow(); + fl.addTerminationHook((ignored) -> { + try { + HttpURLConnection con = (HttpURLConnection) callbackURL.openConnection(); + + System.err.println("Ran the hook."); + + con.setRequestMethod("GET"); + if (con.getResponseCode() != 200) { + throw new RuntimeException("Got bad code from callback"); + } + } catch (Exception e) { + throw new RuntimeException(e); + } + + }); + return fl.supply(() -> { + return 42; + }).get(); + } + +} diff --git a/integration-tests/main/test-6/func.yaml b/integration-tests/funcs/flowTimeouts/func.yaml similarity index 56% rename from integration-tests/main/test-6/func.yaml rename to integration-tests/funcs/flowTimeouts/func.yaml index 0178652a..d8a91857 100644 --- a/integration-tests/main/test-6/func.yaml +++ b/integration-tests/funcs/flowTimeouts/func.yaml @@ -1,6 +1,7 @@ -version: 0.0.1 +schema_version: 20180708 +name: flowtimeouts +version: 0.0.3 runtime: java9 cmd: com.fnproject.fn.integration.test_6.CompleterFunction::handleRequest -format: http +format: http-stream timeout: 120 -name: test-6 \ No newline at end of file diff --git a/integration-tests/main/test-6/pom.xml b/integration-tests/funcs/flowTimeouts/pom.xml similarity index 85% rename from integration-tests/main/test-6/pom.xml rename to integration-tests/funcs/flowTimeouts/pom.xml index c6ea212b..011e9853 100644 --- a/integration-tests/main/test-6/pom.xml +++ b/integration-tests/funcs/flowTimeouts/pom.xml @@ -5,7 +5,7 @@ 4.0.0 UTF-8 - 1.0.0-SNAPSHOT + 1.0.0-SNAPSHOT com.fnproject.fn integration-test-6 @@ -17,18 +17,23 @@ com.fnproject.fn api - ${fnproject.version} + ${fdk.version} + + + com.fnproject.fn + flow-runtime + ${fdk.version} com.fnproject.fn testing-core - ${fnproject.version} + ${fdk.version} test com.fnproject.fn testing-junit4 - ${fnproject.version} + ${fdk.version} test diff --git a/integration-tests/main/test-6/src/main/java/com/fnproject/fn/integration/test_6/CompleterFunction.java b/integration-tests/funcs/flowTimeouts/src/main/java/com/fnproject/fn/integration/test_6/CompleterFunction.java similarity index 67% rename from integration-tests/main/test-6/src/main/java/com/fnproject/fn/integration/test_6/CompleterFunction.java rename to integration-tests/funcs/flowTimeouts/src/main/java/com/fnproject/fn/integration/test_6/CompleterFunction.java index 5041c8dc..bb603493 100644 --- a/integration-tests/main/test-6/src/main/java/com/fnproject/fn/integration/test_6/CompleterFunction.java +++ b/integration-tests/funcs/flowTimeouts/src/main/java/com/fnproject/fn/integration/test_6/CompleterFunction.java @@ -1,23 +1,26 @@ package com.fnproject.fn.integration.test_6; +import com.fnproject.fn.api.FnFeature; import com.fnproject.fn.api.flow.Flow; import com.fnproject.fn.api.flow.Flows; +import com.fnproject.fn.runtime.flow.FlowFeature; import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeoutException; + +@FnFeature(FlowFeature.class) public class CompleterFunction { - public Integer handleRequest(String input) { + public String handleRequest(String input) { Flow fl = Flows.currentFlow(); try { return fl.supply(() -> { Thread.sleep(10000); - return 42; + return "nope"; }).get(1000, TimeUnit.MILLISECONDS); } catch (TimeoutException t) { - System.err.println("Caught timeout"); - return 20; + return "timeout"; } } diff --git a/integration-tests/main/test-2/func.yaml b/integration-tests/funcs/simpleFunc/func.yaml similarity index 52% rename from integration-tests/main/test-2/func.yaml rename to integration-tests/funcs/simpleFunc/func.yaml index aec91b13..187a2f2f 100644 --- a/integration-tests/main/test-2/func.yaml +++ b/integration-tests/funcs/simpleFunc/func.yaml @@ -1,5 +1,6 @@ -name: test-2 -version: 0.0.1 +schema_version: 20180708 +name: simplefunc +version: 0.0.3 runtime: java9 cmd: com.fnproject.fn.integration.test2.PlainFunction::handleRequest -format: http +format: http-stream diff --git a/integration-tests/main/test-2/pom.xml b/integration-tests/funcs/simpleFunc/pom.xml similarity index 90% rename from integration-tests/main/test-2/pom.xml rename to integration-tests/funcs/simpleFunc/pom.xml index d37a302d..60e2ab1c 100644 --- a/integration-tests/main/test-2/pom.xml +++ b/integration-tests/funcs/simpleFunc/pom.xml @@ -5,7 +5,7 @@ 4.0.0 UTF-8 - 1.0.0-SNAPSHOT + 1.0.0-SNAPSHOT com.fnproject.fn integration-test-2 @@ -15,17 +15,17 @@ com.fnproject.fn api - ${fnproject.version} + ${fdk.version} com.fnproject.fn testing-core - ${fnproject.version} + ${fdk.version} com.fnproject.fn testing-junit4 - ${fnproject.version} + ${fdk.version} junit diff --git a/integration-tests/main/test-2/src/main/java/com/fnproject/fn/integration/test2/PlainFunction.java b/integration-tests/funcs/simpleFunc/src/main/java/com/fnproject/fn/integration/test2/PlainFunction.java similarity index 100% rename from integration-tests/main/test-2/src/main/java/com/fnproject/fn/integration/test2/PlainFunction.java rename to integration-tests/funcs/simpleFunc/src/main/java/com/fnproject/fn/integration/test2/PlainFunction.java diff --git a/integration-tests/main/test-2/src/test/java/com/fnproject/fn/integration/test2/PlainFunctionTest.java b/integration-tests/funcs/simpleFunc/src/test/java/com/fnproject/fn/integration/test2/PlainFunctionTest.java similarity index 100% rename from integration-tests/main/test-2/src/test/java/com/fnproject/fn/integration/test2/PlainFunctionTest.java rename to integration-tests/funcs/simpleFunc/src/test/java/com/fnproject/fn/integration/test2/PlainFunctionTest.java diff --git a/integration-tests/lib.sh b/integration-tests/lib.sh deleted file mode 100644 index 83c04b49..00000000 --- a/integration-tests/lib.sh +++ /dev/null @@ -1,48 +0,0 @@ -# Bash clean-up junk -- -typeset -a _deferrals -_on_exit() { - set +x - local idx - for (( idx=${#_deferrals[@]}-1 ; idx>=0 ; idx-- )) ; do - set -x - ${_deferrals[idx]} - set +x - done -} -defer() { - _deferrals+=("$*") -} -trap _on_exit EXIT TERM INT -# -- Bash clean-up junk - -wait_for_http() { - ( - set +ex - local i - for i in {1..15}; do - curl --connect-timeout 5 --max-time 2 "$1" && exit - sleep 1 - done - exit 1 - ) -} - -# prefix each line, whilst evaluating -- -prefix_lines() { - local prefix="$1" - local file="$2" - eval awk \''{print "'"$prefix"' " $0}'\' '<<-EOF'$'\n'"$(< "$file")"$'\n'EOF -} -# -- prefix each line, whilst evaluating - - -line() { - echo -------------------------------------------------------------------------------- -} - -error() { - echo "$1" 1>&2 - exit "${2:-1}" -} - -export SCRIPT_DIR="$( cd "$(dirname "$0")" && command pwd )" diff --git a/integration-tests/main/test-1-jdk8/config b/integration-tests/main/test-1-jdk8/config deleted file mode 100644 index a7c1a5a8..00000000 --- a/integration-tests/main/test-1-jdk8/config +++ /dev/null @@ -1 +0,0 @@ -COMPLETER_BASE_URL=${COMPLETER_BASE_URL} diff --git a/integration-tests/main/test-1-jdk8/expected b/integration-tests/main/test-1-jdk8/expected deleted file mode 100644 index 62f94575..00000000 --- a/integration-tests/main/test-1-jdk8/expected +++ /dev/null @@ -1 +0,0 @@ -6 \ No newline at end of file diff --git a/integration-tests/main/test-1-jdk8/input b/integration-tests/main/test-1-jdk8/input deleted file mode 100644 index 00750edc..00000000 --- a/integration-tests/main/test-1-jdk8/input +++ /dev/null @@ -1 +0,0 @@ -3 diff --git a/integration-tests/main/test-1/config b/integration-tests/main/test-1/config deleted file mode 100644 index a7c1a5a8..00000000 --- a/integration-tests/main/test-1/config +++ /dev/null @@ -1 +0,0 @@ -COMPLETER_BASE_URL=${COMPLETER_BASE_URL} diff --git a/integration-tests/main/test-1/expected b/integration-tests/main/test-1/expected deleted file mode 100644 index 62f94575..00000000 --- a/integration-tests/main/test-1/expected +++ /dev/null @@ -1 +0,0 @@ -6 \ No newline at end of file diff --git a/integration-tests/main/test-1/input b/integration-tests/main/test-1/input deleted file mode 100644 index 00750edc..00000000 --- a/integration-tests/main/test-1/input +++ /dev/null @@ -1 +0,0 @@ -3 diff --git a/integration-tests/main/test-2/config b/integration-tests/main/test-2/config deleted file mode 100644 index 5646b494..00000000 --- a/integration-tests/main/test-2/config +++ /dev/null @@ -1 +0,0 @@ -GREETING=Salutations diff --git a/integration-tests/main/test-2/expected b/integration-tests/main/test-2/expected deleted file mode 100644 index 4082c5fd..00000000 --- a/integration-tests/main/test-2/expected +++ /dev/null @@ -1 +0,0 @@ -Salutations, world! \ No newline at end of file diff --git a/integration-tests/main/test-2/input b/integration-tests/main/test-2/input deleted file mode 100644 index e69de29b..00000000 diff --git a/integration-tests/main/test-4/Dockerfile.custom b/integration-tests/main/test-4/Dockerfile.custom deleted file mode 100644 index e9077432..00000000 --- a/integration-tests/main/test-4/Dockerfile.custom +++ /dev/null @@ -1,4 +0,0 @@ -FROM fnproject/fn-java-fdk:jdk9-latest -WORKDIR /function -COPY target/*.jar /function/app/ -CMD ["com.fnproject.fn.integration.ExerciseEverything::handleRequest"] diff --git a/integration-tests/main/test-4/config b/integration-tests/main/test-4/config deleted file mode 100644 index a7c1a5a8..00000000 --- a/integration-tests/main/test-4/config +++ /dev/null @@ -1 +0,0 @@ -COMPLETER_BASE_URL=${COMPLETER_BASE_URL} diff --git a/integration-tests/main/test-4/expected.sh b/integration-tests/main/test-4/expected.sh deleted file mode 100755 index 1c081e44..00000000 --- a/integration-tests/main/test-4/expected.sh +++ /dev/null @@ -1,3 +0,0 @@ -#!/bin/bash - -tail actual | grep 'Everything worked' diff --git a/integration-tests/main/test-4/input b/integration-tests/main/test-4/input deleted file mode 100644 index 8b137891..00000000 --- a/integration-tests/main/test-4/input +++ /dev/null @@ -1 +0,0 @@ - diff --git a/integration-tests/main/test-4/pre-test.sh b/integration-tests/main/test-4/pre-test.sh deleted file mode 100755 index f6e539dc..00000000 --- a/integration-tests/main/test-4/pre-test.sh +++ /dev/null @@ -1,5 +0,0 @@ -#!/usr/bin/env bash - -set -ex - -cp Dockerfile.custom Dockerfile diff --git a/integration-tests/main/test-5/config b/integration-tests/main/test-5/config deleted file mode 100644 index a7c1a5a8..00000000 --- a/integration-tests/main/test-5/config +++ /dev/null @@ -1 +0,0 @@ -COMPLETER_BASE_URL=${COMPLETER_BASE_URL} diff --git a/integration-tests/main/test-5/expected.sh b/integration-tests/main/test-5/expected.sh deleted file mode 100755 index 432d3fb2..00000000 --- a/integration-tests/main/test-5/expected.sh +++ /dev/null @@ -1,39 +0,0 @@ -#!/bin/bash - -# Horrible bash checker... - -FOUND_FILENAME=`pwd`/success -rm -f "$FOUND_FILENAME" -ATTEMPT=0 -while [ ! -f "$FOUND_FILENAME" ] ; -do - sleep 1 - calls_found=`fn list calls "test-5" | grep "Status: success" | wc -l` - echo "$calls_found successful function calls found" - - # TODO: Remove this check when `fn logs` becomes reliable - if [[ -n `echo $calls_found | grep "3"` ]]; then - touch "$FOUND_FILENAME" - fi - - # TODO: Use this check instead when `fn logs` becomes reliable - # fn list calls "test-5" | while read k v - # do - # if [[ "$k" = "ID:" ]]; then id="$v"; fi - # if [[ -z "$k" ]]; then - # LOG=`fn get log "test-5" "$id"` - # echo $LOG - # if [[ $LOG == *"Ran the hook."* ]]; then - # touch "$FOUND_FILENAME" - # fi - # fi - # done - - ATTEMPT=$((ATTEMPT + 1)) - if [ $ATTEMPT -ge 120 ]; - then - # echo "Did not find termination hook output" - echo "Termination hook was not called or failed" - exit 1 - fi -done diff --git a/integration-tests/main/test-5/input b/integration-tests/main/test-5/input deleted file mode 100644 index e69de29b..00000000 diff --git a/integration-tests/main/test-5/src/main/java/com/fnproject/fn/integration/test_5/CompleterFunction.java b/integration-tests/main/test-5/src/main/java/com/fnproject/fn/integration/test_5/CompleterFunction.java deleted file mode 100644 index e4d2e3c7..00000000 --- a/integration-tests/main/test-5/src/main/java/com/fnproject/fn/integration/test_5/CompleterFunction.java +++ /dev/null @@ -1,14 +0,0 @@ -package com.fnproject.fn.integration.test_5; - -import com.fnproject.fn.api.flow.Flow; -import com.fnproject.fn.api.flow.Flows; - -public class CompleterFunction { - - public Integer handleRequest(String input) { - Flow fl = Flows.currentFlow(); - fl.addTerminationHook( (ignored) -> { System.err.println("Ran the hook."); }); - return fl.supply(() -> { Thread.sleep(1000); return 42; }).get(); - } - -} diff --git a/integration-tests/main/test-6/config b/integration-tests/main/test-6/config deleted file mode 100644 index a7c1a5a8..00000000 --- a/integration-tests/main/test-6/config +++ /dev/null @@ -1 +0,0 @@ -COMPLETER_BASE_URL=${COMPLETER_BASE_URL} diff --git a/integration-tests/main/test-6/expected.sh b/integration-tests/main/test-6/expected.sh deleted file mode 100755 index 0c45fa98..00000000 --- a/integration-tests/main/test-6/expected.sh +++ /dev/null @@ -1,32 +0,0 @@ -#!/bin/bash - -# Horrible bash checker... - -FOUND_FILENAME=`pwd`/success -rm -f "$FOUND_FILENAME" -ATTEMPT=0 -while [ ! -f "$FOUND_FILENAME" ] ; -do - sleep 1 - calls_found=`fn list calls "test-6" | grep "Status: success" | wc -l` - echo "$calls_found successful function calls found" - - fn list calls "test-6" | while read k v - do - if [[ "$k" = "ID:" ]]; then id="$v"; fi - if [[ -z "$k" ]]; then - LOG=`fn get log "test-6" "$id"` - echo $LOG - if [[ $LOG == *"Caught timeout"* ]]; then - touch "$FOUND_FILENAME" - fi - fi - done - - ATTEMPT=$((ATTEMPT + 1)) - if [ $ATTEMPT -ge 120 ]; - then - echo "Did not find expected output" - exit 1 - fi -done diff --git a/integration-tests/main/test-6/input b/integration-tests/main/test-6/input deleted file mode 100644 index e69de29b..00000000 diff --git a/integration-tests/pom.xml b/integration-tests/pom.xml index 30588095..803e5221 100644 --- a/integration-tests/pom.xml +++ b/integration-tests/pom.xml @@ -3,21 +3,43 @@ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> - - com.fnproject.fn - fdk - 1.0.0-SNAPSHOT - 4.0.0 com.fnproject.flow integration-tests + 1.0.0-SNAPSHOT + jar - pom + + + commons-io + commons-io + 2.5 + + + junit + junit + 4.12 + + + org.assertj + assertj-core + 3.6.2 + + + + org.apache.maven.plugins + maven-compiler-plugin + 3.8.0 + + 1.8 + 1.8 + + org.apache.maven.plugins maven-deploy-plugin diff --git a/integration-tests/post-configure-hook.sh b/integration-tests/post-configure-hook.sh deleted file mode 100755 index a81dbd98..00000000 --- a/integration-tests/post-configure-hook.sh +++ /dev/null @@ -1,18 +0,0 @@ -#!/bin/bash - -# This hook runs in the test directory immediately prior to any "fn build" invocation. - -# Turn these lines in func.yaml: - -# name: jbloggs/fn-flows-function -# version: 0.0.1 - -# into these: - -# name: docker-registry:5000/jbloggs/fn-flows-function -# version: 4837492387439724389 <- whatever suffix is. - -set -ex - -docker push $(awk '/^name:/ { print $2 }' func.yaml):$SUFFIX -mv .func.yaml-old func.yaml diff --git a/integration-tests/pre-build-hook.sh b/integration-tests/pre-build-hook.sh deleted file mode 100755 index 1eb1d178..00000000 --- a/integration-tests/pre-build-hook.sh +++ /dev/null @@ -1,31 +0,0 @@ -#!/bin/bash - -# This hook runs in the test directory immediately prior to any "fn build" invocation. - -# Turn these lines in func.yaml: - -# name: jbloggs/fn-flow-function -# version: 0.0.1 - -# into these: - -# name: docker-registry:5000/jbloggs/fn-flow-function -# version: 4837492387439724389 <- whatever suffix is. - -set -e - -while read key rest -do - case "$key" in - name:) - rest="docker-registry:5000/$rest" - ;; - version:) - rest="$SUFFIX" - ;; - esac - echo "$key $rest" -done < func.yaml > .func.yaml-new - -mv func.yaml .func.yaml-old -mv .func.yaml-new func.yaml diff --git a/integration-tests/run-all-tests.sh b/integration-tests/run-all-tests.sh deleted file mode 100755 index d39bf820..00000000 --- a/integration-tests/run-all-tests.sh +++ /dev/null @@ -1,99 +0,0 @@ -#!/bin/bash - -# Run all smoke-tests in parallel, recording their output. -# Report the results on any failures. - -source "$SCRIPT_DIR/lib.sh" - -set -ex - -# ---------------------------------------------------------------------- -# The following variables need to be set -# ---------------------------------------------------------------------- - -# This is an awful bashism -if [[ -z "${FN_API_URL+x}" ]]; then echo "Please set FN_API_URL"; exit 1; fi -if [[ -z "${COMPLETER_BASE_URL+x}" ]]; then echo "Please set COMPLETER_BASE_URL"; exit 1; fi - - -# ---------------------------------------------------------------------- -# Run each smoke-test in parallel -# ---------------------------------------------------------------------- - -fn list apps - -set +x - -SMOKE_HARNESS="$SCRIPT_DIR/smoke-test.sh" -export LIBFUNS="$SCRIPT_DIR/lib.sh" -export FN_TOKEN -export no_proxy=$no_proxy,127.0.0.1,10.167.103.241 - -cd "$SCRIPT_DIR" - -if [[ $# = 0 ]]; then - tests=main/test-* - show= - background='> "$d/output" 2>&1 &' -else - tests=$(find "$@" -type d -name test-\* -prune) - show='set -x' - background= -fi - -echo "Running tests: $tests" - -eval "$show" -for d in $tests -do - - rm -f "$d"/actual "$d"/output - eval "( - # Run the integration test - - cd \"$d\" && \"$SMOKE_HARNESS\" - ) $background" - -done -wait -set +x - - -# ---------------------------------------------------------------------- -# Report on results sequentially -# ---------------------------------------------------------------------- - -okay=1 -report() { - echo "Test $(basename "$1") expected -" - cat "$1/expected" - echo "Test $(basename "$1") actual -" - cat "$1/actual" - echo "Test $(basename "$1") output -" - cat "$1/output" - line -} - -for d in $tests -do - set +e - - if [[ -f "$d/failure" ]]; then - okay=0 - line - echo "Test $(basename "$d") failed:" - report "$d" - elif [[ -f "$d/success" ]]; then - line - echo "Test $(basename "$d") succeeded" - line - else - okay=0 - line - echo "**************** Test $(basename "$d") unknown status" - report "$d" - fi -done - -[[ $okay = 1 ]] || exit 1 -echo Success! diff --git a/integration-tests/run-local.sh b/integration-tests/run-local.sh deleted file mode 100755 index ec73332e..00000000 --- a/integration-tests/run-local.sh +++ /dev/null @@ -1,139 +0,0 @@ -#!/usr/bin/env bash - -# Set up a local test environment in order to run integration tests, -# then execute them. - -source "$(dirname "$0")/lib.sh" - -set -ex - -# ---------------------------------------------------------------------- -# The following variables may be set to parameterise the operation of this script -# ---------------------------------------------------------------------- - -: ${FUNCTIONS_DOCKER_IMAGE:=fnproject/fnserver} -: ${SUFFIX:=$(git rev-parse HEAD)} -: ${COMPLETER_DOCKER_IMAGE:=fnproject/flow} - -# ---------------------------------------------------------------------- -# Stand up a local staging maven directory, if needed -# ---------------------------------------------------------------------- - -if [[ -n "$REPOSITORY_LOCATION" ]]; then - REPO_CONTAINER_ID=$( - docker run -d \ - -v "$REPOSITORY_LOCATION":/repo:ro \ - -w /repo \ - --name repo-$SUFFIX \ - python:2.7 \ - python -mSimpleHTTPServer 18080 - ) - defer docker rm -f $REPO_CONTAINER_ID - REPO_INTERNAL_IP=$( - docker inspect \ - --type container \ - -f '{{range .NetworkSettings.Networks}}{{.IPAddress}}{{end}}' \ - $REPO_CONTAINER_ID - ) - export MAVEN_REPOSITORY_LOCATION="http://$REPO_INTERNAL_IP:18080" - export no_proxy="$no_proxy,$REPO_INTERNAL_IP" -fi - -# ---------------------------------------------------------------------- -# Stand up the functions platform -# ---------------------------------------------------------------------- - -docker pull $FUNCTIONS_DOCKER_IMAGE - -FUNCTIONS_CONTAINER_ID=$( - docker run -d \ - -p 8080:8080 \ - -v /var/run/docker.sock:/var/run/docker.sock \ - --name functions-$SUFFIX \ - -e FN_LOG_LEVEL=debug \ - $FUNCTIONS_DOCKER_IMAGE - ) -defer docker rm -f $FUNCTIONS_CONTAINER_ID -defer docker logs functions-$SUFFIX -defer echo ---- FUNCTIONS OUTPUT FOR TEST ----------------------------------------------------------- - -FUNCTIONS_HOST=$( - docker inspect \ - --type container \ - -f '{{range index .NetworkSettings.Ports "8080/tcp"}}{{.HostIp}}{{end}}' \ - $FUNCTIONS_CONTAINER_ID - ) - -FUNCTIONS_PORT=$( - docker inspect \ - --type container \ - -f '{{range index .NetworkSettings.Ports "8080/tcp"}}{{.HostPort}}{{end}}' \ - $FUNCTIONS_CONTAINER_ID - ) - -FUNCTIONS_INTERNAL_IP=$( - docker inspect \ - --type container \ - -f '{{range .NetworkSettings.Networks}}{{.IPAddress}}{{end}}' \ - $FUNCTIONS_CONTAINER_ID - ) - -export FN_API_URL="http://$FUNCTIONS_HOST:$FUNCTIONS_PORT" -export no_proxy="$no_proxy,$FUNCTIONS_HOST" - - -# ---------------------------------------------------------------------- -# Stand up the completer -# ---------------------------------------------------------------------- - -COMPLETER_CONTAINER_ID=$( - docker run -d \ - -p 8081 \ - --env API_URL=http://${FUNCTIONS_INTERNAL_IP}:8080 \ - --env no_proxy=$no_proxy,${FUNCTIONS_INTERNAL_IP} \ - --name flow-server-$SUFFIX \ - $COMPLETER_DOCKER_IMAGE - ) -defer docker rm -f $COMPLETER_CONTAINER_ID -defer docker logs $COMPLETER_CONTAINER_ID -defer echo ---- COMPLETER OUTPUT FOR TEST ----------------------------------------------------------- - -COMPLETER_HOST=$( - docker inspect \ - --type container \ - -f '{{range index .NetworkSettings.Ports "8081/tcp"}}{{.HostIp}}{{end}}' \ - $COMPLETER_CONTAINER_ID - ) - -COMPLETER_PORT=$( - docker inspect \ - --type container \ - -f '{{range index .NetworkSettings.Ports "8081/tcp"}}{{.HostPort}}{{end}}' \ - $COMPLETER_CONTAINER_ID - ) - -COMPLETER_INTERNAL_IP=$( - docker inspect \ - --type container \ - -f '{{range .NetworkSettings.Networks}}{{.IPAddress}}{{end}}' \ - $COMPLETER_CONTAINER_ID - ) - -export COMPLETER_BASE_URL=http://$COMPLETER_INTERNAL_IP:8081 -export no_proxy="$no_proxy,$COMPLETER_HOST" - - -# ---------------------------------------------------------------------- -# Wait for the containers to become ready -# ---------------------------------------------------------------------- - -export HTTP_PROXY="$http_proxy" -export HTTPS_PROXY="$https_proxy" -export NO_PROXY="$no_proxy" - -wait_for_http "$FN_API_URL" -wait_for_http "http://$COMPLETER_HOST:$COMPLETER_PORT/ping" - -set +x - -"$SCRIPT_DIR/run-all-tests.sh" "$@" diff --git a/integration-tests/run-remote.sh b/integration-tests/run-remote.sh deleted file mode 100755 index 69a1ac4f..00000000 --- a/integration-tests/run-remote.sh +++ /dev/null @@ -1,39 +0,0 @@ -#!/usr/bin/env bash - -# Set up a local test environment in order to run integration tests, -# then execute them. - -source "$(dirname "$0")/lib.sh" - -set -ex - -# ---------------------------------------------------------------------- -# The following variables may be set to parameterise the operation of this script -# ---------------------------------------------------------------------- - -export SUFFIX=$(git rev-parse HEAD) -export FN_TOKEN=${FN_TOKEN:-$(cat ~/.fn-token)} - - -# ---------------------------------------------------------------------- -# The following variables should be set in the integration environment -# ---------------------------------------------------------------------- - -export FN_API_URL=$(cat ~/.fn-api-url) -export COMPLETER_BASE_URL=$(cat ~/.fn-flow-base-url) - - -# We need to push our images into the test environment, so let's ensure that our tunnel is set up -systemctl --user restart ssh-tunnels - -# Ensure we have the hooks we want in place -export PRE_BUILD_HOOK="$SCRIPT_DIR/pre-build-hook.sh" -export POST_CONFIGURE_HOOK="$SCRIPT_DIR/post-configure-hook.sh" - -export HTTP_PROXY="$http_proxy" -export HTTPS_PROXY="$https_proxy" -export NO_PROXY="$no_proxy" - -set +x - -"$SCRIPT_DIR/run-all-tests.sh" "$@" diff --git a/integration-tests/run_tests_ci.sh b/integration-tests/run_tests_ci.sh new file mode 100755 index 00000000..940c28ff --- /dev/null +++ b/integration-tests/run_tests_ci.sh @@ -0,0 +1,94 @@ +#!/usr/bin/env bash +set -e +set -x + + +cd $(dirname $0) + +if [ -z ${REPOSITORY_LOCATION} ]; then + echo no REPOSITORY_LOCATION is specified in env - you need to deploy fn jars to a local dir + exit 1 +fi + + +docker rm -f fn_mvn_repo || true +docker run -d \ + -v "$REPOSITORY_LOCATION":/repo:ro \ + -w /repo -p18080:18080 \ + --name fn_mvn_repo \ + python:2.7 \ + python -mSimpleHTTPServer 18080 + + +until $(curl --output /dev/null --silent --fail http://localhost:18080); do + printf '.' + sleep 1 +done + + +# Start Fn +fn stop || true +fn start --log-level=debug -d + +until $(curl --output /dev/null --silent --fail http://localhost:8080/); do + printf '.' + sleep 1 +done + + +export FN_LOG_FILE=/tmp/fn.log +docker logs -f fnserver >& ${FN_LOG_FILE} & + +FNSERVER_IP=$(docker inspect --type container -f '{{.NetworkSettings.IPAddress}}' fnserver) + + + +docker rm -f flowserver || true +docker run --rm -d \ + -p 8081:8081 \ + -e API_URL="http://${FNSERVER_IP}:8080/invoke" \ + -e no_proxy=${FNSERVER_IP} \ + --name flowserver \ + fnproject/flow:latest + +until $(curl --output /dev/null --silent --fail http://localhost:8081/ping); do + printf '.' + sleep 1 +done +export FLOW_LOG_FILE=/tmp/flow.log + +docker logs -f flowserver >& ${FLOW_LOG_FILE} & +set +e + + +if [ $(uname -s) == "Darwin" ] ; then + DOCKER_LOCALHOST=docker.for.mac.host.internal +else + DOCKER_LOCALHOST=$(ifconfig eth0| grep -Eo 'inet (addr:)?([0-9]*\.){3}[0-9]*' | grep -Eo '([0-9]*\.){3}[0-9]*' | grep -v '127.0.0.1') +fi + +export DOCKER_LOCALHOST + +REPO_IP=$(docker inspect --type container -f '{{.NetworkSettings.IPAddress}}' fn_mvn_repo) +MAVEN_REPOSITORY="http://${REPO_IP}:18080" +export MAVEN_REPOSITORY +COMPLETER_IP=$(docker inspect --type container -f '{{.NetworkSettings.IPAddress}}' flowserver) +COMPLETER_BASE_URL="http://${COMPLETER_IP}:8081" +export COMPLETER_BASE_URL + +export no_proxy="${no_proxy},${DOCKER_LOCALHOST},${COMPLETER_IP},${REPO_IP}" + + + + +echo "Running tests" +mvn test +result=$? + + + +docker rm -f flowserver +docker rm -f fnserver +docker rm -rf fn_mvn_repo + +exit $result diff --git a/integration-tests/smoke-test.sh b/integration-tests/smoke-test.sh deleted file mode 100755 index f0152f21..00000000 --- a/integration-tests/smoke-test.sh +++ /dev/null @@ -1,95 +0,0 @@ -#!/bin/bash - -. "$LIBFUNS" - -# Run an individual smoketest - -# Environmental requirements: -# - cwd is the directory of the smoketest to run -# - LIBFUNS points to the shell helper library -# - up-to-date "fn" command on the PATH -# - FN_TOKEN is set to something that the functions platform will approve -# - FN_API_URL points to the functions platform endpoint -# - any http_proxy, etc. settings are correct to permit access to that endpoint and any maven repos required by fn build -# - COMPLETER_BASE_URL is set to a value that should be configured on the target function -# - MAVEN_REPOSITORY_LOCATION, if set, corresponds to the URL that should be replaced in the test pom files. -# - the runtime docker image is up-to-date - -rm -f success failure Dockerfile -export TESTNAME="$(basename $(pwd))" -set -ex - -if [ -f pre-test.sh ]; then - ./pre-test.sh -fi - -# Replace the maven repo with a staging location, if required -if [ -n "$MAVEN_REPOSITORY_LOCATION" ]; then - sed -i.bak \ - -e "s|https://dl.bintray.com/fnproject/fnproject|$MAVEN_REPOSITORY_LOCATION|g" \ - pom.xml - rm pom.xml.bak -fi - -# Build the integration test - -[[ -n "$PRE_BUILD_HOOK" ]] && $PRE_BUILD_HOOK - -fn -v build --no-cache >build-output 2>&1 || { - echo "Test function build failed:" - cat build-output - exit 1 -} - -if [ -f config ]; then - fn create app "$TESTNAME" $(echo $(prefix_lines --config config)) -else - fn create app "$TESTNAME" -fi - -if [[ -x deploy.sh ]] -then - ./deploy.sh -else - fn deploy --app "$TESTNAME" --local -fi - -[[ -n "$POST_CONFIGURE_HOOK" ]] && $POST_CONFIGURE_HOOK - -fn inspect app "$TESTNAME" -[[ -x route-create.sh ]] || fn inspect route "$TESTNAME" "$TESTNAME" - -if [[ -x run-test.sh ]] -then - ./run-test.sh -else - curl -v "$FN_API_URL/r/$TESTNAME/$TESTNAME" -d @input > actual -fi - -if [[ -x expected.sh ]] -then - ./expected.sh && touch success || touch failure -else - diff --ignore-all-space -u expected actual && touch success || touch failure -fi - -set +x -fn list calls "$TESTNAME" | while read k v -do - echo "$k $v" - if [[ "$k" = "ID:" ]]; then id="$v"; fi - if [[ -z "$k" ]]; then - echo '[[[' - fn get log "$TESTNAME" "$id" - echo ']]]' - echo - fi -done - -set -x - -if [[ -x delete.sh ]] -then - ./delete.sh -fi -fn delete app "$TESTNAME" diff --git a/integration-tests/src/main/java/com/fnproject/fn/integrationtest/IntegrationTestRule.java b/integration-tests/src/main/java/com/fnproject/fn/integrationtest/IntegrationTestRule.java new file mode 100644 index 00000000..19370b38 --- /dev/null +++ b/integration-tests/src/main/java/com/fnproject/fn/integrationtest/IntegrationTestRule.java @@ -0,0 +1,347 @@ +package com.fnproject.fn.integrationtest; + +import org.apache.commons.io.FileUtils; +import org.apache.commons.io.input.Tailer; +import org.apache.commons.io.input.TailerListenerAdapter; +import org.assertj.core.api.Assertions; +import org.junit.rules.TestRule; +import org.junit.runner.Description; +import org.junit.runners.model.Statement; + +import java.io.BufferedReader; +import java.io.File; +import java.io.IOException; +import java.io.InputStreamReader; +import java.nio.charset.StandardCharsets; +import java.nio.file.Files; +import java.nio.file.Path; +import java.util.*; +import java.util.concurrent.CompletableFuture; +import java.util.concurrent.TimeUnit; + +/** + * Wrapper around fn cli to invoke function integration tests. + * Created on 14/09/2018. + *

+ * (c) 2018 Oracle Corporation + */ +public class IntegrationTestRule implements TestRule { + + + private static final String repoPlaceholder = "https://dl.bintray.com/fnproject/fnproject"; + private static final String versionPlaceholder = "1.0.0-SNAPSHOT"; + private static final String snapshotPlaceholderRegex = ".*"; + private int appCount = 0; + private String testName; + + + private final List cleanupDirs = new ArrayList<>(); + private final List cleanupApps = new ArrayList<>(); + + public String getFlowURL() { + String url = System.getenv("COMPLETER_BASE_URL"); + if (url == null) { + return "http://" + getDockerLocalhost() + ":8081"; + } + return url; + } + + /** + * Returns a hostname tha resolves to the test host from within a docker container + */ + public String getDockerLocalhost() { + String dockerLocalhost = System.getenv("DOCKER_LOCALHOST"); + if (dockerLocalhost == null) { + String osName = System.getProperty("os.name", "generic").toLowerCase(Locale.ENGLISH); + + if (osName.contains("darwin") || osName.contains("mac")) { + return "docker.for.mac.host.internal"; + } else + throw new RuntimeException("Unable to determine docker localhost address - set 'DOCKER_LOCALHOST' env variable to the docker host network address "); + } + return dockerLocalhost; + } + + private String getLocalFnRepo() { + String envRepo = System.getenv("MAVEN_REPOSITORY"); + if (envRepo == null) { + envRepo = "http://" + getDockerLocalhost() + ":18080"; + } + return envRepo; + } + + + private String getProjectVersion() { + String version = System.getenv("FN_JAVA_FDK_VERSION"); + + if (version == null) { + version = "1.0.0-SNAPSHOT"; + } + return version; + } + + private String getFnLogFile() { + return System.getenv("FN_LOG_FILE"); + } + + private String getFlowLogFile() { + return System.getenv("FLOW_LOG_FILE"); + } + + private String getFnCmd() { + String cmd = System.getenv("FN_CMD"); + if (cmd == null) { + return "fn"; + } + return cmd; + } + + + public static class CmdResult { + private final String cmd; + private final boolean success; + private final String stdout; + private final String stderr; + + private CmdResult(String cmd, boolean success, String stdout, String stderr) { + this.success = success; + this.stdout = stdout; + this.stderr = stderr; + this.cmd = cmd; + } + + boolean isSuccess() { + return success; + + } + + public String getStdout() { + return stdout; + } + + public String getStderr() { + return stderr; + } + + + } + + public class TestContext { + + private File baseDir; + private final String testName; + + public TestContext(File baseDir, String testName) { + this.baseDir = baseDir; + this.testName = testName; + } + + /** + * Copies the contents of a given directory (relative to test root) into the temporary test directory + * + * @param location local directory + * @return + * @throws IOException + */ + public TestContext withDirFrom(String location) throws IOException { + FileUtils.copyDirectory(new File(location), baseDir); + return this; + } + + public CmdResult runFnWithInput(String input, String... args) throws Exception { + CmdResult res = runFnWithInputAllowError(input, args); + + Assertions.assertThat(res.isSuccess()).withFailMessage("Expected command '" + res.cmd + "' to return 0").isTrue(); + return res; + } + + /** + * Runs the configured Fn command with input returning a process result + * + * @param input the input string ot pass as fn stdin + * @param args args to fn (excluding the fn command itself) + * @return a command result to get the result of a command + * @throws Exception + */ + public CmdResult runFnWithInputAllowError(String input, String... args) throws Exception { + List cmd = new ArrayList<>(); + cmd.add(getFnCmd()); + cmd.addAll(Arrays.asList(args)); + + System.err.println("Running '" + String.join(" ", cmd) + "'"); + ProcessBuilder pb = new ProcessBuilder(cmd); + pb.directory(baseDir); + + if (System.getenv("FN_JAVA_FDK_VERSION") == null) { + // this means that FN init will pick up the local version not the latest. + pb.environment().put("FN_JAVA_FDK_VERSION", "1.0.0-SNAPSHOT"); + } + + // Sort of a hack for local mac running with a proxy + String noProxy = Optional.ofNullable(System.getenv("no_proxy")).map((f) -> f + ",").orElse("") + getDockerLocalhost(); + System.err.printf("setting no_proxy '%s'\n",noProxy); + pb.environment().put("no_proxy", noProxy); + + Process p = pb.start(); + + + p.getOutputStream().write(input.getBytes()); + p.getOutputStream().close(); + + + CompletableFuture stderr = new CompletableFuture<>(); + + new Thread(() -> { + + try { + BufferedReader bri = new BufferedReader + (new InputStreamReader(p.getErrorStream())); + + StringBuilder output = new StringBuilder(); + String line; + while ((line = bri.readLine()) != null) { + System.err.println("FN ERR: " + line); + output.append(line); + } + stderr.complete(output.toString()); + } catch (IOException e) { + stderr.completeExceptionally(e); + } + }).start(); + + BufferedReader bri = new BufferedReader + (new InputStreamReader(p.getInputStream())); + + StringBuilder output = new StringBuilder(); + String line; + while ((line = bri.readLine()) != null) { + System.err.println("FN OUT: " + line); + output.append(line); + } + p.waitFor(600, TimeUnit.SECONDS); + System.err.println("Command '" + String.join(" ", cmd) + "' with code " + p.exitValue()); + + return new CmdResult(String.join(" ", cmd), p.exitValue() == 0, output.toString(), stderr.get()); + } + + /** + * Runs the configure `fn` command with given arguments fails if the command returns without succes + * + * @param args + * @return a command result capturinng the output of fn + * @throws Exception + */ + public CmdResult runFn(String... args) throws Exception { + return runFnWithInput("", args); + } + + + /** + * Rewrites the POM to reflect the correct target repo + */ + public TestContext rewritePOM() throws Exception { + File pomFile = new File(baseDir, "pom.xml"); + + String pomFileContent = FileUtils.readFileToString(pomFile, StandardCharsets.UTF_8); + String newPomContent = pomFileContent.replace(repoPlaceholder, "" + getLocalFnRepo() + ""); + Assertions.assertThat(newPomContent).withFailMessage("No placeholder found in POM").isNotEqualTo(pomFileContent); + + String versionPomContent = newPomContent.replace(versionPlaceholder, "" + getProjectVersion() + ""); + + versionPomContent = versionPomContent.replaceFirst(snapshotPlaceholderRegex, "true"); + + System.err.println(versionPomContent); + FileUtils.writeStringToFile(pomFile, versionPomContent, StandardCharsets.UTF_8); + return this; + } + + + /** + * Gets the app name you should use for tests. + * + * @return + */ + public String appName() { + return this.testName; + } + + public TestContext mkdir(String name) { + new File(baseDir, name).mkdir(); + return this; + } + + public TestContext cd(String dir) { + baseDir = new File(baseDir, dir); + return this; + } + } + + + /** + * creates a new test contesxt + * + * @return + * @throws IOException + */ + public TestContext newTest() throws IOException { + Path tmpDir = Files.createTempDirectory("fnitest"); + cleanupDirs.add(tmpDir.toFile()); + String appName = testName + appCount++; + cleanupApps.add(appName); + return new TestContext(tmpDir.toFile(), appName); + } + + + @Override + public Statement apply(Statement statement, Description description) { + + return new Statement() { + @Override + public void evaluate() throws Throwable { + testName = description.getMethodName(); + StringBuilder fnOutput = new StringBuilder(); + StringBuilder flowOutput = new StringBuilder(); + + Tailer fnTailer = null; + if (getFnLogFile() != null) { + fnTailer = Tailer.create(new File(getFnLogFile()), new TailerListenerAdapter() { + @Override + public void handle(final String line) { + System.err.println("FNSRV:" + line); + fnOutput.append(line); + } + }, 10, true); + } + + Tailer flowTailer = null; + + if (getFlowLogFile() != null) { + flowTailer = Tailer.create(new File(getFlowLogFile()), new TailerListenerAdapter() { + @Override + public void handle(final String line) { + System.err.println("FLOW:" + line); + fnOutput.append(line); + } + }, 10, true); + } + + try { + statement.evaluate(); + } finally { + + for (File cleanup : cleanupDirs) { + FileUtils.deleteDirectory(cleanup); + } + + if (fnTailer != null) { + fnTailer.stop(); + } + + if (flowTailer != null) { + flowTailer.stop(); + } + } + } + }; + } +} diff --git a/integration-tests/src/test/java/com/fnproject/fn/integrationtest/FlowTest.java b/integration-tests/src/test/java/com/fnproject/fn/integrationtest/FlowTest.java new file mode 100644 index 00000000..09733c24 --- /dev/null +++ b/integration-tests/src/test/java/com/fnproject/fn/integrationtest/FlowTest.java @@ -0,0 +1,101 @@ +package com.fnproject.fn.integrationtest; + +import com.fnproject.fn.integrationtest.IntegrationTestRule.CmdResult; +import com.sun.net.httpserver.HttpServer; +import org.junit.Rule; +import org.junit.Test; + +import java.net.InetSocketAddress; +import java.util.concurrent.CompletableFuture; +import java.util.concurrent.TimeUnit; + +import static org.assertj.core.api.Assertions.assertThat; + +/** + * Created on 14/09/2018. + *

+ * (c) 2018 Oracle Corporation + */ +public class FlowTest { + + @Rule + public final IntegrationTestRule testRule = new IntegrationTestRule(); + + + @Test + public void shouldInvokeBasicFlow() throws Exception { + IntegrationTestRule.TestContext tc = testRule.newTest(); + tc.withDirFrom("funcs/flowBasic").rewritePOM(); + tc.runFn("--verbose", "deploy", "--app", tc.appName(), "--local"); + tc.runFn("config", "app", tc.appName(), "COMPLETER_BASE_URL", testRule.getFlowURL()); + CmdResult r = tc.runFnWithInput("1", "invoke", tc.appName(), "flowbasic"); + assertThat(r.getStdout()).isEqualTo("4"); + } + + + @Test + public void shouldInvokeBasicFlowJDK8() throws Exception { + IntegrationTestRule.TestContext tc = testRule.newTest(); + tc.withDirFrom("funcs/flowBasicJDK8").rewritePOM(); + tc.runFn("--verbose", "deploy", "--app", tc.appName(), "--local"); + tc.runFn("config", "app", tc.appName(), "COMPLETER_BASE_URL", testRule.getFlowURL()); + CmdResult r = tc.runFnWithInput("1", "invoke", tc.appName(), "flowbasicj8"); + assertThat(r.getStdout()).isEqualTo("4"); + } + + + @Test + public void shouldExerciseAllFlow() throws Exception { + IntegrationTestRule.TestContext tc = testRule.newTest(); + tc.withDirFrom("funcs/flowAllFeatures").rewritePOM(); + tc.runFn("--verbose", "deploy", "--app", tc.appName(), "--local"); + tc.runFn("config", "app", tc.appName(), "COMPLETER_BASE_URL", testRule.getFlowURL()); + CmdResult r = tc.runFnWithInput("1", "invoke", tc.appName(), "flowallfeatures"); + assertThat(r.getStdout()).contains("Everything worked"); + } + + + @Test + public void shouldCallExitHooks() throws Exception { + CompletableFuture done = new CompletableFuture<>(); + + HttpServer server = HttpServer.create(new InetSocketAddress(8000), 0); + server.createContext("/exited", httpExchange -> { + done.complete(true); + String resp = "ok"; + httpExchange.sendResponseHeaders(200, resp.length()); + httpExchange.getResponseBody().write(resp.getBytes()); + httpExchange.getResponseBody().close(); + }); + server.setExecutor(null); // creates a default executor + server.start(); + try { + IntegrationTestRule.TestContext tc = testRule.newTest(); + tc.withDirFrom("funcs/flowExitHooks").rewritePOM(); + tc.runFn("--verbose", "build", "--no-cache"); + + tc.runFn("--verbose", "deploy", "--app", tc.appName(), "--local"); + tc.runFn("config", "app", tc.appName(), "COMPLETER_BASE_URL", testRule.getFlowURL()); + tc.runFn("config", "app", tc.appName(), "TERMINATION_HOOK_URL", "http://" + testRule.getDockerLocalhost() + ":" + 8000 + "/exited"); + CmdResult r = tc.runFnWithInput("1", "invoke", tc.appName(), "flowexithooks"); + assertThat(r.getStdout()).contains("42"); + + assertThat(done.get(10, TimeUnit.SECONDS)).withFailMessage("Expected callback within 10 seconds").isTrue(); + + } finally { + server.stop(0); + } + } + + + @Test + public void shouldHandleTimeouts() throws Exception { + IntegrationTestRule.TestContext tc = testRule.newTest(); + tc.withDirFrom("funcs/flowTimeouts").rewritePOM(); + tc.runFn("--verbose", "deploy", "--app", tc.appName(), "--local"); + tc.runFn("config", "app", tc.appName(), "COMPLETER_BASE_URL", testRule.getFlowURL()); + CmdResult r = tc.runFn("invoke", tc.appName(), "flowtimeouts"); + assertThat(r.getStdout()).contains("timeout"); + } + +} diff --git a/integration-tests/src/test/java/com/fnproject/fn/integrationtest/FunctionsTest.java b/integration-tests/src/test/java/com/fnproject/fn/integrationtest/FunctionsTest.java new file mode 100644 index 00000000..8f1860ee --- /dev/null +++ b/integration-tests/src/test/java/com/fnproject/fn/integrationtest/FunctionsTest.java @@ -0,0 +1,54 @@ +package com.fnproject.fn.integrationtest; + +import com.fnproject.fn.integrationtest.IntegrationTestRule.CmdResult; +import org.junit.Rule; +import org.junit.Test; + +import static org.assertj.core.api.Assertions.assertThat; + +/** + * Created on 14/09/2018. + *

+ * (c) 2018 Oracle Corporation + */ +public class FunctionsTest { + + @Rule + public final IntegrationTestRule testRule = new IntegrationTestRule(); + + + @Test + public void shouldCallExistingFn() throws Exception { + IntegrationTestRule.TestContext tc = testRule.newTest(); + tc.withDirFrom("funcs/simpleFunc").rewritePOM(); + + tc.runFn("--verbose", "deploy", "--app", tc.appName(), "--local"); + tc.runFn("config", "app", tc.appName(), "GREETING", "Salutations"); + + + CmdResult r1 = tc.runFnWithInput("", "invoke", tc.appName(), "simplefunc"); + assertThat(r1.getStdout()).isEqualTo("Salutations, world!"); + + + CmdResult r2 = tc.runFnWithInput("tests", "invoke", tc.appName(), "simplefunc"); + assertThat(r2.getStdout()).isEqualTo("Salutations, tests!"); + + } + + @Test() + public void checkBoilerPlate() throws Exception { + for (String format : new String[]{"default", "http", "http-stream"}) { + for (String runtime : new String[]{"java9", "java8"}) { + IntegrationTestRule.TestContext tc = testRule.newTest(); + String fnName = "bp" + format + runtime; + + tc.runFn("init", "--runtime", runtime, "--name", fnName,"--format", format); + tc.rewritePOM(); + tc.runFn("--verbose", "deploy", "--app", tc.appName(), "--local"); + CmdResult rs = tc.runFnWithInput("wibble", "invoke", tc.appName(), fnName); + assertThat(rs.getStdout()).contains("Hello, wibble!"); + } + } + } + +} diff --git a/pom.xml b/pom.xml index 40aecf46..f17f58c0 100644 --- a/pom.xml +++ b/pom.xml @@ -2,272 +2,279 @@ - 4.0.0 + 4.0.0 - fdk - com.fnproject.fn - pom - 1.0.0-SNAPSHOT + fdk + com.fnproject.fn + pom + 1.0.0-SNAPSHOT - - api - runtime - testing-core - testing-junit4 - testing - integration-tests + + api + runtime + testing-core + testing-junit4 + testing + flow-api + flow-runtime + flow-testing + fn-spring-cloud-function + examples - fn-spring-cloud-function - examples - + - - UTF-8 - UTF-8 + + UTF-8 + UTF-8 - - 0.8.1 - 4.12 - 2.21.0 - 3.10.0 - 1.4.0 + 9.4.11.v20180605 + + 0.8.1 + 4.12 + 2.21.0 + 3.10.0 + 1.4.0 - 1.7.25 + 1.7.25 - 2.6 - 2.9.6 - 4.4.10 + 2.6 + 2.9.6 + 4.4.10 - 1.16.0 - + 1.16.0 + - - - - - - com.fnproject.fn - api - ${project.version} - - - com.fnproject.fn - runtime - ${project.version} - - - com.fnproject.fn - testing-core - ${project.version} - - - com.fnproject.fn - testing-junit4 - ${project.version} - + + - - com.fasterxml.jackson.core - jackson-databind - ${jackson.version} - - - org.apache.httpcomponents - httpcore - ${httpcore.version} - - - org.apache.httpcomponents - httpmime - 4.5.6 - - - commons-io - commons-io - ${commons-io.version} - - - commons-logging - commons-logging - 1.2 - - - net.jodah - typetools - 0.5.0 - + + + com.fnproject.fn + api + ${project.version} + + + com.fnproject.fn + flow-api + ${project.version} + + + com.fnproject.fn + flow-runtime + ${project.version} + + + com.fnproject.fn + runtime + ${project.version} + + + com.fnproject.fn + testing + ${project.version} + + + com.fnproject.fn + testing-core + ${project.version} + + + com.fnproject.fn + testing-junit4 + ${project.version} + - - org.mockito - mockito-core - ${mockito.version} - test - - - org.assertj - assertj-core - ${assertj-core.version} - test - - - junit - junit - ${junit.version} - test - + + com.fasterxml.jackson.core + jackson-databind + ${jackson.version} + + + org.apache.httpcomponents + httpcore + ${httpcore.version} + + + org.apache.httpcomponents + httpmime + 4.5.6 + + + commons-io + commons-io + ${commons-io.version} + + + commons-logging + commons-logging + 1.2 + + + net.jodah + typetools + 0.5.0 + - - - - - junit - junit - test - - - org.assertj - assertj-core - test - - + + org.mockito + mockito-core + ${mockito.version} + test + + + org.assertj + assertj-core + ${assertj-core.version} + test + + + junit + junit + ${junit.version} + test + - - - - - org.apache.maven.plugins - maven-javadoc-plugin - 3.0.1 - - - org.apache.maven.plugins - maven-deploy-plugin - 2.8.2 - - - maven-dependency-plugin - 3.1.1 - - - org.netbeans.tools - sigtest-maven-plugin - 1.0 - - - org.pitest - pitest-maven - ${pitest.version} - - - - - - org.apache.maven.plugins - maven-compiler-plugin - 3.8.0 - - javac-with-errorprone - true - 1.8 - 1.8 - - - - org.codehaus.plexus - plexus-compiler-javac-errorprone - 2.8.4 - - - com.google.errorprone - error_prone_core - 2.3.1 - - - - org.apache.maven.plugins - maven-source-plugin - 3.0.1 - - - attach-sources - - jar - - - - - - org.jacoco - jacoco-maven-plugin - ${jacoco.version} - - - prepare-agent - - prepare-agent - - - - report - prepare-package - - report - - - - post-unit-test - test - - report - - - + - target/jacoco.exec - - target/jacoco-ut - - - - - - org.pitest - pitest-maven - ${pitest.version} - + + + + + org.apache.maven.plugins + maven-javadoc-plugin + 3.0.1 + + + org.apache.maven.plugins + maven-deploy-plugin + 2.8.2 + + + maven-dependency-plugin + 3.1.1 + + + org.netbeans.tools + sigtest-maven-plugin + 1.0 + + + org.pitest + pitest-maven + ${pitest.version} + + + + + + org.apache.maven.plugins + maven-compiler-plugin + 3.8.0 + + javac-with-errorprone + true + 1.8 + 1.8 + + + + org.codehaus.plexus + plexus-compiler-javac-errorprone + 2.8.4 + + + com.google.errorprone + error_prone_core + 2.3.1 + + + + + org.apache.maven.plugins + maven-source-plugin + 3.0.1 + + + attach-sources + + jar + + + + + + org.jacoco + jacoco-maven-plugin + ${jacoco.version} + + + prepare-agent + + prepare-agent + + + + report + prepare-package + + report + + + + post-unit-test + test + + report + + + - - - - com.spotify - dockerfile-maven-extension - 1.4.3 - - - + target/jacoco.exec + + target/jacoco-ut + + + + + + org.pitest + pitest-maven + ${pitest.version} + - - - _qm-qs - - false - - - - - org.codehaus.mojo - versions-maven-plugin - 2.5 - - - - + + + com.spotify + dockerfile-maven-extension + 1.4.3 + + + + + + + + _qm-qs + + false + + + + + org.codehaus.mojo + versions-maven-plugin + 2.5 + + + + + diff --git a/runtime/Dockerfile b/runtime/Dockerfile index cb69e29e..e2fdc392 100644 --- a/runtime/Dockerfile +++ b/runtime/Dockerfile @@ -1,5 +1,6 @@ FROM openjdk:8-slim COPY target/runtime-*.jar target/dependency/*.jar /function/runtime/ +COPY src/main/c/libfnunixsocket.so /function/runtime/lib/ RUN ["/usr/lib/jvm/java-8-openjdk-amd64/jre/bin/java", "-Xshare:dump"] @@ -15,4 +16,4 @@ RUN ["/usr/lib/jvm/java-8-openjdk-amd64/jre/bin/java", "-Xshare:dump"] # # The max memory value obtained with these args seem to be okay for most memory limits. The exception is when the # memory limit is set to 128MiB, in which case maxMemory returns roughly half. -ENTRYPOINT [ "/usr/lib/jvm/java-8-openjdk-amd64/jre/bin/java", "-XX:+UnlockExperimentalVMOptions", "-XX:+UseCGroupMemoryLimitForHeap", "-XX:MaxRAMFraction=2", "-XX:+UseSerialGC", "-Xshare:on", "-cp", "/function/app/*:/function/runtime/*", "com.fnproject.fn.runtime.EntryPoint" ] +ENTRYPOINT [ "/usr/lib/jvm/java-8-openjdk-amd64/jre/bin/java", "-XX:+UnlockExperimentalVMOptions", "-XX:+UseCGroupMemoryLimitForHeap", "-XX:-UsePerfData", "-XX:MaxRAMFraction=2", "-XX:+UseSerialGC", "-Xshare:on", "-Djava.library.path=/function/runtime/lib", "-cp", "/function/app/*:/function/runtime/*", "com.fnproject.fn.runtime.EntryPoint" ] diff --git a/runtime/Dockerfile-jdk9 b/runtime/Dockerfile-jdk9 index 886bebc6..09364524 100644 --- a/runtime/Dockerfile-jdk9 +++ b/runtime/Dockerfile-jdk9 @@ -1,5 +1,6 @@ FROM openjdk:9-slim COPY target/runtime-*.jar target/dependency/*.jar /function/runtime/ +COPY src/main/c/libfnunixsocket.so /function/runtime/lib/ RUN ["/usr/bin/java", "-Xshare:dump"] @@ -15,4 +16,5 @@ RUN ["/usr/bin/java", "-Xshare:dump"] # # The max memory value obtained with these args seem to be okay for most memory limits. The exception is when the # memory limit is set to 128MiB, in which case maxMemory returns roughly half. -ENTRYPOINT [ "/usr/bin/java", "-XX:+UnlockExperimentalVMOptions", "-XX:+UseCGroupMemoryLimitForHeap", "-XX:MaxRAMFraction=2", "-XX:+UseSerialGC", "-Xshare:on", "-cp", "/function/app/*:/function/runtime/*", "com.fnproject.fn.runtime.EntryPoint" ] +ENTRYPOINT [ "/usr/bin/java", "-XX:+UnlockExperimentalVMOptions", "-XX:+UseCGroupMemoryLimitForHeap", "-XX:MaxRAMFraction=2","-XX:-UsePerfData", "-XX:+UseSerialGC", "-Xshare:on", \ + "-Djava.library.path=/function/runtime/lib", "-cp", "/function/app/*:/function/runtime/*", "com.fnproject.fn.runtime.EntryPoint" ] diff --git a/runtime/pom.xml b/runtime/pom.xml index f02159c9..dca46c91 100644 --- a/runtime/pom.xml +++ b/runtime/pom.xml @@ -25,6 +25,7 @@ httpcore + commons-io commons-io @@ -40,6 +41,12 @@ mockito-core test + + junit + junit + test + + org.assertj assertj-core @@ -50,6 +57,20 @@ httpmime test + + org.eclipse.jetty + jetty-client + ${jetty.version} + test + + + + org.eclipse.jetty + jetty-unixsocket + ${jetty.version} + test + + diff --git a/runtime/src/main/c/.gitignore b/runtime/src/main/c/.gitignore new file mode 100644 index 00000000..417eb980 --- /dev/null +++ b/runtime/src/main/c/.gitignore @@ -0,0 +1,4 @@ +build/ +libfnunixsocket.so +libfnunixsocket.dylib +cmake-build-debug diff --git a/runtime/src/main/c/CMakeLists.txt b/runtime/src/main/c/CMakeLists.txt new file mode 100644 index 00000000..8d2746a7 --- /dev/null +++ b/runtime/src/main/c/CMakeLists.txt @@ -0,0 +1,10 @@ +cmake_minimum_required(VERSION 2.8) +project(fnunixsocket) +set(CMAKE_BUILD_TYPE Release) +find_package(JNI REQUIRED) +include_directories(${JNI_INCLUDE_DIRS}) +set(CMAKE_C_STANDARD 11) +set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wall") + + +add_library(fnunixsocket SHARED unix_socket.c) diff --git a/runtime/src/main/c/Dockerfile-buildimage b/runtime/src/main/c/Dockerfile-buildimage new file mode 100644 index 00000000..7cd37f95 --- /dev/null +++ b/runtime/src/main/c/Dockerfile-buildimage @@ -0,0 +1,8 @@ +FROM oraclelinux:7.5 + +RUN yum install -y gcc cmake java-1.8.0-openjdk-devel.x86_64 make +RUN yum install -y gcc-c++ + +RUN mkdir /build +WORKDIR /build + diff --git a/runtime/src/main/c/README.md b/runtime/src/main/c/README.md new file mode 100644 index 00000000..7e4efe65 --- /dev/null +++ b/runtime/src/main/c/README.md @@ -0,0 +1,19 @@ +# Native components for Fn unix socket protocol + +This is a very simple JNI binding to expose unix sockets to the Fn runtime + +## Building + +you can rebuild a linux version (for the FDK itself) of the JNI library using `./rebuild_so.sh` this runs `buildit.sh` in a suitable docker container + +For testing on a mac you can also compile locally by running `buildit.sh`, you will need at least: + +* XCode compiler toolchain +* cmake +* make +* a JDK installed (for cmake JNI) + + +Current issues: +* This is using old-style JNI array passing which is slow - it should be using native buffers +* Doesn't support non-blocking operations, specifically reads and writes which will block indefinitely \ No newline at end of file diff --git a/runtime/src/main/c/buildit.sh b/runtime/src/main/c/buildit.sh new file mode 100755 index 00000000..3e9df64b --- /dev/null +++ b/runtime/src/main/c/buildit.sh @@ -0,0 +1,14 @@ +#!/usr/bin/env bash +set -e + +src_dir=$(pwd) +build_dir=$src_dir/build/$(uname -s| tr '[:upper:]' '[:lower:]') + +mkdir -p $build_dir +( + cd $build_dir + cmake $src_dir + + make +) +mv $build_dir/libfnunixsocket.* $src_dir \ No newline at end of file diff --git a/runtime/src/main/c/rebuild_so.sh b/runtime/src/main/c/rebuild_so.sh new file mode 100755 index 00000000..114fcc82 --- /dev/null +++ b/runtime/src/main/c/rebuild_so.sh @@ -0,0 +1,10 @@ +#!/usr/bin/env bash + + +mydir=$(cd "$(dirname "$0")"; pwd) +cd $mydir + +set -e +docker build -t fdk_c_build -f Dockerfile-buildimage . + +docker run -v $(pwd):/build fdk_c_build ./buildit.sh diff --git a/runtime/src/main/c/unix_socket.c b/runtime/src/main/c/unix_socket.c new file mode 100644 index 00000000..9d3e4408 --- /dev/null +++ b/runtime/src/main/c/unix_socket.c @@ -0,0 +1,521 @@ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/** + * Throws com.fnproject.fn.runtime.ntv.UnixSocetException, adding strerr(errno) as the second arg if that is set + * @param jenv java env + * @param message message to send + */ +void throwIOException(JNIEnv *jenv, const char *message) { + jclass exc = (*jenv)->FindClass(jenv, + "com/fnproject/fn/runtime/ntv/UnixSocketException"); + if (exc == NULL) { // JVM exception + return; + } + jmethodID constr = (*jenv)->GetMethodID(jenv, exc, "", + "(Ljava/lang/String;Ljava/lang/String;)V"); + + if (constr == NULL) { // JVM exception + return; + } + jstring str = (*jenv)->NewStringUTF(jenv, message); + if (str == NULL) { // JVM exception + return; + } + jstring estr = (*jenv)->NewStringUTF(jenv, strerror(errno)); + if (estr == NULL) { // JVM exception + return; + } + jthrowable t = (jthrowable) (*jenv)->NewObject(jenv, exc, constr, str, estr); + if (t == NULL) { // JVM exception + return; + } + (*jenv)->Throw(jenv, t); +} + + +/** + * Throws a single-arg string exception + * @param jenv + * @param clazz class path (e.g. "java/lang/NullPointerException" + * @param message message to pass into constructor + */ +void throwSingleArgStringException(JNIEnv *jenv, const char *clazz, const char *message) { + jclass exc = (*jenv)->FindClass(jenv, clazz); + if (exc == NULL) { + return; + } + jmethodID constr = (*jenv)->GetMethodID(jenv, exc, "", + "(Ljava/lang/String;)V"); + if (constr == NULL) { // JVM exception + return; + } + jstring str = (*jenv)->NewStringUTF(jenv, message); + if (str == NULL) { // JVM OOM + return; + } + jthrowable t = (jthrowable) (*jenv)->NewObject(jenv, exc, constr, str); + if (t == NULL) { // JVM error + return; + } + (*jenv)->Throw(jenv, t); +} + +void throwIllegalArgumentException(JNIEnv *jenv, const char *message) { + throwSingleArgStringException(jenv, "java/lang/IllegalArgumentException", message); +} + + +void throwSocketTimeoutException(JNIEnv *jenv, const char *message) { + throwSingleArgStringException(jenv, "java/net/SocketTimeoutException", message); +} + + +void throwNPE(JNIEnv *jenv, const char *message) { + throwSingleArgStringException(jenv, "java/lang/NullPointerException", message); +} + + + +// public static native int createSocket(); +JNIEXPORT jint JNICALL +Java_com_fnproject_fn_runtime_ntv_UnixSocketNative_socket(JNIEnv *jenv, jclass jClass) { + errno = 0; + int rv = socket(PF_UNIX, SOCK_STREAM, 0); + + if (rv == -1) { + throwIOException(jenv, "Could not create socket"); + return -1; + } + + return rv; +} + + + +// public static native int bind(int socket, String path) +JNIEXPORT void JNICALL +Java_com_fnproject_fn_runtime_ntv_UnixSocketNative_bind(JNIEnv *jenv, jclass jClass, jint jsocket, jstring jpath) { + errno = 0; + + struct sockaddr_un addr; + bzero(&addr, sizeof(struct sockaddr_un)); + + addr.sun_family = AF_UNIX; + + const char *nativePath = (*jenv)->GetStringUTFChars(jenv, jpath, 0); + if (nativePath == NULL) { // JVM OOM + return; + } + + if (strlen(nativePath) >= sizeof(addr.sun_path)) { + (*jenv)->ReleaseStringUTFChars(jenv, jpath, nativePath); + throwIllegalArgumentException(jenv, "Path too long"); + return; + } + + strncpy(addr.sun_path, nativePath, sizeof(addr.sun_path)); + (*jenv)->ReleaseStringUTFChars(jenv, jpath, nativePath); + + if (bind(jsocket, (struct sockaddr *) &addr, sizeof(addr)) < 0) { + throwIOException(jenv, "Error in bind"); + return; + } +} + +// public static native void connect(int socket, String path) throws UnixSocketException; +JNIEXPORT void JNICALL +Java_com_fnproject_fn_runtime_ntv_UnixSocketNative_connect(JNIEnv *jenv, jclass jClass, jint jsocket, jstring jpath) { + errno = 0; + + + struct sockaddr_un addr; + bzero(&addr, sizeof(struct sockaddr_un)); + addr.sun_family = AF_UNIX; + + const char *nativePath = (*jenv)->GetStringUTFChars(jenv, jpath, 0); + if (nativePath == NULL) {// JVM OOM + return; + } + + if (strlen(nativePath) >= sizeof(addr.sun_path)) { + (*jenv)->ReleaseStringUTFChars(jenv, jpath, nativePath); + throwIllegalArgumentException(jenv, "Path too long"); + return; + } + + strncpy(addr.sun_path, nativePath, sizeof(addr.sun_path)); + (*jenv)->ReleaseStringUTFChars(jenv, jpath, nativePath); + + if (connect(jsocket, (struct sockaddr *) &addr, sizeof(addr)) < 0) { + if (errno == ETIMEDOUT) { + throwSocketTimeoutException(jenv, "Socket connect timed out"); + return; + } + throwIOException(jenv, "Error in bind"); + return; + } +} + +// public static native void listen(int socket, int backlog); +JNIEXPORT void JNICALL +Java_com_fnproject_fn_runtime_ntv_UnixSocketNative_listen(JNIEnv *jenv, jclass jClass, jint jsocket, jint jbacklog) { + errno = 0; + + if (listen(jsocket, jbacklog) < 0) { + throwIOException(jenv, "Error in listen"); + return; + } +} + + + +// public static native int accept(int socket, long timeoutMs) throws UnixSocketException; +// returns 0 in case that the accept timed out +JNIEXPORT jint JNICALL +Java_com_fnproject_fn_runtime_ntv_UnixSocketNative_accept(JNIEnv *jenv, jclass jClass, jint jsocket, jlong timeoutMs) { + errno = 0; + + if (timeoutMs < 0) { + throwIllegalArgumentException(jenv, "Invalid timeout"); + return -1; + } + + struct timeval startTime; + + if (gettimeofday(&startTime, NULL) < 0) { + throwIOException(jenv, "Failed to get time"); + return -1; + } + + struct timeval timeoutAbs; + timeoutAbs.tv_sec = timeoutMs / 1000; + timeoutAbs.tv_usec = (int) (timeoutMs % 1000) * 1000; + + + int rv; + + struct timeval *toPtr = NULL; + struct timeval actualTo; + + + do { + + if (timeoutMs > 0) { + struct timeval nowTime, used; + if (gettimeofday(&nowTime, NULL) < 0) { + throwIOException(jenv, "Failed to get time"); + return -1; + } + + timersub(&nowTime, &startTime, &used); + timersub(&timeoutAbs, &used, &actualTo); + if (actualTo.tv_sec < 0 || (actualTo.tv_sec == 0 && actualTo.tv_usec ==0) ) { + // hit end of poll in loop + return 0; + + } + toPtr = &actualTo; + } + + fd_set set; + FD_ZERO(&set); /* clear the set */ + FD_SET(jsocket, &set); /* add our file descriptor to the set */ + + rv = select(jsocket + 1, &set, NULL, NULL, toPtr); + } while (rv == -1 && errno == EINTR); + + if (rv < 0) { + throwIOException(jenv, "Error in select"); + return -1; + } else if (rv == 0) { + return 0; // timeout + } + + struct sockaddr_un addr; + bzero(&addr, sizeof(struct sockaddr_un)); + socklen_t rlen; + int result; + do { + result = accept(jsocket, (struct sockaddr *) &addr, &rlen); + } while (result == -1 && errno == EINTR); + + if (result < 0) { + throwIOException(jenv, "Error in accept"); + } + return result; +} + + + +// public static native int recv(int socket, byte[] buffer, jint offset, jint length) throws UnixSocketException; +JNIEXPORT jint JNICALL +Java_com_fnproject_fn_runtime_ntv_UnixSocketNative_recv(JNIEnv *jenv, jclass jClass, jint jsocket, jbyteArray jbuf, + jint offset, jint length) { + errno = 0; + + if (offset < 0 || length <= 0) { + throwIllegalArgumentException(jenv, "Invalid offset, length"); + return -1; + } + + if (jbuf == NULL) { + throwNPE(jenv, "buffer is null"); + return -1; + } + + jint bufLen = (*jenv)->GetArrayLength(jenv, jbuf); + + if (offset >= bufLen) { + throwIllegalArgumentException(jenv, "Invalid offset, beyond end of buffer"); + return -1; + } + if (length > (bufLen - offset)) { + length = bufLen - offset; + } + + + jbyte *buf = (*jenv)->GetByteArrayElements(jenv, jbuf, NULL); + if (buf == NULL) { + return -1; + } + + + ssize_t rcount; + + do { + rcount = read(jsocket, &(buf[offset]), (size_t) length); + } while (rcount == -1 && errno == EINTR); + + (*jenv)->ReleaseByteArrayElements(jenv, jbuf, buf, 0); + + + if (rcount == 0) { + return -1; + } else if (rcount < 0) { + if (errno == EAGAIN) { + throwSocketTimeoutException(jenv, "Timeout reading from socket"); + return -1; + } + throwIOException(jenv, "Error reading from socket"); + return -1; + } + return (jint) rcount; + +} + + +// public static native int send(int socket, byte[] buffer) throws UnixSocketException; +JNIEXPORT jint JNICALL +Java_com_fnproject_fn_runtime_ntv_UnixSocketNative_send(JNIEnv *jenv, jclass jClass, jint jsocket, jbyteArray jbuf, + jint offset, jint length) { + errno = 0; + + if (offset < 0 || length <= 0) { + throwIllegalArgumentException(jenv, "Invalid offset, length or timeout"); + return -1; + } + + if (jbuf == NULL) { + throwNPE(jenv, "buffer is null"); + return -1; + } + + jint bufLen = (*jenv)->GetArrayLength(jenv, jbuf); + + + if ((offset >= bufLen) || (length > (bufLen - offset))) { + throwIllegalArgumentException(jenv, "Invalid offset or length, beyond end of buffer"); + return -1; + } + + + jbyte *buf = (*jenv)->GetByteArrayElements(jenv, jbuf, NULL); + if (buf == NULL) { // JVM OOM + return -1; + } + ssize_t wcount; + do { + wcount = write(jsocket, &(buf[offset]), (size_t) length); + } while (wcount == -1 && errno == EINTR); + + + (*jenv)->ReleaseByteArrayElements(jenv, jbuf, buf, 0); + + if (wcount < 0) { + if (errno == EAGAIN) { + throwSocketTimeoutException(jenv, "Timeout writing to socket"); + return -1; + } + throwIOException(jenv, "Error reading from socket"); + return -1; + } + + return (jint) wcount; + +} + + + + +// public static native close(int socket); + +JNIEXPORT void JNICALL +Java_com_fnproject_fn_runtime_ntv_UnixSocketNative_close(JNIEnv *jenv, jclass jClass, jint jsocket) { + errno = 0; + + if (close(jsocket) < 0) { + throwIOException(jenv, "Error in closing socket"); + return; + } +} + + +JNIEXPORT void JNICALL +Java_com_fnproject_fn_runtime_ntv_UnixSocketNative_setSendBufSize(JNIEnv *jenv, jclass jClass, jint socket, + jint bufsize) { + errno = 0; + if (bufsize <= 0) { + throwIllegalArgumentException(jenv, "Invalid buffer size"); + return; + } + + int rv = setsockopt(socket, SOL_SOCKET, SO_SNDBUF, &bufsize, sizeof(jint)); + if (rv < 0) { + throwIOException(jenv, "Error setting socket options"); + return; + } +} + +JNIEXPORT void JNICALL +Java_com_fnproject_fn_runtime_ntv_UnixSocketNative_setRecvBufSize(JNIEnv *jenv, jclass jClass, jint socket, + jint bufsize) { + errno = 0; + if (bufsize <= 0) { + throwIllegalArgumentException(jenv, "invalid buffer size"); + return; + } + + int rv = setsockopt(socket, SOL_SOCKET, SO_RCVBUF, &bufsize, sizeof(jint)); + if (rv < 0) { + throwIOException(jenv, "Error setting socket options"); + return; + } +} + +JNIEXPORT void JNICALL +Java_com_fnproject_fn_runtime_ntv_UnixSocketNative_setSendTimeout(JNIEnv *jenv, jclass jClass, jint socket, + jint timeout) { + errno = 0; + if (timeout < 0) { + throwIllegalArgumentException(jenv, "invalid timeout"); + return; + } + + struct timeval tv; + tv.tv_sec = timeout / 1000; + tv.tv_usec = (timeout % 1000) * 1000; + + int rv = setsockopt(socket, SOL_SOCKET, SO_SNDTIMEO, &tv, sizeof(struct timeval)); + if (rv < 0) { + throwIOException(jenv, "Error setting socket options"); + return; + } +} + + +JNIEXPORT jint JNICALL +Java_com_fnproject_fn_runtime_ntv_UnixSocketNative_getSendTimeout(JNIEnv *jenv, jclass jClass, jint socket) { + errno = 0; + + struct timeval tv; + bzero(&tv, sizeof(struct timeval)); + socklen_t len; + + int rv = getsockopt(socket, SOL_SOCKET, SO_SNDTIMEO, &tv, &len); + if (rv < 0) { + throwIOException(jenv, "Error setting socket options"); + return -1; + } + time_t msecs = tv.tv_sec * 1000 + tv.tv_usec / 1000; + if (msecs > INT_MAX) { + return (jint) INT_MAX; + } + return (jint) msecs; +} + + +JNIEXPORT void JNICALL +Java_com_fnproject_fn_runtime_ntv_UnixSocketNative_setRecvTimeout(JNIEnv *jenv, jclass jClass, jint socket, + jint timeout) { + errno = 0; + if (timeout < 0) { + throwIllegalArgumentException(jenv, "Invalid timeout"); + return; + } + + struct timeval tv; + tv.tv_sec = timeout / 1000; + tv.tv_usec = (timeout % 1000) * 1000; + + int rv = setsockopt(socket, SOL_SOCKET, SO_RCVTIMEO, &tv, sizeof(struct timeval)); + if (rv < 0) { + throwIOException(jenv, "Error setting socket options"); + return; + } +} + + +JNIEXPORT jint JNICALL +Java_com_fnproject_fn_runtime_ntv_UnixSocketNative_getRecvTimeout(JNIEnv *jenv, jclass jClass, jint socket) { + errno = 0; + + struct timeval tv; + bzero(&tv, sizeof(struct timeval)); + socklen_t len; + + int rv = getsockopt(socket, SOL_SOCKET, SO_RCVTIMEO, &tv, &len); + if (rv < 0) { + throwIOException(jenv, "Error setting socket options"); + return -1; + } + time_t msecs = tv.tv_sec * 1000 + tv.tv_usec / 1000; + if (msecs > INT_MAX) { + return (jint) INT_MAX; + } + return (jint) msecs; +} + + +// public static native void shutdown(int socket, boolean input, boolean output) ; +JNIEXPORT void JNICALL +Java_com_fnproject_fn_runtime_ntv_UnixSocketNative_shutdown(JNIEnv *jenv, jclass jClass, jint socket, jboolean input, + jboolean output) { + errno = 0; + int how; + + if (input && output) { + how = SHUT_RDWR; + } else if (input) { + how = SHUT_RD; + } else if (output) { + how = SHUT_WR; + } else { + return; + } + + int rv = shutdown(socket, how); + if (rv < 0) { + throwIOException(jenv, "Failed to shut down socket "); + return; + } +} diff --git a/runtime/src/main/java/com/fnproject/fn/runtime/DefaultEventCodec.java b/runtime/src/main/java/com/fnproject/fn/runtime/DefaultEventCodec.java index 090c0c9c..b0a5d41d 100644 --- a/runtime/src/main/java/com/fnproject/fn/runtime/DefaultEventCodec.java +++ b/runtime/src/main/java/com/fnproject/fn/runtime/DefaultEventCodec.java @@ -9,14 +9,18 @@ import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; +import java.time.Instant; +import java.time.format.DateTimeParseException; +import java.time.temporal.ChronoUnit; import java.util.HashMap; import java.util.Map; -import java.util.Optional; /** * DefaultEventCodec handles plain docker invocations on functions *

* This parses inputs from environment variables and reads and writes raw body and responses to the specified input and output streams + * + * @deprecated all new functions should use {@link HTTPStreamCodec} */ class DefaultEventCodec implements EventCodec { @@ -39,12 +43,20 @@ private String getRequiredEnv(String name) { return val; } - @Override - public Optional readEvent() { - String method = getRequiredEnv("FN_METHOD"); - String appName = getRequiredEnv("FN_APP_NAME"); - String route = getRequiredEnv("FN_PATH"); - String requestUrl = getRequiredEnv("FN_REQUEST_URL"); + protected InputEvent readEvent() { + String callId = env.getOrDefault("FN_CALL_ID", ""); + String deadline = env.get("FN_DEADLINE"); + Instant deadlineDate; + + if (deadline != null) { + try { + deadlineDate = Instant.parse(deadline); + } catch (DateTimeParseException e) { + throw new FunctionInputHandlingException("Invalid deadline date format", e); + } + } else { + deadlineDate = Instant.now().plus(1, ChronoUnit.HOURS); + } Map headers = new HashMap<>(); for (Map.Entry entry : env.entrySet()) { @@ -54,20 +66,22 @@ public Optional readEvent() { } } - return Optional.of(new ReadOnceInputEvent(appName, route, requestUrl, method, in, Headers.fromMap(headers), QueryParametersParser.getParams(requestUrl))); + return new ReadOnceInputEvent(in, Headers.fromMap(headers), callId, deadlineDate); } - @Override - public boolean shouldContinue() { - return false; - } - @Override - public void writeEvent(OutputEvent evt) { + protected void writeEvent(OutputEvent evt) { try { evt.writeToOutput(out); - }catch(IOException e){ - throw new FunctionOutputHandlingException("error writing event",e); + } catch (IOException e) { + throw new FunctionOutputHandlingException("error writing event", e); } } + + @Override + public void runCodec(Handler h) { + InputEvent event = readEvent(); + OutputEvent out = h.handle(event); + writeEvent(out); + } } diff --git a/runtime/src/main/java/com/fnproject/fn/runtime/EntryPoint.java b/runtime/src/main/java/com/fnproject/fn/runtime/EntryPoint.java index 834273ee..1e885b18 100644 --- a/runtime/src/main/java/com/fnproject/fn/runtime/EntryPoint.java +++ b/runtime/src/main/java/com/fnproject/fn/runtime/EntryPoint.java @@ -1,19 +1,18 @@ package com.fnproject.fn.runtime; -import com.fnproject.fn.api.InputEvent; -import com.fnproject.fn.api.OutputEvent; +import com.fnproject.fn.api.*; import com.fnproject.fn.api.exception.FunctionInputHandlingException; import com.fnproject.fn.api.exception.FunctionLoadException; import com.fnproject.fn.api.exception.FunctionOutputHandlingException; +import com.fnproject.fn.runtime.exception.FunctionInitializationException; import com.fnproject.fn.runtime.exception.InternalFunctionInvocationException; import com.fnproject.fn.runtime.exception.InvalidEntryPointException; import java.io.IOException; -import java.io.InputStream; -import java.io.OutputStream; import java.io.PrintStream; import java.util.*; +import java.util.concurrent.atomic.AtomicInteger; /** * Main entry point @@ -26,12 +25,26 @@ public static void main(String... args) throws Exception { // Override stdout while the function is running, so that the function result can be serialized to stdout // without interference from the user printing stuff to what they believe is stdout. System.setOut(System.err); + + + String format = System.getenv("FN_FORMAT"); + EventCodec codec; + if (format != null && format.equalsIgnoreCase("http")) { + codec = new HttpEventCodec(System.getenv(), System.in, originalSystemOut); + } else if (format == null || format.equalsIgnoreCase("default")) { + codec = new DefaultEventCodec(System.getenv(), System.in, originalSystemOut); + } else if (format.equals(HTTPStreamCodec.HTTP_STREAM_FORMAT)) { + codec = new HTTPStreamCodec(System.getenv()); + } else { + throw new FunctionInputHandlingException("Unsupported function format:" + format); + } + + int exitCode = new EntryPoint().run( - System.getenv(), - System.in, - originalSystemOut, - System.err, - args); + System.getenv(), + codec, + System.err, + args); System.setOut(originalSystemOut); System.exit(exitCode); } @@ -41,7 +54,7 @@ public static void main(String... args) throws Exception { * * @return the desired process exit status */ - public int run(Map env, InputStream functionInput, OutputStream functionOutput, PrintStream loggingOutput, String... args) { + public int run(Map env, EventCodec codec, PrintStream loggingOutput, String... args) { if (args.length != 1) { throw new InvalidEntryPointException("Expected one argument, of the form com.company.project.MyFunctionClass::myFunctionMethod"); } @@ -54,77 +67,85 @@ public int run(Map env, InputStream functionInput, OutputStream String cls = classMethod[0]; String mth = classMethod[1]; - int lastStatus = 0; + // TODO deprecate with default contract + final AtomicInteger lastStatus = new AtomicInteger(); try { final Map configFromEnvVars = Collections.unmodifiableMap(excludeInternalConfigAndHeaders(env)); FunctionLoader functionLoader = new FunctionLoader(); - FunctionRuntimeContext runtimeContext = new FunctionRuntimeContext(functionLoader.loadClass(cls, mth), configFromEnvVars); - FunctionConfigurer functionConfigurer = new FunctionConfigurer(); - functionConfigurer.configure(runtimeContext); - String format = env.get("FN_FORMAT"); - EventCodec codec; + MethodWrapper method = functionLoader.loadClass(cls, mth); + FunctionRuntimeContext runtimeContext = new FunctionRuntimeContext(method, configFromEnvVars); + + FnFeature[] features = method.getTargetClass().getAnnotationsByType(FnFeature.class); + for (FnFeature f : features){ + RuntimeFeature rf; + try{ + Class featureClass = f.value(); + rf = featureClass.newInstance(); + }catch (Exception e){ + throw new FunctionInitializationException("Could not load feature class " + f.value().toString() ,e); + } - if (format != null && format.equalsIgnoreCase("http")) { - codec = new HttpEventCodec(env, functionInput, functionOutput); - } else if (format == null || format.equalsIgnoreCase("default")) { - codec = new DefaultEventCodec(env, functionInput, functionOutput); - } else { - throw new FunctionInputHandlingException("Unsupported function format:" + format); + try{ + rf.initialize(runtimeContext); + }catch (Exception e){ + throw new FunctionInitializationException("Exception while calling initialization on runtime feature " + f.value() ,e); + } } - do { - try { - Optional evtOpt = codec.readEvent(); - if (!evtOpt.isPresent()) { - break; - } + + FunctionConfigurer functionConfigurer = new FunctionConfigurer(); + functionConfigurer.configure(runtimeContext); + + + codec.runCodec((evt) -> { + try { FunctionInvocationContext fic = runtimeContext.newInvocationContext(); - try (InputEvent evt = evtOpt.get()) { + try (InputEvent myEvt = evt) { OutputEvent output = runtimeContext.tryInvoke(evt, fic); if (output == null) { throw new FunctionInputHandlingException("No invoker found for input event"); } - codec.writeEvent(output); if (output.isSuccess()) { - lastStatus = 0; + lastStatus.set(0); fic.fireOnSuccessfulInvocation(); } else { - lastStatus = 1; + lastStatus.set(1); fic.fireOnFailedInvocation(); } - } catch (IOException e) { + return output; + + } catch (IOException err) { fic.fireOnFailedInvocation(); - throw new FunctionInputHandlingException("Error closing function input", e); + throw new FunctionInputHandlingException("Error closing function input", err); } catch (Exception e) { // Make sure we commit any pending Flows, then rethrow fic.fireOnFailedInvocation(); throw e; } - } catch (InternalFunctionInvocationException fie) { loggingOutput.println("An error occurred in function: " + filterStackTraceToOnlyIncludeUsersCode(fie)); - codec.writeEvent(fie.toOutput()); - // Here: completer-invoked continuations are *always* reported as successful to the Fn platform; // the completer interprets the embedded HTTP-framed response. - lastStatus = fie.toOutput().isSuccess() ? 0 : 1; + lastStatus.set(fie.toOutput().isSuccess() ? 0 : 1); + return fie.toOutput(); } - } while (codec.shouldContinue()); + + }); } catch (FunctionLoadException | FunctionInputHandlingException | FunctionOutputHandlingException e) { // catch all block; loggingOutput.println(filterStackTraceToOnlyIncludeUsersCode(e)); return 2; - } catch (Exception ee){ + } catch (Exception ee) { loggingOutput.println("An unexpected error occurred:"); ee.printStackTrace(loggingOutput); return 1; } - return lastStatus; + return lastStatus.get(); } @@ -179,7 +200,7 @@ private void addExceptionToStringBuilder(StringBuilder sb, Throwable t) { */ private Map excludeInternalConfigAndHeaders(Map env) { Set nonConfigEnvKeys = new HashSet<>(Arrays.asList("fn_app_name", "fn_path", "fn_method", "fn_request_url", - "fn_format", "content-length", "fn_call_id")); + "fn_format", "content-length", "fn_call_id")); Map config = new HashMap<>(); for (Map.Entry entry : env.entrySet()) { String lowerCaseKey = entry.getKey().toLowerCase(); diff --git a/runtime/src/main/java/com/fnproject/fn/runtime/EventCodec.java b/runtime/src/main/java/com/fnproject/fn/runtime/EventCodec.java index 56408b7d..9a7a9885 100644 --- a/runtime/src/main/java/com/fnproject/fn/runtime/EventCodec.java +++ b/runtime/src/main/java/com/fnproject/fn/runtime/EventCodec.java @@ -3,33 +3,33 @@ import com.fnproject.fn.api.InputEvent; import com.fnproject.fn.api.OutputEvent; -import java.io.IOException; -import java.util.Optional; - /** * Event Codec - deals with different calling conventions between fn and the function docker container */ public interface EventCodec { - /** - * Read a event from the input - * - * @return an empty input stream if the end of the stream is reached or an event if otherwise - */ - Optional readEvent(); /** - * Should the codec be used again - * - * @return true if {@link #readEvent()} can read another message + * Handler handles function content based on codec events + *

+ * A handler should generally deal with all exceptions (except errors) and convert them into appropriate OutputEvents */ - boolean shouldContinue(); + interface Handler { + /** + * Handle a function input event and generate a response + * + * @param event the event to handle + * @return an output event indicating the result of calling a function or an error + */ + OutputEvent handle(InputEvent event); + } /** - * Write an event to the output + * Run Codec should continuously run the function event loop until either the FDK should exit normally (returning normally) or an error occurred. + *

+ * Codec should invoke the handler for each received event * - * @param evt event to write - * @throws IOException if an error occurs while writing + * @param h the handler to run */ - void writeEvent(OutputEvent evt); + void runCodec(Handler h); } diff --git a/runtime/src/main/java/com/fnproject/fn/runtime/FunctionLoader.java b/runtime/src/main/java/com/fnproject/fn/runtime/FunctionLoader.java index 092645a5..ec7fb70e 100644 --- a/runtime/src/main/java/com/fnproject/fn/runtime/FunctionLoader.java +++ b/runtime/src/main/java/com/fnproject/fn/runtime/FunctionLoader.java @@ -20,6 +20,8 @@ public class FunctionLoader { */ public MethodWrapper loadClass(String className, String fnName) { Class targetClass = loadClass(className); + + return new DefaultMethodWrapper(targetClass, getTargetMethod(targetClass, fnName)); } diff --git a/runtime/src/main/java/com/fnproject/fn/runtime/FunctionRuntimeContext.java b/runtime/src/main/java/com/fnproject/fn/runtime/FunctionRuntimeContext.java index 83623335..68ed22c3 100644 --- a/runtime/src/main/java/com/fnproject/fn/runtime/FunctionRuntimeContext.java +++ b/runtime/src/main/java/com/fnproject/fn/runtime/FunctionRuntimeContext.java @@ -6,7 +6,6 @@ import com.fnproject.fn.runtime.coercion.*; import com.fnproject.fn.runtime.coercion.jackson.JacksonCoercion; import com.fnproject.fn.runtime.exception.FunctionClassInstantiationException; -import com.fnproject.fn.runtime.flow.FlowContinuationInvoker; import java.lang.annotation.Annotation; import java.lang.reflect.Constructor; @@ -20,6 +19,7 @@ public class FunctionRuntimeContext implements RuntimeContext { private final Map config; private final MethodWrapper method; private Map attributes = new HashMap<>(); + private List preCallHandlers = new ArrayList<>(); private List configuredInvokers = new ArrayList<>(); private Object instance; @@ -32,7 +32,17 @@ public class FunctionRuntimeContext implements RuntimeContext { public FunctionRuntimeContext(MethodWrapper method, Map config) { this.method = method; this.config = Objects.requireNonNull(config); - configuredInvokers.addAll(Arrays.asList(new FlowContinuationInvoker(), new MethodFunctionInvoker())); + configuredInvokers.add(new MethodFunctionInvoker()); + } + + @Override + public String getAppID() { + return config.getOrDefault("FN_APP_ID",""); + } + + @Override + public String getFunctionID() { + return config.getOrDefault("FN_FN_ID",""); } @Override @@ -49,7 +59,7 @@ public Optional getInvokeInstance() { if (RuntimeContext.class.isAssignableFrom(ctor.getParameterTypes()[0])) { instance = ctor.newInstance(FunctionRuntimeContext.this); } else { - if ( getMethod().getTargetClass().getEnclosingClass() != null && ! Modifier.isStatic(getMethod().getTargetClass().getModifiers()) ) { + if (getMethod().getTargetClass().getEnclosingClass() != null && !Modifier.isStatic(getMethod().getTargetClass().getModifiers())) { throw new FunctionClassInstantiationException("The function " + getMethod().getTargetClass() + " cannot be instantiated as it is a non-static inner class"); } else { throw new FunctionClassInstantiationException("The function " + getMethod().getTargetClass() + " cannot be instantiated as its constructor takes an unrecognized argument of type " + constructors[0].getParameterTypes()[0] + ". Function classes should have a single public constructor that takes either no arguments or a RuntimeContext argument"); @@ -111,8 +121,8 @@ public void addInputCoercion(InputCoercion ic) { public List getInputCoercions(MethodWrapper targetMethod, int param) { Annotation parameterAnnotations[] = targetMethod.getTargetMethod().getParameterAnnotations()[param]; Optional coercionAnnotation = Arrays.stream(parameterAnnotations) - .filter((ann) -> ann.annotationType().equals(InputBinding.class)) - .findFirst(); + .filter((ann) -> ann.annotationType().equals(InputBinding.class)) + .findFirst(); if (coercionAnnotation.isPresent()) { try { List coercionList = new ArrayList(); @@ -134,9 +144,19 @@ public void addOutputCoercion(OutputCoercion oc) { userOutputCoercions.add(Objects.requireNonNull(oc)); } + @Override - public void setInvoker(FunctionInvoker invoker) { - configuredInvokers.add(1, invoker); + public void addInvoker(FunctionInvoker invoker, FunctionInvoker.Phase phase) { + switch (phase) { + case PreCall: + preCallHandlers.add(0, invoker); + break; + case Call: + configuredInvokers.add(0, invoker); + break; + default: + throw new IllegalArgumentException("Unsupported phase " + phase); + } } @Override @@ -150,11 +170,19 @@ public FunctionInvocationContext newInvocationContext() { public OutputEvent tryInvoke(InputEvent evt, InvocationContext entryPoint) { OutputEvent output = null; + for (FunctionInvoker invoker : preCallHandlers) { + Optional result = invoker.tryInvoke(entryPoint, evt); + if (result.isPresent()) { + output = result.get(); + return output; + } + } + for (FunctionInvoker invoker : configuredInvokers) { Optional result = invoker.tryInvoke(entryPoint, evt); if (result.isPresent()) { output = result.get(); - break; + return output; } } return output; diff --git a/runtime/src/main/java/com/fnproject/fn/runtime/HTTPStreamCodec.java b/runtime/src/main/java/com/fnproject/fn/runtime/HTTPStreamCodec.java new file mode 100644 index 00000000..9a2ba047 --- /dev/null +++ b/runtime/src/main/java/com/fnproject/fn/runtime/HTTPStreamCodec.java @@ -0,0 +1,327 @@ +package com.fnproject.fn.runtime; + + +import com.fnproject.fn.api.Headers; +import com.fnproject.fn.api.InputEvent; +import com.fnproject.fn.api.OutputEvent; +import com.fnproject.fn.api.exception.FunctionInputHandlingException; +import com.fnproject.fn.api.exception.FunctionOutputHandlingException; +import com.fnproject.fn.runtime.exception.FunctionIOException; +import com.fnproject.fn.runtime.exception.FunctionInitializationException; +import com.fnproject.fn.runtime.ntv.UnixServerSocket; +import com.fnproject.fn.runtime.ntv.UnixSocket; +import org.apache.http.*; +import org.apache.http.entity.ByteArrayEntity; +import org.apache.http.entity.ContentType; +import org.apache.http.entity.StringEntity; +import org.apache.http.impl.DefaultBHttpServerConnection; +import org.apache.http.impl.io.EmptyInputStream; +import org.apache.http.message.BasicHeader; +import org.apache.http.message.BasicStatusLine; +import org.apache.http.protocol.BasicHttpContext; +import org.apache.http.protocol.HttpService; +import org.apache.http.protocol.ImmutableHttpProcessor; +import org.apache.http.protocol.UriHttpRequestHandlerMapper; + +import java.io.*; +import java.nio.file.Files; +import java.nio.file.attribute.PosixFilePermissions; +import java.time.Instant; +import java.time.format.DateTimeParseException; +import java.time.temporal.ChronoUnit; +import java.util.*; +import java.util.concurrent.CompletableFuture; +import java.util.concurrent.atomic.AtomicBoolean; + +/** + * Fn HTTP Stream over Unix domain sockets codec + *

+ *

+ * This creates a new unix socket on the address specified by env["FN_LISTENER"] - and accepts requests. + *

+ * This currently only handles exactly one concurrent connection + *

+ * Created on 24/08/2018. + *

+ * (c) 2018 Oracle Corporation + */ +public final class HTTPStreamCodec implements EventCodec, Closeable { + + public static final String HTTP_STREAM_FORMAT = "http-stream"; + private static final String FN_LISTENER = "FN_LISTENER"; + private final Map env; + private final AtomicBoolean stopping = new AtomicBoolean(false); + private final File socketFile; + private static final Set stripInputHeaders; + private static final Set stripOutputHeaders; + private final CompletableFuture stopped = new CompletableFuture<>(); + private final UnixServerSocket socket; + + static { + Set hin = new HashSet<>(); + hin.add("Host"); + hin.add("Accept-Encoding"); + hin.add("Transfer-Encoding"); + hin.add("User-Agent"); + hin.add("Connection"); + hin.add("TE"); + + stripInputHeaders = Collections.unmodifiableSet(hin); + + Set hout = new HashSet<>(); + hout.add("Content-Length"); + hout.add("Transfer-Encoding"); + hout.add("Connection"); + stripOutputHeaders = Collections.unmodifiableSet(hout); + } + + private final File tempFile; + + + private String randomString() { + int leftLimit = 97; + int rightLimit = 122; + int targetStringLength = 10; + Random random = new Random(); + StringBuilder buffer = new StringBuilder(targetStringLength); + for (int i = 0; i < targetStringLength; i++) { + int randomLimitedInt = leftLimit + (int) + (random.nextFloat() * (rightLimit - leftLimit + 1)); + buffer.append((char) randomLimitedInt); + } + return buffer.toString(); + } + + /** + * Construct a new HTTPStreamCodec based on the environment + * + * @param env an env map + */ + public HTTPStreamCodec(Map env) { + this.env = Objects.requireNonNull(env, "env"); + String listenerAddress = getRequiredEnv(FN_LISTENER); + + if (!listenerAddress.startsWith("unix:/")) { + throw new FunctionInitializationException("Invalid listener address - it should start with unix:/ :'" + listenerAddress + "'"); + } + String listenerFile = listenerAddress.substring("unix:".length()); + + socketFile = new File(listenerFile); + + + UnixServerSocket serverSocket = null; + File listenerDir = socketFile.getParentFile(); + tempFile = new File(listenerDir, randomString() + ".sock"); + try { + + serverSocket = UnixServerSocket.listen(tempFile.getAbsolutePath(), 1); + // Adjust socket permissions and move file + Files.setPosixFilePermissions(tempFile.toPath(), PosixFilePermissions.fromString("rw-rw-rw-")); + Files.createSymbolicLink(socketFile.toPath(), tempFile.toPath().getFileName()); + + this.socket = serverSocket; + } catch (IOException e) { + if (serverSocket != null) { + try { + serverSocket.close(); + } catch (IOException ignored) { + } + + } + throw new FunctionInitializationException("Unable to bind to unix socket in " + socketFile, e); + } + + + } + + @Override + public void runCodec(Handler h) { + + UriHttpRequestHandlerMapper mapper = new UriHttpRequestHandlerMapper(); + mapper.register("/call", ((request, response, context) -> { + InputEvent evt; + try { + evt = readEvent(request); + } catch (FunctionInputHandlingException e) { + response.setStatusCode(500); + response.setEntity(new StringEntity("{\"message\":\"Invalid input from function\",\"detail\":\"" + e.getMessage() + "\"}", ContentType.APPLICATION_JSON)); + return; + } + + OutputEvent outEvt; + + try { + outEvt = h.handle(evt); + } catch (Exception e) { + response.setStatusCode(500); + response.setEntity(new StringEntity("{\"message\":\"Unhandled internal error in FDK\"}", ContentType.APPLICATION_JSON)); + return; + } + + try { + writeEvent(outEvt, response); + } catch (Exception e) { + // TODO strange edge cases might appear with headers where the response is half written here + response.setStatusCode(500); + response.setEntity(new StringEntity("{\"message\":\"Unhandled internal error while generating response FDK\"}", ContentType.APPLICATION_JSON)); + } + } + )); + + ImmutableHttpProcessor requestProcess = new ImmutableHttpProcessor(new HttpRequestInterceptor[0], new HttpResponseInterceptor[0]); + HttpService svc = new HttpService(requestProcess, mapper); + + try { + + while (!stopping.get()) { + UnixSocket sock; + try { + sock = socket.accept(100); + if (sock == null) { + continue; + } + // TODO tweak these properly + sock.setSendBufferSize(65535); + sock.setReceiveBufferSize(65535); + + } catch (IOException e) { + if (stopping.get()) { + // ignore IO errors on stop + return; + } + throw new FunctionIOException("failed to accept connection from platform, terminating", e); + } + try { + DefaultBHttpServerConnection con = new DefaultBHttpServerConnection(65535); + con.bind(sock); + while (!sock.isClosed()) { + try { + svc.handleRequest(con, new BasicHttpContext()); + } catch (Exception ignored) { + sock.close(); + } + } + } catch (IOException ignored) { + // TODO should log here? + } finally { + try { + sock.close(); + } catch (IOException ignored) { + } + } + + } + } finally { + stopped.complete(true); + } + + + } + + + private String getRequiredEnv(String name) { + String val = env.get(name); + if (val == null) { + throw new FunctionInputHandlingException("Required environment variable " + name + " is not set - are you running a function outside of fn run?"); + } + return val; + } + + private static String getRequiredHeader(HttpRequest request, String headerName) { + Header header = request.getFirstHeader(headerName); + if (header == null) { + throw new FunctionInputHandlingException("Required FDK header variable " + headerName + " is not set, check you are using the latest functinos and FDK versions"); + } + return header.getValue(); + } + + private InputEvent readEvent(HttpRequest request) { + + InputStream bodyStream; + if (request instanceof HttpEntityEnclosingRequest) { + HttpEntityEnclosingRequest entityEnclosingRequest = (HttpEntityEnclosingRequest) request; + try { + bodyStream = entityEnclosingRequest.getEntity().getContent(); + } catch (IOException exception) { + throw new FunctionInputHandlingException("error handling input", exception); + } + } else { + bodyStream = EmptyInputStream.INSTANCE; + } + + + String deadline = getRequiredHeader(request, "Fn-Deadline"); + String callID = getRequiredHeader(request, "Fn-Call-Id"); + + if (callID == null) { + callID = ""; + } + Instant deadlineDate = Instant.now().plus(1, ChronoUnit.HOURS); + if (deadline != null) { + try { + deadlineDate = Instant.parse(deadline); + } catch (DateTimeParseException e) { + throw new FunctionInputHandlingException("Invalid deadline date format", e); + } + } + Headers headersIn = Headers.emptyHeaders(); + + + for (Header h : request.getAllHeaders()) { + if (stripInputHeaders.contains(Headers.canonicalKey(h.getName()))) { + continue; + } + headersIn = headersIn.addHeader(h.getName(), h.getValue()); + } + + return new ReadOnceInputEvent(bodyStream, headersIn, callID, deadlineDate); + + } + + private void writeEvent(OutputEvent evt, HttpResponse response) { + + evt.getHeaders().asMap() + .entrySet() + .stream() + .filter(e -> !stripOutputHeaders.contains(e.getKey())) + .flatMap(e -> e.getValue().stream().map((v) -> new BasicHeader(e.getKey(), v))) + .forEachOrdered(response::addHeader); + + ContentType contentType = evt.getContentType().map(c -> { + try { + return ContentType.parse(c); + } catch (ParseException e) { + return ContentType.DEFAULT_BINARY; + } + }).orElse(ContentType.DEFAULT_BINARY); + + response.setHeader("Content-Type", contentType.toString()); + response.setStatusLine(new BasicStatusLine(HttpVersion.HTTP_1_1, evt.getStatus().getCode(), evt.getStatus().name())); + ByteArrayOutputStream bos = new ByteArrayOutputStream(); + // TODO remove output buffering here - possibly change OutputEvent contract to support providing an InputStream? + try { + evt.writeToOutput(bos); + } catch (IOException e) { + throw new FunctionOutputHandlingException("Error writing output", e); + } + byte[] data = bos.toByteArray(); + response.setEntity(new ByteArrayEntity(data, contentType)); + + } + + + @Override + public void close() throws IOException { + if (stopping.compareAndSet(false, true)) { + socket.close(); + + try { + stopped.get(); + } catch (Exception ignored) { + } + socketFile.delete(); + tempFile.delete(); + } + + } +} diff --git a/runtime/src/main/java/com/fnproject/fn/runtime/HttpEventCodec.java b/runtime/src/main/java/com/fnproject/fn/runtime/HttpEventCodec.java index 8ec9e398..711f895f 100644 --- a/runtime/src/main/java/com/fnproject/fn/runtime/HttpEventCodec.java +++ b/runtime/src/main/java/com/fnproject/fn/runtime/HttpEventCodec.java @@ -19,6 +19,9 @@ import org.apache.http.message.BasicStatusLine; import java.io.*; +import java.time.Instant; +import java.time.format.DateTimeParseException; +import java.time.temporal.ChronoUnit; import java.util.HashMap; import java.util.Map; import java.util.Objects; @@ -30,6 +33,8 @@ * Reads input via an InputStream as an HTTP request. *

* This does not consume the whole event from the buffer, The caller is responsible for ensuring that either {@link InputEvent#consumeBody(Function)} or {@link InputEvent#close()} is called before reading a new event + * + * @deprecated all new functions should use {@link HTTPStreamCodec} */ public class HttpEventCodec implements EventCodec { @@ -67,8 +72,7 @@ private String getRequiredEnv(String name) { return val; } - @Override - public final Optional readEvent() { + protected Optional readEvent() { HttpRequest req; try { @@ -85,34 +89,43 @@ public final Optional readEvent() { long contentLength = Long.parseLong(requiredHeader(req, "content-length")); bodyStream = new ContentLengthInputStream(sib, contentLength); } else if (req.getHeaders("transfer-encoding").length > 0 && - req.getFirstHeader("transfer-encoding").getValue().equalsIgnoreCase("chunked")) { + req.getFirstHeader("transfer-encoding").getValue().equalsIgnoreCase("chunked")) { bodyStream = new ChunkedInputStream(sib); } else { bodyStream = new ByteArrayInputStream(new byte[]{}); } - String appName = getRequiredEnv("FN_APP_NAME"); - String route = getRequiredEnv("FN_PATH"); - String method = requiredHeader(req, "fn_method"); - String requestUrl = requiredHeader(req, "fn_request_url"); + + Instant deadlineDate; + + Header deadlineHeader = req.getFirstHeader("fn_deadline"); + if (deadlineHeader != null) { + try { + deadlineDate = Instant.parse(deadlineHeader.getValue()); + } catch (DateTimeParseException e) { + throw new FunctionInputHandlingException("Invalid deadline date format", e); + } + } else { + deadlineDate = Instant.now().plus(1, ChronoUnit.HOURS); + } + + Header callIDHeader = req.getFirstHeader("fn_call_id"); + + String callID = ""; + if (callIDHeader != null) { + callID = callIDHeader.getValue(); + } Map headers = new HashMap<>(); for (Header h : req.getAllHeaders()) { headers.put(h.getName(), h.getValue()); } - return Optional.of(new ReadOnceInputEvent(appName, route, requestUrl, method, - bodyStream, Headers.fromMap(headers), - QueryParametersParser.getParams(requestUrl))); + return Optional.of(new ReadOnceInputEvent( + bodyStream, Headers.fromMap(headers), callID, deadlineDate)); } - @Override - public boolean shouldContinue() { - return true; - } - - @Override - public void writeEvent(OutputEvent evt) { + protected void writeEvent(OutputEvent evt) { try { // TODO: We buffer the whole output here just to get the content-length // TODO: functions should support chunked @@ -126,12 +139,15 @@ public void writeEvent(OutputEvent evt) { BasicHttpResponse response; if (evt.isSuccess()) { - response = new BasicHttpResponse(new BasicStatusLine(new ProtocolVersion("HTTP", 1, 1), evt.getStatusCode(), "INVOKED")); + response = new BasicHttpResponse(new BasicStatusLine(new ProtocolVersion("HTTP", 1, 1), evt.getStatus().getCode(), evt.getStatus().name())); } else { - response = new BasicHttpResponse(new BasicStatusLine(new ProtocolVersion("HTTP", 1, 1), evt.getStatusCode(), "INVOKE FAILED")); + response = new BasicHttpResponse(new BasicStatusLine(new ProtocolVersion("HTTP", 1, 1), evt.getStatus().getCode(), evt.getStatus().name())); } - evt.getHeaders().getAll().forEach(response::setHeader); + evt.getHeaders().asMap().forEach((k, vs) -> { + vs.forEach(v -> response.addHeader(k, v)); + }); + evt.getContentType().ifPresent((ct) -> response.setHeader(CONTENT_TYPE_HEADER, ct)); response.setHeader("Content-length", String.valueOf(data.length)); @@ -153,4 +169,15 @@ public void writeEvent(OutputEvent evt) { } } + @Override + public void runCodec(Handler h) { + + while (true) { + Optional evt = readEvent(); + if (!evt.isPresent()) { + return; + } + writeEvent(h.handle(evt.get())); + } + } } diff --git a/runtime/src/main/java/com/fnproject/fn/runtime/ReadOnceInputEvent.java b/runtime/src/main/java/com/fnproject/fn/runtime/ReadOnceInputEvent.java index c120b6bd..21276306 100644 --- a/runtime/src/main/java/com/fnproject/fn/runtime/ReadOnceInputEvent.java +++ b/runtime/src/main/java/com/fnproject/fn/runtime/ReadOnceInputEvent.java @@ -2,12 +2,12 @@ import com.fnproject.fn.api.Headers; import com.fnproject.fn.api.InputEvent; -import com.fnproject.fn.api.QueryParameters; import com.fnproject.fn.api.exception.FunctionInputHandlingException; import java.io.BufferedInputStream; import java.io.IOException; import java.io.InputStream; +import java.time.Instant; import java.util.Objects; import java.util.concurrent.atomic.AtomicBoolean; import java.util.function.Function; @@ -18,26 +18,18 @@ * This in */ public class ReadOnceInputEvent implements InputEvent { - - private final String appName; - private final String route; - private final String requestUrl; - private final String method; - private final BufferedInputStream body; private AtomicBoolean consumed = new AtomicBoolean(false); - private QueryParameters queryParameters; private final Headers headers; + private final Instant deadline; + private final String callID; - public ReadOnceInputEvent(String appName, String route, String requestUrl, String method, InputStream body, Headers headers, QueryParameters parameters) { - this.appName = Objects.requireNonNull(appName); - this.route = Objects.requireNonNull(route); - this.requestUrl = Objects.requireNonNull(requestUrl); - this.method = Objects.requireNonNull(method).toUpperCase(); - this.body = new BufferedInputStream(Objects.requireNonNull(body)); - this.headers = Objects.requireNonNull(headers); - this.queryParameters = Objects.requireNonNull(parameters); + public ReadOnceInputEvent(InputStream body, Headers headers, String callID, Instant deadline) { + this.body = new BufferedInputStream(Objects.requireNonNull(body, "body")); + this.headers = Objects.requireNonNull(headers, "headers"); + this.callID = Objects.requireNonNull(callID, "callID"); + this.deadline = Objects.requireNonNull(deadline, "deadline"); body.mark(Integer.MAX_VALUE); } @@ -63,57 +55,22 @@ public T consumeBody(Function dest) { } - /** - * @return The fn application name associated with this call - */ - @Override - public String getAppName() { - return appName; - } - /** - * @return The route associated with this call (starting with a slash) - */ @Override - public String getRoute() { - return route; + public String getCallID() { + return callID; } - /** - * @return The full request URL into the app - */ @Override - public String getRequestUrl() { - return requestUrl; + public Instant getDeadline() { + return deadline; } - /** - * @return The HTTP method (capitalised) of this request - */ - @Override - public String getMethod() { - return method; - } - - /** - * The HTTP headers on the request - * - * @return an immutable map of headers - */ @Override public Headers getHeaders() { return headers; } - /** - * The query parameters of the function invocation - * - * @return an immutable map of query parameters parsed from the request URL - */ - @Override - public QueryParameters getQueryParameters() { - return queryParameters; - } @Override public void close() throws IOException { diff --git a/runtime/src/main/java/com/fnproject/fn/runtime/coercion/ByteArrayCoercion.java b/runtime/src/main/java/com/fnproject/fn/runtime/coercion/ByteArrayCoercion.java index 2f8034b0..401791d2 100644 --- a/runtime/src/main/java/com/fnproject/fn/runtime/coercion/ByteArrayCoercion.java +++ b/runtime/src/main/java/com/fnproject/fn/runtime/coercion/ByteArrayCoercion.java @@ -13,7 +13,7 @@ public class ByteArrayCoercion implements InputCoercion, OutputCoercion { public Optional wrapFunctionResult(InvocationContext ctx, MethodWrapper method, Object value) { if (method.getReturnType().getParameterClass().equals(byte[].class)) { - return Optional.of(OutputEvent.fromBytes(((byte[]) value), OutputEvent.SUCCESS, "application/octet-stream")); + return Optional.of(OutputEvent.fromBytes(((byte[]) value), OutputEvent.Status.Success, "application/octet-stream")); } else { return Optional.empty(); } diff --git a/runtime/src/main/java/com/fnproject/fn/runtime/coercion/StringCoercion.java b/runtime/src/main/java/com/fnproject/fn/runtime/coercion/StringCoercion.java index 0fb6c46f..b51b9d14 100644 --- a/runtime/src/main/java/com/fnproject/fn/runtime/coercion/StringCoercion.java +++ b/runtime/src/main/java/com/fnproject/fn/runtime/coercion/StringCoercion.java @@ -11,7 +11,7 @@ public class StringCoercion implements InputCoercion, OutputCoercion { @Override public Optional wrapFunctionResult(InvocationContext ctx, MethodWrapper method, Object value) { if (method.getReturnType().getParameterClass().equals(String.class)) { - return Optional.of(OutputEvent.fromBytes(((String) value).getBytes(), OutputEvent.SUCCESS, "text/plain")); + return Optional.of(OutputEvent.fromBytes(((String) value).getBytes(), OutputEvent.Status.Success, "text/plain")); } else { return Optional.empty(); } diff --git a/runtime/src/main/java/com/fnproject/fn/runtime/coercion/VoidCoercion.java b/runtime/src/main/java/com/fnproject/fn/runtime/coercion/VoidCoercion.java index 5d0442b6..3586e8dc 100644 --- a/runtime/src/main/java/com/fnproject/fn/runtime/coercion/VoidCoercion.java +++ b/runtime/src/main/java/com/fnproject/fn/runtime/coercion/VoidCoercion.java @@ -11,7 +11,7 @@ public class VoidCoercion implements OutputCoercion { @Override public Optional wrapFunctionResult(InvocationContext ctx, MethodWrapper method, Object value) { if (method.getReturnType().getParameterClass().equals(Void.class)) { - return Optional.of(OutputEvent.emptyResult(OutputEvent.SUCCESS)); + return Optional.of(OutputEvent.emptyResult(OutputEvent.Status.Success)); } else { return Optional.empty(); } diff --git a/runtime/src/main/java/com/fnproject/fn/runtime/coercion/jackson/JacksonCoercion.java b/runtime/src/main/java/com/fnproject/fn/runtime/coercion/jackson/JacksonCoercion.java index 93636d38..3c31a1a1 100644 --- a/runtime/src/main/java/com/fnproject/fn/runtime/coercion/jackson/JacksonCoercion.java +++ b/runtime/src/main/java/com/fnproject/fn/runtime/coercion/jackson/JacksonCoercion.java @@ -64,7 +64,7 @@ private static RuntimeException coercionFailed(Type paramType) { public Optional wrapFunctionResult(InvocationContext ctx, MethodWrapper method, Object value) { try { - return Optional.of(OutputEvent.fromBytes(objectMapper(ctx).writeValueAsBytes(value), OutputEvent.SUCCESS, + return Optional.of(OutputEvent.fromBytes(objectMapper(ctx).writeValueAsBytes(value), OutputEvent.Status.Success, "application/json")); } catch (JsonProcessingException e) { diff --git a/runtime/src/main/java/com/fnproject/fn/runtime/exception/FunctionIOException.java b/runtime/src/main/java/com/fnproject/fn/runtime/exception/FunctionIOException.java new file mode 100644 index 00000000..7b99da89 --- /dev/null +++ b/runtime/src/main/java/com/fnproject/fn/runtime/exception/FunctionIOException.java @@ -0,0 +1,20 @@ +package com.fnproject.fn.runtime.exception; + +/** + * The FDK experienced a terminal issue communicating with the platform + */ +public final class FunctionIOException extends RuntimeException { + + + /** + * create a function invocation exception + * + * @param message private message for this exception - + * @param target the underlying user exception that triggered this failure + */ + public FunctionIOException(String message, Throwable target) { + super(message, target); + } + + +} diff --git a/runtime/src/main/java/com/fnproject/fn/runtime/exception/FunctionInitializationException.java b/runtime/src/main/java/com/fnproject/fn/runtime/exception/FunctionInitializationException.java new file mode 100644 index 00000000..7bbc9323 --- /dev/null +++ b/runtime/src/main/java/com/fnproject/fn/runtime/exception/FunctionInitializationException.java @@ -0,0 +1,23 @@ +package com.fnproject.fn.runtime.exception; + +/** + * The FDK was not able to start up + */ +public final class FunctionInitializationException extends RuntimeException { + + + /** + * create a function invocation exception + * + * @param message private message for this exception - + * @param target the underlying user exception that triggered this failure + */ + public FunctionInitializationException(String message, Throwable target) { + super(message, target); + } + + + public FunctionInitializationException(String message) { + super(message); + } +} diff --git a/runtime/src/main/java/com/fnproject/fn/runtime/exception/InternalFunctionInvocationException.java b/runtime/src/main/java/com/fnproject/fn/runtime/exception/InternalFunctionInvocationException.java index f12338d2..8b416a7c 100644 --- a/runtime/src/main/java/com/fnproject/fn/runtime/exception/InternalFunctionInvocationException.java +++ b/runtime/src/main/java/com/fnproject/fn/runtime/exception/InternalFunctionInvocationException.java @@ -19,7 +19,7 @@ public final class InternalFunctionInvocationException extends RuntimeException public InternalFunctionInvocationException(String message, Throwable target) { super(message); this.cause = target; - this.event = OutputEvent.fromBytes(new byte[0], OutputEvent.FAILURE, null); + this.event = OutputEvent.fromBytes(new byte[0], OutputEvent.Status.FunctionError, null); } diff --git a/runtime/src/main/java/com/fnproject/fn/runtime/exception/PlatformCommunicationException.java b/runtime/src/main/java/com/fnproject/fn/runtime/exception/PlatformCommunicationException.java index 7a3249e7..2bbb33d7 100644 --- a/runtime/src/main/java/com/fnproject/fn/runtime/exception/PlatformCommunicationException.java +++ b/runtime/src/main/java/com/fnproject/fn/runtime/exception/PlatformCommunicationException.java @@ -1,5 +1,8 @@ package com.fnproject.fn.runtime.exception; +/** + * An error occured in the + */ public class PlatformCommunicationException extends RuntimeException { public PlatformCommunicationException(String message) { super(message); diff --git a/runtime/src/main/java/com/fnproject/fn/runtime/QueryParametersImpl.java b/runtime/src/main/java/com/fnproject/fn/runtime/httpgateway/QueryParametersImpl.java similarity index 76% rename from runtime/src/main/java/com/fnproject/fn/runtime/QueryParametersImpl.java rename to runtime/src/main/java/com/fnproject/fn/runtime/httpgateway/QueryParametersImpl.java index bf7309fc..885be4c3 100644 --- a/runtime/src/main/java/com/fnproject/fn/runtime/QueryParametersImpl.java +++ b/runtime/src/main/java/com/fnproject/fn/runtime/httpgateway/QueryParametersImpl.java @@ -1,10 +1,11 @@ -package com.fnproject.fn.runtime; +package com.fnproject.fn.runtime.httpgateway; import com.fnproject.fn.api.QueryParameters; +import java.io.Serializable; import java.util.*; -public class QueryParametersImpl implements QueryParameters { +public class QueryParametersImpl implements QueryParameters, Serializable { private final Map> params; public QueryParametersImpl() { @@ -18,8 +19,8 @@ public QueryParametersImpl(Map> params) { public Optional get(String key) { Objects.requireNonNull(key); return Optional.of(getValues(key)) - .filter((values) -> values.size() > 0) - .flatMap((values) -> Optional.ofNullable(values.get(0))); + .filter((values) -> values.size() > 0) + .flatMap((values) -> Optional.ofNullable(values.get(0))); } public List getValues(String key) { diff --git a/runtime/src/main/java/com/fnproject/fn/runtime/QueryParametersParser.java b/runtime/src/main/java/com/fnproject/fn/runtime/httpgateway/QueryParametersParser.java similarity index 97% rename from runtime/src/main/java/com/fnproject/fn/runtime/QueryParametersParser.java rename to runtime/src/main/java/com/fnproject/fn/runtime/httpgateway/QueryParametersParser.java index 7e73af2f..51242f06 100644 --- a/runtime/src/main/java/com/fnproject/fn/runtime/QueryParametersParser.java +++ b/runtime/src/main/java/com/fnproject/fn/runtime/httpgateway/QueryParametersParser.java @@ -1,4 +1,4 @@ -package com.fnproject.fn.runtime; +package com.fnproject.fn.runtime.httpgateway; import com.fnproject.fn.api.QueryParameters; diff --git a/runtime/src/main/java/com/fnproject/fn/runtime/ntv/UnixServerSocket.java b/runtime/src/main/java/com/fnproject/fn/runtime/ntv/UnixServerSocket.java new file mode 100644 index 00000000..7460d250 --- /dev/null +++ b/runtime/src/main/java/com/fnproject/fn/runtime/ntv/UnixServerSocket.java @@ -0,0 +1,62 @@ +package com.fnproject.fn.runtime.ntv; + +import java.io.Closeable; +import java.io.IOException; +import java.net.SocketException; +import java.util.concurrent.atomic.AtomicBoolean; + +/** + * Created on 12/09/2018. + *

+ * (c) 2018 Oracle Corporation + */ +public class UnixServerSocket implements Closeable { + private final int fd; + AtomicBoolean closed = new AtomicBoolean(); + + private UnixServerSocket(int fd) { + this.fd = fd; + } + + + public static UnixServerSocket listen(String fileName, int backlog) throws IOException { + int fd = UnixSocketNative.socket(); + + try { + UnixSocketNative.bind(fd, fileName); + } catch (UnixSocketException e) { + UnixSocketNative.close(fd); + throw e; + } + + + try { + UnixSocketNative.listen(fd, backlog); + } catch (UnixSocketException e) { + UnixSocketNative.close(fd); + throw e; + } + return new UnixServerSocket(fd); + + } + + @Override + public void close() throws IOException { + if (closed.compareAndSet(false,true)) { + UnixSocketNative.close(fd); + } + } + + public UnixSocket accept(long timeoutMillis) throws IOException { + if (closed.get()) { + throw new SocketException("acceot on closed socket"); + } + int newFd = UnixSocketNative.accept(fd, timeoutMillis); + if (newFd == 0) { + return null; + } + return new UnixSocket(newFd); + } + + +} diff --git a/runtime/src/main/java/com/fnproject/fn/runtime/ntv/UnixSocket.java b/runtime/src/main/java/com/fnproject/fn/runtime/ntv/UnixSocket.java new file mode 100644 index 00000000..592f2108 --- /dev/null +++ b/runtime/src/main/java/com/fnproject/fn/runtime/ntv/UnixSocket.java @@ -0,0 +1,321 @@ +package com.fnproject.fn.runtime.ntv; + +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; +import java.net.*; +import java.util.Objects; +import java.util.concurrent.atomic.AtomicBoolean; + +/** + * This approximates a Java.net.socket for many operations but not by any means all + * Created on 12/09/2018. + *

+ * (c) 2018 Oracle Corporation + */ +public final class UnixSocket extends Socket { + // Fall back to WTF for most unsupported operations + private static final SocketImpl fakeSocketImpl = new SocketImpl() { + @Override + protected void create(boolean stream) throws IOException { + throw new UnsupportedOperationException(); + + } + + @Override + protected void connect(String host, int port) throws IOException { + throw new UnsupportedOperationException(); + + } + + @Override + protected void connect(InetAddress address, int port) throws IOException { + throw new UnsupportedOperationException(); + + } + + @Override + protected void connect(SocketAddress address, int timeout) throws IOException { + throw new UnsupportedOperationException(); + + } + + @Override + protected void bind(InetAddress host, int port) throws IOException { + throw new UnsupportedOperationException(); + + } + + @Override + protected void listen(int backlog) throws IOException { + throw new UnsupportedOperationException(); + + } + + @Override + protected void accept(SocketImpl s) throws IOException { + throw new UnsupportedOperationException(); + + } + + @Override + protected InputStream getInputStream() throws IOException { + throw new UnsupportedOperationException(); + } + + @Override + protected OutputStream getOutputStream() throws IOException { + throw new UnsupportedOperationException(); + } + + @Override + protected int available() throws IOException { + throw new UnsupportedOperationException(); + } + + @Override + protected void close() throws IOException { + throw new UnsupportedOperationException(); + } + + @Override + protected void sendUrgentData(int data) throws IOException { + throw new UnsupportedOperationException(); + + } + + // Thes are overridden specifically + @Override + public void setOption(int optID, Object value) throws SocketException { + throw new UnsupportedOperationException(); + + } + + @Override + public Object getOption(int optID) throws SocketException { + throw new UnsupportedOperationException(); + } + }; + + + private final int fd; + private final AtomicBoolean closed = new AtomicBoolean(); + + private final AtomicBoolean inputClosed = new AtomicBoolean(); + private final AtomicBoolean outputClosed = new AtomicBoolean(); + + private final InputStream in; + private final OutputStream out; + + + UnixSocket(int fd) throws SocketException { + super(fakeSocketImpl); + this.fd = fd; + in = new UsInput(); + out = new UsOutput(); + + } + + private class UsInput extends InputStream { + + @Override + public int read() throws IOException { + + byte[] buf = new byte[1]; + int rv = read(buf, 0, 1); + if (rv == -1) { + return -1; + } + return (int) buf[0]; + } + + + public int read(byte b[]) throws IOException { + return this.read(b, 0, b.length); + } + + @Override + public int read(byte b[], int off, int len) throws IOException { + if (inputClosed.get()) { + throw new UnixSocketException("Read on closed stream"); + } + + return UnixSocketNative.recv(fd, b, off, len); + } + + @Override + public void close() throws IOException { + shutdownInput(); + } + } + + + private class UsOutput extends OutputStream { + + @Override + public void write(int b) throws IOException { + write(new byte[]{(byte) b}, 0, 1); + } + + public void write(byte b[], int off, int len) throws IOException { + if (outputClosed.get()) { + throw new UnixSocketException("Write to closed stream"); + } + Objects.requireNonNull(b); + while (len > 0) { + int sent = UnixSocketNative.send(fd, b, off, len); + + if (sent == 0) { + throw new UnixSocketException("No data written to buffer"); + } + off = off + sent; + len = len - sent; + } + } + + @Override + public void close() throws IOException { + shutdownOutput(); + } + } + + + public static UnixSocket connect(String destination) throws IOException { + int fd = UnixSocketNative.socket(); + UnixSocketNative.connect(fd, destination); + return new UnixSocket(fd); + } + + @Override + public InputStream getInputStream() { + return in; + } + + @Override + public OutputStream getOutputStream() { + return out; + } + + + @Override + public synchronized void setReceiveBufferSize(int size) throws SocketException { + UnixSocketNative.setRecvBufSize(fd, size); + } + + @Override + public synchronized void setSendBufferSize(int size) throws SocketException { + UnixSocketNative.setSendBufSize(fd, size); + } + + + @Override + public void setSoTimeout(int timeout) throws SocketException { + UnixSocketNative.setRecvTimeout(fd, timeout); + + } + + @Override + public int getSoTimeout() throws SocketException { + return UnixSocketNative.getRecvTimeout(fd); + } + + @Override + public void connect(SocketAddress endpoint) throws IOException { + throw new UnsupportedOperationException(); + } + + @Override + public void connect(SocketAddress endpoint, int timeout) throws IOException { + throw new UnsupportedOperationException(); + } + + @Override + public void bind(SocketAddress bindpoint) throws IOException { + throw new UnsupportedOperationException(); + } + + @Override + public InetAddress getInetAddress() { + return null; + } + + @Override + public InetAddress getLocalAddress() { + throw new UnsupportedOperationException(); + } + + @Override + public int getPort() { + return 0; + } + + @Override + public int getLocalPort() { + return -1; + } + + @Override + public SocketAddress getRemoteSocketAddress() { + return null; + } + + @Override + public SocketAddress getLocalSocketAddress() { + return null; + } + + + @Override + public boolean isConnected() { + return true; + } + + @Override + public boolean isBound() { + return true; + } + + + @Override + public boolean isClosed() { + return closed.get(); + } + + + @Override + public boolean isInputShutdown() { + return inputClosed.get(); + } + + @Override + public boolean isOutputShutdown() { + return outputClosed.get(); + } + + @Override + public void shutdownInput() throws IOException { + if (inputClosed.compareAndSet(false, true)) { + UnixSocketNative.shutdown(fd, true, false); + } else { + throw new SocketException("Input already shut down"); + } + } + + @Override + public void shutdownOutput() throws IOException { + if (outputClosed.compareAndSet(false, true)) { + UnixSocketNative.shutdown(fd, false, true); + } else { + throw new SocketException("Output already shut down"); + } + } + + @Override + public void close() throws IOException { + if (!closed.compareAndSet(false, true)) { + UnixSocketNative.close(fd); + } + } + + +} diff --git a/runtime/src/main/java/com/fnproject/fn/runtime/ntv/UnixSocketException.java b/runtime/src/main/java/com/fnproject/fn/runtime/ntv/UnixSocketException.java new file mode 100644 index 00000000..32803bae --- /dev/null +++ b/runtime/src/main/java/com/fnproject/fn/runtime/ntv/UnixSocketException.java @@ -0,0 +1,18 @@ +package com.fnproject.fn.runtime.ntv; + +import java.net.SocketException; + +/** + * Created on 12/09/2018. + *

+ * (c) 2018 Oracle Corporation + */ +public class UnixSocketException extends SocketException { + public UnixSocketException(String message, String detail) { + super(message + ":" + detail); + } + + public UnixSocketException(String message) { + super(message); + } +} diff --git a/runtime/src/main/java/com/fnproject/fn/runtime/ntv/UnixSocketNative.java b/runtime/src/main/java/com/fnproject/fn/runtime/ntv/UnixSocketNative.java new file mode 100644 index 00000000..560c55ce --- /dev/null +++ b/runtime/src/main/java/com/fnproject/fn/runtime/ntv/UnixSocketNative.java @@ -0,0 +1,58 @@ +package com.fnproject.fn.runtime.ntv; + + +import java.io.IOException; + +/** + * Created on 12/09/2018. + *

+ * (c) 2018 Oracle Corporation + */ +class UnixSocketNative { + + static { + String lib = System.mapLibraryName("fnunixsocket"); + + + String libLocation = System.getProperty("com.fnproject.java.native.libdir"); + if (libLocation != null) { + if (!libLocation.endsWith("/")) { + libLocation = libLocation + "/"; + } + lib = libLocation + lib; + System.load(lib); + }else{ + System.loadLibrary("fnunixsocket"); + } + } + + public static native int socket() throws IOException; + + public static native void bind(int socket, String path) throws UnixSocketException; + + public static native void connect(int socket, String path) throws IOException; + + public static native void listen(int socket, int backlog) throws UnixSocketException; + + public static native int accept(int socket, long timeoutMs) throws IOException; + + public static native int recv(int socket, byte[] buffer, int offset, int length) throws IOException; + + public static native int send(int socket, byte[] buffer, int offset, int length) throws IOException; + + public static native void close(int socket) throws UnixSocketException; + + public static native void setSendTimeout(int socket, int timeout) throws UnixSocketException; + + public static native int getSendTimeout(int socket) throws IOException; + + public static native void setRecvTimeout(int socket, int timeout) throws UnixSocketException; + + public static native int getRecvTimeout(int socket) throws UnixSocketException; + + public static native void setSendBufSize(int socket, int bufSize) throws UnixSocketException; + + public static native void setRecvBufSize(int socket, int bufSize) throws UnixSocketException; + + public static native void shutdown(int socket, boolean input, boolean output) throws UnixSocketException; +} diff --git a/runtime/src/test/java/com/fnproject/fn/runtime/ConfigurationMethodsTest.java b/runtime/src/test/java/com/fnproject/fn/runtime/ConfigurationMethodsTest.java index cdde6e98..6b9816d1 100644 --- a/runtime/src/test/java/com/fnproject/fn/runtime/ConfigurationMethodsTest.java +++ b/runtime/src/test/java/com/fnproject/fn/runtime/ConfigurationMethodsTest.java @@ -16,51 +16,51 @@ public class ConfigurationMethodsTest { @Test public void staticTargetWithNoConfigurationIsOK() throws Exception { - fn.givenDefaultEvent().withBody("Hello World").enqueue(); + fn.givenEvent().withBody("Hello World").enqueue(); fn.thenRun(TestFnWithConfigurationMethods.StaticTargetNoConfiguration.class, "echo"); - assertThat(fn.getStdOutAsString()).isEqualTo("StaticTargetNoConfiguration\nHello World"); + assertThat(fn.getOnlyOutputAsString()).isEqualTo("StaticTargetNoConfiguration\nHello World"); assertThat(fn.getStdErrAsString()).isEmpty(); assertThat(fn.exitStatus()).isZero(); } @Test public void instanceTargetWithNoConfigurationIsOK() throws Exception { - fn.givenDefaultEvent().withBody("Hello World").enqueue(); + fn.givenEvent().withBody("Hello World").enqueue(); fn.thenRun(TestFnWithConfigurationMethods.InstanceTargetNoConfiguration.class, "echo"); - assertThat(fn.getStdOutAsString()).isEqualTo("InstanceTargetNoConfiguration\nHello World"); + assertThat(fn.getOnlyOutputAsString()).isEqualTo("InstanceTargetNoConfiguration\nHello World"); assertThat(fn.getStdErrAsString()).isEmpty(); assertThat(fn.exitStatus()).isZero(); } @Test public void staticTargetWithStaticConfigurationIsOK() throws Exception { - fn.givenDefaultEvent().withBody("Hello World").enqueue(); + fn.givenEvent().withBody("Hello World").enqueue(); fn.thenRun(TestFnWithConfigurationMethods.StaticTargetStaticConfiguration.class, "echo"); - assertThat(fn.getStdOutAsString()).isEqualTo("StaticTargetStaticConfiguration\nHello World"); + assertThat(fn.getOnlyOutputAsString()).isEqualTo("StaticTargetStaticConfiguration\nHello World"); assertThat(fn.getStdErrAsString()).isEmpty(); assertThat(fn.exitStatus()).isZero(); } @Test public void instanceTargetWithStaticConfigurationIsOK() throws Exception { - fn.givenDefaultEvent().withBody("Hello World").enqueue(); + fn.givenEvent().withBody("Hello World").enqueue(); fn.thenRun(TestFnWithConfigurationMethods.InstanceTargetStaticConfiguration.class, "echo"); - assertThat(fn.getStdOutAsString()).isEqualTo("InstanceTargetStaticConfiguration\nHello World"); + assertThat(fn.getOnlyOutputAsString()).isEqualTo("InstanceTargetStaticConfiguration\nHello World"); assertThat(fn.getStdErrAsString()).isEmpty(); assertThat(fn.exitStatus()).isZero(); } @Test public void staticTargetWithInstanceConfigurationIsAnError() throws Exception { - fn.givenDefaultEvent().withBody("Hello World").enqueue(); + fn.givenEvent().withBody("Hello World").enqueue(); String expectedMessage = "Configuration method " + "'config'" + @@ -68,78 +68,78 @@ public void staticTargetWithInstanceConfigurationIsAnError() throws Exception { fn.thenRun(TestFnWithConfigurationMethods.StaticTargetInstanceConfiguration.class, "echo"); - assertThat(fn.getStdOutAsString()).isEmpty(); + assertThat(fn.getOutputs()).isEmpty(); assertThat(fn.getStdErrAsString()).startsWith(expectedMessage); assertThat(fn.exitStatus()).isEqualTo(2); } @Test public void instanceTargetWithInstanceConfigurationIsOK() throws Exception { - fn.givenDefaultEvent().withBody("Hello World").enqueue(); + fn.givenEvent().withBody("Hello World").enqueue(); fn.thenRun(TestFnWithConfigurationMethods.InstanceTargetInstanceConfiguration.class, "echo"); - assertThat(fn.getStdOutAsString()).isEqualTo("InstanceTargetInstanceConfiguration\nHello World"); + assertThat(fn.getOnlyOutputAsString()).isEqualTo("InstanceTargetInstanceConfiguration\nHello World"); assertThat(fn.getStdErrAsString()).isEmpty(); assertThat(fn.exitStatus()).isZero(); } @Test public void staticTargetWithStaticConfigurationWithoutRuntimeContextParameterIsOK() throws Exception { - fn.givenDefaultEvent().withBody("Hello World").enqueue(); + fn.givenEvent().withBody("Hello World").enqueue(); fn.thenRun(TestFnWithConfigurationMethods.StaticTargetStaticConfigurationNoRuntime.class, "echo"); - assertThat(fn.getStdOutAsString()).isEqualTo("StaticTargetStaticConfigurationNoRuntime\nHello World"); + assertThat(fn.getOnlyOutputAsString()).isEqualTo("StaticTargetStaticConfigurationNoRuntime\nHello World"); assertThat(fn.getStdErrAsString()).isEmpty(); assertThat(fn.exitStatus()).isZero(); } @Test public void instanceTargetWithStaticConfigurationWithoutRuntimeContextParameterIsOK() throws Exception { - fn.givenDefaultEvent().withBody("Hello World").enqueue(); + fn.givenEvent().withBody("Hello World").enqueue(); fn.thenRun(TestFnWithConfigurationMethods.InstanceTargetStaticConfigurationNoRuntime.class, "echo"); - assertThat(fn.getStdOutAsString()).isEqualTo("InstanceTargetStaticConfigurationNoRuntime\nHello World"); + assertThat(fn.getOnlyOutputAsString()).isEqualTo("InstanceTargetStaticConfigurationNoRuntime\nHello World"); assertThat(fn.getStdErrAsString()).isEmpty(); assertThat(fn.exitStatus()).isZero(); } @Test public void instanceTargetWithInstanceConfigurationWithoutRuntimeContextParameterIsOK() throws Exception { - fn.givenDefaultEvent().withBody("Hello World").enqueue(); + fn.givenEvent().withBody("Hello World").enqueue(); fn.thenRun(TestFnWithConfigurationMethods.InstanceTargetInstanceConfigurationNoRuntime.class, "echo"); - assertThat(fn.getStdOutAsString()).isEqualTo("InstanceTargetInstanceConfigurationNoRuntime\nHello World"); + assertThat(fn.getOnlyOutputAsString()).isEqualTo("InstanceTargetInstanceConfigurationNoRuntime\nHello World"); assertThat(fn.getStdErrAsString()).isEmpty(); assertThat(fn.exitStatus()).isZero(); } @Test public void shouldReturnDefaultParameterIfNotProvided() { - fn.givenDefaultEvent().enqueue(); + fn.givenEvent().enqueue(); fn.thenRun(TestFnWithConfigurationMethods.WithGetConfigurationByKey.class, "getParam"); - assertThat(fn.getStdOutAsString()).isEqualTo("default"); + assertThat(fn.getOnlyOutputAsString()).isEqualTo("default"); } @Test public void shouldReturnSetConfigParameterWhenProvided() { String value = "value"; fn.setConfig("PARAM", value); - fn.givenDefaultEvent().enqueue(); + fn.givenEvent().enqueue(); fn.thenRun(TestFnWithConfigurationMethods.WithGetConfigurationByKey.class, "getParam"); - assertThat(fn.getStdOutAsString()).isEqualTo(value); + assertThat(fn.getOnlyOutputAsString()).isEqualTo(value); } @Test public void nonVoidConfigurationMethodIsAnError() throws Exception { - fn.givenDefaultEvent().withBody("Hello World").enqueue(); + fn.givenEvent().withBody("Hello World").enqueue(); fn.thenRun(TestFnWithConfigurationMethods.ConfigurationMethodIsNonVoid.class, "echo"); @@ -147,7 +147,7 @@ public void nonVoidConfigurationMethodIsAnError() throws Exception { "'config'" + " does not have a void return type"; - assertThat(fn.getStdOutAsString()).isEmpty(); + assertThat(fn.getOutputs()).isEmpty(); assertThat(fn.getStdErrAsString()).startsWith(expectedMessage); assertThat(fn.exitStatus()).isEqualTo(2); } @@ -156,13 +156,13 @@ public void nonVoidConfigurationMethodIsAnError() throws Exception { @Test public void shouldBeAbleToAccessConfigInConfigurationMethodWhenDefault() { fn.setConfig("FOO", "BAR"); - fn.givenDefaultEvent() + fn.givenEvent() .withBody("FOO") .enqueue(); fn.thenRun(TestFnWithConfigurationMethods.ConfigurationMethodWithAccessToConfig.class, "configByKey"); - assertThat(fn.getStdOutAsString()).isEqualTo("ConfigurationMethodWithAccessToConfig\nBAR"); + assertThat(fn.getOnlyOutputAsString()).isEqualTo("ConfigurationMethodWithAccessToConfig\nBAR"); } @Test @@ -174,7 +174,7 @@ public void shouldBeAbleToAccessConfigInConfigurationMethodWhenHttp() { fn.thenRun(TestFnWithConfigurationMethods.ConfigurationMethodWithAccessToConfig.class, "configByKey"); - assertThat(fn.getStdOutAsString()).contains("ConfigurationMethodWithAccessToConfig\nBAR"); + assertThat(fn.getOnlyOutputAsString()).contains("ConfigurationMethodWithAccessToConfig\nBAR"); } @Test @@ -186,19 +186,19 @@ public void shouldOnlyExtractConfigFromEnvironmentNotHeaderWhenHttp() { fn.thenRun(TestFnWithConfigurationMethods.ConfigurationMethodWithAccessToConfig.class, "configByKey"); - assertThat(fn.getStdOutAsString()).doesNotContain("BAR"); + assertThat(fn.getOnlyOutputAsString()).doesNotContain("BAR"); } @Test public void shouldNotBeAbleToAccessHeadersInConfigurationWhenDefault() { - fn.givenDefaultEvent() + fn.givenEvent() .withHeader("FOO", "BAR") .withBody("HEADER_FOO") .enqueue(); fn.thenRun(TestFnWithConfigurationMethods.ConfigurationMethodWithAccessToConfig.class, "configByKey"); - assertThat(fn.getStdOutAsString()).doesNotContain("ConfigurationMethodWithAccessToConfig\nBAR"); + assertThat(fn.getOnlyOutputAsString()).doesNotContain("ConfigurationMethodWithAccessToConfig\nBAR"); } @Test @@ -210,18 +210,18 @@ public void shouldNotBeAbleToAccessHeadersInConfigurationWhenHttp() { fn.thenRun(TestFnWithConfigurationMethods.ConfigurationMethodWithAccessToConfig.class, "configByKey"); - assertThat(fn.getStdOutAsString()).doesNotContain("ConfigurationMethodWithAccessToConfig\nBAR"); + assertThat(fn.getOnlyOutputAsString()).doesNotContain("ConfigurationMethodWithAccessToConfig\nBAR"); } @Test public void shouldCallInheritedConfigMethodsInRightOrder() { - fn.givenDefaultEvent().enqueue(); + fn.givenEvent().enqueue(); TestFnWithConfigurationMethods.SubConfigClass.order = ""; fn.thenRun(TestFnWithConfigurationMethods.SubConfigClass.class, "invoke"); - assertThat(fn.getStdOutAsString()).isEqualTo("OK"); + assertThat(fn.getOnlyOutputAsString()).isEqualTo("OK"); assertThat(TestFnWithConfigurationMethods.SubConfigClass.order) .matches("\\.baseStatic1\\.subStatic1\\.baseFn\\d\\.baseFn\\d\\.subFn\\d\\.subFn\\d\\.subFn\\d\\.subFn\\d"); } diff --git a/runtime/src/test/java/com/fnproject/fn/runtime/DataBindingTest.java b/runtime/src/test/java/com/fnproject/fn/runtime/DataBindingTest.java index 559af89d..da49acbc 100644 --- a/runtime/src/test/java/com/fnproject/fn/runtime/DataBindingTest.java +++ b/runtime/src/test/java/com/fnproject/fn/runtime/DataBindingTest.java @@ -16,132 +16,132 @@ public class DataBindingTest { @Test public void shouldUseInputCoercionSpecifiedOnFunctionRuntimeContext() throws Exception { - fn.givenDefaultEvent().withBody("Hello World").enqueue(); + fn.givenEvent().withBody("Hello World").enqueue(); fn.thenRun(CustomDataBindingFnWithConfig.class, "echo"); - assertThat(fn.getStdOutAsString()).isEqualTo("dlroW olleH"); + assertThat(fn.getOnlyOutputAsString()).isEqualTo("dlroW olleH"); assertThat(fn.getStdErrAsString()).isEmpty(); assertThat(fn.exitStatus()).isZero(); } @Test public void shouldUseInputCoercionSpecifiedWithAnnotation() throws Exception { - fn.givenDefaultEvent().withBody("Hello World").enqueue(); + fn.givenEvent().withBody("Hello World").enqueue(); fn.thenRun(CustomDataBindingFnWithAnnotation.class, "echo"); - assertThat(fn.getStdOutAsString()).isEqualTo("dlroW olleH"); + assertThat(fn.getOnlyOutputAsString()).isEqualTo("dlroW olleH"); assertThat(fn.getStdErrAsString()).isEmpty(); assertThat(fn.exitStatus()).isZero(); } @Test public void shouldUseOutputCoercionSpecifiedOnFunctionRuntimeContext() throws Exception { - fn.givenDefaultEvent().withBody("Hello World").enqueue(); + fn.givenEvent().withBody("Hello World").enqueue(); fn.thenRun(CustomOutputDataBindingFnWithConfig.class, "echo"); - assertThat(fn.getStdOutAsString()).isEqualTo("dlroW olleH"); + assertThat(fn.getOnlyOutputAsString()).isEqualTo("dlroW olleH"); assertThat(fn.getStdErrAsString()).isEmpty(); assertThat(fn.exitStatus()).isZero(); } @Test public void shouldUseOutputCoercionSpecifiedWithAnnotation() throws Exception { - fn.givenDefaultEvent().withBody("Hello World").enqueue(); + fn.givenEvent().withBody("Hello World").enqueue(); fn.thenRun(CustomOutputDataBindingFnWithAnnotation.class, "echo"); - assertThat(fn.getStdOutAsString()).isEqualTo("dlroW olleH"); + assertThat(fn.getOnlyOutputAsString()).isEqualTo("dlroW olleH"); assertThat(fn.getStdErrAsString()).isEmpty(); assertThat(fn.exitStatus()).isZero(); } @Test public void shouldUseFirstInputCoercionSpecifiedOnFunctionRuntimeContext() throws Exception { - fn.givenDefaultEvent().withBody("Hello World").enqueue(); + fn.givenEvent().withBody("Hello World").enqueue(); fn.thenRun(CustomDataBindingFnWithMultipleCoercions.class, "echo"); - assertThat(fn.getStdOutAsString()).isEqualTo("HELLO WORLD"); + assertThat(fn.getOnlyOutputAsString()).isEqualTo("HELLO WORLD"); assertThat(fn.getStdErrAsString()).isEmpty(); assertThat(fn.exitStatus()).isZero(); } @Test public void shouldUseFirstOutputCoercionSpecifiedOnFunctionRuntimeContext() throws Exception { - fn.givenDefaultEvent().withBody("Hello World").enqueue(); + fn.givenEvent().withBody("Hello World").enqueue(); fn.thenRun(CustomOutputDataBindingFnWithMultipleCoercions.class, "echo"); - assertThat(fn.getStdOutAsString()).isEqualTo("HELLO WORLD"); + assertThat(fn.getOnlyOutputAsString()).isEqualTo("HELLO WORLD"); assertThat(fn.getStdErrAsString()).isEmpty(); assertThat(fn.exitStatus()).isZero(); } @Test public void shouldUseBuiltInInputCoercionSpecifiedOnFunctionRuntimeContext() throws Exception { - fn.givenDefaultEvent().withBody("Hello World").enqueue(); + fn.givenEvent().withBody("Hello World").enqueue(); fn.thenRun(CustomDataBindingFnWithNoUserCoersions.class, "echo"); - assertThat(fn.getStdOutAsString()).isEqualTo("Hello World"); + assertThat(fn.getOnlyOutputAsString()).isEqualTo("Hello World"); assertThat(fn.getStdErrAsString()).isEmpty(); assertThat(fn.exitStatus()).isZero(); } @Test public void shouldUseBuiltInOutputCoercionSpecifiedOnFunctionRuntimeContext() throws Exception { - fn.givenDefaultEvent().withBody("Hello World").enqueue(); + fn.givenEvent().withBody("Hello World").enqueue(); fn.thenRun(CustomOutputDataBindingFnWithNoUserCoercions.class, "echo"); - assertThat(fn.getStdOutAsString()).isEqualTo("Hello World"); + assertThat(fn.getOnlyOutputAsString()).isEqualTo("Hello World"); assertThat(fn.getStdErrAsString()).isEmpty(); assertThat(fn.exitStatus()).isZero(); } @Test public void shouldUseSecondInputCoercionSpecifiedOnFunctionRuntimeContext() throws Exception { - fn.givenDefaultEvent().withBody("Hello World").enqueue(); + fn.givenEvent().withBody("Hello World").enqueue(); fn.thenRun(CustomDataBindingFnWithDudCoercion.class, "echo"); - assertThat(fn.getStdOutAsString()).isEqualTo("dlroW olleH"); + assertThat(fn.getOnlyOutputAsString()).isEqualTo("dlroW olleH"); assertThat(fn.getStdErrAsString()).isEmpty(); assertThat(fn.exitStatus()).isZero(); } @Test public void shouldUseSecondOutputCoercionSpecifiedOnFunctionRuntimeContext() throws Exception { - fn.givenDefaultEvent().withBody("Hello World").enqueue(); + fn.givenEvent().withBody("Hello World").enqueue(); fn.thenRun(CustomOutputDataBindingFnWithDudCoercion.class, "echo"); - assertThat(fn.getStdOutAsString()).isEqualTo("dlroW olleH"); + assertThat(fn.getOnlyOutputAsString()).isEqualTo("dlroW olleH"); assertThat(fn.getStdErrAsString()).isEmpty(); assertThat(fn.exitStatus()).isZero(); } @Test public void shouldApplyCoercionsForInputAndOutputSpecifiedOnFunctionRuntimeContext() throws Exception { - fn.givenDefaultEvent().withBody("Hello World").enqueue(); + fn.givenEvent().withBody("Hello World").enqueue(); fn.thenRun(CustomDataBindingFnInputOutput.class, "echo"); - assertThat(fn.getStdOutAsString()).isEqualTo("DLROW OLLEH"); + assertThat(fn.getOnlyOutputAsString()).isEqualTo("DLROW OLLEH"); assertThat(fn.getStdErrAsString()).isEmpty(); assertThat(fn.exitStatus()).isZero(); } @Test public void shouldPrioritiseAnnotationOverConfig() throws Exception { - fn.givenDefaultEvent().withBody("Hello World").enqueue(); + fn.givenEvent().withBody("Hello World").enqueue(); fn.thenRun(CustomDataBindingFnWithAnnotationAndConfig.class, "echo"); - assertThat(fn.getStdOutAsString()).isEqualTo("HELLO WORLD"); + assertThat(fn.getOnlyOutputAsString()).isEqualTo("HELLO WORLD"); assertThat(fn.getStdErrAsString()).isEmpty(); assertThat(fn.exitStatus()).isZero(); } diff --git a/runtime/src/test/java/com/fnproject/fn/runtime/DefaultEventCodecTest.java b/runtime/src/test/java/com/fnproject/fn/runtime/DefaultEventCodecTest.java index b7992114..eccf2af5 100644 --- a/runtime/src/test/java/com/fnproject/fn/runtime/DefaultEventCodecTest.java +++ b/runtime/src/test/java/com/fnproject/fn/runtime/DefaultEventCodecTest.java @@ -2,7 +2,6 @@ import com.fnproject.fn.api.InputEvent; import com.fnproject.fn.api.OutputEvent; -import com.fnproject.fn.api.exception.FunctionInputHandlingException; import org.apache.commons.io.input.NullInputStream; import org.apache.commons.io.output.NullOutputStream; import org.junit.Test; @@ -16,7 +15,6 @@ import static com.fnproject.fn.runtime.HeaderBuilder.headerEntry; import static org.assertj.core.api.Assertions.assertThat; -import static org.junit.Assert.fail; public class DefaultEventCodecTest { @@ -29,11 +27,6 @@ private InputStream asStream(String s) { public void shouldExtractBasicEvent() { Map env = new HashMap<>(); env.put("FN_FORMAT", "default"); - env.put("FN_METHOD", "GET"); - env.put("FN_APP_NAME", "testapp"); - env.put("FN_PATH", "/route"); - env.put("FN_REQUEST_URL", "http://test.com/fn/tryInvoke"); - env.put("FN_HEADER_CONTENT_TYPE", "text/plain"); env.put("FN_HEADER_ACCEPT", "text/html, text/plain;q=0.9"); env.put("FN_HEADER_ACCEPT_ENCODING", "gzip"); @@ -44,56 +37,25 @@ public void shouldExtractBasicEvent() { config.put("CONFIGPARAM", "CONFIGVAL"); DefaultEventCodec codec = new DefaultEventCodec(env, asStream("input"), new NullOutputStream()); - InputEvent evt = codec.readEvent().get(); - assertThat(evt.getMethod()).isEqualTo("GET"); - assertThat(evt.getAppName()).isEqualTo("testapp"); - assertThat(evt.getRoute()).isEqualTo("/route"); - assertThat(evt.getRequestUrl()).isEqualTo("http://test.com/fn/tryInvoke"); + InputEvent evt = codec.readEvent(); - assertThat(evt.getHeaders().getAll().size()).isEqualTo(4); - assertThat(evt.getHeaders().getAll()).contains( + assertThat(evt.getHeaders().asMap().size()).isEqualTo(4); + assertThat(evt.getHeaders().asMap()).contains( headerEntry("CONTENT_TYPE", "text/plain"), headerEntry("ACCEPT_ENCODING", "gzip"), headerEntry("ACCEPT", "text/html, text/plain;q=0.9"), headerEntry("USER_AGENT", "userAgent")); evt.consumeBody((body) -> assertThat(body).hasSameContentAs(asStream("input"))); - - assertThat(codec.shouldContinue()).isFalse(); } - @Test - public void shouldRejectMissingEnv() { - Map requiredEnv = new HashMap<>(); - - requiredEnv.put("FN_PATH", "/route"); - requiredEnv.put("FN_METHOD", "GET"); - requiredEnv.put("FN_APP_NAME", "app_name"); - requiredEnv.put("FN_REQUEST_URL", "http://test.com/fn/tryInvoke"); - - for (String key : requiredEnv.keySet()) { - Map newEnv = new HashMap<>(requiredEnv); - newEnv.remove(key); - - DefaultEventCodec codec = new DefaultEventCodec(newEnv, asStream("input"), new NullOutputStream()); - - try{ - codec.readEvent(); - fail("Should have rejected missing env "+ key); - }catch(FunctionInputHandlingException e){ - assertThat(e).hasMessageContaining("Required environment variable " + key+ " is not set - are you running a function outside of fn run?"); - } - } - - } - @Test public void shouldWriteOutputDirectlyToOutputStream() throws IOException{ - OutputEvent evt = OutputEvent.fromBytes("hello".getBytes(),OutputEvent.SUCCESS,"text/plain"); + OutputEvent evt = OutputEvent.fromBytes("hello".getBytes(),OutputEvent.Status.Success,"text/plain"); ByteArrayOutputStream bos = new ByteArrayOutputStream(); DefaultEventCodec codec = new DefaultEventCodec(new HashMap<>(), new NullInputStream(0),bos); diff --git a/runtime/src/test/java/com/fnproject/fn/runtime/EndToEndInvokeTest.java b/runtime/src/test/java/com/fnproject/fn/runtime/EndToEndInvokeTest.java index 1a019b47..d68f14c7 100644 --- a/runtime/src/test/java/com/fnproject/fn/runtime/EndToEndInvokeTest.java +++ b/runtime/src/test/java/com/fnproject/fn/runtime/EndToEndInvokeTest.java @@ -27,13 +27,13 @@ public static void setup() { @Test public void shouldResolveTestCallWithEnvVarParams() throws Exception { - fn.givenDefaultEvent().withBody("Hello World").enqueue(); + fn.givenEvent().withBody("Hello World").enqueue(); TestFn.setOutput("Hello World Out"); fn.thenRun(TestFn.class, "fnStringInOut"); assertThat(TestFn.getInput()).isEqualTo("Hello World"); - assertThat(fn.getStdOutAsString()).isEqualTo("Hello World Out"); + assertThat(fn.getOnlyOutputAsString()).isEqualTo("Hello World Out"); assertThat(fn.getStdErrAsString()).isEmpty(); assertThat(fn.exitStatus()).isZero(); } @@ -50,85 +50,81 @@ public void shouldResolveTestCallFromHotCall() throws Exception { @Test public void shouldSerializeGenericCollections() throws Exception { - fn.givenDefaultEvent().withBody("four").enqueue(); + fn.givenEvent().withBody("four").enqueue(); fn.thenRun(TestFn.class, "fnGenericCollections"); - assertThat(fn.getStdOutAsString()).isEqualTo("[\"one\",\"two\",\"three\",\"four\"]"); + assertThat(fn.getOnlyOutputAsString()).isEqualTo("[\"one\",\"two\",\"three\",\"four\"]"); } @Test public void shouldSerializeAnimalCollections() throws Exception { - fn.givenDefaultEvent().enqueue(); + fn.givenEvent().enqueue(); fn.thenRun(TestFn.class, "fnGenericAnimal"); - assertThat(fn.getStdOutAsString()).isEqualTo("[{\"name\":\"Spot\",\"age\":6},{\"name\":\"Jason\",\"age\":16}]"); + assertThat(fn.getOnlyOutputAsString()).isEqualTo("[{\"name\":\"Spot\",\"age\":6},{\"name\":\"Jason\",\"age\":16}]"); } @Test public void shouldDeserializeGenericCollections() throws Exception { - fn.givenDefaultEvent() - .withHeader("Content-type", "application/json") - .withBody("[\"one\",\"two\",\"three\",\"four\"]") - .enqueue(); + fn.givenEvent() + .withHeader("Content-type", "application/json") + .withBody("[\"one\",\"two\",\"three\",\"four\"]") + .enqueue(); fn.thenRun(TestFn.class, "fnGenericCollectionsInput"); - assertThat(fn.getStdOutAsString()).isEqualTo("ONE"); + assertThat(fn.getOnlyOutputAsString()).isEqualTo("ONE"); } @Test public void shouldDeserializeCustomObjects() throws Exception { - fn.givenDefaultEvent() - .withHeader("Content-type", "application/json") - .withBody("[{\"name\":\"Spot\",\"age\":6},{\"name\":\"Jason\",\"age\":16}]") - .enqueue(); + fn.givenEvent() + .withHeader("Content-type", "application/json") + .withBody("[{\"name\":\"Spot\",\"age\":6},{\"name\":\"Jason\",\"age\":16}]") + .enqueue(); fn.thenRun(TestFn.class, "fnCustomObjectsCollectionsInput"); - assertThat(fn.getStdOutAsString()).isEqualTo("Spot"); + assertThat(fn.getOnlyOutputAsString()).isEqualTo("Spot"); } @Test public void shouldDeserializeComplexCustomObjects() throws Exception { - fn.givenDefaultEvent() - .withHeader("Content-type", "application/json") - .withBody("{\"number1\":[{\"name\":\"Spot\",\"age\":6}]," + - "\"number2\":[{\"name\":\"Spot\",\"age\":16}]}") - .enqueue(); + fn.givenEvent() + .withHeader("Content-type", "application/json") + .withBody("{\"number1\":[{\"name\":\"Spot\",\"age\":6}]," + + "\"number2\":[{\"name\":\"Spot\",\"age\":16}]}") + .enqueue(); fn.thenRun(TestFn.class, "fnCustomObjectsNestedCollectionsInput"); - assertThat(fn.getStdOutAsString()).isEqualTo("Spot"); + assertThat(fn.getOnlyOutputAsString()).isEqualTo("Spot"); } @Test public void shouldHandledStreamedHotInputEvent() throws Exception { fn.givenEvent() - .withBody("message1") - .withMethod("POST") - .enqueue(); + .withBody("message1") + .enqueue(); fn.givenEvent() - .withBody("message2") - .withMethod("GET") - .enqueue(); + .withBody("message2") + .enqueue(); - fn.thenRun(TestFn.class,"fnEcho"); + fn.thenRun(TestFn.class, "fnEcho"); - List responses = fn.getParsedHttpResponses(); + List responses = fn.getOutputs(); assertThat(responses).size().isEqualTo(2); - FnTestHarness.ParsedHttpResponse r1 = responses.get(0); - assertThat(r1.getBodyAsString()).isEqualTo("message1"); - - FnTestHarness.ParsedHttpResponse r2 = responses.get(1); - assertThat(r2.getBodyAsString()).isEqualTo("message2"); - + FnTestHarness.TestOutput r1 = responses.get(0); + assertThat(new String(r1.getBody())).isEqualTo("message1"); + FnTestHarness.TestOutput r2 = responses.get(1); + assertThat(new String(r2.getBody())).isEqualTo("message2"); } @@ -136,12 +132,10 @@ public void shouldHandledStreamedHotInputEvent() throws Exception { @Test public void shouldPrintErrorOnUnknownMethod() throws Exception { - - fn.thenRun(TestFn.class, "unknownMethod"); - assertThat(fn.getStdOutAsString()).isEqualTo(""); + assertThat(fn.exitStatus()).isEqualTo(2); + assertThat(fn.getOutputs()).isEmpty(); assertThat(fn.getStdErrAsString()).startsWith("Method 'unknownMethod' was not found in class 'com.fnproject.fn.runtime.testfns.TestFn'"); - } @@ -150,8 +144,8 @@ public void shouldPrintErrorOnUnknownClass() throws Exception { fn.thenRun("com.fnproject.unknown.Class", "unknownMethod"); - - assertThat(fn.getStdOutAsString()).isEqualTo(""); + assertThat(fn.exitStatus()).isEqualTo(2); + assertThat(fn.getOutputs()).hasSize(0); assertThat(fn.getStdErrAsString()).startsWith("Class 'com.fnproject.unknown.Class' not found in function jar"); } @@ -159,32 +153,32 @@ public void shouldPrintErrorOnUnknownClass() throws Exception { @Test public void shouldDirectStdOutToStdErrForFunctions() throws Exception { - fn.givenDefaultEvent().enqueue(); + fn.givenEvent().enqueue(); fn.thenRun(TestFn.class, "fnWritesToStdout"); - assertThat(fn.getStdOutAsString()).isEqualTo(""); + assertThat(fn.getOnlyOutputAsString()).isEqualTo(""); assertThat(fn.getStdErrAsString()).isEqualTo("STDOUT"); } @Test public void shouldTerminateDefaultContainerOnExceptionWithError() throws Exception { - fn.givenDefaultEvent().enqueue(); + fn.givenEvent().enqueue(); fn.thenRun(TestFn.class, "fnThrowsException"); assertThat(fn.getStdErrAsString()).startsWith("An error occurred in function:"); - assertThat(fn.getStdOutAsString()).isEmpty(); + assertThat(fn.getOnlyOutputAsString()).isEmpty(); assertThat(fn.exitStatus()).isEqualTo(1); } @Test public void shouldReadJsonObject() throws Exception { - fn.givenDefaultEvent() - .withHeader("Content-type", "application/json") - .withBody("{\"foo\":\"bar\"}") - .enqueue(); + fn.givenEvent() + .withHeader("Content-type", "application/json") + .withBody("{\"foo\":\"bar\"}") + .enqueue(); fn.thenRun(TestFn.class, "fnReadsJsonObj"); @@ -194,21 +188,21 @@ public void shouldReadJsonObject() throws Exception { @Test public void shouldWriteJsonData() throws Exception { - fn.givenDefaultEvent().enqueue(); + fn.givenEvent().enqueue(); TestFn.JsonData data = new TestFn.JsonData(); data.foo = "bar"; TestFn.setOutput(data); fn.thenRun(TestFn.class, "fnWritesJsonObj"); - assertThat(fn.getStdOutAsString()).isEqualTo("{\"foo\":\"bar\"}"); + assertThat(fn.getOnlyOutputAsString()).isEqualTo("{\"foo\":\"bar\"}"); } @Test public void shouldReadBytesOnDefaultCodec() throws Exception { - fn.givenDefaultEvent().withBody("Hello World").enqueue(); + fn.givenEvent().withBody("Hello World").enqueue(); fn.thenRun(TestFn.class, "fnReadsBytes"); @@ -219,12 +213,12 @@ public void shouldReadBytesOnDefaultCodec() throws Exception { @Test public void shouldWriteBytesOnDefaultCodec() throws Exception { - fn.givenDefaultEvent().withBody("Hello World").enqueue(); + fn.givenEvent().withBody("Hello World").enqueue(); TestFn.setOutput("OK".getBytes()); fn.thenRun(TestFn.class, "fnWritesBytes"); - assertThat(fn.getStdOutAsString()).isEqualTo("OK"); + assertThat(fn.getOnlyOutputAsString()).isEqualTo("OK"); } @@ -232,18 +226,18 @@ public void shouldWriteBytesOnDefaultCodec() throws Exception { @Test public void shouldRejectDuplicateMethodsInFunctionClass() throws Exception { - fn.thenRun(BadTestFnDuplicateMethods.class,"fn"); - - assertThat(fn.getStdOutAsString()).isEmpty(); + fn.thenRun(BadTestFnDuplicateMethods.class, "fn"); + assertThat(fn.getOutputs()).isEmpty(); + assertThat(fn.exitStatus()).isEqualTo(2); assertThat(fn.getStdErrAsString()).startsWith("Multiple methods match"); } @Test public void shouldReadRawJson() throws Exception { - fn.givenDefaultEvent() - .withHeader("Content-type", "application/json") - .withBody("[\"foo\",\"bar\"]") - .enqueue(); + fn.givenEvent() + .withHeader("Content-type", "application/json") + .withBody("[\"foo\",\"bar\"]") + .enqueue(); fn.thenRun(TestFn.class, "fnReadsRawJson"); @@ -253,24 +247,4 @@ public void shouldReadRawJson() throws Exception { } - - @Test - public void shouldReadMultipleMessageWhenInputIsNotParsed() throws Exception { - fn.givenHttpEvent().withBody("Hello World 1").enqueue(); - fn.givenHttpEvent().withBody("Hello World 2").enqueue(); - - - fn.thenRun(TestFn.class, "readSecondInput"); - - List results = fn.getParsedHttpResponses(); - assertThat(results).hasSize(2); - assertThat(results.get(0).getStatus()).isEqualTo(200); - assertThat(results.get(0).getBodyAsString()).isEqualTo("first;"); - assertThat(results.get(1).getStatus()).isEqualTo(200); - assertThat(results.get(1).getBodyAsString()).isEqualTo("Hello World 2"); - - - } - - } diff --git a/runtime/src/test/java/com/fnproject/fn/runtime/ErrorMessagesTest.java b/runtime/src/test/java/com/fnproject/fn/runtime/ErrorMessagesTest.java index f4f96c07..5809ae20 100644 --- a/runtime/src/test/java/com/fnproject/fn/runtime/ErrorMessagesTest.java +++ b/runtime/src/test/java/com/fnproject/fn/runtime/ErrorMessagesTest.java @@ -54,21 +54,21 @@ public void userSpecifiesMethodWhichDoesNotExist(){ @Test public void userFunctionInputCoercionError(){ - fn.givenDefaultEvent().withBody("This is not a...").enqueue(); + fn.givenEvent().withBody("This is not a...").enqueue(); fn.thenRun(ErrorMessages.OtherMethodsClass.class, "takesAnInteger"); assertIsEntrypointErrorWithStacktrace("An exception was thrown during Input Coercion: Failed to coerce event to user function parameter type class java.lang.Integer"); } @Test public void objectConstructionThrowsARuntimeException(){ - fn.givenDefaultEvent().enqueue(); + fn.givenEvent().enqueue(); fn.thenRun(StacktraceFilteringTestFunctions.ExceptionInConstructor.class, "invoke"); assertIsEntrypointErrorWithStacktrace("Whoops"); } @Test public void objectConstructionThrowsADeepException(){ - fn.givenDefaultEvent().enqueue(); + fn.givenEvent().enqueue(); fn.thenRun(StacktraceFilteringTestFunctions.DeepExceptionInConstructor.class, "invoke"); assertIsEntrypointErrorWithStacktrace("Inside a method called by the constructor"); assertThat(fn.getStdErrAsString()).contains("at not.in.com.fnproject.fn.StacktraceFilteringTestFunctions$DeepExceptionInConstructor.naughtyMethod"); @@ -77,7 +77,7 @@ public void objectConstructionThrowsADeepException(){ @Test public void objectConstructionThrowsANestedException(){ - fn.givenDefaultEvent().enqueue(); + fn.givenEvent().enqueue(); fn.thenRun(StacktraceFilteringTestFunctions.NestedExceptionInConstructor.class, "invoke"); assertIsEntrypointErrorWithStacktrace("Caused by: java.lang.RuntimeException: Oh no!"); assertThat(fn.getStdErrAsString()).contains("at not.in.com.fnproject.fn.StacktraceFilteringTestFunctions$NestedExceptionInConstructor.naughtyMethod"); @@ -88,14 +88,14 @@ public void objectConstructionThrowsANestedException(){ @Test public void fnConfigurationThrowsARuntimeException(){ - fn.givenDefaultEvent().enqueue(); + fn.givenEvent().enqueue(); fn.thenRun(StacktraceFilteringTestFunctions.ExceptionInConfiguration.class, "invoke"); assertIsEntrypointErrorWithStacktrace("Caused by: java.lang.RuntimeException: Config fail"); } @Test public void fnConfigurationThrowsADeepException(){ - fn.givenDefaultEvent().enqueue(); + fn.givenEvent().enqueue(); fn.thenRun(StacktraceFilteringTestFunctions.DeepExceptionInConfiguration.class, "invoke"); assertIsEntrypointErrorWithStacktrace("Caused by: java.lang.RuntimeException: Deep config fail"); assertThat(fn.getStdErrAsString()).contains("at not.in.com.fnproject.fn.StacktraceFilteringTestFunctions$DeepExceptionInConfiguration.throwDeep"); @@ -104,7 +104,7 @@ public void fnConfigurationThrowsADeepException(){ @Test public void fnConfigurationThrowsANestedException(){ - fn.givenDefaultEvent().enqueue(); + fn.givenEvent().enqueue(); fn.thenRun(StacktraceFilteringTestFunctions.NestedExceptionInConfiguration.class, "invoke"); assertIsEntrypointErrorWithStacktrace("Error invoking configuration method: config"); assertThat(fn.getStdErrAsString()).contains("Caused by: java.lang.RuntimeException: nested at 3"); @@ -116,7 +116,7 @@ public void fnConfigurationThrowsANestedException(){ @Test public void functionThrowsNestedException(){ - fn.givenDefaultEvent().enqueue(); + fn.givenEvent().enqueue(); fn.thenRun(StacktraceFilteringTestFunctions.CauseStackTraceInResult.class, "invoke"); assertIsFunctionErrorWithStacktrace("An error occurred in function: Throw two"); assertThat(fn.getStdErrAsString()).contains("Caused by: java.lang.RuntimeException: Throw two"); diff --git a/runtime/src/test/java/com/fnproject/fn/runtime/FnTestHarness.java b/runtime/src/test/java/com/fnproject/fn/runtime/FnTestHarness.java index 5434029e..5ee6b8e2 100644 --- a/runtime/src/test/java/com/fnproject/fn/runtime/FnTestHarness.java +++ b/runtime/src/test/java/com/fnproject/fn/runtime/FnTestHarness.java @@ -1,29 +1,25 @@ package com.fnproject.fn.runtime; -import org.apache.commons.io.IOUtils; +import com.fnproject.fn.api.Headers; +import com.fnproject.fn.api.InputEvent; +import com.fnproject.fn.api.OutputEvent; import org.apache.commons.io.output.TeeOutputStream; -import org.apache.http.HttpResponse; -import org.apache.http.NoHttpResponseException; -import org.apache.http.impl.io.ContentLengthInputStream; -import org.apache.http.impl.io.DefaultHttpResponseParser; -import org.apache.http.impl.io.HttpTransportMetricsImpl; -import org.apache.http.impl.io.SessionInputBufferImpl; import org.junit.rules.TestRule; import org.junit.runner.Description; import org.junit.runners.model.Statement; import java.io.*; +import java.time.Instant; +import java.time.temporal.ChronoUnit; import java.util.*; /** - * Function testing harness - this provides the call-side of iron functions' process contract for both HTTP and default type functions + * Function internal testing harness - this provides access the call-side of the functions contract excluding the codec which is mocked */ public class FnTestHarness implements TestRule { - private Map vars = new HashMap<>(); - private boolean hasEvents = false; - private InputStream pendingInput = new ByteArrayInputStream(new byte[0]); - private ByteArrayOutputStream stdOut = new ByteArrayOutputStream(); + private List pendingInput = Collections.synchronizedList(new ArrayList<>()); + private List output = Collections.synchronizedList(new ArrayList<>()); private ByteArrayOutputStream stdErr = new ByteArrayOutputStream(); private int exitStatus = -1; @@ -46,25 +42,28 @@ public void setConfig(String key, String value) { /** * Gets a function config variable by key, or null if absent * - * @param key the configuration key + * @param key the configuration key */ public String getConfig(String key) { return config.get(key.toUpperCase().replaceAll("[- ]", "_")); } + public String getOnlyOutputAsString() { + if (output.size() != 1) { + throw new IllegalStateException("expecting exactly one result, got " + output.size()); + } + return new String(output.get(0).getBody()); + } + /** * Builds a mocked input event into the function runtime */ - public abstract class EventBuilder { - protected String method = "GET"; - protected String appName = "appName"; - protected String route = "/route"; - protected String requestUrl = "http://example.com/r/appName/route"; - protected InputStream body = new ByteArrayInputStream(new byte[0]); - protected int contentLength = 0; - protected String contentType = null; - - protected Map headers = new HashMap<>(); + public final class EventBuilder { + InputStream body = new ByteArrayInputStream(new byte[0]); + String contentType = null; + String callID = "callID"; + Instant deadline = Instant.now().plus(1, ChronoUnit.HOURS); + Headers headers = Headers.emptyHeaders(); /** * Add a header to the input @@ -76,14 +75,15 @@ public abstract class EventBuilder { public EventBuilder withHeader(String key, String value) { Objects.requireNonNull(key, "key"); Objects.requireNonNull(value, "value"); - headers.put(key, value); + headers = headers.addHeader(key, value); return this; } /** * Add a series of headers to the input * This may override duplicate headers - * @param headers Map of headers to add + * + * @param headers Map of headers to add */ public EventBuilder withHeaders(Map headers) { headers.forEach(this::withHeader); @@ -94,21 +94,11 @@ public EventBuilder withHeaders(Map headers) { * Set the body of the request by providing an InputStream * * @param body the bytes of the body - * @param contentLength how long the body is supposed to be */ - public EventBuilder withBody(InputStream body, int contentLength) { + public EventBuilder withBody(InputStream body) { Objects.requireNonNull(body, "body"); - if (contentLength < 0) { - throw new IllegalArgumentException("Invalid contentLength"); - } - // This is for safety. Because we concatenate events, an input stream shorter than content length will cause - // the implementation to continue reading through to the next http request. We need to avoid a sort of - // buffer overrun. - // FIXME: Make InputStream handling simpler. - SessionInputBufferImpl sib = new SessionInputBufferImpl(new HttpTransportMetricsImpl(), 65535); - sib.bind(body); - this.body = new ContentLengthInputStream(sib, contentLength); - this.contentLength = contentLength; + + this.body = body; return this; } @@ -119,7 +109,7 @@ public EventBuilder withBody(InputStream body, int contentLength) { */ public EventBuilder withBody(byte[] body) { Objects.requireNonNull(body, "body"); - return withBody(new ByteArrayInputStream(body), body.length); + return withBody(new ByteArrayInputStream(body)); } /** @@ -132,60 +122,6 @@ public EventBuilder withBody(String body) { return withBody(stringAsBytes); } - /** - * Set the body of the request from a stream - * @param contentStream the content of the body - */ - public EventBuilder withBody(InputStream contentStream) throws IOException { - return withBody(IOUtils.toByteArray(contentStream)); - } - - /** - * Set the fn route associated with the call - * - * @param route the route - */ - public EventBuilder withRoute(String route) { - Objects.requireNonNull(route, "route"); - this.route = route; - return this; - } - - /** - * Set the HTTP method of the incoming request - * - * @param method an HTTP method - * @return - */ - public EventBuilder withMethod(String method) { - Objects.requireNonNull(method, "method"); - this.method = method.toUpperCase(); - return this; - } - - /** - * Set the app name the incoming event - * - * @param appName the app name - * @return - */ - public EventBuilder withAppName(String appName) { - Objects.requireNonNull(appName, "appName"); - this.appName = appName; - return this; - } - - /** - * Set the request URL of the incoming event - * - * @param requestUrl the request URL - * @return - */ - public EventBuilder withRequestUrl(String requestUrl) { - Objects.requireNonNull(requestUrl, "requestUrl"); - this.requestUrl = requestUrl; - return this; - } /** * Prepare an event for the configured codec - this sets appropriate environment variable in the Env mock and StdIn mocks. @@ -193,55 +129,54 @@ public EventBuilder withRequestUrl(String requestUrl) { * * @throws IllegalStateException If the the codec only supports one event and an event has already been enqueued. */ - public abstract void enqueue(); + public void enqueue() { + InputEvent event = new ReadOnceInputEvent(body, headers, callID, deadline); + pendingInput.add(event); + + } Map commonEnv() { - Map env = new HashMap<>(); - env.putAll(config); - headers.forEach((k, v) -> { - env.put("FN_HEADER_" + k.toUpperCase().replaceAll("-", "_"), v); - }); - env.put("FN_METHOD", method); - env.put("FN_APP_NAME", appName); - env.put("FN_PATH", route); - env.put("FN_REQUEST_URL", requestUrl); + Map env = new HashMap<>(config); + env.put("FN_APP_ID", "appID"); + env.put("FN_FN_ID", "fnID"); + return env; } } - private final class HttpEventBuilder extends EventBuilder { + static class TestOutput implements OutputEvent { + private final OutputEvent from; + byte[] body; + + TestOutput(OutputEvent from) throws IOException { + this.from = from; + ByteArrayOutputStream bos = new ByteArrayOutputStream(); + from.writeToOutput(bos); + body = bos.toByteArray(); + } + @Override - public void enqueue() { - StringBuilder inputString = new StringBuilder(); - // Only set env for first event. - if (!hasEvents) { - commonEnv().forEach(vars::put); - vars.put("FN_FORMAT", "http"); - } - inputString.append(method); - inputString.append(" / HTTP/1.1\r\n"); - inputString.append("Fn_App_name: ").append(appName).append("\r\n"); - inputString.append("Fn_Method: ").append(method).append("\r\n"); - inputString.append("Fn_Path: ").append(route).append("\r\n"); - inputString.append("Fn_Request_url: ").append(requestUrl).append("\r\n"); - if (contentType != null) { - inputString.append("Content-Type: ").append(contentType).append("\r\n"); - } + public Status getStatus() { + return from.getStatus(); + } - inputString.append("Content-length: ").append(Integer.toString(contentLength)).append("\r\n"); - headers.forEach((k, v) -> { - inputString.append(k).append(": ").append(v).append("\r\n"); - }); + @Override + public Optional getContentType() { + return from.getContentType(); + } + + @Override + public Headers getHeaders() { + return from.getHeaders(); + } - // added to the http request as headers to mimic the behaviour of `functions` but should NOT be used as config - config.forEach((k, v) -> { - inputString.append(k).append(": ").append(v).append("\r\n"); - }); - inputString.append("\r\n"); + @Override + public void writeToOutput(OutputStream out) throws IOException { + out.write(body); + } - pendingInput = new SequenceInputStream(pendingInput, new ByteArrayInputStream(inputString.toString().getBytes())); - pendingInput = new SequenceInputStream(pendingInput, body); - hasEvents = true; + public byte[] getBody() { + return body; } } @@ -255,6 +190,27 @@ public void thenRun(Class cls, String method) { thenRun(cls.getName(), method); } + static class TestCodec implements EventCodec { + private final List input; + private final List output; + + TestCodec(List input, List output) { + this.input = input; + this.output = output; + } + + @Override + public void runCodec(Handler h) { + for (InputEvent in : input) { + try { + output.add(new TestOutput(h.handle(in))); + } catch (IOException e) { + throw new RuntimeException("Unexpected exception in test", e); + } + } + } + } + /** * Runs the function runtime with the specified class and method * @@ -266,17 +222,21 @@ public void thenRun(String cls, String method) { PrintStream oldSystemOut = System.out; PrintStream oldSystemErr = System.err; try { - PrintStream functionOut = new PrintStream(stdOut); PrintStream functionErr = new PrintStream(new TeeOutputStream(stdErr, oldSystemErr)); System.setOut(functionErr); System.setErr(functionErr); + + Map fnConfig = new HashMap<>(config); + fnConfig.put("FN_APP_ID","appID"); + fnConfig.put("FN_FORMAT","http-stream"); + fnConfig.put("FN_FN_ID","fnID"); + + exitStatus = new EntryPoint().run( - vars, - pendingInput, - functionOut, - functionErr, - cls + "::" + method); - stdOut.flush(); + fnConfig, + new TestCodec(pendingInput, output), + functionErr, + cls + "::" + method); stdErr.flush(); } catch (Exception e) { throw new RuntimeException(e); @@ -305,7 +265,7 @@ public int exitStatus() { * @return a new event builder. */ public EventBuilder givenEvent() { - return new HttpEventBuilder(); + return new EventBuilder(); } @@ -334,152 +294,16 @@ public String getStdErrAsString() { * * @return the bytes returned by the function runtime; */ - public byte[] getStdOut() { - return stdOut.toByteArray(); - } - - /** - * Get the output produced by the runtime as a string. - *

- * For Hot functions this will include the HTTP envelope with (possibly) multiple messages - * - * @return a string representation of the function output - */ - public String getStdOutAsString() { - return new String(stdOut.toByteArray()); + public List getOutputs() { + return output; } - /** - * A simple abstraction for a parsed HTTP response returned by a hot function - */ - public interface ParsedHttpResponse { - /** - * Return the body of the function result as a byte array - * - * @return the function response body - */ - byte[] getBodyAsBytes(); - - /** - * return the body of the function response as a string - * - * @return a function response body - */ - String getBodyAsString(); - - /** - * A map of he headers returned by the function - *

- * These are squashed so duplicated headers will be ignored (takes the first header) - * - * @return a map of headers - */ - Map getHeaders(); - - /** - * @return the HTTP status code returned by the function - */ - int getStatus(); - } - - /** - * Parses any pending HTTP responses on the functions stdout stream - * - * @return a list of Parsed HTTP responses from the function runtime output; - */ - public List getParsedHttpResponses() { - return getParsedHttpResponses(stdOut.toByteArray()); - } - - public static List getParsedHttpResponses(byte[] streamAsBytes) { - - SessionInputBufferImpl sib = new SessionInputBufferImpl(new HttpTransportMetricsImpl(), 65535); - ByteArrayInputStream parseStream = new ByteArrayInputStream(streamAsBytes); - sib.bind(parseStream); - - DefaultHttpResponseParser parser = new DefaultHttpResponseParser(sib); - List responses = new ArrayList<>(); - - while (true) { - try { - HttpResponse response = parser.parse(); - ByteArrayOutputStream bos = new ByteArrayOutputStream(); - ContentLengthInputStream cis = new ContentLengthInputStream(sib, Long.parseLong(response.getFirstHeader("Content-length").getValue())); - - IOUtils.copy(cis, bos); - cis.close(); - byte[] body = bos.toByteArray(); - ParsedHttpResponse r = new ParsedHttpResponse() { - @Override - public byte[] getBodyAsBytes() { - return body; - } - - @Override - public String getBodyAsString() { - return new String(body); - } - - @Override - public Map getHeaders() { - Map headers = new HashMap<>(); - Arrays.stream(response.getAllHeaders()).forEach((h) -> { - headers.put(h.getName(), h.getValue()); - }); - return headers; - } - - @Override - public int getStatus() { - return response.getStatusLine().getStatusCode(); - } - }; - responses.add(r); - } catch (NoHttpResponseException e) { - break; - } catch (Exception e) { - throw new RuntimeException("Invalid HTTP response", e); - } - } - return responses; - - } - @Override public Statement apply(Statement base, Description description) { return base; } - private final class DefaultEventBuilder extends EventBuilder { - boolean sent = false; - - @Override - public void enqueue() { - if (sent) { - throw new IllegalStateException("Cannot enqueue multiple default events "); - } - pendingInput = body; - sent = true; - commonEnv().forEach(vars::put); - } - } - - /** - * mock a default event (Input and stdOut encoded as stdin/stdout) - * - * @return a new event builder. - */ - public EventBuilder givenDefaultEvent() { - return new DefaultEventBuilder(); - } - - /** - * mock an http event - */ - public EventBuilder givenHttpEvent() { - return new HttpEventBuilder(); - } } diff --git a/runtime/src/test/java/com/fnproject/fn/runtime/FunctionConstructionTests.java b/runtime/src/test/java/com/fnproject/fn/runtime/FunctionConstructionTest.java similarity index 83% rename from runtime/src/test/java/com/fnproject/fn/runtime/FunctionConstructionTests.java rename to runtime/src/test/java/com/fnproject/fn/runtime/FunctionConstructionTest.java index 4d78c9e1..4d439175 100644 --- a/runtime/src/test/java/com/fnproject/fn/runtime/FunctionConstructionTests.java +++ b/runtime/src/test/java/com/fnproject/fn/runtime/FunctionConstructionTest.java @@ -9,38 +9,38 @@ /** * End-to-end tests for function configuration methods */ -public class FunctionConstructionTests { +public class FunctionConstructionTest { @Rule public final FnTestHarness fn = new FnTestHarness(); @Test public void shouldConstructWithDefaultConstructor() { - fn.givenDefaultEvent().enqueue(); + fn.givenEvent().enqueue(); fn.thenRun(TestFnConstructors.DefaultEmptyConstructor.class, "invoke"); assertThat(fn.exitStatus()).isEqualTo(0); - assertThat(fn.getStdOutAsString()).isEqualTo("OK"); + assertThat(fn.getOnlyOutputAsString()).isEqualTo("OK"); } @Test public void shouldConstructWithExplicitConstructor() { - fn.givenDefaultEvent().enqueue(); + fn.givenEvent().enqueue(); fn.thenRun(TestFnConstructors.ExplicitEmptyConstructor.class, "invoke"); assertThat(fn.exitStatus()).isEqualTo(0); - assertThat(fn.getStdOutAsString()).isEqualTo("OK"); + assertThat(fn.getOnlyOutputAsString()).isEqualTo("OK"); } @Test public void shouldInjectConfigIntoConstructor() { - fn.givenDefaultEvent().enqueue(); + fn.givenEvent().enqueue(); fn.thenRun(TestFnConstructors.ConfigurationOnConstructor.class, "invoke"); assertThat(fn.exitStatus()).isEqualTo(0); - assertThat(fn.getStdOutAsString()).isEqualTo("OK"); + assertThat(fn.getOnlyOutputAsString()).isEqualTo("OK"); } @Test public void shouldFailWithInaccessibleConstructor() { - fn.givenDefaultEvent().enqueue(); + fn.givenEvent().enqueue(); fn.thenRun(TestFnConstructors.BadConstructorNotAccessible.class, "invoke"); assertThat(fn.exitStatus()).isEqualTo(2); assertThat(fn.getStdErrAsString()).contains("cannot be instantiated as it has no public constructors"); @@ -48,7 +48,7 @@ public void shouldFailWithInaccessibleConstructor() { @Test public void shouldFailFunctionWithTooManyConstructorArgs() { - fn.givenDefaultEvent().enqueue(); + fn.givenEvent().enqueue(); fn.thenRun(TestFnConstructors.BadConstructorTooManyArgs.class, "invoke"); assertThat(fn.exitStatus()).isEqualTo(2); assertThat(fn.getStdErrAsString()).contains("cannot be instantiated as its constructor takes more than one argument"); @@ -56,7 +56,7 @@ public void shouldFailFunctionWithTooManyConstructorArgs() { @Test public void shouldFailFunctionWithAmbiguousConstructors() { - fn.givenDefaultEvent().enqueue(); + fn.givenEvent().enqueue(); fn.thenRun(TestFnConstructors.BadConstructorAmbiguousConstructors.class, "invoke"); assertThat(fn.exitStatus()).isEqualTo(2); assertThat(fn.getStdErrAsString()).contains("cannot be instantiated as it has multiple public constructors"); @@ -64,7 +64,7 @@ public void shouldFailFunctionWithAmbiguousConstructors() { @Test public void shouldFailFunctionWithErrorInConstructor() { - fn.givenDefaultEvent().enqueue(); + fn.givenEvent().enqueue(); fn.thenRun(TestFnConstructors.BadConstructorThrowsException.class, "invoke"); assertThat(fn.exitStatus()).isEqualTo(2); assertThat(fn.getStdErrAsString()).contains("An error occurred in the function constructor while instantiating class"); @@ -72,7 +72,7 @@ public void shouldFailFunctionWithErrorInConstructor() { @Test public void shouldFailFunctionWithBadSingleConstructConstructorArg() { - fn.givenDefaultEvent().enqueue(); + fn.givenEvent().enqueue(); fn.thenRun(TestFnConstructors.BadConstructorUnrecognisedArg.class, "invoke"); assertThat(fn.exitStatus()).isEqualTo(2); assertThat(fn.getStdErrAsString()).contains("cannot be instantiated as its constructor takes an unrecognized argument of type int"); @@ -81,7 +81,7 @@ public void shouldFailFunctionWithBadSingleConstructConstructorArg() { @Test public void shouldFailNonStaticInnerClassWithANiceMessage(){ - fn.givenDefaultEvent().enqueue(); + fn.givenEvent().enqueue(); fn.thenRun(TestFnConstructors.NonStaticInnerClass.class, "invoke"); assertThat(fn.exitStatus()).isEqualTo(2); assertThat(fn.getStdErrAsString()).contains("cannot be instantiated as it is a non-static inner class"); diff --git a/runtime/src/test/java/com/fnproject/fn/runtime/HTTPStreamCodecTest.java b/runtime/src/test/java/com/fnproject/fn/runtime/HTTPStreamCodecTest.java new file mode 100644 index 00000000..ca933b56 --- /dev/null +++ b/runtime/src/test/java/com/fnproject/fn/runtime/HTTPStreamCodecTest.java @@ -0,0 +1,329 @@ +package com.fnproject.fn.runtime; + + +import com.fnproject.fn.api.Headers; +import com.fnproject.fn.api.InputEvent; +import com.fnproject.fn.api.OutputEvent; +import org.apache.commons.io.IOUtils; +import org.eclipse.jetty.client.HttpClient; +import org.eclipse.jetty.client.api.ContentResponse; +import org.eclipse.jetty.client.api.Request; +import org.eclipse.jetty.client.api.Result; +import org.eclipse.jetty.client.util.BytesContentProvider; +import org.eclipse.jetty.client.util.StringContentProvider; +import org.eclipse.jetty.unixsocket.client.HttpClientTransportOverUnixSockets; +import org.junit.After; +import org.junit.Rule; +import org.junit.Test; +import org.junit.rules.Timeout; + +import java.io.File; +import java.io.IOException; +import java.nio.file.Files; +import java.nio.file.attribute.PosixFilePermissions; +import java.security.MessageDigest; +import java.util.*; +import java.util.concurrent.CompletableFuture; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.atomic.AtomicInteger; +import java.util.concurrent.atomic.AtomicReference; + +import static org.assertj.core.api.Assertions.assertThat; + +/** + * This uses the Jetty client largely as witness of "good HTTP behaviour" + * Created on 24/08/2018. + *

+ * (c) 2018 Oracle Corporation + */ +public class HTTPStreamCodecTest { + + + @Rule + public final Timeout to = new Timeout(60, TimeUnit.SECONDS); + + private static final Map defaultEnv; + private final List cleanups = new ArrayList<>(); + + private static File generateSocketFile() { + File f = null; + try { + + f = File.createTempFile("socket", ".sock"); + f.delete(); + f.deleteOnExit(); + } catch (IOException e) { + } + + return f; + } + + static { + System.setProperty("com.fnproject.java.native.libdir", new File("src/main/c/").getAbsolutePath()); + System.setProperty("org.eclipse.jetty.util.log.class", "org.eclipse.jetty.util.log.StdErrLog"); + System.setProperty("org.eclipse.jetty.LEVEL", "WARN"); + + + Map env = new HashMap<>(); + env.put("FN_APP_NAME", "myapp"); + env.put("FN_PATH", "mypath"); + + defaultEnv = Collections.unmodifiableMap(env); + } + + private HttpClient createClient(File unixSocket) throws Exception { + HttpClient client = new HttpClient(new HttpClientTransportOverUnixSockets(unixSocket.getAbsolutePath()), null); + client.start(); + cleanups.add(() -> { + try { + client.stop(); + } catch (Exception e) { + throw new RuntimeException(e); + } + }); + return client; + } + + private Request defaultRequest(HttpClient httpClient) { + return httpClient.newRequest("http://localhost/call") + .method("POST") + .header("Fn-Call-Id", "callID") + .header("Fn-Deadline", "2002-10-02T10:00:00.992Z") + .header("Custom-header", "v1") + .header("Custom-header", "v2") + .header("Content-Type", "text/plain") + .content(new StringContentProvider("hello ")); + + } + + + @After + public void cleanup() throws Exception { + cleanups.forEach(Runnable::run); + } + + + public File startCodec(Map env, EventCodec.Handler h) { + Map newEnv = new HashMap<>(env); + File socket = generateSocketFile(); + newEnv.put("FN_LISTENER", "unix:" + socket.getAbsolutePath()); + + HTTPStreamCodec codec = new HTTPStreamCodec(newEnv); + + Thread t = new Thread(() -> codec.runCodec(h)); + t.start(); + cleanups.add(() -> { + try { + codec.close(); + } catch (IOException e) { + throw new RuntimeException(e); + } + }); + return socket; + } + + @Test + public void shouldAcceptDataOnHttp() throws Exception { + CompletableFuture lastEvent = new CompletableFuture<>(); + + File socketFile = startCodec(defaultEnv, (in) -> { + lastEvent.complete(in); + return OutputEvent.fromBytes("hello".getBytes(), OutputEvent.Status.Success, "text/plain", Headers.emptyHeaders().addHeader("x-test", "bar")); + }); + + HttpClient client = createClient(socketFile); + ContentResponse resp = client.newRequest("http://localhost/call") + .method("POST") + .header("Fn-Call-Id", "callID") + .header("Fn-Deadline", "2002-10-02T10:00:00.992Z") + .header("Custom-header", "v1") + .header("Custom-header", "v2") + .header("Content-Type", "text/plain") + .content(new StringContentProvider("hello ")).send(); + + assertThat(resp.getStatus()).isEqualTo(200); + assertThat(resp.getContent()).isEqualTo("hello".getBytes()); + assertThat(resp.getHeaders().get("x-test")).isEqualTo("bar"); + + InputEvent evt = lastEvent.get(1, TimeUnit.MILLISECONDS); + assertThat(evt.getCallID()).isEqualTo("callID"); + assertThat(evt.getDeadline().toEpochMilli()).isEqualTo(1033552800992L); + assertThat(evt.getHeaders()).isEqualTo(Headers.emptyHeaders().addHeader("Fn-Call-Id", "callID").addHeader("Fn-Deadline", "2002-10-02T10:00:00.992Z").addHeader("Custom-header", "v1", "v2").addHeader("Content-Type", "text/plain").addHeader("Content-Length","6")); + + } + + @Test + public void shouldRejectFnMissingHeaders() throws Exception { + + Map headers = new HashMap<>(); + headers.put("Fn-Call-Id", "callID"); + headers.put("Fn-Deadline", "2002-10-02T10:00:00.992Z"); + + + File socket = startCodec(defaultEnv, (in) -> OutputEvent.emptyResult(OutputEvent.Status.Success)); + + HttpClient client = createClient(socket); + + Request positive = client.newRequest("http://localhost/call") + .method("POST"); + headers.forEach(positive::header); + assertThat(positive.send().getStatus()).withFailMessage("Expecting req with mandatory headers to pass").isEqualTo(200); + + for (String h : headers.keySet()) { + Request r = client.newRequest("http://localhost/call") + .method("POST"); + headers.forEach((k, v) -> { + if (!k.equals(h)) { + r.header(k, v); + } + }); + + + ContentResponse resp = r.send(); + assertThat(resp.getStatus()).withFailMessage("Expected failure error code for missing header " + h).isEqualTo(500); + + } + } + + @Test + public void shouldHandleMultipleRequests() throws Exception { + AtomicReference lastInput = new AtomicReference<>(); + AtomicInteger count = new AtomicInteger(0); + + File socket = startCodec(defaultEnv, (in) -> { + byte[] body = in.consumeBody((is) -> { + try { + return IOUtils.toByteArray(is); + } catch (IOException e) { + throw new RuntimeException(e); + } + }); + + lastInput.set(body); + return OutputEvent.fromBytes(body, OutputEvent.Status.Success, "application/octet-stream", Headers.emptyHeaders()); + }); + + HttpClient httpClient = createClient(socket); + + for (int i = 0; i < 200; i++) { + byte[] body = randomBytes(i * 1997); + ContentResponse resp = httpClient.newRequest("http://localhost/call") + .method("POST") + .header("Fn-Call-Id", "callID") + .header("Fn-Deadline", "2002-10-02T10:00:00.992Z") + .header("Custom-header", "v1") + .header("Custom-header", "v2") + .header("Content-Type", "text/plain") + .content(new BytesContentProvider(body)).send(); + + assertThat(resp.getStatus()).isEqualTo(200); + assertThat(resp.getContent()).isEqualTo(body); + assertThat(lastInput).isNotNull(); + assertThat(lastInput.get()).isEqualTo(body); + } + + } + + @Test + public void shouldHandleLargeBodies() throws Exception { + // Round trips 10 meg of data through the codec and validates it got the right stuff back + byte[] randomString = randomBytes(1024 * 1024 * 10); + byte[] inDigest = MessageDigest.getInstance("SHA-256").digest(randomString); + + + File socket = startCodec(defaultEnv, (in) -> { + byte[] content = in.consumeBody((is) -> { + try { + return IOUtils.toByteArray(is); + } catch (IOException e) { + throw new RuntimeException(e); + } + }); + + return OutputEvent.fromBytes(content, OutputEvent.Status.Success, "application/octet-binary", Headers.emptyHeaders()); + }); + + HttpClient client = createClient(socket); + + CompletableFuture cdl = new CompletableFuture<>(); + MessageDigest readDigest = MessageDigest.getInstance("SHA-256"); + defaultRequest(client) + .content(new BytesContentProvider(randomString)) + .onResponseContent((response, byteBuffer) -> { + readDigest.update(byteBuffer); + }) + .send(cdl::complete); + Result r = cdl.get(); + assertThat(r.getResponse().getStatus()).isEqualTo(200); + assertThat(readDigest.digest()).isEqualTo(inDigest); + } + + private byte[] randomBytes(int sz) { + Random sr = new Random(); + byte[] part = new byte[1024]; + sr.nextBytes(part); + + byte[] randomString = new byte[sz]; + int left = sz; + for (int i = 0; i < randomString.length; i += part.length) { + int copy = Math.min(left, part.length); + + System.arraycopy(part, 0, randomString, i, copy); + left -= part.length; + } + return randomString; + } + + @Test + public void shouldConvertStatusResponses() throws Exception { + + for (OutputEvent.Status s : OutputEvent.Status.values()) { + CompletableFuture lastEvent = new CompletableFuture<>(); + + File socket = startCodec(defaultEnv, (in) -> { + lastEvent.complete(in); + return OutputEvent.fromBytes("hello".getBytes(), s, "text/plain", Headers.emptyHeaders()); + }); + + HttpClient client = createClient(socket); + + ContentResponse resp = defaultRequest(client).send(); + + assertThat(resp.getStatus()).isEqualTo(s.getCode()); + + } + + } + + @Test + public void shouldStripHopToHopHeadersFromFunctionInput() throws Exception { + + for (String header[] : new String[][]{ + {"Transfer-encoding", "chunked"}, + {"Connection", "close"}, + }) { + CompletableFuture lastEvent = new CompletableFuture<>(); + + File socket = startCodec(defaultEnv, (in) -> { + lastEvent.complete(in); + return OutputEvent.fromBytes("hello".getBytes(), OutputEvent.Status.Success, "text/plain", Headers.emptyHeaders().addHeader(header[0], header[1])); + }); + HttpClient client = createClient(socket); + ContentResponse resp = defaultRequest(client).send(); + + assertThat(resp.getHeaders().get(header[0])).isNull(); + + } + } + + @Test + public void socketShouldHaveCorrectPermissions() throws Exception { + File listener = startCodec(defaultEnv, (in) -> OutputEvent.fromBytes("hello".getBytes(), OutputEvent.Status.Success, "text/plain", Headers.emptyHeaders())); + + assertThat(Files.getPosixFilePermissions(listener.toPath())).isEqualTo(PosixFilePermissions.fromString("rw-rw-rw-")); + + cleanup(); + } + + +} diff --git a/runtime/src/test/java/com/fnproject/fn/runtime/HeaderBuilder.java b/runtime/src/test/java/com/fnproject/fn/runtime/HeaderBuilder.java index bc5c4895..2ac8f53c 100644 --- a/runtime/src/test/java/com/fnproject/fn/runtime/HeaderBuilder.java +++ b/runtime/src/test/java/com/fnproject/fn/runtime/HeaderBuilder.java @@ -1,10 +1,14 @@ package com.fnproject.fn.runtime; +import com.fnproject.fn.api.Headers; + import java.util.AbstractMap; +import java.util.Collections; +import java.util.List; import java.util.Map; class HeaderBuilder { - static Map.Entry headerEntry(String key, String value) { - return new AbstractMap.SimpleEntry<>(key, value); + static Map.Entry> headerEntry(String key, String value) { + return new AbstractMap.SimpleEntry<>(Headers.canonicalKey(key), Collections.singletonList(value)); } } diff --git a/runtime/src/test/java/com/fnproject/fn/runtime/HttpEventCodecTest.java b/runtime/src/test/java/com/fnproject/fn/runtime/HttpEventCodecTest.java index 0f06c49b..7163caf6 100644 --- a/runtime/src/test/java/com/fnproject/fn/runtime/HttpEventCodecTest.java +++ b/runtime/src/test/java/com/fnproject/fn/runtime/HttpEventCodecTest.java @@ -14,7 +14,6 @@ import java.io.OutputStream; import java.util.HashMap; import java.util.Map; -import java.util.stream.Collectors; import static com.fnproject.fn.runtime.HeaderBuilder.headerEntry; import static org.assertj.core.api.Assertions.assertThat; @@ -26,30 +25,31 @@ public class HttpEventCodecTest { private final InputStream nullIn = new NullInputStream(0); private final String postReq = "GET /test HTTP/1.1\n" + - "Accept-Encoding: gzip\n" + - "User-Agent: useragent\n" + - "Accept: text/html, text/plain;q=0.9\n" + - "Fn_Request_url: http//localhost:8080/r/testapp/test\n" + - "Fn_Path: /test\n" + - "Fn_Method: POST\n" + - "Content-Length: 11\n" + - "Fn_App_name: testapp\n" + - "Fn_Call_id: task-id\n" + - "Myconfig: fooconfig\n" + - "Content-Type: text/plain\n\n" + - "Hello World"; + "Accept-Encoding: gzip\n" + + "User-Agent: useragent\n" + + "Accept: text/html, text/plain;q=0.9\n" + + "Fn_Request_url: http//localhost:8080/r/testapp/test\n" + + "Fn_Path: /test\n" + + "Fn_Method: POST\n" + + "Content-Length: 11\n" + + "Fn_App_name: testapp\n" + + "Fn_Call_id: task-id\n" + + "Myconfig: fooconfig\n" + + "Content-Type: text/plain\n\n" + + "Hello World"; private final String getReq = "GET /test HTTP/1.1\n" + - "Accept-Encoding: gzip\n" + - "User-Agent: useragent\n" + - "Fn_Request_url: http//localhost:8080/r/testapp/test\n" + - "Fn_Method: GET\n" + - "Content-Length: 0\n" + - "Fn_Call_Id: task-id2\n" + - "Myconfig: fooconfig\n\n"; + "Accept-Encoding: gzip\n" + + "User-Agent: useragent\n" + + "Fn_Request_url: http//localhost:8080/r/testapp/test\n" + + "Fn_Method: GET\n" + + "Content-Length: 0\n" + + "Fn_Call_Id: task-id2\n" + + "Myconfig: fooconfig\n\n"; private final Map emptyConfig = new HashMap<>(); + private final Map env() { HashMap env = new HashMap<>(); env.put("FN_APP_NAME", "testapp"); @@ -108,61 +108,18 @@ public void shouldRejectInvalidHttpRequest() { } - @Test - public void shouldRejectMissingHttpHeaders() { - - Map requiredHeaders = new HashMap<>(); - requiredHeaders.put("fn_request_url", "request_url"); - requiredHeaders.put("fn_method", "GET"); - - for (String key : requiredHeaders.keySet()) { - Map newMap = new HashMap<>(requiredHeaders); - newMap.remove(key); - String req = "GET / HTTP/1.1\n" + newMap.entrySet().stream().map(e -> e.getKey() + ": " + e.getValue()).collect(Collectors.joining("\n")) + "\n\n"; - - try { - HttpEventCodec httpEventCodec = new HttpEventCodec(env(), asStream(req), nullOut); - httpEventCodec.readEvent(); - fail("Should fail with header missing:" + key); - } catch (FunctionInputHandlingException e) { - assertThat(e).hasMessageMatching("Incoming HTTP frame is missing required header: " + key); - } - } - } - - @Test - public void shouldRejectMissingEnv() { - Map requiredEnv = new HashMap<>(); - - requiredEnv.put("FN_PATH", "/route"); - requiredEnv.put("FN_APP_NAME", "app_name"); - - for (String key : requiredEnv.keySet()) { - Map newMap = new HashMap<>(requiredEnv); - newMap.remove(key); - - try { - ByteArrayInputStream bis = new ByteArrayInputStream(postReq.getBytes()); - HttpEventCodec httpEventCodec = new HttpEventCodec(newMap, bis, nullOut); - httpEventCodec.readEvent(); - fail("Should fail with header missing:" + key); - } catch (FunctionInputHandlingException e) { - assertThat(e).hasMessageMatching("Required environment variable " + key + " is not set - are you running a function outside of fn run\\?"); - } - } - } @Test - public void shouldSerializeSimpleSuccessfulEvent() throws Exception{ + public void shouldSerializeSimpleSuccessfulEvent() throws Exception { ByteArrayOutputStream bos = new ByteArrayOutputStream(); HttpEventCodec httpEventCodec = new HttpEventCodec(env(), nullIn, bos); - OutputEvent outEvent = OutputEvent.fromBytes("Hello".getBytes(),OutputEvent.SUCCESS,"text/plain"); + OutputEvent outEvent = OutputEvent.fromBytes("Hello".getBytes(), OutputEvent.Status.Success, "text/plain"); httpEventCodec.writeEvent(outEvent); String httpResponse = new String(bos.toByteArray()); - assertThat(statusLine(httpResponse)).isEqualTo("HTTP/1.1 200 INVOKED"); + assertThat(statusLine(httpResponse)).isEqualTo("HTTP/1.1 200 Success"); assertThat(headers(httpResponse)).containsOnly(entry("content-type", "text/plain"), entry("content-length", "5")); assertThat(body(httpResponse)).isEqualTo("Hello"); @@ -175,8 +132,10 @@ private static String statusLine(String httpResponse) { private static Map headers(String httpResponse) { Map hs = new HashMap<>(); boolean firstLine = true; - for (String line: httpResponse.split("\\\r\\\n")) { - if (line.equals("")) { break; } + for (String line : httpResponse.split("\\\r\\\n")) { + if (line.equals("")) { + break; + } if (firstLine) { firstLine = false; continue; @@ -192,7 +151,7 @@ private static String body(String httpResponse) { } @Test - public void shouldSerializeSuccessfulEventWithHeaders() throws Exception{ + public void shouldSerializeSuccessfulEventWithHeaders() throws Exception { ByteArrayOutputStream bos = new ByteArrayOutputStream(); HttpEventCodec httpEventCodec = new HttpEventCodec(env(), nullIn, bos); @@ -200,54 +159,54 @@ public void shouldSerializeSuccessfulEventWithHeaders() throws Exception{ hs.put("foo", "bar"); hs.put("Content-Type", "application/octet-stream"); // ignored hs.put("Content-length", "99"); // ignored - OutputEvent outEvent = OutputEvent.fromBytes("Hello".getBytes(),OutputEvent.SUCCESS,"text/plain", Headers.fromMap(hs)); + OutputEvent outEvent = OutputEvent.fromBytes("Hello".getBytes(), OutputEvent.Status.Success, "text/plain", Headers.fromMap(hs)); httpEventCodec.writeEvent(outEvent); String httpResponse = new String(bos.toByteArray()); - assertThat(statusLine(httpResponse)).isEqualTo("HTTP/1.1 200 INVOKED"); + assertThat(statusLine(httpResponse)).isEqualTo("HTTP/1.1 200 Success"); assertThat(headers(httpResponse)).containsOnly(entry("foo", "bar"), - entry("content-type", "text/plain"), - entry("content-length", "5")); + entry("content-type", "text/plain"), + entry("content-length", "5")); assertThat(body(httpResponse)).isEqualTo("Hello"); } @Test - public void shouldSerializeSimpleFailedEvent() throws Exception{ + public void shouldSerializeSimpleFailedEvent() throws Exception { ByteArrayOutputStream bos = new ByteArrayOutputStream(); HttpEventCodec httpEventCodec = new HttpEventCodec(env(), nullIn, bos); - OutputEvent outEvent = OutputEvent.fromBytes("Hello".getBytes(), OutputEvent.FAILURE,"text/plain"); + OutputEvent outEvent = OutputEvent.fromBytes("Hello".getBytes(), OutputEvent.Status.FunctionError, "text/plain"); httpEventCodec.writeEvent(outEvent); String httpResponse = new String(bos.toByteArray()); - assertThat(statusLine(httpResponse)).isEqualTo("HTTP/1.1 500 INVOKE FAILED"); + assertThat(statusLine(httpResponse)).isEqualTo("HTTP/1.1 502 FunctionError"); assertThat(headers(httpResponse)).containsOnly(entry("content-type", "text/plain"), - entry("content-length", "5")); + entry("content-length", "5")); assertThat(body(httpResponse)).isEqualTo("Hello"); } @Test - public void shouldSerializeFailedEventWithHeaders() throws Exception{ + public void shouldSerializeFailedEventWithHeaders() throws Exception { ByteArrayOutputStream bos = new ByteArrayOutputStream(); - HttpEventCodec httpEventCodec = new HttpEventCodec(env(), nullIn,bos); + HttpEventCodec httpEventCodec = new HttpEventCodec(env(), nullIn, bos); Map hs = new HashMap<>(); hs.put("foo", "bar"); hs.put("Content-Type", "application/octet-stream"); // ignored hs.put("Content-length", "99"); // ignored - OutputEvent outEvent = OutputEvent.fromBytes("Hello".getBytes(), OutputEvent.FAILURE,"text/plain", Headers.fromMap(hs)); + OutputEvent outEvent = OutputEvent.fromBytes("Hello".getBytes(), OutputEvent.Status.FunctionError, "text/plain", Headers.fromMap(hs)); httpEventCodec.writeEvent(outEvent); String httpResponse = new String(bos.toByteArray()); - assertThat(statusLine(httpResponse)).isEqualTo("HTTP/1.1 500 INVOKE FAILED"); + assertThat(statusLine(httpResponse)).isEqualTo("HTTP/1.1 502 FunctionError"); assertThat(headers(httpResponse)).containsOnly(entry("foo", "bar"), - entry("content-type", "text/plain"), - entry("content-length", "5")); + entry("content-type", "text/plain"), + entry("content-length", "5")); assertThat(body(httpResponse)).isEqualTo("Hello"); } @@ -257,31 +216,32 @@ private InputStream asStream(String sin) { } private void isExpectedGetEvent(InputEvent getEvent) { - assertThat(getEvent.getAppName()).isEqualTo("testapp"); - assertThat(getEvent.getMethod()).isEqualTo("GET"); - assertThat(getEvent.getRoute()).isEqualTo("/test"); + //assertThat(getEvent.getAppName()).isEqualTo("testapp"); +// assertThat(getEvent.getMethod()).isEqualTo("GET"); +// assertThat(getEvent.getRoute()).isEqualTo("/test"); - assertThat(getEvent.getHeaders().getAll()) - .contains(headerEntry("Accept-Encoding", "gzip"), - headerEntry("User-Agent", "useragent")); + assertThat(getEvent.getHeaders().asMap()) + .contains(headerEntry("Accept-Encoding", "gzip"), + headerEntry("User-Agent", "useragent")); getEvent.consumeBody((is) -> assertThat(is).hasSameContentAs(asStream(""))); } + private void isExpectedPostEvent(InputEvent postEvent) { - assertThat(postEvent.getAppName()).isEqualTo("testapp"); - assertThat(postEvent.getMethod()).isEqualTo("POST"); - assertThat(postEvent.getRoute()).isEqualTo("/test"); - assertThat(postEvent.getHeaders().getAll().size()).isEqualTo(11); - assertThat(postEvent.getHeaders().getAll()) - .contains(headerEntry("Accept", "text/html, text/plain;q=0.9"), - headerEntry("Accept-Encoding", "gzip"), - headerEntry("User-Agent", "useragent"), - headerEntry("Content-Type", "text/plain")); + //assertThat(postEvent.getAppName()).isEqualTo("testapp"); +// assertThat(postEvent.getMethod()).isEqualTo("POST"); +// assertThat(postEvent.getRoute()).isEqualTo("/test"); + assertThat(postEvent.getHeaders().asMap().size()).isEqualTo(11); + assertThat(postEvent.getHeaders().asMap()) + .contains(headerEntry("Accept", "text/html, text/plain;q=0.9"), + headerEntry("Accept-Encoding", "gzip"), + headerEntry("User-Agent", "useragent"), + headerEntry("Content-Type", "text/plain")); postEvent.consumeBody((is) -> assertThat(is).hasSameContentAs(asStream("Hello World"))); } - +// } diff --git a/runtime/src/test/java/com/fnproject/fn/runtime/JacksonCoercionTest.java b/runtime/src/test/java/com/fnproject/fn/runtime/JacksonCoercionTest.java index 8b62f975..28effe29 100644 --- a/runtime/src/test/java/com/fnproject/fn/runtime/JacksonCoercionTest.java +++ b/runtime/src/test/java/com/fnproject/fn/runtime/JacksonCoercionTest.java @@ -9,6 +9,7 @@ import org.junit.Test; import java.io.ByteArrayInputStream; +import java.time.Instant; import java.util.HashMap; import java.util.List; import java.util.Map; @@ -33,7 +34,7 @@ public void listOfCustomObjects() throws NoSuchMethodException { headers.put("content-type", "application/json"); ByteArrayInputStream body = new ByteArrayInputStream("[{\"name\":\"Spot\",\"age\":6},{\"name\":\"Jason\",\"age\":16}]".getBytes()); - InputEvent inputEvent = new ReadOnceInputEvent("", "", "", "testMethod", body, Headers.fromMap(headers), new QueryParametersImpl()); + InputEvent inputEvent = new ReadOnceInputEvent( body, Headers.fromMap(headers),"call",Instant.now()); Optional object = jc.tryCoerceParam(invocationContext, 0, inputEvent, method); @@ -55,7 +56,7 @@ public void failureToParseIsUserFriendlyError() throws NoSuchMethodException { headers.put("content-type", "application/json"); ByteArrayInputStream body = new ByteArrayInputStream("INVALID JSON".getBytes()); - InputEvent inputEvent = new ReadOnceInputEvent("", "", "", "testMethod", body, Headers.fromMap(headers), new QueryParametersImpl()); + InputEvent inputEvent = new ReadOnceInputEvent( body, Headers.fromMap(headers), "call",Instant.now()); boolean causedExpectedError; try { diff --git a/runtime/src/test/java/com/fnproject/fn/runtime/QueryParametersParserTest.java b/runtime/src/test/java/com/fnproject/fn/runtime/QueryParametersParserTest.java index 60d73543..b799d451 100644 --- a/runtime/src/test/java/com/fnproject/fn/runtime/QueryParametersParserTest.java +++ b/runtime/src/test/java/com/fnproject/fn/runtime/QueryParametersParserTest.java @@ -1,6 +1,7 @@ package com.fnproject.fn.runtime; import com.fnproject.fn.api.QueryParameters; +import com.fnproject.fn.runtime.httpgateway.QueryParametersParser; import org.junit.Test; import java.util.Collections; diff --git a/runtime/src/test/java/com/fnproject/fn/runtime/flow/FlowsTest.java b/runtime/src/test/java/com/fnproject/fn/runtime/flow/FlowsTest.java deleted file mode 100644 index 03e07a1c..00000000 --- a/runtime/src/test/java/com/fnproject/fn/runtime/flow/FlowsTest.java +++ /dev/null @@ -1,280 +0,0 @@ -package com.fnproject.fn.runtime.flow; - -import com.fnproject.fn.runtime.FnTestHarness; -import com.fnproject.fn.runtime.testfns.FnFlowsFunction; -import org.junit.Before; -import org.junit.Rule; -import org.junit.Test; -import org.mockito.Mock; -import org.mockito.MockitoAnnotations; - -import java.util.concurrent.atomic.AtomicBoolean; - -import static org.mockito.Mockito.*; - -public class FlowsTest { - - @Rule - public FnTestHarness fnTestHarness = new FnTestHarness(); - - private final String FUNCTION_ID = "app/testfn"; - private final FlowId FLOW_ID = new FlowId("test-flow-id"); - - // static to avoid issues with serialized AtomicRefs - static AtomicBoolean tag = new AtomicBoolean(false); - - @Mock - CompleterClient mockCompleterClient; - - TestBlobStore testBlobStore; - - @Before - public void setup() { - tag.set(false); - MockitoAnnotations.initMocks(this); - FlowRuntimeGlobals.resetCompleterClientFactory(); - - FlowRuntimeGlobals.setCompleterClientFactory(new CompleterClientFactory() { - @Override - public CompleterClient getCompleterClient() { - return mockCompleterClient; - } - - @Override - public BlobStoreClient getBlobStoreClient() { - return testBlobStore; - } - }); - } - - private FnTestHarness.EventBuilder eventToTestFN() { - return fnTestHarness.givenDefaultEvent().withAppName("app").withRoute("/testfn"); - } - - private FnTestHarness.EventBuilder httpEventToTestFN() { - return fnTestHarness.givenHttpEvent() - .withAppName("app") - .withRoute("/testfn"); - } - - @Test - public void completerNotCalledIfFlowRuntimeUnused() throws Exception { - - eventToTestFN().enqueue(); - fnTestHarness.thenRun(FnFlowsFunction.class, "notUsingFlows"); - - verify(mockCompleterClient, never()).createFlow(any()); - } - - @Test - public void completerCalledWhenFlowRuntimeIsAccessed() { - - when(mockCompleterClient.createFlow(FUNCTION_ID)).thenReturn(FLOW_ID); - - eventToTestFN().enqueue(); - fnTestHarness.thenRun(FnFlowsFunction.class, "usingFlows"); - - verify(mockCompleterClient, times(1)).createFlow(FUNCTION_ID); - } - - @Test - public void onlyOneThreadIsCreatedWhenRuntimeIsAccessedMultipleTimes() { - - when(mockCompleterClient.createFlow(FUNCTION_ID)).thenReturn(FLOW_ID); - - eventToTestFN().enqueue(); - fnTestHarness.thenRun(FnFlowsFunction.class, "accessRuntimeMultipleTimes"); - - verify(mockCompleterClient, times(1)).createFlow(FUNCTION_ID); - } - -// @Test -// public void invokeWithinAsyncFunction() throws InterruptedException, IOException, ClassNotFoundException { -// -// AtomicReference continuationResult = new AtomicReference<>(); -// CompletionId completionId = new CompletionId("continuation-completion-id"); -// -// when(mockCompleterClient.createFlow(FUNCTION_ID)).thenReturn(FLOW_ID); -// -// when(mockCompleterClient.supply(eq(FLOW_ID), -// isA(Flows.SerCallable.class),isA(CodeLocation.class))) -// .thenAnswer(invokeContinuation(completionId, continuationResult, "supplyAndGetResult")); -// when(mockCompleterClient.waitForCompletion(eq(FLOW_ID), eq(completionId), eq(getClass().getClassLoader()))) -// .thenAnswer(invocationOnMock -> continuationResult.get()); -// -// httpEventToTestFN().enqueue(); -// fnTestHarness.thenRun(FnFlowsFunction.class, "supplyAndGetResult"); -// -// FnTestHarness.ParsedHttpResponse response = getSingleItem(fnTestHarness.getParsedHttpResponses()); -// assertThat(response.getBodyAsString()).isEqualTo(continuationResult.toString()); -// ArgumentCaptor locCaptor = ArgumentCaptor.forClass(CodeLocation.class); -// verify(mockCompleterClient, times(1)) -// .supply(eq(FLOW_ID), isA(Flows.SerCallable.class), locCaptor.capture()); -// -// CodeLocation gotLocation = locCaptor.getValue(); -// assertThat(gotLocation.getLocation()) -// .matches(Pattern.compile("com\\.fnproject\\.fn\\.runtime\\.testfns\\.FnFlowsFunction\\.supplyAndGetResult\\(.*\\.java\\:\\d+\\)")); -// verify(mockCompleterClient, times(1)) -// .waitForCompletion(eq(FLOW_ID), eq(completionId), eq(getClass().getClassLoader())); -// } -// -// /** -// * Mock the behaviour of a call to the Completer service through supply -// *

-// * When called by Mockito in response to a matching method call, -// * starts a function using the test harness, puts the result into a shared -// * AtomicReference, and returns the supplied Completion Id. -// * -// * @param completionId CompletionId to return from the invocation -// * @param result The result from invoking the continuation -// * @param methodName -// * @return a Mockito Answer instance providing the mock behaviour -// */ -// private Answer invokeContinuation(CompletionId completionId, AtomicReference result, String methodName) { -// return fn -> { -// if (fn.getArguments().length == 3) { -// -// Flows.SerCallable closure = fn.getArgument(1); -// -// -// FnTestHarness fnTestHarness = new FnTestHarness(); -// ` -// fnTestHarness.thenRun(FnFlowsFunction.class, methodName); -// -// FnTestHarness.ParsedHttpResponse response = getInnerResponse(fnTestHarness); -// try { -// assertThat(normalisedHeaders(response)) -// .containsEntry(DATUM_TYPE_HEADER.toLowerCase(), DATUM_TYPE_BLOB) -// .containsEntry(CONTENT_TYPE_HEADER.toLowerCase(), CONTENT_TYPE_JAVA_OBJECT); -// result.set(SerUtils.deserializeObject(response.getBodyAsBytes())); -// } catch (Exception e) { -// result.set(e); -// } -// -// return completionId; -// } else { -// throw new RuntimeException("Too few arguments given to supply"); -// } -// }; -// } -// -// -// -// -// @Test -// public void capturedCallableIsInvoked() throws Exception { -// -// Callable r = (Flows.SerCallable) () -> "Foo Bar"; -// -// TestSerUtils.HttpMultipartSerialization ser = new TestSerUtils.HttpMultipartSerialization() -// .addJavaEntity(r); -// -// httpEventToTestFN() -// .withHeader(FLOW_ID_HEADER, FLOW_ID.getId()) -// .withHeaders(ser.getHeaders()) -// .withBody(ser.getContentStream()) -// .enqueue(); -// -// fnTestHarness.thenRun(FnFlowsFunction.class, "supply"); -// -// assertThat(getResultObjectFromSingleResponse(fnTestHarness)).isEqualTo("Foo Bar"); -// } -// -// @Test -// public void capturedRunnableIsInvoked() throws Exception { -// Runnable r = (Flows.SerRunnable) () -> { -// tag.set(true); -// }; -// -// TestSerUtils.HttpMultipartSerialization ser = new TestSerUtils.HttpMultipartSerialization() -// .addJavaEntity(r); -// -// httpEventToTestFN() -// .withHeader(FLOW_ID_HEADER, FLOW_ID.getId()) -// .withHeaders(ser.getHeaders()) -// .withBody(ser.getContentStream()) -// .enqueue(); -// -// fnTestHarness.thenRun(FnFlowsFunction.class, "supply"); -// assertThat(tag.get()).isTrue(); -// } -// -// -// @Test -// public void capturedFunctionWithArgsIsInvoked() throws Exception { -// Function func = (Flows.SerFunction) (in) ->"Foo" + in; -// -// TestSerUtils.HttpMultipartSerialization ser = new TestSerUtils.HttpMultipartSerialization() -// .addJavaEntity(func) -// .addJavaEntity("BAR"); -// -// httpEventToTestFN() -// .withHeader(FLOW_ID_HEADER, FLOW_ID.getId()) -// .withHeaders(ser.getHeaders()) -// .withBody(ser.getContentStream()) -// .enqueue(); -// -// fnTestHarness.thenRun(FnFlowsFunction.class, "supply"); -// -// assertThat(getResultObjectFromSingleResponse(fnTestHarness)).isEqualTo("FooBAR"); -// } -// -// @Test -// public void catastrophicFailureStillResultsInGraphCommitted() throws Exception { -// when(mockCompleterClient.createFlow(FUNCTION_ID)).thenReturn(FLOW_ID); -// -// httpEventToTestFN().enqueue(); -// fnTestHarness.thenRun(FnFlowsFunction.class, "createFlowAndThenFail"); -// -// verify(mockCompleterClient, times(1)).commit(FLOW_ID); -// } -// -// private Object getResultObjectFromSingleResponse(FnTestHarness fnTestHarness) throws IOException, ClassNotFoundException { -// FnTestHarness.ParsedHttpResponse innerResponse = getInnerResponse(fnTestHarness); -// assertThat(normalisedHeaders(innerResponse)) -// .containsEntry(DATUM_TYPE_HEADER.toLowerCase(), DATUM_TYPE_BLOB) -// .containsEntry(CONTENT_TYPE_HEADER.toLowerCase(), CONTENT_TYPE_JAVA_OBJECT); -// return SerUtils.deserializeObject(innerResponse.getBodyAsBytes()); -// } -// -// private FnTestHarness.ParsedHttpResponse getInnerResponse(FnTestHarness fnTestHarness) { -// FnTestHarness.ParsedHttpResponse response = getSingleItem(fnTestHarness.getParsedHttpResponses()); -// return getSingleItem(FnTestHarness.getParsedHttpResponses(response.getBodyAsBytes())); -// } -// -// private T getSingleItem(List items) { -// assertThat(items.size()).isEqualTo(1); -// return items.get(0); -// } -// -// private Map normalisedHeaders(FnTestHarness.ParsedHttpResponse response) { -// return response.getHeaders().entrySet().stream() -// .collect(Collectors.toMap((kv) -> kv.getKey().toLowerCase(), Map.Entry::getValue)); -// } -// -// @Test -// public void capturedRunnableCanGetCurrentFlowRuntime() throws Exception { -// Callable r = (Flows.SerCallable) () -> { -// return Flows.currentFlow().getClass().getName(); -// }; -// -// TestSerUtils.HttpMultipartSerialization ser = new TestSerUtils.HttpMultipartSerialization() -// .addJavaEntity(r); -// -// httpEventToTestFN() -// .withHeader(FLOW_ID_HEADER, FLOW_ID.getId()) -// .withHeaders(ser.getHeaders()) -// .withBody(ser.getContentStream()) -// .enqueue(); -// -// fnTestHarness.thenRun(FnFlowsFunction.class, "supply"); -// -// assertThat(getResultObjectFromSingleResponse(fnTestHarness)).isEqualTo(RemoteFlow.class.getName()); -// } - - //NotSerializedResult - //Throws Exception in closure - //throws unserialized exception in closure - //null result from closure - //null value to closure. -} diff --git a/runtime/src/test/java/com/fnproject/fn/runtime/ntv/UnixSocketNativeTest.java b/runtime/src/test/java/com/fnproject/fn/runtime/ntv/UnixSocketNativeTest.java new file mode 100644 index 00000000..a98d1202 --- /dev/null +++ b/runtime/src/test/java/com/fnproject/fn/runtime/ntv/UnixSocketNativeTest.java @@ -0,0 +1,469 @@ +package com.fnproject.fn.runtime.ntv; + +import org.junit.BeforeClass; +import org.junit.Test; + +import java.io.File; +import java.io.IOException; +import java.net.SocketTimeoutException; +import java.util.concurrent.Callable; +import java.util.concurrent.CompletableFuture; +import java.util.concurrent.CountDownLatch; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.fail; + +/** + * Created on 12/09/2018. + *

+ * (c) 2018 Oracle Corporation + */ +public class UnixSocketNativeTest { + + @BeforeClass + public static void init() { + System.setProperty("com.fnproject.java.native.libdir", new File("src/main/c/").getAbsolutePath()); + } + + File createSocketFile() throws IOException { + File f = File.createTempFile("socket", "sock"); + f.delete(); + f.deleteOnExit(); + return f; + } + + @Test + public void shouldHandleBind() throws Exception { + + + try { // invalid socket + UnixSocketNative.bind(-1, createSocketFile().getAbsolutePath()); + fail("should have thrown an invalid argument"); + } catch (UnixSocketException ignored) { + } + + int socket = UnixSocketNative.socket(); + try { // invalid file location + UnixSocketNative.bind(socket, "/tmp/foodir/socket"); + fail("should have thrown an invalid argument"); + } catch (UnixSocketException ignored) { + } finally { + UnixSocketNative.close(socket); + } + + + socket = UnixSocketNative.socket(); + File socketFile = createSocketFile(); + try { // valid bind + UnixSocketNative.bind(socket, socketFile.getAbsolutePath()); + } finally { + UnixSocketNative.close(socket); + } + } + + public CompletableFuture runServerLoop(Callable loop) { + CompletableFuture result = new CompletableFuture<>(); + Thread t = new Thread(() -> { + try { + result.complete(loop.call()); + } catch (Exception e) { + result.completeExceptionally(e); + } + }); + t.start(); + return result; + } + + @Test + public void shouldHandleConnectAccept() throws Exception { + + // invalid socket + { + try { + UnixSocketNative.connect(-1, "/tmp/nonexistant_path.sock"); + fail("should have failed"); + } catch (UnixSocketException ignored) { + } + } + + + // unknown path + { + int socket = UnixSocketNative.socket(); + try { + UnixSocketNative.connect(socket, "/tmp/nonexistant_path.sock"); + fail("should have failed"); + } catch (UnixSocketException ignored) { + } finally { + UnixSocketNative.close(socket); + } + } + // accept rejects sresult = runServerLoop(() -> { + int ss = UnixSocketNative.socket(); + try { + UnixSocketNative.bind(ss, serverSocket.getAbsolutePath()); + UnixSocketNative.listen(ss, 1); + ready.countDown(); + int cs = UnixSocketNative.accept(ss, 0); + if (cs > 0) { + return true; + } + return false; + } finally { + UnixSocketNative.close(ss); + } + + }); + ready.await(); + int cs; + cs = UnixSocketNative.socket(); + UnixSocketNative.connect(cs, serverSocket.getAbsolutePath()); + + assertThat(sresult.get()).isTrue(); + } + + } + + @Test + public void shouldHonorWrites() throws Exception { + + CountDownLatch ready = new CountDownLatch(1); + File serverSocket = createSocketFile(); + + CompletableFuture result = runServerLoop(() -> { + int ss = UnixSocketNative.socket(); + try { + UnixSocketNative.bind(ss, serverSocket.getAbsolutePath()); + UnixSocketNative.listen(ss, 1); + ready.countDown(); + int cs = UnixSocketNative.accept(ss, 0); + byte[] buf = new byte[100]; + int read = UnixSocketNative.recv(cs, buf, 0, buf.length); + byte[] newBuf = new byte[read]; + System.arraycopy(buf, 0, newBuf, 0, read); + + return newBuf; + } finally { + UnixSocketNative.close(ss); + } + }); + + + {// zero byte write is a noop + ready.await(); + int cs = UnixSocketNative.socket(); + UnixSocketNative.connect(cs, serverSocket.getAbsolutePath()); + + // must NPE on buff + try { + UnixSocketNative.send(cs, null, 0, 10); + fail("should have NPEd"); + } catch (NullPointerException ignored) { + + } + + + // invalid offset + try { + UnixSocketNative.send(cs, "hello".getBytes(), 100, 10); + fail("should have IAEd"); + } catch (IllegalArgumentException ignored) { + + } + + // invalid offset + try { + UnixSocketNative.send(cs, "hello".getBytes(), -1, 10); + fail("should have IAEd"); + } catch (IllegalArgumentException ignored) { + + } + + // invalid offset + try { + UnixSocketNative.send(cs, "hello".getBytes(), 0, 10); + fail("should have IAEd"); + } catch (IllegalArgumentException ignored) { + + } + + try { + // Must nop on write + UnixSocketNative.send(cs, new byte[0], 0, 0); + fail("should have IAEd"); + } catch (IllegalArgumentException ignored) { + + } + + // validate a real write to be sure + UnixSocketNative.send(cs, "hello".getBytes(), 0, 5); + byte[] got = result.get(); + + assertThat(got).isEqualTo("hello".getBytes()); + } + } + + + @Test + public void shouldHonorReads() throws Exception { + CountDownLatch ready = new CountDownLatch(1); + File serverSocket = createSocketFile(); + CompletableFuture result = runServerLoop(() -> { + int ss = UnixSocketNative.socket(); + try { + UnixSocketNative.bind(ss, serverSocket.getAbsolutePath()); + UnixSocketNative.listen(ss, 1); + ready.countDown(); + int cs = UnixSocketNative.accept(ss, 0); + int read = UnixSocketNative.send(cs, "hello".getBytes(), 0, 5); + UnixSocketNative.close(cs); + return true; + } finally { + UnixSocketNative.close(ss); + } + }); + + + {// zero byte write is a noop + ready.await(); + int cs = UnixSocketNative.socket(); + UnixSocketNative.connect(cs, serverSocket.getAbsolutePath()); + + // must NPE on buff + try { + UnixSocketNative.recv(cs, null, 0, 10); + fail("should have NPEd"); + } catch (NullPointerException ignored) { + + } + + // invalid offset + try { + UnixSocketNative.recv(cs, new byte[5], -1, 1); + fail("should have IAEd"); + } catch (IllegalArgumentException ignored) { + + } + // invalid length + try { + UnixSocketNative.recv(cs, new byte[5], 0, -1); + fail("should have IAEd"); + } catch (IllegalArgumentException ignored) { + + } + + // invalid length + try { + UnixSocketNative.recv(cs, new byte[5], 0, 0); + fail("should have IAEd"); + } catch (IllegalArgumentException ignored) { + + } + + // invalid offset beyond buffer + try { + UnixSocketNative.recv(cs, new byte[5], 100, 10); + fail("should have IAEd"); + } catch (IllegalArgumentException ignored) { + + } + + // invalid offset + try { + UnixSocketNative.recv(cs, "hello".getBytes(), -1, 10); + fail("should have IAEd"); + } catch (IllegalArgumentException ignored) { + + } + + // validate a real write to be sure + byte[] buf = new byte[5]; + + int count = UnixSocketNative.recv(cs, buf, 0, 5); + assertThat(count).isEqualTo(5); + + assertThat(buf).isEqualTo("hello".getBytes()); + } + } + + @Test + public void shouldSetSocketOpts() throws Exception { + + int sock = UnixSocketNative.socket(); + try { + try { + UnixSocketNative.setSendBufSize(-1, 1); + fail("should have failed"); + } catch (UnixSocketException ignored) { + } + + try { + UnixSocketNative.setSendBufSize(sock, -1); + fail("should have IAEd"); + } catch (IllegalArgumentException ignored) { + } + + UnixSocketNative.setSendBufSize(sock, 65535); + + + try { + UnixSocketNative.setRecvBufSize(-1, 1); + fail("should have failed"); + } catch (UnixSocketException ignored) { + } + + try { + UnixSocketNative.setRecvBufSize(sock, -1); + fail("should have IAEd"); + } catch (IllegalArgumentException ignored) { + } + + UnixSocketNative.setRecvBufSize(sock, 65535); + + + try { + UnixSocketNative.setSendTimeout(-1, 1); + fail("should have failed"); + } catch (UnixSocketException ignored) { + } + + try { + UnixSocketNative.setSendTimeout(sock, -1); + fail("should have IAEd"); + } catch (IllegalArgumentException ignored) { + } + + UnixSocketNative.setSendTimeout(sock, 2000); + assertThat(UnixSocketNative.getSendTimeout(sock)).isEqualTo(2000); + + + try { + UnixSocketNative.setRecvTimeout(-1, 1); + fail("should have failed"); + } catch (UnixSocketException ignored) { + } + + try { + UnixSocketNative.setRecvTimeout(sock, -1); + fail("should have IAEd"); + } catch (IllegalArgumentException ignored) { + } + + UnixSocketNative.setRecvTimeout(sock, 3000); + assertThat(UnixSocketNative.getRecvTimeout(sock)).isEqualTo(3000); + + + } finally { + UnixSocketNative.close(sock); + } + + } + + + @Test + public void shouldHandleReadTimeouts() throws Exception { + + CountDownLatch ready = new CountDownLatch(1); + File serverSocket = createSocketFile(); + + CompletableFuture result = runServerLoop(() -> { + int ss = UnixSocketNative.socket(); + try { + UnixSocketNative.bind(ss, serverSocket.getAbsolutePath()); + UnixSocketNative.listen(ss, 1); + ready.countDown(); + int cs = UnixSocketNative.accept(ss, 0); + Thread.sleep(100); + int read = UnixSocketNative.send(cs, "hello".getBytes(), 0, 5); + UnixSocketNative.close(cs); + return true; + } finally { + UnixSocketNative.close(ss); + } + }); + + int clientFd = UnixSocketNative.socket(); + UnixSocketNative.setRecvTimeout(clientFd,50); + + ready.await(); + UnixSocketNative.connect(clientFd,serverSocket.getAbsolutePath()); + byte[] buf = new byte[100]; + try { + UnixSocketNative.recv(clientFd, buf, 0, buf.length); + fail("should have timed out"); + }catch (SocketTimeoutException ignored){ + } + + } + + + @Test + public void shouldHandleConnectTimeouts() throws Exception { + + CountDownLatch ready = new CountDownLatch(1); + File serverSocket = createSocketFile(); + + CompletableFuture result = runServerLoop(() -> { + int ss = UnixSocketNative.socket(); + try { + UnixSocketNative.bind(ss, serverSocket.getAbsolutePath()); + UnixSocketNative.listen(ss, 1); + ready.countDown(); + Thread.sleep(1000); + + return true; + } finally { + UnixSocketNative.close(ss); + } + }); + + int clientFd = UnixSocketNative.socket(); + UnixSocketNative.setSendTimeout(clientFd,50); + ready.await(); + try { + UnixSocketNative.connect(clientFd,serverSocket.getAbsolutePath()); + + }catch (SocketTimeoutException ignored){ + } + + } + +} diff --git a/runtime/src/test/java/com/fnproject/fn/runtime/ntv/UnixSocketTest.java b/runtime/src/test/java/com/fnproject/fn/runtime/ntv/UnixSocketTest.java new file mode 100644 index 00000000..050b9ba9 --- /dev/null +++ b/runtime/src/test/java/com/fnproject/fn/runtime/ntv/UnixSocketTest.java @@ -0,0 +1,93 @@ +package com.fnproject.fn.runtime.ntv; + +import org.assertj.core.api.Assertions; +import org.junit.BeforeClass; +import org.junit.Test; + +import java.io.DataInputStream; +import java.io.File; +import java.io.IOException; +import java.util.Random; +import java.util.concurrent.CompletableFuture; +import java.util.concurrent.CountDownLatch; + +/** + * Created on 12/09/2018. + *

+ * (c) 2018 Oracle Corporation + */ +public class UnixSocketTest { + + @BeforeClass + public static void setup() { + System.setProperty("com.fnproject.java.native.libdir", new File("src/main/c/").getAbsolutePath()); + } + + File createSocketFile() throws IOException { + File f = File.createTempFile("socket", "sock"); + f.delete(); + f.deleteOnExit(); + return f; + } + + public byte[] roundTripViaEcho(byte[] data) throws Exception { + + File f = createSocketFile(); + try (UnixServerSocket ss = UnixServerSocket.listen(f.getPath(), 1)) { + + CompletableFuture result = new CompletableFuture<>(); + CountDownLatch cdl = new CountDownLatch(1); + Thread client = new Thread(() -> { + try { + cdl.await(); + try (UnixSocket us = UnixSocket.connect(f.getPath())) { + us.setReceiveBufferSize(65535); + us.setSendBufferSize(65535); + byte[] buf = new byte[data.length]; + us.getOutputStream().write(data); + DataInputStream dis = new DataInputStream(us.getInputStream()); + dis.readFully(buf); + result.complete(buf); + } + } catch (Exception e) { + result.completeExceptionally(e); + } + }); + client.start(); + + cdl.countDown(); + UnixSocket in = ss.accept(1000); + byte[] sbuf = new byte[data.length]; + in.setReceiveBufferSize(65535); + in.setSendBufferSize(65535); + new DataInputStream(in.getInputStream()).readFully(sbuf); + in.getOutputStream().write(sbuf); + in.close(); + return result.get(); + } + } + + @Test + public void shouldHandleEmptyData() throws Exception { + byte[] data = "hello".getBytes(); + Assertions.assertThat(roundTripViaEcho(data)).isEqualTo(data); + + } + + + @Test + public void shouldHandleBigData() throws Exception { + Random r = new Random(); + byte[] dataPart = new byte[2048]; + + r.nextBytes(dataPart); + + byte[] data = new byte[1024 * 1024 * 10]; + for (int i = 0 ; i < data.length ;i += dataPart.length){ + System.arraycopy(dataPart,0,data,i,dataPart.length); + } + + Assertions.assertThat(roundTripViaEcho(data)).isEqualTo(data); + + } +} diff --git a/runtime/src/test/java/com/fnproject/fn/runtime/testfns/coercions/StringReversalCoercion.java b/runtime/src/test/java/com/fnproject/fn/runtime/testfns/coercions/StringReversalCoercion.java index a08d6bb7..9994b3d2 100644 --- a/runtime/src/test/java/com/fnproject/fn/runtime/testfns/coercions/StringReversalCoercion.java +++ b/runtime/src/test/java/com/fnproject/fn/runtime/testfns/coercions/StringReversalCoercion.java @@ -26,7 +26,7 @@ public Optional wrapFunctionResult(InvocationContext ctx, MethodWra if (ctx.getRuntimeContext().getMethod().getTargetMethod().getReturnType().equals(String.class)) { try { String reversedOutput = new StringBuffer((String) value).reverse().toString(); - return Optional.of(OutputEvent.fromBytes(reversedOutput.getBytes(), OutputEvent.SUCCESS, "text/plain")); + return Optional.of(OutputEvent.fromBytes(reversedOutput.getBytes(), OutputEvent.Status.Success, "text/plain")); } catch (ClassCastException e) { return Optional.empty(); } diff --git a/runtime/src/test/java/com/fnproject/fn/runtime/testfns/coercions/StringUpperCaseCoercion.java b/runtime/src/test/java/com/fnproject/fn/runtime/testfns/coercions/StringUpperCaseCoercion.java index b2a5959e..809c5ed1 100644 --- a/runtime/src/test/java/com/fnproject/fn/runtime/testfns/coercions/StringUpperCaseCoercion.java +++ b/runtime/src/test/java/com/fnproject/fn/runtime/testfns/coercions/StringUpperCaseCoercion.java @@ -27,7 +27,7 @@ public Optional wrapFunctionResult(InvocationContext ctx, MethodWra if (ctx.getRuntimeContext().getMethod().getTargetMethod().getReturnType().equals(String.class)) { try { String capitilisedOutput = new StringBuffer((String) value).toString().toUpperCase(); - return Optional.of(OutputEvent.fromBytes(capitilisedOutput.getBytes(), OutputEvent.SUCCESS, "text/plain")); + return Optional.of(OutputEvent.fromBytes(capitilisedOutput.getBytes(), OutputEvent.Status.Success, "text/plain")); } catch (ClassCastException e) { return Optional.empty(); } diff --git a/testing-core/src/main/java/com/fnproject/fn/testing/FnEventBuilder.java b/testing-core/src/main/java/com/fnproject/fn/testing/FnEventBuilder.java index fe5809df..21804284 100644 --- a/testing-core/src/main/java/com/fnproject/fn/testing/FnEventBuilder.java +++ b/testing-core/src/main/java/com/fnproject/fn/testing/FnEventBuilder.java @@ -1,5 +1,6 @@ package com.fnproject.fn.testing; +import java.io.IOException; import java.io.InputStream; /** @@ -22,10 +23,9 @@ public interface FnEventBuilder { * Note - setting the body to an input stream means that only one event can be enqueued using this builder. * * @param body the bytes of the body - * @param contentLength how long the body is supposed to be * @return an event builder */ - FnEventBuilder withBody(InputStream body, int contentLength); + FnEventBuilder withBody(InputStream body) throws IOException; /** * Set the body of the request as a byte array @@ -43,47 +43,6 @@ public interface FnEventBuilder { */ FnEventBuilder withBody(String body); - /** - * Set the app name associated with the call - * - * @param appName the app name - * @return an event builder - */ - FnEventBuilder withAppName(String appName); - - /** - * Set the fn route associated with the call - * - * @param route the route - * @return an event builder - */ - FnEventBuilder withRoute(String route); - - /** - * Set the HTTP method of the incoming request - * - * @param method an HTTP method - * @return an event builder - */ - FnEventBuilder withMethod(String method); - - /** - * Set the request URL of the incoming event - * - * @param requestUrl the request URL - * @return an event builder - */ - FnEventBuilder withRequestUrl(String requestUrl); - - /** - * Add a query parameter to the request URL - * - * @param key - non URL encoded key - * @param value - non URL encoded value - * @return an event builder - */ - FnEventBuilder withQueryParameter(String key, String value); - /** * Consume the builder and enqueue this event to be passed into the function when it is run * diff --git a/testing-core/src/main/java/com/fnproject/fn/testing/FnHttpEventBuilder.java b/testing-core/src/main/java/com/fnproject/fn/testing/FnHttpEventBuilder.java index 9fe4a5b0..0813ce5b 100644 --- a/testing-core/src/main/java/com/fnproject/fn/testing/FnHttpEventBuilder.java +++ b/testing-core/src/main/java/com/fnproject/fn/testing/FnHttpEventBuilder.java @@ -1,58 +1,41 @@ package com.fnproject.fn.testing; -import org.apache.http.impl.io.ContentLengthInputStream; -import org.apache.http.impl.io.HttpTransportMetricsImpl; -import org.apache.http.impl.io.SessionInputBufferImpl; +import com.fnproject.fn.api.Headers; +import com.fnproject.fn.api.InputEvent; +import com.fnproject.fn.runtime.ReadOnceInputEvent; +import org.apache.commons.io.IOUtils; import java.io.ByteArrayInputStream; +import java.io.IOException; import java.io.InputStream; -import java.io.SequenceInputStream; -import java.io.UnsupportedEncodingException; -import java.net.URLEncoder; -import java.util.*; -import java.util.stream.Collectors; +import java.time.Instant; +import java.time.temporal.ChronoUnit; +import java.util.Map; +import java.util.Objects; -class FnHttpEventBuilder { - private Map> queryParams = new TreeMap<>(); - private boolean streamRead = false; - private String method; - private String appName; - private String route; - private String requestUrl; +public class FnHttpEventBuilder { private byte[] bodyBytes = new byte[0]; - private InputStream bodyStream; - private int contentLength = 0; - private Map headers = new HashMap<>(); - + private Headers headers = Headers.emptyHeaders(); + private Instant deadline = Instant.now().plus(1, ChronoUnit.HOURS); public FnHttpEventBuilder withHeader(String key, String value) { Objects.requireNonNull(key, "key"); Objects.requireNonNull(value, "value"); - headers.put(key, value); + headers = headers.addHeader(key, value); return this; } - public FnHttpEventBuilder withBody(InputStream body, int contentLength) { + public FnHttpEventBuilder withBody(InputStream body) throws IOException { Objects.requireNonNull(body, "body"); - if (contentLength < 0) { - throw new IllegalArgumentException("Invalid contentLength"); - } - // This is for safety. Because we concatenate events, an input stream shorter than content length will cause - // the implementation to continue reading through to the next http request. We need to avoid a sort of - // buffer overrun. - // FIXME: Make InputStream handling simpler. - SessionInputBufferImpl sib = new SessionInputBufferImpl(new HttpTransportMetricsImpl(), 65535); - sib.bind(body); - this.bodyStream = new ContentLengthInputStream(sib, contentLength); - this.contentLength = contentLength; + this.bodyBytes = IOUtils.toByteArray(body); + return this; } public FnHttpEventBuilder withBody(byte[] body) { Objects.requireNonNull(body, "body"); this.bodyBytes = body; - this.contentLength = body.length; - this.bodyStream = null; + return this; } @@ -61,117 +44,19 @@ public FnHttpEventBuilder withBody(String body) { return withBody(stringAsBytes); } - public FnHttpEventBuilder withRoute(String route) { - Objects.requireNonNull(route, "route"); - this.route = route; - return this; - } - - public FnHttpEventBuilder withMethod(String method) { - Objects.requireNonNull(method, "method"); - this.method = method.toUpperCase(); - return this; - } - - public FnHttpEventBuilder withAppName(String appName) { - Objects.requireNonNull(appName, "appName"); - this.appName = appName; - return this; - } - - public FnHttpEventBuilder withRequestUrl(String requestUrl) { - Objects.requireNonNull(requestUrl, "requestUrl"); - this.requestUrl = requestUrl; - return this; - } - - private String buildQueryParams() { - return queryParams.entrySet().stream() - .flatMap((e) -> e.getValue().stream() - .map((v) -> urlEncode(e.getKey()) + "=" + urlEncode(v))) - .collect(Collectors.joining("&")); - } - - - public FnHttpEventBuilder withQueryParameter(String key, String value) { - if (!this.queryParams.containsKey(key)) { - this.queryParams.put(key, new ArrayList<>()); - } - this.queryParams.get(key).add(value); - return this; - } public FnHttpEventBuilder withHeaders(Map headers) { - this.headers.putAll(headers); - return this; - } - - private String urlEncode(String str) { - try { - return URLEncoder.encode(str, "utf-8"); - } catch (UnsupportedEncodingException e) { - throw new RuntimeException("Your jvm doesn't support UTF-8, cannot continue."); - } - } - - private InputStream bodyAsStream() { - if (bodyStream != null) { - if (streamRead) { - throw new IllegalStateException("events with an overridden input stream can only be enqueued once"); - } - streamRead = true; - return bodyStream; - } else { - return new ByteArrayInputStream(bodyBytes); + Headers h = this.headers; + for (Map.Entry he : headers.entrySet()) { + h = h.setHeader(he.getKey(), he.getValue()); } + this.headers = h; + return this; } - private void verify() { - Objects.requireNonNull(method, "method not set"); - Objects.requireNonNull(appName, "appName not set"); - Objects.requireNonNull(route, "route not set"); - Objects.requireNonNull(requestUrl, "requestUrl not set"); - - } - - public Map currentEventEnv() { - verify(); - Map env = new HashMap<>(); - headers.forEach((k, v) -> env.put("FN_HEADER_" + k.toUpperCase().replaceAll("-", "_"), v)); - env.put("FN_METHOD", method); - env.put("FN_APP_NAME", appName); - env.put("FN_PATH", route); - env.put("FN_REQUEST_URL", requestUrl); - return env; - } - - public InputStream currentEventInputStream() { - verify(); - - String queryParamsFullString = buildQueryParams(); - StringBuilder inputString = new StringBuilder(); - - inputString.append(method); - inputString.append(" / HTTP/1.1\r\n"); - inputString.append("Fn_App_name: ").append(appName).append("\r\n"); - inputString.append("Fn_Method: ").append(method).append("\r\n"); - inputString.append("Fn_Path: ").append(route).append("\r\n"); - inputString.append("Fn_Request_url: ").append(requestUrl); - if (!queryParamsFullString.isEmpty()) { - inputString.append("?").append(queryParamsFullString); - } - inputString.append("\r\n"); - - - inputString.append("Content-length: ").append(Integer.toString(contentLength)).append("\r\n"); - headers.forEach((k, v) -> inputString.append(k).append(": ").append(String.join(", ", v)).append("\r\n")); - - - inputString.append("\r\n"); - return new SequenceInputStream( - new ByteArrayInputStream(inputString.toString().getBytes()), - bodyAsStream()); + public InputEvent buildEvent() { + return new ReadOnceInputEvent(new ByteArrayInputStream(bodyBytes), headers, "callId", deadline); } diff --git a/testing-core/src/main/java/com/fnproject/fn/testing/FnResult.java b/testing-core/src/main/java/com/fnproject/fn/testing/FnResult.java index cbfadb6e..6c660013 100644 --- a/testing-core/src/main/java/com/fnproject/fn/testing/FnResult.java +++ b/testing-core/src/main/java/com/fnproject/fn/testing/FnResult.java @@ -1,11 +1,11 @@ package com.fnproject.fn.testing; -import com.fnproject.fn.api.Headers; +import com.fnproject.fn.api.OutputEvent; /** - * A simple abstraction for a parsed HTTP response returned by a function + * A simple abstraction over {@link OutputEvent} that buffers the response body */ -public interface FnResult { +public interface FnResult extends OutputEvent { /** * Returns the body of the function result as a byte array * @@ -20,21 +20,6 @@ public interface FnResult { */ String getBodyAsString(); - /** - * A map of the headers returned by the function - *

- * These are squashed so duplicated headers will be ignored (takes the first header). - * - * @return a map of headers - */ - Headers getHeaders(); - - /** - * Returns the HTTP status code of the function response - * - * @return the HTTP status code returned by the function - */ - int getStatus(); /** * Determine if the status code corresponds to a successful invocation @@ -42,6 +27,6 @@ public interface FnResult { * @return true if the status code indicates success */ default boolean isSuccess() { - return 100 <= getStatus() && getStatus() < 400; + return getStatus() == Status.Success; } } diff --git a/testing-core/src/main/java/com/fnproject/fn/testing/FnTestingClassLoader.java b/testing-core/src/main/java/com/fnproject/fn/testing/FnTestingClassLoader.java index ca6dffcd..ff45abec 100644 --- a/testing-core/src/main/java/com/fnproject/fn/testing/FnTestingClassLoader.java +++ b/testing-core/src/main/java/com/fnproject/fn/testing/FnTestingClassLoader.java @@ -1,13 +1,11 @@ package com.fnproject.fn.testing; import com.fnproject.fn.runtime.EntryPoint; -import com.fnproject.fn.runtime.flow.CompleterClientFactory; -import com.fnproject.fn.runtime.flow.FlowRuntimeGlobals; +import com.fnproject.fn.runtime.EventCodec; import org.apache.commons.io.IOUtils; import java.io.IOException; import java.io.InputStream; -import java.io.OutputStream; import java.io.PrintStream; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; @@ -18,11 +16,11 @@ /** * Testing classloader that loads all classes afresh when needed, otherwise delegates shared classes to the parent classloader */ -class FnTestingClassLoader extends ClassLoader { +public class FnTestingClassLoader extends ClassLoader { private final List sharedPrefixes; private final Map> loaded = new HashMap<>(); - FnTestingClassLoader(ClassLoader parent, List sharedPrefixes) { + public FnTestingClassLoader(ClassLoader parent, List sharedPrefixes) { super(parent); this.sharedPrefixes = sharedPrefixes; } @@ -67,16 +65,8 @@ public synchronized Class loadClass(String className) throws ClassNotFoundExc return cls; } - void setCompleterClient(CompleterClientFactory completerClientFactory) { - try { - Class completerGlobals = loadClass(FlowRuntimeGlobals.class.getName()); - callMethodInFnClassloader(completerGlobals, "setCompleterClientFactory", CompleterClientFactory.class).invoke(completerGlobals, completerClientFactory); - } catch (NoSuchMethodException | IllegalAccessException | InvocationTargetException | ClassNotFoundException | IllegalArgumentException e) { - throw new RuntimeException("Something broke in the reflective classloader", e); - } - } - public int run(Map mutableEnv, InputStream is, PrintStream functionOut, PrintStream functionErr, String... s) { + public int run(Map mutableEnv, EventCodec codec, PrintStream functionErr, String... s) { ClassLoader currentClassLoader = Thread.currentThread().getContextClassLoader(); try { @@ -86,16 +76,16 @@ public int run(Map mutableEnv, InputStream is, PrintStream funct Class entryPoint_class = loadClass(EntryPoint.class.getName()); Object entryPoint = entryPoint_class.newInstance(); - return (int) callMethodInFnClassloader(entryPoint, "run", Map.class, InputStream.class, OutputStream.class, PrintStream.class, String[].class) - .invoke(entryPoint, mutableEnv, is, functionOut, functionErr, s); + return (int) getMethodInClassLoader(entryPoint, "run", Map.class, EventCodec.class, PrintStream.class, String[].class) + .invoke(entryPoint, mutableEnv, codec, functionErr, s); } catch (ClassNotFoundException | IllegalAccessException | InstantiationException | NoSuchMethodException | InvocationTargetException | IllegalArgumentException e) { throw new RuntimeException("Something broke in the reflective classloader", e); - }finally { + } finally { Thread.currentThread().setContextClassLoader(currentClassLoader); } } - private Method callMethodInFnClassloader(Object target, String method, Class... types) throws NoSuchMethodException, InvocationTargetException, IllegalAccessException { + private Method getMethodInClassLoader(Object target, String method, Class... types) throws NoSuchMethodException { Class targetClass; if (target instanceof Class) { targetClass = (Class) target; diff --git a/testing-junit4/pom.xml b/testing-junit4/pom.xml index 61f4d5be..1e8f9c37 100644 --- a/testing-junit4/pom.xml +++ b/testing-junit4/pom.xml @@ -26,6 +26,11 @@ junit compile + + org.assertj + assertj-core + test + \ No newline at end of file diff --git a/testing-junit4/src/main/java/com/fnproject/fn/testing/FnFunctionStubBuilderJUnit4.java b/testing-junit4/src/main/java/com/fnproject/fn/testing/FnFunctionStubBuilderJUnit4.java deleted file mode 100644 index aff322b9..00000000 --- a/testing-junit4/src/main/java/com/fnproject/fn/testing/FnFunctionStubBuilderJUnit4.java +++ /dev/null @@ -1,9 +0,0 @@ -package com.fnproject.fn.testing; - -public interface FnFunctionStubBuilderJUnit4 extends FnFunctionStubBuilder { - - - - - -} diff --git a/testing-junit4/src/main/java/com/fnproject/fn/testing/FnTestingRule.java b/testing-junit4/src/main/java/com/fnproject/fn/testing/FnTestingRule.java index df4a7ff6..4e5932de 100644 --- a/testing-junit4/src/main/java/com/fnproject/fn/testing/FnTestingRule.java +++ b/testing-junit4/src/main/java/com/fnproject/fn/testing/FnTestingRule.java @@ -1,30 +1,22 @@ package com.fnproject.fn.testing; -import com.fasterxml.jackson.core.JsonProcessingException; import com.fasterxml.jackson.databind.ObjectMapper; import com.fnproject.fn.api.Headers; import com.fnproject.fn.api.InputEvent; import com.fnproject.fn.api.OutputEvent; -import com.fnproject.fn.api.QueryParameters; -import com.fnproject.fn.api.flow.*; -import com.fnproject.fn.runtime.flow.*; -import org.apache.commons.io.IOUtils; +import com.fnproject.fn.runtime.EventCodec; import org.apache.commons.io.output.TeeOutputStream; -import org.apache.http.HttpResponse; -import org.apache.http.NoHttpResponseException; -import org.apache.http.impl.io.*; +import org.junit.Rule; import org.junit.rules.TestRule; import org.junit.runner.Description; import org.junit.runners.model.Statement; import java.io.*; import java.util.*; -import java.util.concurrent.CompletableFuture; -import static com.fnproject.fn.runtime.flow.RemoteFlowApiClient.CONTENT_TYPE_HEADER; /** - * Testing {@link org.junit.Rule} for fn Java FDK functions. + * Testing {@link Rule} for fn Java FDK functions. *

* This interface facilitates: *

    @@ -42,11 +34,7 @@ * public void myTest() { * // Create an event to invoke MyFunction and put it into the event queue * fn.givenEvent() - * .withAppName("alpha") - * .withRoute("/bravo") - * .withRequestUrl("http://charlie/alpha/bravo") - * .withMethod("POST") - * .withHeader("FOO", "BAR") + * .addHeader("FOO", "BAR") * .withBody("Body") * .enqueue(); * @@ -64,16 +52,14 @@ public final class FnTestingRule implements TestRule { private final Map config = new HashMap<>(); private Map eventEnv = new HashMap<>(); private boolean hasEvents = false; - private InputStream pendingInput = new ByteArrayInputStream(new byte[0]); - private ByteArrayOutputStream stdOut = new ByteArrayOutputStream(); + private List pendingInput = Collections.synchronizedList(new ArrayList<>()); + private List output = Collections.synchronizedList(new ArrayList<>()); private ByteArrayOutputStream stdErr = new ByteArrayOutputStream(); - private Map functionStubs = new HashMap<>(); - public static InMemCompleter completer = null; private static final ObjectMapper objectMapper = new ObjectMapper(); - private final List sharedPrefixes = new ArrayList<>(); private int lastExitCode; + private final List features = new ArrayList<>(); { // Internal shared classes required to bridge completer into tests @@ -82,33 +68,92 @@ public final class FnTestingRule implements TestRule { addSharedClassPrefix("sun."); addSharedClassPrefix("jdk."); - addSharedClass(CompleterClient.class); - addSharedClass(BlobStoreClient.class); - addSharedClass(BlobResponse.class); - addSharedClass(CompleterClientFactory.class); - addSharedClass(CompletionId.class); - addSharedClass(FlowId.class); - addSharedClass(Flow.FlowState.class); - addSharedClass(CodeLocation.class); addSharedClass(Headers.class); - addSharedClass(HttpMethod.class); - addSharedClass(com.fnproject.fn.api.flow.HttpRequest.class); - addSharedClass(com.fnproject.fn.api.flow.HttpResponse.class); - addSharedClass(QueryParameters.class); addSharedClass(InputEvent.class); addSharedClass(OutputEvent.class); - addSharedClass(FlowCompletionException.class); - addSharedClass(FunctionInvocationException.class); - addSharedClass(PlatformException.class); + addSharedClass(OutputEvent.Status.class); + addSharedClass(TestOutput.class); + addSharedClass(TestCodec.class); + addSharedClass(EventCodec.class); + addSharedClass(EventCodec.Handler.class); + + + } + + /** + * TestOutput represents an output of a function it wraps OutputEvent and provides buffered access to the function output + */ + public static final class TestOutput implements FnResult { + private final OutputEvent from; + byte[] body; + + private TestOutput(OutputEvent from) throws IOException { + this.from = Objects.requireNonNull(from, "from"); + ByteArrayOutputStream bos = new ByteArrayOutputStream(); + from.writeToOutput(bos); + body = bos.toByteArray(); + } + + /** + * construct a test output from an output event - this consums the body of the output event + * + * @param from an output event to consume + * @return a new TestEvent that wraps the passed even t + * @throws IOException + */ + public static TestOutput fromOutputEvent(OutputEvent from) throws IOException { + return new TestOutput(from); + } + + @Override + public Status getStatus() { + return from.getStatus(); + } + + @Override + public Optional getContentType() { + return from.getContentType(); + } + + @Override + public Headers getHeaders() { + return from.getHeaders(); + } + + @Override + public void writeToOutput(OutputStream out) throws IOException { + out.write(body); + } + + + @Override + public byte[] getBodyAsBytes() { + return body; + } + + /** + * Returns the buffered body of the event as a string + * + * @return the body of the event as a string + */ + @Override + public String getBodyAsString() { + return new String(body); + } } private FnTestingRule() { } + + public void addFeature(FnTestingRuleFeature f) { + this.features.add(f); + } + /** - * Create an instance of the testing {@link org.junit.Rule}, with Flows support + * Create an instance of the testing {@link Rule}, with Flows support * * @return a new test rule */ @@ -180,6 +225,27 @@ public void thenRun(Class cls, String method) { } + public static class TestCodec implements EventCodec { + private final List input; + private final List output; + + public TestCodec(List input, List output) { + this.input = input; + this.output = output; + } + + @Override + public void runCodec(Handler h) { + for (InputEvent in : input) { + try { + output.add(new TestOutput(h.handle(in))); + } catch (IOException e) { + throw new RuntimeException("Unexpected exception in test", e); + } + } + } + } + /** * Runs the function runtime with the specified class and method (and waits for Flow stages to finish * if the test spawns any Flow) @@ -206,46 +272,45 @@ public void thenRun(String cls, String method) { PrintStream oldSystemOut = System.out; PrintStream oldSystemErr = System.err; - InMemCompleter.CompleterInvokeClient client = new TestRuleCompleterInvokeClient(functionClassLoader, oldSystemErr, cls, method); - - InMemCompleter.FnInvokeClient fnInvokeClient = new TestRuleFnInvokeClient(); - - // FlowContinuationInvoker.setTestingMode(true); - // The following must be a static: otherwise the factory (the lambda) will not be serializable. - completer = new InMemCompleter(client, fnInvokeClient); - - //TestSupport.installCompleterClientFactory(completer, oldSystemErr); - + for (FnTestingRuleFeature f : features) { + f.prepareTest(functionClassLoader, oldSystemErr, cls, method); + } Map mutableEnv = new HashMap<>(); try { - PrintStream functionOut = new PrintStream(stdOut); PrintStream functionErr = new PrintStream(new TeeOutputStream(stdErr, oldSystemErr)); System.setOut(functionErr); System.setErr(functionErr); mutableEnv.putAll(config); mutableEnv.putAll(eventEnv); - mutableEnv.put("FN_FORMAT", "http"); + mutableEnv.put("FN_FORMAT", "http-stream"); + mutableEnv.put("FN_FN_ID","myFnID"); + mutableEnv.put("FN_APP_ID","myAppID"); FnTestingClassLoader forked = new FnTestingClassLoader(functionClassLoader, sharedPrefixes); if (forked.isShared(cls)) { oldSystemErr.println("WARNING: The function class under test is shared with the test ClassLoader."); oldSystemErr.println(" This may result in unexpected behaviour around function initialization and configuration."); } - forked.setCompleterClient(completer); + for (FnTestingRuleFeature f : features) { + f.prepareFunctionClassLoader(forked); + } + + TestCodec codec = new TestCodec(pendingInput, output); + lastExitCode = forked.run( - mutableEnv, - pendingInput, - functionOut, - functionErr, - cls + "::" + method); + mutableEnv, + codec, + functionErr, + cls + "::" + method); - stdOut.flush(); stdErr.flush(); - completer.awaitTermination(); + for (FnTestingRuleFeature f : features) { + f.afterTestComplete(); + } } catch (Exception e) { throw new RuntimeException("internal error raised by entry point or flushing the test streams", e); } finally { @@ -291,7 +356,7 @@ public String getStdErrAsString() { * @return a list of Parsed HTTP responses (as {@link FnResult}s) from the function runtime output */ public List getResults() { - return parseHttpStreamForResults(stdOut.toByteArray()); + return output; } /** @@ -309,108 +374,25 @@ public FnResult getOnlyResult() { } - private List parseHttpStreamForResults(byte[] httpStream) { - SessionInputBufferImpl sib = new SessionInputBufferImpl(new HttpTransportMetricsImpl(), 65535); - ByteArrayInputStream parseStream = new ByteArrayInputStream(httpStream); - sib.bind(parseStream); - - DefaultHttpResponseParser parser = new DefaultHttpResponseParser(sib); - List responses = new ArrayList<>(); - - while (true) { - try { - HttpResponse response = parser.parse(); - ByteArrayOutputStream bos = new ByteArrayOutputStream(); - ContentLengthInputStream cis = new ContentLengthInputStream(sib, Long.parseLong(response.getFirstHeader("Content-length").getValue())); - - IOUtils.copy(cis, bos); - cis.close(); - byte[] body = bos.toByteArray(); - FnResult r = new FnResult() { - @Override - public byte[] getBodyAsBytes() { - return body; - } - - @Override - public String getBodyAsString() { - return new String(body); - } - - @Override - public Headers getHeaders() { - Map headers = new HashMap<>(); - Arrays.stream(response.getAllHeaders()).forEach((h) -> - headers.put(h.getName(), h.getValue())); - return Headers.fromMap(headers); - } - - @Override - public int getStatus() { - return response.getStatusLine().getStatusCode(); - } - }; - responses.add(r); - } catch (NoHttpResponseException e) { - break; - } catch (Exception e) { - throw new RuntimeException("Invalid HTTP response", e); - } - } - return responses; + public List getSharedPrefixes() { + return Collections.unmodifiableList(sharedPrefixes); } - - public FnFunctionStubBuilderJUnit4 givenFn(String id) { - return new FnFunctionStubBuilderJUnit4() { - @Override - public FnTestingRule withResult(byte[] result) { - return withAction((body) -> result); - } - - @Override - public FnTestingRule withFunctionError() { - return withAction((body) -> { - throw new FunctionError("simulated by testing platform"); - }); - } - - @Override - public FnTestingRule withPlatformError() { - return withAction((body) -> { - throw new PlatformError("simulated by testing platform"); - }); - } - - @Override - public FnTestingRule withAction(ExternalFunctionAction f) { - functionStubs.put(id, (HttpMethod method, Headers headers, byte[] body) -> { - try { - return new DefaultHttpResponse(200, Headers.emptyHeaders(), f.apply(body)); - } catch (FunctionError functionError) { - return new DefaultHttpResponse(500, Headers.emptyHeaders(), functionError.getMessage().getBytes()); - } catch (PlatformError platformError) { - throw new RuntimeException("Platform Error"); - } - }); - return FnTestingRule.this; - } - }; + public Map getConfig() { + return Collections.unmodifiableMap(config); } - private interface FnFunctionStub { - com.fnproject.fn.api.flow.HttpResponse stubFunction(HttpMethod method, Headers headers, byte[] body); + public Map getEventEnv() { + return Collections.unmodifiableMap(eventEnv); } + /** * Builds a mocked input event into the function runtime */ private class DefaultFnEventBuilder implements FnEventBuilderJUnit4 { - FnHttpEventBuilder builder = new FnHttpEventBuilder().withMethod("GET") - .withAppName("appName") - .withRoute("/route") - .withRequestUrl("http://example.com/r/appName/route"); + FnHttpEventBuilder builder = new FnHttpEventBuilder(); @Override @@ -420,8 +402,8 @@ public FnEventBuilder withHeader(String key, String value) { } @Override - public FnEventBuilder withBody(InputStream body, int contentLength) { - builder.withBody(body, contentLength); + public FnEventBuilder withBody(InputStream body) throws IOException { + builder.withBody(body); return this; } @@ -437,47 +419,11 @@ public FnEventBuilder withBody(String body) { return this; } - @Override - public FnEventBuilder withAppName(String appName) { - builder.withAppName(appName); - return this; - } - - @Override - public FnEventBuilder withRoute(String route) { - builder.withRoute(route); - return this; - } - - @Override - public FnEventBuilder withMethod(String method) { - builder.withMethod(method); - return this; - } - - @Override - public FnEventBuilder withRequestUrl(String requestUrl) { - builder.withRequestUrl(requestUrl); - return this; - - } - - @Override - public FnEventBuilder withQueryParameter(String key, String value) { - builder.withQueryParameter(key, value); - return this; - } @Override public FnTestingRule enqueue() { - // Only set env for first event. - if (!hasEvents) { - eventEnv.putAll(builder.currentEventEnv()); - } - hasEvents = true; - - pendingInput = new SequenceInputStream(pendingInput, builder.currentEventInputStream()); + pendingInput.add(builder.buildEvent()); return FnTestingRule.this; } @@ -496,118 +442,4 @@ public FnTestingRule enqueue(int n) { } - private class TestRuleCompleterInvokeClient implements InMemCompleter.CompleterInvokeClient { - private final ClassLoader functionClassLoader; - private final PrintStream oldSystemErr; - private final String cls; - private final String method; - private final Set pool = new HashSet<>(); - - - public TestRuleCompleterInvokeClient(ClassLoader functionClassLoader, PrintStream oldSystemErr, String cls, String method) { - this.functionClassLoader = functionClassLoader; - this.oldSystemErr = oldSystemErr; - this.cls = cls; - this.method = method; - } - - - @Override - public APIModel.CompletionResult invokeStage(String fnId, FlowId flowId, CompletionId stageId, APIModel.Blob closure, List input) { - // Construct a new ClassLoader hierarchy with a copy of the statics embedded in the runtime. - // Initialise it appropriately. - FnTestingClassLoader fcl = new FnTestingClassLoader(functionClassLoader, sharedPrefixes); - fcl.setCompleterClient(completer); - - - APIModel.InvokeStageRequest request = new APIModel.InvokeStageRequest(); - request.stageId = stageId.getId(); - request.flowId = flowId.getId(); - request.closure = closure; - request.args = input; - - String inputBody = null; - try { - inputBody = objectMapper.writeValueAsString(request); - } catch (JsonProcessingException e) { - throw new IllegalStateException("Invalid request"); - } - - // oldSystemErr.println("Body\n" + new String(inputBody)); - - InputStream is = new FnHttpEventBuilder() - .withBody(inputBody) - .withAppName("appName") - .withRoute("/route").withRequestUrl("http://some/url") - .withMethod("POST") - .withHeader(CONTENT_TYPE_HEADER, "application/json") - .withHeader(FlowContinuationInvoker.FLOW_ID_HEADER, flowId.getId()).currentEventInputStream(); - - ByteArrayOutputStream output = new ByteArrayOutputStream(); - Map mutableEnv = new HashMap<>(); - PrintStream functionOut = new PrintStream(output); - PrintStream functionErr = new PrintStream(oldSystemErr); - - // Do we want to capture IO from continuations on the main log stream? - // System.setOut(functionErr); - // System.setErr(functionErr); - - mutableEnv.putAll(config); - mutableEnv.putAll(eventEnv); - mutableEnv.put("FN_FORMAT", "http"); - - - fcl.run( - mutableEnv, - is, - functionOut, - functionErr, - cls + "::" + method); - - - SessionInputBufferImpl sib = new SessionInputBufferImpl(new HttpTransportMetricsImpl(), 65535); - ByteArrayInputStream parseStream = new ByteArrayInputStream(output.toByteArray()); - sib.bind(parseStream); - DefaultHttpResponseParser parser = new DefaultHttpResponseParser(sib); - APIModel.CompletionResult r; - try { - // Read wrapping result, and throw it away - parser.parse(); - IdentityInputStream iis = new IdentityInputStream(sib); - byte[] responseBody = IOUtils.toByteArray(iis); - - APIModel.InvokeStageResponse response = objectMapper.readValue(responseBody, APIModel.InvokeStageResponse.class); - r = response.result; - - } catch (Exception e) { - oldSystemErr.println("Err\n" + e); - e.printStackTrace(oldSystemErr); - r = APIModel.CompletionResult.failure(APIModel.ErrorDatum.newError(APIModel.ErrorType.UnknownError, "Error reading fn Response:" + e.getMessage())); - } - - if (!r.successful) { - throw new ResultException(r.result); - } - return r; - - } - } - - private class TestRuleFnInvokeClient implements InMemCompleter.FnInvokeClient { - @Override - public CompletableFuture invokeFunction(String fnId, HttpMethod method, Headers headers, byte[] data) { - FnFunctionStub stub = functionStubs - .computeIfAbsent(fnId, (k) -> { - throw new IllegalStateException("Function was invoked that had no definition: " + k); - }); - - try { - return CompletableFuture.completedFuture(stub.stubFunction(method, headers, data)); - } catch (Exception e) { - CompletableFuture respFuture = new CompletableFuture<>(); - respFuture.completeExceptionally(e); - return respFuture; - } - } - } } diff --git a/testing-junit4/src/main/java/com/fnproject/fn/testing/FnTestingRuleFeature.java b/testing-junit4/src/main/java/com/fnproject/fn/testing/FnTestingRuleFeature.java new file mode 100644 index 00000000..42b25454 --- /dev/null +++ b/testing-junit4/src/main/java/com/fnproject/fn/testing/FnTestingRuleFeature.java @@ -0,0 +1,26 @@ +package com.fnproject.fn.testing; + +import java.io.PrintStream; + +/** + * Created on 07/09/2018. + *

    + * (c) 2018 Oracle Corporation + */ +public interface FnTestingRuleFeature { + + /** + * Prepares a test + * @param functionClassLoader + * @param stderr + * @param cls + * @param method + */ + void prepareTest(ClassLoader functionClassLoader, PrintStream stderr, String cls, String method); + + + void prepareFunctionClassLoader(FnTestingClassLoader cl); + + + void afterTestComplete(); +} diff --git a/testing-junit4/src/test/java/com/fnproject/fn/testing/FnTestingRuleTest.java b/testing-junit4/src/test/java/com/fnproject/fn/testing/FnTestingRuleTest.java new file mode 100644 index 00000000..03df8764 --- /dev/null +++ b/testing-junit4/src/test/java/com/fnproject/fn/testing/FnTestingRuleTest.java @@ -0,0 +1,340 @@ +package com.fnproject.fn.testing; + +import com.fnproject.fn.api.Headers; +import com.fnproject.fn.api.InputEvent; +import com.fnproject.fn.api.OutputEvent; +import com.fnproject.fn.api.RuntimeContext; +import org.apache.commons.io.IOUtils; +import org.assertj.core.api.Assertions; +import org.junit.Before; +import org.junit.Rule; +import org.junit.Test; + +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.io.InputStream; +import java.util.*; + +public class FnTestingRuleTest { + + public static Map configuration; + public static InputEvent inEvent; + public static List capturedInputs = new ArrayList<>(); + public static List capturedBodies = new ArrayList<>(); + + @Rule + public FnTestingRule fn = FnTestingRule.createDefault(); + private final String exampleBaseUrl = "http://www.example.com"; + + @Before + public void reset() { + fn.addSharedClass(FnTestingRuleTest.class); + fn.addSharedClass(InputEvent.class); + + + FnTestingRuleTest.configuration = null; + FnTestingRuleTest.inEvent = null; + FnTestingRuleTest.capturedInputs = new ArrayList<>(); + FnTestingRuleTest.capturedBodies = new ArrayList<>(); + } + + + public static class TestFn { + private RuntimeContext ctx; + + public TestFn(RuntimeContext ctx) { + this.ctx = ctx; + } + + public void copyConfiguration() { + configuration = new HashMap<>(ctx.getConfiguration()); + } + + public void copyInputEvent(InputEvent inEvent) { + FnTestingRuleTest.inEvent = inEvent; + } + + public void err() { + throw new RuntimeException("ERR"); + } + + public void captureInput(InputEvent in) { + capturedInputs.add(in); + capturedBodies.add(in.consumeBody(TestFn::consumeToBytes)); + } + + private static byte[] consumeToBytes(InputStream is) { + try { + ByteArrayOutputStream bos = new ByteArrayOutputStream(); + IOUtils.copy(is, bos); + return bos.toByteArray(); + } catch (IOException e) { + throw new RuntimeException(e); + } + } + + + public OutputEvent echoInput(InputEvent in) { + byte[] result = in.consumeBody(TestFn::consumeToBytes); + return OutputEvent.fromBytes(result, OutputEvent.Status.Success, "application/octet-stream"); + } + + } + + + @Test + public void shouldSetEnvironmentInsideFnScope() { + fn.givenEvent().enqueue(); + fn.setConfig("CONFIG_FOO", "BAR"); + + fn.thenRun(FnTestingRuleTest.TestFn.class, "copyConfiguration"); + + Assertions.assertThat(configuration).containsEntry("CONFIG_FOO", "BAR"); + } + + + @Test + public void shouldCleanEnvironmentOfSpecialVarsInsideFnScope() { + fn.givenEvent().enqueue(); + fn.setConfig("CONFIG_FOO", "BAR"); + + fn.thenRun(FnTestingRuleTest.TestFn.class, "copyConfiguration"); + + Assertions.assertThat(configuration).doesNotContainKeys("APP_NAME", "ROUTE", "METHOD", "REQUEST_URL"); + } + + + @Test + public void shouldHandleErrors() { + fn.givenEvent().enqueue(); + + fn.thenRun(FnTestingRuleTest.TestFn.class, "err"); + + Assertions.assertThat(fn.getOnlyResult().getStatus()).isEqualTo(OutputEvent.Status.FunctionError); + Assertions.assertThat(fn.getStdErrAsString()).contains("An error occurred in function: ERR"); + } + + + @Test + public void configShouldNotOverrideIntrinsicHeaders() { + fn.givenEvent().enqueue(); + fn.setConfig("Fn-Call-Id", "BAR"); + + fn.thenRun(FnTestingRuleTest.TestFn.class, "copyInputEvent"); + + Assertions.assertThat(inEvent.getCallID()).isEqualTo("callId"); + } + + + @Test + public void configShouldBeCaptitalisedAndReplacedWithUnderscores() {// Basic test + // Test uppercasing and mangling of keys + fn.givenEvent().enqueue(); + + fn.setConfig("some-key-with-dashes", "some-value"); + + fn.thenRun(FnTestingRuleTest.TestFn.class, "copyConfiguration"); + + Assertions.assertThat(configuration).containsEntry("SOME_KEY_WITH_DASHES", "some-value"); + + } + + + @Test + public void shouldSendEventDataToSDKInputEvent() { + + fn.setConfig("SOME_CONFIG", "SOME_VALUE"); + fn.givenEvent() + .withHeader("FOO", "BAR, BAZ") + .withHeader("FEH", "") + .withBody("Body") // body as string + .enqueue(); + + fn.thenRun(TestFn.class, "captureInput"); + + FnResult result = fn.getOnlyResult(); + Assertions.assertThat(result.getBodyAsString()).isEmpty(); + Assertions.assertThat(result.getStatus()).isEqualTo(OutputEvent.Status.Success); + + InputEvent event = capturedInputs.get(0); + Assertions.assertThat(event.getHeaders().asMap()) + .contains(headerEntry("FOO", "BAR, BAZ")) + .contains(headerEntry("FEH", "")); + Assertions.assertThat(capturedBodies.get(0)).isEqualTo("Body".getBytes()); + } + + + @Test + public void shouldEnqueueMultipleDistinctEvents() { + fn.setConfig("SOME_CONFIG", "SOME_VALUE"); + fn.givenEvent() + .withHeader("FOO", "BAR") + .withBody("Body") // body as string + .enqueue(); + + + fn.givenEvent() + .withHeader("FOO2", "BAR2") + .withBody("Body2") // body as string + .enqueue(); + + fn.thenRun(TestFn.class, "captureInput"); + + FnResult result = fn.getResults().get(0); + Assertions.assertThat(result.getBodyAsString()).isEmpty(); + Assertions.assertThat(result.getStatus()).isEqualTo(OutputEvent.Status.Success); + + InputEvent event = capturedInputs.get(0); + Assertions.assertThat(event.getHeaders().asMap()).contains(headerEntry("FOO", "BAR")); + Assertions.assertThat(capturedBodies.get(0)).isEqualTo("Body".getBytes()); + + + FnResult result2 = fn.getResults().get(1); + Assertions.assertThat(result2.getBodyAsString()).isEmpty(); + Assertions.assertThat(result2.getStatus()).isEqualTo(OutputEvent.Status.Success); + + InputEvent event2 = capturedInputs.get(1); + Assertions.assertThat(event2.getHeaders().asMap()).contains(headerEntry("FOO2", "BAR2")); + Assertions.assertThat(capturedBodies.get(1)).isEqualTo("Body2".getBytes()); + } + + + @Test + public void shouldEnqueueMultipleIdenticalEvents() { + fn.givenEvent() + .withHeader("FOO", "BAR") + .withHeader("Content-Type", "application/octet-stream") + .withBody("Body") // body as string + .enqueue(10); + + fn.thenRun(TestFn.class, "echoInput"); + + List results = fn.getResults(); + Assertions.assertThat(results).hasSize(10); + + + results.forEach((r) -> { + Assertions.assertThat(r.getStatus()).isEqualTo(OutputEvent.Status.Success); + + }); + } + + + @Test + public void shouldEnqueuIndependentEventsWithInputStreams() throws IOException { + fn.givenEvent() + .withBody(new ByteArrayInputStream("Body".getBytes())) // body as string + .enqueue(); + + fn.givenEvent() + .withBody(new ByteArrayInputStream("Body1".getBytes())) // body as string + .enqueue(); + + fn.thenRun(TestFn.class, "echoInput"); + + List results = fn.getResults(); + Assertions.assertThat(results).hasSize(2); + + Assertions.assertThat(results.get(0).getBodyAsString()).isEqualTo("Body"); + Assertions.assertThat(results.get(1).getBodyAsString()).isEqualTo("Body1"); + } + + @Test + public void shouldHandleBodyAsInputStream() throws IOException { + fn.givenEvent().withBody(new ByteArrayInputStream("FOO BAR".getBytes())).enqueue(); + + fn.thenRun(TestFn.class, "captureInput"); + + Assertions.assertThat(fn.getOnlyResult().getStatus()).isEqualTo(OutputEvent.Status.Success); + Assertions.assertThat(capturedBodies.get(0)).isEqualTo("FOO BAR".getBytes()); + } + + // TODO move this to HTTP gateway +// @Test +// public void shouldLeaveQueryParamtersOffIfNotSpecified() { +// String baseUrl = "www.example.com"; +// fn.givenEvent() +// .withRequestUrl(baseUrl) +// .enqueue(); +// fn.thenRun(TestFn.class, "copyInputEvent"); +// +// Assertions.assertThat(inEvent.getRequestUrl()).isEqualTo(baseUrl); +// } +// +// @Test +// public void shouldPrependQuestionMarkForFirstQueryParam() { +// String baseUrl = "www.example.com"; +// fn.givenEvent() +// .withRequestUrl(baseUrl) +// .withQueryParameter("var", "val") +// .enqueue(); +// fn.thenRun(TestFn.class, "copyInputEvent"); +// Assertions.assertThat(fn.getOnlyResult().getStatus()).isEqualTo(200); +// Assertions.assertThat(inEvent.getRequestUrl()).isEqualTo(baseUrl + "?var=val"); +// } +// +// @Test +// public void shouldHandleMultipleQueryParameters() { +// String baseUrl = "www.example.com"; +// fn.givenEvent() +// .withRequestUrl(baseUrl) +// .withQueryParameter("var1", "val1") +// .withQueryParameter("var2", "val2") +// .enqueue(); +// fn.thenRun(TestFn.class, "copyInputEvent"); +// +// Assertions.assertThat(inEvent.getRequestUrl()).isEqualTo(baseUrl + "?var1=val1&var2=val2"); +// } +// +// @Test +// public void shouldHandleMultipleQueryParametersWithSameKey() { +// String baseUrl = "www.example.com"; +// fn.givenEvent() +// .withRequestUrl(baseUrl) +// .withQueryParameter("var", "val1") +// .withQueryParameter("var", "val2") +// .enqueue(); +// fn.thenRun(TestFn.class, "copyInputEvent"); +// +// Assertions.assertThat(inEvent.getRequestUrl()).isEqualTo(baseUrl + "?var=val1&var=val2"); +// } +// +// @Test +// public void shouldUrlEncodeQueryParameterKey() { +// fn.givenEvent() +// .withRequestUrl(exampleBaseUrl) +// .withQueryParameter("&", "val") +// .enqueue(); +// fn.thenRun(TestFn.class, "copyInputEvent"); +// +// Assertions.assertThat(inEvent.getRequestUrl()).isEqualTo(exampleBaseUrl + "?%26=val"); +// } +// +// @Test +// public void shouldHandleQueryParametersWithSpaces() { +// fn.givenEvent() +// .withRequestUrl(exampleBaseUrl) +// .withQueryParameter("my var", "this val") +// .enqueue(); +// fn.thenRun(TestFn.class, "copyInputEvent"); +// +// Assertions.assertThat(inEvent.getRequestUrl()).isEqualTo(exampleBaseUrl + "?my+var=this+val"); +// } +// +// @Test +// public void shouldUrlEncodeQueryParameterValue() { +// String baseUrl = "www.example.com"; +// fn.givenEvent() +// .withRequestUrl(baseUrl) +// .withQueryParameter("var", "&") +// .enqueue(); +// fn.thenRun(TestFn.class, "copyInputEvent"); +// +// Assertions.assertThat(inEvent.getRequestUrl()).isEqualTo(baseUrl + "?var=%26"); +// } + + private static Map.Entry> headerEntry(String key, String... values) { + return new AbstractMap.SimpleEntry<>(Headers.canonicalKey(key), Arrays.asList(values)); + } +} diff --git a/testing-junit4/src/test/java/junit/com/fnproject/fn/testing/FnTestingRuleTest.java b/testing-junit4/src/test/java/junit/com/fnproject/fn/testing/FnTestingRuleTest.java deleted file mode 100644 index 35d303f8..00000000 --- a/testing-junit4/src/test/java/junit/com/fnproject/fn/testing/FnTestingRuleTest.java +++ /dev/null @@ -1,402 +0,0 @@ -package junit.com.fnproject.fn.testing; - -import com.fnproject.fn.api.InputEvent; -import com.fnproject.fn.api.OutputEvent; -import com.fnproject.fn.api.RuntimeContext; -import com.fnproject.fn.testing.FnResult; -import com.fnproject.fn.testing.FnTestingRule; -import org.apache.commons.io.IOUtils; -import org.assertj.core.api.Assertions; -import org.junit.Before; -import org.junit.Rule; -import org.junit.Test; - -import java.io.ByteArrayInputStream; -import java.io.ByteArrayOutputStream; -import java.io.IOException; -import java.io.InputStream; -import java.util.*; - -public class FnTestingRuleTest { - - public static Map configuration; - public static InputEvent inEvent; - public static List capturedInputs = new ArrayList<>(); - public static List capturedBodies = new ArrayList<>(); - - @Rule - public FnTestingRule fn = FnTestingRule.createDefault(); - private final String exampleBaseUrl = "http://www.example.com"; - - @Before - public void reset() { - fn.addSharedClass(FnTestingRuleTest.class); - fn.addSharedClass(InputEvent.class); - - - FnTestingRuleTest.configuration = null; - FnTestingRuleTest.inEvent = null; - FnTestingRuleTest.capturedInputs = new ArrayList<>(); - FnTestingRuleTest.capturedBodies = new ArrayList<>(); - } - - - public static class TestFn { - private RuntimeContext ctx; - - public TestFn(RuntimeContext ctx) { - this.ctx = ctx; - } - - public void copyConfiguration() { - configuration = new HashMap<>(ctx.getConfiguration()); - } - - public void copyInputEvent(InputEvent inEvent) { - FnTestingRuleTest.inEvent = inEvent; - } - - public void err() { - throw new RuntimeException("ERR"); - } - - public void captureInput(InputEvent in) { - capturedInputs.add(in); - capturedBodies.add(in.consumeBody(TestFn::consumeToBytes)); - } - - private static byte[] consumeToBytes(InputStream is) { - try { - ByteArrayOutputStream bos = new ByteArrayOutputStream(); - IOUtils.copy(is, bos); - return bos.toByteArray(); - } catch (IOException e) { - throw new RuntimeException(e); - } - } - - - public OutputEvent echoInput(InputEvent in) { - byte[] result = in.consumeBody(TestFn::consumeToBytes); - return OutputEvent.fromBytes(result, OutputEvent.SUCCESS, "application/octet-stream"); - } - - } - - - @Test - public void shouldSetEnvironmentInsideFnScope() { - fn.givenEvent().enqueue(); - fn.setConfig("CONFIG_FOO", "BAR"); - - fn.thenRun(FnTestingRuleTest.TestFn.class, "copyConfiguration"); - - Assertions.assertThat(configuration).containsEntry("CONFIG_FOO", "BAR"); - } - - - @Test - public void shouldCleanEnvironmentOfSpecialVarsInsideFnScope() { - fn.givenEvent().enqueue(); - fn.setConfig("CONFIG_FOO", "BAR"); - - fn.thenRun(FnTestingRuleTest.TestFn.class, "copyConfiguration"); - - Assertions.assertThat(configuration).doesNotContainKeys("APP_NAME", "ROUTE", "METHOD", "REQUEST_URL"); - } - - - @Test - public void shouldHandleErrors() { - fn.givenEvent().enqueue(); - - fn.thenRun(FnTestingRuleTest.TestFn.class, "err"); - - Assertions.assertThat(fn.getOnlyResult().getStatus()).isEqualTo(500); - Assertions.assertThat(fn.getStdErrAsString()).contains("An error occurred in function: ERR"); - } - - - @Test - public void configShouldNotOverrideIntrinsicHeaders() { - fn.givenEvent().enqueue(); - fn.setConfig("APP_NAME", "BAR"); - - fn.thenRun(FnTestingRuleTest.TestFn.class, "copyInputEvent"); - - Assertions.assertThat(inEvent.getAppName()).isEqualTo("appName"); - } - - - @Test - public void configShouldBeCaptitalisedAndReplacedWithUnderscores() {// Basic test - // Test uppercasing and mangling of keys - fn.givenEvent().enqueue(); - - fn.setConfig("some-key-with-dashes", "some-value"); - - fn.thenRun(FnTestingRuleTest.TestFn.class, "copyConfiguration"); - - Assertions.assertThat(configuration).containsEntry("SOME_KEY_WITH_DASHES", "some-value"); - - } - - @Test - public void shouldSetArgsInFirstEvent() { - fn.givenEvent().withAppName("TEST_APP") - .withHeader("H1", "H2") - .withMethod("PUT") - .withRequestUrl("http://example.com/mytest") - .withRoute("/myroute") - .enqueue(); - - fn.thenRun(FnTestingRuleTest.TestFn.class, "copyInputEvent"); - - Assertions.assertThat(inEvent.getAppName()).isEqualTo("TEST_APP"); - Assertions.assertThat(inEvent.getRoute()).isEqualTo("/myroute"); - Assertions.assertThat(inEvent.getMethod()).isEqualTo("PUT"); - Assertions.assertThat(inEvent.getRequestUrl()).isEqualTo("http://example.com/mytest"); - } - - - @Test - public void shouldSendEventDataToSDKInputEvent() { - final String APP_NAME = "alpha"; - final String ROUTE = "/bravo"; - final String REQUEST_URL = "http://charlie/alpha/bravo"; - final String METHOD = "POST"; - - fn.setConfig("SOME_CONFIG", "SOME_VALUE"); - fn.givenEvent() - .withAppName(APP_NAME) - .withRoute(ROUTE) - .withRequestUrl(REQUEST_URL) - .withMethod(METHOD) - .withHeader("FOO", "BAR, BAZ") - .withHeader("FEH", "") - .withBody("Body") // body as string - .enqueue(); - - fn.thenRun(TestFn.class, "captureInput"); - - FnResult result = fn.getOnlyResult(); - Assertions.assertThat(result.getBodyAsString()).isEmpty(); - Assertions.assertThat(result.getHeaders().getAll()).contains(headerEntry("Content-length", "0")); - Assertions.assertThat(result.getStatus()).isEqualTo(200); - - InputEvent event = capturedInputs.get(0); - Assertions.assertThat(event.getAppName()).isEqualTo(APP_NAME); - Assertions.assertThat(event.getHeaders().getAll()) - .contains(headerEntry("FOO", "BAR, BAZ")) - .contains(headerEntry("FEH", "")); - Assertions.assertThat(event.getMethod()).isEqualTo(METHOD); - Assertions.assertThat(capturedBodies.get(0)).isEqualTo("Body".getBytes()); - } - - - @Test - public void shouldEnqueueMultipleDistinctEvents() { - fn.setConfig("SOME_CONFIG", "SOME_VALUE"); - fn.givenEvent() - .withAppName("alpha") - .withRoute("/bravo") - .withRequestUrl("http://charlie/alpha/bravo") - .withMethod("POST") - .withHeader("FOO", "BAR") - .withBody("Body") // body as string - .enqueue(); - - - fn.givenEvent() - .withAppName("alpha") - .withRoute("/bravo2") - .withRequestUrl("http://charlie/alpha/bravo2") - .withMethod("PUT") - .withHeader("FOO2", "BAR2") - .withBody("Body2") // body as string - .enqueue(); - - fn.thenRun(TestFn.class, "captureInput"); - - FnResult result = fn.getResults().get(0); - Assertions.assertThat(result.getBodyAsString()).isEmpty(); - Assertions.assertThat(result.getHeaders().getAll()).contains(headerEntry("Content-length", "0")); - Assertions.assertThat(result.getStatus()).isEqualTo(200); - - InputEvent event = capturedInputs.get(0); - Assertions.assertThat(event.getAppName()).isEqualTo("alpha"); - Assertions.assertThat(event.getHeaders().getAll()).contains(headerEntry("FOO", "BAR")); - Assertions.assertThat(event.getMethod()).isEqualTo("POST"); - Assertions.assertThat(capturedBodies.get(0)).isEqualTo("Body".getBytes()); - - - FnResult result2 = fn.getResults().get(1); - Assertions.assertThat(result2.getBodyAsString()).isEmpty(); - Assertions.assertThat(result2.getHeaders().getAll()).contains(headerEntry("Content-length", "0")); - Assertions.assertThat(result2.getStatus()).isEqualTo(200); - - InputEvent event2 = capturedInputs.get(1); - Assertions.assertThat(event2.getAppName()).isEqualTo("alpha"); - Assertions.assertThat(event2.getHeaders().getAll()).contains(headerEntry("FOO2", "BAR2")); - Assertions.assertThat(event2.getMethod()).isEqualTo("PUT"); - Assertions.assertThat(capturedBodies.get(1)).isEqualTo("Body2".getBytes()); - } - - - @Test - public void shouldEnqueueMultipleIdenticalEvents() { - fn.givenEvent() - .withAppName("alpha") - .withRoute("/bravo") - .withRequestUrl("http://charlie/alpha/bravo") - .withMethod("POST") - .withHeader("FOO", "BAR") - .withBody("Body") // body as string - .enqueue(10); - - fn.thenRun(TestFn.class, "echoInput"); - - List results = fn.getResults(); - Assertions.assertThat(results).hasSize(10); - - - results.forEach((r) -> { - Assertions.assertThat(r.getStatus()).isEqualTo(200); - Assertions.assertThat(r.getHeaders().getAll()) - .contains(headerEntry("Content-Type", "application/octet-stream")) - .contains(headerEntry("Content-length", String.valueOf("Body".getBytes().length))); - - }); - } - - - @Test(expected = IllegalStateException.class) - public void shouldNotAllowSecondEnqueueOnInputStreamInput() { - fn.givenEvent() - .withAppName("alpha") - .withRoute("/bravo") - .withRequestUrl("http://charlie/alpha/bravo") - .withMethod("POST") - .withHeader("FOO", "BAR") - .withBody(new ByteArrayInputStream("Body".getBytes()), 4) // body as string - .enqueue(2); - - - } - - @Test - public void shouldEnqueuIndependentEventsWithInputStreams() { - fn.givenEvent() - .withBody(new ByteArrayInputStream("Body".getBytes()), 4) // body as string - .enqueue(); - - fn.givenEvent() - .withBody(new ByteArrayInputStream("Body1".getBytes()), 5) // body as string - .enqueue(); - - fn.thenRun(TestFn.class, "echoInput"); - - List results = fn.getResults(); - Assertions.assertThat(results).hasSize(2); - - Assertions.assertThat(results.get(0).getBodyAsString()).isEqualTo("Body"); - Assertions.assertThat(results.get(1).getBodyAsString()).isEqualTo("Body1"); - } - - @Test - public void shouldHandleBodyAsInputStream() { - fn.givenEvent().withBody(new ByteArrayInputStream("FOO BAR".getBytes()), 3).enqueue(); - - fn.thenRun(TestFn.class, "captureInput"); - - Assertions.assertThat(fn.getOnlyResult().getStatus()).isEqualTo(200); - Assertions.assertThat(capturedBodies.get(0)).isEqualTo("FOO".getBytes()); - } - - @Test - public void shouldLeaveQueryParamtersOffIfNotSpecified() { - String baseUrl = "www.example.com"; - fn.givenEvent() - .withRequestUrl(baseUrl) - .enqueue(); - fn.thenRun(TestFn.class, "copyInputEvent"); - - Assertions.assertThat(inEvent.getRequestUrl()).isEqualTo(baseUrl); - } - - @Test - public void shouldPrependQuestionMarkForFirstQueryParam() { - String baseUrl = "www.example.com"; - fn.givenEvent() - .withRequestUrl(baseUrl) - .withQueryParameter("var", "val") - .enqueue(); - fn.thenRun(TestFn.class, "copyInputEvent"); - Assertions.assertThat(fn.getOnlyResult().getStatus()).isEqualTo(200); - Assertions.assertThat(inEvent.getRequestUrl()).isEqualTo(baseUrl + "?var=val"); - } - - @Test - public void shouldHandleMultipleQueryParameters() { - String baseUrl = "www.example.com"; - fn.givenEvent() - .withRequestUrl(baseUrl) - .withQueryParameter("var1", "val1") - .withQueryParameter("var2", "val2") - .enqueue(); - fn.thenRun(TestFn.class, "copyInputEvent"); - - Assertions.assertThat(inEvent.getRequestUrl()).isEqualTo(baseUrl + "?var1=val1&var2=val2"); - } - - @Test - public void shouldHandleMultipleQueryParametersWithSameKey() { - String baseUrl = "www.example.com"; - fn.givenEvent() - .withRequestUrl(baseUrl) - .withQueryParameter("var", "val1") - .withQueryParameter("var", "val2") - .enqueue(); - fn.thenRun(TestFn.class, "copyInputEvent"); - - Assertions.assertThat(inEvent.getRequestUrl()).isEqualTo(baseUrl + "?var=val1&var=val2"); - } - - @Test - public void shouldUrlEncodeQueryParameterKey() { - fn.givenEvent() - .withRequestUrl(exampleBaseUrl) - .withQueryParameter("&", "val") - .enqueue(); - fn.thenRun(TestFn.class, "copyInputEvent"); - - Assertions.assertThat(inEvent.getRequestUrl()).isEqualTo(exampleBaseUrl + "?%26=val"); - } - - @Test - public void shouldHandleQueryParametersWithSpaces() { - fn.givenEvent() - .withRequestUrl(exampleBaseUrl) - .withQueryParameter("my var", "this val") - .enqueue(); - fn.thenRun(TestFn.class, "copyInputEvent"); - - Assertions.assertThat(inEvent.getRequestUrl()).isEqualTo(exampleBaseUrl + "?my+var=this+val"); - } - - @Test - public void shouldUrlEncodeQueryParameterValue() { - String baseUrl = "www.example.com"; - fn.givenEvent() - .withRequestUrl(baseUrl) - .withQueryParameter("var", "&") - .enqueue(); - fn.thenRun(TestFn.class, "copyInputEvent"); - - Assertions.assertThat(inEvent.getRequestUrl()).isEqualTo(baseUrl + "?var=%26"); - } - - private static Map.Entry headerEntry(String key, String value) { - return new AbstractMap.SimpleEntry<>(key, value); - } -} diff --git a/testing-junit4/src/test/java/junit/com/fnproject/fn/testing/IntegrationTest.java b/testing-junit4/src/test/java/junit/com/fnproject/fn/testing/IntegrationTest.java deleted file mode 100644 index 2582d470..00000000 --- a/testing-junit4/src/test/java/junit/com/fnproject/fn/testing/IntegrationTest.java +++ /dev/null @@ -1,37 +0,0 @@ -package junit.com.fnproject.fn.testing; - -import com.fnproject.fn.testing.FnTestingRule; -import com.fnproject.fn.testing.FunctionError; -import org.assertj.core.api.Assertions; -import org.junit.Rule; -import org.junit.Test; - -public class IntegrationTest { - - @Rule - public FnTestingRule fn = FnTestingRule.createDefault(); - - @Test - public void runIntegrationTests() { - - fn.givenFn("nonexistent/nonexistent") - .withFunctionError() - - .givenFn("appName/route") - .withAction((body) -> { - if (new String(body).equals("PASS")) { - return "okay".getBytes(); - } else { - throw new FunctionError("failed as demanded"); - } - }) - .givenEvent() - .withBody("") // or "1,5,6,32" to select a set of tests individually - .enqueue() - - .thenRun(ExerciseEverything.class, "handleRequest"); - - Assertions.assertThat(fn.getResults().get(0).getBodyAsString()) - .endsWith("Everything worked\n"); - } -} From 29c2b476d2f1d20a93341c75fbde5b7e0be8bec7 Mon Sep 17 00:00:00 2001 From: Owen Cliffe Date: Wed, 19 Sep 2018 15:30:52 +0100 Subject: [PATCH 036/310] bump version to fix broken release [skip ci] --- release.version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/release.version b/release.version index 7f2b1404..c8b47425 100644 --- a/release.version +++ b/release.version @@ -1 +1 @@ -1.0.66 +1.0.67 From 3df1c6f46f7cac27f38482797d5a7398dfdb849c Mon Sep 17 00:00:00 2001 From: Owen Cliffe Date: Wed, 19 Sep 2018 19:11:50 +0100 Subject: [PATCH 037/310] Initial cut at HTTP gateway prtotocol support --- .../java/com/fnproject/fn/api/Headers.java | 26 ++++- .../fnproject/fn/api/InvocationContext.java | 32 ++++++ .../com/fnproject/fn/api/OutputEvent.java | 39 ++++++- .../api/httpgateway/HTTPGatewayContext.java | 77 +++++++++++++ .../api/httpgateway/HTTPGatewayRequest.java | 25 ----- .../fn/api/httpgateway/HTTPResponse.java | 26 ----- .../flow/FlowsContinuationInvokerTest.java | 17 +++ integration-tests/funcs/httpgwfunc/func.yaml | 12 +++ integration-tests/funcs/httpgwfunc/pom.xml | 66 ++++++++++++ .../com/fnproject/fn/runtime/EntryPoint.java | 26 ++--- .../fn/runtime/FunctionInvocationContext.java | 53 ++++++++- .../fn/runtime/FunctionRuntimeContext.java | 14 +-- .../fn/runtime/coercion/ContextCoercion.java | 28 +++++ .../FunctionHTTPGatewayContext.java | 101 ++++++++++++++++++ .../fn/runtime/JacksonCoercionTest.java | 5 +- 15 files changed, 462 insertions(+), 85 deletions(-) create mode 100644 api/src/main/java/com/fnproject/fn/api/httpgateway/HTTPGatewayContext.java delete mode 100644 api/src/main/java/com/fnproject/fn/api/httpgateway/HTTPGatewayRequest.java delete mode 100644 api/src/main/java/com/fnproject/fn/api/httpgateway/HTTPResponse.java create mode 100644 integration-tests/funcs/httpgwfunc/func.yaml create mode 100644 integration-tests/funcs/httpgwfunc/pom.xml create mode 100644 runtime/src/main/java/com/fnproject/fn/runtime/coercion/ContextCoercion.java create mode 100644 runtime/src/main/java/com/fnproject/fn/runtime/httpgateway/FunctionHTTPGatewayContext.java diff --git a/api/src/main/java/com/fnproject/fn/api/Headers.java b/api/src/main/java/com/fnproject/fn/api/Headers.java index 6995c771..38787b40 100644 --- a/api/src/main/java/com/fnproject/fn/api/Headers.java +++ b/api/src/main/java/com/fnproject/fn/api/Headers.java @@ -15,12 +15,12 @@ * Keys are are stored and compared in a case-insensitive way and are canonicalised according to RFC 7230 conventions such that : * *

      - *
    • a-header
    • - *
    • A-Header
    • - *
    • A-HeaDer
    • + *
    • a-header
    • + *
    • A-Header
    • + *
    • A-HeaDer
    • *
    - * are all equivalent - keys are returned in the canonical form (lower cased except for leading characters) - * Where keys do not comply with HTTP header naming they are left as is. + * are all equivalent - keys are returned in the canonical form (lower cased except for leading characters) + * Where keys do not comply with HTTP header naming they are left as is. */ public final class Headers implements Serializable { private static final Headers emptyHeaders = new Headers(Collections.emptyMap()); @@ -94,6 +94,22 @@ public static Headers emptyHeaders() { } + /** + * Sets a map of headers, overwriting any headers in the current headers with the respective values + * + * @param vals a map of headers + * @return a new headers object with thos headers set + */ + public Headers setHeaders(Map> vals) { + Objects.requireNonNull(vals, "vals"); + Map> nm = new HashMap<>(headers); + vals.forEach((k, vs) -> { + vs.forEach(v -> Objects.requireNonNull(v, "header list contains null entries")); + nm.put(canonicalKey(k), vs); + }); + return new Headers(nm); + } + /** * Creates a new headers object with the specified header added - if a header with the same key existed it the new value is appended *

    diff --git a/api/src/main/java/com/fnproject/fn/api/InvocationContext.java b/api/src/main/java/com/fnproject/fn/api/InvocationContext.java index 3b3395a1..70297158 100644 --- a/api/src/main/java/com/fnproject/fn/api/InvocationContext.java +++ b/api/src/main/java/com/fnproject/fn/api/InvocationContext.java @@ -19,4 +19,36 @@ public interface InvocationContext { */ void addListener(InvocationListener listener); + + /** + * Returns the current request headers for the invocation + * @return the headers passed into the function + */ + Headers getRequestHeaders(); + + /** + * Sets the response content type + * @param contentType a mime type for the response + */ + default void setResponseContentType(String contentType){ + this.setResponseHeader("Content-Type",contentType); + } + + /** + * Adds a response header to the outbound event + * + * @param key header key + * @param value header value + */ + void addResponseHeader(String key, String value); + + /** + * Sets a response header to the outbound event, overriding a previous value. + *

    + * Headers set in this way override any headers returned by the function or any middleware on the function + * + * @param key header key + * @param value header value set to null to clear the header + */ + void setResponseHeader(String key, String value); } diff --git a/api/src/main/java/com/fnproject/fn/api/OutputEvent.java b/api/src/main/java/com/fnproject/fn/api/OutputEvent.java index 6dcfa381..430054e0 100644 --- a/api/src/main/java/com/fnproject/fn/api/OutputEvent.java +++ b/api/src/main/java/com/fnproject/fn/api/OutputEvent.java @@ -46,7 +46,6 @@ public int getCode() { } - /** * Report the outcome status code of this event. * @@ -91,6 +90,39 @@ default boolean isSuccess() { void writeToOutput(OutputStream out) throws IOException; + /** + * Creates a new output event based on this one with the headers overriding + * @param headers + * @return a new output event with these set + */ + default OutputEvent withHeaders(Headers headers) { + Objects.requireNonNull(headers, "headers"); + + OutputEvent a = this; + return new OutputEvent() { + + @Override + public Status getStatus() { + return a.getStatus(); + } + + @Override + public Optional getContentType() { + return a.getContentType(); + } + + @Override + public Headers getHeaders() { + return headers; + } + + @Override + public void writeToOutput(OutputStream out) throws IOException { + a.writeToOutput(out); + } + }; + } + /** * Create an output event from a byte array * @@ -141,6 +173,11 @@ public void writeToOutput(OutputStream out) throws IOException { }; } + /** + * Returns an output event with an empty body and a given status + * @param status the status of the event + * @return a new output event + */ static OutputEvent emptyResult(final Status status) { Objects.requireNonNull(status, "status"); diff --git a/api/src/main/java/com/fnproject/fn/api/httpgateway/HTTPGatewayContext.java b/api/src/main/java/com/fnproject/fn/api/httpgateway/HTTPGatewayContext.java new file mode 100644 index 00000000..9f64b104 --- /dev/null +++ b/api/src/main/java/com/fnproject/fn/api/httpgateway/HTTPGatewayContext.java @@ -0,0 +1,77 @@ +package com.fnproject.fn.api.httpgateway; + +import com.fnproject.fn.api.Headers; +import com.fnproject.fn.api.InvocationContext; +import com.fnproject.fn.api.QueryParameters; + +/** + * A context for accessing and setting HTTP Gateway atributes such aas headers and query parameters from a function call + * + * Created on 19/09/2018. + *

    + * (c) 2018 Oracle Corporation + */ +public interface HTTPGatewayContext { + + /** + * Returns the underlying invocation context behind this HTTP context + * @return an invocation context related to this function + */ + InvocationContext getInvocationContext(); + + + /** + * Returns the HTTP headers for the request associated with this function call + * If no headers were set this will return an empty headers object + * + * @return the incoming HTTP headers sent in the gateway request + */ + Headers getHeaders(); + + + /** + * Returns the fully qualified request URI that the function was called with, including query parameters + * @return the request URI of the function + */ + String getRequestURL(); + + + /** + * Returns the incoming request method for the HTTP + * @return the HTTP method set on this call + */ + String getMethod(); + + /** + * Returns the query parameters of the request + * @return a query parameters object + */ + QueryParameters getQueryParameters(); + + + /** + * Adds a response header to the outbound event + * + * @param key header key + * @param value header value + */ + void addResponseHeader(String key, String value); + + /** + * Sets a response header to the outbound event, overriding a previous value. + *

    + * Headers set in this way override any headers returned by the function or any middleware on the function + * + * Setting the "Content-Type" response header also sets this on the underlying Invocation context + * @param key header key + * @param value header value set to null to clear the header + */ + void setResponseHeader(String key, String value); + + /** + * Sets the HTTP status code of the response + * @param code an HTTP status code + * @throws IllegalArgumentException if the code is < 100 or >=600 + */ + void setStatusCode(int code); +} diff --git a/api/src/main/java/com/fnproject/fn/api/httpgateway/HTTPGatewayRequest.java b/api/src/main/java/com/fnproject/fn/api/httpgateway/HTTPGatewayRequest.java deleted file mode 100644 index bb00abb8..00000000 --- a/api/src/main/java/com/fnproject/fn/api/httpgateway/HTTPGatewayRequest.java +++ /dev/null @@ -1,25 +0,0 @@ -package com.fnproject.fn.api.httpgateway; - -import com.fnproject.fn.api.Headers; -import com.fnproject.fn.api.QueryParameters; - -import java.io.InputStream; -import java.util.function.Function; - -/** - * Created on 05/09/2018. - *

    - * (c) 2018 Oracle Corporation - */ -public interface HTTPGatewayRequest { - - String getMethod(); - - String getRequestURI(); - - Headers getHeaders(); - - QueryParameters getQueryParameters(); - - T consumeBody(Function dest); -} diff --git a/api/src/main/java/com/fnproject/fn/api/httpgateway/HTTPResponse.java b/api/src/main/java/com/fnproject/fn/api/httpgateway/HTTPResponse.java deleted file mode 100644 index 78052a7f..00000000 --- a/api/src/main/java/com/fnproject/fn/api/httpgateway/HTTPResponse.java +++ /dev/null @@ -1,26 +0,0 @@ -package com.fnproject.fn.api.httpgateway; - -import com.fnproject.fn.api.Headers; - -import java.io.IOException; -import java.io.OutputStream; - -/** - * Created on 05/09/2018. - *

    - * (c) 2018 Oracle Corporation - */ -public interface HTTPResponse { - - int getStatusCode(); - - Headers getHeaders(); - - /** - * Write the body of the output to a stream - * - * @param out an outputstream to emit the body of the event - * @throws IOException OutputStream exceptions percolate up through this method - */ - void writeToOutput(OutputStream out) throws IOException; -} diff --git a/flow-runtime/src/test/java/com/fnproject/fn/runtime/flow/FlowsContinuationInvokerTest.java b/flow-runtime/src/test/java/com/fnproject/fn/runtime/flow/FlowsContinuationInvokerTest.java index 06f83d9b..a7401bc8 100644 --- a/flow-runtime/src/test/java/com/fnproject/fn/runtime/flow/FlowsContinuationInvokerTest.java +++ b/flow-runtime/src/test/java/com/fnproject/fn/runtime/flow/FlowsContinuationInvokerTest.java @@ -654,5 +654,22 @@ public RuntimeContext getRuntimeContext() { public void addListener(InvocationListener listener) { } + @Override + public Headers getRequestHeaders() { + return Headers.emptyHeaders(); + } + + + + @Override + public void addResponseHeader(String key, String value) { + + } + + @Override + public void setResponseHeader(String key, String value) { + + } + } } diff --git a/integration-tests/funcs/httpgwfunc/func.yaml b/integration-tests/funcs/httpgwfunc/func.yaml new file mode 100644 index 00000000..7b86fd7a --- /dev/null +++ b/integration-tests/funcs/httpgwfunc/func.yaml @@ -0,0 +1,12 @@ +schema_version: 20180708 +name: httpgwfunc +version: 0.0.1 +runtime: java +build_image: fnproject/fn-java-fdk-build:jdk9-1.0.64 +run_image: fnproject/fn-java-fdk:jdk9-1.0.64 +cmd: com.example.fn.TriggerFunction::handleRequest +format: http +triggers: +- name: httpgwfunc-trigger + type: http + source: /httpgwfunc-trigger diff --git a/integration-tests/funcs/httpgwfunc/pom.xml b/integration-tests/funcs/httpgwfunc/pom.xml new file mode 100644 index 00000000..fa9aad4f --- /dev/null +++ b/integration-tests/funcs/httpgwfunc/pom.xml @@ -0,0 +1,66 @@ + + + 4.0.0 + + UTF-8 + 1.0.0-SNAPSHOT + + com.example.fn + hello + 1.0.0 + + + + fn-release-repo + https://dl.bintray.com/fnproject/fnproject + + true + + + true + + + + + + + com.fnproject.fn + api + ${fdk.version} + + + com.fnproject.fn + testing-core + ${fdk.version} + test + + + com.fnproject.fn + testing-junit4 + ${fdk.version} + test + + + junit + junit + 4.12 + test + + + + + + + org.apache.maven.plugins + maven-compiler-plugin + 3.3 + + 8 + 8 + + + + + diff --git a/runtime/src/main/java/com/fnproject/fn/runtime/EntryPoint.java b/runtime/src/main/java/com/fnproject/fn/runtime/EntryPoint.java index 1e885b18..7510c75a 100644 --- a/runtime/src/main/java/com/fnproject/fn/runtime/EntryPoint.java +++ b/runtime/src/main/java/com/fnproject/fn/runtime/EntryPoint.java @@ -40,11 +40,7 @@ public static void main(String... args) throws Exception { } - int exitCode = new EntryPoint().run( - System.getenv(), - codec, - System.err, - args); + int exitCode = new EntryPoint().run(System.getenv(), codec, System.err, args); System.setOut(originalSystemOut); System.exit(exitCode); } @@ -79,31 +75,30 @@ public int run(Map env, EventCodec codec, PrintStream loggingOut FunctionRuntimeContext runtimeContext = new FunctionRuntimeContext(method, configFromEnvVars); FnFeature[] features = method.getTargetClass().getAnnotationsByType(FnFeature.class); - for (FnFeature f : features){ + for (FnFeature f : features) { RuntimeFeature rf; - try{ + try { Class featureClass = f.value(); rf = featureClass.newInstance(); - }catch (Exception e){ - throw new FunctionInitializationException("Could not load feature class " + f.value().toString() ,e); + } catch (Exception e) { + throw new FunctionInitializationException("Could not load feature class " + f.value().toString(), e); } - try{ + try { rf.initialize(runtimeContext); - }catch (Exception e){ - throw new FunctionInitializationException("Exception while calling initialization on runtime feature " + f.value() ,e); + } catch (Exception e) { + throw new FunctionInitializationException("Exception while calling initialization on runtime feature " + f.value(), e); } } - FunctionConfigurer functionConfigurer = new FunctionConfigurer(); functionConfigurer.configure(runtimeContext); codec.runCodec((evt) -> { try { - FunctionInvocationContext fic = runtimeContext.newInvocationContext(); + FunctionInvocationContext fic = runtimeContext.newInvocationContext(evt); try (InputEvent myEvt = evt) { OutputEvent output = runtimeContext.tryInvoke(evt, fic); if (output == null) { @@ -116,7 +111,8 @@ public int run(Map env, EventCodec codec, PrintStream loggingOut lastStatus.set(1); fic.fireOnFailedInvocation(); } - return output; + + return output.withHeaders(output.getHeaders().setHeaders(fic.getAdditionalResponseHeaders())); } catch (IOException err) { fic.fireOnFailedInvocation(); diff --git a/runtime/src/main/java/com/fnproject/fn/runtime/FunctionInvocationContext.java b/runtime/src/main/java/com/fnproject/fn/runtime/FunctionInvocationContext.java index c828bf83..9e057c20 100644 --- a/runtime/src/main/java/com/fnproject/fn/runtime/FunctionInvocationContext.java +++ b/runtime/src/main/java/com/fnproject/fn/runtime/FunctionInvocationContext.java @@ -1,9 +1,12 @@ package com.fnproject.fn.runtime; +import com.fnproject.fn.api.Headers; +import com.fnproject.fn.api.InputEvent; import com.fnproject.fn.api.InvocationContext; import com.fnproject.fn.api.InvocationListener; -import java.util.List; +import java.util.*; +import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.CopyOnWriteArrayList; /** @@ -14,8 +17,12 @@ public class FunctionInvocationContext implements InvocationContext, FunctionInv private final FunctionRuntimeContext runtimeContext; private List invocationListeners = new CopyOnWriteArrayList<>(); - public FunctionInvocationContext(FunctionRuntimeContext ctx) { + private final InputEvent event; + private Map> additionalResponseHeaders = new ConcurrentHashMap<>(); + + FunctionInvocationContext(FunctionRuntimeContext ctx, InputEvent event) { this.runtimeContext = ctx; + this.event = event; } @Override @@ -28,12 +35,50 @@ public void addListener(InvocationListener listener) { invocationListeners.add(listener); } + @Override + public Headers getRequestHeaders() { + return event.getHeaders(); + } + + @Override + public void addResponseHeader(String key, String value) { + Objects.requireNonNull(key, "key"); + Objects.requireNonNull(value, "value"); + + additionalResponseHeaders.merge(key, Collections.singletonList(value), (a, b) -> { + List l = new ArrayList<>(a); + l.addAll(b); + return l; + }); + } + + /** + * returns the internal map of added response headers + * + * @return mutable map of internal response headers + */ + Map> getAdditionalResponseHeaders() { + return additionalResponseHeaders; + } + + @Override + public void setResponseHeader(String key, String value) { + Objects.requireNonNull(key, "key"); + + String cKey = Headers.canonicalKey(key); + if (value == null) { + additionalResponseHeaders.remove(cKey); + return; + } + additionalResponseHeaders.put(cKey, Collections.singletonList(value)); + } + @Override public void fireOnSuccessfulInvocation() { for (InvocationListener listener : invocationListeners) { try { listener.onSuccess(); - } catch (Exception e) { + } catch (Exception ignored) { } } } @@ -43,7 +88,7 @@ public void fireOnFailedInvocation() { for (InvocationListener listener : invocationListeners) { try { listener.onFailure(); - } catch (Exception e) { + } catch (Exception ignored) { } } } diff --git a/runtime/src/main/java/com/fnproject/fn/runtime/FunctionRuntimeContext.java b/runtime/src/main/java/com/fnproject/fn/runtime/FunctionRuntimeContext.java index 68ed22c3..810a30b5 100644 --- a/runtime/src/main/java/com/fnproject/fn/runtime/FunctionRuntimeContext.java +++ b/runtime/src/main/java/com/fnproject/fn/runtime/FunctionRuntimeContext.java @@ -24,7 +24,7 @@ public class FunctionRuntimeContext implements RuntimeContext { private Object instance; - private final List builtinInputCoercions = Arrays.asList(new StringCoercion(), new ByteArrayCoercion(), new InputEventCoercion(), JacksonCoercion.instance()); + private final List builtinInputCoercions = Arrays.asList(new ContextCoercion(), new StringCoercion(), new ByteArrayCoercion(), new InputEventCoercion(), JacksonCoercion.instance()); private final List userInputCoercions = new LinkedList<>(); private final List builtinOutputCoercions = Arrays.asList(new StringCoercion(), new ByteArrayCoercion(), new VoidCoercion(), new OutputEventCoercion(), JacksonCoercion.instance()); private final List userOutputCoercions = new LinkedList<>(); @@ -37,12 +37,12 @@ public FunctionRuntimeContext(MethodWrapper method, Map config) @Override public String getAppID() { - return config.getOrDefault("FN_APP_ID",""); + return config.getOrDefault("FN_APP_ID", ""); } @Override public String getFunctionID() { - return config.getOrDefault("FN_FN_ID",""); + return config.getOrDefault("FN_FN_ID", ""); } @Override @@ -121,8 +121,8 @@ public void addInputCoercion(InputCoercion ic) { public List getInputCoercions(MethodWrapper targetMethod, int param) { Annotation parameterAnnotations[] = targetMethod.getTargetMethod().getParameterAnnotations()[param]; Optional coercionAnnotation = Arrays.stream(parameterAnnotations) - .filter((ann) -> ann.annotationType().equals(InputBinding.class)) - .findFirst(); + .filter((ann) -> ann.annotationType().equals(InputBinding.class)) + .findFirst(); if (coercionAnnotation.isPresent()) { try { List coercionList = new ArrayList(); @@ -164,8 +164,8 @@ public MethodWrapper getMethod() { return method; } - public FunctionInvocationContext newInvocationContext() { - return new FunctionInvocationContext(this); + public FunctionInvocationContext newInvocationContext(InputEvent inputEvent) { + return new FunctionInvocationContext(this, inputEvent); } public OutputEvent tryInvoke(InputEvent evt, InvocationContext entryPoint) { diff --git a/runtime/src/main/java/com/fnproject/fn/runtime/coercion/ContextCoercion.java b/runtime/src/main/java/com/fnproject/fn/runtime/coercion/ContextCoercion.java new file mode 100644 index 00000000..de0d2ada --- /dev/null +++ b/runtime/src/main/java/com/fnproject/fn/runtime/coercion/ContextCoercion.java @@ -0,0 +1,28 @@ +package com.fnproject.fn.runtime.coercion; + +import com.fnproject.fn.api.*; +import com.fnproject.fn.api.httpgateway.HTTPGatewayContext; +import com.fnproject.fn.runtime.httpgateway.FunctionHTTPGatewayContext; + +import java.util.Optional; + +/** + * Handles coercion to build in context objects (RuntiemContext, InvocationContext , HTTTP context) + */ +public class ContextCoercion implements InputCoercion { + + @Override + public Optional tryCoerceParam(InvocationContext currentContext, int arg, InputEvent input, MethodWrapper method) { + Class paramClass = method.getParamType(arg).getParameterClass(); + + if (paramClass.equals(RuntimeContext.class)) { + return Optional.of(currentContext.getRuntimeContext()); + } else if (paramClass.equals(InvocationContext.class)) { + return Optional.of(currentContext); + } else if (paramClass.equals(HTTPGatewayContext.class)) { + return Optional.of(new FunctionHTTPGatewayContext(currentContext)); + } else { + return Optional.empty(); + } + } +} diff --git a/runtime/src/main/java/com/fnproject/fn/runtime/httpgateway/FunctionHTTPGatewayContext.java b/runtime/src/main/java/com/fnproject/fn/runtime/httpgateway/FunctionHTTPGatewayContext.java new file mode 100644 index 00000000..59e25055 --- /dev/null +++ b/runtime/src/main/java/com/fnproject/fn/runtime/httpgateway/FunctionHTTPGatewayContext.java @@ -0,0 +1,101 @@ +package com.fnproject.fn.runtime.httpgateway; + +import com.fnproject.fn.api.Headers; +import com.fnproject.fn.api.InvocationContext; +import com.fnproject.fn.api.QueryParameters; +import com.fnproject.fn.api.httpgateway.HTTPGatewayContext; + +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Objects; + +/** + * Created on 19/09/2018. + *

    + * (c) 2018 Oracle Corporation + */ +public class FunctionHTTPGatewayContext implements HTTPGatewayContext { + + private final InvocationContext invocationContext; + private final Headers httpRequestHeaders; + private final String method; + private final String requestUrl; + private final QueryParameters queryParameters; + + public FunctionHTTPGatewayContext(InvocationContext invocationContext) { + this.invocationContext = Objects.requireNonNull(invocationContext, "invocationContext"); + + Map> myHeaders = new HashMap<>(); + + String requestUri = ""; + String method = ""; + for (Map.Entry> e : invocationContext.getRequestHeaders().asMap().entrySet()) { + String key = e.getKey(); + if (key.startsWith("Fn-Http-H-")) { + String httpKey = key.substring("Fn-Http-H-".length()); + if (httpKey.length() > 0) { + myHeaders.put(httpKey, e.getValue()); + } + } + + if (key.equals("Fn-Http-Request-Url")) { + requestUri = e.getValue().get(0); + } + if (key.equals("Fn-Http-Method")) { + method = e.getValue().get(0); + } + + } + this.queryParameters = QueryParametersParser.getParams(requestUri); + this.requestUrl = requestUri; + this.method = method; + this.httpRequestHeaders = Headers.emptyHeaders().setHeaders(myHeaders); + + } + + @Override + public InvocationContext getInvocationContext() { + return invocationContext; + } + + @Override + public Headers getHeaders() { + return httpRequestHeaders; + } + + @Override + public String getRequestURL() { + return requestUrl; + } + + @Override + public String getMethod() { + return method; + } + + @Override + public QueryParameters getQueryParameters() { + return queryParameters; + } + + @Override + public void addResponseHeader(String key, String value) { + invocationContext.addResponseHeader("Fn-Http-H-" + key, value); + + } + + @Override + public void setResponseHeader(String key, String value) { + invocationContext.setResponseHeader("Fn-Http-H-" + key, value); + + } + + @Override + public void setStatusCode(int code) { + if (code < 100 || code >= 600) { + throw new IllegalArgumentException("Invalid HTTP status code: " + code); + } + invocationContext.setResponseHeader("Fn-Http-Status", "" + code); + } +} diff --git a/runtime/src/test/java/com/fnproject/fn/runtime/JacksonCoercionTest.java b/runtime/src/test/java/com/fnproject/fn/runtime/JacksonCoercionTest.java index 28effe29..a1db9bd2 100644 --- a/runtime/src/test/java/com/fnproject/fn/runtime/JacksonCoercionTest.java +++ b/runtime/src/test/java/com/fnproject/fn/runtime/JacksonCoercionTest.java @@ -5,6 +5,7 @@ import com.fnproject.fn.api.MethodWrapper; import com.fnproject.fn.runtime.coercion.jackson.JacksonCoercion; import com.fnproject.fn.runtime.testfns.Animal; +import jdk.internal.util.xml.impl.Input; import org.junit.Assert; import org.junit.Test; @@ -28,7 +29,7 @@ public void listOfCustomObjects() throws NoSuchMethodException { MethodWrapper method = new DefaultMethodWrapper(JacksonCoercionTest.class, "testMethod"); FunctionRuntimeContext frc = new FunctionRuntimeContext(method, new HashMap<>()); - FunctionInvocationContext invocationContext = new FunctionInvocationContext(frc); + FunctionInvocationContext invocationContext = new FunctionInvocationContext(frc,new ReadOnceInputEvent(new ByteArrayInputStream(new byte[0]),Headers.emptyHeaders(),"callID",Instant.now())); Map headers = new HashMap<>(); headers.put("content-type", "application/json"); @@ -50,7 +51,7 @@ public void failureToParseIsUserFriendlyError() throws NoSuchMethodException { MethodWrapper method = new DefaultMethodWrapper(JacksonCoercionTest.class, "testMethod"); FunctionRuntimeContext frc = new FunctionRuntimeContext(method, new HashMap<>()); - FunctionInvocationContext invocationContext = new FunctionInvocationContext(frc); + FunctionInvocationContext invocationContext = new FunctionInvocationContext(frc,new ReadOnceInputEvent(new ByteArrayInputStream(new byte[0]),Headers.emptyHeaders(),"callID",Instant.now())); Map headers = new HashMap<>(); headers.put("content-type", "application/json"); From 984353e81b360dcb878f00cba197957ccf20d4b0 Mon Sep 17 00:00:00 2001 From: Owen Cliffe Date: Wed, 19 Sep 2018 19:12:40 +0100 Subject: [PATCH 038/310] regen sig file --- api/src/main/api/snapshot.sigfile | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/api/src/main/api/snapshot.sigfile b/api/src/main/api/snapshot.sigfile index 73833a22..2d27df2f 100644 --- a/api/src/main/api/snapshot.sigfile +++ b/api/src/main/api/snapshot.sigfile @@ -31,6 +31,7 @@ meth public !varargs com.fnproject.fn.api.Headers setHeader(java.lang.String,jav meth public boolean equals(java.lang.Object) meth public com.fnproject.fn.api.Headers removeHeader(java.lang.String) meth public com.fnproject.fn.api.Headers setHeader(java.lang.String,java.util.Collection) +meth public com.fnproject.fn.api.Headers setHeaders(java.util.Map>) meth public int hashCode() meth public java.lang.String toString() meth public java.util.Collection keys() @@ -61,8 +62,12 @@ meth public abstract java.lang.String getCallID() meth public abstract java.time.Instant getDeadline() CLSS public abstract interface com.fnproject.fn.api.InvocationContext +meth public abstract com.fnproject.fn.api.Headers getRequestHeaders() meth public abstract com.fnproject.fn.api.RuntimeContext getRuntimeContext() meth public abstract void addListener(com.fnproject.fn.api.InvocationListener) +meth public abstract void addResponseHeader(java.lang.String,java.lang.String) +meth public abstract void setResponseHeader(java.lang.String,java.lang.String) +meth public void setResponseContentType(java.lang.String) CLSS public abstract interface com.fnproject.fn.api.InvocationListener intf java.util.EventListener @@ -93,6 +98,7 @@ meth public abstract com.fnproject.fn.api.OutputEvent$Status getStatus() meth public abstract java.util.Optional getContentType() meth public abstract void writeToOutput(java.io.OutputStream) throws java.io.IOException meth public boolean isSuccess() +meth public com.fnproject.fn.api.OutputEvent withHeaders(com.fnproject.fn.api.Headers) meth public static com.fnproject.fn.api.OutputEvent emptyResult(com.fnproject.fn.api.OutputEvent$Status) meth public static com.fnproject.fn.api.OutputEvent fromBytes(byte[],com.fnproject.fn.api.OutputEvent$Status,java.lang.String) meth public static com.fnproject.fn.api.OutputEvent fromBytes(byte[],com.fnproject.fn.api.OutputEvent$Status,java.lang.String,com.fnproject.fn.api.Headers) From 31573e0afc07e96073085672035020bd59f8ec99 Mon Sep 17 00:00:00 2001 From: Owen Cliffe Date: Thu, 20 Sep 2018 20:28:47 +0100 Subject: [PATCH 039/310] unit tests on HTTPGw Stuff --- api/src/main/api/snapshot.sigfile | 3 +- .../java/com/fnproject/fn/api/Headers.java | 20 ++-- .../fnproject/fn/api/InvocationContext.java | 20 ++-- .../com/fnproject/fn/api/OutputEvent.java | 27 ++--- .../api/httpgateway/HTTPGatewayContext.java | 19 ++-- .../runtime/flow/FlowContinuationInvoker.java | 20 ++-- .../flow/FlowsContinuationInvokerTest.java | 7 +- .../com/fnproject/fn/runtime/EntryPoint.java | 1 + .../fn/runtime/FunctionInvocationContext.java | 4 +- .../FunctionHTTPGatewayContext.java | 13 ++- .../fn/runtime/EndToEndInvokeTest.java | 32 ++++++ .../fnproject/fn/runtime/FnTestHarness.java | 41 ++++++-- .../fnproject/fn/runtime/HeaderBuilder.java | 9 +- .../FunctionHTTPGatewayContextTest.java | 98 +++++++++++++++++++ .../fnproject/fn/runtime/testfns/TestFn.java | 16 +++ 15 files changed, 258 insertions(+), 72 deletions(-) create mode 100644 runtime/src/test/java/com/fnproject/fn/runtime/httpgateway/FunctionHTTPGatewayContextTest.java diff --git a/api/src/main/api/snapshot.sigfile b/api/src/main/api/snapshot.sigfile index 2d27df2f..65f35f80 100644 --- a/api/src/main/api/snapshot.sigfile +++ b/api/src/main/api/snapshot.sigfile @@ -92,13 +92,14 @@ CLSS public abstract interface com.fnproject.fn.api.OutputCoercion meth public abstract java.util.Optional wrapFunctionResult(com.fnproject.fn.api.InvocationContext,com.fnproject.fn.api.MethodWrapper,java.lang.Object) CLSS public abstract interface com.fnproject.fn.api.OutputEvent +fld public final static java.lang.String CONTENT_TYPE_HEADER = "Content-Type" innr public final static !enum Status meth public abstract com.fnproject.fn.api.Headers getHeaders() meth public abstract com.fnproject.fn.api.OutputEvent$Status getStatus() -meth public abstract java.util.Optional getContentType() meth public abstract void writeToOutput(java.io.OutputStream) throws java.io.IOException meth public boolean isSuccess() meth public com.fnproject.fn.api.OutputEvent withHeaders(com.fnproject.fn.api.Headers) +meth public java.util.Optional getContentType() meth public static com.fnproject.fn.api.OutputEvent emptyResult(com.fnproject.fn.api.OutputEvent$Status) meth public static com.fnproject.fn.api.OutputEvent fromBytes(byte[],com.fnproject.fn.api.OutputEvent$Status,java.lang.String) meth public static com.fnproject.fn.api.OutputEvent fromBytes(byte[],com.fnproject.fn.api.OutputEvent$Status,java.lang.String,com.fnproject.fn.api.Headers) diff --git a/api/src/main/java/com/fnproject/fn/api/Headers.java b/api/src/main/java/com/fnproject/fn/api/Headers.java index 38787b40..75a35a4a 100644 --- a/api/src/main/java/com/fnproject/fn/api/Headers.java +++ b/api/src/main/java/com/fnproject/fn/api/Headers.java @@ -216,7 +216,7 @@ public Headers removeHeader(String key) { /** * Returns the header matching the specified key. This matches headers in a case-insensitive way and substitutes - * underscore and hyphen characters such that : "CONTENT_TYPE" and "Content-type" are equivalent. If no matching + * underscore and hyphen characters such that : "CONTENT_TYPE_HEADER" and "Content-type" are equivalent. If no matching * header is found then {@code Optional.empty} is returned. *

    * When multiple headers are present then the first value is returned- see { #getAllValues(String key)} to get all values for a header @@ -229,12 +229,11 @@ public Optional get(String key) { Objects.requireNonNull(key, "Key cannot be null"); String canonKey = canonicalKey(key); - return headers.entrySet().stream() - .filter((e) -> e.getKey() - .equals(canonKey)) - .map(Map.Entry::getValue) - .map((v) -> v.get(0)) - .findFirst(); + List val = headers.get(canonKey); + if (val == null){ + return Optional.empty(); + } + return Optional.of(val.get(0)); } /** @@ -255,8 +254,13 @@ public Map> asMap() { return headers; } + /** + * GetAllValues returns all values for a header or an empty list if the header has no values + * @param key the Header key + * @return a possibly empty list of values + */ public List getAllValues(String key) { - return headers.getOrDefault(key, Collections.emptyList()); + return headers.getOrDefault(canonicalKey(key), Collections.emptyList()); } public int hashCode() { diff --git a/api/src/main/java/com/fnproject/fn/api/InvocationContext.java b/api/src/main/java/com/fnproject/fn/api/InvocationContext.java index 70297158..080e3bc6 100644 --- a/api/src/main/java/com/fnproject/fn/api/InvocationContext.java +++ b/api/src/main/java/com/fnproject/fn/api/InvocationContext.java @@ -9,6 +9,11 @@ */ public interface InvocationContext { + /** + * Returns the {@link RuntimeContext} associated with this invocation context + * + * @return a runtime context + */ RuntimeContext getRuntimeContext(); /** @@ -22,16 +27,18 @@ public interface InvocationContext { /** * Returns the current request headers for the invocation + * * @return the headers passed into the function */ Headers getRequestHeaders(); /** - * Sets the response content type + * Sets the response content type, this will override the default content type of the output + * * @param contentType a mime type for the response */ - default void setResponseContentType(String contentType){ - this.setResponseHeader("Content-Type",contentType); + default void setResponseContentType(String contentType) { + this.setResponseHeader(OutputEvent.CONTENT_TYPE_HEADER, contentType); } /** @@ -47,8 +54,9 @@ default void setResponseContentType(String contentType){ *

    * Headers set in this way override any headers returned by the function or any middleware on the function * - * @param key header key - * @param value header value set to null to clear the header + * @param key header key + * @param v1 first value to set + * @param vs other values to set header to */ - void setResponseHeader(String key, String value); + void setResponseHeader(String key, String v1, String... vs); } diff --git a/api/src/main/java/com/fnproject/fn/api/OutputEvent.java b/api/src/main/java/com/fnproject/fn/api/OutputEvent.java index 430054e0..0b93b68f 100644 --- a/api/src/main/java/com/fnproject/fn/api/OutputEvent.java +++ b/api/src/main/java/com/fnproject/fn/api/OutputEvent.java @@ -11,6 +11,8 @@ */ public interface OutputEvent { + String CONTENT_TYPE_HEADER = "Content-Type"; + /** * The outcome status of this function event * This determines how the platform will reflect this error to the customer and how it will treat the container after an error @@ -70,7 +72,9 @@ default boolean isSuccess() { * * @return The name of the content type. */ - Optional getContentType(); + default Optional getContentType(){ + return getHeaders().get(CONTENT_TYPE_HEADER); + } /** * Any additional {@link Headers} that should be supplied along with the content @@ -92,7 +96,7 @@ default boolean isSuccess() { /** * Creates a new output event based on this one with the headers overriding - * @param headers + * @param headers the headers use in place of this event * @return a new output event with these set */ default OutputEvent withHeaders(Headers headers) { @@ -106,11 +110,6 @@ public Status getStatus() { return a.getStatus(); } - @Override - public Optional getContentType() { - return a.getContentType(); - } - @Override public Headers getHeaders() { return headers; @@ -140,7 +139,7 @@ static OutputEvent fromBytes(byte[] bytes, Status status, String contentType) { * * @param bytes the byte array to write to the output * @param status the status code of this event - * @param contentType the content type to present on HTTP responses + * @param contentType the content type to present on HTTP responses or null * @param headers any additional headers to supply with HTTP responses * @return a new output event */ @@ -149,6 +148,7 @@ static OutputEvent fromBytes(final byte[] bytes, final Status status, final Stri Objects.requireNonNull(status, "status"); Objects.requireNonNull(headers, "headers"); + final Headers newHeaders = contentType== null?Headers.emptyHeaders():headers.setHeader("Content-Type",contentType); return new OutputEvent() { @Override @@ -156,14 +156,10 @@ public Status getStatus() { return status; } - @Override - public Optional getContentType() { - return Optional.ofNullable(contentType); - } @Override public Headers getHeaders() { - return headers; + return newHeaders; } @Override @@ -187,11 +183,6 @@ public Status getStatus() { return status; } - @Override - public Optional getContentType() { - return Optional.empty(); - } - @Override public Headers getHeaders() { return Headers.emptyHeaders(); diff --git a/api/src/main/java/com/fnproject/fn/api/httpgateway/HTTPGatewayContext.java b/api/src/main/java/com/fnproject/fn/api/httpgateway/HTTPGatewayContext.java index 9f64b104..d97c0edb 100644 --- a/api/src/main/java/com/fnproject/fn/api/httpgateway/HTTPGatewayContext.java +++ b/api/src/main/java/com/fnproject/fn/api/httpgateway/HTTPGatewayContext.java @@ -6,7 +6,7 @@ /** * A context for accessing and setting HTTP Gateway atributes such aas headers and query parameters from a function call - * + *

    * Created on 19/09/2018. *

    * (c) 2018 Oracle Corporation @@ -15,6 +15,7 @@ public interface HTTPGatewayContext { /** * Returns the underlying invocation context behind this HTTP context + * * @return an invocation context related to this function */ InvocationContext getInvocationContext(); @@ -31,6 +32,7 @@ public interface HTTPGatewayContext { /** * Returns the fully qualified request URI that the function was called with, including query parameters + * * @return the request URI of the function */ String getRequestURL(); @@ -38,12 +40,14 @@ public interface HTTPGatewayContext { /** * Returns the incoming request method for the HTTP + * * @return the HTTP method set on this call */ String getMethod(); /** * Returns the query parameters of the request + * * @return a query parameters object */ QueryParameters getQueryParameters(); @@ -61,17 +65,20 @@ public interface HTTPGatewayContext { * Sets a response header to the outbound event, overriding a previous value. *

    * Headers set in this way override any headers returned by the function or any middleware on the function - * + *

    * Setting the "Content-Type" response header also sets this on the underlying Invocation context - * @param key header key - * @param value header value set to null to clear the header + * + * @param key header key + * @param v1 first value to set + * @param vs other values to set header to */ - void setResponseHeader(String key, String value); + void setResponseHeader(String key, String v1, String... vs); /** * Sets the HTTP status code of the response + * * @param code an HTTP status code - * @throws IllegalArgumentException if the code is < 100 or >=600 + * @throws IllegalArgumentException if the code is < 100 or >l=600 */ void setStatusCode(int code); } diff --git a/flow-runtime/src/main/java/com/fnproject/fn/runtime/flow/FlowContinuationInvoker.java b/flow-runtime/src/main/java/com/fnproject/fn/runtime/flow/FlowContinuationInvoker.java index 49656cb8..177b2e89 100644 --- a/flow-runtime/src/main/java/com/fnproject/fn/runtime/flow/FlowContinuationInvoker.java +++ b/flow-runtime/src/main/java/com/fnproject/fn/runtime/flow/FlowContinuationInvoker.java @@ -31,7 +31,7 @@ public final class FlowContinuationInvoker implements FunctionInvoker { public static final String FLOW_ID_HEADER = "Fnproject-FlowId"; - public FlowContinuationInvoker(){ + FlowContinuationInvoker() { } @@ -48,7 +48,7 @@ private static class URLCompleterClientFactory implements CompleterClientFactory public synchronized CompleterClient getCompleterClient() { if (this.completerClient == null) { this.completerClient = new RemoteFlowApiClient(completerBaseUrl + "/v1", - getBlobStoreClient(), new HttpClient()); + getBlobStoreClient(), new HttpClient()); } return this.completerClient; } @@ -138,7 +138,7 @@ public synchronized Flow currentFlow() { if (matchingDispatchPattern != null) { if (matchingDispatchPattern.numArguments() != invokeStageRequest.args.size()) { - throw new FunctionInputHandlingException("Number of arguments provided (" + invokeStageRequest.args.size() + ") in .InvokeStageRequest does not match the number required by the function type (" + matchingDispatchPattern.numArguments() + ")"); + throw new FunctionInputHandlingException("Number of arguments provided (" + invokeStageRequest.args.size() + ") in .InvokeStageRequest does not match the number required by the function type (" + matchingDispatchPattern.numArguments() + ")"); } } else { throw new FunctionInputHandlingException("No functional interface type matches the supplied continuation class"); @@ -207,9 +207,9 @@ private OutputEvent invokeContinuation(BlobStoreClient blobStoreClient, FlowId f APIModel.Datum datum = APIModel.datumFromJava(flowId, ite.getCause(), blobStoreClient); throw new InternalFunctionInvocationException( - "Error invoking flows lambda", - ite.getCause(), - constructOutputEvent(datum, false) + "Error invoking flows lambda", + ite.getCause(), + constructOutputEvent(datum, false) ); } catch (Exception ex) { throw new PlatformException(ex); @@ -226,6 +226,7 @@ private OutputEvent invokeContinuation(BlobStoreClient blobStoreClient, FlowId f */ final static class ContinuationOutputEvent implements OutputEvent { private final byte[] body; + private static final Headers headers = Headers.emptyHeaders().setHeader(OutputEvent.CONTENT_TYPE_HEADER, "application/json"); private ContinuationOutputEvent(boolean success, byte[] body) { this.body = body; @@ -237,11 +238,6 @@ public Status getStatus() { } - @Override - public Optional getContentType() { - return Optional.of("application/json"); - } - @Override public void writeToOutput(OutputStream out) throws IOException { out.write(body); @@ -249,7 +245,7 @@ public void writeToOutput(OutputStream out) throws IOException { @Override public Headers getHeaders() { - return Headers.emptyHeaders(); + return headers; } } diff --git a/flow-runtime/src/test/java/com/fnproject/fn/runtime/flow/FlowsContinuationInvokerTest.java b/flow-runtime/src/test/java/com/fnproject/fn/runtime/flow/FlowsContinuationInvokerTest.java index a7401bc8..e38dfe45 100644 --- a/flow-runtime/src/test/java/com/fnproject/fn/runtime/flow/FlowsContinuationInvokerTest.java +++ b/flow-runtime/src/test/java/com/fnproject/fn/runtime/flow/FlowsContinuationInvokerTest.java @@ -553,7 +553,7 @@ private Map> currentHeaders() { public InputEventBuilder withHeader(String name, String value) { - this.headers = headers.setHeader(name,value); + this.headers = headers.setHeader(name, value); return this; } @@ -564,7 +564,7 @@ private String getHeader(String key) { public InputEvent build() { return new ReadOnceInputEvent( body, - headers, "callID",Instant.now()); + headers, "callID", Instant.now()); } } @@ -660,14 +660,13 @@ public Headers getRequestHeaders() { } - @Override public void addResponseHeader(String key, String value) { } @Override - public void setResponseHeader(String key, String value) { + public void setResponseHeader(String key, String value, String... vs) { } diff --git a/runtime/src/main/java/com/fnproject/fn/runtime/EntryPoint.java b/runtime/src/main/java/com/fnproject/fn/runtime/EntryPoint.java index 7510c75a..5fc52b56 100644 --- a/runtime/src/main/java/com/fnproject/fn/runtime/EntryPoint.java +++ b/runtime/src/main/java/com/fnproject/fn/runtime/EntryPoint.java @@ -114,6 +114,7 @@ public int run(Map env, EventCodec codec, PrintStream loggingOut return output.withHeaders(output.getHeaders().setHeaders(fic.getAdditionalResponseHeaders())); + } catch (IOException err) { fic.fireOnFailedInvocation(); throw new FunctionInputHandlingException("Error closing function input", err); diff --git a/runtime/src/main/java/com/fnproject/fn/runtime/FunctionInvocationContext.java b/runtime/src/main/java/com/fnproject/fn/runtime/FunctionInvocationContext.java index 9e057c20..597bd18d 100644 --- a/runtime/src/main/java/com/fnproject/fn/runtime/FunctionInvocationContext.java +++ b/runtime/src/main/java/com/fnproject/fn/runtime/FunctionInvocationContext.java @@ -62,8 +62,10 @@ Map> getAdditionalResponseHeaders() { } @Override - public void setResponseHeader(String key, String value) { + public void setResponseHeader(String key, String value, String... vs) { Objects.requireNonNull(key, "key"); + Objects.requireNonNull(vs, "vs"); + Arrays.stream(vs).forEach(v->Objects.requireNonNull(v,"null value in list ")); String cKey = Headers.canonicalKey(key); if (value == null) { diff --git a/runtime/src/main/java/com/fnproject/fn/runtime/httpgateway/FunctionHTTPGatewayContext.java b/runtime/src/main/java/com/fnproject/fn/runtime/httpgateway/FunctionHTTPGatewayContext.java index 59e25055..a0f1c8be 100644 --- a/runtime/src/main/java/com/fnproject/fn/runtime/httpgateway/FunctionHTTPGatewayContext.java +++ b/runtime/src/main/java/com/fnproject/fn/runtime/httpgateway/FunctionHTTPGatewayContext.java @@ -2,6 +2,7 @@ import com.fnproject.fn.api.Headers; import com.fnproject.fn.api.InvocationContext; +import com.fnproject.fn.api.OutputEvent; import com.fnproject.fn.api.QueryParameters; import com.fnproject.fn.api.httpgateway.HTTPGatewayContext; @@ -86,8 +87,16 @@ public void addResponseHeader(String key, String value) { } @Override - public void setResponseHeader(String key, String value) { - invocationContext.setResponseHeader("Fn-Http-H-" + key, value); + public void setResponseHeader(String key, String value, String... vs) { + + if (Headers.canonicalKey(key).equals(OutputEvent.CONTENT_TYPE_HEADER)) { + invocationContext.setResponseContentType(value); + invocationContext.setResponseHeader("Fn-Http-H-" + key, value); + } else { + invocationContext.setResponseHeader("Fn-Http-H-" + key, value, vs); + + } + } diff --git a/runtime/src/test/java/com/fnproject/fn/runtime/EndToEndInvokeTest.java b/runtime/src/test/java/com/fnproject/fn/runtime/EndToEndInvokeTest.java index d68f14c7..4be57f20 100644 --- a/runtime/src/test/java/com/fnproject/fn/runtime/EndToEndInvokeTest.java +++ b/runtime/src/test/java/com/fnproject/fn/runtime/EndToEndInvokeTest.java @@ -1,5 +1,6 @@ package com.fnproject.fn.runtime; +import com.fnproject.fn.api.InputEvent; import com.fnproject.fn.runtime.testfns.BadTestFnDuplicateMethods; import com.fnproject.fn.runtime.testfns.TestFn; import org.junit.BeforeClass; @@ -247,4 +248,35 @@ public void shouldReadRawJson() throws Exception { } + @Test + public void shouldReadInputHeaders() throws Exception{ + fn.givenEvent() + .withHeader("myHeader", "Foo") + .withHeader("a-n-header", "b0o","b10") + .enqueue(); + fn.thenRun(TestFn.class, "readRawEvent"); + + InputEvent iev = (InputEvent)TestFn.getInput(); + assertThat(iev).isNotNull(); + assertThat(iev.getHeaders().getAllValues("Myheader")).contains("Foo"); + assertThat(iev.getHeaders().getAllValues("A-N-Header")).contains("b0o","b10"); + + + } + + @Test + public void shouldExposeOutputHeaders() throws Exception{ + fn.givenEvent() + .enqueue(); + fn.thenRun(TestFn.class, "setsOutputHeaders"); + + + FnTestHarness.TestOutput to = fn.getOutputs().get(0); + + System.err.println("got response" + to ); + assertThat(to.getContentType()).contains("foo-ct"); + assertThat(to.getHeaders().get("Header-1")).contains("v1"); + assertThat(to.getHeaders().getAllValues("A")).contains("b1","b2"); + + } } diff --git a/runtime/src/test/java/com/fnproject/fn/runtime/FnTestHarness.java b/runtime/src/test/java/com/fnproject/fn/runtime/FnTestHarness.java index 5ee6b8e2..e6dd0644 100644 --- a/runtime/src/test/java/com/fnproject/fn/runtime/FnTestHarness.java +++ b/runtime/src/test/java/com/fnproject/fn/runtime/FnTestHarness.java @@ -70,12 +70,19 @@ public final class EventBuilder { * Duplicate headers will be overwritten * * @param key header key - * @param value header value + * @param v1 header value + * @param vs other header values */ - public EventBuilder withHeader(String key, String value) { + public EventBuilder withHeader(String key, String v1, String... vs) { Objects.requireNonNull(key, "key"); - Objects.requireNonNull(value, "value"); - headers = headers.addHeader(key, value); + Objects.requireNonNull(v1, "value"); + Objects.requireNonNull(vs, "vs"); + Arrays.stream(vs).forEach(v -> Objects.requireNonNull(v, "null value in varags list ")); + headers = headers.addHeader(key, v1); + for (String v : vs) { + headers = headers.addHeader(key, v); + } + return this; } @@ -178,6 +185,24 @@ public void writeToOutput(OutputStream out) throws IOException { public byte[] getBody() { return body; } + + @Override + public String toString() { + final StringBuffer sb = new StringBuffer("TestOutput{"); + sb.append("body="); + if (body == null) sb.append("null"); + else { + sb.append('['); + for (int i = 0; i < body.length; ++i) + sb.append(i == 0 ? "" : ", ").append(body[i]); + sb.append(']'); + } + sb.append(", status=").append(getStatus()); + sb.append(", contentType=").append(getContentType()); + sb.append(", headers=").append(getHeaders()); + sb.append('}'); + return sb.toString(); + } } /** @@ -226,10 +251,10 @@ public void thenRun(String cls, String method) { System.setOut(functionErr); System.setErr(functionErr); - Map fnConfig = new HashMap<>(config); - fnConfig.put("FN_APP_ID","appID"); - fnConfig.put("FN_FORMAT","http-stream"); - fnConfig.put("FN_FN_ID","fnID"); + Map fnConfig = new HashMap<>(config); + fnConfig.put("FN_APP_ID", "appID"); + fnConfig.put("FN_FORMAT", "http-stream"); + fnConfig.put("FN_FN_ID", "fnID"); exitStatus = new EntryPoint().run( diff --git a/runtime/src/test/java/com/fnproject/fn/runtime/HeaderBuilder.java b/runtime/src/test/java/com/fnproject/fn/runtime/HeaderBuilder.java index 2ac8f53c..bed47b53 100644 --- a/runtime/src/test/java/com/fnproject/fn/runtime/HeaderBuilder.java +++ b/runtime/src/test/java/com/fnproject/fn/runtime/HeaderBuilder.java @@ -2,13 +2,10 @@ import com.fnproject.fn.api.Headers; -import java.util.AbstractMap; -import java.util.Collections; -import java.util.List; -import java.util.Map; +import java.util.*; class HeaderBuilder { - static Map.Entry> headerEntry(String key, String value) { - return new AbstractMap.SimpleEntry<>(Headers.canonicalKey(key), Collections.singletonList(value)); + static Map.Entry> headerEntry(String key, String... values) { + return new AbstractMap.SimpleEntry<>(Headers.canonicalKey(key), Arrays.asList(values)); } } diff --git a/runtime/src/test/java/com/fnproject/fn/runtime/httpgateway/FunctionHTTPGatewayContextTest.java b/runtime/src/test/java/com/fnproject/fn/runtime/httpgateway/FunctionHTTPGatewayContextTest.java new file mode 100644 index 00000000..93ac7015 --- /dev/null +++ b/runtime/src/test/java/com/fnproject/fn/runtime/httpgateway/FunctionHTTPGatewayContextTest.java @@ -0,0 +1,98 @@ +package com.fnproject.fn.runtime.httpgateway; + +import com.fnproject.fn.api.Headers; +import com.fnproject.fn.api.InvocationContext; +import org.junit.Rule; +import org.junit.Test; +import org.mockito.Mock; +import org.mockito.Mockito; +import org.mockito.junit.MockitoJUnit; +import org.mockito.junit.MockitoRule; + +import static org.assertj.core.api.Assertions.assertThat; + +/** + * Created on 20/09/2018. + *

    + * (c) 2018 Oracle Corporation + */ +public class FunctionHTTPGatewayContextTest { + + @Rule + public MockitoRule rule = MockitoJUnit.rule(); + + + @Mock + InvocationContext ctx; + + @Test + public void shouldCreateGatewayContextFromInputs() { + Headers h = Headers.emptyHeaders() + .setHeader("H1", "h1val") + .setHeader("Fn-Http-Method", "PATCH") + .setHeader("Fn-Http-Request-Url", "http://blah.com?a=b&c=d&c=e") + .setHeader("Fn-Http-H-", "ignored") + .setHeader("Fn-Http-H-A", "b") + .setHeader("Fn-Http-H-mv", "c", "d"); + + Mockito.when(ctx.getRequestHeaders()).thenReturn(h); + + FunctionHTTPGatewayContext hctx = new FunctionHTTPGatewayContext(ctx); + + assertThat(hctx.getHeaders()) + .isEqualTo(Headers.emptyHeaders() + .addHeader("A", "b") + .addHeader("mv", "c", "d")); + + + assertThat(hctx.getRequestURL()) + .isEqualTo("http://blah.com?a=b&c=d&c=e"); + + assertThat(hctx.getQueryParameters().get("a")).contains("b"); + assertThat(hctx.getQueryParameters().getValues("c")).contains("d", "e"); + + assertThat(hctx.getMethod()).isEqualTo("PATCH"); + + + } + + + @Test + public void shouldCreateGatewayContextFromEmptyHeaders() { + + Mockito.when(ctx.getRequestHeaders()).thenReturn(Headers.emptyHeaders()); + + FunctionHTTPGatewayContext hctx = new FunctionHTTPGatewayContext(ctx); + + assertThat(hctx.getMethod()).isEqualTo(""); + assertThat(hctx.getRequestURL()).isEqualTo(""); + assertThat(hctx.getHeaders()).isEqualTo(Headers.emptyHeaders()); + assertThat(hctx.getQueryParameters().getAll()).isEmpty(); + + } + + + @Test + public void shouldPassThroughResponseAttributes() { + + Mockito.when(ctx.getRequestHeaders()).thenReturn(Headers.emptyHeaders()); + + FunctionHTTPGatewayContext hctx = new FunctionHTTPGatewayContext(ctx); + hctx.setResponseHeader("My-Header", "foo", "bar"); + Mockito.verify(ctx).setResponseHeader("Fn-Http-H-My-Header", "foo", "bar"); + + hctx.setResponseHeader("Content-Type", "my/ct", "ignored"); + Mockito.verify(ctx).setResponseContentType("my/ct"); + Mockito.verify(ctx).setResponseHeader("Fn-Http-H-Content-Type", "my/ct"); + + hctx.addResponseHeader("new-H", "v1"); + Mockito.verify(ctx).addResponseHeader("Fn-Http-H-new-H", "v1"); + + hctx.setStatusCode(101); + + + Mockito.verify(ctx).setResponseHeader("Fn-Http-Status", "101"); + + } + +} diff --git a/runtime/src/test/java/com/fnproject/fn/runtime/testfns/TestFn.java b/runtime/src/test/java/com/fnproject/fn/runtime/testfns/TestFn.java index 345262a5..ecdbb92a 100644 --- a/runtime/src/test/java/com/fnproject/fn/runtime/testfns/TestFn.java +++ b/runtime/src/test/java/com/fnproject/fn/runtime/testfns/TestFn.java @@ -1,6 +1,7 @@ package com.fnproject.fn.runtime.testfns; import com.fnproject.fn.api.InputEvent; +import com.fnproject.fn.api.InvocationContext; import org.apache.commons.io.IOUtils; import java.io.IOException; @@ -105,6 +106,21 @@ public static String readSecondInput(InputEvent evt) { } + + public static void readRawEvent(InputEvent evt) { + input = evt; + + } + + + public static void setsOutputHeaders(InvocationContext ic) { + ic.addResponseHeader("Header-1","v1"); + ic.setResponseContentType("foo-ct"); + ic.addResponseHeader("a","b1"); + ic.addResponseHeader("a","b2"); + + + } public static List fnGenericAnimal() { Animal dog = new Animal("Spot", 6); Animal cat = new Animal("Jason", 16); From edb50c6fee20df18e88b59eb748a28598f05bec3 Mon Sep 17 00:00:00 2001 From: Owen Cliffe Date: Thu, 20 Sep 2018 20:29:14 +0100 Subject: [PATCH 040/310] ign tests code --- .../java/com/example/fn/TriggerFunction.java | 27 +++++++++++++ .../com/example/fn/TriggerFunctionTest.java | 40 +++++++++++++++++++ 2 files changed, 67 insertions(+) create mode 100644 integration-tests/funcs/httpgwfunc/src/main/java/com/example/fn/TriggerFunction.java create mode 100644 integration-tests/funcs/httpgwfunc/src/test/java/com/example/fn/TriggerFunctionTest.java diff --git a/integration-tests/funcs/httpgwfunc/src/main/java/com/example/fn/TriggerFunction.java b/integration-tests/funcs/httpgwfunc/src/main/java/com/example/fn/TriggerFunction.java new file mode 100644 index 00000000..83c5bb13 --- /dev/null +++ b/integration-tests/funcs/httpgwfunc/src/main/java/com/example/fn/TriggerFunction.java @@ -0,0 +1,27 @@ +package com.example.fn; + +import com.fnproject.fn.api.InvocationContext; +import com.fnproject.fn.api.httpgateway.HTTPGatewayContext; + +public class TriggerFunction { + + public String handleRequest(String input, HTTPGatewayContext hctx, InvocationContext ctx) { + String name = (input == null || input.isEmpty()) ? "world" : input; + + + + ctx.setResponseHeader("MyRawHeader","bar"); + ctx.addResponseHeader("MyRawHeader","bob"); + + + hctx.setResponseHeader("Content-Type","text/plain"); + hctx.addResponseHeader("MyHTTPHeader","foo"); + + hctx.addResponseHeader("GotMethod",hctx.getMethod()); + hctx.addResponseHeader("GotURL",hctx.getRequestURL()); + + hctx.setStatusCode(202); + return "Hello, " + name + "!"; + } + +} \ No newline at end of file diff --git a/integration-tests/funcs/httpgwfunc/src/test/java/com/example/fn/TriggerFunctionTest.java b/integration-tests/funcs/httpgwfunc/src/test/java/com/example/fn/TriggerFunctionTest.java new file mode 100644 index 00000000..2c46f1e8 --- /dev/null +++ b/integration-tests/funcs/httpgwfunc/src/test/java/com/example/fn/TriggerFunctionTest.java @@ -0,0 +1,40 @@ +package com.example.fn; + +import com.fnproject.fn.testing.FnResult; +import com.fnproject.fn.testing.FnTestingRule; +import org.junit.Rule; +import org.junit.Test; + +import static org.junit.Assert.assertEquals; + +public class TriggerFunctionTest { + + @Rule + public final FnTestingRule testing = FnTestingRule.createDefault(); + + @Test + public void shouldReturnGreeting() { + testing.givenEvent().enqueue(); + testing.thenRun(TriggerFunction.class, "handleRequest"); + + FnResult result = testing.getOnlyResult(); + assertEquals("Hello, world!", result.getBodyAsString()); + } + + + @Test + public void shouldWorkWithHTTP() { + testing.givenEvent() + .withHeader("Fn-Http-Method", "POST") + .withHeader("Fn-Http-H-Foo", "bar") + .withHeader("Fn-Http-Request-Url", "http://mysite.com/?q1=2&q3=4") + .enqueue(); + testing.thenRun(TriggerFunction.class, "handleRequest"); + + FnResult result = testing.getOnlyResult(); + assertEquals("Hello, world!", result.getBodyAsString()); + assertEquals("202", result.getHeaders().get("Fn-Http-Status").orElse("")); + } + + +} \ No newline at end of file From 6ae96aa5f7e2f4570fd2f9c3fad45eb46f5b9f2f Mon Sep 17 00:00:00 2001 From: Owen Cliffe Date: Thu, 20 Sep 2018 22:37:08 +0100 Subject: [PATCH 041/310] integration tests --- api/src/main/api/snapshot.sigfile | 2 +- integration-tests/funcs/httpgwfunc/func.yaml | 6 +-- integration-tests/funcs/httpgwfunc/pom.xml | 6 --- .../java/com/example/fn/TriggerFunction.java | 16 +++--- integration-tests/pom.xml | 32 ++++++++++-- .../fn/integrationtest/FunctionsTest.java | 52 ++++++++++++++++++- 6 files changed, 90 insertions(+), 24 deletions(-) diff --git a/api/src/main/api/snapshot.sigfile b/api/src/main/api/snapshot.sigfile index 65f35f80..d9794397 100644 --- a/api/src/main/api/snapshot.sigfile +++ b/api/src/main/api/snapshot.sigfile @@ -62,11 +62,11 @@ meth public abstract java.lang.String getCallID() meth public abstract java.time.Instant getDeadline() CLSS public abstract interface com.fnproject.fn.api.InvocationContext +meth public abstract !varargs void setResponseHeader(java.lang.String,java.lang.String,java.lang.String[]) meth public abstract com.fnproject.fn.api.Headers getRequestHeaders() meth public abstract com.fnproject.fn.api.RuntimeContext getRuntimeContext() meth public abstract void addListener(com.fnproject.fn.api.InvocationListener) meth public abstract void addResponseHeader(java.lang.String,java.lang.String) -meth public abstract void setResponseHeader(java.lang.String,java.lang.String) meth public void setResponseContentType(java.lang.String) CLSS public abstract interface com.fnproject.fn.api.InvocationListener diff --git a/integration-tests/funcs/httpgwfunc/func.yaml b/integration-tests/funcs/httpgwfunc/func.yaml index 7b86fd7a..8380eb34 100644 --- a/integration-tests/funcs/httpgwfunc/func.yaml +++ b/integration-tests/funcs/httpgwfunc/func.yaml @@ -2,11 +2,9 @@ schema_version: 20180708 name: httpgwfunc version: 0.0.1 runtime: java -build_image: fnproject/fn-java-fdk-build:jdk9-1.0.64 -run_image: fnproject/fn-java-fdk:jdk9-1.0.64 cmd: com.example.fn.TriggerFunction::handleRequest -format: http +format: http-stream triggers: -- name: httpgwfunc-trigger +- name: trig type: http source: /httpgwfunc-trigger diff --git a/integration-tests/funcs/httpgwfunc/pom.xml b/integration-tests/funcs/httpgwfunc/pom.xml index fa9aad4f..28d3df65 100644 --- a/integration-tests/funcs/httpgwfunc/pom.xml +++ b/integration-tests/funcs/httpgwfunc/pom.xml @@ -15,12 +15,6 @@ fn-release-repo https://dl.bintray.com/fnproject/fnproject - - true - - - true - diff --git a/integration-tests/funcs/httpgwfunc/src/main/java/com/example/fn/TriggerFunction.java b/integration-tests/funcs/httpgwfunc/src/main/java/com/example/fn/TriggerFunction.java index 83c5bb13..4d45661f 100644 --- a/integration-tests/funcs/httpgwfunc/src/main/java/com/example/fn/TriggerFunction.java +++ b/integration-tests/funcs/httpgwfunc/src/main/java/com/example/fn/TriggerFunction.java @@ -6,19 +6,19 @@ public class TriggerFunction { public String handleRequest(String input, HTTPGatewayContext hctx, InvocationContext ctx) { - String name = (input == null || input.isEmpty()) ? "world" : input; + String name = (input == null || input.isEmpty()) ? "world" : input; + ctx.setResponseHeader("MyRawHeader", "bar"); + ctx.addResponseHeader("MyRawHeader", "bob"); - ctx.setResponseHeader("MyRawHeader","bar"); - ctx.addResponseHeader("MyRawHeader","bob"); + hctx.setResponseHeader("Content-Type", "text/plain"); + hctx.addResponseHeader("MyHTTPHeader", "foo"); - hctx.setResponseHeader("Content-Type","text/plain"); - hctx.addResponseHeader("MyHTTPHeader","foo"); - - hctx.addResponseHeader("GotMethod",hctx.getMethod()); - hctx.addResponseHeader("GotURL",hctx.getRequestURL()); + hctx.addResponseHeader("GotMethod", hctx.getMethod()); + hctx.addResponseHeader("GotURL", hctx.getRequestURL()); + hctx.addResponseHeader("GotHeader", hctx.getHeaders().get("Foo").orElse("nope")); hctx.setStatusCode(202); return "Hello, " + name + "!"; diff --git a/integration-tests/pom.xml b/integration-tests/pom.xml index 803e5221..8eb7e9ad 100644 --- a/integration-tests/pom.xml +++ b/integration-tests/pom.xml @@ -6,28 +6,52 @@ 4.0.0 - com.fnproject.flow + com.fnproject integration-tests 1.0.0-SNAPSHOT + + 2.9.6 + 4.12 + 2.5 + 3.6.2 + jar commons-io commons-io - 2.5 + ${commons-io.version} junit junit - 4.12 + ${junit.version} org.assertj assertj-core - 3.6.2 + ${assertj-core.version} + + + com.fasterxml.jackson.core + jackson-databind + ${jackson.version} + + + + com.fasterxml.jackson.core + jackson-core + ${jackson.version} + + + com.fasterxml.jackson.core + jackson-annotations + ${jackson.version} + + diff --git a/integration-tests/src/test/java/com/fnproject/fn/integrationtest/FunctionsTest.java b/integration-tests/src/test/java/com/fnproject/fn/integrationtest/FunctionsTest.java index 8f1860ee..0b484bc6 100644 --- a/integration-tests/src/test/java/com/fnproject/fn/integrationtest/FunctionsTest.java +++ b/integration-tests/src/test/java/com/fnproject/fn/integrationtest/FunctionsTest.java @@ -1,9 +1,17 @@ package com.fnproject.fn.integrationtest; +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.databind.ObjectMapper; import com.fnproject.fn.integrationtest.IntegrationTestRule.CmdResult; import org.junit.Rule; import org.junit.Test; +import java.net.HttpURLConnection; +import java.net.URI; +import java.net.URL; +import java.util.HashMap; +import java.util.Map; + import static org.assertj.core.api.Assertions.assertThat; /** @@ -42,7 +50,7 @@ public void checkBoilerPlate() throws Exception { IntegrationTestRule.TestContext tc = testRule.newTest(); String fnName = "bp" + format + runtime; - tc.runFn("init", "--runtime", runtime, "--name", fnName,"--format", format); + tc.runFn("init", "--runtime", runtime, "--name", fnName, "--format", format); tc.rewritePOM(); tc.runFn("--verbose", "deploy", "--app", tc.appName(), "--local"); CmdResult rs = tc.runFnWithInput("wibble", "invoke", tc.appName(), fnName); @@ -51,4 +59,46 @@ public void checkBoilerPlate() throws Exception { } } + + @JsonIgnoreProperties(ignoreUnknown = true) + public static class InspectResponse { + + public Map annotations = new HashMap<>(); + } + + @Test() + public void shouldHandleTrigger() throws Exception { + IntegrationTestRule.TestContext tc = testRule.newTest(); + tc.withDirFrom("funcs/httpgwfunc").rewritePOM(); + + tc.runFn("--verbose", "deploy", "--app", tc.appName(), "--local"); + + // Get me the trigger URL + CmdResult output = tc.runFn("inspect", "trigger", tc.appName(), "httpgwfunc", "trig"); + + ObjectMapper om = new ObjectMapper(); + InspectResponse resp = om.readValue(output.getStdout(), InspectResponse.class); + String dest = resp.annotations.get("fnproject.io/trigger/httpEndpoint"); + assertThat(dest).withFailMessage("Missing trigger endpoint annotation").isNotNull(); + + String url = dest + "?q1=a&q2=b"; + URL invokeURL = URI.create(url).toURL(); + + System.out.println("calling " + url); + HttpURLConnection con = (HttpURLConnection) invokeURL.openConnection(); + + con.setRequestMethod("POST"); + con.addRequestProperty("Foo","bar"); + + + assertThat(con.getResponseCode()).isEqualTo(202); + assertThat(con.getHeaderField("GotMethod")).isEqualTo("POST"); + assertThat(con.getHeaderField("GotURL")).isEqualTo(url); + assertThat(con.getHeaderField("GotHeader")).isEqualTo("bar"); + assertThat(con.getHeaderField("MyHTTPHeader")).isEqualTo("foo"); + + + + } + } From 93c6f76715e171b40e3874f95de3891207b7ef65 Mon Sep 17 00:00:00 2001 From: Owen Cliffe Date: Thu, 20 Sep 2018 22:55:25 +0100 Subject: [PATCH 042/310] update QR code demo to be HTTP Gateway friendly --- examples/qr-code/README.md | 49 ++++++++++--------- examples/qr-code/pom.xml | 6 +++ .../java/com/fnproject/fn/examples/QRGen.java | 22 ++++----- .../com/fnproject/fn/examples/QRGenTest.java | 28 +++++------ 4 files changed, 56 insertions(+), 49 deletions(-) diff --git a/examples/qr-code/README.md b/examples/qr-code/README.md index 7cb3aaa1..eda10787 100644 --- a/examples/qr-code/README.md +++ b/examples/qr-code/README.md @@ -54,21 +54,22 @@ of the example function. The body of the function is shown below: ```java -public OutputEvent create(InputEvent event) throws MalformedURLException, UnsupportedEncodingException { - String decodedUrl = URLDecoder.decode(event.getRequestUrl(), "utf-8"); - QueryParameters params = getParams(decodedUrl); - ImageType type = getFormat(params.getFirst("format").orElse("png")); - String contents = params.getFirst("contents").orElse(""); - - ByteArrayOutputStream stream = QRCode.from(contents).to(type).stream(); - System.err.println("Generated QR Code for contents: " + contents); - return OutputEvent.fromBytes(stream.toByteArray(), true, getMimeType(type)); -} + + public byte[] create(HTTPGatewayContext hctx) { + ImageType type = getFormat(hctx.getQueryParameters().get("format").orElse(defaultFormat)); + System.err.println("Default format: " + type.toString()); + String contents = hctx.getQueryParameters().get("contents").orElseThrow(() -> new RuntimeException("Contents must be provided to the QR code")); + + ByteArrayOutputStream stream = QRCode.from(contents).to(type).stream(); + System.err.println("Generated QR Code for contents: " + contents); + + hctx.setResponseHeader("Content-Type", getMimeType(type)); + return stream.toByteArray(); + } + ``` -The fn Java FDK facilitates access to the internal events representing the -invocation of the function, `InputEvent`, and response of the function, -`OutputEvent`, for more fine grained control of the platform. See +The fn Java FDK facilitates access to the HTTP context of events triggered from HTTP gateways via `HTTPGatewayContext` , and response of the function as a bye array, for more fine grained control of the platform. See [Data Binding](/docs/DataBinding.md) for further information on the types of input that the fn Java FDK provides. @@ -116,17 +117,17 @@ this to handle invocations of functions and retrieving function results ```java ... - @Test - public void textHelloWorld() throws Exception { - fn.givenEvent() - .withRequestUrl("http://www.example.com/qr?contents=" + URLEncoder.encode("hello world", "utf-8")) - .withMethod("GET") - .enqueue(); - fn.thenRun(QRGen.class, "create"); - - assertArrayEquals(readTestFile("qr-code-text-hello-world.png"), fn.getOnlyResult().getBodyAsBytes()); - } -... + @Test + public void textHelloWorld() throws Exception { + String content = "hello world"; + fn.givenEvent() + .withHeader("Fn-Http-Request-Url", "http://www.example.com/qr?contents=hello+world&format=png") + .withHeader("Fn-Http-Method","GET") + .enqueue(); + fn.thenRun(QRGen.class, "create"); + + assertEquals(content, decode(fn.getOnlyResult().getBodyAsBytes())); + } ``` Input events are constructed using `fn.givenEvent()` providing an `FnEventBuilder` diff --git a/examples/qr-code/pom.xml b/examples/qr-code/pom.xml index 45e3c6f2..f2a60dfc 100644 --- a/examples/qr-code/pom.xml +++ b/examples/qr-code/pom.xml @@ -39,6 +39,12 @@ ${fdk.version} test + + com.fnproject.fn + testing-junit4 + ${fdk.version} + test + diff --git a/examples/qr-code/src/main/java/com/fnproject/fn/examples/QRGen.java b/examples/qr-code/src/main/java/com/fnproject/fn/examples/QRGen.java index f1ea1fbc..9f233e29 100644 --- a/examples/qr-code/src/main/java/com/fnproject/fn/examples/QRGen.java +++ b/examples/qr-code/src/main/java/com/fnproject/fn/examples/QRGen.java @@ -1,12 +1,11 @@ package com.fnproject.fn.examples; -import com.fnproject.fn.api.InputEvent; -import com.fnproject.fn.api.OutputEvent; import com.fnproject.fn.api.RuntimeContext; +import com.fnproject.fn.api.httpgateway.HTTPGatewayContext; import net.glxn.qrgen.core.image.ImageType; import net.glxn.qrgen.javase.QRCode; -import java.net.MalformedURLException; +import java.io.ByteArrayOutputStream; public class QRGen { private final String defaultFormat; @@ -15,19 +14,20 @@ public QRGen(RuntimeContext ctx) { defaultFormat = ctx.getConfigurationByKey("FORMAT").orElse("png"); } - public OutputEvent create(InputEvent event) throws MalformedURLException, UnsupportedEncodingException { - ImageType type = getFormat(event.getQueryParameters().get("format").orElse(defaultFormat)); + public byte[] create(HTTPGatewayContext hctx) { + ImageType type = getFormat(hctx.getQueryParameters().get("format").orElse(defaultFormat)); System.err.println("Default format: " + type.toString()); - String contents = event.getQueryParameters().get("contents").orElseThrow(() -> new RuntimeException("Contents must be provided to the QR code")); + String contents = hctx.getQueryParameters().get("contents").orElseThrow(() -> new RuntimeException("Contents must be provided to the QR code")); ByteArrayOutputStream stream = QRCode.from(contents).to(type).stream(); System.err.println("Generated QR Code for contents: " + contents); - return OutputEvent.fromBytes(stream.toByteArray(), OutputEvent.SUCCESS, getMimeType(type)); + hctx.setResponseHeader("Content-Type", getMimeType(type)); + return stream.toByteArray(); } private ImageType getFormat(String extension) { - switch(extension.toLowerCase()) { + switch (extension.toLowerCase()) { case "png": return ImageType.PNG; case "jpg": @@ -42,8 +42,8 @@ private ImageType getFormat(String extension) { } } - private String getMimeType(ImageType type) { - switch(type) { + private String getMimeType(ImageType type) { + switch (type) { case JPG: return "image/jpeg"; case GIF: @@ -55,5 +55,5 @@ private String getMimeType(ImageType type) { default: throw new RuntimeException("Invalid ImageType: " + type); } - } + } } diff --git a/examples/qr-code/src/test/java/com/fnproject/fn/examples/QRGenTest.java b/examples/qr-code/src/test/java/com/fnproject/fn/examples/QRGenTest.java index d727e941..c23ec6c2 100644 --- a/examples/qr-code/src/test/java/com/fnproject/fn/examples/QRGenTest.java +++ b/examples/qr-code/src/test/java/com/fnproject/fn/examples/QRGenTest.java @@ -1,7 +1,10 @@ package com.fnproject.fn.examples; import com.fnproject.fn.testing.FnTestingRule; -import com.google.zxing.*; +import com.google.zxing.BinaryBitmap; +import com.google.zxing.ChecksumException; +import com.google.zxing.FormatException; +import com.google.zxing.NotFoundException; import com.google.zxing.client.j2se.BufferedImageLuminanceSource; import com.google.zxing.common.HybridBinarizer; import com.google.zxing.qrcode.QRCodeReader; @@ -23,11 +26,9 @@ public class QRGenTest { public void textHelloWorld() throws Exception { String content = "hello world"; fn.givenEvent() - .withRequestUrl("http://www.example.com/qr") - .withQueryParameter("contents", content) - .withQueryParameter("format", "png") - .withMethod("GET") - .enqueue(); + .withHeader("Fn-Http-Request-Url", "http://www.example.com/qr?contents=hello+world&format=png") + .withHeader("Fn-Http-Method","GET") + .enqueue(); fn.thenRun(QRGen.class, "create"); assertEquals(content, decode(fn.getOnlyResult().getBodyAsBytes())); @@ -37,10 +38,9 @@ public void textHelloWorld() throws Exception { public void phoneNumber() throws Exception { String telephoneNumber = "tel:0-12345-67890"; fn.givenEvent() - .withRequestUrl("http://www.example.com/qr") - .withQueryParameter("contents", telephoneNumber) - .withMethod("GET") - .enqueue(); + .withHeader("Fn-Http-Request-Url", "http://www.example.com/qr?contents=tel:0-12345-67890") + .withHeader("Fn-Http-Method","GET") + .enqueue(); fn.thenRun(QRGen.class, "create"); assertEquals(telephoneNumber, decode(fn.getOnlyResult().getBodyAsBytes())); @@ -51,14 +51,14 @@ public void formatConfigurationIsUsedIfNoFormatIsProvided() throws Exception { String contents = "hello world"; fn.setConfig("FORMAT", "jpg"); fn.givenEvent() - .withRequestUrl("http://www.example.com/qr") - .withQueryParameter("contents", contents) - .withMethod("GET") - .enqueue(); + .withHeader("Fn-Http-Request-Url", "http://www.example.com/qr?contents=hello+world") + .withHeader("Fn-Http-Method","GET") + .enqueue(); fn.thenRun(QRGen.class, "create"); assertEquals(contents, decode(fn.getOnlyResult().getBodyAsBytes())); } + private String decode(byte[] imageBytes) throws IOException, NotFoundException, ChecksumException, FormatException { BinaryBitmap bitmap = readToBitmap(imageBytes); return new QRCodeReader().decode(bitmap).getText(); From a6b116a98f830dbdb51ac44afad97ba6bbe8becc Mon Sep 17 00:00:00 2001 From: Owen Cliffe Date: Fri, 21 Sep 2018 00:03:20 +0100 Subject: [PATCH 043/310] tests and docs, organize inputs --- README.md | 4 +++ .../java/com/fnproject/fn/api/InputEvent.java | 1 - .../com/fnproject/fn/api/HeadersTest.java | 1 + docs/HTTPGatewayFunctions.md | 36 +++++++++++++++++++ .../fnproject/fn/runtime/HeaderBuilder.java | 5 ++- .../fn/runtime/JacksonCoercionTest.java | 1 - 6 files changed, 45 insertions(+), 3 deletions(-) create mode 100644 docs/HTTPGatewayFunctions.md diff --git a/README.md b/README.md index 7ee76718..a2efdc60 100644 --- a/README.md +++ b/README.md @@ -299,6 +299,10 @@ invoked, and to use external configuration variables that you can set up with the Fn tool, have a look at the [Function Configuration](docs/FunctionConfiguration.md) tutorial. +### Handling HTTP requests + +If your function serves an HTTP trigger you may want to access HTTP details such as request or response headers or the HTTP status , checko ut [Accessing HTTP Information From Functions](docs/HTTPGatewayFunctions.md). + ### Input and output bindings You have the option of taking more control of how serialization and diff --git a/api/src/main/java/com/fnproject/fn/api/InputEvent.java b/api/src/main/java/com/fnproject/fn/api/InputEvent.java index 9eeaf234..cda6cca3 100644 --- a/api/src/main/java/com/fnproject/fn/api/InputEvent.java +++ b/api/src/main/java/com/fnproject/fn/api/InputEvent.java @@ -3,7 +3,6 @@ import java.io.Closeable; import java.io.InputStream; import java.time.Instant; -import java.util.Date; import java.util.function.Function; public interface InputEvent extends Closeable { diff --git a/api/src/test/java/com/fnproject/fn/api/HeadersTest.java b/api/src/test/java/com/fnproject/fn/api/HeadersTest.java index 4ec75e23..946ed305 100644 --- a/api/src/test/java/com/fnproject/fn/api/HeadersTest.java +++ b/api/src/test/java/com/fnproject/fn/api/HeadersTest.java @@ -1,6 +1,7 @@ package com.fnproject.fn.api; import org.junit.Test; + import static org.assertj.core.api.Assertions.assertThat; /** diff --git a/docs/HTTPGatewayFunctions.md b/docs/HTTPGatewayFunctions.md new file mode 100644 index 00000000..6f0c00c6 --- /dev/null +++ b/docs/HTTPGatewayFunctions.md @@ -0,0 +1,36 @@ +# Accessing HTTP Information From Functions + +Functions can be used to handle events, RPC calls or HTTP requests. When you are writing a function that handles an HTTP request you frequently need access to the HTTP headers of the incoming request or need to set HTTP headers or the status code on the outbound respsonse. + + +In Fn for Java, when your function is being served by an HTTP trigger (or another compatible HTTP gatway) you can get access to both the incoming request headers for your function by adding a 'com.fnproject.fn.api.httpgateway.HTTPGatewayContext' parameter to your function's parameters. + + + Using this allows you to : + + * Read incoming headers + * Access the method and request URL for the trigger + * Write outbound headers to the response + * Set the status code of the response + + + For example this function reads a request header the method and request URL, sets an response header and sets the response status code to perform an HTTP redirect. + +```java +package com.fnproject.fn.examples; +import com.fnproject.fn.api.httpgateway.HTTPGatewayContext; + + +public class RedirectFunction { + + public redirect(HTTPGatewayContext hctx) { + System.err.println("Request URL is:" + hctx.getRequestURL()); + System.err.println("Trace ID" + hctx.getHeaders().get("My-Trace-ID").orElse("N/A")); + + hctx.setResponseHeader("Location","http://example.com"); + hctx.setStatusCode(302); + + } +} + +``` diff --git a/runtime/src/test/java/com/fnproject/fn/runtime/HeaderBuilder.java b/runtime/src/test/java/com/fnproject/fn/runtime/HeaderBuilder.java index bed47b53..69c3fc7c 100644 --- a/runtime/src/test/java/com/fnproject/fn/runtime/HeaderBuilder.java +++ b/runtime/src/test/java/com/fnproject/fn/runtime/HeaderBuilder.java @@ -2,7 +2,10 @@ import com.fnproject.fn.api.Headers; -import java.util.*; +import java.util.AbstractMap; +import java.util.Arrays; +import java.util.List; +import java.util.Map; class HeaderBuilder { static Map.Entry> headerEntry(String key, String... values) { diff --git a/runtime/src/test/java/com/fnproject/fn/runtime/JacksonCoercionTest.java b/runtime/src/test/java/com/fnproject/fn/runtime/JacksonCoercionTest.java index a1db9bd2..35b3cba4 100644 --- a/runtime/src/test/java/com/fnproject/fn/runtime/JacksonCoercionTest.java +++ b/runtime/src/test/java/com/fnproject/fn/runtime/JacksonCoercionTest.java @@ -5,7 +5,6 @@ import com.fnproject.fn.api.MethodWrapper; import com.fnproject.fn.runtime.coercion.jackson.JacksonCoercion; import com.fnproject.fn.runtime.testfns.Animal; -import jdk.internal.util.xml.impl.Input; import org.junit.Assert; import org.junit.Test; From ee2f61c587d19eb7ee5a817ae3599a067691d66e Mon Sep 17 00:00:00 2001 From: Tom Coupland Date: Fri, 21 Sep 2018 09:02:24 +0100 Subject: [PATCH 044/310] Readme typos --- README.md | 4 ++-- docs/HTTPGatewayFunctions.md | 26 +++++++++++++------------- 2 files changed, 15 insertions(+), 15 deletions(-) diff --git a/README.md b/README.md index a2efdc60..896c3fee 100644 --- a/README.md +++ b/README.md @@ -299,9 +299,9 @@ invoked, and to use external configuration variables that you can set up with the Fn tool, have a look at the [Function Configuration](docs/FunctionConfiguration.md) tutorial. -### Handling HTTP requests +### Handling HTTP requests -If your function serves an HTTP trigger you may want to access HTTP details such as request or response headers or the HTTP status , checko ut [Accessing HTTP Information From Functions](docs/HTTPGatewayFunctions.md). +If your function serves an HTTP trigger you may want to access HTTP details such as request or response headers or the HTTP status , check out [Accessing HTTP Information From Functions](docs/HTTPGatewayFunctions.md). ### Input and output bindings diff --git a/docs/HTTPGatewayFunctions.md b/docs/HTTPGatewayFunctions.md index 6f0c00c6..76fa319c 100644 --- a/docs/HTTPGatewayFunctions.md +++ b/docs/HTTPGatewayFunctions.md @@ -1,35 +1,35 @@ -# Accessing HTTP Information From Functions +# Accessing HTTP Information From Functions -Functions can be used to handle events, RPC calls or HTTP requests. When you are writing a function that handles an HTTP request you frequently need access to the HTTP headers of the incoming request or need to set HTTP headers or the status code on the outbound respsonse. +Functions can be used to handle events, RPC calls or HTTP requests. When you are writing a function that handles an HTTP request you frequently need access to the HTTP headers of the incoming request or need to set HTTP headers or the status code on the outbound respsonse. -In Fn for Java, when your function is being served by an HTTP trigger (or another compatible HTTP gatway) you can get access to both the incoming request headers for your function by adding a 'com.fnproject.fn.api.httpgateway.HTTPGatewayContext' parameter to your function's parameters. +In Fn for Java, when your function is being served by an HTTP trigger (or another compatible HTTP gateway) you can get access to both the incoming request headers for your function by adding a 'com.fnproject.fn.api.httpgateway.HTTPGatewayContext' parameter to your function's parameters. + + + Using this allows you to : - - Using this allows you to : - * Read incoming headers * Access the method and request URL for the trigger - * Write outbound headers to the response + * Write outbound headers to the response * Set the status code of the response - - + + For example this function reads a request header the method and request URL, sets an response header and sets the response status code to perform an HTTP redirect. - + ```java package com.fnproject.fn.examples; import com.fnproject.fn.api.httpgateway.HTTPGatewayContext; public class RedirectFunction { - + public redirect(HTTPGatewayContext hctx) { System.err.println("Request URL is:" + hctx.getRequestURL()); System.err.println("Trace ID" + hctx.getHeaders().get("My-Trace-ID").orElse("N/A")); - + hctx.setResponseHeader("Location","http://example.com"); hctx.setStatusCode(302); - + } } From 2b5cad6d34dc3658ae709dad2253f0e91ec0025e Mon Sep 17 00:00:00 2001 From: CI Date: Fri, 21 Sep 2018 09:07:49 +0000 Subject: [PATCH 045/310] fn-java-fdk: post-1.0.67 version bump [skip ci] --- release.version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/release.version b/release.version index c8b47425..01c08cf3 100644 --- a/release.version +++ b/release.version @@ -1 +1 @@ -1.0.67 +1.0.68 From 4be879447910f7027e879bd698e3d8e653a3deca Mon Sep 17 00:00:00 2001 From: Owen Cliffe Date: Wed, 26 Sep 2018 16:26:55 +0100 Subject: [PATCH 046/310] Fix typos, minor lints, and a small race condition in stream codec cleanup (#155) * Fix typos, minor lints, and a small race condition in stream codec cleanup * review feedback * debug log * add more logging * mask binary stuff in c debug code * Fix issue with uninitialised addres in accept * default REPO location in ign tests, fix race condition in Flow test tests * fix typo from #154 * bump jetty client to latest --- README.md | 2 +- .../testing/flow/FnTestingRuleFlowsTest.java | 8 +- integration-tests/run_tests_ci.sh | 7 +- .../fn/integrationtest/FunctionsTest.java | 2 - pom.xml | 2 +- runtime/src/main/c/buildit.sh | 10 +-- runtime/src/main/c/rebuild_so.sh | 2 +- runtime/src/main/c/unix_socket.c | 65 ++++++++++++--- .../fn/runtime/DefaultEventCodec.java | 6 +- .../fn/runtime/DefaultMethodWrapper.java | 15 ++-- .../com/fnproject/fn/runtime/EntryPoint.java | 6 +- .../fn/runtime/FunctionConfigurer.java | 1 - .../runtime/FunctionInvocationCallback.java | 1 - .../fn/runtime/FunctionInvocationContext.java | 4 +- .../fnproject/fn/runtime/FunctionLoader.java | 2 +- .../fn/runtime/FunctionRuntimeContext.java | 21 +++-- .../fnproject/fn/runtime/HTTPStreamCodec.java | 81 ++++++++++++------- .../fnproject/fn/runtime/HttpEventCodec.java | 10 +-- .../fn/runtime/MethodTypeWrapper.java | 19 +++-- .../fn/runtime/ParameterWrapper.java | 24 ------ .../fn/runtime/PrimitiveTypeResolver.java | 2 +- .../fn/runtime/ReadOnceInputEvent.java | 2 +- .../fn/runtime/ReturnTypeWrapper.java | 18 ----- .../fn/runtime/coercion/ContextCoercion.java | 2 +- .../coercion/jackson/JacksonCoercion.java | 8 +- .../InternalFunctionInvocationException.java | 2 +- .../exception/InvalidEntryPointException.java | 2 +- .../PlatformCommunicationException.java | 2 +- .../fn/runtime/ntv/UnixServerSocket.java | 4 +- .../fnproject/fn/runtime/ntv/UnixSocket.java | 3 +- .../fnproject/fn/runtime/DataBindingTest.java | 2 +- .../fn/runtime/ErrorMessagesTest.java | 16 ++-- .../fnproject/fn/runtime/FnTestHarness.java | 8 +- .../fn/runtime/HTTPStreamCodecTest.java | 25 +++--- .../fn/runtime/HttpEventCodecTest.java | 2 +- .../fn/runtime/MethodWrapperTests.java | 28 +++---- .../fn/runtime/QueryParametersParserTest.java | 2 +- .../fn/runtime/ntv/UnixSocketNativeTest.java | 5 +- ...stomDataBindingFnWithNoUserCoercions.java} | 2 +- .../fnproject/fn/runtime/testfns/TestFn.java | 2 +- .../coercions/StringUpperCaseCoercion.java | 6 +- 41 files changed, 228 insertions(+), 203 deletions(-) delete mode 100644 runtime/src/main/java/com/fnproject/fn/runtime/ParameterWrapper.java delete mode 100644 runtime/src/main/java/com/fnproject/fn/runtime/ReturnTypeWrapper.java rename runtime/src/test/java/com/fnproject/fn/runtime/testfns/{CustomDataBindingFnWithNoUserCoersions.java => CustomDataBindingFnWithNoUserCoercions.java} (83%) diff --git a/README.md b/README.md index 896c3fee..c9a1788f 100644 --- a/README.md +++ b/README.md @@ -61,7 +61,7 @@ runtime: java cmd: com.example.fn.HelloFunction::handleRequest ``` -The `cmd` field determines which method is called when your funciton is +The `cmd` field determines which method is called when your function is invoked. In the generated Function, the `func.yaml` references `com.example.fn.HelloFunction::handleRequest`. Your functions will likely live in different classes, and this field should always point to the method to diff --git a/flow-testing/src/test/java/com/fnproject/fn/testing/flow/FnTestingRuleFlowsTest.java b/flow-testing/src/test/java/com/fnproject/fn/testing/flow/FnTestingRuleFlowsTest.java index cf7946ce..f2e6a03b 100644 --- a/flow-testing/src/test/java/com/fnproject/fn/testing/flow/FnTestingRuleFlowsTest.java +++ b/flow-testing/src/test/java/com/fnproject/fn/testing/flow/FnTestingRuleFlowsTest.java @@ -677,9 +677,9 @@ static void reset() { // These members are external to the class under test so as to be visible from the unit tests. // They must be public, since the TestFn class will be instantiated under a separate ClassLoader; // therefore we need broader access than might be anticipated. - public static Result result = null; - public static Throwable exception = null; - public static Integer staticConfig = null; - public static Integer count = 0; + public static volatile Result result = null; + public static volatile Throwable exception = null; + public static volatile Integer staticConfig = null; + public static volatile Integer count = 0; } diff --git a/integration-tests/run_tests_ci.sh b/integration-tests/run_tests_ci.sh index 940c28ff..e28ee838 100755 --- a/integration-tests/run_tests_ci.sh +++ b/integration-tests/run_tests_ci.sh @@ -6,14 +6,15 @@ set -x cd $(dirname $0) if [ -z ${REPOSITORY_LOCATION} ]; then - echo no REPOSITORY_LOCATION is specified in env - you need to deploy fn jars to a local dir - exit 1 + echo no REPOSITORY_LOCATION is specified in env using /tmp/staging_repo as default + + REPOSITORY_LOCATION=/tmp/staging_repo fi docker rm -f fn_mvn_repo || true docker run -d \ - -v "$REPOSITORY_LOCATION":/repo:ro \ + -v "${REPOSITORY_LOCATION}":/repo:ro \ -w /repo -p18080:18080 \ --name fn_mvn_repo \ python:2.7 \ diff --git a/integration-tests/src/test/java/com/fnproject/fn/integrationtest/FunctionsTest.java b/integration-tests/src/test/java/com/fnproject/fn/integrationtest/FunctionsTest.java index 0b484bc6..1be6f34a 100644 --- a/integration-tests/src/test/java/com/fnproject/fn/integrationtest/FunctionsTest.java +++ b/integration-tests/src/test/java/com/fnproject/fn/integrationtest/FunctionsTest.java @@ -97,8 +97,6 @@ public void shouldHandleTrigger() throws Exception { assertThat(con.getHeaderField("GotHeader")).isEqualTo("bar"); assertThat(con.getHeaderField("MyHTTPHeader")).isEqualTo("foo"); - - } } diff --git a/pom.xml b/pom.xml index f17f58c0..fc93e7b0 100644 --- a/pom.xml +++ b/pom.xml @@ -28,7 +28,7 @@ UTF-8 UTF-8 - 9.4.11.v20180605 + 9.4.12.v20180830 0.8.1 4.12 diff --git a/runtime/src/main/c/buildit.sh b/runtime/src/main/c/buildit.sh index 3e9df64b..09958c0a 100755 --- a/runtime/src/main/c/buildit.sh +++ b/runtime/src/main/c/buildit.sh @@ -2,13 +2,13 @@ set -e src_dir=$(pwd) -build_dir=$src_dir/build/$(uname -s| tr '[:upper:]' '[:lower:]') +build_dir=${src_dir}/build/$(uname -s| tr '[:upper:]' '[:lower:]') -mkdir -p $build_dir +mkdir -p ${build_dir} ( - cd $build_dir - cmake $src_dir + cd ${build_dir} + cmake ${src_dir} make ) -mv $build_dir/libfnunixsocket.* $src_dir \ No newline at end of file +mv ${build_dir}/libfnunixsocket.* ${src_dir} \ No newline at end of file diff --git a/runtime/src/main/c/rebuild_so.sh b/runtime/src/main/c/rebuild_so.sh index 114fcc82..05c6edfd 100755 --- a/runtime/src/main/c/rebuild_so.sh +++ b/runtime/src/main/c/rebuild_so.sh @@ -2,7 +2,7 @@ mydir=$(cd "$(dirname "$0")"; pwd) -cd $mydir +cd ${mydir} set -e docker build -t fdk_c_build -f Dockerfile-buildimage . diff --git a/runtime/src/main/c/unix_socket.c b/runtime/src/main/c/unix_socket.c index 9d3e4408..f773d715 100644 --- a/runtime/src/main/c/unix_socket.c +++ b/runtime/src/main/c/unix_socket.c @@ -10,6 +10,13 @@ #include #include +#ifdef US_DEBUG +#define debuglog(...) fprintf (stderr, __VA_ARGS__) +#else +#define debuglog(...) + +#endif + /** * Throws com.fnproject.fn.runtime.ntv.UnixSocetException, adding strerr(errno) as the second arg if that is set * @param jenv java env @@ -96,6 +103,7 @@ Java_com_fnproject_fn_runtime_ntv_UnixSocketNative_socket(JNIEnv *jenv, jclass j throwIOException(jenv, "Could not create socket"); return -1; } + debuglog("got result from socket %d\n",rv); return rv; } @@ -126,7 +134,9 @@ Java_com_fnproject_fn_runtime_ntv_UnixSocketNative_bind(JNIEnv *jenv, jclass jCl strncpy(addr.sun_path, nativePath, sizeof(addr.sun_path)); (*jenv)->ReleaseStringUTFChars(jenv, jpath, nativePath); - if (bind(jsocket, (struct sockaddr *) &addr, sizeof(addr)) < 0) { + int rv = bind(jsocket, (struct sockaddr *) &addr, sizeof(addr)); + debuglog("got result from bind %d,%s\n",rv,strerror(errno)); + if (rv < 0) { throwIOException(jenv, "Error in bind"); return; } @@ -155,13 +165,14 @@ Java_com_fnproject_fn_runtime_ntv_UnixSocketNative_connect(JNIEnv *jenv, jclass strncpy(addr.sun_path, nativePath, sizeof(addr.sun_path)); (*jenv)->ReleaseStringUTFChars(jenv, jpath, nativePath); - - if (connect(jsocket, (struct sockaddr *) &addr, sizeof(addr)) < 0) { + int result = connect(jsocket, (struct sockaddr *) &addr, sizeof(addr)); + debuglog("%d: got result from connect %d %s\n",jsocket,result,strerror(errno)); + if (result < 0) { if (errno == ETIMEDOUT) { throwSocketTimeoutException(jenv, "Socket connect timed out"); return; } - throwIOException(jenv, "Error in bind"); + throwIOException(jenv, "Error in connect"); return; } } @@ -171,7 +182,10 @@ JNIEXPORT void JNICALL Java_com_fnproject_fn_runtime_ntv_UnixSocketNative_listen(JNIEnv *jenv, jclass jClass, jint jsocket, jint jbacklog) { errno = 0; - if (listen(jsocket, jbacklog) < 0) { + int rv = listen(jsocket, jbacklog); + debuglog("got result from listen %d,%s\n",rv,strerror(errno)); + + if (rv < 0) { throwIOException(jenv, "Error in listen"); return; } @@ -209,6 +223,7 @@ Java_com_fnproject_fn_runtime_ntv_UnixSocketNative_accept(JNIEnv *jenv, jclass j do { + errno = 0; if (timeoutMs > 0) { struct timeval nowTime, used; @@ -232,6 +247,11 @@ Java_com_fnproject_fn_runtime_ntv_UnixSocketNative_accept(JNIEnv *jenv, jclass j FD_SET(jsocket, &set); /* add our file descriptor to the set */ rv = select(jsocket + 1, &set, NULL, NULL, toPtr); + debuglog("XXX %d Got result from select %d : %s\n",jsocket,rv,strerror(errno)); + + if(!FD_ISSET(jsocket,&set)){ + continue; + } } while (rv == -1 && errno == EINTR); if (rv < 0) { @@ -241,12 +261,15 @@ Java_com_fnproject_fn_runtime_ntv_UnixSocketNative_accept(JNIEnv *jenv, jclass j return 0; // timeout } - struct sockaddr_un addr; - bzero(&addr, sizeof(struct sockaddr_un)); - socklen_t rlen; + int result; do { + struct sockaddr_un addr; + bzero(&addr, sizeof(struct sockaddr_un)); + socklen_t rlen = sizeof(struct sockaddr_un); result = accept(jsocket, (struct sockaddr *) &addr, &rlen); + debuglog("XXX %d Got result from accept %d : %s\n",jsocket, result,strerror(errno)); + } while (result == -1 && errno == EINTR); if (result < 0) { @@ -294,12 +317,15 @@ Java_com_fnproject_fn_runtime_ntv_UnixSocketNative_recv(JNIEnv *jenv, jclass jCl do { rcount = read(jsocket, &(buf[offset]), (size_t) length); + debuglog("XXX %d Got result from read %ld : %s\n",jsocket,rcount,strerror(errno)); + } while (rcount == -1 && errno == EINTR); (*jenv)->ReleaseByteArrayElements(jenv, jbuf, buf, 0); if (rcount == 0) { + // EOF in c is -1 in java return -1; } else if (rcount < 0) { if (errno == EAGAIN) { @@ -346,6 +372,7 @@ Java_com_fnproject_fn_runtime_ntv_UnixSocketNative_send(JNIEnv *jenv, jclass jCl ssize_t wcount; do { wcount = write(jsocket, &(buf[offset]), (size_t) length); + debuglog("XXX %d Got result from write %ld : %s\n",jsocket,wcount,strerror(errno)); } while (wcount == -1 && errno == EINTR); @@ -373,7 +400,9 @@ JNIEXPORT void JNICALL Java_com_fnproject_fn_runtime_ntv_UnixSocketNative_close(JNIEnv *jenv, jclass jClass, jint jsocket) { errno = 0; - if (close(jsocket) < 0) { + int rv = close(jsocket); + debuglog("XXX %d got result from close %d,%s\n",jsocket,rv,strerror(errno)); + if (rv < 0) { throwIOException(jenv, "Error in closing socket"); return; } @@ -439,9 +468,11 @@ Java_com_fnproject_fn_runtime_ntv_UnixSocketNative_getSendTimeout(JNIEnv *jenv, struct timeval tv; bzero(&tv, sizeof(struct timeval)); - socklen_t len; + socklen_t len = sizeof(struct timeval); int rv = getsockopt(socket, SOL_SOCKET, SO_SNDTIMEO, &tv, &len); + debuglog("XXX %d getsockopt _getSendTimeout rv %dz\n",socket,rv); + if (rv < 0) { throwIOException(jenv, "Error setting socket options"); return -1; @@ -468,6 +499,7 @@ Java_com_fnproject_fn_runtime_ntv_UnixSocketNative_setRecvTimeout(JNIEnv *jenv, tv.tv_usec = (timeout % 1000) * 1000; int rv = setsockopt(socket, SOL_SOCKET, SO_RCVTIMEO, &tv, sizeof(struct timeval)); + debuglog("XXX %d setsockopt setRecvTimeout rv %dz\n",socket,rv); if (rv < 0) { throwIOException(jenv, "Error setting socket options"); return; @@ -481,13 +513,18 @@ Java_com_fnproject_fn_runtime_ntv_UnixSocketNative_getRecvTimeout(JNIEnv *jenv, struct timeval tv; bzero(&tv, sizeof(struct timeval)); - socklen_t len; + socklen_t len = sizeof(struct timeval); int rv = getsockopt(socket, SOL_SOCKET, SO_RCVTIMEO, &tv, &len); + debuglog("XXX %d getsockopt rv %dz\n",socket,rv); + if (rv < 0) { throwIOException(jenv, "Error setting socket options"); return -1; } + + debuglog("XXX %d getsockopt _getSendTimeout rv %dz\n",socket,rv); + time_t msecs = tv.tv_sec * 1000 + tv.tv_usec / 1000; if (msecs > INT_MAX) { return (jint) INT_MAX; @@ -498,7 +535,7 @@ Java_com_fnproject_fn_runtime_ntv_UnixSocketNative_getRecvTimeout(JNIEnv *jenv, // public static native void shutdown(int socket, boolean input, boolean output) ; JNIEXPORT void JNICALL -Java_com_fnproject_fn_runtime_ntv_UnixSocketNative_shutdown(JNIEnv *jenv, jclass jClass, jint socket, jboolean input, +Java_com_fnproject_fn_runtime_ntv_UnixSocketNative_shutdown(JNIEnv *jenv, jclass jClass, jint jsocket, jboolean input, jboolean output) { errno = 0; int how; @@ -513,7 +550,9 @@ Java_com_fnproject_fn_runtime_ntv_UnixSocketNative_shutdown(JNIEnv *jenv, jclass return; } - int rv = shutdown(socket, how); + + int rv = shutdown(jsocket, how); + debuglog("XXX %d got result from shutdown %d %d,%s\n",jsocket,how,rv,strerror(errno)); if (rv < 0) { throwIOException(jenv, "Failed to shut down socket "); return; diff --git a/runtime/src/main/java/com/fnproject/fn/runtime/DefaultEventCodec.java b/runtime/src/main/java/com/fnproject/fn/runtime/DefaultEventCodec.java index b0a5d41d..4edb7ed5 100644 --- a/runtime/src/main/java/com/fnproject/fn/runtime/DefaultEventCodec.java +++ b/runtime/src/main/java/com/fnproject/fn/runtime/DefaultEventCodec.java @@ -28,7 +28,7 @@ class DefaultEventCodec implements EventCodec { private final InputStream in; private final OutputStream out; - public DefaultEventCodec(Map env, InputStream in, OutputStream out) { + DefaultEventCodec(Map env, InputStream in, OutputStream out) { this.env = env; this.in = in; this.out = out; @@ -43,7 +43,7 @@ private String getRequiredEnv(String name) { return val; } - protected InputEvent readEvent() { + InputEvent readEvent() { String callId = env.getOrDefault("FN_CALL_ID", ""); String deadline = env.get("FN_DEADLINE"); Instant deadlineDate; @@ -70,7 +70,7 @@ protected InputEvent readEvent() { } - protected void writeEvent(OutputEvent evt) { + void writeEvent(OutputEvent evt) { try { evt.writeToOutput(out); } catch (IOException e) { diff --git a/runtime/src/main/java/com/fnproject/fn/runtime/DefaultMethodWrapper.java b/runtime/src/main/java/com/fnproject/fn/runtime/DefaultMethodWrapper.java index 20fc0f97..98a61a2c 100644 --- a/runtime/src/main/java/com/fnproject/fn/runtime/DefaultMethodWrapper.java +++ b/runtime/src/main/java/com/fnproject/fn/runtime/DefaultMethodWrapper.java @@ -19,12 +19,11 @@ public class DefaultMethodWrapper implements MethodWrapper { this.srcMethod = srcMethod; } - public DefaultMethodWrapper(Class srcClass, String srcMethod) { - this.srcClass = srcClass; - this.srcMethod = Arrays.stream(srcClass.getMethods()) - .filter((m) -> m.getName().equals(srcMethod)) - .findFirst() - .orElseThrow(() -> new RuntimeException(new NoSuchMethodException(srcClass.getCanonicalName() + "::" + srcMethod))); + DefaultMethodWrapper(Class srcClass, String srcMethod) { + this(srcClass, Arrays.stream(srcClass.getMethods()) + .filter((m) -> m.getName().equals(srcMethod)) + .findFirst() + .orElseThrow(() -> new RuntimeException(new NoSuchMethodException(srcClass.getCanonicalName() + "::" + srcMethod)))); } @@ -40,12 +39,12 @@ public Method getTargetMethod() { @Override public TypeWrapper getParamType(int index) { - return new ParameterWrapper(this, index); + return MethodTypeWrapper.fromParameter(this, index); } @Override public TypeWrapper getReturnType() { - return new ReturnTypeWrapper(this); + return MethodTypeWrapper.fromReturnType(this); } @Override diff --git a/runtime/src/main/java/com/fnproject/fn/runtime/EntryPoint.java b/runtime/src/main/java/com/fnproject/fn/runtime/EntryPoint.java index 5fc52b56..8e357d2d 100644 --- a/runtime/src/main/java/com/fnproject/fn/runtime/EntryPoint.java +++ b/runtime/src/main/java/com/fnproject/fn/runtime/EntryPoint.java @@ -46,8 +46,12 @@ public static void main(String... args) throws Exception { } /** - * Entrypoint runner - this executes the whole lifecycle of the fn Java FDK runtime - including multiple invocations in the function for hot functions + * Entry point runner - this executes the whole lifecycle of the fn Java FDK runtime - including multiple invocations in the function for hot functions * + * @param env the map of environment variables to run the function with (typically System.getenv but may be customised for testing) + * @param codec the codec to run the function with + * @param loggingOutput the stream to send function error/logging to - this will be wrapped into System.err within the funciton + * @param args any further args passed to the entry point - specifically the class/method name * @return the desired process exit status */ public int run(Map env, EventCodec codec, PrintStream loggingOutput, String... args) { diff --git a/runtime/src/main/java/com/fnproject/fn/runtime/FunctionConfigurer.java b/runtime/src/main/java/com/fnproject/fn/runtime/FunctionConfigurer.java index 6a80408b..f9a1b939 100644 --- a/runtime/src/main/java/com/fnproject/fn/runtime/FunctionConfigurer.java +++ b/runtime/src/main/java/com/fnproject/fn/runtime/FunctionConfigurer.java @@ -21,7 +21,6 @@ public class FunctionConfigurer { * create a function runtime context for a given class and method name * * @param runtimeContext The runtime context encapsulating the function to be run - * @return a new runtime context */ public void configure(FunctionRuntimeContext runtimeContext) { validateConfigurationMethods(runtimeContext.getMethodWrapper()); diff --git a/runtime/src/main/java/com/fnproject/fn/runtime/FunctionInvocationCallback.java b/runtime/src/main/java/com/fnproject/fn/runtime/FunctionInvocationCallback.java index 4d51637a..9c1c5772 100644 --- a/runtime/src/main/java/com/fnproject/fn/runtime/FunctionInvocationCallback.java +++ b/runtime/src/main/java/com/fnproject/fn/runtime/FunctionInvocationCallback.java @@ -1,7 +1,6 @@ package com.fnproject.fn.runtime; public interface FunctionInvocationCallback { - void fireOnSuccessfulInvocation(); void fireOnFailedInvocation(); diff --git a/runtime/src/main/java/com/fnproject/fn/runtime/FunctionInvocationContext.java b/runtime/src/main/java/com/fnproject/fn/runtime/FunctionInvocationContext.java index 597bd18d..9103726d 100644 --- a/runtime/src/main/java/com/fnproject/fn/runtime/FunctionInvocationContext.java +++ b/runtime/src/main/java/com/fnproject/fn/runtime/FunctionInvocationContext.java @@ -15,10 +15,10 @@ */ public class FunctionInvocationContext implements InvocationContext, FunctionInvocationCallback { private final FunctionRuntimeContext runtimeContext; - private List invocationListeners = new CopyOnWriteArrayList<>(); + private final List invocationListeners = new CopyOnWriteArrayList<>(); private final InputEvent event; - private Map> additionalResponseHeaders = new ConcurrentHashMap<>(); + private final Map> additionalResponseHeaders = new ConcurrentHashMap<>(); FunctionInvocationContext(FunctionRuntimeContext ctx, InputEvent event) { this.runtimeContext = ctx; diff --git a/runtime/src/main/java/com/fnproject/fn/runtime/FunctionLoader.java b/runtime/src/main/java/com/fnproject/fn/runtime/FunctionLoader.java index ec7fb70e..30b10101 100644 --- a/runtime/src/main/java/com/fnproject/fn/runtime/FunctionLoader.java +++ b/runtime/src/main/java/com/fnproject/fn/runtime/FunctionLoader.java @@ -68,7 +68,7 @@ private Class loadClass(String className) { * Override the classloader used for fn class resolution * Primarily for testing, otherwise the system/default classloader is used. * - * @param loader + * @param loader the context class loader to use for this function */ public static void setContextClassLoader(ClassLoader loader) { contextClassLoader = loader; diff --git a/runtime/src/main/java/com/fnproject/fn/runtime/FunctionRuntimeContext.java b/runtime/src/main/java/com/fnproject/fn/runtime/FunctionRuntimeContext.java index 810a30b5..24c53e43 100644 --- a/runtime/src/main/java/com/fnproject/fn/runtime/FunctionRuntimeContext.java +++ b/runtime/src/main/java/com/fnproject/fn/runtime/FunctionRuntimeContext.java @@ -18,9 +18,9 @@ public class FunctionRuntimeContext implements RuntimeContext { private final Map config; private final MethodWrapper method; - private Map attributes = new HashMap<>(); - private List preCallHandlers = new ArrayList<>(); - private List configuredInvokers = new ArrayList<>(); + private final Map attributes = new HashMap<>(); + private final List preCallHandlers = new ArrayList<>(); + private final List configuredInvokers = new ArrayList<>(); private Object instance; @@ -125,7 +125,7 @@ public List getInputCoercions(MethodWrapper targetMethod, int par .findFirst(); if (coercionAnnotation.isPresent()) { try { - List coercionList = new ArrayList(); + List coercionList = new ArrayList<>(); InputBinding inputBindingAnnotation = (InputBinding) coercionAnnotation.get(); coercionList.add(inputBindingAnnotation.coercion().getDeclaredConstructor().newInstance()); return coercionList; @@ -169,23 +169,20 @@ public FunctionInvocationContext newInvocationContext(InputEvent inputEvent) { } public OutputEvent tryInvoke(InputEvent evt, InvocationContext entryPoint) { - OutputEvent output = null; for (FunctionInvoker invoker : preCallHandlers) { Optional result = invoker.tryInvoke(entryPoint, evt); if (result.isPresent()) { - output = result.get(); - return output; + return result.get(); } } for (FunctionInvoker invoker : configuredInvokers) { Optional result = invoker.tryInvoke(entryPoint, evt); if (result.isPresent()) { - output = result.get(); - return output; + return result.get(); } } - return output; + return null; } @Override @@ -193,7 +190,7 @@ public List getOutputCoercions(Method method) { OutputBinding coercionAnnotation = method.getAnnotation(OutputBinding.class); if (coercionAnnotation != null) { try { - List coercionList = new ArrayList(); + List coercionList = new ArrayList<>(); coercionList.add(coercionAnnotation.coercion().getDeclaredConstructor().newInstance()); return coercionList; @@ -201,7 +198,7 @@ public List getOutputCoercions(Method method) { throw new FunctionConfigurationException("Unable to instantiate output coercion class for method " + getMethod()); } } - List outputList = new ArrayList(); + List outputList = new ArrayList<>(); outputList.addAll(userOutputCoercions); outputList.addAll(builtinOutputCoercions); return outputList; diff --git a/runtime/src/main/java/com/fnproject/fn/runtime/HTTPStreamCodec.java b/runtime/src/main/java/com/fnproject/fn/runtime/HTTPStreamCodec.java index 9a2ba047..a28d9ccd 100644 --- a/runtime/src/main/java/com/fnproject/fn/runtime/HTTPStreamCodec.java +++ b/runtime/src/main/java/com/fnproject/fn/runtime/HTTPStreamCodec.java @@ -1,6 +1,7 @@ package com.fnproject.fn.runtime; +import com.fasterxml.jackson.core.io.CharTypes; import com.fnproject.fn.api.Headers; import com.fnproject.fn.api.InputEvent; import com.fnproject.fn.api.OutputEvent; @@ -49,13 +50,15 @@ public final class HTTPStreamCodec implements EventCodec, Closeable { public static final String HTTP_STREAM_FORMAT = "http-stream"; private static final String FN_LISTENER = "FN_LISTENER"; + private static final Set stripInputHeaders; + private static final Set stripOutputHeaders; private final Map env; private final AtomicBoolean stopping = new AtomicBoolean(false); private final File socketFile; - private static final Set stripInputHeaders; - private static final Set stripOutputHeaders; private final CompletableFuture stopped = new CompletableFuture<>(); private final UnixServerSocket socket; + private final File tempFile; + static { Set hin = new HashSet<>(); @@ -75,7 +78,6 @@ public final class HTTPStreamCodec implements EventCodec, Closeable { stripOutputHeaders = Collections.unmodifiableSet(hout); } - private final File tempFile; private String randomString() { @@ -97,7 +99,7 @@ private String randomString() { * * @param env an env map */ - public HTTPStreamCodec(Map env) { + HTTPStreamCodec(Map env) { this.env = Objects.requireNonNull(env, "env"); String listenerAddress = getRequiredEnv(FN_LISTENER); @@ -134,6 +136,27 @@ public HTTPStreamCodec(Map env) { } + + private String jsonError(String message, String detail) { + if (message == null) { + message = ""; + } + + StringBuilder sb = new StringBuilder(); + sb.append("{ \"message\":\""); + CharTypes.appendQuoted(sb, message); + sb.append("\""); + + if (detail != null) { + sb.append(", \"detail\":\""); + CharTypes.appendQuoted(sb, detail); + sb.append("\""); + } + + sb.append("}"); + return sb.toString(); + } + @Override public void runCodec(Handler h) { @@ -144,7 +167,7 @@ public void runCodec(Handler h) { evt = readEvent(request); } catch (FunctionInputHandlingException e) { response.setStatusCode(500); - response.setEntity(new StringEntity("{\"message\":\"Invalid input from function\",\"detail\":\"" + e.getMessage() + "\"}", ContentType.APPLICATION_JSON)); + response.setEntity(new StringEntity(jsonError("Invalid input for function", e.getMessage()), ContentType.APPLICATION_JSON)); return; } @@ -154,7 +177,7 @@ public void runCodec(Handler h) { outEvt = h.handle(evt); } catch (Exception e) { response.setStatusCode(500); - response.setEntity(new StringEntity("{\"message\":\"Unhandled internal error in FDK\"}", ContentType.APPLICATION_JSON)); + response.setEntity(new StringEntity(jsonError("Unhandled internal error in FDK",e.getMessage()), ContentType.APPLICATION_JSON)); return; } @@ -163,7 +186,7 @@ public void runCodec(Handler h) { } catch (Exception e) { // TODO strange edge cases might appear with headers where the response is half written here response.setStatusCode(500); - response.setEntity(new StringEntity("{\"message\":\"Unhandled internal error while generating response FDK\"}", ContentType.APPLICATION_JSON)); + response.setEntity(new StringEntity(jsonError("Unhandled internal error while writing FDK response",e.getMessage()), ContentType.APPLICATION_JSON)); } } )); @@ -174,40 +197,42 @@ public void runCodec(Handler h) { try { while (!stopping.get()) { - UnixSocket sock; - try { - sock = socket.accept(100); + try (UnixSocket sock = socket.accept(100)) { if (sock == null) { + // timeout during accept, try again continue; } // TODO tweak these properly sock.setSendBufferSize(65535); sock.setReceiveBufferSize(65535); - } catch (IOException e) { + if (stopping.get()) { // ignore IO errors on stop return; } - throw new FunctionIOException("failed to accept connection from platform, terminating", e); - } - try { - DefaultBHttpServerConnection con = new DefaultBHttpServerConnection(65535); - con.bind(sock); - while (!sock.isClosed()) { - try { - svc.handleRequest(con, new BasicHttpContext()); - } catch (Exception ignored) { - sock.close(); + try { + DefaultBHttpServerConnection con = new DefaultBHttpServerConnection(65535); + con.bind(sock); + while (!sock.isClosed()) { + try { + svc.handleRequest(con, new BasicHttpContext()); + } catch (HttpException e) { + sock.close(); + throw e; + } } + } catch (HttpException | IOException e) { + System.err.println("FDK Got Exception while handling HTTP request" + e.getMessage()); + e.printStackTrace(); + // we continue here and leave the container hot } - } catch (IOException ignored) { - // TODO should log here? - } finally { - try { - sock.close(); - } catch (IOException ignored) { + } catch (IOException e) { + if (stopping.get()) { + // ignore IO errors on stop + return; } + throw new FunctionIOException("failed to accept connection from platform, terminating", e); } } @@ -230,7 +255,7 @@ private String getRequiredEnv(String name) { private static String getRequiredHeader(HttpRequest request, String headerName) { Header header = request.getFirstHeader(headerName); if (header == null) { - throw new FunctionInputHandlingException("Required FDK header variable " + headerName + " is not set, check you are using the latest functinos and FDK versions"); + throw new FunctionInputHandlingException("Required FDK header variable " + headerName + " is not set, check you are using the latest fn and FDK versions"); } return header.getValue(); } diff --git a/runtime/src/main/java/com/fnproject/fn/runtime/HttpEventCodec.java b/runtime/src/main/java/com/fnproject/fn/runtime/HttpEventCodec.java index 711f895f..6e980e44 100644 --- a/runtime/src/main/java/com/fnproject/fn/runtime/HttpEventCodec.java +++ b/runtime/src/main/java/com/fnproject/fn/runtime/HttpEventCodec.java @@ -36,7 +36,7 @@ * * @deprecated all new functions should use {@link HTTPStreamCodec} */ -public class HttpEventCodec implements EventCodec { +public final class HttpEventCodec implements EventCodec { private static final String CONTENT_TYPE_HEADER = "Content-Type"; private final SessionInputBuffer sib; @@ -72,7 +72,7 @@ private String getRequiredEnv(String name) { return val; } - protected Optional readEvent() { + Optional readEvent() { HttpRequest req; try { @@ -125,7 +125,7 @@ protected Optional readEvent() { } - protected void writeEvent(OutputEvent evt) { + void writeEvent(OutputEvent evt) { try { // TODO: We buffer the whole output here just to get the content-length // TODO: functions should support chunked @@ -144,9 +144,7 @@ protected void writeEvent(OutputEvent evt) { response = new BasicHttpResponse(new BasicStatusLine(new ProtocolVersion("HTTP", 1, 1), evt.getStatus().getCode(), evt.getStatus().name())); } - evt.getHeaders().asMap().forEach((k, vs) -> { - vs.forEach(v -> response.addHeader(k, v)); - }); + evt.getHeaders().asMap().forEach((k, vs) -> vs.forEach(v -> response.addHeader(k, v))); evt.getContentType().ifPresent((ct) -> response.setHeader(CONTENT_TYPE_HEADER, ct)); response.setHeader("Content-length", String.valueOf(data.length)); diff --git a/runtime/src/main/java/com/fnproject/fn/runtime/MethodTypeWrapper.java b/runtime/src/main/java/com/fnproject/fn/runtime/MethodTypeWrapper.java index aff98db4..3972784f 100644 --- a/runtime/src/main/java/com/fnproject/fn/runtime/MethodTypeWrapper.java +++ b/runtime/src/main/java/com/fnproject/fn/runtime/MethodTypeWrapper.java @@ -7,12 +7,10 @@ import java.lang.reflect.ParameterizedType; import java.lang.reflect.Type; -public abstract class MethodTypeWrapper implements TypeWrapper { - protected final MethodWrapper src; - protected Class parameterClass; +public final class MethodTypeWrapper implements TypeWrapper { + private final Class parameterClass; - public MethodTypeWrapper(MethodWrapper src, Class parameterClass) { - this.src = src; + private MethodTypeWrapper(Class parameterClass) { this.parameterClass = parameterClass; } @@ -21,7 +19,7 @@ public Class getParameterClass() { return parameterClass; } - protected static Class resolveType(Type type, MethodWrapper src) { + static Class resolveType(Type type, MethodWrapper src) { if (type instanceof Class) { return PrimitiveTypeResolver.resolve((Class) type); } else if (type instanceof ParameterizedType) { @@ -36,4 +34,13 @@ protected static Class resolveType(Type type, MethodWrapper src) { } } + public static TypeWrapper fromParameter(MethodWrapper method, int paramIndex) { + return new MethodTypeWrapper(resolveType(method.getTargetMethod().getGenericParameterTypes()[paramIndex], method)); + } + + public static TypeWrapper fromReturnType(MethodWrapper method) { + return new MethodTypeWrapper(resolveType(method.getTargetMethod().getGenericReturnType(), method)); + + } + } diff --git a/runtime/src/main/java/com/fnproject/fn/runtime/ParameterWrapper.java b/runtime/src/main/java/com/fnproject/fn/runtime/ParameterWrapper.java deleted file mode 100644 index efe099a4..00000000 --- a/runtime/src/main/java/com/fnproject/fn/runtime/ParameterWrapper.java +++ /dev/null @@ -1,24 +0,0 @@ -package com.fnproject.fn.runtime; - -import com.fnproject.fn.api.MethodWrapper; - -/** - * A {@link com.fnproject.fn.api.TypeWrapper} for capturing type information about a method's parameter. - */ -class ParameterWrapper extends MethodTypeWrapper { - - /** - * Constructor - * - * @param method the method - * @param paramIndex the index of the parameter which we store type information about - */ - public ParameterWrapper(MethodWrapper method, int paramIndex) { - super(method, resolveType(method.getTargetMethod().getGenericParameterTypes()[paramIndex], method)); - } - - @Override - public Class getParameterClass() { - return parameterClass; - } -} diff --git a/runtime/src/main/java/com/fnproject/fn/runtime/PrimitiveTypeResolver.java b/runtime/src/main/java/com/fnproject/fn/runtime/PrimitiveTypeResolver.java index 6c3e66a2..5f2f8e3f 100644 --- a/runtime/src/main/java/com/fnproject/fn/runtime/PrimitiveTypeResolver.java +++ b/runtime/src/main/java/com/fnproject/fn/runtime/PrimitiveTypeResolver.java @@ -4,7 +4,7 @@ import java.util.Map; public class PrimitiveTypeResolver { - private static Map, Class> boxedTypes = new HashMap<>(); + private static final Map, Class> boxedTypes = new HashMap<>(); static { boxedTypes.put(void.class, Void.class); boxedTypes.put(boolean.class, Boolean.class); diff --git a/runtime/src/main/java/com/fnproject/fn/runtime/ReadOnceInputEvent.java b/runtime/src/main/java/com/fnproject/fn/runtime/ReadOnceInputEvent.java index 21276306..7bfb4cde 100644 --- a/runtime/src/main/java/com/fnproject/fn/runtime/ReadOnceInputEvent.java +++ b/runtime/src/main/java/com/fnproject/fn/runtime/ReadOnceInputEvent.java @@ -19,7 +19,7 @@ */ public class ReadOnceInputEvent implements InputEvent { private final BufferedInputStream body; - private AtomicBoolean consumed = new AtomicBoolean(false); + private final AtomicBoolean consumed = new AtomicBoolean(false); private final Headers headers; private final Instant deadline; private final String callID; diff --git a/runtime/src/main/java/com/fnproject/fn/runtime/ReturnTypeWrapper.java b/runtime/src/main/java/com/fnproject/fn/runtime/ReturnTypeWrapper.java deleted file mode 100644 index 120fffd1..00000000 --- a/runtime/src/main/java/com/fnproject/fn/runtime/ReturnTypeWrapper.java +++ /dev/null @@ -1,18 +0,0 @@ -package com.fnproject.fn.runtime; - -import com.fnproject.fn.api.MethodWrapper; - -/** - * A {@link com.fnproject.fn.api.TypeWrapper} for capturing type information about a method's parameter. - */ -class ReturnTypeWrapper extends MethodTypeWrapper { - - /** - * Constructor - * - * @param method the method which we store return-type information about - */ - ReturnTypeWrapper(MethodWrapper method) { - super(method, resolveType(method.getTargetMethod().getGenericReturnType(), method)); - } -} diff --git a/runtime/src/main/java/com/fnproject/fn/runtime/coercion/ContextCoercion.java b/runtime/src/main/java/com/fnproject/fn/runtime/coercion/ContextCoercion.java index de0d2ada..9bea4611 100644 --- a/runtime/src/main/java/com/fnproject/fn/runtime/coercion/ContextCoercion.java +++ b/runtime/src/main/java/com/fnproject/fn/runtime/coercion/ContextCoercion.java @@ -7,7 +7,7 @@ import java.util.Optional; /** - * Handles coercion to build in context objects (RuntiemContext, InvocationContext , HTTTP context) + * Handles coercion to build in context objects ({@link RuntimeContext}, {@link InvocationContext} , {@link HTTPGatewayContext}) */ public class ContextCoercion implements InputCoercion { diff --git a/runtime/src/main/java/com/fnproject/fn/runtime/coercion/jackson/JacksonCoercion.java b/runtime/src/main/java/com/fnproject/fn/runtime/coercion/jackson/JacksonCoercion.java index 3c31a1a1..50a1f8d3 100644 --- a/runtime/src/main/java/com/fnproject/fn/runtime/coercion/jackson/JacksonCoercion.java +++ b/runtime/src/main/java/com/fnproject/fn/runtime/coercion/jackson/JacksonCoercion.java @@ -15,10 +15,14 @@ * This supports marshalling and unmarshalling of event parameters and responses to */ public class JacksonCoercion implements InputCoercion, OutputCoercion { - private static String OM_KEY = JacksonCoercion.class.getCanonicalName() + ".om"; + private static final String OM_KEY = JacksonCoercion.class.getCanonicalName() + ".om"; - private static JacksonCoercion instance = new JacksonCoercion(); + private static final JacksonCoercion instance = new JacksonCoercion(); + /** + * Return the global instance of this coercion + * @return a singleton instance of the JSON coercion for the VM + */ public static JacksonCoercion instance() { return instance; } diff --git a/runtime/src/main/java/com/fnproject/fn/runtime/exception/InternalFunctionInvocationException.java b/runtime/src/main/java/com/fnproject/fn/runtime/exception/InternalFunctionInvocationException.java index 8b416a7c..40ca5d80 100644 --- a/runtime/src/main/java/com/fnproject/fn/runtime/exception/InternalFunctionInvocationException.java +++ b/runtime/src/main/java/com/fnproject/fn/runtime/exception/InternalFunctionInvocationException.java @@ -43,7 +43,7 @@ public Throwable getCause() { /** * map this exception to an output event - * @return + * @return the output event associated with this exception */ public OutputEvent toOutput() { return event; diff --git a/runtime/src/main/java/com/fnproject/fn/runtime/exception/InvalidEntryPointException.java b/runtime/src/main/java/com/fnproject/fn/runtime/exception/InvalidEntryPointException.java index 8cc01cbc..2e7e03c6 100644 --- a/runtime/src/main/java/com/fnproject/fn/runtime/exception/InvalidEntryPointException.java +++ b/runtime/src/main/java/com/fnproject/fn/runtime/exception/InvalidEntryPointException.java @@ -3,7 +3,7 @@ import com.fnproject.fn.api.exception.FunctionLoadException; /** - * The function entrypoint was malformed. + * The function entry point spec was malformed. */ public class InvalidEntryPointException extends FunctionLoadException { public InvalidEntryPointException(String msg) { diff --git a/runtime/src/main/java/com/fnproject/fn/runtime/exception/PlatformCommunicationException.java b/runtime/src/main/java/com/fnproject/fn/runtime/exception/PlatformCommunicationException.java index 2bbb33d7..09db0863 100644 --- a/runtime/src/main/java/com/fnproject/fn/runtime/exception/PlatformCommunicationException.java +++ b/runtime/src/main/java/com/fnproject/fn/runtime/exception/PlatformCommunicationException.java @@ -1,7 +1,7 @@ package com.fnproject.fn.runtime.exception; /** - * An error occured in the + * An error occurred in the */ public class PlatformCommunicationException extends RuntimeException { public PlatformCommunicationException(String message) { diff --git a/runtime/src/main/java/com/fnproject/fn/runtime/ntv/UnixServerSocket.java b/runtime/src/main/java/com/fnproject/fn/runtime/ntv/UnixServerSocket.java index 7460d250..a4fb310b 100644 --- a/runtime/src/main/java/com/fnproject/fn/runtime/ntv/UnixServerSocket.java +++ b/runtime/src/main/java/com/fnproject/fn/runtime/ntv/UnixServerSocket.java @@ -12,7 +12,7 @@ */ public class UnixServerSocket implements Closeable { private final int fd; - AtomicBoolean closed = new AtomicBoolean(); + private final AtomicBoolean closed = new AtomicBoolean(); private UnixServerSocket(int fd) { this.fd = fd; @@ -49,7 +49,7 @@ public void close() throws IOException { public UnixSocket accept(long timeoutMillis) throws IOException { if (closed.get()) { - throw new SocketException("acceot on closed socket"); + throw new SocketException("accept on closed socket"); } int newFd = UnixSocketNative.accept(fd, timeoutMillis); if (newFd == 0) { diff --git a/runtime/src/main/java/com/fnproject/fn/runtime/ntv/UnixSocket.java b/runtime/src/main/java/com/fnproject/fn/runtime/ntv/UnixSocket.java index 592f2108..26ca8457 100644 --- a/runtime/src/main/java/com/fnproject/fn/runtime/ntv/UnixSocket.java +++ b/runtime/src/main/java/com/fnproject/fn/runtime/ntv/UnixSocket.java @@ -84,7 +84,6 @@ protected void sendUrgentData(int data) throws IOException { } - // Thes are overridden specifically @Override public void setOption(int optID, Object value) throws SocketException { throw new UnsupportedOperationException(); @@ -312,7 +311,7 @@ public void shutdownOutput() throws IOException { @Override public void close() throws IOException { - if (!closed.compareAndSet(false, true)) { + if (closed.compareAndSet(false, true)) { UnixSocketNative.close(fd); } } diff --git a/runtime/src/test/java/com/fnproject/fn/runtime/DataBindingTest.java b/runtime/src/test/java/com/fnproject/fn/runtime/DataBindingTest.java index da49acbc..16095e8a 100644 --- a/runtime/src/test/java/com/fnproject/fn/runtime/DataBindingTest.java +++ b/runtime/src/test/java/com/fnproject/fn/runtime/DataBindingTest.java @@ -84,7 +84,7 @@ public void shouldUseFirstOutputCoercionSpecifiedOnFunctionRuntimeContext() thro public void shouldUseBuiltInInputCoercionSpecifiedOnFunctionRuntimeContext() throws Exception { fn.givenEvent().withBody("Hello World").enqueue(); - fn.thenRun(CustomDataBindingFnWithNoUserCoersions.class, "echo"); + fn.thenRun(CustomDataBindingFnWithNoUserCoercions.class, "echo"); assertThat(fn.getOnlyOutputAsString()).isEqualTo("Hello World"); assertThat(fn.getStdErrAsString()).isEmpty(); diff --git a/runtime/src/test/java/com/fnproject/fn/runtime/ErrorMessagesTest.java b/runtime/src/test/java/com/fnproject/fn/runtime/ErrorMessagesTest.java index 5809ae20..49c472e8 100644 --- a/runtime/src/test/java/com/fnproject/fn/runtime/ErrorMessagesTest.java +++ b/runtime/src/test/java/com/fnproject/fn/runtime/ErrorMessagesTest.java @@ -18,7 +18,7 @@ private void assertIsErrorWithoutStacktrace(String errorMessage) { assertThat(fn.getStdErrAsString().split(System.getProperty("line.separator")).length).isEqualTo(1); } - private void assertIsEntrypointErrorWithStacktrace(String errorMessage) { + private void assertIsEntryPointErrorWithStacktrace(String errorMessage) { assertThat(fn.exitStatus()).isEqualTo(2); assertThat(fn.getStdErrAsString()).contains(errorMessage); assertThat(fn.getStdErrAsString().split(System.getProperty("line.separator")).length).isGreaterThan(1); @@ -56,21 +56,21 @@ public void userSpecifiesMethodWhichDoesNotExist(){ public void userFunctionInputCoercionError(){ fn.givenEvent().withBody("This is not a...").enqueue(); fn.thenRun(ErrorMessages.OtherMethodsClass.class, "takesAnInteger"); - assertIsEntrypointErrorWithStacktrace("An exception was thrown during Input Coercion: Failed to coerce event to user function parameter type class java.lang.Integer"); + assertIsEntryPointErrorWithStacktrace("An exception was thrown during Input Coercion: Failed to coerce event to user function parameter type class java.lang.Integer"); } @Test public void objectConstructionThrowsARuntimeException(){ fn.givenEvent().enqueue(); fn.thenRun(StacktraceFilteringTestFunctions.ExceptionInConstructor.class, "invoke"); - assertIsEntrypointErrorWithStacktrace("Whoops"); + assertIsEntryPointErrorWithStacktrace("Whoops"); } @Test public void objectConstructionThrowsADeepException(){ fn.givenEvent().enqueue(); fn.thenRun(StacktraceFilteringTestFunctions.DeepExceptionInConstructor.class, "invoke"); - assertIsEntrypointErrorWithStacktrace("Inside a method called by the constructor"); + assertIsEntryPointErrorWithStacktrace("Inside a method called by the constructor"); assertThat(fn.getStdErrAsString()).contains("at not.in.com.fnproject.fn.StacktraceFilteringTestFunctions$DeepExceptionInConstructor.naughtyMethod"); assertThat(fn.getStdErrAsString()).contains("at not.in.com.fnproject.fn.StacktraceFilteringTestFunctions$DeepExceptionInConstructor."); } @@ -79,7 +79,7 @@ public void objectConstructionThrowsADeepException(){ public void objectConstructionThrowsANestedException(){ fn.givenEvent().enqueue(); fn.thenRun(StacktraceFilteringTestFunctions.NestedExceptionInConstructor.class, "invoke"); - assertIsEntrypointErrorWithStacktrace("Caused by: java.lang.RuntimeException: Oh no!"); + assertIsEntryPointErrorWithStacktrace("Caused by: java.lang.RuntimeException: Oh no!"); assertThat(fn.getStdErrAsString()).contains("at not.in.com.fnproject.fn.StacktraceFilteringTestFunctions$NestedExceptionInConstructor.naughtyMethod"); assertThat(fn.getStdErrAsString()).contains("Caused by: java.lang.ArithmeticException: / by zero"); assertThat(fn.getStdErrAsString()).contains("at not.in.com.fnproject.fn.StacktraceFilteringTestFunctions$NestedExceptionInConstructor.naughtyMethod"); @@ -90,14 +90,14 @@ public void objectConstructionThrowsANestedException(){ public void fnConfigurationThrowsARuntimeException(){ fn.givenEvent().enqueue(); fn.thenRun(StacktraceFilteringTestFunctions.ExceptionInConfiguration.class, "invoke"); - assertIsEntrypointErrorWithStacktrace("Caused by: java.lang.RuntimeException: Config fail"); + assertIsEntryPointErrorWithStacktrace("Caused by: java.lang.RuntimeException: Config fail"); } @Test public void fnConfigurationThrowsADeepException(){ fn.givenEvent().enqueue(); fn.thenRun(StacktraceFilteringTestFunctions.DeepExceptionInConfiguration.class, "invoke"); - assertIsEntrypointErrorWithStacktrace("Caused by: java.lang.RuntimeException: Deep config fail"); + assertIsEntryPointErrorWithStacktrace("Caused by: java.lang.RuntimeException: Deep config fail"); assertThat(fn.getStdErrAsString()).contains("at not.in.com.fnproject.fn.StacktraceFilteringTestFunctions$DeepExceptionInConfiguration.throwDeep"); assertThat(fn.getStdErrAsString()).contains("at not.in.com.fnproject.fn.StacktraceFilteringTestFunctions$DeepExceptionInConfiguration.config"); } @@ -106,7 +106,7 @@ public void fnConfigurationThrowsADeepException(){ public void fnConfigurationThrowsANestedException(){ fn.givenEvent().enqueue(); fn.thenRun(StacktraceFilteringTestFunctions.NestedExceptionInConfiguration.class, "invoke"); - assertIsEntrypointErrorWithStacktrace("Error invoking configuration method: config"); + assertIsEntryPointErrorWithStacktrace("Error invoking configuration method: config"); assertThat(fn.getStdErrAsString()).contains("Caused by: java.lang.RuntimeException: nested at 3"); assertThat(fn.getStdErrAsString()).contains("Caused by: java.lang.RuntimeException: nested at 2"); assertThat(fn.getStdErrAsString()).contains("Caused by: java.lang.RuntimeException: nested at 1"); diff --git a/runtime/src/test/java/com/fnproject/fn/runtime/FnTestHarness.java b/runtime/src/test/java/com/fnproject/fn/runtime/FnTestHarness.java index e6dd0644..6c5561b6 100644 --- a/runtime/src/test/java/com/fnproject/fn/runtime/FnTestHarness.java +++ b/runtime/src/test/java/com/fnproject/fn/runtime/FnTestHarness.java @@ -18,9 +18,9 @@ * Function internal testing harness - this provides access the call-side of the functions contract excluding the codec which is mocked */ public class FnTestHarness implements TestRule { - private List pendingInput = Collections.synchronizedList(new ArrayList<>()); - private List output = Collections.synchronizedList(new ArrayList<>()); - private ByteArrayOutputStream stdErr = new ByteArrayOutputStream(); + private final List pendingInput = Collections.synchronizedList(new ArrayList<>()); + private final List output = Collections.synchronizedList(new ArrayList<>()); + private final ByteArrayOutputStream stdErr = new ByteArrayOutputStream(); private int exitStatus = -1; private final Map config = new HashMap<>(); @@ -188,7 +188,7 @@ public byte[] getBody() { @Override public String toString() { - final StringBuffer sb = new StringBuffer("TestOutput{"); + final StringBuilder sb = new StringBuilder("TestOutput{"); sb.append("body="); if (body == null) sb.append("null"); else { diff --git a/runtime/src/test/java/com/fnproject/fn/runtime/HTTPStreamCodecTest.java b/runtime/src/test/java/com/fnproject/fn/runtime/HTTPStreamCodecTest.java index ca933b56..2b3c07ed 100644 --- a/runtime/src/test/java/com/fnproject/fn/runtime/HTTPStreamCodecTest.java +++ b/runtime/src/test/java/com/fnproject/fn/runtime/HTTPStreamCodecTest.java @@ -40,19 +40,19 @@ public class HTTPStreamCodecTest { @Rule - public final Timeout to = new Timeout(60, TimeUnit.SECONDS); + public final Timeout to = Timeout.builder().withTimeout(60, TimeUnit.SECONDS).withLookingForStuckThread(true).build(); private static final Map defaultEnv; private final List cleanups = new ArrayList<>(); private static File generateSocketFile() { - File f = null; + File f ; try { - f = File.createTempFile("socket", ".sock"); f.delete(); f.deleteOnExit(); } catch (IOException e) { + throw new RuntimeException("Error creating socket file",e); } return f; @@ -103,7 +103,7 @@ public void cleanup() throws Exception { } - public File startCodec(Map env, EventCodec.Handler h) { + File startCodec(Map env, EventCodec.Handler h) { Map newEnv = new HashMap<>(env); File socket = generateSocketFile(); newEnv.put("FN_LISTENER", "unix:" + socket.getAbsolutePath()); @@ -148,7 +148,7 @@ public void shouldAcceptDataOnHttp() throws Exception { InputEvent evt = lastEvent.get(1, TimeUnit.MILLISECONDS); assertThat(evt.getCallID()).isEqualTo("callID"); assertThat(evt.getDeadline().toEpochMilli()).isEqualTo(1033552800992L); - assertThat(evt.getHeaders()).isEqualTo(Headers.emptyHeaders().addHeader("Fn-Call-Id", "callID").addHeader("Fn-Deadline", "2002-10-02T10:00:00.992Z").addHeader("Custom-header", "v1", "v2").addHeader("Content-Type", "text/plain").addHeader("Content-Length","6")); + assertThat(evt.getHeaders()).isEqualTo(Headers.emptyHeaders().addHeader("Fn-Call-Id", "callID").addHeader("Fn-Deadline", "2002-10-02T10:00:00.992Z").addHeader("Custom-header", "v1", "v2").addHeader("Content-Type", "text/plain").addHeader("Content-Length", "6")); } @@ -180,6 +180,7 @@ public void shouldRejectFnMissingHeaders() throws Exception { ContentResponse resp = r.send(); + assertThat(resp.getStatus()).withFailMessage("Expected failure error code for missing header " + h).isEqualTo(500); } @@ -249,9 +250,7 @@ public void shouldHandleLargeBodies() throws Exception { MessageDigest readDigest = MessageDigest.getInstance("SHA-256"); defaultRequest(client) .content(new BytesContentProvider(randomString)) - .onResponseContent((response, byteBuffer) -> { - readDigest.update(byteBuffer); - }) + .onResponseContent((response, byteBuffer) -> readDigest.update(byteBuffer)) .send(cdl::complete); Result r = cdl.get(); assertThat(r.getResponse().getStatus()).isEqualTo(200); @@ -260,9 +259,14 @@ public void shouldHandleLargeBodies() throws Exception { private byte[] randomBytes(int sz) { Random sr = new Random(); - byte[] part = new byte[1024]; + byte[] part = new byte[997]; sr.nextBytes(part); + // Make random ascii for convenience in debugging + for(int i = 0 ; i < part.length; i++){ + part[i] = (byte)((part[i]%26) + 65); + } + byte[] randomString = new byte[sz]; int left = sz; for (int i = 0; i < randomString.length; i += part.length) { @@ -290,9 +294,7 @@ public void shouldConvertStatusResponses() throws Exception { ContentResponse resp = defaultRequest(client).send(); assertThat(resp.getStatus()).isEqualTo(s.getCode()); - } - } @Test @@ -319,7 +321,6 @@ public void shouldStripHopToHopHeadersFromFunctionInput() throws Exception { @Test public void socketShouldHaveCorrectPermissions() throws Exception { File listener = startCodec(defaultEnv, (in) -> OutputEvent.fromBytes("hello".getBytes(), OutputEvent.Status.Success, "text/plain", Headers.emptyHeaders())); - assertThat(Files.getPosixFilePermissions(listener.toPath())).isEqualTo(PosixFilePermissions.fromString("rw-rw-rw-")); cleanup(); diff --git a/runtime/src/test/java/com/fnproject/fn/runtime/HttpEventCodecTest.java b/runtime/src/test/java/com/fnproject/fn/runtime/HttpEventCodecTest.java index 7163caf6..70312a14 100644 --- a/runtime/src/test/java/com/fnproject/fn/runtime/HttpEventCodecTest.java +++ b/runtime/src/test/java/com/fnproject/fn/runtime/HttpEventCodecTest.java @@ -50,7 +50,7 @@ public class HttpEventCodecTest { private final Map emptyConfig = new HashMap<>(); - private final Map env() { + private Map env() { HashMap env = new HashMap<>(); env.put("FN_APP_NAME", "testapp"); env.put("FN_PATH", "/test"); diff --git a/runtime/src/test/java/com/fnproject/fn/runtime/MethodWrapperTests.java b/runtime/src/test/java/com/fnproject/fn/runtime/MethodWrapperTests.java index 37218dec..7f8341ad 100644 --- a/runtime/src/test/java/com/fnproject/fn/runtime/MethodWrapperTests.java +++ b/runtime/src/test/java/com/fnproject/fn/runtime/MethodWrapperTests.java @@ -69,20 +69,20 @@ public static Collection data() throws Exception { } static class ConcreteTypeExamples { - public void voidReturnType() { }; - public void singleParameter(String s) { }; - public void singlePrimitiveParameter(boolean i) { }; - public void singlePrimitiveParameter(byte i) { }; - public void singlePrimitiveParameter(char i) { }; - public void singlePrimitiveParameter(short i) { }; - public void singlePrimitiveParameter(int i) { }; - public void singlePrimitiveParameter(long i) { }; - public void singlePrimitiveParameter(float i) { }; - public void singlePrimitiveParameter(double i) { }; - public void multipleParameters(String s, double i) { }; - public String noArgs() { return ""; }; - public int noArgsWithPrimitiveReturnType() { return 1; }; - public void singleGenericParameter(List s) { }; + public void voidReturnType() { } + public void singleParameter(String s) { } + public void singlePrimitiveParameter(boolean i) { } + public void singlePrimitiveParameter(byte i) { } + public void singlePrimitiveParameter(char i) { } + public void singlePrimitiveParameter(short i) { } + public void singlePrimitiveParameter(int i) { } + public void singlePrimitiveParameter(long i) { } + public void singlePrimitiveParameter(float i) { } + public void singlePrimitiveParameter(double i) { } + public void multipleParameters(String s, double i) { } + public String noArgs() { return ""; } + public int noArgsWithPrimitiveReturnType() { return 1; } + public void singleGenericParameter(List s) { } } static class ParentClassWithGenericType { diff --git a/runtime/src/test/java/com/fnproject/fn/runtime/QueryParametersParserTest.java b/runtime/src/test/java/com/fnproject/fn/runtime/QueryParametersParserTest.java index b799d451..72d39463 100644 --- a/runtime/src/test/java/com/fnproject/fn/runtime/QueryParametersParserTest.java +++ b/runtime/src/test/java/com/fnproject/fn/runtime/QueryParametersParserTest.java @@ -21,7 +21,7 @@ public void noUrlParametersProducesEmptyMap() { } @Test - public void gettingNonExistantParameterProducesOptionalEmpty() { + public void gettingNonExistentParameterProducesOptionalEmpty() { QueryParameters params = QueryParametersParser.getParams("www.example.com"); assertThat(params.getValues("var")).isEmpty(); diff --git a/runtime/src/test/java/com/fnproject/fn/runtime/ntv/UnixSocketNativeTest.java b/runtime/src/test/java/com/fnproject/fn/runtime/ntv/UnixSocketNativeTest.java index a98d1202..436da667 100644 --- a/runtime/src/test/java/com/fnproject/fn/runtime/ntv/UnixSocketNativeTest.java +++ b/runtime/src/test/java/com/fnproject/fn/runtime/ntv/UnixSocketNativeTest.java @@ -143,10 +143,7 @@ public void shouldHandleConnectAccept() throws Exception { UnixSocketNative.listen(ss, 1); ready.countDown(); int cs = UnixSocketNative.accept(ss, 0); - if (cs > 0) { - return true; - } - return false; + return cs > 0; } finally { UnixSocketNative.close(ss); } diff --git a/runtime/src/test/java/com/fnproject/fn/runtime/testfns/CustomDataBindingFnWithNoUserCoersions.java b/runtime/src/test/java/com/fnproject/fn/runtime/testfns/CustomDataBindingFnWithNoUserCoercions.java similarity index 83% rename from runtime/src/test/java/com/fnproject/fn/runtime/testfns/CustomDataBindingFnWithNoUserCoersions.java rename to runtime/src/test/java/com/fnproject/fn/runtime/testfns/CustomDataBindingFnWithNoUserCoercions.java index e94b28c6..6902cdf0 100644 --- a/runtime/src/test/java/com/fnproject/fn/runtime/testfns/CustomDataBindingFnWithNoUserCoersions.java +++ b/runtime/src/test/java/com/fnproject/fn/runtime/testfns/CustomDataBindingFnWithNoUserCoercions.java @@ -3,7 +3,7 @@ import com.fnproject.fn.api.FnConfiguration; import com.fnproject.fn.api.RuntimeContext; -public class CustomDataBindingFnWithNoUserCoersions { +public class CustomDataBindingFnWithNoUserCoercions { @FnConfiguration public static void inputConfig(RuntimeContext ctx){ diff --git a/runtime/src/test/java/com/fnproject/fn/runtime/testfns/TestFn.java b/runtime/src/test/java/com/fnproject/fn/runtime/testfns/TestFn.java index ecdbb92a..306bce2e 100644 --- a/runtime/src/test/java/com/fnproject/fn/runtime/testfns/TestFn.java +++ b/runtime/src/test/java/com/fnproject/fn/runtime/testfns/TestFn.java @@ -131,7 +131,7 @@ public static List fnGenericAnimal() { * Reset the internal (static) state * Should be called between runs; */ - public static final void reset() { + public static void reset() { input = NOTHING; output = NOTHING; count = 0; diff --git a/runtime/src/test/java/com/fnproject/fn/runtime/testfns/coercions/StringUpperCaseCoercion.java b/runtime/src/test/java/com/fnproject/fn/runtime/testfns/coercions/StringUpperCaseCoercion.java index 809c5ed1..3ac217fd 100644 --- a/runtime/src/test/java/com/fnproject/fn/runtime/testfns/coercions/StringUpperCaseCoercion.java +++ b/runtime/src/test/java/com/fnproject/fn/runtime/testfns/coercions/StringUpperCaseCoercion.java @@ -14,7 +14,7 @@ public Optional tryCoerceParam(InvocationContext currentContext, int arg return Optional.of( input.consumeBody(is -> { try { - return new StringBuffer(IOUtils.toString(is, StandardCharsets.UTF_8)).toString().toUpperCase(); + return IOUtils.toString(is, StandardCharsets.UTF_8).toUpperCase(); } catch (IOException e) { return null; // Tests will fail if we end up here } @@ -26,8 +26,8 @@ public Optional tryCoerceParam(InvocationContext currentContext, int arg public Optional wrapFunctionResult(InvocationContext ctx, MethodWrapper method, Object value) { if (ctx.getRuntimeContext().getMethod().getTargetMethod().getReturnType().equals(String.class)) { try { - String capitilisedOutput = new StringBuffer((String) value).toString().toUpperCase(); - return Optional.of(OutputEvent.fromBytes(capitilisedOutput.getBytes(), OutputEvent.Status.Success, "text/plain")); + String capitalizedOutput = ((String) value).toUpperCase(); + return Optional.of(OutputEvent.fromBytes(capitalizedOutput.getBytes(), OutputEvent.Status.Success, "text/plain")); } catch (ClassCastException e) { return Optional.empty(); } From b3d5d57715293c5907768b62e5776845e90cd378 Mon Sep 17 00:00:00 2001 From: CI Date: Wed, 26 Sep 2018 15:37:29 +0000 Subject: [PATCH 047/310] fn-java-fdk: post-1.0.68 version bump [skip ci] --- release.version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/release.version b/release.version index 01c08cf3..31160872 100644 --- a/release.version +++ b/release.version @@ -1 +1 @@ -1.0.68 +1.0.69 From 3dbcbc7f30346beeb0a5e79e4d2f5f1eb99d5633 Mon Sep 17 00:00:00 2001 From: Owen Cliffe Date: Wed, 26 Sep 2018 17:04:31 +0100 Subject: [PATCH 048/310] trying new delpoyment setting --- .circleci/release.sh | 1 + 1 file changed, 1 insertion(+) diff --git a/.circleci/release.sh b/.circleci/release.sh index f4a3983e..867010b9 100755 --- a/.circleci/release.sh +++ b/.circleci/release.sh @@ -33,6 +33,7 @@ fi mvn -s ./settings-deploy.xml \ -DskipTests \ -DaltDeploymentRepository="fnproject-release-repo::default::$MVN_RELEASE_REPO" \ + -DaltReleaseDeploymentRepository="fnproject-release-repo::default::$MVN_RELEASE_REPO" \ -Dfnproject-release-repo.username="$MVN_RELEASE_USER" \ -Dfnproject-release-repo.password="$MVN_RELEASE_PASSWORD" \ -DdeployAtEnd=true \ From 06cfe9dceb4c074b4862a84f56e887c3085aae3b Mon Sep 17 00:00:00 2001 From: CI Date: Wed, 26 Sep 2018 16:26:37 +0000 Subject: [PATCH 049/310] fn-java-fdk: post-1.0.69 version bump [skip ci] --- release.version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/release.version b/release.version index 31160872..9d8637ce 100644 --- a/release.version +++ b/release.version @@ -1 +1 @@ -1.0.69 +1.0.70 From d2850feabe98c440fbd2dcb276a19f54e17a1c44 Mon Sep 17 00:00:00 2001 From: Richard Connon Date: Wed, 26 Sep 2018 17:52:18 +0100 Subject: [PATCH 050/310] Try another new deployment setting (#158) --- .circleci/release.sh | 2 -- 1 file changed, 2 deletions(-) diff --git a/.circleci/release.sh b/.circleci/release.sh index 867010b9..2ba6b2d2 100755 --- a/.circleci/release.sh +++ b/.circleci/release.sh @@ -33,10 +33,8 @@ fi mvn -s ./settings-deploy.xml \ -DskipTests \ -DaltDeploymentRepository="fnproject-release-repo::default::$MVN_RELEASE_REPO" \ - -DaltReleaseDeploymentRepository="fnproject-release-repo::default::$MVN_RELEASE_REPO" \ -Dfnproject-release-repo.username="$MVN_RELEASE_USER" \ -Dfnproject-release-repo.password="$MVN_RELEASE_PASSWORD" \ - -DdeployAtEnd=true \ clean deploy From fa2087c0d9a1bc48c5a43e4b3681f0666bc2c55d Mon Sep 17 00:00:00 2001 From: CI Date: Wed, 26 Sep 2018 17:03:37 +0000 Subject: [PATCH 051/310] fn-java-fdk: post-1.0.70 version bump [skip ci] --- release.version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/release.version b/release.version index 9d8637ce..1edd0625 100644 --- a/release.version +++ b/release.version @@ -1 +1 @@ -1.0.70 +1.0.71 From b41e4a6e002d4527b92694888d5a755d49cb9004 Mon Sep 17 00:00:00 2001 From: Owen Cliffe Date: Thu, 4 Oct 2018 22:12:42 +0100 Subject: [PATCH 052/310] make FnFeature multi-valued remove use of getAnnotationsByType (#160) --- api/src/main/api/snapshot.sigfile | 14 ++++++ .../java/com/fnproject/fn/api/FnFeature.java | 6 +-- .../java/com/fnproject/fn/api/FnFeatures.java | 17 +++++++ .../com/fnproject/fn/runtime/EntryPoint.java | 49 +++++++++++-------- .../fnproject/fn/testing/FnTestingRule.java | 5 +- 5 files changed, 63 insertions(+), 28 deletions(-) create mode 100644 api/src/main/java/com/fnproject/fn/api/FnFeatures.java diff --git a/api/src/main/api/snapshot.sigfile b/api/src/main/api/snapshot.sigfile index d9794397..67479c47 100644 --- a/api/src/main/api/snapshot.sigfile +++ b/api/src/main/api/snapshot.sigfile @@ -7,11 +7,18 @@ CLSS public abstract interface !annotation com.fnproject.fn.api.FnConfiguration intf java.lang.annotation.Annotation CLSS public abstract interface !annotation com.fnproject.fn.api.FnFeature + anno 0 java.lang.annotation.Repeatable(java.lang.Class value=class com.fnproject.fn.api.FnFeatures) anno 0 java.lang.annotation.Retention(java.lang.annotation.RetentionPolicy value=RUNTIME) anno 0 java.lang.annotation.Target(java.lang.annotation.ElementType[] value=[TYPE]) intf java.lang.annotation.Annotation meth public abstract java.lang.Class value() +CLSS public abstract interface !annotation com.fnproject.fn.api.FnFeatures + anno 0 java.lang.annotation.Retention(java.lang.annotation.RetentionPolicy value=RUNTIME) + anno 0 java.lang.annotation.Target(java.lang.annotation.ElementType[] value=[TYPE]) +intf java.lang.annotation.Annotation +meth public abstract com.fnproject.fn.api.FnFeature[] value() + CLSS public abstract interface com.fnproject.fn.api.FunctionInvoker innr public final static !enum Phase meth public abstract java.util.Optional tryInvoke(com.fnproject.fn.api.InvocationContext,com.fnproject.fn.api.InputEvent) @@ -260,6 +267,13 @@ CLSS public abstract interface !annotation java.lang.annotation.Documented anno 0 java.lang.annotation.Target(java.lang.annotation.ElementType[] value=[ANNOTATION_TYPE]) intf java.lang.annotation.Annotation +CLSS public abstract interface !annotation java.lang.annotation.Repeatable + anno 0 java.lang.annotation.Documented() + anno 0 java.lang.annotation.Retention(java.lang.annotation.RetentionPolicy value=RUNTIME) + anno 0 java.lang.annotation.Target(java.lang.annotation.ElementType[] value=[ANNOTATION_TYPE]) +intf java.lang.annotation.Annotation +meth public abstract java.lang.Class value() + CLSS public abstract interface !annotation java.lang.annotation.Retention anno 0 java.lang.annotation.Documented() anno 0 java.lang.annotation.Retention(java.lang.annotation.RetentionPolicy value=RUNTIME) diff --git a/api/src/main/java/com/fnproject/fn/api/FnFeature.java b/api/src/main/java/com/fnproject/fn/api/FnFeature.java index 9d2e886d..83f9dd77 100644 --- a/api/src/main/java/com/fnproject/fn/api/FnFeature.java +++ b/api/src/main/java/com/fnproject/fn/api/FnFeature.java @@ -1,9 +1,6 @@ package com.fnproject.fn.api; -import java.lang.annotation.ElementType; -import java.lang.annotation.Retention; -import java.lang.annotation.RetentionPolicy; -import java.lang.annotation.Target; +import java.lang.annotation.*; /** * Annotation to be used in user function classes to enable runtime-wide feature. @@ -12,6 +9,7 @@ */ @Retention(RetentionPolicy.RUNTIME) @Target(ElementType.TYPE) +@Repeatable(FnFeatures.class) public @interface FnFeature { /** * The feature class to load this must have a zero-arg public constructor diff --git a/api/src/main/java/com/fnproject/fn/api/FnFeatures.java b/api/src/main/java/com/fnproject/fn/api/FnFeatures.java new file mode 100644 index 00000000..3db2a4dc --- /dev/null +++ b/api/src/main/java/com/fnproject/fn/api/FnFeatures.java @@ -0,0 +1,17 @@ +package com.fnproject.fn.api; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +/** + * Annotation to be used in user function classes to enable runtime-wide feature. + * + * Runtime features are initialized at the point that the function class is loaded but prior to the call chain. + */ +@Retention(RetentionPolicy.RUNTIME) +@Target(ElementType.TYPE) +public @interface FnFeatures { + FnFeature[] value(); +} diff --git a/runtime/src/main/java/com/fnproject/fn/runtime/EntryPoint.java b/runtime/src/main/java/com/fnproject/fn/runtime/EntryPoint.java index 8e357d2d..c146c913 100644 --- a/runtime/src/main/java/com/fnproject/fn/runtime/EntryPoint.java +++ b/runtime/src/main/java/com/fnproject/fn/runtime/EntryPoint.java @@ -48,10 +48,10 @@ public static void main(String... args) throws Exception { /** * Entry point runner - this executes the whole lifecycle of the fn Java FDK runtime - including multiple invocations in the function for hot functions * - * @param env the map of environment variables to run the function with (typically System.getenv but may be customised for testing) - * @param codec the codec to run the function with - * @param loggingOutput the stream to send function error/logging to - this will be wrapped into System.err within the funciton - * @param args any further args passed to the entry point - specifically the class/method name + * @param env the map of environment variables to run the function with (typically System.getenv but may be customised for testing) + * @param codec the codec to run the function with + * @param loggingOutput the stream to send function error/logging to - this will be wrapped into System.err within the funciton + * @param args any further args passed to the entry point - specifically the class/method name * @return the desired process exit status */ public int run(Map env, EventCodec codec, PrintStream loggingOutput, String... args) { @@ -74,28 +74,19 @@ public int run(Map env, EventCodec codec, PrintStream loggingOut FunctionLoader functionLoader = new FunctionLoader(); - MethodWrapper method = functionLoader.loadClass(cls, mth); FunctionRuntimeContext runtimeContext = new FunctionRuntimeContext(method, configFromEnvVars); - - FnFeature[] features = method.getTargetClass().getAnnotationsByType(FnFeature.class); - for (FnFeature f : features) { - RuntimeFeature rf; - try { - Class featureClass = f.value(); - rf = featureClass.newInstance(); - } catch (Exception e) { - throw new FunctionInitializationException("Could not load feature class " + f.value().toString(), e); - } - - try { - rf.initialize(runtimeContext); - } catch (Exception e) { - throw new FunctionInitializationException("Exception while calling initialization on runtime feature " + f.value(), e); + FnFeature f = method.getTargetClass().getAnnotation(FnFeature.class); + if (f != null) { + enableFeature(runtimeContext, f); + } + FnFeatures fs = method.getTargetClass().getAnnotation(FnFeatures.class); + if (fs != null) { + for (FnFeature fnFeature : fs.value()) { + enableFeature(runtimeContext,fnFeature); } } - FunctionConfigurer functionConfigurer = new FunctionConfigurer(); functionConfigurer.configure(runtimeContext); @@ -149,6 +140,22 @@ public int run(Map env, EventCodec codec, PrintStream loggingOut return lastStatus.get(); } + private void enableFeature(FunctionRuntimeContext runtimeContext, FnFeature f) { + RuntimeFeature rf; + try { + Class featureClass = f.value(); + rf = featureClass.newInstance(); + } catch (Exception e) { + throw new FunctionInitializationException("Could not load feature class " + f.value().toString(), e); + } + + try { + rf.initialize(runtimeContext); + } catch (Exception e) { + throw new FunctionInitializationException("Exception while calling initialization on runtime feature " + f.value(), e); + } + } + /** * Produces a string representation of the supplied Throwable. diff --git a/testing-junit4/src/main/java/com/fnproject/fn/testing/FnTestingRule.java b/testing-junit4/src/main/java/com/fnproject/fn/testing/FnTestingRule.java index 4e5932de..367cf5be 100644 --- a/testing-junit4/src/main/java/com/fnproject/fn/testing/FnTestingRule.java +++ b/testing-junit4/src/main/java/com/fnproject/fn/testing/FnTestingRule.java @@ -1,9 +1,7 @@ package com.fnproject.fn.testing; import com.fasterxml.jackson.databind.ObjectMapper; -import com.fnproject.fn.api.Headers; -import com.fnproject.fn.api.InputEvent; -import com.fnproject.fn.api.OutputEvent; +import com.fnproject.fn.api.*; import com.fnproject.fn.runtime.EventCodec; import org.apache.commons.io.output.TeeOutputStream; import org.junit.Rule; @@ -79,6 +77,7 @@ public final class FnTestingRule implements TestRule { addSharedClass(EventCodec.Handler.class); + } /** From 2978cd45eb08a1dd82d063bc79d8b36b90b8ff93 Mon Sep 17 00:00:00 2001 From: CI Date: Thu, 4 Oct 2018 21:24:32 +0000 Subject: [PATCH 053/310] fn-java-fdk: post-1.0.71 version bump [skip ci] --- release.version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/release.version b/release.version index 1edd0625..eea6f62c 100644 --- a/release.version +++ b/release.version @@ -1 +1 @@ -1.0.71 +1.0.72 From 6a56da61b8734e3964a00ee663ac6fcc66aa3d87 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tom=C3=A1=C5=A1=20Zezula?= Date: Thu, 4 Oct 2018 23:29:17 +0200 Subject: [PATCH 054/310] Build and Init Images for substrate VM This adds a a build and init image that builds functions using substrateVM as consolidated binaries. --- build.sh | 18 +++++ native-image/Dockerfile | 44 ++++++++++++ native-image/docker-build.sh | 6 ++ native-image/init-image/Dockerfile | 29 ++++++++ native-image/init-image/Dockerfile-init-image | 25 +++++++ native-image/init-image/docker-build.sh | 8 +++ native-image/init-image/func.init.yaml | 2 + native-image/init-image/pom.xml | 72 +++++++++++++++++++ .../init-image/src/main/conf/reflection.json | 10 +++ .../java/com/example/fn/HelloFunction.java | 11 +++ .../com/example/fn/HelloFunctionTest.java | 22 ++++++ 11 files changed, 247 insertions(+) create mode 100644 native-image/Dockerfile create mode 100755 native-image/docker-build.sh create mode 100644 native-image/init-image/Dockerfile create mode 100644 native-image/init-image/Dockerfile-init-image create mode 100755 native-image/init-image/docker-build.sh create mode 100644 native-image/init-image/func.init.yaml create mode 100644 native-image/init-image/pom.xml create mode 100644 native-image/init-image/src/main/conf/reflection.json create mode 100644 native-image/init-image/src/main/java/com/example/fn/HelloFunction.java create mode 100644 native-image/init-image/src/test/java/com/example/fn/HelloFunctionTest.java diff --git a/build.sh b/build.sh index 466efad9..a057210f 100755 --- a/build.sh +++ b/build.sh @@ -8,6 +8,16 @@ rm -rf /tmp/staging_repo/* BUILD_VERSION=${FN_FDK_VERSION:-1.0.0-SNAPSHOT} export REPOSITORY_LOCATION=${REPOSITORY_LOCATION:-/tmp/staging_repo} +while [ $# -ne 0 ] +do + case "$1" in + --build-native-java) + BUILD_NATIVE_JAVA=true + ;; + esac + shift +done + ( runtime/src/main/c/rebuild_so.sh ) @@ -33,3 +43,11 @@ mvn -B deploy -DaltDeploymentRepository=localStagingDir::default::file://${REP cd runtime docker build -f Dockerfile-jdk9 -t fnproject/fn-java-fdk:jdk9-${BUILD_VERSION} . ) + +if [ "${BUILD_NATIVE_JAVA}" = true ] + then + ( + cd native-image + ./docker-build.sh + ) +fi diff --git a/native-image/Dockerfile b/native-image/Dockerfile new file mode 100644 index 00000000..6384bb00 --- /dev/null +++ b/native-image/Dockerfile @@ -0,0 +1,44 @@ +FROM openjdk:8-jdk-slim as build +LABEL maintainer="tomas.zezula@oracle.com" + +RUN set -x \ + && apt-get -y update \ + && apt-get -y install gcc g++ git make openjdk-8-doc openjdk-8-source python zlib1g-dev \ + && rm -rf /var/lib/apt/lists/* + +ENV JVMCI_VERSION 0.47 + +WORKDIR /build + +RUN set -x \ + && git clone https://github.com/graalvm/mx.git \ + && git clone https://github.com/graalvm/graal-jvmci-8.git \ + && git -C graal-jvmci-8 checkout jvmci-${JVMCI_VERSION} \ + && mx/mx --primary-suite graal-jvmci-8 --vm=server build -DFULL_DEBUG_SYMBOLS=0 \ + && mx/mx --primary-suite graal-jvmci-8 --vm=server -v vm -version \ + && mx/mx --primary-suite graal-jvmci-8 --vm=server -v unittest \ + && cp -r $(/build/mx/mx --primary-suite graal-jvmci-8 jdkhome) /build/jvmcijdk8 + +RUN git clone https://github.com/oracle/graal.git \ + && git -C graal checkout dca98069dc57c458b8bcb3392cf9e66316dd37b6 +WORKDIR /build/graal/vm +RUN export JAVA_HOME=/build/jvmcijdk8 \ + && /build/mx/mx --dy /substratevm --force-bash-launchers=true --disable-polyglot --disable-libpolyglot build + +WORKDIR /build/graal/vm/latest_graalvm +RUN LONG_NAME=$(ls) \ + && SHORT_NAME=graalvm \ + && mv $LONG_NAME $SHORT_NAME + +FROM debian:stretch-slim as final +LABEL maintainer="tomas.zezula@oracle.com" + +RUN set -x \ + && apt-get -y update \ + && apt-get -y install gcc zlib1g-dev + +COPY --from=build /build/graal/vm/latest_graalvm/graalvm /usr/local/graalvm + + +ENV GRAALVM_HOME=/usr/local/graalvm +WORKDIR /function diff --git a/native-image/docker-build.sh b/native-image/docker-build.sh new file mode 100755 index 00000000..11ae75dd --- /dev/null +++ b/native-image/docker-build.sh @@ -0,0 +1,6 @@ +#!/bin/sh +docker build -t "fnproject/fn-java-native:latest" . +( + cd init-image + ./docker-build.sh +) diff --git a/native-image/init-image/Dockerfile b/native-image/init-image/Dockerfile new file mode 100644 index 00000000..5f3f22bd --- /dev/null +++ b/native-image/init-image/Dockerfile @@ -0,0 +1,29 @@ +FROM fnproject/fn-java-fdk-build:latest as build +LABEL maintainer="tomas.zezula@oracle.com" +WORKDIR /function +ENV MAVEN_OPTS=-Dmaven.repo.local=/usr/share/maven/ref/repository +ADD pom.xml pom.xml +RUN ["mvn", "package", "dependency:copy-dependencies", "-DincludeScope=runtime", "-DskipTests=true", "-Dmdep.prependGroupId=true", "-DoutputDirectory=target", "--fail-never"] +ADD src src +RUN ["mvn", "package"] + +FROM fnproject/fn-java-native:latest as build-native-image +LABEL maintainer="tomas.zezula@oracle.com" +WORKDIR /function +COPY --from=build /function/target/*.jar target/ +COPY --from=build /function/src/main/conf/reflection.json reflection.json +RUN /usr/local/graalvm/bin/native-image \ + --static \ + -H:Name=func \ + -H:+ReportUnsupportedElementsAtRuntime \ + -H:ReflectionConfigurationFiles=reflection.json \ + -classpath "target/*"\ + com.fnproject.fn.runtime.EntryPoint + + +FROM scratch +LABEL maintainer="tomas.zezula@oracle.com" +WORKDIR /function +COPY --from=build-native-image /function/func func +ENTRYPOINT ["./func", "-XX:MaximumHeapSizePercent=80"] +CMD [ "com.example.fn.HelloFunction::handleRequest" ] diff --git a/native-image/init-image/Dockerfile-init-image b/native-image/init-image/Dockerfile-init-image new file mode 100644 index 00000000..0850e955 --- /dev/null +++ b/native-image/init-image/Dockerfile-init-image @@ -0,0 +1,25 @@ +FROM alpine:latest +LABEL maintainer="tomas.zezula@oracle.com" + +WORKDIR /build +COPY src src +COPY pom.xml . +COPY func.init.yaml . +COPY Dockerfile . + +RUN echo $'#!/bin/sh\n\ +if [ -n ${FN_FUNCTION_NAME} ]\n\ + then\n\ + JAVA_NAME=$(echo ${FN_FUNCTION_NAME:0:1} | tr "[:lower:]" "[:upper:]")${FN_FUNCTION_NAME:1}\n\ + sed -i -e "s|hello|${FN_FUNCTION_NAME}|" pom.xml\n\ + sed -i -e "s|com.example.fn.HelloFunction|com.example.fn.${JAVA_NAME}|" Dockerfile\n\ + sed -i -e "s|com.example.fn.HelloFunction|com.example.fn.${JAVA_NAME}|" src/main/conf/reflection.json\n\ + sed -i -e "s|HelloFunction|${JAVA_NAME}|" src/main/java/com/example/fn/HelloFunction.java\n\ + mv src/main/java/com/example/fn/HelloFunction.java "src/main/java/com/example/fn/${JAVA_NAME}.java"\n\ + sed -i -e "s|HelloFunction|${JAVA_NAME}|" src/test/java/com/example/fn/HelloFunctionTest.java\n\ + mv src/test/java/com/example/fn/HelloFunctionTest.java "src/test/java/com/example/fn/${JAVA_NAME}Test.java"\n\ +fi\n\ +tar c src pom.xml func.init.yaml Dockerfile\n' > build_init_image.sh \ + && chmod 755 build_init_image.sh + +CMD ["./build_init_image.sh"] diff --git a/native-image/init-image/docker-build.sh b/native-image/init-image/docker-build.sh new file mode 100755 index 00000000..ced52457 --- /dev/null +++ b/native-image/init-image/docker-build.sh @@ -0,0 +1,8 @@ +#!/bin/sh +if [ -z "${release_version}" ] + then + release_version=$(cat ../../release.version) +fi +BUILD_VERSION=${FN_FDK_VERSION:-1.0.0-SNAPSHOT} +sed -i.bak -e "s|.*|${release_version}|" pom.xml && rm pom.xml.bak +docker build -t fnproject/fn-java-native-init:latest -f Dockerfile-init-image . diff --git a/native-image/init-image/func.init.yaml b/native-image/init-image/func.init.yaml new file mode 100644 index 00000000..86cc0c76 --- /dev/null +++ b/native-image/init-image/func.init.yaml @@ -0,0 +1,2 @@ +runtime: docker +format: http diff --git a/native-image/init-image/pom.xml b/native-image/init-image/pom.xml new file mode 100644 index 00000000..9bb5db9e --- /dev/null +++ b/native-image/init-image/pom.xml @@ -0,0 +1,72 @@ + + + 4.0.0 + + UTF-8 + 1.0.0-SNAPSHOT + + com.example.fn + hello + 1.0.0 + + + + fn-release-repo + https://dl.bintray.com/fnproject/fnproject + + true + + + false + + + + + + + com.fnproject.fn + api + ${fdk.version} + + + com.fnproject.fn + testing-core + ${fdk.version} + test + + + com.fnproject.fn + testing-junit4 + ${fdk.version} + test + + + junit + junit + 4.12 + test + + + com.fnproject.fn + runtime + ${fdk.version} + runtime + + + + + + + org.apache.maven.plugins + maven-compiler-plugin + 3.3 + + 1.8 + 1.8 + + + + + diff --git a/native-image/init-image/src/main/conf/reflection.json b/native-image/init-image/src/main/conf/reflection.json new file mode 100644 index 00000000..9110b519 --- /dev/null +++ b/native-image/init-image/src/main/conf/reflection.json @@ -0,0 +1,10 @@ + +[ + { + "name" : "com.example.fn.HelloFunction", + "methods" : [ + { "name" : "handleRequest" }, + { "name" : ""} + ] + } +] diff --git a/native-image/init-image/src/main/java/com/example/fn/HelloFunction.java b/native-image/init-image/src/main/java/com/example/fn/HelloFunction.java new file mode 100644 index 00000000..8c581e76 --- /dev/null +++ b/native-image/init-image/src/main/java/com/example/fn/HelloFunction.java @@ -0,0 +1,11 @@ +package com.example.fn; + +public class HelloFunction { + + public String handleRequest(String input) { + String name = (input == null || input.isEmpty()) ? "world" : input; + + return "Hello, " + name + "!"; + } + +} \ No newline at end of file diff --git a/native-image/init-image/src/test/java/com/example/fn/HelloFunctionTest.java b/native-image/init-image/src/test/java/com/example/fn/HelloFunctionTest.java new file mode 100644 index 00000000..e6b7a5e3 --- /dev/null +++ b/native-image/init-image/src/test/java/com/example/fn/HelloFunctionTest.java @@ -0,0 +1,22 @@ +package com.example.fn; + +import com.fnproject.fn.testing.*; +import org.junit.*; + +import static org.junit.Assert.*; + +public class HelloFunctionTest { + + @Rule + public final FnTestingRule testing = FnTestingRule.createDefault(); + + @Test + public void shouldReturnGreeting() { + testing.givenEvent().enqueue(); + testing.thenRun(HelloFunction.class, "handleRequest"); + + FnResult result = testing.getOnlyResult(); + assertEquals("Hello, world!", result.getBodyAsString()); + } + +} \ No newline at end of file From 58b67d79f95bb2d467c6c3f91d22f2932147609a Mon Sep 17 00:00:00 2001 From: CI Date: Thu, 4 Oct 2018 21:39:58 +0000 Subject: [PATCH 055/310] fn-java-fdk: post-1.0.72 version bump [skip ci] --- release.version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/release.version b/release.version index eea6f62c..be1dcc8a 100644 --- a/release.version +++ b/release.version @@ -1 +1 @@ -1.0.72 +1.0.73 From c4c141d4c0214bb99bd96a22dd97ebbb26c48235 Mon Sep 17 00:00:00 2001 From: Owen Cliffe Date: Mon, 8 Oct 2018 23:32:59 +0100 Subject: [PATCH 056/310] CI/Release of substrate related images (#161) * first cut at substrate images * fix docker build --- .circleci/release.sh | 74 ++++++++++++------- build.sh | 23 +++--- .../build-native}/Dockerfile | 0 images/build-native/README.md | 5 ++ images/build-native/docker-build.sh | 12 +++ images/build-native/native.version | 1 + {build-image => images/build}/Dockerfile | 0 {build-image => images/build}/Dockerfile-jdk9 | 0 {build-image => images/build}/cache-deps.sh | 0 {build-image => images/build}/docker-build.sh | 0 {build-image => images/build}/pom.xml | 0 .../java/com/example/fn/HelloFunction.java | 0 .../com/example/fn/HelloFunctionTest.java | 0 .../init-native}/Dockerfile | 0 .../init-native}/Dockerfile-init-image | 0 images/init-native/README.md | 2 + images/init-native/docker-build.sh | 6 ++ .../init-native}/func.init.yaml | 0 .../init-image => images/init-native}/pom.xml | 0 .../src/main/conf/reflection.json | 0 .../java/com/example/fn/HelloFunction.java | 0 .../com/example/fn/HelloFunctionTest.java | 0 {runtime => images/runtime}/Dockerfile | 0 {runtime => images/runtime}/Dockerfile-jdk9 | 0 images/runtime/README.md | 3 + native-image/docker-build.sh | 6 -- native-image/init-image/docker-build.sh | 8 -- 27 files changed, 89 insertions(+), 51 deletions(-) rename {native-image => images/build-native}/Dockerfile (100%) create mode 100644 images/build-native/README.md create mode 100755 images/build-native/docker-build.sh create mode 100644 images/build-native/native.version rename {build-image => images/build}/Dockerfile (100%) rename {build-image => images/build}/Dockerfile-jdk9 (100%) rename {build-image => images/build}/cache-deps.sh (100%) rename {build-image => images/build}/docker-build.sh (100%) rename {build-image => images/build}/pom.xml (100%) rename {build-image => images/build}/src/main/java/com/example/fn/HelloFunction.java (100%) rename {build-image => images/build}/src/test/java/com/example/fn/HelloFunctionTest.java (100%) rename {native-image/init-image => images/init-native}/Dockerfile (100%) rename {native-image/init-image => images/init-native}/Dockerfile-init-image (100%) create mode 100644 images/init-native/README.md create mode 100755 images/init-native/docker-build.sh rename {native-image/init-image => images/init-native}/func.init.yaml (100%) rename {native-image/init-image => images/init-native}/pom.xml (100%) rename {native-image/init-image => images/init-native}/src/main/conf/reflection.json (100%) rename {native-image/init-image => images/init-native}/src/main/java/com/example/fn/HelloFunction.java (100%) rename {native-image/init-image => images/init-native}/src/test/java/com/example/fn/HelloFunctionTest.java (100%) rename {runtime => images/runtime}/Dockerfile (100%) rename {runtime => images/runtime}/Dockerfile-jdk9 (100%) create mode 100644 images/runtime/README.md delete mode 100755 native-image/docker-build.sh delete mode 100755 native-image/init-image/docker-build.sh diff --git a/.circleci/release.sh b/.circleci/release.sh index 2ba6b2d2..0dcd678f 100755 --- a/.circleci/release.sh +++ b/.circleci/release.sh @@ -6,9 +6,11 @@ USER=fnproject SERVICE=fn-java-fdk RUNTIME_IMAGE=${SERVICE} BUILD_IMAGE=${SERVICE}-build +NATIVE_INIT_IMAGE=fn-java-native-init +NATIVE_BUILD_IMAGE=fn-java-native release_version=$(cat release.version) -if [[ $release_version =~ ^[0-9]+\.[0-9]+\.[0-9]+$ ]] ; then +if [[ ${release_version} =~ ^[0-9]+\.[0-9]+\.[0-9]+$ ]] ; then echo "Deploying version $release_version" else echo Invalid version $release_version @@ -21,10 +23,10 @@ version_parts=(${release_version//./ }) new_minor=$((${version_parts[2]}+1)) new_version="${version_parts[0]}.${version_parts[1]}.$new_minor" -if [[ $new_version =~ ^[0-9]+\.[0-9]+\.[0-9]+$ ]] ; then +if [[ ${new_version} =~ ^[0-9]+\.[0-9]+\.[0-9]+$ ]] ; then echo "Next version $new_version" else - echo Invalid new version $new_version + echo Invalid new version ${new_version} exit 1 fi @@ -32,9 +34,9 @@ fi # Deploy to bintray mvn -s ./settings-deploy.xml \ -DskipTests \ - -DaltDeploymentRepository="fnproject-release-repo::default::$MVN_RELEASE_REPO" \ - -Dfnproject-release-repo.username="$MVN_RELEASE_USER" \ - -Dfnproject-release-repo.password="$MVN_RELEASE_PASSWORD" \ + -DaltDeploymentRepository="fnproject-release-repo::default::${MVN_RELEASE_REPO}" \ + -Dfnproject-release-repo.username="${MVN_RELEASE_USER}" \ + -Dfnproject-release-repo.password="${MVN_RELEASE_PASSWORD}" \ clean deploy @@ -43,38 +45,56 @@ mvn -s ./settings-deploy.xml \ moving_version=${release_version%.*}-latest ## jdk8 runtime - docker tag $USER/$RUNTIME_IMAGE:${release_version} $USER/$RUNTIME_IMAGE:latest - docker tag $USER/$RUNTIME_IMAGE:${release_version} $USER/$RUNTIME_IMAGE:${moving_version} - docker push $USER/$RUNTIME_IMAGE:latest - docker push $USER/$RUNTIME_IMAGE:${release_version} - docker push $USER/$RUNTIME_IMAGE:${moving_version} + docker tag ${USER}/${RUNTIME_IMAGE}:${release_version} ${USER}/${RUNTIME_IMAGE}:latest + docker tag ${USER}/${RUNTIME_IMAGE}:${release_version} ${USER}/${RUNTIME_IMAGE}:${moving_version} + docker push ${USER}/${RUNTIME_IMAGE}:latest + docker push ${USER}/${RUNTIME_IMAGE}:${release_version} + docker push ${USER}/${RUNTIME_IMAGE}:${moving_version} ## jdk8 build - docker tag $USER/$BUILD_IMAGE:${release_version} $USER/$BUILD_IMAGE:latest - docker tag $USER/$BUILD_IMAGE:${release_version} $USER/$BUILD_IMAGE:${moving_version} - docker push $USER/$BUILD_IMAGE:latest - docker push $USER/$BUILD_IMAGE:${release_version} - docker push $USER/$BUILD_IMAGE:${moving_version} + docker tag ${USER}/${BUILD_IMAGE}:${release_version} ${USER}/${BUILD_IMAGE}:latest + docker tag ${USER}/${BUILD_IMAGE}:${release_version} ${USER}/${BUILD_IMAGE}:${moving_version} + docker push ${USER}/${BUILD_IMAGE}:latest + docker push ${USER}/${BUILD_IMAGE}:${release_version} + docker push ${USER}/${BUILD_IMAGE}:${moving_version} ## jdk9 runtime - docker tag $USER/$RUNTIME_IMAGE:jdk9-${release_version} $USER/$RUNTIME_IMAGE:jdk9-latest - docker tag $USER/$RUNTIME_IMAGE:jdk9-${release_version} $USER/$RUNTIME_IMAGE:jdk9-${moving_version} - docker push $USER/$RUNTIME_IMAGE:jdk9-latest - docker push $USER/$RUNTIME_IMAGE:jdk9-${release_version} - docker push $USER/$RUNTIME_IMAGE:jdk9-${moving_version} + docker tag ${USER}/${RUNTIME_IMAGE}:jdk9-${release_version} ${USER}/${RUNTIME_IMAGE}:jdk9-latest + docker tag ${USER}/${RUNTIME_IMAGE}:jdk9-${release_version} ${USER}/${RUNTIME_IMAGE}:jdk9-${moving_version} + docker push ${USER}/${RUNTIME_IMAGE}:jdk9-latest + docker push ${USER}/${RUNTIME_IMAGE}:jdk9-${release_version} + docker push ${USER}/${RUNTIME_IMAGE}:jdk9-${moving_version} ## jdk9 build - docker tag $USER/$BUILD_IMAGE:jdk9-${release_version} $USER/$BUILD_IMAGE:jdk9-latest - docker tag $USER/$BUILD_IMAGE:jdk9-${release_version} $USER/$BUILD_IMAGE:jdk9-${moving_version} - docker push $USER/$BUILD_IMAGE:jdk9-latest - docker push $USER/$BUILD_IMAGE:jdk9-${release_version} - docker push $USER/$BUILD_IMAGE:jdk9-${moving_version} + docker tag ${USER}/${BUILD_IMAGE}:jdk9-${release_version} ${USER}/${BUILD_IMAGE}:jdk9-latest + docker tag ${USER}/${BUILD_IMAGE}:jdk9-${release_version} ${USER}/${BUILD_IMAGE}:jdk9-${moving_version} + docker push ${USER}/${BUILD_IMAGE}:jdk9-latest + docker push ${USER}/${BUILD_IMAGE}:jdk9-${release_version} + docker push ${USER}/${BUILD_IMAGE}:jdk9-${moving_version} + + + ## native init image + docker tag ${USER}/${NATIVE_INIT_IMAGE}:${release_version} ${USER}/${NATIVE_INIT_IMAGE}:latest + docker tag ${USER}/${NATIVE_INIT_IMAGE}:${release_version} ${USER}/${NATIVE_INIT_IMAGE}:${moving_version} + docker push ${USER}/${NATIVE_INIT_IMAGE}:latest + docker push ${USER}/${NATIVE_INIT_IMAGE}:${release_version} + docker push ${USER}/${NATIVE_INIT_IMAGE}:${moving_version} + +) + +( + if [ -f images/build-native/native_build.image ] ; then + native_build_image=$(cat images/build-native/native_build.image) + docker tag ${native_build_image} ${USER}/${NATIVE_BUILD_IMAGE}:latest + docker push ${USER}/${NATIVE_BUILD_IMAGE}:latest + docker push ${native_build_image} + fi ) # Push result to git -echo $new_version > release.version +echo ${new_version} > release.version git tag -a "$release_version" -m "version $release_version" git add release.version git commit -m "$SERVICE: post-$release_version version bump [skip ci]" diff --git a/build.sh b/build.sh index a057210f..57e3e777 100755 --- a/build.sh +++ b/build.sh @@ -25,29 +25,32 @@ done mvn -B deploy -DaltDeploymentRepository=localStagingDir::default::file://${REPOSITORY_LOCATION} ( - cd build-image + cd images/build ./docker-build.sh -t fnproject/fn-java-fdk-build:${BUILD_VERSION} . ) ( - cd build-image + cd images/build ./docker-build.sh -f Dockerfile-jdk9 -t fnproject/fn-java-fdk-build:jdk9-${BUILD_VERSION} . ) ( cd runtime - docker build -t fnproject/fn-java-fdk:${BUILD_VERSION} . + docker build -t fnproject/fn-java-fdk:${BUILD_VERSION} -f ../images/runtime/Dockerfile . ) ( cd runtime - docker build -f Dockerfile-jdk9 -t fnproject/fn-java-fdk:jdk9-${BUILD_VERSION} . + docker build -f ../images/runtime/Dockerfile-jdk9 -t fnproject/fn-java-fdk:jdk9-${BUILD_VERSION} . ) -if [ "${BUILD_NATIVE_JAVA}" = true ] - then - ( - cd native-image +( + cd images/build-native ./docker-build.sh - ) -fi +) + + +( + cd images/init-native + ./docker-build.sh +) diff --git a/native-image/Dockerfile b/images/build-native/Dockerfile similarity index 100% rename from native-image/Dockerfile rename to images/build-native/Dockerfile diff --git a/images/build-native/README.md b/images/build-native/README.md new file mode 100644 index 00000000..11d3eb0a --- /dev/null +++ b/images/build-native/README.md @@ -0,0 +1,5 @@ +# Native Build image + +This rebuilds the substrate build image for native java functions - this build does not run by default on all builds + +To update the build image, make a change to `native.version` (the target version for the release image) on a branch and merge into master. \ No newline at end of file diff --git a/images/build-native/docker-build.sh b/images/build-native/docker-build.sh new file mode 100755 index 00000000..d1e7c6ee --- /dev/null +++ b/images/build-native/docker-build.sh @@ -0,0 +1,12 @@ +#!/bin/sh +native_version=$(cat native.version) +set -e + +native_image="fnproject/fn-java-native:${native_version}" +if docker pull ${native_image} ; then + echo ${native_image} already exists, skipping native build + exit 0 +fi + +docker build -t "fnproject/fn-java-native:${native_version}" . +echo "fnproject/fn-java-native:${native_version}" > native_build.image diff --git a/images/build-native/native.version b/images/build-native/native.version new file mode 100644 index 00000000..6c6aa7cb --- /dev/null +++ b/images/build-native/native.version @@ -0,0 +1 @@ +0.1.0 \ No newline at end of file diff --git a/build-image/Dockerfile b/images/build/Dockerfile similarity index 100% rename from build-image/Dockerfile rename to images/build/Dockerfile diff --git a/build-image/Dockerfile-jdk9 b/images/build/Dockerfile-jdk9 similarity index 100% rename from build-image/Dockerfile-jdk9 rename to images/build/Dockerfile-jdk9 diff --git a/build-image/cache-deps.sh b/images/build/cache-deps.sh similarity index 100% rename from build-image/cache-deps.sh rename to images/build/cache-deps.sh diff --git a/build-image/docker-build.sh b/images/build/docker-build.sh similarity index 100% rename from build-image/docker-build.sh rename to images/build/docker-build.sh diff --git a/build-image/pom.xml b/images/build/pom.xml similarity index 100% rename from build-image/pom.xml rename to images/build/pom.xml diff --git a/build-image/src/main/java/com/example/fn/HelloFunction.java b/images/build/src/main/java/com/example/fn/HelloFunction.java similarity index 100% rename from build-image/src/main/java/com/example/fn/HelloFunction.java rename to images/build/src/main/java/com/example/fn/HelloFunction.java diff --git a/build-image/src/test/java/com/example/fn/HelloFunctionTest.java b/images/build/src/test/java/com/example/fn/HelloFunctionTest.java similarity index 100% rename from build-image/src/test/java/com/example/fn/HelloFunctionTest.java rename to images/build/src/test/java/com/example/fn/HelloFunctionTest.java diff --git a/native-image/init-image/Dockerfile b/images/init-native/Dockerfile similarity index 100% rename from native-image/init-image/Dockerfile rename to images/init-native/Dockerfile diff --git a/native-image/init-image/Dockerfile-init-image b/images/init-native/Dockerfile-init-image similarity index 100% rename from native-image/init-image/Dockerfile-init-image rename to images/init-native/Dockerfile-init-image diff --git a/images/init-native/README.md b/images/init-native/README.md new file mode 100644 index 00000000..080f648f --- /dev/null +++ b/images/init-native/README.md @@ -0,0 +1,2 @@ +# Native init image + diff --git a/images/init-native/docker-build.sh b/images/init-native/docker-build.sh new file mode 100755 index 00000000..4aea7a2b --- /dev/null +++ b/images/init-native/docker-build.sh @@ -0,0 +1,6 @@ +#!/bin/sh +if [ -z "${FN_FDK_VERSION}" ]; then + FN_FDK_VERSION=$(cat ../../release.version) +fi +sed -i.bak -e "s|.*|${FN_FDK_VERSION}|" pom.xml && rm pom.xml.bak +docker build -t fnproject/fn-java-native-init:${FN_FDK_VERSION} -f Dockerfile-init-image . diff --git a/native-image/init-image/func.init.yaml b/images/init-native/func.init.yaml similarity index 100% rename from native-image/init-image/func.init.yaml rename to images/init-native/func.init.yaml diff --git a/native-image/init-image/pom.xml b/images/init-native/pom.xml similarity index 100% rename from native-image/init-image/pom.xml rename to images/init-native/pom.xml diff --git a/native-image/init-image/src/main/conf/reflection.json b/images/init-native/src/main/conf/reflection.json similarity index 100% rename from native-image/init-image/src/main/conf/reflection.json rename to images/init-native/src/main/conf/reflection.json diff --git a/native-image/init-image/src/main/java/com/example/fn/HelloFunction.java b/images/init-native/src/main/java/com/example/fn/HelloFunction.java similarity index 100% rename from native-image/init-image/src/main/java/com/example/fn/HelloFunction.java rename to images/init-native/src/main/java/com/example/fn/HelloFunction.java diff --git a/native-image/init-image/src/test/java/com/example/fn/HelloFunctionTest.java b/images/init-native/src/test/java/com/example/fn/HelloFunctionTest.java similarity index 100% rename from native-image/init-image/src/test/java/com/example/fn/HelloFunctionTest.java rename to images/init-native/src/test/java/com/example/fn/HelloFunctionTest.java diff --git a/runtime/Dockerfile b/images/runtime/Dockerfile similarity index 100% rename from runtime/Dockerfile rename to images/runtime/Dockerfile diff --git a/runtime/Dockerfile-jdk9 b/images/runtime/Dockerfile-jdk9 similarity index 100% rename from runtime/Dockerfile-jdk9 rename to images/runtime/Dockerfile-jdk9 diff --git a/images/runtime/README.md b/images/runtime/README.md new file mode 100644 index 00000000..672f311d --- /dev/null +++ b/images/runtime/README.md @@ -0,0 +1,3 @@ +# Fn Java runtime base image + +This image is used as a base image for functions - it includes a JDK and the latest version of the runtime \ No newline at end of file diff --git a/native-image/docker-build.sh b/native-image/docker-build.sh deleted file mode 100755 index 11ae75dd..00000000 --- a/native-image/docker-build.sh +++ /dev/null @@ -1,6 +0,0 @@ -#!/bin/sh -docker build -t "fnproject/fn-java-native:latest" . -( - cd init-image - ./docker-build.sh -) diff --git a/native-image/init-image/docker-build.sh b/native-image/init-image/docker-build.sh deleted file mode 100755 index ced52457..00000000 --- a/native-image/init-image/docker-build.sh +++ /dev/null @@ -1,8 +0,0 @@ -#!/bin/sh -if [ -z "${release_version}" ] - then - release_version=$(cat ../../release.version) -fi -BUILD_VERSION=${FN_FDK_VERSION:-1.0.0-SNAPSHOT} -sed -i.bak -e "s|.*|${release_version}|" pom.xml && rm pom.xml.bak -docker build -t fnproject/fn-java-native-init:latest -f Dockerfile-init-image . From 0de66d8ea4ebba5d1bfaa061f89ac29e96f39e00 Mon Sep 17 00:00:00 2001 From: Owen Cliffe Date: Thu, 11 Oct 2018 14:58:57 +0100 Subject: [PATCH 057/310] bump fdk for release --- release.version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/release.version b/release.version index be1dcc8a..ea2f1d39 100644 --- a/release.version +++ b/release.version @@ -1 +1 @@ -1.0.73 +1.0.74 From 4136d556724646b89ff9f548adc3a160fd29df95 Mon Sep 17 00:00:00 2001 From: CI Date: Fri, 12 Oct 2018 16:48:33 +0000 Subject: [PATCH 058/310] fn-java-fdk: post-1.0.74 version bump [skip ci] --- release.version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/release.version b/release.version index ea2f1d39..e9acec7f 100644 --- a/release.version +++ b/release.version @@ -1 +1 @@ -1.0.74 +1.0.75 From 4e4e66c564a13943f8d3611a572cea69ea9abb86 Mon Sep 17 00:00:00 2001 From: Owen Cliffe Date: Mon, 15 Oct 2018 14:14:25 +0100 Subject: [PATCH 059/310] Rev jackson-databind to deal with latest vulnerabilities. (#163) * Fix Jackson databind to deal with latest CVE * rev minio version used in async thumbnails test to pick up newer jetty version * fix up async thumbnails to test new minio version --- examples/async-thumbnails/README.md | 84 ++++++++++--------- examples/async-thumbnails/func.yaml | 14 ++-- examples/async-thumbnails/pom.xml | 11 ++- examples/async-thumbnails/run.sh | 12 +-- .../setup/resize128/func.yaml | 7 +- .../setup/resize256/func.yaml | 7 +- .../setup/resize512/func.yaml | 7 +- examples/async-thumbnails/setup/setup.sh | 76 ++++++++--------- .../fn/examples/ThumbnailsFunction.java | 18 +++- .../fn/examples/ThumbnailsFunctionTest.java | 11 ++- examples/regex-query/pom.xml | 2 +- pom.xml | 2 +- 12 files changed, 138 insertions(+), 113 deletions(-) diff --git a/examples/async-thumbnails/README.md b/examples/async-thumbnails/README.md index 543a8651..b3cff27d 100644 --- a/examples/async-thumbnails/README.md +++ b/examples/async-thumbnails/README.md @@ -32,9 +32,8 @@ this example. Run: ``` This will start a local functions service, a local flow completion -service, and will set up a `myapp` application and three routes: `/resize128`, -`/resize256` and `/resize512`. The routes are implemented as Fn functions -which just invoke `imagemagick` to convert the images to the specified sizes. +service, and will set up a `myapp` application and three functions: `resize128`, +`resize256` and `resize512`. These functions just invoke `imagemagick` to convert the images to the specified sizes. The setup script also starts a docker container with an object storage daemon based on `minio` (with access key `alpha` and secret key `betabetabetabeta`). @@ -48,14 +47,9 @@ docker container, so that you can verify when the thumbnails are uploaded. Build the function locally: ```bash -$ fn build +$ fn deploy --local --app myapp ``` -Create a route to host the function: - -```bash -$ fn create route myapp /async-thumbnails -``` Configure the app. In order to do this you must determine the IP address of the storage server docker container: @@ -68,18 +62,18 @@ $ docker inspect --type container -f '{{range .NetworkSettings.Networks}}{{.IPAd and then use it as the storage host: ```bash -$ fn config route myapp /async-thumbnails OBJECT_STORAGE_URL http://172.17.0.4:9000 +$ fn config app myapp OBJECT_STORAGE_URL http://172.17.0.4:9000 myapp /async-thumbnails updated OBJECT_STORAGE_URL with http://172.17.0.4:9000 -$ fn config route myapp /async-thumbnails OBJECT_STORAGE_ACCESS alpha +$ fn config app myapp OBJECT_STORAGE_ACCESS alpha myapp /async-thumbnails updated OBJECT_STORAGE_ACCESS with alpha -$ fn config route myapp /async-thumbnails OBJECT_STORAGE_SECRET betabetabetabeta +$ fn config app myapp OBJECT_STORAGE_SECRET betabetabetabeta myapp /async-thumbnails updated OBJECT_STORAGE_SECRET with betabetabetabeta ``` Invoke the function by passing the provided test image: ```bash -$ curl -X POST --data-binary @test-image.png -H "Content-type: application/octet-stream" "http://localhost:8080/r/myapp/async-thumbnails" +$ curl -X POST --data-binary @test-image.png -H "Content-type: application/octet-stream" "http://localhost:8080/t/myapp/async-thumbnails" {"imageId":"bd74fff4-0388-4c6f-82f2-8cde9ba9b6fc"} ``` @@ -116,6 +110,13 @@ public class ThumbnailsFunction { .orElseThrow(() -> new RuntimeException("Missing configuration: OBJECT_STORAGE_ACCESS")); storageSecretKey = ctx.getConfigurationByKey("OBJECT_STORAGE_SECRET") .orElseThrow(() -> new RuntimeException("Missing configuration: OBJECT_STORAGE_SECRET")); + + resize128ID = ctx.getConfigurationByKey("RESIZE_128_FN_ID") + .orElseThrow(() -> new RuntimeException("Missing configuration: RESIZE_128_FN_ID")); + resize256ID = ctx.getConfigurationByKey("RESIZE_256_FN_ID") + .orElseThrow(() -> new RuntimeException("Missing configuration: RESIZE_256_FN_ID")); + resize512ID = ctx.getConfigurationByKey("RESIZE_512_FN_ID") + .orElseThrow(() -> new RuntimeException("Missing configuration: RESIZE_512_FN_ID")); } // ... @@ -155,11 +156,11 @@ public class ThumbnailsFunction { Flow runtime = Flows.currentFlow(); runtime.allOf( - runtime.invokeFunction("myapp/resize128", HttpMethod.POST, Headers.emptyHeaders(), imageBuffer) + runtime.invokeFunction(resize128ID, HttpMethod.POST, Headers.emptyHeaders(), imageBuffer) .thenAccept((img) -> objectUpload(img.getBodyAsBytes(), id + "-128.png")), - runtime.invokeFunction("myapp/resize256", HttpMethod.POST, Headers.emptyHeaders(), imageBuffer) + runtime.invokeFunction(resize256ID, HttpMethod.POST, Headers.emptyHeaders(), imageBuffer) .thenAccept((img) -> objectUpload(img.getBodyAsBytes(), id + "-256.png")), - runtime.invokeFunction("myapp/resize512", HttpMethod.POST, Headers.emptyHeaders(), imageBuffer) + runtime.invokeFunction(resize512ID, HttpMethod.POST, Headers.emptyHeaders(), imageBuffer) .thenAccept((img) -> objectUpload(img.getBodyAsBytes(), id + "-512.png")), runtime.supply(() -> objectUpload(imageBuffer, id + ".png")) ); @@ -218,8 +219,9 @@ in [Testing Functions](../../docs/TestingFunctions.md). ```java public class ThumbnailsFunctionTest { - @Rule - public final FnTestingRule testing = FnTestingRule.createDefault(); + @Rule + public final FnTestingRule fn = FnTestingRule.createDefault(); + private final FlowTesting flow = FlowTesting.create(fn); // ... } @@ -259,20 +261,22 @@ public class ThumbnailsFunctionTest { @Test public void testThumbnail() { - testing - .setConfig("OBJECT_STORAGE_URL", "http://localhost:" + mockServer.port()) - .setConfig("OBJECT_STORAGE_ACCESS", "alpha") - .setConfig("OBJECT_STORAGE_SECRET", "betabetabetabeta") + fn.setConfig("OBJECT_STORAGE_URL", "http://localhost:" + mockServer.port()) + .setConfig("OBJECT_STORAGE_ACCESS", "alpha") + .setConfig("OBJECT_STORAGE_SECRET", "betabetabetabeta") + .setConfig("RESIZE_128_FN_ID","myapp/resize128") + .setConfig("RESIZE_256_FN_ID","myapp/resize256") + .setConfig("RESIZE_512_FN_ID","myapp/resize512"); - .givenFn("myapp/resize128") + flow.givenFn("myapp/resize128") .withAction((data) -> "128".getBytes()) .givenFn("myapp/resize256") .withAction((data) -> "256".getBytes()) .givenFn("myapp/resize512") .withAction((data) -> "512".getBytes()) - .givenEvent() + fn.givenEvent() .withBody("testing".getBytes()) .enqueue(); @@ -301,21 +305,23 @@ public class ThumbnailsFunctionTest { @Test public void anExternalFunctionFailure() { - testing - .setConfig("OBJECT_STORAGE_URL", "http://localhost:" + mockServer.port()) - .setConfig("OBJECT_STORAGE_ACCESS", "alpha") - .setConfig("OBJECT_STORAGE_SECRET", "betabetabetabeta") - - .givenFn("myapp/resize128") - .withResult("128".getBytes()) - .givenFn("myapp/resize256") - .withResult("256".getBytes()) - .givenFn("myapp/resize512") - .withFunctionError() - - .givenEvent() - .withBody("testing".getBytes()) - .enqueue(); + fn.setConfig("OBJECT_STORAGE_URL", "http://localhost:" + mockServer.port()) + .setConfig("OBJECT_STORAGE_ACCESS", "alpha") + .setConfig("OBJECT_STORAGE_SECRET", "betabetabetabeta") + .setConfig("RESIZE_128_FN_ID","myapp/resize128") + .setConfig("RESIZE_256_FN_ID","myapp/resize256") + .setConfig("RESIZE_512_FN_ID","myapp/resize512"); + + flow.givenFn("myapp/resize128") + .withResult("128".getBytes()) + .givenFn("myapp/resize256") + .withResult("256".getBytes()) + .givenFn("myapp/resize512") + .withFunctionError(); + + fn.givenEvent() + .withBody("testing".getBytes()) + .enqueue(); // Mock the http endpoint mockMinio(); diff --git a/examples/async-thumbnails/func.yaml b/examples/async-thumbnails/func.yaml index d6003dc4..7bd97826 100644 --- a/examples/async-thumbnails/func.yaml +++ b/examples/async-thumbnails/func.yaml @@ -1,7 +1,11 @@ -name: fn-example/async-thumbnails -version: 0.0.1 +schema_version: 20180708 +name: async-thumbnails +version: 0.0.8 runtime: java cmd: com.fnproject.fn.examples.ThumbnailsFunction::handleRequest -path: /async-thumbnails -format: http -timeout: 30 +format: http-stream +timeout: 120 +triggers: +- name: async-thumbnails + type: http + source: /async-thumbnails diff --git a/examples/async-thumbnails/pom.xml b/examples/async-thumbnails/pom.xml index 87aa5c34..17a6f37d 100644 --- a/examples/async-thumbnails/pom.xml +++ b/examples/async-thumbnails/pom.xml @@ -10,6 +10,7 @@ 1.0.0-SNAPSHOT 2.8.47 + 2.9.7 com.fnproject.fn.examples @@ -17,6 +18,7 @@ 1.0.0-SNAPSHOT + com.fnproject.fn api @@ -32,10 +34,15 @@ commons-net 3.6 + + com.fasterxml.jackson.core + jackson-databind + ${jackson.version} + io.minio minio - 3.0.12 + 5.0.1 com.fnproject.fn @@ -65,7 +72,7 @@ com.github.tomakehurst wiremock - 2.18.0 + 2.19.0 diff --git a/examples/async-thumbnails/run.sh b/examples/async-thumbnails/run.sh index d8576a57..68bd6574 100755 --- a/examples/async-thumbnails/run.sh +++ b/examples/async-thumbnails/run.sh @@ -1,15 +1,11 @@ #!/bin/bash +set -e -fn build +fn --verbose deploy --app myapp --local -fn create route myapp /async-thumbnails -STORAGE_SERVER_IP=`docker inspect --type container -f '{{range .NetworkSettings.Networks}}{{.IPAddress}}{{end}}' example-storage-server` -fn config route myapp /async-thumbnails OBJECT_STORAGE_URL http://${STORAGE_SERVER_IP}:9000 -fn config route set myapp /async-thumbnails OBJECT_STORAGE_ACCESS alpha -fn config route set myapp /async-thumbnails OBJECT_STORAGE_SECRET betabetabetabeta - -curl -X POST --data-binary @test-image.png -H "Content-type: application/octet-stream" "http://localhost:8080/r/myapp/async-thumbnails" +echo "Calling function" +curl -v -X POST --data-binary @test-image.png -H "Content-type: application/octet-stream" "http://localhost:8080/t/myapp/async-thumbnails" echo "Contents of bucket" mc ls -r example-storage-server diff --git a/examples/async-thumbnails/setup/resize128/func.yaml b/examples/async-thumbnails/setup/resize128/func.yaml index b7a5071b..27013369 100644 --- a/examples/async-thumbnails/setup/resize128/func.yaml +++ b/examples/async-thumbnails/setup/resize128/func.yaml @@ -1,4 +1,5 @@ -name: example/resize128 -version: 0.0.1 +schema_version: 20180708 +name: resize128 +version: 0.0.5 entrypoint: convert - -resize 128x128 - -path: /resize128 +format: default diff --git a/examples/async-thumbnails/setup/resize256/func.yaml b/examples/async-thumbnails/setup/resize256/func.yaml index 9261f2f6..cd5b4032 100644 --- a/examples/async-thumbnails/setup/resize256/func.yaml +++ b/examples/async-thumbnails/setup/resize256/func.yaml @@ -1,4 +1,5 @@ -name: example/resize256 -version: 0.0.1 +schema_version: 20180708 +name: resize256 +version: 0.0.5 entrypoint: convert - -resize 256x256 - -path: /resize256 +format: default diff --git a/examples/async-thumbnails/setup/resize512/func.yaml b/examples/async-thumbnails/setup/resize512/func.yaml index 8ee1d02f..82d9a844 100644 --- a/examples/async-thumbnails/setup/resize512/func.yaml +++ b/examples/async-thumbnails/setup/resize512/func.yaml @@ -1,4 +1,5 @@ -name: example/resize512 -version: 0.0.1 +schema_version: 20180708 +name: resize512 +version: 0.0.8 entrypoint: convert - -resize 512x512 - -path: /resize512 +format: default diff --git a/examples/async-thumbnails/setup/setup.sh b/examples/async-thumbnails/setup/setup.sh index 916a1dcf..96c3e3a4 100755 --- a/examples/async-thumbnails/setup/setup.sh +++ b/examples/async-thumbnails/setup/setup.sh @@ -51,26 +51,21 @@ fi STORAGE_SERVER_IP=`docker inspect --type container -f '{{range .NetworkSettings.Networks}}{{.IPAddress}}{{end}}' example-storage-server` # Start functions server if not there -if [[ -z `docker ps | grep "functions"` ]]; then - docker run -d --name functions \ - -e NO_PROXY="$STORAGE_SERVER_IP:$NO_PROXY" \ - -p 8080:8080 \ - -v /var/run/docker.sock:/var/run/docker.sock \ - "$FUNCTIONS_IMAGE" - # Give it time to start up +if [[ -z `docker ps | grep "fnserver"` ]]; then + fn start -d sleep 3 else echo "Functions server is already up." fi # Get its IP -FUNCTIONS_SERVER_IP=`docker inspect --type container -f '{{range .NetworkSettings.Networks}}{{.IPAddress}}{{end}}' functions` +FUNCTIONS_SERVER_IP=`docker inspect --type container -f '{{range .NetworkSettings.Networks}}{{.IPAddress}}{{end}}' fnserver` # Start flow service if not there if [[ -z `docker ps | grep "flow-service"` ]]; then docker run -d --name flow-service \ -e LOG_LEVEL=debug \ -e NO_PROXY="$FUNCTIONS_SERVER_IP:$NO_PROXY" \ - -e API_URL=http://$FUNCTIONS_SERVER_IP:8080/r \ + -e API_URL=http://$FUNCTIONS_SERVER_IP:8080/invoke \ -p 8081:8081 \ "$COMPLETER_IMAGE" # Give it time to start up @@ -86,42 +81,37 @@ if [[ `fn list apps` == *"myapp"* ]]; then echo "App myapp is already there." else fn create app myapp - fn config app myapp COMPLETER_BASE_URL http://10.167.103.193:8081 fi -if [[ `fn list routes myapp` == *"/resize128"* ]]; then - echo "Route /resize128 is already there." -else - # This works around proxy issues - cd $SCRIPT_DIR/resize128 && \ - docker build -t example/resize128:0.0.1 \ - --build-arg http_proxy=$http_proxy \ - --build-arg https_proxy=$https_proxy \ - . && \ - fn create route myapp /resize128 -fi -if [[ `fn list routes myapp` == *"/resize256"* ]]; then - echo "Route /resize256 is already there." -else - # This works around proxy issues - cd $SCRIPT_DIR/resize256 && \ - docker build -t example/resize256:0.0.1 \ - --build-arg http_proxy=$http_proxy \ - --build-arg https_proxy=$https_proxy \ - . && \ - fn create route myapp /resize256 -fi -if [[ `fn list routes myapp` == *"/resize512"* ]]; then - echo "Route /resize512 is already there." -else - # This works around proxy issues - cd $SCRIPT_DIR/resize512 && \ - docker build -t example/resize512:0.0.1 \ - --build-arg http_proxy=$http_proxy \ - --build-arg https_proxy=$https_proxy \ - . && \ - fn create route myapp /resize512 -fi + +fn config app myapp COMPLETER_BASE_URL http://${COMPLETER_SERVER_IP}:8081 +fn config app myapp OBJECT_STORAGE_URL http://${STORAGE_SERVER_IP}:9000 +fn config app myapp OBJECT_STORAGE_ACCESS alpha +fn config app myapp OBJECT_STORAGE_SECRET betabetabetabeta + +( + cd ${SCRIPT_DIR}/resize128 + fn deploy --app myapp --local +) + +fn config app myapp RESIZE_128_FN_ID $(fn list functions myapp | grep resize128 | awk '{print $3}') + +( + cd ${SCRIPT_DIR}/resize256 + fn deploy --app myapp --local +) + +fn config app myapp RESIZE_256_FN_ID $(fn list functions myapp | grep resize256 | awk '{print $3}') + + +( + cd ${SCRIPT_DIR}/resize512 + fn deploy --app myapp --local +) + +fn config app myapp RESIZE_512_FN_ID $(fn list functions myapp | grep resize512 | awk '{print $3}') + + if mc config host list | grep example-storage-server &>/dev/null ; then diff --git a/examples/async-thumbnails/src/main/java/com/fnproject/fn/examples/ThumbnailsFunction.java b/examples/async-thumbnails/src/main/java/com/fnproject/fn/examples/ThumbnailsFunction.java index eb2cb4da..5f6c1dee 100644 --- a/examples/async-thumbnails/src/main/java/com/fnproject/fn/examples/ThumbnailsFunction.java +++ b/examples/async-thumbnails/src/main/java/com/fnproject/fn/examples/ThumbnailsFunction.java @@ -19,6 +19,10 @@ public class ThumbnailsFunction implements Serializable { private final String storageAccessKey; private final String storageSecretKey; + private final String resize128ID; + private final String resize256ID; + private final String resize512ID; + public ThumbnailsFunction(RuntimeContext ctx) { storageUrl = ctx.getConfigurationByKey("OBJECT_STORAGE_URL") .orElseThrow(() -> new RuntimeException("Missing configuration: OBJECT_STORAGE_URL")); @@ -26,6 +30,14 @@ public ThumbnailsFunction(RuntimeContext ctx) { .orElseThrow(() -> new RuntimeException("Missing configuration: OBJECT_STORAGE_ACCESS")); storageSecretKey = ctx.getConfigurationByKey("OBJECT_STORAGE_SECRET") .orElseThrow(() -> new RuntimeException("Missing configuration: OBJECT_STORAGE_SECRET")); + + resize128ID = ctx.getConfigurationByKey("RESIZE_128_FN_ID") + .orElseThrow(() -> new RuntimeException("Missing configuration: RESIZE_128_FN_ID")); + resize256ID = ctx.getConfigurationByKey("RESIZE_256_FN_ID") + .orElseThrow(() -> new RuntimeException("Missing configuration: RESIZE_256_FN_ID")); + resize512ID = ctx.getConfigurationByKey("RESIZE_512_FN_ID") + .orElseThrow(() -> new RuntimeException("Missing configuration: RESIZE_512_FN_ID")); + } public class Response { @@ -38,11 +50,11 @@ public Response handleRequest(byte[] imageBuffer) { Flow runtime = Flows.currentFlow(); runtime.allOf( - runtime.invokeFunction("myapp/resize128", HttpMethod.POST, Headers.emptyHeaders(), imageBuffer) + runtime.invokeFunction(resize128ID, HttpMethod.POST, Headers.emptyHeaders(), imageBuffer) .thenAccept((img) -> objectUpload(img.getBodyAsBytes(), id + "-128.png")), - runtime.invokeFunction("myapp/resize256", HttpMethod.POST, Headers.emptyHeaders(), imageBuffer) + runtime.invokeFunction(resize256ID, HttpMethod.POST, Headers.emptyHeaders(), imageBuffer) .thenAccept((img) -> objectUpload(img.getBodyAsBytes(), id + "-256.png")), - runtime.invokeFunction("myapp/resize512", HttpMethod.POST, Headers.emptyHeaders(), imageBuffer) + runtime.invokeFunction(resize512ID, HttpMethod.POST, Headers.emptyHeaders(), imageBuffer) .thenAccept((img) -> objectUpload(img.getBodyAsBytes(), id + "-512.png")), runtime.supply(() -> objectUpload(imageBuffer, id + ".png")) ); diff --git a/examples/async-thumbnails/src/test/java/com/fnproject/fn/examples/ThumbnailsFunctionTest.java b/examples/async-thumbnails/src/test/java/com/fnproject/fn/examples/ThumbnailsFunctionTest.java index 9c9fba43..8179ea10 100644 --- a/examples/async-thumbnails/src/test/java/com/fnproject/fn/examples/ThumbnailsFunctionTest.java +++ b/examples/async-thumbnails/src/test/java/com/fnproject/fn/examples/ThumbnailsFunctionTest.java @@ -23,7 +23,11 @@ public void testThumbnail() { fn .setConfig("OBJECT_STORAGE_URL", "http://localhost:" + mockServer.port()) .setConfig("OBJECT_STORAGE_ACCESS", "alpha") - .setConfig("OBJECT_STORAGE_SECRET", "betabetabetabeta"); + .setConfig("OBJECT_STORAGE_SECRET", "betabetabetabeta") + .setConfig("RESIZE_128_FN_ID","myapp/resize128") + .setConfig("RESIZE_256_FN_ID","myapp/resize256") + .setConfig("RESIZE_512_FN_ID","myapp/resize512"); + flow .givenFn("myapp/resize128") @@ -56,7 +60,10 @@ public void anExternalFunctionFailure() { fn .setConfig("OBJECT_STORAGE_URL", "http://localhost:" + mockServer.port()) .setConfig("OBJECT_STORAGE_ACCESS", "alpha") - .setConfig("OBJECT_STORAGE_SECRET", "betabetabetabeta"); + .setConfig("OBJECT_STORAGE_SECRET", "betabetabetabeta") + .setConfig("RESIZE_128_FN_ID","myapp/resize128") + .setConfig("RESIZE_256_FN_ID","myapp/resize256") + .setConfig("RESIZE_512_FN_ID","myapp/resize512");; flow .givenFn("myapp/resize128") diff --git a/examples/regex-query/pom.xml b/examples/regex-query/pom.xml index 61b63c85..0d08dd2e 100644 --- a/examples/regex-query/pom.xml +++ b/examples/regex-query/pom.xml @@ -9,7 +9,7 @@ UTF-8 1.0.0-SNAPSHOT - 2.9.6 + 2.9.7 com.fnproject.fn.examples diff --git a/pom.xml b/pom.xml index fc93e7b0..be1c5883 100644 --- a/pom.xml +++ b/pom.xml @@ -39,7 +39,7 @@ 1.7.25 2.6 - 2.9.6 + 2.9.7 4.4.10 1.16.0 From 7a3b14812faaf2ba47b081c79b22d1d44671c424 Mon Sep 17 00:00:00 2001 From: CI Date: Mon, 15 Oct 2018 13:26:25 +0000 Subject: [PATCH 060/310] fn-java-fdk: post-1.0.75 version bump [skip ci] --- release.version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/release.version b/release.version index e9acec7f..e7468c7d 100644 --- a/release.version +++ b/release.version @@ -1 +1 @@ -1.0.75 +1.0.76 From 327ca84093ae5d53dcca9679f61e5e949b6c6139 Mon Sep 17 00:00:00 2001 From: Tomas Zezula Date: Thu, 15 Nov 2018 20:50:17 +0100 Subject: [PATCH 061/310] [164] Support http-stream protocol in substrate/native java. --- build.sh | 3 ++- images/build-native/Dockerfile | 5 +++-- images/build-native/docker-build.sh | 13 +++++++++-- images/build-native/native.version | 2 +- images/init-native/Dockerfile | 6 ++++- images/init-native/func.init.yaml | 2 +- images/init-native/src/main/conf/jni.json | 22 +++++++++++++++++++ .../init-native/src/main/conf/reflection.json | 5 ++--- 8 files changed, 47 insertions(+), 11 deletions(-) create mode 100644 images/init-native/src/main/conf/jni.json diff --git a/build.sh b/build.sh index 57e3e777..70e1edec 100755 --- a/build.sh +++ b/build.sh @@ -45,8 +45,9 @@ mvn -B deploy -DaltDeploymentRepository=localStagingDir::default::file://${REP ) ( + workdir=$(pwd)/runtime cd images/build-native - ./docker-build.sh + ./docker-build.sh ${workdir} ) diff --git a/images/build-native/Dockerfile b/images/build-native/Dockerfile index 6384bb00..4e63888f 100644 --- a/images/build-native/Dockerfile +++ b/images/build-native/Dockerfile @@ -6,7 +6,7 @@ RUN set -x \ && apt-get -y install gcc g++ git make openjdk-8-doc openjdk-8-source python zlib1g-dev \ && rm -rf /var/lib/apt/lists/* -ENV JVMCI_VERSION 0.47 +ENV JVMCI_VERSION 0.49 WORKDIR /build @@ -20,7 +20,7 @@ RUN set -x \ && cp -r $(/build/mx/mx --primary-suite graal-jvmci-8 jdkhome) /build/jvmcijdk8 RUN git clone https://github.com/oracle/graal.git \ - && git -C graal checkout dca98069dc57c458b8bcb3392cf9e66316dd37b6 + && git -C graal checkout vm-1.0.0-rc9 WORKDIR /build/graal/vm RUN export JAVA_HOME=/build/jvmcijdk8 \ && /build/mx/mx --dy /substratevm --force-bash-launchers=true --disable-polyglot --disable-libpolyglot build @@ -38,6 +38,7 @@ RUN set -x \ && apt-get -y install gcc zlib1g-dev COPY --from=build /build/graal/vm/latest_graalvm/graalvm /usr/local/graalvm +COPY src/main/c/libfnunixsocket.so /function/runtime/lib/ ENV GRAALVM_HOME=/usr/local/graalvm diff --git a/images/build-native/docker-build.sh b/images/build-native/docker-build.sh index d1e7c6ee..9e5625bc 100755 --- a/images/build-native/docker-build.sh +++ b/images/build-native/docker-build.sh @@ -1,4 +1,9 @@ #!/bin/sh +if [ -z "$1" ] +then + echo "Needs runtime folder as an argument" + exit 1 +fi native_version=$(cat native.version) set -e @@ -7,6 +12,10 @@ if docker pull ${native_image} ; then echo ${native_image} already exists, skipping native build exit 0 fi - -docker build -t "fnproject/fn-java-native:${native_version}" . +workdir=${1} +dockerfiledir=$(pwd) +( + cd ${workdir} + docker build -f ${dockerfiledir}/Dockerfile -t "fnproject/fn-java-native:${native_version}" . +) echo "fnproject/fn-java-native:${native_version}" > native_build.image diff --git a/images/build-native/native.version b/images/build-native/native.version index 6c6aa7cb..0ea3a944 100644 --- a/images/build-native/native.version +++ b/images/build-native/native.version @@ -1 +1 @@ -0.1.0 \ No newline at end of file +0.2.0 diff --git a/images/init-native/Dockerfile b/images/init-native/Dockerfile index 5f3f22bd..673bb276 100644 --- a/images/init-native/Dockerfile +++ b/images/init-native/Dockerfile @@ -12,18 +12,22 @@ LABEL maintainer="tomas.zezula@oracle.com" WORKDIR /function COPY --from=build /function/target/*.jar target/ COPY --from=build /function/src/main/conf/reflection.json reflection.json +COPY --from=build /function/src/main/conf/jni.json jni.json RUN /usr/local/graalvm/bin/native-image \ --static \ + --delay-class-initialization-to-runtime=com.fnproject.fn.runtime.ntv.UnixSocketNative \ -H:Name=func \ -H:+ReportUnsupportedElementsAtRuntime \ -H:ReflectionConfigurationFiles=reflection.json \ + -H:JNIConfigurationFiles=jni.json \ -classpath "target/*"\ com.fnproject.fn.runtime.EntryPoint -FROM scratch +FROM busybox:glibc LABEL maintainer="tomas.zezula@oracle.com" WORKDIR /function COPY --from=build-native-image /function/func func +COPY --from=build-native-image /function/runtime/lib/* . ENTRYPOINT ["./func", "-XX:MaximumHeapSizePercent=80"] CMD [ "com.example.fn.HelloFunction::handleRequest" ] diff --git a/images/init-native/func.init.yaml b/images/init-native/func.init.yaml index 86cc0c76..b7b18322 100644 --- a/images/init-native/func.init.yaml +++ b/images/init-native/func.init.yaml @@ -1,2 +1,2 @@ runtime: docker -format: http +format: http-stream diff --git a/images/init-native/src/main/conf/jni.json b/images/init-native/src/main/conf/jni.json new file mode 100644 index 00000000..05def46f --- /dev/null +++ b/images/init-native/src/main/conf/jni.json @@ -0,0 +1,22 @@ +[ + { + "name" : "com.fnproject.fn.runtime.ntv.UnixSocketNative", + "methods" : [ + { "name" : "socket" }, + { "name" : "bind" }, + { "name" : "connect" }, + { "name" : "listen" }, + { "name" : "accept" }, + { "name" : "recv" }, + { "name" : "send" }, + { "name" : "close" }, + { "name" : "setSendTimeout" }, + { "name" : "getSendTimeout" }, + { "name" : "setRecvTimeout" }, + { "name" : "getRecvTimeout" }, + { "name" : "setSendBufSize" }, + { "name" : "setRecvBufSize" }, + { "name" : "shutdown"} + ] + } +] diff --git a/images/init-native/src/main/conf/reflection.json b/images/init-native/src/main/conf/reflection.json index 9110b519..e1e25e08 100644 --- a/images/init-native/src/main/conf/reflection.json +++ b/images/init-native/src/main/conf/reflection.json @@ -1,10 +1,9 @@ - [ { "name" : "com.example.fn.HelloFunction", "methods" : [ - { "name" : "handleRequest" }, - { "name" : ""} + { "name" : "handleRequest" }, + { "name" : "" } ] } ] From 8fa2f330d954a62f74b3beaa9d4917b2bb1dff16 Mon Sep 17 00:00:00 2001 From: Rik Gibson Date: Tue, 20 Nov 2018 01:15:48 +0000 Subject: [PATCH 062/310] This gets the local build.sh working again on the latest JDK8 --- .gitignore | 4 ++++ api/pom.xml | 2 +- api/src/main/api/snapshot.sigfile | 12 ++++++++++++ api/src/main/java/com/fnproject/fn/api/Headers.java | 3 +++ .../fn/runtime/flow/RemoteFlowApiClient.java | 3 +++ .../fn/runtime/flow/RemoteFlowApiClientTest.java | 6 +++++- images/build/pom.xml | 8 ++++++++ images/init-native/pom.xml | 2 +- .../fnproject/fn/runtime/ntv/UnixSocketNative.java | 2 ++ 9 files changed, 39 insertions(+), 3 deletions(-) diff --git a/.gitignore b/.gitignore index 1fff5367..1e68a65a 100644 --- a/.gitignore +++ b/.gitignore @@ -12,3 +12,7 @@ logs/ *.versionsBackup .gradle examples/gradle-build/build +**/*.classpath +**/*.project +**/*.settings + diff --git a/api/pom.xml b/api/pom.xml index 2bc26b02..a7a27704 100644 --- a/api/pom.xml +++ b/api/pom.xml @@ -50,7 +50,7 @@ src/main/api/snapshot.sigfile strictcheck - com.fnproject.fn.api,com.fnproject.fn.api.exception,com.fnproject.fn.api.flow + com.fnproject.fn.api,com.fnproject.fn.api.exception diff --git a/api/src/main/api/snapshot.sigfile b/api/src/main/api/snapshot.sigfile index 67479c47..2ed59945 100644 --- a/api/src/main/api/snapshot.sigfile +++ b/api/src/main/api/snapshot.sigfile @@ -33,6 +33,7 @@ supr java.lang.Enum CLSS public final com.fnproject.fn.api.Headers intf java.io.Serializable +meth public java.util.Map getAll() meth public !varargs com.fnproject.fn.api.Headers addHeader(java.lang.String,java.lang.String,java.lang.String[]) meth public !varargs com.fnproject.fn.api.Headers setHeader(java.lang.String,java.lang.String,java.lang.String[]) meth public boolean equals(java.lang.Object) @@ -170,6 +171,17 @@ cons public init(java.lang.String) cons public init(java.lang.String,java.lang.Exception) supr java.lang.RuntimeException + +CLSS public abstract interface com.fnproject.fn.api.httpgateway.HTTPGatewayContext +meth public abstract InvocationContext getInvocationContext() +meth public abstract Headers getHeaders() +meth public abstract String getRequestURL() +meth public abstract String getMethod() +meth public abstract QueryParameters getQueryParameters() +meth public abstract void addResponseHeader(String key, String value) +meth public abstract void setResponseHeader(String key, String v1, String... vs) +meth public abstract void setStatusCode(int code) + CLSS public abstract interface java.io.Closeable intf java.lang.AutoCloseable meth public abstract void close() throws java.io.IOException diff --git a/api/src/main/java/com/fnproject/fn/api/Headers.java b/api/src/main/java/com/fnproject/fn/api/Headers.java index 75a35a4a..7029e909 100644 --- a/api/src/main/java/com/fnproject/fn/api/Headers.java +++ b/api/src/main/java/com/fnproject/fn/api/Headers.java @@ -32,6 +32,9 @@ private Headers(Map> headersIn) { private static Pattern headerName = Pattern.compile("[A-Za-z0-9!#%&'*+-.^_`|~]+"); + public Map getAll() { + return headers; + } /** * Calculates the canonical key (cf RFC 7230) for a header diff --git a/flow-runtime/src/main/java/com/fnproject/fn/runtime/flow/RemoteFlowApiClient.java b/flow-runtime/src/main/java/com/fnproject/fn/runtime/flow/RemoteFlowApiClient.java index 872b5653..a60bf452 100644 --- a/flow-runtime/src/main/java/com/fnproject/fn/runtime/flow/RemoteFlowApiClient.java +++ b/flow-runtime/src/main/java/com/fnproject/fn/runtime/flow/RemoteFlowApiClient.java @@ -121,6 +121,9 @@ public CompletionId invokeFunction(FlowId flowId, String functionId, byte[] data httpReq.headers = new ArrayList<>(); headers.asMap().forEach((k, vs) -> vs.forEach(v -> httpReq.headers.add(APIModel.HTTPHeader.create(k, v)))); + + Map> headersMap = headers.asMap(); + headersMap.forEach((key, values) -> values.forEach(value -> httpReq.headers.add(APIModel.HTTPHeader.create(key, value)))); } httpReq.method = APIModel.HTTPMethod.fromFlow(method); diff --git a/flow-runtime/src/test/java/com/fnproject/fn/runtime/flow/RemoteFlowApiClientTest.java b/flow-runtime/src/test/java/com/fnproject/fn/runtime/flow/RemoteFlowApiClientTest.java index 1f76e0d8..2798e083 100644 --- a/flow-runtime/src/test/java/com/fnproject/fn/runtime/flow/RemoteFlowApiClientTest.java +++ b/flow-runtime/src/test/java/com/fnproject/fn/runtime/flow/RemoteFlowApiClientTest.java @@ -22,6 +22,7 @@ import java.io.ObjectOutputStream; import java.util.Collections; import java.util.List; +import java.util.Map; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertNotNull; @@ -130,7 +131,10 @@ public void invokeFunctionWithInvalidFunctionId() throws Exception { thrown.expectMessage("Failed to add stage"); // When - completerClient.invokeFunction(new FlowId(testFlowId), testFunctionId, invokeBody, HttpMethod.POST, Headers.fromMap(Collections.singletonMap("Content-type", contentType)), locationFn()); + Map headersMap = Collections.singletonMap("Content-type", contentType); +// Headers headers = Headers.fromMap(headersMap); + Headers headers = null; + completerClient.invokeFunction(new FlowId(testFlowId), testFunctionId, invokeBody, HttpMethod.POST, headers, locationFn()); } @Test diff --git a/images/build/pom.xml b/images/build/pom.xml index 2a2e01cc..0e49b548 100644 --- a/images/build/pom.xml +++ b/images/build/pom.xml @@ -55,6 +55,14 @@ 1.8 + + org.apache.maven.plugins + maven-surefire-plugin + 2.17 + + -Djdk.net.URLClassPath.disableClassPathURLCheck=true + + org.apache.maven.plugins maven-deploy-plugin diff --git a/images/init-native/pom.xml b/images/init-native/pom.xml index 9bb5db9e..f3fda442 100644 --- a/images/init-native/pom.xml +++ b/images/init-native/pom.xml @@ -5,7 +5,7 @@ 4.0.0 UTF-8 - 1.0.0-SNAPSHOT + 1.0.76 com.example.fn hello diff --git a/runtime/src/main/java/com/fnproject/fn/runtime/ntv/UnixSocketNative.java b/runtime/src/main/java/com/fnproject/fn/runtime/ntv/UnixSocketNative.java index 560c55ce..0dd06fda 100644 --- a/runtime/src/main/java/com/fnproject/fn/runtime/ntv/UnixSocketNative.java +++ b/runtime/src/main/java/com/fnproject/fn/runtime/ntv/UnixSocketNative.java @@ -10,6 +10,8 @@ */ class UnixSocketNative { + public UnixSocketNative() {} + static { String lib = System.mapLibraryName("fnunixsocket"); From 1e6091294a0701655c533ad2b7fc87cb7a1bb9d0 Mon Sep 17 00:00:00 2001 From: Rik Gibson Date: Tue, 20 Nov 2018 01:37:02 +0000 Subject: [PATCH 063/310] Remove comment --- .../com/fnproject/fn/runtime/flow/RemoteFlowApiClientTest.java | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/flow-runtime/src/test/java/com/fnproject/fn/runtime/flow/RemoteFlowApiClientTest.java b/flow-runtime/src/test/java/com/fnproject/fn/runtime/flow/RemoteFlowApiClientTest.java index 2798e083..72388243 100644 --- a/flow-runtime/src/test/java/com/fnproject/fn/runtime/flow/RemoteFlowApiClientTest.java +++ b/flow-runtime/src/test/java/com/fnproject/fn/runtime/flow/RemoteFlowApiClientTest.java @@ -132,8 +132,7 @@ public void invokeFunctionWithInvalidFunctionId() throws Exception { // When Map headersMap = Collections.singletonMap("Content-type", contentType); -// Headers headers = Headers.fromMap(headersMap); - Headers headers = null; + Headers headers = Headers.fromMap(headersMap); completerClient.invokeFunction(new FlowId(testFlowId), testFunctionId, invokeBody, HttpMethod.POST, headers, locationFn()); } From 0e156e9c95ab9f25c07f7b8a15c24d489a3f1ad7 Mon Sep 17 00:00:00 2001 From: Rik Gibson Date: Tue, 20 Nov 2018 11:48:30 +0000 Subject: [PATCH 064/310] Include some CI fixes from @tteggel --- .circleci/config.yml | 3 +++ .circleci/fix-java-for-surefire.sh | 19 +++++++++++++++++++ integration-tests/pom.xml | 18 +++++++++++------- pom.xml | 17 ++++++----------- 4 files changed, 39 insertions(+), 18 deletions(-) create mode 100644 .circleci/fix-java-for-surefire.sh diff --git a/.circleci/config.yml b/.circleci/config.yml index 23fe9b7a..e8a142bf 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -17,6 +17,9 @@ jobs: - run: name: Install fn binary (as it is needed for the integration tests) command: ./.circleci/install-fn.sh + - run: + name: Workaround for https://issues.apache.org/jira/browse/SUREFIRE-1588 + command: ./.circleci/fix-java-for-surefire.sh - run: name: Install junit-merge command: npm install -g junit-merge diff --git a/.circleci/fix-java-for-surefire.sh b/.circleci/fix-java-for-surefire.sh new file mode 100644 index 00000000..fb00731c --- /dev/null +++ b/.circleci/fix-java-for-surefire.sh @@ -0,0 +1,19 @@ +#!/usr/bin/env bash + + set -ex + + cat << 'EOF' > $HOME/.m2/settings.xml + + + + SUREFIRE-1588 + + true + + + -Djdk.net.URLClassPath.disableClassPathURLCheck=true + + + + + EOF \ No newline at end of file diff --git a/integration-tests/pom.xml b/integration-tests/pom.xml index 8eb7e9ad..28483af2 100644 --- a/integration-tests/pom.xml +++ b/integration-tests/pom.xml @@ -3,17 +3,17 @@ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> - 4.0.0 com.fnproject integration-tests 1.0.0-SNAPSHOT + 3.6.2 + 2.5 2.9.6 4.12 - 2.5 - 3.6.2 + 2.22.1 jar @@ -28,19 +28,16 @@ junit ${junit.version} - org.assertj assertj-core ${assertj-core.version} - com.fasterxml.jackson.core jackson-databind ${jackson.version} - com.fasterxml.jackson.core jackson-core @@ -72,7 +69,14 @@ true + + org.apache.maven.plugins + maven-surefire-plugin + ${surefire.version} + + false + + - diff --git a/pom.xml b/pom.xml index be1c5883..9276e6d3 100644 --- a/pom.xml +++ b/pom.xml @@ -21,31 +21,26 @@ flow-testing fn-spring-cloud-function examples - UTF-8 UTF-8 - 9.4.12.v20180830 - + 3.10.0 + 2.6 + 4.4.10 + 2.9.7 0.8.1 + 9.4.12.v20180830 4.12 2.21.0 - 3.10.0 1.4.0 - 1.7.25 - - 2.6 - 2.9.7 - 4.4.10 - + 2.22.1 1.16.0 - From 8eb37b5603cdd2e441f125be85d992e41b6e6b4a Mon Sep 17 00:00:00 2001 From: Rik Gibson Date: Tue, 20 Nov 2018 12:12:36 +0000 Subject: [PATCH 065/310] Update file permissions on surefire CI fix script --- .circleci/fix-java-for-surefire.sh | 0 1 file changed, 0 insertions(+), 0 deletions(-) mode change 100644 => 100755 .circleci/fix-java-for-surefire.sh diff --git a/.circleci/fix-java-for-surefire.sh b/.circleci/fix-java-for-surefire.sh old mode 100644 new mode 100755 From 51c1cb48b3cca4b2ef37a6d9077353c2397ae0a0 Mon Sep 17 00:00:00 2001 From: Rik Gibson Date: Tue, 20 Nov 2018 12:29:16 +0000 Subject: [PATCH 066/310] Remove old default and http formats from boilerplate test --- .../java/com/fnproject/fn/integrationtest/FunctionsTest.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/integration-tests/src/test/java/com/fnproject/fn/integrationtest/FunctionsTest.java b/integration-tests/src/test/java/com/fnproject/fn/integrationtest/FunctionsTest.java index 1be6f34a..b01a34e1 100644 --- a/integration-tests/src/test/java/com/fnproject/fn/integrationtest/FunctionsTest.java +++ b/integration-tests/src/test/java/com/fnproject/fn/integrationtest/FunctionsTest.java @@ -45,7 +45,7 @@ public void shouldCallExistingFn() throws Exception { @Test() public void checkBoilerPlate() throws Exception { - for (String format : new String[]{"default", "http", "http-stream"}) { + for (String format : new String[]{"http-stream"}) { for (String runtime : new String[]{"java9", "java8"}) { IntegrationTestRule.TestContext tc = testRule.newTest(); String fnName = "bp" + format + runtime; From 1771916141ec8f0097d29b0e7a0faec16aeebf82 Mon Sep 17 00:00:00 2001 From: Rik Gibson Date: Tue, 20 Nov 2018 15:28:27 +0000 Subject: [PATCH 067/310] Add some logging to boilerplate test --- .../com/fnproject/fn/integrationtest/FunctionsTest.java | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/integration-tests/src/test/java/com/fnproject/fn/integrationtest/FunctionsTest.java b/integration-tests/src/test/java/com/fnproject/fn/integrationtest/FunctionsTest.java index b01a34e1..21cc7a54 100644 --- a/integration-tests/src/test/java/com/fnproject/fn/integrationtest/FunctionsTest.java +++ b/integration-tests/src/test/java/com/fnproject/fn/integrationtest/FunctionsTest.java @@ -11,6 +11,8 @@ import java.net.URL; import java.util.HashMap; import java.util.Map; +import java.util.logging.Logger; +import java.util.logging.Level; import static org.assertj.core.api.Assertions.assertThat; @@ -54,6 +56,10 @@ public void checkBoilerPlate() throws Exception { tc.rewritePOM(); tc.runFn("--verbose", "deploy", "--app", tc.appName(), "--local"); CmdResult rs = tc.runFnWithInput("wibble", "invoke", tc.appName(), fnName); + System.out.println("TEST OUT: " + rs.getStdout()); + System.out.println("TEST ERR: " + rs.getStderr()); + Logger.getAnonymousLogger.log(Level.INFO, "TEST OUT: " + rs.getStdout()); + Logger.getAnonymousLogger.log(Level.INFO, "TEST ERR: " + rs.getStderr()); assertThat(rs.getStdout()).contains("Hello, wibble!"); } } From e447d4219d29366be0c06ab32fe08630575cf2a0 Mon Sep 17 00:00:00 2001 From: Rik Gibson Date: Tue, 20 Nov 2018 15:39:12 +0000 Subject: [PATCH 068/310] Update FunctionsTest.java --- .../java/com/fnproject/fn/integrationtest/FunctionsTest.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/integration-tests/src/test/java/com/fnproject/fn/integrationtest/FunctionsTest.java b/integration-tests/src/test/java/com/fnproject/fn/integrationtest/FunctionsTest.java index 21cc7a54..430e72f6 100644 --- a/integration-tests/src/test/java/com/fnproject/fn/integrationtest/FunctionsTest.java +++ b/integration-tests/src/test/java/com/fnproject/fn/integrationtest/FunctionsTest.java @@ -58,8 +58,8 @@ public void checkBoilerPlate() throws Exception { CmdResult rs = tc.runFnWithInput("wibble", "invoke", tc.appName(), fnName); System.out.println("TEST OUT: " + rs.getStdout()); System.out.println("TEST ERR: " + rs.getStderr()); - Logger.getAnonymousLogger.log(Level.INFO, "TEST OUT: " + rs.getStdout()); - Logger.getAnonymousLogger.log(Level.INFO, "TEST ERR: " + rs.getStderr()); + Logger.getAnonymousLogger().log(Level.INFO, "TEST OUT: " + rs.getStdout()); + Logger.getAnonymousLogger().log(Level.INFO, "TEST ERR: " + rs.getStderr()); assertThat(rs.getStdout()).contains("Hello, wibble!"); } } From dfd9faaa21fd63e06bd1e0de2fa75b2145738229 Mon Sep 17 00:00:00 2001 From: Rik Gibson Date: Tue, 20 Nov 2018 16:11:24 +0000 Subject: [PATCH 069/310] Update FunctionsTest.java --- .../java/com/fnproject/fn/integrationtest/FunctionsTest.java | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/integration-tests/src/test/java/com/fnproject/fn/integrationtest/FunctionsTest.java b/integration-tests/src/test/java/com/fnproject/fn/integrationtest/FunctionsTest.java index 430e72f6..f558f1da 100644 --- a/integration-tests/src/test/java/com/fnproject/fn/integrationtest/FunctionsTest.java +++ b/integration-tests/src/test/java/com/fnproject/fn/integrationtest/FunctionsTest.java @@ -56,10 +56,7 @@ public void checkBoilerPlate() throws Exception { tc.rewritePOM(); tc.runFn("--verbose", "deploy", "--app", tc.appName(), "--local"); CmdResult rs = tc.runFnWithInput("wibble", "invoke", tc.appName(), fnName); - System.out.println("TEST OUT: " + rs.getStdout()); - System.out.println("TEST ERR: " + rs.getStderr()); - Logger.getAnonymousLogger().log(Level.INFO, "TEST OUT: " + rs.getStdout()); - Logger.getAnonymousLogger().log(Level.INFO, "TEST ERR: " + rs.getStderr()); + assertEquals("BP output=" + rs.getStdout(), "Hello, wibble!", rs.getStdout()); assertThat(rs.getStdout()).contains("Hello, wibble!"); } } From ee48ff6b30ab1397edbb11e44fa29c3ac8a15ab6 Mon Sep 17 00:00:00 2001 From: Rik Gibson Date: Tue, 20 Nov 2018 16:30:02 +0000 Subject: [PATCH 070/310] Update FunctionsTest.java --- .../java/com/fnproject/fn/integrationtest/FunctionsTest.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/integration-tests/src/test/java/com/fnproject/fn/integrationtest/FunctionsTest.java b/integration-tests/src/test/java/com/fnproject/fn/integrationtest/FunctionsTest.java index f558f1da..3e62bba1 100644 --- a/integration-tests/src/test/java/com/fnproject/fn/integrationtest/FunctionsTest.java +++ b/integration-tests/src/test/java/com/fnproject/fn/integrationtest/FunctionsTest.java @@ -3,6 +3,7 @@ import com.fasterxml.jackson.annotation.JsonIgnoreProperties; import com.fasterxml.jackson.databind.ObjectMapper; import com.fnproject.fn.integrationtest.IntegrationTestRule.CmdResult; +import org.junit.Assert; import org.junit.Rule; import org.junit.Test; @@ -56,7 +57,7 @@ public void checkBoilerPlate() throws Exception { tc.rewritePOM(); tc.runFn("--verbose", "deploy", "--app", tc.appName(), "--local"); CmdResult rs = tc.runFnWithInput("wibble", "invoke", tc.appName(), fnName); - assertEquals("BP output=" + rs.getStdout(), "Hello, wibble!", rs.getStdout()); + Assert.assertEquals("BP output=" + rs.getStdout(), "Hello, wibble!", rs.getStdout()); assertThat(rs.getStdout()).contains("Hello, wibble!"); } } From 1cb7a1de2e349d7e28dd9408ac768936ef707675 Mon Sep 17 00:00:00 2001 From: Rik Gibson Date: Tue, 20 Nov 2018 16:32:05 +0000 Subject: [PATCH 071/310] Update FunctionsTest.java --- .../java/com/fnproject/fn/integrationtest/FunctionsTest.java | 1 + 1 file changed, 1 insertion(+) diff --git a/integration-tests/src/test/java/com/fnproject/fn/integrationtest/FunctionsTest.java b/integration-tests/src/test/java/com/fnproject/fn/integrationtest/FunctionsTest.java index 3e62bba1..3e61b812 100644 --- a/integration-tests/src/test/java/com/fnproject/fn/integrationtest/FunctionsTest.java +++ b/integration-tests/src/test/java/com/fnproject/fn/integrationtest/FunctionsTest.java @@ -57,6 +57,7 @@ public void checkBoilerPlate() throws Exception { tc.rewritePOM(); tc.runFn("--verbose", "deploy", "--app", tc.appName(), "--local"); CmdResult rs = tc.runFnWithInput("wibble", "invoke", tc.appName(), fnName); + System.err.println("FN OUT: " + rs.getStdout()); Assert.assertEquals("BP output=" + rs.getStdout(), "Hello, wibble!", rs.getStdout()); assertThat(rs.getStdout()).contains("Hello, wibble!"); } From 57c299c2a6e3b920fb4c259742a003ce2628758f Mon Sep 17 00:00:00 2001 From: Rik Gibson Date: Tue, 20 Nov 2018 16:43:25 +0000 Subject: [PATCH 072/310] Update FunctionsTest.java --- .../java/com/fnproject/fn/integrationtest/FunctionsTest.java | 3 --- 1 file changed, 3 deletions(-) diff --git a/integration-tests/src/test/java/com/fnproject/fn/integrationtest/FunctionsTest.java b/integration-tests/src/test/java/com/fnproject/fn/integrationtest/FunctionsTest.java index 3e61b812..d077e5d4 100644 --- a/integration-tests/src/test/java/com/fnproject/fn/integrationtest/FunctionsTest.java +++ b/integration-tests/src/test/java/com/fnproject/fn/integrationtest/FunctionsTest.java @@ -3,7 +3,6 @@ import com.fasterxml.jackson.annotation.JsonIgnoreProperties; import com.fasterxml.jackson.databind.ObjectMapper; import com.fnproject.fn.integrationtest.IntegrationTestRule.CmdResult; -import org.junit.Assert; import org.junit.Rule; import org.junit.Test; @@ -57,8 +56,6 @@ public void checkBoilerPlate() throws Exception { tc.rewritePOM(); tc.runFn("--verbose", "deploy", "--app", tc.appName(), "--local"); CmdResult rs = tc.runFnWithInput("wibble", "invoke", tc.appName(), fnName); - System.err.println("FN OUT: " + rs.getStdout()); - Assert.assertEquals("BP output=" + rs.getStdout(), "Hello, wibble!", rs.getStdout()); assertThat(rs.getStdout()).contains("Hello, wibble!"); } } From 74bab4fbe6d4bcf3aab46247b3b81e5b751495e6 Mon Sep 17 00:00:00 2001 From: Rik Gibson Date: Tue, 20 Nov 2018 16:50:49 +0000 Subject: [PATCH 073/310] Added some output to help if fn operation fails --- .../fnproject/fn/integrationtest/IntegrationTestRule.java | 8 ++++++-- .../com/fnproject/fn/integrationtest/FunctionsTest.java | 6 ------ 2 files changed, 6 insertions(+), 8 deletions(-) diff --git a/integration-tests/src/main/java/com/fnproject/fn/integrationtest/IntegrationTestRule.java b/integration-tests/src/main/java/com/fnproject/fn/integrationtest/IntegrationTestRule.java index 19370b38..914f2bb1 100644 --- a/integration-tests/src/main/java/com/fnproject/fn/integrationtest/IntegrationTestRule.java +++ b/integration-tests/src/main/java/com/fnproject/fn/integrationtest/IntegrationTestRule.java @@ -112,7 +112,6 @@ private CmdResult(String cmd, boolean success, String stdout, String stderr) { boolean isSuccess() { return success; - } public String getStdout() { @@ -123,7 +122,9 @@ public String getStderr() { return stderr; } - + public String toString() { + return "CmdResult: cmd=" + cmd + ", success=" + success + ", stdout=" + stdout + ", stderr=" + stderr; + } } public class TestContext { @@ -151,6 +152,9 @@ public TestContext withDirFrom(String location) throws IOException { public CmdResult runFnWithInput(String input, String... args) throws Exception { CmdResult res = runFnWithInputAllowError(input, args); + if (!res.isSuccess()) { + System.err.println(res); + } Assertions.assertThat(res.isSuccess()).withFailMessage("Expected command '" + res.cmd + "' to return 0").isTrue(); return res; } diff --git a/integration-tests/src/test/java/com/fnproject/fn/integrationtest/FunctionsTest.java b/integration-tests/src/test/java/com/fnproject/fn/integrationtest/FunctionsTest.java index 21cc7a54..a5ba1978 100644 --- a/integration-tests/src/test/java/com/fnproject/fn/integrationtest/FunctionsTest.java +++ b/integration-tests/src/test/java/com/fnproject/fn/integrationtest/FunctionsTest.java @@ -35,11 +35,9 @@ public void shouldCallExistingFn() throws Exception { tc.runFn("--verbose", "deploy", "--app", tc.appName(), "--local"); tc.runFn("config", "app", tc.appName(), "GREETING", "Salutations"); - CmdResult r1 = tc.runFnWithInput("", "invoke", tc.appName(), "simplefunc"); assertThat(r1.getStdout()).isEqualTo("Salutations, world!"); - CmdResult r2 = tc.runFnWithInput("tests", "invoke", tc.appName(), "simplefunc"); assertThat(r2.getStdout()).isEqualTo("Salutations, tests!"); @@ -56,10 +54,6 @@ public void checkBoilerPlate() throws Exception { tc.rewritePOM(); tc.runFn("--verbose", "deploy", "--app", tc.appName(), "--local"); CmdResult rs = tc.runFnWithInput("wibble", "invoke", tc.appName(), fnName); - System.out.println("TEST OUT: " + rs.getStdout()); - System.out.println("TEST ERR: " + rs.getStderr()); - Logger.getAnonymousLogger.log(Level.INFO, "TEST OUT: " + rs.getStdout()); - Logger.getAnonymousLogger.log(Level.INFO, "TEST ERR: " + rs.getStderr()); assertThat(rs.getStdout()).contains("Hello, wibble!"); } } From a9b16c927cb76578dcb0b04f883aca3e6fc6c5d2 Mon Sep 17 00:00:00 2001 From: Rik Gibson Date: Tue, 20 Nov 2018 17:01:25 +0000 Subject: [PATCH 074/310] Update IntegrationTestRule.java --- .../fnproject/fn/integrationtest/IntegrationTestRule.java | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/integration-tests/src/main/java/com/fnproject/fn/integrationtest/IntegrationTestRule.java b/integration-tests/src/main/java/com/fnproject/fn/integrationtest/IntegrationTestRule.java index 914f2bb1..19bf39ec 100644 --- a/integration-tests/src/main/java/com/fnproject/fn/integrationtest/IntegrationTestRule.java +++ b/integration-tests/src/main/java/com/fnproject/fn/integrationtest/IntegrationTestRule.java @@ -152,9 +152,9 @@ public TestContext withDirFrom(String location) throws IOException { public CmdResult runFnWithInput(String input, String... args) throws Exception { CmdResult res = runFnWithInputAllowError(input, args); - if (!res.isSuccess()) { - System.err.println(res); - } +// if (!res.isSuccess()) { +// System.out.println(res); +// } Assertions.assertThat(res.isSuccess()).withFailMessage("Expected command '" + res.cmd + "' to return 0").isTrue(); return res; } From f6ca1de509b642689e31166c8da4a3fd7c4b8d54 Mon Sep 17 00:00:00 2001 From: Rik Gibson Date: Tue, 20 Nov 2018 17:48:30 +0000 Subject: [PATCH 075/310] Update IntegrationTestRule.java --- .../fnproject/fn/integrationtest/IntegrationTestRule.java | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/integration-tests/src/main/java/com/fnproject/fn/integrationtest/IntegrationTestRule.java b/integration-tests/src/main/java/com/fnproject/fn/integrationtest/IntegrationTestRule.java index 19bf39ec..f8a6b533 100644 --- a/integration-tests/src/main/java/com/fnproject/fn/integrationtest/IntegrationTestRule.java +++ b/integration-tests/src/main/java/com/fnproject/fn/integrationtest/IntegrationTestRule.java @@ -152,9 +152,9 @@ public TestContext withDirFrom(String location) throws IOException { public CmdResult runFnWithInput(String input, String... args) throws Exception { CmdResult res = runFnWithInputAllowError(input, args); -// if (!res.isSuccess()) { -// System.out.println(res); -// } + if (res.isSuccess() == false) { + System.out.println(res.toString()); + } Assertions.assertThat(res.isSuccess()).withFailMessage("Expected command '" + res.cmd + "' to return 0").isTrue(); return res; } From a58139ad9bf34e8505ee6bc1b44af6537d40c77a Mon Sep 17 00:00:00 2001 From: Rik Gibson Date: Tue, 20 Nov 2018 18:39:59 +0000 Subject: [PATCH 076/310] Update IntegrationTestRule.java --- .../com/fnproject/fn/integrationtest/IntegrationTestRule.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/integration-tests/src/main/java/com/fnproject/fn/integrationtest/IntegrationTestRule.java b/integration-tests/src/main/java/com/fnproject/fn/integrationtest/IntegrationTestRule.java index f8a6b533..64bf796d 100644 --- a/integration-tests/src/main/java/com/fnproject/fn/integrationtest/IntegrationTestRule.java +++ b/integration-tests/src/main/java/com/fnproject/fn/integrationtest/IntegrationTestRule.java @@ -155,7 +155,7 @@ public CmdResult runFnWithInput(String input, String... args) throws Exception { if (res.isSuccess() == false) { System.out.println(res.toString()); } - Assertions.assertThat(res.isSuccess()).withFailMessage("Expected command '" + res.cmd + "' to return 0").isTrue(); + Assertions.assertThat(res.isSuccess()).withFailMessage("Expected command '" + res.cmd + "' to return 0. " + res).isTrue(); return res; } From 0218beaeeac7622a6470981bef268390531f2e60 Mon Sep 17 00:00:00 2001 From: Rik Gibson Date: Wed, 21 Nov 2018 13:39:55 +0000 Subject: [PATCH 077/310] Update pom.xml --- images/build/pom.xml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/images/build/pom.xml b/images/build/pom.xml index 0e49b548..da894edb 100644 --- a/images/build/pom.xml +++ b/images/build/pom.xml @@ -60,7 +60,8 @@ maven-surefire-plugin 2.17 - -Djdk.net.URLClassPath.disableClassPathURLCheck=true + + false From bfe4b151dda720ef64a0a298ce1b41c5f818ff39 Mon Sep 17 00:00:00 2001 From: Rik Gibson Date: Wed, 21 Nov 2018 14:27:25 +0000 Subject: [PATCH 078/310] tweak to surefire version and config --- images/build/pom.xml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/images/build/pom.xml b/images/build/pom.xml index 0e49b548..0a5ab9ad 100644 --- a/images/build/pom.xml +++ b/images/build/pom.xml @@ -58,9 +58,9 @@ org.apache.maven.plugins maven-surefire-plugin - 2.17 + 2.22.1 - -Djdk.net.URLClassPath.disableClassPathURLCheck=true + false From 6f5493cb08e5a2958ab73e9b6b96a9b2f2478035 Mon Sep 17 00:00:00 2001 From: Rik Gibson Date: Thu, 22 Nov 2018 15:47:25 +0000 Subject: [PATCH 079/310] Add specific 8-friendly test and pom for boilerplate test. --- integration-tests/funcs/helloFunc/func.yaml | 6 ++ integration-tests/funcs/helloFunc/pom.xml | 68 +++++++++++++++++++ .../fn/integration/hello/HelloFunction.java | 8 +++ .../integrationtest/IntegrationTestRule.java | 5 +- .../fn/integrationtest/FunctionsTest.java | 3 +- 5 files changed, 87 insertions(+), 3 deletions(-) create mode 100644 integration-tests/funcs/helloFunc/func.yaml create mode 100644 integration-tests/funcs/helloFunc/pom.xml create mode 100644 integration-tests/funcs/helloFunc/src/main/java/com/fnproject/fn/integration/hello/HelloFunction.java diff --git a/integration-tests/funcs/helloFunc/func.yaml b/integration-tests/funcs/helloFunc/func.yaml new file mode 100644 index 00000000..e43cf9f4 --- /dev/null +++ b/integration-tests/funcs/helloFunc/func.yaml @@ -0,0 +1,6 @@ +schema_version: 20180708 +name: hellofunc +version: 0.0.1 +runtime: java8 +cmd: com.fnproject.fn.integration.hello.HelloFunction::handleRequest +format: http-stream \ No newline at end of file diff --git a/integration-tests/funcs/helloFunc/pom.xml b/integration-tests/funcs/helloFunc/pom.xml new file mode 100644 index 00000000..3d35af89 --- /dev/null +++ b/integration-tests/funcs/helloFunc/pom.xml @@ -0,0 +1,68 @@ + + + 4.0.0 + + UTF-8 + 1.0.0-SNAPSHOT + + com.example.fn + hello-func + 1.0.0 + + + + fn-release-repo + https://dl.bintray.com/fnproject/fnproject + + + + + + com.fnproject.fn + api + ${fdk.version} + + + com.fnproject.fn + testing-core + ${fdk.version} + test + + + com.fnproject.fn + testing-junit4 + ${fdk.version} + test + + + junit + junit + 4.12 + test + + + + + + + org.apache.maven.plugins + maven-compiler-plugin + 3.3 + + 8 + 8 + + + + org.apache.maven.plugins + maven-surefire-plugin + 2.22.1 + + false + + + + + diff --git a/integration-tests/funcs/helloFunc/src/main/java/com/fnproject/fn/integration/hello/HelloFunction.java b/integration-tests/funcs/helloFunc/src/main/java/com/fnproject/fn/integration/hello/HelloFunction.java new file mode 100644 index 00000000..7efa98ab --- /dev/null +++ b/integration-tests/funcs/helloFunc/src/main/java/com/fnproject/fn/integration/hello/HelloFunction.java @@ -0,0 +1,8 @@ +package com.fnproject.fn.integration.hello; + +public class HelloFunction { + public String handleRequest(String input) { + String name = (input == null || input.isEmpty()) ? "world" : input; + return "Hello, " + name + "!"; + } +} \ No newline at end of file diff --git a/integration-tests/src/main/java/com/fnproject/fn/integrationtest/IntegrationTestRule.java b/integration-tests/src/main/java/com/fnproject/fn/integrationtest/IntegrationTestRule.java index 64bf796d..a2d1c252 100644 --- a/integration-tests/src/main/java/com/fnproject/fn/integrationtest/IntegrationTestRule.java +++ b/integration-tests/src/main/java/com/fnproject/fn/integrationtest/IntegrationTestRule.java @@ -153,9 +153,10 @@ public CmdResult runFnWithInput(String input, String... args) throws Exception { CmdResult res = runFnWithInputAllowError(input, args); if (res.isSuccess() == false) { - System.out.println(res.toString()); + System.err.println(res.toString()); } - Assertions.assertThat(res.isSuccess()).withFailMessage("Expected command '" + res.cmd + "' to return 0. " + res).isTrue(); + + Assertions.assertThat(res.isSuccess()).withFailMessage("Expected command '" + res.cmd + "' to return 0.").isTrue(); return res; } diff --git a/integration-tests/src/test/java/com/fnproject/fn/integrationtest/FunctionsTest.java b/integration-tests/src/test/java/com/fnproject/fn/integrationtest/FunctionsTest.java index a5ba1978..d611785a 100644 --- a/integration-tests/src/test/java/com/fnproject/fn/integrationtest/FunctionsTest.java +++ b/integration-tests/src/test/java/com/fnproject/fn/integrationtest/FunctionsTest.java @@ -48,8 +48,9 @@ public void checkBoilerPlate() throws Exception { for (String format : new String[]{"http-stream"}) { for (String runtime : new String[]{"java9", "java8"}) { IntegrationTestRule.TestContext tc = testRule.newTest(); - String fnName = "bp" + format + runtime; + tc.withDirFrom("funcs/hellofunc"); + String fnName = "bp" + format + runtime; tc.runFn("init", "--runtime", runtime, "--name", fnName, "--format", format); tc.rewritePOM(); tc.runFn("--verbose", "deploy", "--app", tc.appName(), "--local"); From 27e3a42213c7a474353fb332b952e37842fef278 Mon Sep 17 00:00:00 2001 From: Rik Gibson Date: Thu, 22 Nov 2018 16:26:54 +0000 Subject: [PATCH 080/310] Update FunctionsTest.java --- .../java/com/fnproject/fn/integrationtest/FunctionsTest.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/integration-tests/src/test/java/com/fnproject/fn/integrationtest/FunctionsTest.java b/integration-tests/src/test/java/com/fnproject/fn/integrationtest/FunctionsTest.java index d611785a..b795f3e3 100644 --- a/integration-tests/src/test/java/com/fnproject/fn/integrationtest/FunctionsTest.java +++ b/integration-tests/src/test/java/com/fnproject/fn/integrationtest/FunctionsTest.java @@ -48,7 +48,7 @@ public void checkBoilerPlate() throws Exception { for (String format : new String[]{"http-stream"}) { for (String runtime : new String[]{"java9", "java8"}) { IntegrationTestRule.TestContext tc = testRule.newTest(); - tc.withDirFrom("funcs/hellofunc"); + tc.withDirFrom("funcs/helloFunc"); String fnName = "bp" + format + runtime; tc.runFn("init", "--runtime", runtime, "--name", fnName, "--format", format); From 5ec9635f35c651b785b68f07ced14d30bfae3ebd Mon Sep 17 00:00:00 2001 From: Rik Gibson Date: Thu, 22 Nov 2018 16:46:03 +0000 Subject: [PATCH 081/310] Another attempt at logging a failed result...sigh --- .../com/fnproject/fn/integrationtest/IntegrationTestRule.java | 3 ++- .../java/com/fnproject/fn/integrationtest/FunctionsTest.java | 2 +- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/integration-tests/src/main/java/com/fnproject/fn/integrationtest/IntegrationTestRule.java b/integration-tests/src/main/java/com/fnproject/fn/integrationtest/IntegrationTestRule.java index a2d1c252..f190dc11 100644 --- a/integration-tests/src/main/java/com/fnproject/fn/integrationtest/IntegrationTestRule.java +++ b/integration-tests/src/main/java/com/fnproject/fn/integrationtest/IntegrationTestRule.java @@ -153,10 +153,11 @@ public CmdResult runFnWithInput(String input, String... args) throws Exception { CmdResult res = runFnWithInputAllowError(input, args); if (res.isSuccess() == false) { + System.err.println("FN FAIL!"); System.err.println(res.toString()); } - Assertions.assertThat(res.isSuccess()).withFailMessage("Expected command '" + res.cmd + "' to return 0.").isTrue(); + Assertions.assertThat(res.isSuccess()).withFailMessage("Expected command '" + res.cmd + "' to return 0." + "FN FAIL: " + res).isTrue(); return res; } diff --git a/integration-tests/src/test/java/com/fnproject/fn/integrationtest/FunctionsTest.java b/integration-tests/src/test/java/com/fnproject/fn/integrationtest/FunctionsTest.java index d611785a..b795f3e3 100644 --- a/integration-tests/src/test/java/com/fnproject/fn/integrationtest/FunctionsTest.java +++ b/integration-tests/src/test/java/com/fnproject/fn/integrationtest/FunctionsTest.java @@ -48,7 +48,7 @@ public void checkBoilerPlate() throws Exception { for (String format : new String[]{"http-stream"}) { for (String runtime : new String[]{"java9", "java8"}) { IntegrationTestRule.TestContext tc = testRule.newTest(); - tc.withDirFrom("funcs/hellofunc"); + tc.withDirFrom("funcs/helloFunc"); String fnName = "bp" + format + runtime; tc.runFn("init", "--runtime", runtime, "--name", fnName, "--format", format); From 0b05257ae24bc3ac5edea5ad9167742ff8e529e8 Mon Sep 17 00:00:00 2001 From: Rik Gibson Date: Thu, 22 Nov 2018 17:10:30 +0000 Subject: [PATCH 082/310] Rename func.yaml to prevent overwrite --- integration-tests/funcs/helloFunc/{func.yaml => func-proto.yaml} | 0 .../java/com/fnproject/fn/integration/hello/HelloFunction.java | 0 2 files changed, 0 insertions(+), 0 deletions(-) rename integration-tests/funcs/helloFunc/{func.yaml => func-proto.yaml} (100%) rename integration-tests/funcs/helloFunc/{src => src-proto}/main/java/com/fnproject/fn/integration/hello/HelloFunction.java (100%) diff --git a/integration-tests/funcs/helloFunc/func.yaml b/integration-tests/funcs/helloFunc/func-proto.yaml similarity index 100% rename from integration-tests/funcs/helloFunc/func.yaml rename to integration-tests/funcs/helloFunc/func-proto.yaml diff --git a/integration-tests/funcs/helloFunc/src/main/java/com/fnproject/fn/integration/hello/HelloFunction.java b/integration-tests/funcs/helloFunc/src-proto/main/java/com/fnproject/fn/integration/hello/HelloFunction.java similarity index 100% rename from integration-tests/funcs/helloFunc/src/main/java/com/fnproject/fn/integration/hello/HelloFunction.java rename to integration-tests/funcs/helloFunc/src-proto/main/java/com/fnproject/fn/integration/hello/HelloFunction.java From 437de69b8d5e28a6ddc872d67973d61f4fd4548e Mon Sep 17 00:00:00 2001 From: Rik Gibson Date: Sun, 2 Dec 2018 10:07:22 +0000 Subject: [PATCH 083/310] Let's go again... --- integration-tests/funcs/helloFunc/pom.xml | 2 +- .../com/fnproject/fn/integrationtest/IntegrationTestRule.java | 2 -- .../java/com/fnproject/fn/integrationtest/FunctionsTest.java | 1 - 3 files changed, 1 insertion(+), 4 deletions(-) diff --git a/integration-tests/funcs/helloFunc/pom.xml b/integration-tests/funcs/helloFunc/pom.xml index 3d35af89..f53da8dd 100644 --- a/integration-tests/funcs/helloFunc/pom.xml +++ b/integration-tests/funcs/helloFunc/pom.xml @@ -62,7 +62,7 @@ false - + diff --git a/integration-tests/src/main/java/com/fnproject/fn/integrationtest/IntegrationTestRule.java b/integration-tests/src/main/java/com/fnproject/fn/integrationtest/IntegrationTestRule.java index f190dc11..ed2463f8 100644 --- a/integration-tests/src/main/java/com/fnproject/fn/integrationtest/IntegrationTestRule.java +++ b/integration-tests/src/main/java/com/fnproject/fn/integrationtest/IntegrationTestRule.java @@ -190,11 +190,9 @@ public CmdResult runFnWithInputAllowError(String input, String... args) throws E Process p = pb.start(); - p.getOutputStream().write(input.getBytes()); p.getOutputStream().close(); - CompletableFuture stderr = new CompletableFuture<>(); new Thread(() -> { diff --git a/integration-tests/src/test/java/com/fnproject/fn/integrationtest/FunctionsTest.java b/integration-tests/src/test/java/com/fnproject/fn/integrationtest/FunctionsTest.java index b795f3e3..fba24f7d 100644 --- a/integration-tests/src/test/java/com/fnproject/fn/integrationtest/FunctionsTest.java +++ b/integration-tests/src/test/java/com/fnproject/fn/integrationtest/FunctionsTest.java @@ -48,7 +48,6 @@ public void checkBoilerPlate() throws Exception { for (String format : new String[]{"http-stream"}) { for (String runtime : new String[]{"java9", "java8"}) { IntegrationTestRule.TestContext tc = testRule.newTest(); - tc.withDirFrom("funcs/helloFunc"); String fnName = "bp" + format + runtime; tc.runFn("init", "--runtime", runtime, "--name", fnName, "--format", format); From 050c2cccae12cd3df519a9e24717770d80a74ea7 Mon Sep 17 00:00:00 2001 From: CI Date: Sun, 2 Dec 2018 11:42:42 +0000 Subject: [PATCH 084/310] fn-java-fdk: post-1.0.76 version bump [skip ci] --- release.version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/release.version b/release.version index e7468c7d..52575757 100644 --- a/release.version +++ b/release.version @@ -1 +1 @@ -1.0.76 +1.0.77 From c3da760080471c1e149270e8aaf1bc38afab1619 Mon Sep 17 00:00:00 2001 From: CI Date: Mon, 3 Dec 2018 12:42:32 +0000 Subject: [PATCH 085/310] fn-java-fdk: post-1.0.77 version bump [skip ci] --- release.version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/release.version b/release.version index 52575757..f9ef507c 100644 --- a/release.version +++ b/release.version @@ -1 +1 @@ -1.0.77 +1.0.78 From c6f6f3ae79ae567ad140a38c7dee38a9f8f4b28b Mon Sep 17 00:00:00 2001 From: Rik Gibson Date: Thu, 6 Dec 2018 00:45:16 +0000 Subject: [PATCH 086/310] Add jdk11 build/runtime images (#169) * Add build for J11 images * Remove JDK9 VM memory options --- README.md | 6 +++--- build.sh | 5 +++-- images/build/Dockerfile-jdk11 | 8 ++++++++ images/runtime/Dockerfile-jdk11 | 15 +++++++++++++++ integration-tests/README.md | 2 +- 5 files changed, 30 insertions(+), 6 deletions(-) create mode 100644 images/build/Dockerfile-jdk11 create mode 100644 images/runtime/Dockerfile-jdk11 diff --git a/README.md b/README.md index c9a1788f..8978ea11 100644 --- a/README.md +++ b/README.md @@ -2,7 +2,7 @@ [![CircleCI](https://circleci.com/gh/fnproject/fdk-java.svg?style=svg&circle-token=348bec5610c34421f6c436ab8f6a18e153cb1c01)](https://circleci.com/gh/fnproject/fdk-java) This project adds support for writing functions in Java on the [Fn -platform](https://github.com/fnproject/fn), with full support for Java 9 +platform](https://github.com/fnproject/fn), with full support for Java 11 as the default out of the box. # FAQ @@ -44,7 +44,7 @@ func.yaml created ``` This creates the boilerplate for a new Java Function based on Maven and Oracle -Java 9. The `pom.xml` includes a dependency on the latest version of the Fn +Java 11. The `pom.xml` includes a dependency on the latest version of the Fn Java FDK that is useful for developing your Java functions. You can now import this project into your favourite IDE as normal. @@ -101,7 +101,7 @@ You are now ready to run your Function locally using the Fn CLI tool. $ fn build Building image your_dockerhub_account/hello:0.0.1 Sending build context to Docker daemon 14.34kB -Step 1/11 : FROM fnproject/fn-java-fdk-build:jdk9-latest as build-stage +Step 1/11 : FROM fnproject/fn-java-fdk-build:jdk11-latest as build-stage ---> 5435658a63ac Step 2/11 : WORKDIR /function ---> 37340c5aa451 diff --git a/build.sh b/build.sh index 70e1edec..2abb4bc2 100755 --- a/build.sh +++ b/build.sh @@ -32,6 +32,7 @@ mvn -B deploy -DaltDeploymentRepository=localStagingDir::default::file://${REP ( cd images/build ./docker-build.sh -f Dockerfile-jdk9 -t fnproject/fn-java-fdk-build:jdk9-${BUILD_VERSION} . + ./docker-build.sh -f Dockerfile-jdk11 -t fnproject/fn-java-fdk-build:jdk11-${BUILD_VERSION} . ) ( @@ -42,6 +43,7 @@ mvn -B deploy -DaltDeploymentRepository=localStagingDir::default::file://${REP ( cd runtime docker build -f ../images/runtime/Dockerfile-jdk9 -t fnproject/fn-java-fdk:jdk9-${BUILD_VERSION} . + docker build -f ../images/runtime/Dockerfile-jdk11 -t fnproject/fn-java-fdk:jdk11-${BUILD_VERSION} . ) ( @@ -50,8 +52,7 @@ mvn -B deploy -DaltDeploymentRepository=localStagingDir::default::file://${REP ./docker-build.sh ${workdir} ) - ( cd images/init-native ./docker-build.sh -) +) \ No newline at end of file diff --git a/images/build/Dockerfile-jdk11 b/images/build/Dockerfile-jdk11 new file mode 100644 index 00000000..e8b96ddc --- /dev/null +++ b/images/build/Dockerfile-jdk11 @@ -0,0 +1,8 @@ +FROM maven:3-jdk-11-slim + +ARG FN_REPO_URL + +ADD pom.xml /tmp/cache-deps/pom.xml +ADD cache-deps.sh /tmp/cache-deps/cache-deps.sh +ADD src /tmp/cache-deps/src +RUN /tmp/cache-deps/cache-deps.sh diff --git a/images/runtime/Dockerfile-jdk11 b/images/runtime/Dockerfile-jdk11 new file mode 100644 index 00000000..51a7496c --- /dev/null +++ b/images/runtime/Dockerfile-jdk11 @@ -0,0 +1,15 @@ +FROM openjdk:11-jdk-slim +COPY target/runtime-*.jar target/dependency/*.jar /function/runtime/ +COPY src/main/c/libfnunixsocket.so /function/runtime/lib/ + +RUN ["/usr/bin/java", "-Xshare:dump"] + +# The UseExeperimentalVMOptions, UseCGroupMemoryLimitForHeap and MaxRAMFraction options that were used in the JDK 9 builds are +# no longer supported in JDK 11 - so these have been removed. We now rely on the built-in ContainerSupport option that Linux JDKs +# use to configure themselves when detecting they are running in a container. +# +# SerialGC is used here as it's likely that we'll be running many JVMs on the same host machine and it's also likely +# that the number of JVMs will outnumber the number of available processors. +# +ENTRYPOINT [ "/usr/bin/java", "-XX:-UsePerfData", "-XX:+UseSerialGC", "-Xshare:on", \ + "-Djava.library.path=/function/runtime/lib", "-cp", "/function/app/*:/function/runtime/*", "com.fnproject.fn.runtime.EntryPoint" ] diff --git a/integration-tests/README.md b/integration-tests/README.md index 6f4ad5b8..eb34a654 100644 --- a/integration-tests/README.md +++ b/integration-tests/README.md @@ -34,7 +34,7 @@ and runtime images: ``` cd runtime docker build -t fnproject/fn-java-fdk . -docker build -f Dockerfile-jdk9 -t fnproject/fn-java-fdk:jdk9-latest . +docker build -f Dockerfile-jdk11 -t fnproject/fn-java-fdk:jdk11-latest . ``` Finally you can run the integration tests: From d694e3b5b993adef36ef77ddca45434104246e74 Mon Sep 17 00:00:00 2001 From: CI Date: Thu, 6 Dec 2018 00:58:48 +0000 Subject: [PATCH 087/310] fn-java-fdk: post-1.0.78 version bump [skip ci] --- release.version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/release.version b/release.version index f9ef507c..ac329bf4 100644 --- a/release.version +++ b/release.version @@ -1 +1 @@ -1.0.78 +1.0.79 From c718bc083dc2b75ce717e3f6842d5d5c8e67e864 Mon Sep 17 00:00:00 2001 From: Rik Gibson Date: Thu, 6 Dec 2018 11:29:22 +0000 Subject: [PATCH 088/310] Use JRE instead of JDK for 11 runtime image, and add push of 11 images into CI release.sh --- .circleci/release.sh | 13 +++++++++++++ build.sh | 2 +- images/init-native/pom.xml | 2 +- .../runtime/{Dockerfile-jdk11 => Dockerfile-jre11} | 2 +- 4 files changed, 16 insertions(+), 3 deletions(-) rename images/runtime/{Dockerfile-jdk11 => Dockerfile-jre11} (97%) diff --git a/.circleci/release.sh b/.circleci/release.sh index 0dcd678f..bf09c10f 100755 --- a/.circleci/release.sh +++ b/.circleci/release.sh @@ -72,6 +72,19 @@ mvn -s ./settings-deploy.xml \ docker push ${USER}/${BUILD_IMAGE}:jdk9-${release_version} docker push ${USER}/${BUILD_IMAGE}:jdk9-${moving_version} + ## jre11 runtime + docker tag ${USER}/${RUNTIME_IMAGE}:jre11-${release_version} ${USER}/${RUNTIME_IMAGE}:jre11-latest + docker tag ${USER}/${RUNTIME_IMAGE}:jre11-${release_version} ${USER}/${RUNTIME_IMAGE}:jre11-${moving_version} + docker push ${USER}/${RUNTIME_IMAGE}:jre11-latest + docker push ${USER}/${RUNTIME_IMAGE}:jre11-${release_version} + docker push ${USER}/${RUNTIME_IMAGE}:jre11-${moving_version} + + ## jdk11 build + docker tag ${USER}/${BUILD_IMAGE}:jdk11-${release_version} ${USER}/${BUILD_IMAGE}:jdk11-latest + docker tag ${USER}/${BUILD_IMAGE}:jdk11-${release_version} ${USER}/${BUILD_IMAGE}:jdk11-${moving_version} + docker push ${USER}/${BUILD_IMAGE}:jdk11-latest + docker push ${USER}/${BUILD_IMAGE}:jdk11-${release_version} + docker push ${USER}/${BUILD_IMAGE}:jdk11-${moving_version} ## native init image docker tag ${USER}/${NATIVE_INIT_IMAGE}:${release_version} ${USER}/${NATIVE_INIT_IMAGE}:latest diff --git a/build.sh b/build.sh index 2abb4bc2..ace29976 100755 --- a/build.sh +++ b/build.sh @@ -43,7 +43,7 @@ mvn -B deploy -DaltDeploymentRepository=localStagingDir::default::file://${REP ( cd runtime docker build -f ../images/runtime/Dockerfile-jdk9 -t fnproject/fn-java-fdk:jdk9-${BUILD_VERSION} . - docker build -f ../images/runtime/Dockerfile-jdk11 -t fnproject/fn-java-fdk:jdk11-${BUILD_VERSION} . + docker build -f ../images/runtime/Dockerfile-jre11 -t fnproject/fn-java-fdk:jre11-${BUILD_VERSION} . ) ( diff --git a/images/init-native/pom.xml b/images/init-native/pom.xml index f3fda442..18215e12 100644 --- a/images/init-native/pom.xml +++ b/images/init-native/pom.xml @@ -5,7 +5,7 @@ 4.0.0 UTF-8 - 1.0.76 + 1.0.79 com.example.fn hello diff --git a/images/runtime/Dockerfile-jdk11 b/images/runtime/Dockerfile-jre11 similarity index 97% rename from images/runtime/Dockerfile-jdk11 rename to images/runtime/Dockerfile-jre11 index 51a7496c..0574f914 100644 --- a/images/runtime/Dockerfile-jdk11 +++ b/images/runtime/Dockerfile-jre11 @@ -1,4 +1,4 @@ -FROM openjdk:11-jdk-slim +FROM openjdk:11-jre-slim COPY target/runtime-*.jar target/dependency/*.jar /function/runtime/ COPY src/main/c/libfnunixsocket.so /function/runtime/lib/ From d2b1bb9220aca28ba8a81ceaae26672739f3d0e9 Mon Sep 17 00:00:00 2001 From: Rik Gibson Date: Fri, 7 Dec 2018 11:14:48 +0000 Subject: [PATCH 089/310] Reinstate SNAPSHOT version in init-native pom --- images/init-native/pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/images/init-native/pom.xml b/images/init-native/pom.xml index 18215e12..9bb5db9e 100644 --- a/images/init-native/pom.xml +++ b/images/init-native/pom.xml @@ -5,7 +5,7 @@ 4.0.0 UTF-8 - 1.0.79 + 1.0.0-SNAPSHOT com.example.fn hello From 8be6ffa4d4ecacba65f352d745bd9f5b78f9b715 Mon Sep 17 00:00:00 2001 From: CI Date: Fri, 7 Dec 2018 11:41:55 +0000 Subject: [PATCH 090/310] fn-java-fdk: post-1.0.79 version bump [skip ci] --- release.version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/release.version b/release.version index ac329bf4..a747663c 100644 --- a/release.version +++ b/release.version @@ -1 +1 @@ -1.0.79 +1.0.80 From 61815686df15fb4ef1de0629b5586b9b66a4c759 Mon Sep 17 00:00:00 2001 From: Rik Gibson Date: Fri, 7 Dec 2018 12:28:21 +0000 Subject: [PATCH 091/310] Replace java9 tests with java11 --- .../fn/integrationtest/FunctionsTest.java | 20 +++++++++---------- 1 file changed, 9 insertions(+), 11 deletions(-) diff --git a/integration-tests/src/test/java/com/fnproject/fn/integrationtest/FunctionsTest.java b/integration-tests/src/test/java/com/fnproject/fn/integrationtest/FunctionsTest.java index fba24f7d..9b42ef40 100644 --- a/integration-tests/src/test/java/com/fnproject/fn/integrationtest/FunctionsTest.java +++ b/integration-tests/src/test/java/com/fnproject/fn/integrationtest/FunctionsTest.java @@ -45,17 +45,15 @@ public void shouldCallExistingFn() throws Exception { @Test() public void checkBoilerPlate() throws Exception { - for (String format : new String[]{"http-stream"}) { - for (String runtime : new String[]{"java9", "java8"}) { - IntegrationTestRule.TestContext tc = testRule.newTest(); - - String fnName = "bp" + format + runtime; - tc.runFn("init", "--runtime", runtime, "--name", fnName, "--format", format); - tc.rewritePOM(); - tc.runFn("--verbose", "deploy", "--app", tc.appName(), "--local"); - CmdResult rs = tc.runFnWithInput("wibble", "invoke", tc.appName(), fnName); - assertThat(rs.getStdout()).contains("Hello, wibble!"); - } + for (String runtime : new String[]{"java8", "java11"}) { + IntegrationTestRule.TestContext tc = testRule.newTest(); + + String fnName = "bp" + format + runtime; + tc.runFn("init", "--runtime", runtime, "--name", fnName); + tc.rewritePOM(); + tc.runFn("--verbose", "deploy", "--app", tc.appName(), "--local"); + CmdResult rs = tc.runFnWithInput("wibble", "invoke", tc.appName(), fnName); + assertThat(rs.getStdout()).contains("Hello, wibble!"); } } From 165bf4a002ba5576d0e3082c4b45a2567e695dfb Mon Sep 17 00:00:00 2001 From: Rik Gibson Date: Fri, 7 Dec 2018 12:51:11 +0000 Subject: [PATCH 092/310] Ooops... --- .../java/com/fnproject/fn/integrationtest/FunctionsTest.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/integration-tests/src/test/java/com/fnproject/fn/integrationtest/FunctionsTest.java b/integration-tests/src/test/java/com/fnproject/fn/integrationtest/FunctionsTest.java index 9b42ef40..9635e86b 100644 --- a/integration-tests/src/test/java/com/fnproject/fn/integrationtest/FunctionsTest.java +++ b/integration-tests/src/test/java/com/fnproject/fn/integrationtest/FunctionsTest.java @@ -48,7 +48,7 @@ public void checkBoilerPlate() throws Exception { for (String runtime : new String[]{"java8", "java11"}) { IntegrationTestRule.TestContext tc = testRule.newTest(); - String fnName = "bp" + format + runtime; + String fnName = "bp" + runtime; tc.runFn("init", "--runtime", runtime, "--name", fnName); tc.rewritePOM(); tc.runFn("--verbose", "deploy", "--app", tc.appName(), "--local"); From 656786d57cd79a142f9789af0d45c9bc875d875c Mon Sep 17 00:00:00 2001 From: Rik Gibson Date: Fri, 7 Dec 2018 14:03:44 +0000 Subject: [PATCH 093/310] Add JDK9 test back whilst CLI still supports it. --- .../java/com/fnproject/fn/integrationtest/FunctionsTest.java | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/integration-tests/src/test/java/com/fnproject/fn/integrationtest/FunctionsTest.java b/integration-tests/src/test/java/com/fnproject/fn/integrationtest/FunctionsTest.java index 9635e86b..e10b7199 100644 --- a/integration-tests/src/test/java/com/fnproject/fn/integrationtest/FunctionsTest.java +++ b/integration-tests/src/test/java/com/fnproject/fn/integrationtest/FunctionsTest.java @@ -45,7 +45,7 @@ public void shouldCallExistingFn() throws Exception { @Test() public void checkBoilerPlate() throws Exception { - for (String runtime : new String[]{"java8", "java11"}) { + for (String runtime : new String[]{"java8", "java9", "java11"}) { IntegrationTestRule.TestContext tc = testRule.newTest(); String fnName = "bp" + runtime; @@ -57,7 +57,6 @@ public void checkBoilerPlate() throws Exception { } } - @JsonIgnoreProperties(ignoreUnknown = true) public static class InspectResponse { From eac3fffe1decde276536821c2924b425a4589e7d Mon Sep 17 00:00:00 2001 From: CI Date: Fri, 7 Dec 2018 15:38:10 +0000 Subject: [PATCH 094/310] fn-java-fdk: post-1.0.80 version bump [skip ci] --- release.version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/release.version b/release.version index a747663c..818b8de7 100644 --- a/release.version +++ b/release.version @@ -1 +1 @@ -1.0.80 +1.0.81 From 9d29dc504790d9088a68d7e058f0091f4d25f9c5 Mon Sep 17 00:00:00 2001 From: Harry Smith Date: Mon, 7 Jan 2019 09:58:09 +0000 Subject: [PATCH 095/310] Bump jackson version --- examples/async-thumbnails/pom.xml | 2 +- examples/regex-query/pom.xml | 2 +- integration-tests/pom.xml | 2 +- pom.xml | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/examples/async-thumbnails/pom.xml b/examples/async-thumbnails/pom.xml index 17a6f37d..6b90b28e 100644 --- a/examples/async-thumbnails/pom.xml +++ b/examples/async-thumbnails/pom.xml @@ -10,7 +10,7 @@ 1.0.0-SNAPSHOT 2.8.47 - 2.9.7 + 2.9.8 com.fnproject.fn.examples diff --git a/examples/regex-query/pom.xml b/examples/regex-query/pom.xml index 0d08dd2e..584ccfc9 100644 --- a/examples/regex-query/pom.xml +++ b/examples/regex-query/pom.xml @@ -9,7 +9,7 @@ UTF-8 1.0.0-SNAPSHOT - 2.9.7 + 2.9.8 com.fnproject.fn.examples diff --git a/integration-tests/pom.xml b/integration-tests/pom.xml index 28483af2..df380729 100644 --- a/integration-tests/pom.xml +++ b/integration-tests/pom.xml @@ -11,7 +11,7 @@ 3.6.2 2.5 - 2.9.6 + 2.9.8 4.12 2.22.1 diff --git a/pom.xml b/pom.xml index 9276e6d3..c0caa164 100644 --- a/pom.xml +++ b/pom.xml @@ -30,7 +30,7 @@ 3.10.0 2.6 4.4.10 - 2.9.7 + 2.9.8 0.8.1 9.4.12.v20180830 4.12 From 520fc3bbffbc5b3fb0576607aea0f54b890db52f Mon Sep 17 00:00:00 2001 From: CI Date: Mon, 7 Jan 2019 10:27:29 +0000 Subject: [PATCH 096/310] fn-java-fdk: post-1.0.81 version bump [skip ci] --- release.version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/release.version b/release.version index 818b8de7..224d004c 100644 --- a/release.version +++ b/release.version @@ -1 +1 @@ -1.0.81 +1.0.82 From 35fc557f3356e1472b99a7584b752ab1087b1ef3 Mon Sep 17 00:00:00 2001 From: David Delabassee Date: Wed, 9 Jan 2019 16:06:55 +0100 Subject: [PATCH 097/310] removed the (now) useless Docker & Format entries (#178) --- images/init-native/func.init.yaml | 2 -- 1 file changed, 2 deletions(-) diff --git a/images/init-native/func.init.yaml b/images/init-native/func.init.yaml index b7b18322..e69de29b 100644 --- a/images/init-native/func.init.yaml +++ b/images/init-native/func.init.yaml @@ -1,2 +0,0 @@ -runtime: docker -format: http-stream From 5419e6a5575b63602066223bd6971fde756308c2 Mon Sep 17 00:00:00 2001 From: CI Date: Wed, 9 Jan 2019 15:21:29 +0000 Subject: [PATCH 098/310] fn-java-fdk: post-1.0.82 version bump [skip ci] --- release.version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/release.version b/release.version index 224d004c..53fe5d60 100644 --- a/release.version +++ b/release.version @@ -1 +1 @@ -1.0.82 +1.0.83 From 566cccdff4d9cde4293b33518b9aa07ce1215946 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tom=C3=A1=C5=A1=20Zezula?= Date: Wed, 16 Jan 2019 11:45:46 +0100 Subject: [PATCH 099/310] Native java fixes (#179) * Fixed maven surefire classloader. * Fixed SVM problem with max heap size in container. --- images/build-native/Dockerfile | 2 +- images/build-native/native.version | 2 +- images/init-native/pom.xml | 16 ++++++++++++++++ 3 files changed, 18 insertions(+), 2 deletions(-) diff --git a/images/build-native/Dockerfile b/images/build-native/Dockerfile index 4e63888f..d85c0c52 100644 --- a/images/build-native/Dockerfile +++ b/images/build-native/Dockerfile @@ -20,7 +20,7 @@ RUN set -x \ && cp -r $(/build/mx/mx --primary-suite graal-jvmci-8 jdkhome) /build/jvmcijdk8 RUN git clone https://github.com/oracle/graal.git \ - && git -C graal checkout vm-1.0.0-rc9 + && git -C graal checkout vm-1.0.0-rc11 WORKDIR /build/graal/vm RUN export JAVA_HOME=/build/jvmcijdk8 \ && /build/mx/mx --dy /substratevm --force-bash-launchers=true --disable-polyglot --disable-libpolyglot build diff --git a/images/build-native/native.version b/images/build-native/native.version index 0ea3a944..0d91a54c 100644 --- a/images/build-native/native.version +++ b/images/build-native/native.version @@ -1 +1 @@ -0.2.0 +0.3.0 diff --git a/images/init-native/pom.xml b/images/init-native/pom.xml index 9bb5db9e..4d8e2703 100644 --- a/images/init-native/pom.xml +++ b/images/init-native/pom.xml @@ -67,6 +67,22 @@ 1.8 + + org.apache.maven.plugins + maven-surefire-plugin + 2.22.1 + + false + + + + org.apache.maven.plugins + maven-deploy-plugin + 2.8.2 + + true + + From 29aa5b1ee14edc56963744ffb99535eda173f928 Mon Sep 17 00:00:00 2001 From: CI Date: Wed, 16 Jan 2019 11:13:28 +0000 Subject: [PATCH 100/310] fn-java-fdk: post-1.0.83 version bump [skip ci] --- release.version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/release.version b/release.version index 53fe5d60..72602433 100644 --- a/release.version +++ b/release.version @@ -1 +1 @@ -1.0.83 +1.0.84 From d6e105f770f11ff6504c1d085d0117fcbc7f0324 Mon Sep 17 00:00:00 2001 From: Rik Gibson Date: Sat, 2 Feb 2019 18:46:27 +0000 Subject: [PATCH 101/310] Removed old format codecs and tests --- .../fn/runtime/DefaultEventCodec.java | 87 ------ .../com/fnproject/fn/runtime/EntryPoint.java | 8 +- .../fnproject/fn/runtime/HttpEventCodec.java | 181 ------------- .../fn/runtime/DefaultEventCodecTest.java | 66 ----- .../fn/runtime/HttpEventCodecTest.java | 247 ------------------ 5 files changed, 1 insertion(+), 588 deletions(-) delete mode 100644 runtime/src/main/java/com/fnproject/fn/runtime/DefaultEventCodec.java delete mode 100644 runtime/src/main/java/com/fnproject/fn/runtime/HttpEventCodec.java delete mode 100644 runtime/src/test/java/com/fnproject/fn/runtime/DefaultEventCodecTest.java delete mode 100644 runtime/src/test/java/com/fnproject/fn/runtime/HttpEventCodecTest.java diff --git a/runtime/src/main/java/com/fnproject/fn/runtime/DefaultEventCodec.java b/runtime/src/main/java/com/fnproject/fn/runtime/DefaultEventCodec.java deleted file mode 100644 index 4edb7ed5..00000000 --- a/runtime/src/main/java/com/fnproject/fn/runtime/DefaultEventCodec.java +++ /dev/null @@ -1,87 +0,0 @@ -package com.fnproject.fn.runtime; - -import com.fnproject.fn.api.Headers; -import com.fnproject.fn.api.InputEvent; -import com.fnproject.fn.api.OutputEvent; -import com.fnproject.fn.api.exception.FunctionInputHandlingException; -import com.fnproject.fn.api.exception.FunctionOutputHandlingException; - -import java.io.IOException; -import java.io.InputStream; -import java.io.OutputStream; -import java.time.Instant; -import java.time.format.DateTimeParseException; -import java.time.temporal.ChronoUnit; -import java.util.HashMap; -import java.util.Map; - -/** - * DefaultEventCodec handles plain docker invocations on functions - *

    - * This parses inputs from environment variables and reads and writes raw body and responses to the specified input and output streams - * - * @deprecated all new functions should use {@link HTTPStreamCodec} - */ -class DefaultEventCodec implements EventCodec { - - private final Map env; - private final InputStream in; - private final OutputStream out; - - DefaultEventCodec(Map env, InputStream in, OutputStream out) { - this.env = env; - this.in = in; - this.out = out; - } - - - private String getRequiredEnv(String name) { - String val = env.get(name); - if (val == null) { - throw new FunctionInputHandlingException("Required environment variable " + name + " is not set - are you running a function outside of fn run?"); - } - return val; - } - - InputEvent readEvent() { - String callId = env.getOrDefault("FN_CALL_ID", ""); - String deadline = env.get("FN_DEADLINE"); - Instant deadlineDate; - - if (deadline != null) { - try { - deadlineDate = Instant.parse(deadline); - } catch (DateTimeParseException e) { - throw new FunctionInputHandlingException("Invalid deadline date format", e); - } - } else { - deadlineDate = Instant.now().plus(1, ChronoUnit.HOURS); - } - - Map headers = new HashMap<>(); - for (Map.Entry entry : env.entrySet()) { - String lowerCaseKey = entry.getKey().toLowerCase(); - if (lowerCaseKey.startsWith("fn_header_")) { - headers.put(entry.getKey().substring("fn_header_".length()), entry.getValue()); - } - } - - return new ReadOnceInputEvent(in, Headers.fromMap(headers), callId, deadlineDate); - } - - - void writeEvent(OutputEvent evt) { - try { - evt.writeToOutput(out); - } catch (IOException e) { - throw new FunctionOutputHandlingException("error writing event", e); - } - } - - @Override - public void runCodec(Handler h) { - InputEvent event = readEvent(); - OutputEvent out = h.handle(event); - writeEvent(out); - } -} diff --git a/runtime/src/main/java/com/fnproject/fn/runtime/EntryPoint.java b/runtime/src/main/java/com/fnproject/fn/runtime/EntryPoint.java index c146c913..76ca4b3b 100644 --- a/runtime/src/main/java/com/fnproject/fn/runtime/EntryPoint.java +++ b/runtime/src/main/java/com/fnproject/fn/runtime/EntryPoint.java @@ -26,20 +26,14 @@ public static void main(String... args) throws Exception { // without interference from the user printing stuff to what they believe is stdout. System.setOut(System.err); - String format = System.getenv("FN_FORMAT"); EventCodec codec; - if (format != null && format.equalsIgnoreCase("http")) { - codec = new HttpEventCodec(System.getenv(), System.in, originalSystemOut); - } else if (format == null || format.equalsIgnoreCase("default")) { - codec = new DefaultEventCodec(System.getenv(), System.in, originalSystemOut); - } else if (format.equals(HTTPStreamCodec.HTTP_STREAM_FORMAT)) { + if (format.equals(HTTPStreamCodec.HTTP_STREAM_FORMAT)) { codec = new HTTPStreamCodec(System.getenv()); } else { throw new FunctionInputHandlingException("Unsupported function format:" + format); } - int exitCode = new EntryPoint().run(System.getenv(), codec, System.err, args); System.setOut(originalSystemOut); System.exit(exitCode); diff --git a/runtime/src/main/java/com/fnproject/fn/runtime/HttpEventCodec.java b/runtime/src/main/java/com/fnproject/fn/runtime/HttpEventCodec.java deleted file mode 100644 index 6e980e44..00000000 --- a/runtime/src/main/java/com/fnproject/fn/runtime/HttpEventCodec.java +++ /dev/null @@ -1,181 +0,0 @@ -package com.fnproject.fn.runtime; - - -import com.fnproject.fn.api.Headers; -import com.fnproject.fn.api.InputEvent; -import com.fnproject.fn.api.OutputEvent; -import com.fnproject.fn.api.exception.FunctionInputHandlingException; -import com.fnproject.fn.api.exception.FunctionOutputHandlingException; -import org.apache.http.Header; -import org.apache.http.HttpException; -import org.apache.http.HttpRequest; -import org.apache.http.ProtocolVersion; -import org.apache.http.config.MessageConstraints; -import org.apache.http.impl.io.*; -import org.apache.http.io.HttpMessageParser; -import org.apache.http.io.SessionInputBuffer; -import org.apache.http.io.SessionOutputBuffer; -import org.apache.http.message.BasicHttpResponse; -import org.apache.http.message.BasicStatusLine; - -import java.io.*; -import java.time.Instant; -import java.time.format.DateTimeParseException; -import java.time.temporal.ChronoUnit; -import java.util.HashMap; -import java.util.Map; -import java.util.Objects; -import java.util.Optional; -import java.util.function.Function; - - -/** - * Reads input via an InputStream as an HTTP request. - *

    - * This does not consume the whole event from the buffer, The caller is responsible for ensuring that either {@link InputEvent#consumeBody(Function)} or {@link InputEvent#close()} is called before reading a new event - * - * @deprecated all new functions should use {@link HTTPStreamCodec} - */ -public final class HttpEventCodec implements EventCodec { - - private static final String CONTENT_TYPE_HEADER = "Content-Type"; - private final SessionInputBuffer sib; - private final SessionOutputBuffer sob; - private final HttpMessageParser parser; - - private final Map env; - - HttpEventCodec(Map env, InputStream input, OutputStream output) { - - this.env = env; - - SessionInputBufferImpl sib = new SessionInputBufferImpl(new HttpTransportMetricsImpl(), 65535); - sib.bind(Objects.requireNonNull(input)); - this.sib = sib; - - SessionOutputBufferImpl sob = new SessionOutputBufferImpl(new HttpTransportMetricsImpl(), 65535); - sob.bind(output); - this.sob = sob; - - parser = new DefaultHttpRequestParserFactory(null, null).create(sib, MessageConstraints.custom().setMaxHeaderCount(65535).setMaxLineLength(65535).build()); - } - - private static String requiredHeader(HttpRequest req, String id) { - return Optional.ofNullable(req.getFirstHeader(id)).map(Header::getValue).orElseThrow(() -> new FunctionInputHandlingException("Incoming HTTP frame is missing required header: " + id)); - } - - private String getRequiredEnv(String name) { - String val = env.get(name); - if (val == null) { - throw new FunctionInputHandlingException("Required environment variable " + name + " is not set - are you running a function outside of fn run?"); - } - return val; - } - - Optional readEvent() { - - HttpRequest req; - try { - req = parser.parse(); - } catch (org.apache.http.ConnectionClosedException e) { - // End of stream - signal normal termination - return Optional.empty(); - } catch (IOException | HttpException e) { - throw new FunctionInputHandlingException("Failed to read HTTP content from input", e); - } - - InputStream bodyStream; - if (req.getHeaders("content-length").length > 0) { - long contentLength = Long.parseLong(requiredHeader(req, "content-length")); - bodyStream = new ContentLengthInputStream(sib, contentLength); - } else if (req.getHeaders("transfer-encoding").length > 0 && - req.getFirstHeader("transfer-encoding").getValue().equalsIgnoreCase("chunked")) { - bodyStream = new ChunkedInputStream(sib); - } else { - bodyStream = new ByteArrayInputStream(new byte[]{}); - } - - - Instant deadlineDate; - - Header deadlineHeader = req.getFirstHeader("fn_deadline"); - if (deadlineHeader != null) { - try { - deadlineDate = Instant.parse(deadlineHeader.getValue()); - } catch (DateTimeParseException e) { - throw new FunctionInputHandlingException("Invalid deadline date format", e); - } - } else { - deadlineDate = Instant.now().plus(1, ChronoUnit.HOURS); - } - - Header callIDHeader = req.getFirstHeader("fn_call_id"); - - String callID = ""; - if (callIDHeader != null) { - callID = callIDHeader.getValue(); - } - Map headers = new HashMap<>(); - for (Header h : req.getAllHeaders()) { - headers.put(h.getName(), h.getValue()); - } - - return Optional.of(new ReadOnceInputEvent( - bodyStream, Headers.fromMap(headers), callID, deadlineDate)); - - } - - void writeEvent(OutputEvent evt) { - try { - // TODO: We buffer the whole output here just to get the content-length - // TODO: functions should support chunked - - ByteArrayOutputStream bos = new ByteArrayOutputStream(); - - evt.writeToOutput(bos); - - byte[] data = bos.toByteArray(); - - BasicHttpResponse response; - - if (evt.isSuccess()) { - response = new BasicHttpResponse(new BasicStatusLine(new ProtocolVersion("HTTP", 1, 1), evt.getStatus().getCode(), evt.getStatus().name())); - } else { - response = new BasicHttpResponse(new BasicStatusLine(new ProtocolVersion("HTTP", 1, 1), evt.getStatus().getCode(), evt.getStatus().name())); - } - - evt.getHeaders().asMap().forEach((k, vs) -> vs.forEach(v -> response.addHeader(k, v))); - - evt.getContentType().ifPresent((ct) -> response.setHeader(CONTENT_TYPE_HEADER, ct)); - response.setHeader("Content-length", String.valueOf(data.length)); - - - DefaultHttpResponseWriter writer = new DefaultHttpResponseWriter(sob); - try { - writer.write(response); - } catch (HttpException e) { - throw new FunctionOutputHandlingException("Failed to write response", e); - } - ContentLengthOutputStream clos = new ContentLengthOutputStream(sob, data.length); - clos.write(data); - clos.flush(); - clos.close(); - sob.flush(); - - } catch (IOException e) { - throw new FunctionOutputHandlingException("Failed to write output to stream", e); - } - } - - @Override - public void runCodec(Handler h) { - - while (true) { - Optional evt = readEvent(); - if (!evt.isPresent()) { - return; - } - writeEvent(h.handle(evt.get())); - } - } -} diff --git a/runtime/src/test/java/com/fnproject/fn/runtime/DefaultEventCodecTest.java b/runtime/src/test/java/com/fnproject/fn/runtime/DefaultEventCodecTest.java deleted file mode 100644 index eccf2af5..00000000 --- a/runtime/src/test/java/com/fnproject/fn/runtime/DefaultEventCodecTest.java +++ /dev/null @@ -1,66 +0,0 @@ -package com.fnproject.fn.runtime; - -import com.fnproject.fn.api.InputEvent; -import com.fnproject.fn.api.OutputEvent; -import org.apache.commons.io.input.NullInputStream; -import org.apache.commons.io.output.NullOutputStream; -import org.junit.Test; - -import java.io.ByteArrayInputStream; -import java.io.ByteArrayOutputStream; -import java.io.IOException; -import java.io.InputStream; -import java.util.HashMap; -import java.util.Map; - -import static com.fnproject.fn.runtime.HeaderBuilder.headerEntry; -import static org.assertj.core.api.Assertions.assertThat; - -public class DefaultEventCodecTest { - - private final Map emptyConfig = new HashMap<>(); - private InputStream asStream(String s) { - return new ByteArrayInputStream(s.getBytes()); - } - - @Test - public void shouldExtractBasicEvent() { - Map env = new HashMap<>(); - env.put("FN_FORMAT", "default"); - env.put("FN_HEADER_CONTENT_TYPE", "text/plain"); - env.put("FN_HEADER_ACCEPT", "text/html, text/plain;q=0.9"); - env.put("FN_HEADER_ACCEPT_ENCODING", "gzip"); - env.put("FN_HEADER_USER_AGENT", "userAgent"); - - Map config = new HashMap<>(); - config.put("configparam", "configval"); - config.put("CONFIGPARAM", "CONFIGVAL"); - - DefaultEventCodec codec = new DefaultEventCodec(env, asStream("input"), new NullOutputStream()); - InputEvent evt = codec.readEvent(); - - - assertThat(evt.getHeaders().asMap().size()).isEqualTo(4); - assertThat(evt.getHeaders().asMap()).contains( - headerEntry("CONTENT_TYPE", "text/plain"), - headerEntry("ACCEPT_ENCODING", "gzip"), - headerEntry("ACCEPT", "text/html, text/plain;q=0.9"), - headerEntry("USER_AGENT", "userAgent")); - - evt.consumeBody((body) -> assertThat(body).hasSameContentAs(asStream("input"))); - } - - - - @Test - public void shouldWriteOutputDirectlyToOutputStream() throws IOException{ - - OutputEvent evt = OutputEvent.fromBytes("hello".getBytes(),OutputEvent.Status.Success,"text/plain"); - ByteArrayOutputStream bos = new ByteArrayOutputStream(); - - DefaultEventCodec codec = new DefaultEventCodec(new HashMap<>(), new NullInputStream(0),bos); - codec.writeEvent(evt); - assertThat(new String(bos.toByteArray())).isEqualTo("hello"); - - } -} diff --git a/runtime/src/test/java/com/fnproject/fn/runtime/HttpEventCodecTest.java b/runtime/src/test/java/com/fnproject/fn/runtime/HttpEventCodecTest.java deleted file mode 100644 index 70312a14..00000000 --- a/runtime/src/test/java/com/fnproject/fn/runtime/HttpEventCodecTest.java +++ /dev/null @@ -1,247 +0,0 @@ -package com.fnproject.fn.runtime; - -import com.fnproject.fn.api.Headers; -import com.fnproject.fn.api.InputEvent; -import com.fnproject.fn.api.OutputEvent; -import com.fnproject.fn.api.exception.FunctionInputHandlingException; -import org.apache.commons.io.input.NullInputStream; -import org.apache.commons.io.output.NullOutputStream; -import org.junit.Test; - -import java.io.ByteArrayInputStream; -import java.io.ByteArrayOutputStream; -import java.io.InputStream; -import java.io.OutputStream; -import java.util.HashMap; -import java.util.Map; - -import static com.fnproject.fn.runtime.HeaderBuilder.headerEntry; -import static org.assertj.core.api.Assertions.assertThat; -import static org.assertj.core.api.Assertions.entry; -import static org.junit.Assert.fail; - -public class HttpEventCodecTest { - private final OutputStream nullOut = new NullOutputStream(); - private final InputStream nullIn = new NullInputStream(0); - - private final String postReq = "GET /test HTTP/1.1\n" + - "Accept-Encoding: gzip\n" + - "User-Agent: useragent\n" + - "Accept: text/html, text/plain;q=0.9\n" + - "Fn_Request_url: http//localhost:8080/r/testapp/test\n" + - "Fn_Path: /test\n" + - "Fn_Method: POST\n" + - "Content-Length: 11\n" + - "Fn_App_name: testapp\n" + - "Fn_Call_id: task-id\n" + - "Myconfig: fooconfig\n" + - "Content-Type: text/plain\n\n" + - "Hello World"; - - - private final String getReq = "GET /test HTTP/1.1\n" + - "Accept-Encoding: gzip\n" + - "User-Agent: useragent\n" + - "Fn_Request_url: http//localhost:8080/r/testapp/test\n" + - "Fn_Method: GET\n" + - "Content-Length: 0\n" + - "Fn_Call_Id: task-id2\n" + - "Myconfig: fooconfig\n\n"; - - private final Map emptyConfig = new HashMap<>(); - - private Map env() { - HashMap env = new HashMap<>(); - env.put("FN_APP_NAME", "testapp"); - env.put("FN_PATH", "/test"); - return env; - } - - @Test - public void testParsingSimpleHttpRequestWithFnHeadersAndBody() { - ByteArrayInputStream bis = new ByteArrayInputStream(postReq.getBytes()); - ByteArrayOutputStream bos = new ByteArrayOutputStream(); - HttpEventCodec httpEventCodec = new HttpEventCodec(env(), bis, bos); - - InputEvent event = httpEventCodec.readEvent().get(); - isExpectedPostEvent(event); - } - - @Test - public void shouldReadMultipleRequestsOnSameStream() { - byte req1[] = postReq.getBytes(); - byte req2[] = getReq.getBytes(); - byte req3[] = postReq.getBytes(); - - byte input[] = new byte[req1.length + req2.length + req3.length]; - - System.arraycopy(req1, 0, input, 0, req1.length); - System.arraycopy(req2, 0, input, req1.length, req2.length); - System.arraycopy(req3, 0, input, req1.length + req2.length, req3.length); - - ByteArrayInputStream bis = new ByteArrayInputStream(input); - ByteArrayOutputStream bos = new ByteArrayOutputStream(); - HttpEventCodec httpEventCodec = new HttpEventCodec(env(), bis, bos); - - InputEvent postEvent = httpEventCodec.readEvent().get(); - isExpectedPostEvent(postEvent); - - InputEvent getEvent = httpEventCodec.readEvent().get(); - isExpectedGetEvent(getEvent); - - InputEvent postEvent2 = httpEventCodec.readEvent().get(); - isExpectedPostEvent(postEvent2); - - - } - - @Test - public void shouldRejectInvalidHttpRequest() { - try { - HttpEventCodec httpEventCodec = new HttpEventCodec(env(), asStream("NOT_HTTP " + getReq), nullOut); - - httpEventCodec.readEvent(); - fail(); - } catch (FunctionInputHandlingException e) { - assertThat(e).hasMessageContaining("Failed to read HTTP content from input"); - } - } - - - - @Test - public void shouldSerializeSimpleSuccessfulEvent() throws Exception { - ByteArrayOutputStream bos = new ByteArrayOutputStream(); - - HttpEventCodec httpEventCodec = new HttpEventCodec(env(), nullIn, bos); - OutputEvent outEvent = OutputEvent.fromBytes("Hello".getBytes(), OutputEvent.Status.Success, "text/plain"); - - httpEventCodec.writeEvent(outEvent); - String httpResponse = new String(bos.toByteArray()); - - assertThat(statusLine(httpResponse)).isEqualTo("HTTP/1.1 200 Success"); - assertThat(headers(httpResponse)).containsOnly(entry("content-type", "text/plain"), entry("content-length", "5")); - assertThat(body(httpResponse)).isEqualTo("Hello"); - - } - - private static String statusLine(String httpResponse) { - return httpResponse.split("\\\r\\\n", 2)[0]; - } - - private static Map headers(String httpResponse) { - Map hs = new HashMap<>(); - boolean firstLine = true; - for (String line : httpResponse.split("\\\r\\\n")) { - if (line.equals("")) { - break; - } - if (firstLine) { - firstLine = false; - continue; - } - String[] parts = line.split(": *", 2); - hs.put(parts[0].toLowerCase(), parts[1]); - } - return hs; - } - - private static String body(String httpResponse) { - return httpResponse.split("\\\r\\\n\\\r\\\n", 2)[1]; - } - - @Test - public void shouldSerializeSuccessfulEventWithHeaders() throws Exception { - ByteArrayOutputStream bos = new ByteArrayOutputStream(); - - HttpEventCodec httpEventCodec = new HttpEventCodec(env(), nullIn, bos); - Map hs = new HashMap<>(); - hs.put("foo", "bar"); - hs.put("Content-Type", "application/octet-stream"); // ignored - hs.put("Content-length", "99"); // ignored - OutputEvent outEvent = OutputEvent.fromBytes("Hello".getBytes(), OutputEvent.Status.Success, "text/plain", Headers.fromMap(hs)); - - httpEventCodec.writeEvent(outEvent); - String httpResponse = new String(bos.toByteArray()); - - assertThat(statusLine(httpResponse)).isEqualTo("HTTP/1.1 200 Success"); - assertThat(headers(httpResponse)).containsOnly(entry("foo", "bar"), - entry("content-type", "text/plain"), - entry("content-length", "5")); - assertThat(body(httpResponse)).isEqualTo("Hello"); - } - - - @Test - public void shouldSerializeSimpleFailedEvent() throws Exception { - ByteArrayOutputStream bos = new ByteArrayOutputStream(); - - HttpEventCodec httpEventCodec = new HttpEventCodec(env(), nullIn, bos); - OutputEvent outEvent = OutputEvent.fromBytes("Hello".getBytes(), OutputEvent.Status.FunctionError, "text/plain"); - - httpEventCodec.writeEvent(outEvent); - String httpResponse = new String(bos.toByteArray()); - - assertThat(statusLine(httpResponse)).isEqualTo("HTTP/1.1 502 FunctionError"); - assertThat(headers(httpResponse)).containsOnly(entry("content-type", "text/plain"), - entry("content-length", "5")); - assertThat(body(httpResponse)).isEqualTo("Hello"); - } - - - @Test - public void shouldSerializeFailedEventWithHeaders() throws Exception { - ByteArrayOutputStream bos = new ByteArrayOutputStream(); - - HttpEventCodec httpEventCodec = new HttpEventCodec(env(), nullIn, bos); - Map hs = new HashMap<>(); - hs.put("foo", "bar"); - hs.put("Content-Type", "application/octet-stream"); // ignored - hs.put("Content-length", "99"); // ignored - OutputEvent outEvent = OutputEvent.fromBytes("Hello".getBytes(), OutputEvent.Status.FunctionError, "text/plain", Headers.fromMap(hs)); - - httpEventCodec.writeEvent(outEvent); - String httpResponse = new String(bos.toByteArray()); - - assertThat(statusLine(httpResponse)).isEqualTo("HTTP/1.1 502 FunctionError"); - assertThat(headers(httpResponse)).containsOnly(entry("foo", "bar"), - entry("content-type", "text/plain"), - entry("content-length", "5")); - assertThat(body(httpResponse)).isEqualTo("Hello"); - } - - - private InputStream asStream(String sin) { - return new ByteArrayInputStream(sin.getBytes()); - } - - private void isExpectedGetEvent(InputEvent getEvent) { - //assertThat(getEvent.getAppName()).isEqualTo("testapp"); -// assertThat(getEvent.getMethod()).isEqualTo("GET"); -// assertThat(getEvent.getRoute()).isEqualTo("/test"); - - assertThat(getEvent.getHeaders().asMap()) - .contains(headerEntry("Accept-Encoding", "gzip"), - headerEntry("User-Agent", "useragent")); - - - getEvent.consumeBody((is) -> assertThat(is).hasSameContentAs(asStream(""))); - } - - - private void isExpectedPostEvent(InputEvent postEvent) { - //assertThat(postEvent.getAppName()).isEqualTo("testapp"); -// assertThat(postEvent.getMethod()).isEqualTo("POST"); -// assertThat(postEvent.getRoute()).isEqualTo("/test"); - assertThat(postEvent.getHeaders().asMap().size()).isEqualTo(11); - assertThat(postEvent.getHeaders().asMap()) - .contains(headerEntry("Accept", "text/html, text/plain;q=0.9"), - headerEntry("Accept-Encoding", "gzip"), - headerEntry("User-Agent", "useragent"), - headerEntry("Content-Type", "text/plain")); - - postEvent.consumeBody((is) -> assertThat(is).hasSameContentAs(asStream("Hello World"))); - } -// - -} From 5b9b147f6bc76a8538d2191036ec75d074cb264c Mon Sep 17 00:00:00 2001 From: Rik Gibson Date: Sat, 2 Feb 2019 19:06:51 +0000 Subject: [PATCH 102/310] Remove Java 9 dockerfiles, update builds and tests --- build.sh | 2 -- images/build/Dockerfile-jdk9 | 8 -------- images/runtime/Dockerfile-jdk9 | 20 ------------------- images/runtime/README.md | 4 ++-- .../fn/integrationtest/FunctionsTest.java | 2 +- 5 files changed, 3 insertions(+), 33 deletions(-) delete mode 100644 images/build/Dockerfile-jdk9 delete mode 100644 images/runtime/Dockerfile-jdk9 diff --git a/build.sh b/build.sh index ace29976..b19ac5a0 100755 --- a/build.sh +++ b/build.sh @@ -31,7 +31,6 @@ mvn -B deploy -DaltDeploymentRepository=localStagingDir::default::file://${REP ( cd images/build - ./docker-build.sh -f Dockerfile-jdk9 -t fnproject/fn-java-fdk-build:jdk9-${BUILD_VERSION} . ./docker-build.sh -f Dockerfile-jdk11 -t fnproject/fn-java-fdk-build:jdk11-${BUILD_VERSION} . ) @@ -42,7 +41,6 @@ mvn -B deploy -DaltDeploymentRepository=localStagingDir::default::file://${REP ( cd runtime - docker build -f ../images/runtime/Dockerfile-jdk9 -t fnproject/fn-java-fdk:jdk9-${BUILD_VERSION} . docker build -f ../images/runtime/Dockerfile-jre11 -t fnproject/fn-java-fdk:jre11-${BUILD_VERSION} . ) diff --git a/images/build/Dockerfile-jdk9 b/images/build/Dockerfile-jdk9 deleted file mode 100644 index c6396862..00000000 --- a/images/build/Dockerfile-jdk9 +++ /dev/null @@ -1,8 +0,0 @@ -FROM maven:3-jdk-9-slim -ARG FN_REPO_URL - -ADD pom.xml /tmp/cache-deps/pom.xml -ADD cache-deps.sh /tmp/cache-deps/cache-deps.sh -ADD src /tmp/cache-deps/src - -RUN /tmp/cache-deps/cache-deps.sh diff --git a/images/runtime/Dockerfile-jdk9 b/images/runtime/Dockerfile-jdk9 deleted file mode 100644 index 09364524..00000000 --- a/images/runtime/Dockerfile-jdk9 +++ /dev/null @@ -1,20 +0,0 @@ -FROM openjdk:9-slim -COPY target/runtime-*.jar target/dependency/*.jar /function/runtime/ -COPY src/main/c/libfnunixsocket.so /function/runtime/lib/ - -RUN ["/usr/bin/java", "-Xshare:dump"] - -# UseCGroupMemoryLimitForHeap looks up /sys/fs/cgroup/memory/memory.limit_in_bytes inside the container to determine -# what the heap should be set to. This is an experimental feature at the moment, thus we need to unlock to use it. -# -# MaxRAMFraction is used modify the heap size and it is used as a denominator where the numerator is phys_mem. -# It seems that this value is a uint in the JVM code, thus can only specify 1 => 100%, 2 => 50%, 3 => 33.3%, 4 => 25% -# and so on. -# -# SerialGC is used here as it's likely that we'll be running many JVMs on the same host machine and it's also likely -# that the number of JVMs will outnumber the number of available processors. -# -# The max memory value obtained with these args seem to be okay for most memory limits. The exception is when the -# memory limit is set to 128MiB, in which case maxMemory returns roughly half. -ENTRYPOINT [ "/usr/bin/java", "-XX:+UnlockExperimentalVMOptions", "-XX:+UseCGroupMemoryLimitForHeap", "-XX:MaxRAMFraction=2","-XX:-UsePerfData", "-XX:+UseSerialGC", "-Xshare:on", \ - "-Djava.library.path=/function/runtime/lib", "-cp", "/function/app/*:/function/runtime/*", "com.fnproject.fn.runtime.EntryPoint" ] diff --git a/images/runtime/README.md b/images/runtime/README.md index 672f311d..dfd530a0 100644 --- a/images/runtime/README.md +++ b/images/runtime/README.md @@ -1,3 +1,3 @@ -# Fn Java runtime base image +# Fn Java runtime base images -This image is used as a base image for functions - it includes a JDK and the latest version of the runtime \ No newline at end of file +These images are used as a base image for functions - they include a JDK and the latest version of the runtime \ No newline at end of file diff --git a/integration-tests/src/test/java/com/fnproject/fn/integrationtest/FunctionsTest.java b/integration-tests/src/test/java/com/fnproject/fn/integrationtest/FunctionsTest.java index fba24f7d..728bde8c 100644 --- a/integration-tests/src/test/java/com/fnproject/fn/integrationtest/FunctionsTest.java +++ b/integration-tests/src/test/java/com/fnproject/fn/integrationtest/FunctionsTest.java @@ -46,7 +46,7 @@ public void shouldCallExistingFn() throws Exception { @Test() public void checkBoilerPlate() throws Exception { for (String format : new String[]{"http-stream"}) { - for (String runtime : new String[]{"java9", "java8"}) { + for (String runtime : new String[]{"java8", "java11"}) { IntegrationTestRule.TestContext tc = testRule.newTest(); String fnName = "bp" + format + runtime; From 502ac88de04c5687b6f8a54246bbf921aa8bbd68 Mon Sep 17 00:00:00 2001 From: Rik Gibson Date: Mon, 4 Feb 2019 16:38:29 -0800 Subject: [PATCH 103/310] Update tests to java11 --- integration-tests/funcs/flowExitHooks/func.yaml | 2 +- integration-tests/funcs/flowTimeouts/func.yaml | 2 +- integration-tests/funcs/simpleFunc/func.yaml | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/integration-tests/funcs/flowExitHooks/func.yaml b/integration-tests/funcs/flowExitHooks/func.yaml index 2a0161e8..52034a1e 100644 --- a/integration-tests/funcs/flowExitHooks/func.yaml +++ b/integration-tests/funcs/flowExitHooks/func.yaml @@ -1,7 +1,7 @@ schema_version: 20180708 name: flowexithooks version: 0.0.3 -runtime: java9 +runtime: java11 cmd: com.fnproject.fn.integration.test_5.CompleterFunction::handleRequest format: http-stream timeout: 120 diff --git a/integration-tests/funcs/flowTimeouts/func.yaml b/integration-tests/funcs/flowTimeouts/func.yaml index d8a91857..6d83f8ec 100644 --- a/integration-tests/funcs/flowTimeouts/func.yaml +++ b/integration-tests/funcs/flowTimeouts/func.yaml @@ -1,7 +1,7 @@ schema_version: 20180708 name: flowtimeouts version: 0.0.3 -runtime: java9 +runtime: java11 cmd: com.fnproject.fn.integration.test_6.CompleterFunction::handleRequest format: http-stream timeout: 120 diff --git a/integration-tests/funcs/simpleFunc/func.yaml b/integration-tests/funcs/simpleFunc/func.yaml index 187a2f2f..c0c9c79b 100644 --- a/integration-tests/funcs/simpleFunc/func.yaml +++ b/integration-tests/funcs/simpleFunc/func.yaml @@ -1,6 +1,6 @@ schema_version: 20180708 name: simplefunc version: 0.0.3 -runtime: java9 +runtime: java11 cmd: com.fnproject.fn.integration.test2.PlainFunction::handleRequest format: http-stream From 46e126fd8175d7ec0012408f9189fe37771b3046 Mon Sep 17 00:00:00 2001 From: Rik Gibson Date: Tue, 5 Feb 2019 16:10:19 -0800 Subject: [PATCH 104/310] Fix broken release --- .circleci/release.sh | 14 -------------- examples/gradle-build/README.md | 2 +- 2 files changed, 1 insertion(+), 15 deletions(-) diff --git a/.circleci/release.sh b/.circleci/release.sh index bf09c10f..74424e58 100755 --- a/.circleci/release.sh +++ b/.circleci/release.sh @@ -58,20 +58,6 @@ mvn -s ./settings-deploy.xml \ docker push ${USER}/${BUILD_IMAGE}:${release_version} docker push ${USER}/${BUILD_IMAGE}:${moving_version} - ## jdk9 runtime - docker tag ${USER}/${RUNTIME_IMAGE}:jdk9-${release_version} ${USER}/${RUNTIME_IMAGE}:jdk9-latest - docker tag ${USER}/${RUNTIME_IMAGE}:jdk9-${release_version} ${USER}/${RUNTIME_IMAGE}:jdk9-${moving_version} - docker push ${USER}/${RUNTIME_IMAGE}:jdk9-latest - docker push ${USER}/${RUNTIME_IMAGE}:jdk9-${release_version} - docker push ${USER}/${RUNTIME_IMAGE}:jdk9-${moving_version} - - ## jdk9 build - docker tag ${USER}/${BUILD_IMAGE}:jdk9-${release_version} ${USER}/${BUILD_IMAGE}:jdk9-latest - docker tag ${USER}/${BUILD_IMAGE}:jdk9-${release_version} ${USER}/${BUILD_IMAGE}:jdk9-${moving_version} - docker push ${USER}/${BUILD_IMAGE}:jdk9-latest - docker push ${USER}/${BUILD_IMAGE}:jdk9-${release_version} - docker push ${USER}/${BUILD_IMAGE}:jdk9-${moving_version} - ## jre11 runtime docker tag ${USER}/${RUNTIME_IMAGE}:jre11-${release_version} ${USER}/${RUNTIME_IMAGE}:jre11-latest docker tag ${USER}/${RUNTIME_IMAGE}:jre11-${release_version} ${USER}/${RUNTIME_IMAGE}:jre11-${moving_version} diff --git a/examples/gradle-build/README.md b/examples/gradle-build/README.md index 1b68ab3a..3214e0b3 100644 --- a/examples/gradle-build/README.md +++ b/examples/gradle-build/README.md @@ -11,4 +11,4 @@ Key points: * [Dockerfile](Dockerfile) - contains the containerised docker build (based on dockerhub library/gradle images) and image build - this includes the gradle invocation * The `cacheDeps` task in `build.gradle` is invoked within the Dockerfile - The task pulls down dependencies into the container gradle cache to speed up docker builds. * The `copyDeps` task in `build.gradle` copies the functions compile deps -* This uses JDK 8 by default - you can change this to Java 9 by changing : `FROM gradle:4.5.1-jdk8 as build-stage` to `FROM gradle:4.5.1-jdk9 as build-stage` and `FROM fnproject/fn-java-fdk:1.0.56` to `FROM fnproject/fn-java-fdk:jdk9-1.0.56` \ No newline at end of file +* This uses JDK 8 by default - you can change this to Java 11 by changing : `FROM gradle:4.5.1-jdk8 as build-stage` to `FROM gradle:4.5.1-jre11 as build-stage` and `FROM fnproject/fn-java-fdk:1.0.85` to `FROM fnproject/fn-java-fdk:jre11-1.0.85` \ No newline at end of file From 57e37c1253c17b2dbbc4fb5713bf0a6d729a5902 Mon Sep 17 00:00:00 2001 From: Rik Gibson Date: Tue, 5 Feb 2019 16:56:30 -0800 Subject: [PATCH 105/310] Bump version number past previous broken release --- release.version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/release.version b/release.version index 72602433..8bdc5322 100644 --- a/release.version +++ b/release.version @@ -1 +1 @@ -1.0.84 +1.0.85 From bab04415dcb557d4c0cda58cac637d126631061b Mon Sep 17 00:00:00 2001 From: CI Date: Wed, 6 Feb 2019 01:10:07 +0000 Subject: [PATCH 106/310] fn-java-fdk: post-1.0.85 version bump [skip ci] --- release.version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/release.version b/release.version index 8bdc5322..24f0f658 100644 --- a/release.version +++ b/release.version @@ -1 +1 @@ -1.0.85 +1.0.86 From b9fe8963642ada78b0b58ee608bee95df9bea0fc Mon Sep 17 00:00:00 2001 From: Iovana Pavlovici Date: Fri, 8 Feb 2019 11:15:53 +0000 Subject: [PATCH 107/310] Update HTTPGatewayFunctions.md --- docs/HTTPGatewayFunctions.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/HTTPGatewayFunctions.md b/docs/HTTPGatewayFunctions.md index 76fa319c..86afd87a 100644 --- a/docs/HTTPGatewayFunctions.md +++ b/docs/HTTPGatewayFunctions.md @@ -23,7 +23,7 @@ import com.fnproject.fn.api.httpgateway.HTTPGatewayContext; public class RedirectFunction { - public redirect(HTTPGatewayContext hctx) { + public void redirect(HTTPGatewayContext hctx) { System.err.println("Request URL is:" + hctx.getRequestURL()); System.err.println("Trace ID" + hctx.getHeaders().get("My-Trace-ID").orElse("N/A")); From 1b174c218cf6e78224e20b4b069be0c69b9e0b38 Mon Sep 17 00:00:00 2001 From: David Delabassee Date: Wed, 20 Feb 2019 09:47:41 +0100 Subject: [PATCH 108/310] removed some legacy stuff (fn call & route) --- docs/FnFlowsUserGuide.md | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/docs/FnFlowsUserGuide.md b/docs/FnFlowsUserGuide.md index 7cb4997b..7834fe0c 100644 --- a/docs/FnFlowsUserGuide.md +++ b/docs/FnFlowsUserGuide.md @@ -199,15 +199,22 @@ $ fn config app flows-example COMPLETER_BASE_URL "http://$DOCKER_LOCALHOST:8081" ### Run your Flow function -You can now run your function using `fn call` or HTTP and curl: +You can now run your function using `fn invoke` or HTTP. ``` -$ echo 10 | fn call flows-example /primes +$ echo 10 | fn invoke flows-example primes The 10th prime number is 29 ``` +To invoke your function via HTTP, you need to know its invocation endpoint (or the function needs to have an HTTP trigger defined). + +``` +$ fn inspect fn flows-examples primes ``` -$ curl -XPOST -d "10" http://localhost:8080/r/flows-example/primes + +Take note of the `fnproject.io/fn/invokeEndpoint` URL and invoke it (ex. using curl). + +$ curl -X POST -d "10" http://localhost:8080/invoke/... The 10th prime number is 29 ``` From d85e3a18c69daf6510ff3c4de5e16b4cc1bee640 Mon Sep 17 00:00:00 2001 From: Michael Williams Date: Wed, 20 Mar 2019 17:35:03 -0600 Subject: [PATCH 109/310] A first cut at updating and simplifying the Java FDK Readme. Removed user tutorial already included in tutorials. Reorganized and simplified. More work to do reviewing each of the docs linked here. --- README.md | 333 ++++++------------------------------------------------ 1 file changed, 32 insertions(+), 301 deletions(-) diff --git a/README.md b/README.md index 8978ea11..be0be541 100644 --- a/README.md +++ b/README.md @@ -1,310 +1,50 @@ -# Fn Java Functions Developer Kit (FDK) [![CircleCI](https://circleci.com/gh/fnproject/fdk-java.svg?style=svg&circle-token=348bec5610c34421f6c436ab8f6a18e153cb1c01)](https://circleci.com/gh/fnproject/fdk-java) -This project adds support for writing functions in Java on the [Fn -platform](https://github.com/fnproject/fn), with full support for Java 11 -as the default out of the box. - -# FAQ -Some common questions are answered in [our FAQ](docs/FAQ.md). - -# Quick Start Tutorial - -By following this step-by-step guide you will learn to create, run and deploy -a simple app written in Java on Fn. - -## Pre-requisites - -Before you get started you will need the following things: - -* The [Fn CLI](https://github.com/fnproject/cli) tool -* [Docker-ce 17.06+ installed locally](https://docs.docker.com/engine/installation/) - -### Install the Fn CLI tool - -To install the Fn CLI tool, just run the following: - -``` -curl -LSs https://raw.githubusercontent.com/fnproject/cli/master/install | sh -``` - -This will download a shell script and execute it. If the script asks for -a password, that is because it invokes sudo. - -## Your first Function - -### 1. Create your first Java Function: - -```bash -$ mkdir hello-java-function && cd hello-java-function -$ fn init --runtime=java --name your_dockerhub_account/hello -Runtime: java -function boilerplate generated. -func.yaml created -``` - -This creates the boilerplate for a new Java Function based on Maven and Oracle -Java 11. The `pom.xml` includes a dependency on the latest version of the Fn -Java FDK that is useful for developing your Java functions. - -You can now import this project into your favourite IDE as normal. - -### 2. Deep dive into your first Java Function: -We'll now take a look at what makes up our new Java Function. First, lets take -a look at the `func.yaml`: - -```bash -$ cat func.yaml -name: your_dockerhub_account/hello -version: 0.0.1 -runtime: java -cmd: com.example.fn.HelloFunction::handleRequest -``` - -The `cmd` field determines which method is called when your function is -invoked. In the generated Function, the `func.yaml` references -`com.example.fn.HelloFunction::handleRequest`. Your functions will likely live -in different classes, and this field should always point to the method to -execute, with the following syntax: - -```text -cmd: :: -``` - -For more information about the fields in `func.yaml`, refer to the [Fn platform -documentation](https://github.com/fnproject/fn/blob/master/docs/function-file.md) -about it. - -Let's also have a brief look at the source: -`src/main/java/com/example/fn/HelloFunction.java`: - -```java -package com.example.fn; - -public class HelloFunction { - - public String handleRequest(String input) { - String name = (input == null || input.isEmpty()) ? "world" : input; - - return "Hello, " + name + "!"; - } - -} -``` - -The function takes some optional input and returns a greeting dependent on it. - -### 3. Run your first Java Function: -You are now ready to run your Function locally using the Fn CLI tool. - -```bash -$ fn build -Building image your_dockerhub_account/hello:0.0.1 -Sending build context to Docker daemon 14.34kB -Step 1/11 : FROM fnproject/fn-java-fdk-build:jdk11-latest as build-stage - ---> 5435658a63ac -Step 2/11 : WORKDIR /function - ---> 37340c5aa451 - -... - -Step 5/11 : RUN mvn package dependency:copy-dependencies -DincludeScope=runtime -DskipTests=true -Dmdep.prependGroupId=true -DoutputDirectory=target --fail-never ----> Running in 58b3b1397ba2 -[INFO] Scanning for projects... -Downloading: https://repo.maven.apache.org/maven2/org/apache/maven/plugins/maven-compiler-plugin/3.3/maven-compiler-plugin-3.3.pom -Downloaded: https://repo.maven.apache.org/maven2/org/apache/maven/plugins/maven-compiler-plugin/3.3/maven-compiler-plugin-3.3.pom (11 kB at 21 kB/s) - -... - -[INFO] ------------------------------------------------------------------------ -[INFO] BUILD SUCCESS -[INFO] ------------------------------------------------------------------------ -[INFO] Total time: 2.228 s -[INFO] Finished at: 2017-06-27T12:06:59Z -[INFO] Final Memory: 18M/143M -[INFO] ------------------------------------------------------------------------ - -... - -Function your_dockerhub_account/hello:0.0.1 built successfully. - -$ fn run -Hello, world! -``` - -The next time you run this, it will execute much quicker as your dependencies -are cached. Try passing in some input this time: - -```bash -$ echo -n "Universe" | fn run -... -Hello, Universe! -``` - -### 4. Testing your function -The Fn Java FDK includes a testing library providing useful [JUnit -4](http://junit.org/junit4/) rules to test functions. Look at the test in -`src/test/java/com/example/fn/HelloFunctionTest.java`: - -```java -package com.example.fn; - -import com.fnproject.fn.testing.*; -import org.junit.*; - -import static org.junit.Assert.*; - -public class HelloFunctionTest { - - @Rule - public final FnTestingRule testing = FnTestingRule.createDefault(); - - @Test - public void shouldReturnGreeting() { - testing.givenEvent().enqueue(); - testing.thenRun(HelloFunction.class, "handleRequest"); - - FnResult result = testing.getOnlyResult(); - assertEquals("Hello, world!", result.getBodyAsString()); - } - -} -``` - -This test is very simple: it just enqueues an event with empty input and then -runs the function, checking its output. Under the hood, the `FnTestingRule` is -actually instantiating the same runtime wrapping function invocations, so that -during the test your function will be invoked in exactly the same way that it -would when deployed. - -There is much more functionality to construct tests in the testing library. -Testing functions is covered in more detail in [Testing -Functions](docs/TestingFunctions.md). - -### 5. Run using HTTP and the local Fn server -The previous example used `fn run` to run a function directly via docker, you -can also use the Fn server locally to test the deployment of your function and -the HTTP calls to your functions. - -Open another terminal and start the Fn server: - -```bash -$ fn start -``` - -Then in your original terminal create an app: - -```bash -$ fn create app java-app -Successfully created app: java-app -``` - -Now deploy your Function using the `fn deploy` command. This will bump the -function's version up, rebuild it, and push the image to the Docker registry, -ready to be used in the function deployment. Finally it will create a route on -the local Fn server, corresponding to your function. - -We are using the `--local` flag to tell fn to skip pushing the image anywhere -as we are just going to run this on our local fn server that we started with -`fn start` above. - -```bash -$ fn deploy --app java-app --local -... -Bumped to version 0.0.2 -Building image hello:0.0.2 -Sending build context to Docker daemon 14.34kB - -... - -Successfully built bf2b7fa55520 -Successfully tagged your_dockerhub_account/hello:0.0.2 -Updating route /hello-java-function using image your_dockerhub_account/hello:0.0.2... -``` - -Call the Function via the Fn CLI: - -```bash -$ fn call java-app /hello-java-function -Hello, world! -``` - -You can also call the Function via curl: +# Fn Java Functions Developer Kit (FDK) +The Java Function Developer Kit (FDK) makes it easy to deploy Java functions to Fn with full support for Java 11+ as the default out of the box. -```bash -$ curl http://localhost:8080/r/java-app/hello-java-function -Hello, world! +## Install +MacOS installation: +```sh +brew update && brew install fn ``` -### 6. Something more interesting -The Fn Java FDK supports [flexible data binding](docs/DataBinding.md) to make -it easier for you to map function input and output data to Java objects. - -Below is an example to of a Function that returns a POJO which will be -serialized to JSON using Jackson: - -```java -package com.example.fn; - -public class PojoFunction { - - public static class Greeting { - public final String name; - public final String salutation; - - public Greeting(String salutation, String name) { - this.salutation = salutation; - this.name = name; - } - } - - public Greeting greet(String name) { - if (name == null || name.isEmpty()) - name = "World"; - - return new Greeting("Hello", name); - } - -} -``` +or -Update your `func.yaml` to reference the new method: +Alternatively for Linux/Unix/MacOS: -```yaml -cmd: com.example.fn.PojoFunction::greet +```sh +curl -LSs https://raw.githubusercontent.com/fnproject/cli/master/install | sh ``` -Now run your new function: - -```bash -$ fn run -... -{"name":"World","salutation":"Hello"} +## General Information +* See the Fn [Quickstart](https://github.com/fnproject/fn/blob/master/README.md) for sample commands. +* [Detailed installation instructions](http://fnproject.io/tutorials/install/). +* [Configure your CLI Context](http://fnproject.io/tutorials/install/#ConfigureyourContext). +* For a list of commands see [Fn CLI Command Guide and Reference](https://github.com/fnproject/docs/blob/master/cli/README.md). +* For general information see Fn [docs](https://github.com/fnproject/docs) and [tutorials](https://fnproject.io/tutorials/). -$ echo -n Michael | fn run -... -{"name":"Michael","salutation":"Hello"} -``` +## Fn Java FDK Development Information +### Contributing +Please see [CONTRIBUTING.md](CONTRIBUTING.md). -## 7. Where do I go from here? +### Fn Java FDK FAQ +Some common questions are answered in [our FAQ](docs/FAQ.md). -Learn more about the Fn Java FDK by reading the next tutorials in the series. -Also check out the examples in the [`examples` directory](examples) for some -functions demonstrating different features of the Fn Java FDK. +### Fn Java FDK Tutorials and Examples -### Configuring your function +#### Examples +Check out Java FDK examples in the [`examples`](examples) directory for +functions demonstrating different Fn Java FDK features. -If you want to set up the state of your function object before the function is -invoked, and to use external configuration variables that you can set up with -the Fn tool, have a look at the [Function +#### Configuring your Function +Want to set up function object state before the function is invoked using external configuration variables? Have a look at the [Function Configuration](docs/FunctionConfiguration.md) tutorial. -### Handling HTTP requests - -If your function serves an HTTP trigger you may want to access HTTP details such as request or response headers or the HTTP status , check out [Accessing HTTP Information From Functions](docs/HTTPGatewayFunctions.md). - -### Input and output bindings +#### Handling HTTP Requests +Want to access HTTP details such as request or response headers or the HTTP status? Check out [Accessing HTTP Information from Functions](docs/HTTPGatewayFunctions.md). +#### Input and Output Bindings You have the option of taking more control of how serialization and deserialization is performed by defining your own bindings. @@ -312,8 +52,7 @@ See the [Data Binding](docs/DataBinding.md) tutorial for other out-of-the-box options and the [Extending Data Binding](docs/ExtendingDataBinding.md) tutorial for how to define and use your own bindings. -### Asynchronous workflows - +#### Asynchronous Workflows Suppose you want to call out to some other function from yours - perhaps a function written in a different language, or even one maintained by a different team. Maybe you then want to do some processing on the result. Or @@ -323,13 +62,5 @@ function, but you don't want to pay for execution time while you're waiting for someone else to do their work. If this sounds like you, then have a look at the [Fn Flow -quickstart](docs/FnFlowsUserGuide.md). - -# Get help +Quickstart](docs/FnFlowsUserGuide.md). - * Come over and chat to us on the [fnproject Slack](https://join.slack.com/t/fnproject/shared_invite/enQtMjIwNzc5MTE4ODg3LTdlYjE2YzU1MjAxODNhNGUzOGNhMmU2OTNhZmEwOTcxZDQxNGJiZmFiMzNiMTk0NjU2NTIxZGEyNjI0YmY4NTA). - * Raise an issue in [our github](https://github.com/fnproject/fn-java-fdk/). - -# Contributing - -Please see [CONTRIBUTING.md](CONTRIBUTING.md). From ace2f37accef022145bc68eef808e2fbafe04654 Mon Sep 17 00:00:00 2001 From: Chad Arimura Date: Thu, 21 Mar 2019 08:51:40 -0700 Subject: [PATCH 110/310] simplifying the fdk repo readme along with mikes update --- README.md | 65 ++++++++++--------------------------------------------- 1 file changed, 11 insertions(+), 54 deletions(-) diff --git a/README.md b/README.md index be0be541..914dc5a7 100644 --- a/README.md +++ b/README.md @@ -1,66 +1,23 @@ [![CircleCI](https://circleci.com/gh/fnproject/fdk-java.svg?style=svg&circle-token=348bec5610c34421f6c436ab8f6a18e153cb1c01)](https://circleci.com/gh/fnproject/fdk-java) -# Fn Java Functions Developer Kit (FDK) -The Java Function Developer Kit (FDK) makes it easy to deploy Java functions to Fn with full support for Java 11+ as the default out of the box. +# Java Function Development Kit (FDK) -## Install -MacOS installation: -```sh -brew update && brew install fn -``` +The Java Function Development Kit (FDK) makes it easy to build and deploy Java functions to Fn with full support for Java 11+ as the default out of the box. -or +Some of the Java FDK's features include: -Alternatively for Linux/Unix/MacOS: +- Parsing input and writing output +- Flexible data binding to Java objects +- Function testing using JUNit rules +- And more! -```sh -curl -LSs https://raw.githubusercontent.com/fnproject/cli/master/install | sh -``` -## General Information -* See the Fn [Quickstart](https://github.com/fnproject/fn/blob/master/README.md) for sample commands. -* [Detailed installation instructions](http://fnproject.io/tutorials/install/). -* [Configure your CLI Context](http://fnproject.io/tutorials/install/#ConfigureyourContext). -* For a list of commands see [Fn CLI Command Guide and Reference](https://github.com/fnproject/docs/blob/master/cli/README.md). -* For general information see Fn [docs](https://github.com/fnproject/docs) and [tutorials](https://fnproject.io/tutorials/). +## Using the Java FDK -## Fn Java FDK Development Information -### Contributing -Please see [CONTRIBUTING.md](CONTRIBUTING.md). - -### Fn Java FDK FAQ -Some common questions are answered in [our FAQ](docs/FAQ.md). - -### Fn Java FDK Tutorials and Examples - -#### Examples -Check out Java FDK examples in the [`examples`](examples) directory for -functions demonstrating different Fn Java FDK features. +For detailed instructions on using the Java FDK to build and deploy Java functions to Fn, please see the official Java FDK developer guide in our docs repo here: https://github.com/fnproject/docs/blob/master/fdks/fdk-java/README.md. -#### Configuring your Function -Want to set up function object state before the function is invoked using external configuration variables? Have a look at the [Function -Configuration](docs/FunctionConfiguration.md) tutorial. +## Contributing to the Java FDK -#### Handling HTTP Requests -Want to access HTTP details such as request or response headers or the HTTP status? Check out [Accessing HTTP Information from Functions](docs/HTTPGatewayFunctions.md). - -#### Input and Output Bindings -You have the option of taking more control of how serialization and -deserialization is performed by defining your own bindings. - -See the [Data Binding](docs/DataBinding.md) tutorial for other out-of-the-box -options and the [Extending Data Binding](docs/ExtendingDataBinding.md) tutorial -for how to define and use your own bindings. - -#### Asynchronous Workflows -Suppose you want to call out to some other function from yours - perhaps -a function written in a different language, or even one maintained by -a different team. Maybe you then want to do some processing on the result. Or -even have your function interact asynchronously with a completely different -system. Perhaps you also need to maintain some state for the duration of your -function, but you don't want to pay for execution time while you're waiting for -someone else to do their work. +Please see [CONTRIBUTING.md](CONTRIBUTING.md). -If this sounds like you, then have a look at the [Fn Flow -Quickstart](docs/FnFlowsUserGuide.md). From 83c34b4d5949d82972a5628820d8d9c61e53d5be Mon Sep 17 00:00:00 2001 From: Chad Arimura Date: Thu, 21 Mar 2019 08:52:24 -0700 Subject: [PATCH 111/310] Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 914dc5a7..000999e1 100644 --- a/README.md +++ b/README.md @@ -8,7 +8,7 @@ Some of the Java FDK's features include: - Parsing input and writing output - Flexible data binding to Java objects -- Function testing using JUNit rules +- Function testing using JUnit rules - And more! From d6615af2c1c72fbf3e0d574b17abc5a3f30443c6 Mon Sep 17 00:00:00 2001 From: Chad Arimura Date: Mon, 25 Mar 2019 14:23:41 -0700 Subject: [PATCH 112/310] add generic link back to official docs --- README.md | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/README.md b/README.md index 914dc5a7..814d6bb4 100644 --- a/README.md +++ b/README.md @@ -11,6 +11,9 @@ Some of the Java FDK's features include: - Function testing using JUNit rules - And more! +## Learn about the Fn Project + +New to Fn Project? If you want to learn more about using the Fn Project to power your next project, start with the [official documentation](https://github.com/fnproject/docs). ## Using the Java FDK @@ -21,3 +24,5 @@ For detailed instructions on using the Java FDK to build and deploy Java functio Please see [CONTRIBUTING.md](CONTRIBUTING.md). + + From b6a39f01a6c5120d3e896d7705b92156e7a5154e Mon Sep 17 00:00:00 2001 From: Nisha Lad Date: Wed, 27 Mar 2019 15:28:29 +0000 Subject: [PATCH 113/310] WIP fn user added to runtime image, working on adding user to the init-image --- images/runtime/Dockerfile | 2 ++ images/runtime/Dockerfile-jre11 | 2 ++ 2 files changed, 4 insertions(+) diff --git a/images/runtime/Dockerfile b/images/runtime/Dockerfile index e2fdc392..0133627b 100644 --- a/images/runtime/Dockerfile +++ b/images/runtime/Dockerfile @@ -4,6 +4,8 @@ COPY src/main/c/libfnunixsocket.so /function/runtime/lib/ RUN ["/usr/lib/jvm/java-8-openjdk-amd64/jre/bin/java", "-Xshare:dump"] +RUN addgroup -g 1000 -S fn && adduser -S -u 1000 -G fn fn + # UseCGroupMemoryLimitForHeap looks up /sys/fs/cgroup/memory/memory.limit_in_bytes inside the container to determine # what the heap should be set to. This is an experimental feature at the moment, thus we need to unlock to use it. # diff --git a/images/runtime/Dockerfile-jre11 b/images/runtime/Dockerfile-jre11 index 0574f914..b4bf5984 100644 --- a/images/runtime/Dockerfile-jre11 +++ b/images/runtime/Dockerfile-jre11 @@ -4,6 +4,8 @@ COPY src/main/c/libfnunixsocket.so /function/runtime/lib/ RUN ["/usr/bin/java", "-Xshare:dump"] +RUN addgroup -g 1000 -S fn && adduser -S -u 1000 -G fn fn + # The UseExeperimentalVMOptions, UseCGroupMemoryLimitForHeap and MaxRAMFraction options that were used in the JDK 9 builds are # no longer supported in JDK 11 - so these have been removed. We now rely on the built-in ContainerSupport option that Linux JDKs # use to configure themselves when detecting they are running in a container. From 42d2725676a1293db523d5ffbf22d36ad17b672f Mon Sep 17 00:00:00 2001 From: Nisha Lad Date: Thu, 28 Mar 2019 11:19:26 +0000 Subject: [PATCH 114/310] added fn user to runtime java --- images/init-native/Dockerfile | 1 + images/init-native/Dockerfile-init-image | 1 + 2 files changed, 2 insertions(+) diff --git a/images/init-native/Dockerfile b/images/init-native/Dockerfile index 673bb276..c5e9c675 100644 --- a/images/init-native/Dockerfile +++ b/images/init-native/Dockerfile @@ -30,4 +30,5 @@ WORKDIR /function COPY --from=build-native-image /function/func func COPY --from=build-native-image /function/runtime/lib/* . ENTRYPOINT ["./func", "-XX:MaximumHeapSizePercent=80"] +RUN addgroup -g 1000 -S fn && adduser -S -u 1000 -G fn fn CMD [ "com.example.fn.HelloFunction::handleRequest" ] diff --git a/images/init-native/Dockerfile-init-image b/images/init-native/Dockerfile-init-image index 0850e955..529d4527 100644 --- a/images/init-native/Dockerfile-init-image +++ b/images/init-native/Dockerfile-init-image @@ -22,4 +22,5 @@ fi\n\ tar c src pom.xml func.init.yaml Dockerfile\n' > build_init_image.sh \ && chmod 755 build_init_image.sh +RUN addgroup -g 1000 -S fn && adduser -S -u 1000 -G fn fn CMD ["./build_init_image.sh"] From 4a5b363846cc04f5a245a0d2274abbe74455a0da Mon Sep 17 00:00:00 2001 From: Nisha Lad Date: Thu, 28 Mar 2019 11:58:22 +0000 Subject: [PATCH 115/310] changes to RUN cmd syntax --- images/init-native/Dockerfile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/images/init-native/Dockerfile b/images/init-native/Dockerfile index c5e9c675..4fa99a90 100644 --- a/images/init-native/Dockerfile +++ b/images/init-native/Dockerfile @@ -30,5 +30,5 @@ WORKDIR /function COPY --from=build-native-image /function/func func COPY --from=build-native-image /function/runtime/lib/* . ENTRYPOINT ["./func", "-XX:MaximumHeapSizePercent=80"] -RUN addgroup -g 1000 -S fn && adduser -S -u 1000 -G fn fn +RUN addgroup --system --gid 1000 fn && adduser --uid 1000 --group fn fn CMD [ "com.example.fn.HelloFunction::handleRequest" ] From 2063c06e9166c84ff11667d84dd74a7e1aa014ce Mon Sep 17 00:00:00 2001 From: Nisha Lad Date: Thu, 28 Mar 2019 12:12:24 +0000 Subject: [PATCH 116/310] trying to run fn user with correct cli flags --- images/init-native/Dockerfile | 1 - images/init-native/Dockerfile-init-image | 1 - images/runtime/Dockerfile | 2 +- images/runtime/Dockerfile-jre11 | 2 -- 4 files changed, 1 insertion(+), 5 deletions(-) diff --git a/images/init-native/Dockerfile b/images/init-native/Dockerfile index 4fa99a90..673bb276 100644 --- a/images/init-native/Dockerfile +++ b/images/init-native/Dockerfile @@ -30,5 +30,4 @@ WORKDIR /function COPY --from=build-native-image /function/func func COPY --from=build-native-image /function/runtime/lib/* . ENTRYPOINT ["./func", "-XX:MaximumHeapSizePercent=80"] -RUN addgroup --system --gid 1000 fn && adduser --uid 1000 --group fn fn CMD [ "com.example.fn.HelloFunction::handleRequest" ] diff --git a/images/init-native/Dockerfile-init-image b/images/init-native/Dockerfile-init-image index 529d4527..0850e955 100644 --- a/images/init-native/Dockerfile-init-image +++ b/images/init-native/Dockerfile-init-image @@ -22,5 +22,4 @@ fi\n\ tar c src pom.xml func.init.yaml Dockerfile\n' > build_init_image.sh \ && chmod 755 build_init_image.sh -RUN addgroup -g 1000 -S fn && adduser -S -u 1000 -G fn fn CMD ["./build_init_image.sh"] diff --git a/images/runtime/Dockerfile b/images/runtime/Dockerfile index 0133627b..6fe496f4 100644 --- a/images/runtime/Dockerfile +++ b/images/runtime/Dockerfile @@ -4,7 +4,7 @@ COPY src/main/c/libfnunixsocket.so /function/runtime/lib/ RUN ["/usr/lib/jvm/java-8-openjdk-amd64/jre/bin/java", "-Xshare:dump"] -RUN addgroup -g 1000 -S fn && adduser -S -u 1000 -G fn fn +RUN addgroup --system --gid 1000 fn && adduser --uid 1000 --group fn fn # UseCGroupMemoryLimitForHeap looks up /sys/fs/cgroup/memory/memory.limit_in_bytes inside the container to determine # what the heap should be set to. This is an experimental feature at the moment, thus we need to unlock to use it. diff --git a/images/runtime/Dockerfile-jre11 b/images/runtime/Dockerfile-jre11 index b4bf5984..0574f914 100644 --- a/images/runtime/Dockerfile-jre11 +++ b/images/runtime/Dockerfile-jre11 @@ -4,8 +4,6 @@ COPY src/main/c/libfnunixsocket.so /function/runtime/lib/ RUN ["/usr/bin/java", "-Xshare:dump"] -RUN addgroup -g 1000 -S fn && adduser -S -u 1000 -G fn fn - # The UseExeperimentalVMOptions, UseCGroupMemoryLimitForHeap and MaxRAMFraction options that were used in the JDK 9 builds are # no longer supported in JDK 11 - so these have been removed. We now rely on the built-in ContainerSupport option that Linux JDKs # use to configure themselves when detecting they are running in a container. From accc42873d69b9e5ad87c9d747b09764be0e96c8 Mon Sep 17 00:00:00 2001 From: Nisha Lad Date: Thu, 28 Mar 2019 12:24:41 +0000 Subject: [PATCH 117/310] added user name --- images/runtime/Dockerfile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/images/runtime/Dockerfile b/images/runtime/Dockerfile index 6fe496f4..c1108d52 100644 --- a/images/runtime/Dockerfile +++ b/images/runtime/Dockerfile @@ -4,7 +4,7 @@ COPY src/main/c/libfnunixsocket.so /function/runtime/lib/ RUN ["/usr/lib/jvm/java-8-openjdk-amd64/jre/bin/java", "-Xshare:dump"] -RUN addgroup --system --gid 1000 fn && adduser --uid 1000 --group fn fn +RUN addgroup --system --gid 1000 fn && adduser fn --uid 1000 --group fn # UseCGroupMemoryLimitForHeap looks up /sys/fs/cgroup/memory/memory.limit_in_bytes inside the container to determine # what the heap should be set to. This is an experimental feature at the moment, thus we need to unlock to use it. From f9e02c7d9bc25f6fd9b731c3d63a61d0066aebe7 Mon Sep 17 00:00:00 2001 From: Nisha Lad Date: Thu, 28 Mar 2019 12:32:24 +0000 Subject: [PATCH 118/310] added gid --- images/runtime/Dockerfile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/images/runtime/Dockerfile b/images/runtime/Dockerfile index c1108d52..3aef82ba 100644 --- a/images/runtime/Dockerfile +++ b/images/runtime/Dockerfile @@ -4,7 +4,7 @@ COPY src/main/c/libfnunixsocket.so /function/runtime/lib/ RUN ["/usr/lib/jvm/java-8-openjdk-amd64/jre/bin/java", "-Xshare:dump"] -RUN addgroup --system --gid 1000 fn && adduser fn --uid 1000 --group fn +RUN addgroup --system --gid 1000 fn && adduser --uid 1000 --gid 1000 fn # UseCGroupMemoryLimitForHeap looks up /sys/fs/cgroup/memory/memory.limit_in_bytes inside the container to determine # what the heap should be set to. This is an experimental feature at the moment, thus we need to unlock to use it. From 3a09582b0eee41e5652f4613b92e0befdd4cfc5b Mon Sep 17 00:00:00 2001 From: Nisha Lad Date: Thu, 28 Mar 2019 13:24:59 +0000 Subject: [PATCH 119/310] create app before deploy app --- .../test/java/com/fnproject/fn/integrationtest/FlowTest.java | 3 +++ 1 file changed, 3 insertions(+) diff --git a/integration-tests/src/test/java/com/fnproject/fn/integrationtest/FlowTest.java b/integration-tests/src/test/java/com/fnproject/fn/integrationtest/FlowTest.java index 09733c24..4dd0eb23 100644 --- a/integration-tests/src/test/java/com/fnproject/fn/integrationtest/FlowTest.java +++ b/integration-tests/src/test/java/com/fnproject/fn/integrationtest/FlowTest.java @@ -26,6 +26,7 @@ public class FlowTest { public void shouldInvokeBasicFlow() throws Exception { IntegrationTestRule.TestContext tc = testRule.newTest(); tc.withDirFrom("funcs/flowBasic").rewritePOM(); + tc.runFn("--verbose", "create", "app", tc.appName(), "--local"); tc.runFn("--verbose", "deploy", "--app", tc.appName(), "--local"); tc.runFn("config", "app", tc.appName(), "COMPLETER_BASE_URL", testRule.getFlowURL()); CmdResult r = tc.runFnWithInput("1", "invoke", tc.appName(), "flowbasic"); @@ -37,6 +38,7 @@ public void shouldInvokeBasicFlow() throws Exception { public void shouldInvokeBasicFlowJDK8() throws Exception { IntegrationTestRule.TestContext tc = testRule.newTest(); tc.withDirFrom("funcs/flowBasicJDK8").rewritePOM(); + tc.runFn("--verbose", "create", "app", tc.appName(), "--local"); tc.runFn("--verbose", "deploy", "--app", tc.appName(), "--local"); tc.runFn("config", "app", tc.appName(), "COMPLETER_BASE_URL", testRule.getFlowURL()); CmdResult r = tc.runFnWithInput("1", "invoke", tc.appName(), "flowbasicj8"); @@ -48,6 +50,7 @@ public void shouldInvokeBasicFlowJDK8() throws Exception { public void shouldExerciseAllFlow() throws Exception { IntegrationTestRule.TestContext tc = testRule.newTest(); tc.withDirFrom("funcs/flowAllFeatures").rewritePOM(); + tc.runFn("--verbose", "create", "app", tc.appName(), "--local"); tc.runFn("--verbose", "deploy", "--app", tc.appName(), "--local"); tc.runFn("config", "app", tc.appName(), "COMPLETER_BASE_URL", testRule.getFlowURL()); CmdResult r = tc.runFnWithInput("1", "invoke", tc.appName(), "flowallfeatures"); From 00acda10d95608110df4f209926b6dcf47cdf3c0 Mon Sep 17 00:00:00 2001 From: Nisha Lad Date: Thu, 28 Mar 2019 13:37:54 +0000 Subject: [PATCH 120/310] remove --local from create app --- .../java/com/fnproject/fn/integrationtest/FlowTest.java | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/integration-tests/src/test/java/com/fnproject/fn/integrationtest/FlowTest.java b/integration-tests/src/test/java/com/fnproject/fn/integrationtest/FlowTest.java index 4dd0eb23..c82a1044 100644 --- a/integration-tests/src/test/java/com/fnproject/fn/integrationtest/FlowTest.java +++ b/integration-tests/src/test/java/com/fnproject/fn/integrationtest/FlowTest.java @@ -26,7 +26,7 @@ public class FlowTest { public void shouldInvokeBasicFlow() throws Exception { IntegrationTestRule.TestContext tc = testRule.newTest(); tc.withDirFrom("funcs/flowBasic").rewritePOM(); - tc.runFn("--verbose", "create", "app", tc.appName(), "--local"); + tc.runFn("--verbose", "create", "app", tc.appName()); tc.runFn("--verbose", "deploy", "--app", tc.appName(), "--local"); tc.runFn("config", "app", tc.appName(), "COMPLETER_BASE_URL", testRule.getFlowURL()); CmdResult r = tc.runFnWithInput("1", "invoke", tc.appName(), "flowbasic"); @@ -38,7 +38,7 @@ public void shouldInvokeBasicFlow() throws Exception { public void shouldInvokeBasicFlowJDK8() throws Exception { IntegrationTestRule.TestContext tc = testRule.newTest(); tc.withDirFrom("funcs/flowBasicJDK8").rewritePOM(); - tc.runFn("--verbose", "create", "app", tc.appName(), "--local"); + tc.runFn("--verbose", "create", "app", tc.appName()); tc.runFn("--verbose", "deploy", "--app", tc.appName(), "--local"); tc.runFn("config", "app", tc.appName(), "COMPLETER_BASE_URL", testRule.getFlowURL()); CmdResult r = tc.runFnWithInput("1", "invoke", tc.appName(), "flowbasicj8"); @@ -50,7 +50,7 @@ public void shouldInvokeBasicFlowJDK8() throws Exception { public void shouldExerciseAllFlow() throws Exception { IntegrationTestRule.TestContext tc = testRule.newTest(); tc.withDirFrom("funcs/flowAllFeatures").rewritePOM(); - tc.runFn("--verbose", "create", "app", tc.appName(), "--local"); + tc.runFn("--verbose", "create", "app", tc.appName()); tc.runFn("--verbose", "deploy", "--app", tc.appName(), "--local"); tc.runFn("config", "app", tc.appName(), "COMPLETER_BASE_URL", testRule.getFlowURL()); CmdResult r = tc.runFnWithInput("1", "invoke", tc.appName(), "flowallfeatures"); From 01b1a90d19f850a44e4d0dc4151ec2932b643274 Mon Sep 17 00:00:00 2001 From: Nisha Lad Date: Thu, 28 Mar 2019 13:57:44 +0000 Subject: [PATCH 121/310] create app before deploy in all integ tests --- .../java/com/fnproject/fn/integrationtest/FunctionsTest.java | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/integration-tests/src/test/java/com/fnproject/fn/integrationtest/FunctionsTest.java b/integration-tests/src/test/java/com/fnproject/fn/integrationtest/FunctionsTest.java index 62e078d0..09d9e5da 100644 --- a/integration-tests/src/test/java/com/fnproject/fn/integrationtest/FunctionsTest.java +++ b/integration-tests/src/test/java/com/fnproject/fn/integrationtest/FunctionsTest.java @@ -32,6 +32,7 @@ public void shouldCallExistingFn() throws Exception { IntegrationTestRule.TestContext tc = testRule.newTest(); tc.withDirFrom("funcs/simpleFunc").rewritePOM(); + tc.runFn("--verbose", "create", "app", tc.appName()); tc.runFn("--verbose", "deploy", "--app", tc.appName(), "--local"); tc.runFn("config", "app", tc.appName(), "GREETING", "Salutations"); @@ -45,6 +46,7 @@ public void shouldCallExistingFn() throws Exception { @Test() public void checkBoilerPlate() throws Exception { + tc.runFn("--verbose", "create", "app", tc.appName()); for (String runtime : new String[]{"java8", "java11"}) { IntegrationTestRule.TestContext tc = testRule.newTest(); @@ -67,7 +69,7 @@ public static class InspectResponse { public void shouldHandleTrigger() throws Exception { IntegrationTestRule.TestContext tc = testRule.newTest(); tc.withDirFrom("funcs/httpgwfunc").rewritePOM(); - + tc.runFn("--verbose", "create", "app", tc.appName()); tc.runFn("--verbose", "deploy", "--app", tc.appName(), "--local"); // Get me the trigger URL From bb3f3379d4113c2a58d92392faebf22565a0e81a Mon Sep 17 00:00:00 2001 From: Nisha Lad Date: Thu, 28 Mar 2019 14:11:25 +0000 Subject: [PATCH 122/310] deploy after context created --- .../java/com/fnproject/fn/integrationtest/FunctionsTest.java | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/integration-tests/src/test/java/com/fnproject/fn/integrationtest/FunctionsTest.java b/integration-tests/src/test/java/com/fnproject/fn/integrationtest/FunctionsTest.java index 09d9e5da..8aaff874 100644 --- a/integration-tests/src/test/java/com/fnproject/fn/integrationtest/FunctionsTest.java +++ b/integration-tests/src/test/java/com/fnproject/fn/integrationtest/FunctionsTest.java @@ -46,10 +46,9 @@ public void shouldCallExistingFn() throws Exception { @Test() public void checkBoilerPlate() throws Exception { - tc.runFn("--verbose", "create", "app", tc.appName()); for (String runtime : new String[]{"java8", "java11"}) { - IntegrationTestRule.TestContext tc = testRule.newTest(); - + IntegrationTestRule.TestContext tc = testRule.newTest(); + tc.runFn("--verbose", "create", "app", tc.appName()); String fnName = "bp" + runtime; tc.runFn("init", "--runtime", runtime, "--name", fnName); tc.rewritePOM(); From ab5a3ad7fb74f81239b47c169d735c405bce866c Mon Sep 17 00:00:00 2001 From: Nisha Lad Date: Thu, 28 Mar 2019 15:02:51 +0000 Subject: [PATCH 123/310] --create-app change to integ tests --- .../fn/integrationtest/FlowTest.java | 19 ++++++++++--------- .../fn/integrationtest/FunctionsTest.java | 12 ++++++------ 2 files changed, 16 insertions(+), 15 deletions(-) diff --git a/integration-tests/src/test/java/com/fnproject/fn/integrationtest/FlowTest.java b/integration-tests/src/test/java/com/fnproject/fn/integrationtest/FlowTest.java index c82a1044..b691232d 100644 --- a/integration-tests/src/test/java/com/fnproject/fn/integrationtest/FlowTest.java +++ b/integration-tests/src/test/java/com/fnproject/fn/integrationtest/FlowTest.java @@ -26,8 +26,8 @@ public class FlowTest { public void shouldInvokeBasicFlow() throws Exception { IntegrationTestRule.TestContext tc = testRule.newTest(); tc.withDirFrom("funcs/flowBasic").rewritePOM(); - tc.runFn("--verbose", "create", "app", tc.appName()); - tc.runFn("--verbose", "deploy", "--app", tc.appName(), "--local"); + // tc.runFn("--verbose", "create", "app", tc.appName()); + tc.runFn("--verbose", "deploy", "--create-app", "--app", tc.appName(), "--local"); tc.runFn("config", "app", tc.appName(), "COMPLETER_BASE_URL", testRule.getFlowURL()); CmdResult r = tc.runFnWithInput("1", "invoke", tc.appName(), "flowbasic"); assertThat(r.getStdout()).isEqualTo("4"); @@ -38,8 +38,8 @@ public void shouldInvokeBasicFlow() throws Exception { public void shouldInvokeBasicFlowJDK8() throws Exception { IntegrationTestRule.TestContext tc = testRule.newTest(); tc.withDirFrom("funcs/flowBasicJDK8").rewritePOM(); - tc.runFn("--verbose", "create", "app", tc.appName()); - tc.runFn("--verbose", "deploy", "--app", tc.appName(), "--local"); + //tc.runFn("--verbose", "create", "app", tc.appName()); + tc.runFn("--verbose", "deploy", "--create-app", "--app", tc.appName(), "--local"); tc.runFn("config", "app", tc.appName(), "COMPLETER_BASE_URL", testRule.getFlowURL()); CmdResult r = tc.runFnWithInput("1", "invoke", tc.appName(), "flowbasicj8"); assertThat(r.getStdout()).isEqualTo("4"); @@ -50,8 +50,8 @@ public void shouldInvokeBasicFlowJDK8() throws Exception { public void shouldExerciseAllFlow() throws Exception { IntegrationTestRule.TestContext tc = testRule.newTest(); tc.withDirFrom("funcs/flowAllFeatures").rewritePOM(); - tc.runFn("--verbose", "create", "app", tc.appName()); - tc.runFn("--verbose", "deploy", "--app", tc.appName(), "--local"); + //tc.runFn("--verbose", "create", "app", tc.appName()); + tc.runFn("--verbose", "deploy", "--create-app", "--app", tc.appName(), "--local"); tc.runFn("config", "app", tc.appName(), "COMPLETER_BASE_URL", testRule.getFlowURL()); CmdResult r = tc.runFnWithInput("1", "invoke", tc.appName(), "flowallfeatures"); assertThat(r.getStdout()).contains("Everything worked"); @@ -76,8 +76,8 @@ public void shouldCallExitHooks() throws Exception { IntegrationTestRule.TestContext tc = testRule.newTest(); tc.withDirFrom("funcs/flowExitHooks").rewritePOM(); tc.runFn("--verbose", "build", "--no-cache"); - - tc.runFn("--verbose", "deploy", "--app", tc.appName(), "--local"); + //tc.runFn("--verbose", "create", "app", tc.appName()); + tc.runFn("--verbose", "deploy", "--create-app", "--app", tc.appName(), "--local"); tc.runFn("config", "app", tc.appName(), "COMPLETER_BASE_URL", testRule.getFlowURL()); tc.runFn("config", "app", tc.appName(), "TERMINATION_HOOK_URL", "http://" + testRule.getDockerLocalhost() + ":" + 8000 + "/exited"); CmdResult r = tc.runFnWithInput("1", "invoke", tc.appName(), "flowexithooks"); @@ -95,7 +95,8 @@ public void shouldCallExitHooks() throws Exception { public void shouldHandleTimeouts() throws Exception { IntegrationTestRule.TestContext tc = testRule.newTest(); tc.withDirFrom("funcs/flowTimeouts").rewritePOM(); - tc.runFn("--verbose", "deploy", "--app", tc.appName(), "--local"); + //tc.runFn("--verbose", "create", "app", tc.appName()); + tc.runFn("--verbose", "deploy", "--create-app", "--app", tc.appName(), "--local"); tc.runFn("config", "app", tc.appName(), "COMPLETER_BASE_URL", testRule.getFlowURL()); CmdResult r = tc.runFn("invoke", tc.appName(), "flowtimeouts"); assertThat(r.getStdout()).contains("timeout"); diff --git a/integration-tests/src/test/java/com/fnproject/fn/integrationtest/FunctionsTest.java b/integration-tests/src/test/java/com/fnproject/fn/integrationtest/FunctionsTest.java index 8aaff874..f6e356d2 100644 --- a/integration-tests/src/test/java/com/fnproject/fn/integrationtest/FunctionsTest.java +++ b/integration-tests/src/test/java/com/fnproject/fn/integrationtest/FunctionsTest.java @@ -32,8 +32,8 @@ public void shouldCallExistingFn() throws Exception { IntegrationTestRule.TestContext tc = testRule.newTest(); tc.withDirFrom("funcs/simpleFunc").rewritePOM(); - tc.runFn("--verbose", "create", "app", tc.appName()); - tc.runFn("--verbose", "deploy", "--app", tc.appName(), "--local"); + //tc.runFn("--verbose", "create", "app", tc.appName()); + tc.runFn("--verbose", "deploy", "--create-app", "--app", tc.appName(), "--local"); tc.runFn("config", "app", tc.appName(), "GREETING", "Salutations"); CmdResult r1 = tc.runFnWithInput("", "invoke", tc.appName(), "simplefunc"); @@ -48,11 +48,11 @@ public void shouldCallExistingFn() throws Exception { public void checkBoilerPlate() throws Exception { for (String runtime : new String[]{"java8", "java11"}) { IntegrationTestRule.TestContext tc = testRule.newTest(); - tc.runFn("--verbose", "create", "app", tc.appName()); + //tc.runFn("--verbose", "create", "app", tc.appName()); String fnName = "bp" + runtime; tc.runFn("init", "--runtime", runtime, "--name", fnName); tc.rewritePOM(); - tc.runFn("--verbose", "deploy", "--app", tc.appName(), "--local"); + tc.runFn("--verbose", "deploy", "--create-app", "--app", tc.appName(), "--local"); CmdResult rs = tc.runFnWithInput("wibble", "invoke", tc.appName(), fnName); assertThat(rs.getStdout()).contains("Hello, wibble!"); } @@ -68,8 +68,8 @@ public static class InspectResponse { public void shouldHandleTrigger() throws Exception { IntegrationTestRule.TestContext tc = testRule.newTest(); tc.withDirFrom("funcs/httpgwfunc").rewritePOM(); - tc.runFn("--verbose", "create", "app", tc.appName()); - tc.runFn("--verbose", "deploy", "--app", tc.appName(), "--local"); + //tc.runFn("--verbose", "create", "app", tc.appName()); + tc.runFn("--verbose", "deploy", "--create-app", "--app", tc.appName(), "--local"); // Get me the trigger URL CmdResult output = tc.runFn("inspect", "trigger", tc.appName(), "httpgwfunc", "trig"); From 712aa4a8e679ba5e203b3fdc349778fbab80659e Mon Sep 17 00:00:00 2001 From: Nisha Lad Date: Thu, 28 Mar 2019 15:14:28 +0000 Subject: [PATCH 124/310] removal of comments --- .../test/java/com/fnproject/fn/integrationtest/FlowTest.java | 5 ----- .../java/com/fnproject/fn/integrationtest/FunctionsTest.java | 3 --- 2 files changed, 8 deletions(-) diff --git a/integration-tests/src/test/java/com/fnproject/fn/integrationtest/FlowTest.java b/integration-tests/src/test/java/com/fnproject/fn/integrationtest/FlowTest.java index b691232d..45dd0bc9 100644 --- a/integration-tests/src/test/java/com/fnproject/fn/integrationtest/FlowTest.java +++ b/integration-tests/src/test/java/com/fnproject/fn/integrationtest/FlowTest.java @@ -26,7 +26,6 @@ public class FlowTest { public void shouldInvokeBasicFlow() throws Exception { IntegrationTestRule.TestContext tc = testRule.newTest(); tc.withDirFrom("funcs/flowBasic").rewritePOM(); - // tc.runFn("--verbose", "create", "app", tc.appName()); tc.runFn("--verbose", "deploy", "--create-app", "--app", tc.appName(), "--local"); tc.runFn("config", "app", tc.appName(), "COMPLETER_BASE_URL", testRule.getFlowURL()); CmdResult r = tc.runFnWithInput("1", "invoke", tc.appName(), "flowbasic"); @@ -38,7 +37,6 @@ public void shouldInvokeBasicFlow() throws Exception { public void shouldInvokeBasicFlowJDK8() throws Exception { IntegrationTestRule.TestContext tc = testRule.newTest(); tc.withDirFrom("funcs/flowBasicJDK8").rewritePOM(); - //tc.runFn("--verbose", "create", "app", tc.appName()); tc.runFn("--verbose", "deploy", "--create-app", "--app", tc.appName(), "--local"); tc.runFn("config", "app", tc.appName(), "COMPLETER_BASE_URL", testRule.getFlowURL()); CmdResult r = tc.runFnWithInput("1", "invoke", tc.appName(), "flowbasicj8"); @@ -50,7 +48,6 @@ public void shouldInvokeBasicFlowJDK8() throws Exception { public void shouldExerciseAllFlow() throws Exception { IntegrationTestRule.TestContext tc = testRule.newTest(); tc.withDirFrom("funcs/flowAllFeatures").rewritePOM(); - //tc.runFn("--verbose", "create", "app", tc.appName()); tc.runFn("--verbose", "deploy", "--create-app", "--app", tc.appName(), "--local"); tc.runFn("config", "app", tc.appName(), "COMPLETER_BASE_URL", testRule.getFlowURL()); CmdResult r = tc.runFnWithInput("1", "invoke", tc.appName(), "flowallfeatures"); @@ -76,7 +73,6 @@ public void shouldCallExitHooks() throws Exception { IntegrationTestRule.TestContext tc = testRule.newTest(); tc.withDirFrom("funcs/flowExitHooks").rewritePOM(); tc.runFn("--verbose", "build", "--no-cache"); - //tc.runFn("--verbose", "create", "app", tc.appName()); tc.runFn("--verbose", "deploy", "--create-app", "--app", tc.appName(), "--local"); tc.runFn("config", "app", tc.appName(), "COMPLETER_BASE_URL", testRule.getFlowURL()); tc.runFn("config", "app", tc.appName(), "TERMINATION_HOOK_URL", "http://" + testRule.getDockerLocalhost() + ":" + 8000 + "/exited"); @@ -95,7 +91,6 @@ public void shouldCallExitHooks() throws Exception { public void shouldHandleTimeouts() throws Exception { IntegrationTestRule.TestContext tc = testRule.newTest(); tc.withDirFrom("funcs/flowTimeouts").rewritePOM(); - //tc.runFn("--verbose", "create", "app", tc.appName()); tc.runFn("--verbose", "deploy", "--create-app", "--app", tc.appName(), "--local"); tc.runFn("config", "app", tc.appName(), "COMPLETER_BASE_URL", testRule.getFlowURL()); CmdResult r = tc.runFn("invoke", tc.appName(), "flowtimeouts"); diff --git a/integration-tests/src/test/java/com/fnproject/fn/integrationtest/FunctionsTest.java b/integration-tests/src/test/java/com/fnproject/fn/integrationtest/FunctionsTest.java index f6e356d2..ab73d8b8 100644 --- a/integration-tests/src/test/java/com/fnproject/fn/integrationtest/FunctionsTest.java +++ b/integration-tests/src/test/java/com/fnproject/fn/integrationtest/FunctionsTest.java @@ -32,7 +32,6 @@ public void shouldCallExistingFn() throws Exception { IntegrationTestRule.TestContext tc = testRule.newTest(); tc.withDirFrom("funcs/simpleFunc").rewritePOM(); - //tc.runFn("--verbose", "create", "app", tc.appName()); tc.runFn("--verbose", "deploy", "--create-app", "--app", tc.appName(), "--local"); tc.runFn("config", "app", tc.appName(), "GREETING", "Salutations"); @@ -48,7 +47,6 @@ public void shouldCallExistingFn() throws Exception { public void checkBoilerPlate() throws Exception { for (String runtime : new String[]{"java8", "java11"}) { IntegrationTestRule.TestContext tc = testRule.newTest(); - //tc.runFn("--verbose", "create", "app", tc.appName()); String fnName = "bp" + runtime; tc.runFn("init", "--runtime", runtime, "--name", fnName); tc.rewritePOM(); @@ -68,7 +66,6 @@ public static class InspectResponse { public void shouldHandleTrigger() throws Exception { IntegrationTestRule.TestContext tc = testRule.newTest(); tc.withDirFrom("funcs/httpgwfunc").rewritePOM(); - //tc.runFn("--verbose", "create", "app", tc.appName()); tc.runFn("--verbose", "deploy", "--create-app", "--app", tc.appName(), "--local"); // Get me the trigger URL From 8fc154351dd8d29d7271344492321503677775dc Mon Sep 17 00:00:00 2001 From: CI Date: Fri, 29 Mar 2019 12:28:00 +0000 Subject: [PATCH 125/310] fn-java-fdk: post-1.0.86 version bump [skip ci] --- release.version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/release.version b/release.version index 24f0f658..9435145c 100644 --- a/release.version +++ b/release.version @@ -1 +1 @@ -1.0.86 +1.0.87 From ece041642401e5bbc980a5f43e3c33766a5104d3 Mon Sep 17 00:00:00 2001 From: Michael Williams Date: Thu, 4 Apr 2019 12:06:25 -0600 Subject: [PATCH 126/310] Update Java FDK string-reverse example --- examples/README.md | 20 +++--- examples/string-reverse/README.md | 60 +++++++++-------- examples/string-reverse/func.yaml | 16 +++-- examples/string-reverse/pom.xml | 66 ++++++++++++------- .../java/com/example/fn/StringReverse.java | 7 ++ .../fnproject/fn/examples/StringReverse.java | 11 ---- .../fn/testing}/StringReverseTest.java | 4 +- 7 files changed, 104 insertions(+), 80 deletions(-) create mode 100644 examples/string-reverse/src/main/java/com/example/fn/StringReverse.java delete mode 100644 examples/string-reverse/src/main/java/com/fnproject/fn/examples/StringReverse.java rename examples/string-reverse/src/test/java/com/{fnproject/examples => example/fn/testing}/StringReverseTest.java (87%) diff --git a/examples/README.md b/examples/README.md index 4995a246..0514760b 100644 --- a/examples/README.md +++ b/examples/README.md @@ -1,39 +1,39 @@ -# `fn` Java FDK Example Projects +# Fn Java FDK Example Projects In this directory you will find some example projects demonstrating different -features of the `fn` Java FDK: +features of the Fn Java FDK: * Plain java code support (`string-reverse`) * Functional testing of your functions (`regex-query` and `qr-code`) * Built-in JSON coercion (`regex-query`) * [InputEvent and OutputEvent](/docs/DataBinding.md) handling (`qr-code`) -## 1. String reverse +## (1) [String reverse](string-reverse/README.md) This function takes a string and returns the reverse of the string. -The `fn` Java FDK runtime will handle marshalling data into your -functions without the function having to have any knowledge of the FDK API. +The Fn Java FDK handles marshalling data into your +functions without the function having any knowledge of the FDK API. -## 2. Regex query +## (2) Regex query This function takes a JSON object containing a `text` field and a `regex` field and return a JSON object with a list of matches in the `matches` field. It demonstrates the builtin JSON support of the fn Java -wrapper (provided through Jackson) and how the platform handles serialisation +wrapper (provided through Jackson) and how the platform handles serialization of POJO return values. -## 3. QR Code gen +## (3) QR Code gen This function parses the query parameters of a GET request (through the `InputEvent` passed into the function) to generate a QR code. It demonstrates the `InputEvent` and `OutputEvent` interfaces which provide low level access to data entering the `fn` Java FDK. -## 4. Asynchronous thumbnails generation +## (4) Asynchronous thumbnails generation This example showcases the Fn Flow asynchronous execution API, by creating a workflow that takes an image and asynchronously generates three thumbnails for it, then uploads them to an object storage. -## 5. Gradle build +## (5) Gradle build This shows how to use Gradle to build functions using the Java FDK. diff --git a/examples/string-reverse/README.md b/examples/string-reverse/README.md index 4ae5f707..97eb79a0 100644 --- a/examples/string-reverse/README.md +++ b/examples/string-reverse/README.md @@ -1,71 +1,75 @@ -# Example oFunctions Project: String Reverse +# Example Java Function: String Reverse -This example provides an HTTP endpoint for reversing strings +This example provides an HTTP trigger endpoint for reversing strings. ```bash -$ curl -d "Hello, World!" "http://localhost:8080/r/string-reverse-app/reverse" -!dlroW ,olleH +$ curl -d "Hello World" http://localhost:8080/t/string-reverse-app/string-reverse +dlroW olleH ``` ## Demonstrated FDK features -This example uses **no** features of the fn Java FDK; in fact it doesn't have -a dependency on the fn Java FDK, it just plain old Java code. +This example uses **none** of the Fn Java FDK features, in fact it doesn't have +any dependency on the Fn Java FDK. It is just plain old Java code. ## Step by step -Ensure you have the functions server running using, this will host your -function and provide the HTTP endpoints that invoke it: +Ensure you have the Fn server running to host your +function and provide the HTTP endpoint that invokes it: -```bash +(1) Start the server + +```sh $ fn start ``` -Build the function locally +(2) Create an app for the function -```bash -$ fn build +```sh +$ fn create app string-reverse-app ``` -Create an app and route to host the function +(3) Deploy the function to your app from the `string-reverse` directory. -```bash -$ fn create app string-reverse-app -$ fn create route string-reverse-app /reverse +```sh +fn deploy --app string-reverse-app --local +``` + +(4) Invoke the function and reverse the string. + +```sh +echo "Hello World" | fn invoke string-reverse-app string-reverse +dlroW olleH ``` -Invoke the function to reverse a string +(5) Invoke the function using curl and a trigger to reverse a string. ```bash -$ curl -d "Hello, World!" "http://localhost:8080/r/string-reverse-app/reverse" -!dlroW ,olleH +$ curl -d "Hello World" http://localhost:8080/t/string-reverse-app/string-reverse +dlroW olleH ``` ## Code walkthrough The entrypoint to the function is specified in `func.yaml` in the `cmd` key. -It is set this to `com.fnproject.fn.examples.StringReverse::reverse`. The whole class +It is set this to `com.example.fn.StringReverse::reverse`. The whole class `StringReverse` is shown below: ```java -package com.fnproject.fn.examples; +package com.example.fn; public class StringReverse { public String reverse(String str) { - StringBuilder builder = new StringBuilder(); - for (int i = str.length() - 1; i >= 0; i--) { - builder.append(str.charAt(i)); - } - return builder.toString(); + return new StringBuilder(str).reverse().toString(); } } ``` -As you can see, this is plain java with no references to the fn API. The -fn Java FDK handles the marshalling of the HTTP body into the `str` +As you can see, this is plain java with no references to the Fn API. The +Fn Java FDK handles the marshalling of the HTTP body into the `str` parameter as well as the marshalling of the returned reversed string into the HTTP response body (see [Data Binding](/docs/DataBinding.md) for more information on how marshalling is performed). diff --git a/examples/string-reverse/func.yaml b/examples/string-reverse/func.yaml index 197eebe2..4d56d44f 100644 --- a/examples/string-reverse/func.yaml +++ b/examples/string-reverse/func.yaml @@ -1,7 +1,11 @@ -name: fn-example/string-reverse -version: 0.0.1 +schema_version: 20180708 +name: string-reverse +version: 0.0.2 runtime: java -timeout: 30 -format: http -cmd: com.fnproject.fn.examples.StringReverse::reverse -path: /reverse +build_image: fnproject/fn-java-fdk-build:jdk11-1.0.87 +run_image: fnproject/fn-java-fdk:jre11-1.0.87 +cmd: com.example.fn.StringReverse::reverse +triggers: +- name: string-reverse + type: http + source: /string-reverse diff --git a/examples/string-reverse/pom.xml b/examples/string-reverse/pom.xml index 296d9d7f..982f7e30 100644 --- a/examples/string-reverse/pom.xml +++ b/examples/string-reverse/pom.xml @@ -3,23 +3,50 @@ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> 4.0.0 - - UTF-8 - UTF-8 - + 1.0.87 - - com.fnproject.fn.examples + com.example.fn string-reverse - 1.0.0-SNAPSHOT + 1.0.0 + + + + fn-release-repo + https://dl.bintray.com/fnproject/fnproject + + true + + + false + + + + + com.fnproject.fn + api + ${fdk.version} + + + com.fnproject.fn + testing-core + ${fdk.version} + test + + + com.fnproject.fn + testing-junit4 + ${fdk.version} + test + junit junit 4.12 + test @@ -28,27 +55,20 @@ org.apache.maven.plugins maven-compiler-plugin - 3.8.0 + 3.3 - 1.8 - 1.8 + 11 + 11 - org.apache.maven.plugins - maven-deploy-plugin - 2.8.2 - - true - + org.apache.maven.plugins + maven-surefire-plugin + 2.22.1 + + false + - - - - fn-maven-releases - https://dl.bintray.com/fnproject/fnproject - - diff --git a/examples/string-reverse/src/main/java/com/example/fn/StringReverse.java b/examples/string-reverse/src/main/java/com/example/fn/StringReverse.java new file mode 100644 index 00000000..46d0f5fb --- /dev/null +++ b/examples/string-reverse/src/main/java/com/example/fn/StringReverse.java @@ -0,0 +1,7 @@ +package com.example.fn; + +public class StringReverse { + public String reverse(String str) { + return new StringBuilder(str).reverse().toString(); + } +} diff --git a/examples/string-reverse/src/main/java/com/fnproject/fn/examples/StringReverse.java b/examples/string-reverse/src/main/java/com/fnproject/fn/examples/StringReverse.java deleted file mode 100644 index e95ce08e..00000000 --- a/examples/string-reverse/src/main/java/com/fnproject/fn/examples/StringReverse.java +++ /dev/null @@ -1,11 +0,0 @@ -package com.fnproject.fn.examples; - -public class StringReverse { - public String reverse(String str) { - StringBuilder builder = new StringBuilder(); - for (int i = str.length() - 1; i >= 0; i--) { - builder.append(str.charAt(i)); - } - return builder.toString(); - } -} diff --git a/examples/string-reverse/src/test/java/com/fnproject/examples/StringReverseTest.java b/examples/string-reverse/src/test/java/com/example/fn/testing/StringReverseTest.java similarity index 87% rename from examples/string-reverse/src/test/java/com/fnproject/examples/StringReverseTest.java rename to examples/string-reverse/src/test/java/com/example/fn/testing/StringReverseTest.java index 9f67dd2c..e9b59af0 100644 --- a/examples/string-reverse/src/test/java/com/fnproject/examples/StringReverseTest.java +++ b/examples/string-reverse/src/test/java/com/example/fn/testing/StringReverseTest.java @@ -1,6 +1,6 @@ -package com.fnproject.examples; +package com.example.fn.testing; -import com.fnproject.fn.examples.StringReverse; +import com.example.fn.StringReverse; import org.junit.Test; import static junit.framework.TestCase.assertEquals; From 4fd9ae1e58620ea6b11619268a7d56990f6704cc Mon Sep 17 00:00:00 2001 From: Rik Gibson Date: Fri, 5 Apr 2019 00:51:04 +0100 Subject: [PATCH 127/310] post-1.0.87 bump (manual) --- release.version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/release.version b/release.version index 9435145c..5ca06039 100644 --- a/release.version +++ b/release.version @@ -1 +1 @@ -1.0.87 +1.0.88 From afca0c0b1af1a987d3317ee1bb807b2c3725eade Mon Sep 17 00:00:00 2001 From: CI Date: Fri, 5 Apr 2019 00:31:59 +0000 Subject: [PATCH 128/310] fn-java-fdk: post-1.0.88 version bump [skip ci] --- release.version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/release.version b/release.version index 5ca06039..9d25b397 100644 --- a/release.version +++ b/release.version @@ -1 +1 @@ -1.0.88 +1.0.89 From 0e8ba9236d3b56309645c46905e3801d56dd0273 Mon Sep 17 00:00:00 2001 From: Nisha Lad Date: Thu, 11 Apr 2019 12:09:15 +0100 Subject: [PATCH 129/310] WIP adding logframer and tests to fdk-java, before each function invocation --- .../fn/runtime/MethodFunctionInvoker.java | 23 +++++++++++++++++++ .../fn/testing/FnTestingRuleTest.java | 16 +++++++++++++ 2 files changed, 39 insertions(+) diff --git a/runtime/src/main/java/com/fnproject/fn/runtime/MethodFunctionInvoker.java b/runtime/src/main/java/com/fnproject/fn/runtime/MethodFunctionInvoker.java index 0f46d749..e0463d55 100644 --- a/runtime/src/main/java/com/fnproject/fn/runtime/MethodFunctionInvoker.java +++ b/runtime/src/main/java/com/fnproject/fn/runtime/MethodFunctionInvoker.java @@ -17,6 +17,27 @@ */ public class MethodFunctionInvoker implements FunctionInvoker { + /* + * If enabled, print the logging framing content + */ + public void logFramer(FunctionRuntimeContext rctx, InputEvent evt) { + String framer = rctx.getConfigurationByKey("FN_LOGFRAME_NAME").orElse(""); + + if (framer != "") { + String valueSrc = rctx.getConfigurationByKey("FN_LOGFRAME_HDR").orElse(""); + + if (valueSrc != "") { + String id = evt.getHeaders().get(valueSrc).orElse(""); + if (id != "") { + System.out.println(framer + "=" + id); + System.err.println(framer + "=" + id); + } + } + } + + } + + /** * Invoke the function wrapped by this loader * @@ -33,6 +54,8 @@ public Optional tryInvoke(InvocationContext ctx, InputEvent evt) th Object rawResult; + logFramer(runtimeContext, evt); + try { rawResult = method.getTargetMethod().invoke(ctx.getRuntimeContext().getInvokeInstance().orElse(null), userFunctionParams); } catch (IllegalAccessException | InvocationTargetException e) { diff --git a/testing-junit4/src/test/java/com/fnproject/fn/testing/FnTestingRuleTest.java b/testing-junit4/src/test/java/com/fnproject/fn/testing/FnTestingRuleTest.java index 03df8764..430e76c4 100644 --- a/testing-junit4/src/test/java/com/fnproject/fn/testing/FnTestingRuleTest.java +++ b/testing-junit4/src/test/java/com/fnproject/fn/testing/FnTestingRuleTest.java @@ -250,6 +250,22 @@ public void shouldHandleBodyAsInputStream() throws IOException { Assertions.assertThat(capturedBodies.get(0)).isEqualTo("FOO BAR".getBytes()); } + @Test + public void shouldPrintLogFrame() throws Exception { + fn.setConfig("FN_LOGFRAME_NAME", "containerID"); + fn.setConfig("FN_LOGFRAME_HDR", "fnID"); + fn.givenEvent().withBody("Hello World").enqueue(); + + fn.thenRun(TestFn.class, "copyConfiguration"); + Assertions.assertThat(configuration).containsEntry("FN_LOGFRAME_NAME", "containerID"); + Assertions.assertThat(configuration).containsEntry("FN_LOGFRAME_HDR", "fnID"); + + FnResult result = fn.getOnlyResult(); + Assertions.assertThat(result.getBodyAsString()).isEqualTo("containerID=fnID\nHello World"); + // assertThat(fn.getOnlyOutputAsString()).isEqualTo("containerID=fnID\nHello World"); + } + + // TODO move this to HTTP gateway // @Test // public void shouldLeaveQueryParamtersOffIfNotSpecified() { From 7cff542944c34ff49e59ad20e1211df0b7c0c971 Mon Sep 17 00:00:00 2001 From: Nisha Lad Date: Thu, 11 Apr 2019 15:08:07 +0100 Subject: [PATCH 130/310] WIP debugging test --- .../fn/runtime/EndToEndInvokeTest.java | 20 ++++++++++++++ .../fn/testing/FnTestingRuleTest.java | 27 ++++++++++--------- 2 files changed, 34 insertions(+), 13 deletions(-) diff --git a/runtime/src/test/java/com/fnproject/fn/runtime/EndToEndInvokeTest.java b/runtime/src/test/java/com/fnproject/fn/runtime/EndToEndInvokeTest.java index 4be57f20..4616c1c3 100644 --- a/runtime/src/test/java/com/fnproject/fn/runtime/EndToEndInvokeTest.java +++ b/runtime/src/test/java/com/fnproject/fn/runtime/EndToEndInvokeTest.java @@ -211,6 +211,26 @@ public void shouldReadBytesOnDefaultCodec() throws Exception { } + @Test + public void shouldPrintLogFrame() throws Exception { + fn.setConfig("FN_LOGFRAME_NAME", "containerID"); + fn.setConfig("FN_LOGFRAME_HDR", "fnID"); + fn.givenEvent().enqueue(); + TestFn.setOutput("Hello world"); + + fn.thenRun(TestFn.class, "setOutput"); + assertThat(fn.getOnlyOutputAsString()).isEqualTo("Hello world!"); + + // fn.getConfig("FN_LOGFRAME_NAME").isE + // fn.thenRun(TestFn.class, "echoInput"); + // assertThat(configuration).containsEntry("FN_LOGFRAME_NAME", "containerID"); + // assertThat(configuration).containsEntry("FN_LOGFRAME_HDR", "fnID"); + + // FnResult result = fn.getResults().get(0); + // Assertions.assertThat(result.getBodyAsString()).isEqualTo("containerID=fnID\nHello World"); + // assertThat(fn.getOnlyOutputAsString()).isEqualTo("containerID=fnID\nHello World"); + } + @Test public void shouldWriteBytesOnDefaultCodec() throws Exception { diff --git a/testing-junit4/src/test/java/com/fnproject/fn/testing/FnTestingRuleTest.java b/testing-junit4/src/test/java/com/fnproject/fn/testing/FnTestingRuleTest.java index 430e76c4..ff8deb3d 100644 --- a/testing-junit4/src/test/java/com/fnproject/fn/testing/FnTestingRuleTest.java +++ b/testing-junit4/src/test/java/com/fnproject/fn/testing/FnTestingRuleTest.java @@ -250,20 +250,21 @@ public void shouldHandleBodyAsInputStream() throws IOException { Assertions.assertThat(capturedBodies.get(0)).isEqualTo("FOO BAR".getBytes()); } - @Test - public void shouldPrintLogFrame() throws Exception { - fn.setConfig("FN_LOGFRAME_NAME", "containerID"); - fn.setConfig("FN_LOGFRAME_HDR", "fnID"); - fn.givenEvent().withBody("Hello World").enqueue(); - - fn.thenRun(TestFn.class, "copyConfiguration"); - Assertions.assertThat(configuration).containsEntry("FN_LOGFRAME_NAME", "containerID"); - Assertions.assertThat(configuration).containsEntry("FN_LOGFRAME_HDR", "fnID"); + // @Test + // public void shouldPrintLogFrame() throws Exception { + // fn.setConfig("FN_LOGFRAME_NAME", "containerID"); + // fn.setConfig("FN_LOGFRAME_HDR", "fnID"); + // fn.givenEvent().withBody("Hello World").enqueue(); + + // fn.thenRun(TestFn.class, "copyConfiguration"); + // // fn.thenRun(TestFn.class, "echoInput"); + // Assertions.assertThat(configuration).containsEntry("FN_LOGFRAME_NAME", "containerID"); + // Assertions.assertThat(configuration).containsEntry("FN_LOGFRAME_HDR", "fnID"); - FnResult result = fn.getOnlyResult(); - Assertions.assertThat(result.getBodyAsString()).isEqualTo("containerID=fnID\nHello World"); - // assertThat(fn.getOnlyOutputAsString()).isEqualTo("containerID=fnID\nHello World"); - } + // FnResult result = fn.getResults().get(0); + // Assertions.assertThat(result.getBodyAsString()).isEqualTo("containerID=fnID\nHello World"); + // // assertThat(fn.getOnlyOutputAsString()).isEqualTo("containerID=fnID\nHello World"); + // } // TODO move this to HTTP gateway From 5b58491f17c31dd5bc22b6ed1a3ada86720fb25c Mon Sep 17 00:00:00 2001 From: jan grant Date: Thu, 11 Apr 2019 15:30:48 +0100 Subject: [PATCH 131/310] Quick fix..? --- .../fn/runtime/MethodFunctionInvoker.java | 9 ++++----- .../fnproject/fn/runtime/EndToEndInvokeTest.java | 14 +++----------- 2 files changed, 7 insertions(+), 16 deletions(-) diff --git a/runtime/src/main/java/com/fnproject/fn/runtime/MethodFunctionInvoker.java b/runtime/src/main/java/com/fnproject/fn/runtime/MethodFunctionInvoker.java index e0463d55..197c9723 100644 --- a/runtime/src/main/java/com/fnproject/fn/runtime/MethodFunctionInvoker.java +++ b/runtime/src/main/java/com/fnproject/fn/runtime/MethodFunctionInvoker.java @@ -22,10 +22,10 @@ public class MethodFunctionInvoker implements FunctionInvoker { */ public void logFramer(FunctionRuntimeContext rctx, InputEvent evt) { String framer = rctx.getConfigurationByKey("FN_LOGFRAME_NAME").orElse(""); - + if (framer != "") { String valueSrc = rctx.getConfigurationByKey("FN_LOGFRAME_HDR").orElse(""); - + if (valueSrc != "") { String id = evt.getHeaders().get(valueSrc).orElse(""); if (id != "") { @@ -34,10 +34,9 @@ public void logFramer(FunctionRuntimeContext rctx, InputEvent evt) { } } } - } - - + + /** * Invoke the function wrapped by this loader * diff --git a/runtime/src/test/java/com/fnproject/fn/runtime/EndToEndInvokeTest.java b/runtime/src/test/java/com/fnproject/fn/runtime/EndToEndInvokeTest.java index 4616c1c3..a1d1d457 100644 --- a/runtime/src/test/java/com/fnproject/fn/runtime/EndToEndInvokeTest.java +++ b/runtime/src/test/java/com/fnproject/fn/runtime/EndToEndInvokeTest.java @@ -215,20 +215,12 @@ public void shouldReadBytesOnDefaultCodec() throws Exception { public void shouldPrintLogFrame() throws Exception { fn.setConfig("FN_LOGFRAME_NAME", "containerID"); fn.setConfig("FN_LOGFRAME_HDR", "fnID"); - fn.givenEvent().enqueue(); - TestFn.setOutput("Hello world"); + fn.givenEvent().withHeader("fnID", "uhfieuwfhieuwh").withBody( "Hello world!").enqueue(); - fn.thenRun(TestFn.class, "setOutput"); + fn.thenRun(TestFn.class, "fnEcho"); assertThat(fn.getOnlyOutputAsString()).isEqualTo("Hello world!"); + assertThat(fn.getStdErrAsString()).isEqualTo(""); - // fn.getConfig("FN_LOGFRAME_NAME").isE - // fn.thenRun(TestFn.class, "echoInput"); - // assertThat(configuration).containsEntry("FN_LOGFRAME_NAME", "containerID"); - // assertThat(configuration).containsEntry("FN_LOGFRAME_HDR", "fnID"); - - // FnResult result = fn.getResults().get(0); - // Assertions.assertThat(result.getBodyAsString()).isEqualTo("containerID=fnID\nHello World"); - // assertThat(fn.getOnlyOutputAsString()).isEqualTo("containerID=fnID\nHello World"); } From 736813e96e4bed88963974496ec5c1d0fc0fea3e Mon Sep 17 00:00:00 2001 From: Nisha Lad Date: Thu, 11 Apr 2019 16:00:17 +0100 Subject: [PATCH 132/310] checking if env variables are logged out to stdout and stderr, stdout gets redirected to stderr hence the duplication in the assertion --- .../java/com/fnproject/fn/runtime/EndToEndInvokeTest.java | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/runtime/src/test/java/com/fnproject/fn/runtime/EndToEndInvokeTest.java b/runtime/src/test/java/com/fnproject/fn/runtime/EndToEndInvokeTest.java index a1d1d457..6f666ca2 100644 --- a/runtime/src/test/java/com/fnproject/fn/runtime/EndToEndInvokeTest.java +++ b/runtime/src/test/java/com/fnproject/fn/runtime/EndToEndInvokeTest.java @@ -215,11 +215,12 @@ public void shouldReadBytesOnDefaultCodec() throws Exception { public void shouldPrintLogFrame() throws Exception { fn.setConfig("FN_LOGFRAME_NAME", "containerID"); fn.setConfig("FN_LOGFRAME_HDR", "fnID"); - fn.givenEvent().withHeader("fnID", "uhfieuwfhieuwh").withBody( "Hello world!").enqueue(); + fn.givenEvent().withHeader("fnID", "fnIDVal").withBody( "Hello world!").enqueue(); fn.thenRun(TestFn.class, "fnEcho"); assertThat(fn.getOnlyOutputAsString()).isEqualTo("Hello world!"); - assertThat(fn.getStdErrAsString()).isEqualTo(""); + // stdout gets redirected to stderr - hence printing out twice + assertThat(fn.getStdErrAsString()).isEqualTo("containerID=fnIDVal\ncontainerID=fnIDVal\n"); } From b5da35da39e76f79af3a90f3f98d0c9c3e24b906 Mon Sep 17 00:00:00 2001 From: Nisha Lad Date: Thu, 11 Apr 2019 16:05:04 +0100 Subject: [PATCH 133/310] removing comments of test in wrong file --- .../fnproject/fn/testing/FnTestingRuleTest.java | 17 ----------------- 1 file changed, 17 deletions(-) diff --git a/testing-junit4/src/test/java/com/fnproject/fn/testing/FnTestingRuleTest.java b/testing-junit4/src/test/java/com/fnproject/fn/testing/FnTestingRuleTest.java index ff8deb3d..03df8764 100644 --- a/testing-junit4/src/test/java/com/fnproject/fn/testing/FnTestingRuleTest.java +++ b/testing-junit4/src/test/java/com/fnproject/fn/testing/FnTestingRuleTest.java @@ -250,23 +250,6 @@ public void shouldHandleBodyAsInputStream() throws IOException { Assertions.assertThat(capturedBodies.get(0)).isEqualTo("FOO BAR".getBytes()); } - // @Test - // public void shouldPrintLogFrame() throws Exception { - // fn.setConfig("FN_LOGFRAME_NAME", "containerID"); - // fn.setConfig("FN_LOGFRAME_HDR", "fnID"); - // fn.givenEvent().withBody("Hello World").enqueue(); - - // fn.thenRun(TestFn.class, "copyConfiguration"); - // // fn.thenRun(TestFn.class, "echoInput"); - // Assertions.assertThat(configuration).containsEntry("FN_LOGFRAME_NAME", "containerID"); - // Assertions.assertThat(configuration).containsEntry("FN_LOGFRAME_HDR", "fnID"); - - // FnResult result = fn.getResults().get(0); - // Assertions.assertThat(result.getBodyAsString()).isEqualTo("containerID=fnID\nHello World"); - // // assertThat(fn.getOnlyOutputAsString()).isEqualTo("containerID=fnID\nHello World"); - // } - - // TODO move this to HTTP gateway // @Test // public void shouldLeaveQueryParamtersOffIfNotSpecified() { From 1f616e60bd776f0e427cbf190b71c7c89ebb8456 Mon Sep 17 00:00:00 2001 From: CI Date: Fri, 12 Apr 2019 14:00:12 +0000 Subject: [PATCH 134/310] fn-java-fdk: post-1.0.89 version bump [skip ci] --- release.version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/release.version b/release.version index 9d25b397..ac2282af 100644 --- a/release.version +++ b/release.version @@ -1 +1 @@ -1.0.89 +1.0.90 From 5f2fa09790101b5b04ad02d2088a6d5d57320efd Mon Sep 17 00:00:00 2001 From: Nisha Lad Date: Tue, 23 Apr 2019 09:29:12 +0100 Subject: [PATCH 135/310] adding explicit newline characters in print statements --- .../java/com/fnproject/fn/runtime/MethodFunctionInvoker.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/runtime/src/main/java/com/fnproject/fn/runtime/MethodFunctionInvoker.java b/runtime/src/main/java/com/fnproject/fn/runtime/MethodFunctionInvoker.java index 197c9723..04192a37 100644 --- a/runtime/src/main/java/com/fnproject/fn/runtime/MethodFunctionInvoker.java +++ b/runtime/src/main/java/com/fnproject/fn/runtime/MethodFunctionInvoker.java @@ -29,8 +29,8 @@ public void logFramer(FunctionRuntimeContext rctx, InputEvent evt) { if (valueSrc != "") { String id = evt.getHeaders().get(valueSrc).orElse(""); if (id != "") { - System.out.println(framer + "=" + id); - System.err.println(framer + "=" + id); + System.out.println("\n" + framer + "=" + id + "\n"); + System.err.println("\n" + framer + "=" + id + "\n"); } } } From 162c24c91d92996326064d008fd9812a7c458ca1 Mon Sep 17 00:00:00 2001 From: Nisha Lad Date: Tue, 23 Apr 2019 09:40:23 +0100 Subject: [PATCH 136/310] editing tests --- .../test/java/com/fnproject/fn/runtime/EndToEndInvokeTest.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/runtime/src/test/java/com/fnproject/fn/runtime/EndToEndInvokeTest.java b/runtime/src/test/java/com/fnproject/fn/runtime/EndToEndInvokeTest.java index 6f666ca2..91292d57 100644 --- a/runtime/src/test/java/com/fnproject/fn/runtime/EndToEndInvokeTest.java +++ b/runtime/src/test/java/com/fnproject/fn/runtime/EndToEndInvokeTest.java @@ -220,7 +220,7 @@ public void shouldPrintLogFrame() throws Exception { fn.thenRun(TestFn.class, "fnEcho"); assertThat(fn.getOnlyOutputAsString()).isEqualTo("Hello world!"); // stdout gets redirected to stderr - hence printing out twice - assertThat(fn.getStdErrAsString()).isEqualTo("containerID=fnIDVal\ncontainerID=fnIDVal\n"); + assertThat(fn.getStdErrAsString()).isEqualTo("\ncontainerID=fnIDVal\n\ncontainerID=fnIDVal\n\n"); } From b13b5a15a39c6274f3206cf57fe9db3344bdd389 Mon Sep 17 00:00:00 2001 From: Nisha Lad Date: Tue, 23 Apr 2019 09:52:00 +0100 Subject: [PATCH 137/310] correcting \n --- .../test/java/com/fnproject/fn/runtime/EndToEndInvokeTest.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/runtime/src/test/java/com/fnproject/fn/runtime/EndToEndInvokeTest.java b/runtime/src/test/java/com/fnproject/fn/runtime/EndToEndInvokeTest.java index 91292d57..a028c368 100644 --- a/runtime/src/test/java/com/fnproject/fn/runtime/EndToEndInvokeTest.java +++ b/runtime/src/test/java/com/fnproject/fn/runtime/EndToEndInvokeTest.java @@ -220,7 +220,7 @@ public void shouldPrintLogFrame() throws Exception { fn.thenRun(TestFn.class, "fnEcho"); assertThat(fn.getOnlyOutputAsString()).isEqualTo("Hello world!"); // stdout gets redirected to stderr - hence printing out twice - assertThat(fn.getStdErrAsString()).isEqualTo("\ncontainerID=fnIDVal\n\ncontainerID=fnIDVal\n\n"); + assertThat(fn.getStdErrAsString()).isEqualTo("\ncontainerID=fnIDVal\n\n\ncontainerID=fnIDVal\n\n"); } From 6d63aca547567a7ee7cafd6f514c16a3fccaf400 Mon Sep 17 00:00:00 2001 From: CI Date: Wed, 24 Apr 2019 16:34:06 +0000 Subject: [PATCH 138/310] fn-java-fdk: post-1.0.90 version bump [skip ci] --- release.version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/release.version b/release.version index ac2282af..34b31707 100644 --- a/release.version +++ b/release.version @@ -1 +1 @@ -1.0.90 +1.0.91 From ee86024192fac2209cd87acca074ca5010b4eb0c Mon Sep 17 00:00:00 2001 From: Michael Williams Date: Thu, 25 Apr 2019 10:58:46 -0600 Subject: [PATCH 139/310] Update pom.xml so circleci test will pass. JDK 11 not allowed currently. --- examples/string-reverse/pom.xml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/examples/string-reverse/pom.xml b/examples/string-reverse/pom.xml index 982f7e30..e41c77fa 100644 --- a/examples/string-reverse/pom.xml +++ b/examples/string-reverse/pom.xml @@ -57,8 +57,8 @@ maven-compiler-plugin 3.3 - 11 - 11 + 8 + 8 From 5a5d00d1f0c9e566562d3381f1a5e6c35a50dc97 Mon Sep 17 00:00:00 2001 From: Reed Allman Date: Sat, 27 Apr 2019 00:08:48 -0700 Subject: [PATCH 140/310] fnproject/functions -> fnproject/fnserver --- infra/update/functions/Jenkinsfile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/infra/update/functions/Jenkinsfile b/infra/update/functions/Jenkinsfile index b5691ecf..8162ef57 100644 --- a/infra/update/functions/Jenkinsfile +++ b/infra/update/functions/Jenkinsfile @@ -1,7 +1,7 @@ pipeline { agent any parameters { - string(name: 'IMAGE', defaultValue: 'registry.oracledx.com/skeppare/functions-service:latest', description: 'Which image to use (full repository:tag, e.g. fnproject/functions:latest)') + string(name: 'IMAGE', defaultValue: 'registry.oracledx.com/skeppare/functions-service:latest', description: 'Which image to use (full repository:tag, e.g. fnproject/fnserver:latest)') string(name: 'SOURCE_REPO', defaultValue: 'git@github.com:fnproject/fn.git', description: 'Which git repo to use to build the CLI tool') string(name: 'SOURCE_BRANCH', defaultValue: 'master', description: 'Which git repo branch to use to build the CLI tool') } From 54426db448aea24a833f31e9628836072a09024b Mon Sep 17 00:00:00 2001 From: Tomas Knappek Date: Mon, 8 Apr 2019 14:09:34 -0700 Subject: [PATCH 141/310] add fn user to jre11 runtime image --- images/runtime/Dockerfile-jre11 | 2 ++ 1 file changed, 2 insertions(+) diff --git a/images/runtime/Dockerfile-jre11 b/images/runtime/Dockerfile-jre11 index 0574f914..fbbf5a9c 100644 --- a/images/runtime/Dockerfile-jre11 +++ b/images/runtime/Dockerfile-jre11 @@ -4,6 +4,8 @@ COPY src/main/c/libfnunixsocket.so /function/runtime/lib/ RUN ["/usr/bin/java", "-Xshare:dump"] +RUN addgroup --system --gid 1000 fn && adduser --uid 1000 --gid 1000 fn + # The UseExeperimentalVMOptions, UseCGroupMemoryLimitForHeap and MaxRAMFraction options that were used in the JDK 9 builds are # no longer supported in JDK 11 - so these have been removed. We now rely on the built-in ContainerSupport option that Linux JDKs # use to configure themselves when detecting they are running in a container. From 7e1fb0d0646f6f778b9a798fd5972c10c08eea7c Mon Sep 17 00:00:00 2001 From: CI Date: Mon, 29 Apr 2019 22:28:48 +0000 Subject: [PATCH 142/310] fn-java-fdk: post-1.0.91 version bump [skip ci] --- release.version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/release.version b/release.version index 34b31707..814eec79 100644 --- a/release.version +++ b/release.version @@ -1 +1 @@ -1.0.91 +1.0.92 From 45da3e0ace6455ec2c26953e65ebfe1f097223dc Mon Sep 17 00:00:00 2001 From: CI Date: Mon, 29 Apr 2019 23:16:30 +0000 Subject: [PATCH 143/310] fn-java-fdk: post-1.0.92 version bump [skip ci] --- release.version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/release.version b/release.version index 814eec79..87903b67 100644 --- a/release.version +++ b/release.version @@ -1 +1 @@ -1.0.92 +1.0.93 From 38f28ddadd7251305dab16db795ecccc405dd233 Mon Sep 17 00:00:00 2001 From: Richard Connon Date: Thu, 9 May 2019 15:03:51 +0100 Subject: [PATCH 144/310] Re-order release artifact publishing By publishing tag to github first we ensure that no artifacts are pushed for a version which isn't tagged. Publishing to bintray last ensures that the CLI won't pick up a version which is not pushed everywhere. --- .circleci/release.sh | 29 ++++++++++++++--------------- 1 file changed, 14 insertions(+), 15 deletions(-) diff --git a/.circleci/release.sh b/.circleci/release.sh index 74424e58..7a8b83ad 100755 --- a/.circleci/release.sh +++ b/.circleci/release.sh @@ -30,14 +30,14 @@ else exit 1 fi +# Push result to git -# Deploy to bintray -mvn -s ./settings-deploy.xml \ - -DskipTests \ - -DaltDeploymentRepository="fnproject-release-repo::default::${MVN_RELEASE_REPO}" \ - -Dfnproject-release-repo.username="${MVN_RELEASE_USER}" \ - -Dfnproject-release-repo.password="${MVN_RELEASE_PASSWORD}" \ - clean deploy +echo ${new_version} > release.version +git tag -a "$release_version" -m "version $release_version" +git add release.version +git commit -m "$SERVICE: post-$release_version version bump [skip ci]" +git push +git push origin "$release_version" # Regenerate runtime and build images and push them @@ -91,11 +91,10 @@ mvn -s ./settings-deploy.xml \ ) -# Push result to git - -echo ${new_version} > release.version -git tag -a "$release_version" -m "version $release_version" -git add release.version -git commit -m "$SERVICE: post-$release_version version bump [skip ci]" -git push -git push origin "$release_version" +# Deploy to bintray +mvn -s ./settings-deploy.xml \ + -DskipTests \ + -DaltDeploymentRepository="fnproject-release-repo::default::${MVN_RELEASE_REPO}" \ + -Dfnproject-release-repo.username="${MVN_RELEASE_USER}" \ + -Dfnproject-release-repo.password="${MVN_RELEASE_PASSWORD}" \ + clean deploy From f8d929553fb35f56b80ea708f2f34cce6beba2b7 Mon Sep 17 00:00:00 2001 From: Richard Connon Date: Thu, 9 May 2019 15:52:37 +0100 Subject: [PATCH 145/310] Post-1.0.93 version bump [skip ci] --- release.version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/release.version b/release.version index 87903b67..00572cea 100644 --- a/release.version +++ b/release.version @@ -1 +1 @@ -1.0.93 +1.0.94 From c86b5c64f6c2435c1d308784885c16b6a8489ace Mon Sep 17 00:00:00 2001 From: CI Date: Thu, 9 May 2019 15:07:08 +0000 Subject: [PATCH 146/310] fn-java-fdk: post-1.0.94 version bump [skip ci] --- release.version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/release.version b/release.version index 00572cea..875bf08a 100644 --- a/release.version +++ b/release.version @@ -1 +1 @@ -1.0.94 +1.0.95 From 8d6e48047a2a1c1a6d9f6992b0adef8f3d755b9f Mon Sep 17 00:00:00 2001 From: Richard Connon Date: Thu, 9 May 2019 19:00:55 +0100 Subject: [PATCH 147/310] Skip deployment of example code Do not attempt to publish artifacts for the string-reverse exapmle function --- examples/string-reverse/pom.xml | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/examples/string-reverse/pom.xml b/examples/string-reverse/pom.xml index e41c77fa..916d988d 100644 --- a/examples/string-reverse/pom.xml +++ b/examples/string-reverse/pom.xml @@ -61,6 +61,14 @@ 8 + + org.apache.maven.plugins + maven-deploy-plugin + 2.8.2 + + true + + org.apache.maven.plugins maven-surefire-plugin From b4cf50924b60e443941a247a0feb7de3f6ca71bb Mon Sep 17 00:00:00 2001 From: CI Date: Fri, 10 May 2019 09:03:26 +0000 Subject: [PATCH 148/310] fn-java-fdk: post-1.0.95 version bump [skip ci] --- release.version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/release.version b/release.version index 875bf08a..f42a27c9 100644 --- a/release.version +++ b/release.version @@ -1 +1 @@ -1.0.95 +1.0.96 From 86700d928e0b7e08845811ea176d94f1e8250e3a Mon Sep 17 00:00:00 2001 From: Owen Cliffe Date: Thu, 23 May 2019 13:48:38 +0100 Subject: [PATCH 149/310] Bump Jackson version --- examples/async-thumbnails/pom.xml | 2 +- examples/regex-query/pom.xml | 2 +- integration-tests/pom.xml | 2 +- pom.xml | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/examples/async-thumbnails/pom.xml b/examples/async-thumbnails/pom.xml index 6b90b28e..6727da9b 100644 --- a/examples/async-thumbnails/pom.xml +++ b/examples/async-thumbnails/pom.xml @@ -10,7 +10,7 @@ 1.0.0-SNAPSHOT 2.8.47 - 2.9.8 + 2.9.9 com.fnproject.fn.examples diff --git a/examples/regex-query/pom.xml b/examples/regex-query/pom.xml index 584ccfc9..77ccee8c 100644 --- a/examples/regex-query/pom.xml +++ b/examples/regex-query/pom.xml @@ -9,7 +9,7 @@ UTF-8 1.0.0-SNAPSHOT - 2.9.8 + 2.9.9 com.fnproject.fn.examples diff --git a/integration-tests/pom.xml b/integration-tests/pom.xml index df380729..eae2b43a 100644 --- a/integration-tests/pom.xml +++ b/integration-tests/pom.xml @@ -11,7 +11,7 @@ 3.6.2 2.5 - 2.9.8 + 2.9.9 4.12 2.22.1 diff --git a/pom.xml b/pom.xml index c0caa164..5c26d0d3 100644 --- a/pom.xml +++ b/pom.xml @@ -30,7 +30,7 @@ 3.10.0 2.6 4.4.10 - 2.9.8 + 2.9.9 0.8.1 9.4.12.v20180830 4.12 From a2ee599aa6b05d3a387ec254ab9c794117c9f8c6 Mon Sep 17 00:00:00 2001 From: CI Date: Thu, 23 May 2019 13:16:27 +0000 Subject: [PATCH 150/310] fn-java-fdk: post-1.0.96 version bump [skip ci] --- release.version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/release.version b/release.version index f42a27c9..7776610f 100644 --- a/release.version +++ b/release.version @@ -1 +1 @@ -1.0.96 +1.0.97 From b887f050d39978f94f05af7a352565412543ad9c Mon Sep 17 00:00:00 2001 From: Harry Smith <33180538+harryjsmith@users.noreply.github.com> Date: Thu, 20 Jun 2019 18:03:19 +0100 Subject: [PATCH 151/310] Fix path of java binary in Dockerfile (#210) --- images/runtime/Dockerfile | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/images/runtime/Dockerfile b/images/runtime/Dockerfile index 3aef82ba..bdad842f 100644 --- a/images/runtime/Dockerfile +++ b/images/runtime/Dockerfile @@ -1,8 +1,8 @@ -FROM openjdk:8-slim +FROM openjdk:8-jre-slim COPY target/runtime-*.jar target/dependency/*.jar /function/runtime/ COPY src/main/c/libfnunixsocket.so /function/runtime/lib/ -RUN ["/usr/lib/jvm/java-8-openjdk-amd64/jre/bin/java", "-Xshare:dump"] +RUN ["java", "-Xshare:dump"] RUN addgroup --system --gid 1000 fn && adduser --uid 1000 --gid 1000 fn @@ -18,4 +18,4 @@ RUN addgroup --system --gid 1000 fn && adduser --uid 1000 --gid 1000 fn # # The max memory value obtained with these args seem to be okay for most memory limits. The exception is when the # memory limit is set to 128MiB, in which case maxMemory returns roughly half. -ENTRYPOINT [ "/usr/lib/jvm/java-8-openjdk-amd64/jre/bin/java", "-XX:+UnlockExperimentalVMOptions", "-XX:+UseCGroupMemoryLimitForHeap", "-XX:-UsePerfData", "-XX:MaxRAMFraction=2", "-XX:+UseSerialGC", "-Xshare:on", "-Djava.library.path=/function/runtime/lib", "-cp", "/function/app/*:/function/runtime/*", "com.fnproject.fn.runtime.EntryPoint" ] +ENTRYPOINT [ "java", "-XX:+UnlockExperimentalVMOptions", "-XX:+UseCGroupMemoryLimitForHeap", "-XX:-UsePerfData", "-XX:MaxRAMFraction=2", "-XX:+UseSerialGC", "-Xshare:on", "-Djava.library.path=/function/runtime/lib", "-cp", "/function/app/*:/function/runtime/*", "com.fnproject.fn.runtime.EntryPoint" ] From bb739768672ba15ce8cf39e1b5799776b6b9891c Mon Sep 17 00:00:00 2001 From: CI Date: Thu, 20 Jun 2019 17:14:37 +0000 Subject: [PATCH 152/310] fn-java-fdk: post-1.0.97 version bump [skip ci] --- release.version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/release.version b/release.version index 7776610f..8eafdc0a 100644 --- a/release.version +++ b/release.version @@ -1 +1 @@ -1.0.97 +1.0.98 From 8ebeee714f21c0fe5b9d59754500537e1e9a91c1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tom=C3=A1=C5=A1=20Zezula?= Date: Fri, 21 Jun 2019 15:51:17 +0200 Subject: [PATCH 153/310] Updated to GraalVM 19. (#209) --- images/build-native/Dockerfile | 5 +++-- images/build-native/native.version | 2 +- images/init-native/Dockerfile | 4 +++- 3 files changed, 7 insertions(+), 4 deletions(-) diff --git a/images/build-native/Dockerfile b/images/build-native/Dockerfile index d85c0c52..b6a81285 100644 --- a/images/build-native/Dockerfile +++ b/images/build-native/Dockerfile @@ -2,11 +2,12 @@ FROM openjdk:8-jdk-slim as build LABEL maintainer="tomas.zezula@oracle.com" RUN set -x \ + && mkdir /usr/share/man/man1 \ && apt-get -y update \ && apt-get -y install gcc g++ git make openjdk-8-doc openjdk-8-source python zlib1g-dev \ && rm -rf /var/lib/apt/lists/* -ENV JVMCI_VERSION 0.49 +ENV JVMCI_VERSION 19-b04 WORKDIR /build @@ -20,7 +21,7 @@ RUN set -x \ && cp -r $(/build/mx/mx --primary-suite graal-jvmci-8 jdkhome) /build/jvmcijdk8 RUN git clone https://github.com/oracle/graal.git \ - && git -C graal checkout vm-1.0.0-rc11 + && git -C graal checkout vm-19.0.2 WORKDIR /build/graal/vm RUN export JAVA_HOME=/build/jvmcijdk8 \ && /build/mx/mx --dy /substratevm --force-bash-launchers=true --disable-polyglot --disable-libpolyglot build diff --git a/images/build-native/native.version b/images/build-native/native.version index 0d91a54c..1d0ba9ea 100644 --- a/images/build-native/native.version +++ b/images/build-native/native.version @@ -1 +1 @@ -0.3.0 +0.4.0 diff --git a/images/init-native/Dockerfile b/images/init-native/Dockerfile index 673bb276..5a10991a 100644 --- a/images/init-native/Dockerfile +++ b/images/init-native/Dockerfile @@ -15,7 +15,9 @@ COPY --from=build /function/src/main/conf/reflection.json reflection.json COPY --from=build /function/src/main/conf/jni.json jni.json RUN /usr/local/graalvm/bin/native-image \ --static \ - --delay-class-initialization-to-runtime=com.fnproject.fn.runtime.ntv.UnixSocketNative \ + --no-fallback \ + --initialize-at-build-time= \ + --initialize-at-run-time=com.fnproject.fn.runtime.ntv.UnixSocketNative \ -H:Name=func \ -H:+ReportUnsupportedElementsAtRuntime \ -H:ReflectionConfigurationFiles=reflection.json \ From c5a6bad166dfa08f252b7bfb77cddf9726d548af Mon Sep 17 00:00:00 2001 From: CI Date: Fri, 21 Jun 2019 23:01:07 +0000 Subject: [PATCH 154/310] fn-java-fdk: post-1.0.98 version bump [skip ci] --- release.version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/release.version b/release.version index 8eafdc0a..1f61f612 100644 --- a/release.version +++ b/release.version @@ -1 +1 @@ -1.0.98 +1.0.99 From 557d406f88616b7717a183e944dc91ed93197fd3 Mon Sep 17 00:00:00 2001 From: Owen Cliffe Date: Sat, 24 Aug 2019 08:31:57 +0100 Subject: [PATCH 155/310] Add env to test server to allow setting fn limits (#214) work around changed paths in new j11 image --- images/runtime/Dockerfile-jre11 | 9 ++++++--- integration-tests/README.md | 24 +++--------------------- integration-tests/fnserver.env | 3 +++ integration-tests/run_tests_ci.sh | 2 +- 4 files changed, 13 insertions(+), 25 deletions(-) create mode 100644 integration-tests/fnserver.env diff --git a/images/runtime/Dockerfile-jre11 b/images/runtime/Dockerfile-jre11 index fbbf5a9c..2f704297 100644 --- a/images/runtime/Dockerfile-jre11 +++ b/images/runtime/Dockerfile-jre11 @@ -2,7 +2,7 @@ FROM openjdk:11-jre-slim COPY target/runtime-*.jar target/dependency/*.jar /function/runtime/ COPY src/main/c/libfnunixsocket.so /function/runtime/lib/ -RUN ["/usr/bin/java", "-Xshare:dump"] +RUN ["/usr/local/openjdk-11/bin/java", "-Xshare:dump"] RUN addgroup --system --gid 1000 fn && adduser --uid 1000 --gid 1000 fn @@ -13,5 +13,8 @@ RUN addgroup --system --gid 1000 fn && adduser --uid 1000 --gid 1000 fn # SerialGC is used here as it's likely that we'll be running many JVMs on the same host machine and it's also likely # that the number of JVMs will outnumber the number of available processors. # -ENTRYPOINT [ "/usr/bin/java", "-XX:-UsePerfData", "-XX:+UseSerialGC", "-Xshare:on", \ - "-Djava.library.path=/function/runtime/lib", "-cp", "/function/app/*:/function/runtime/*", "com.fnproject.fn.runtime.EntryPoint" ] +ENTRYPOINT [ "/usr/local/openjdk-11/bin/java", "-XX:-UsePerfData", "-XX:+UseSerialGC", "-Xshare:on", \ + "-Djava.awt.headless=true" , \ + "-Djava.library.path=/function/runtime/lib", \ + "-cp", "/function/app/*:/function/runtime/*", \ + "com.fnproject.fn.runtime.EntryPoint" ] diff --git a/integration-tests/README.md b/integration-tests/README.md index eb34a654..90e881e7 100644 --- a/integration-tests/README.md +++ b/integration-tests/README.md @@ -14,30 +14,12 @@ They should _not_ be used for: # Running locally - -(in top-level dir) +Build the runtime: ```bash -export REPOSITORY_LOCATION=/tmp/staging-repository -# on OSX: -export DOCKER_LOCALHOST=docker.for.mac.host.internal - -mvn deploy -DaltDeploymentRepository=localStagingDir::default::file://"$REPOSITORY_LOCATION" -``` - -You may also want to/need build local copies of the build images: -```bash -cd build-image -./docker-build.sh -t fnproject/fn-java-fdk-build . -``` - -and runtime images: -``` -cd runtime -docker build -t fnproject/fn-java-fdk . -docker build -f Dockerfile-jdk11 -t fnproject/fn-java-fdk:jdk11-latest . +./build.sh ``` -Finally you can run the integration tests: +Run the integration tests: ```bash ./integration-tests/run_tests_ci.sh diff --git a/integration-tests/fnserver.env b/integration-tests/fnserver.env new file mode 100644 index 00000000..fd6e3b46 --- /dev/null +++ b/integration-tests/fnserver.env @@ -0,0 +1,3 @@ +FN_MAX_REQUEST_SIZE=6291456 +FN_MAX_RESPONSE_SIZE=6291456 +FN_MAX_HDR_RESPONSE_SIZE=16384 \ No newline at end of file diff --git a/integration-tests/run_tests_ci.sh b/integration-tests/run_tests_ci.sh index e28ee838..21145e79 100755 --- a/integration-tests/run_tests_ci.sh +++ b/integration-tests/run_tests_ci.sh @@ -29,7 +29,7 @@ done # Start Fn fn stop || true -fn start --log-level=debug -d +fn start --log-level=debug -d --env-file fnserver.env until $(curl --output /dev/null --silent --fail http://localhost:8080/); do printf '.' From 30e1875d5e37f46bedf4fb88427200f2b8cfb984 Mon Sep 17 00:00:00 2001 From: CI Date: Sat, 24 Aug 2019 07:45:26 +0000 Subject: [PATCH 156/310] fn-java-fdk: post-1.0.99 version bump [skip ci] --- release.version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/release.version b/release.version index 1f61f612..eab53e16 100644 --- a/release.version +++ b/release.version @@ -1 +1 @@ -1.0.99 +1.0.100 From a518795518726e913543276c403f47a13e64412d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tom=C3=A1=C5=A1=20Zezula?= Date: Sun, 25 Aug 2019 22:22:29 +0200 Subject: [PATCH 157/310] Updated native-image to GraalVM 19.2.0. (#213) * Updated to GraalVM 19.2.0. * Fixed build-native Dockerfile. --- images/build-native/Dockerfile | 7 +++---- images/build-native/native.version | 2 +- images/init-native/Dockerfile | 2 +- 3 files changed, 5 insertions(+), 6 deletions(-) diff --git a/images/build-native/Dockerfile b/images/build-native/Dockerfile index b6a81285..e50f84dc 100644 --- a/images/build-native/Dockerfile +++ b/images/build-native/Dockerfile @@ -2,12 +2,11 @@ FROM openjdk:8-jdk-slim as build LABEL maintainer="tomas.zezula@oracle.com" RUN set -x \ - && mkdir /usr/share/man/man1 \ && apt-get -y update \ - && apt-get -y install gcc g++ git make openjdk-8-doc openjdk-8-source python zlib1g-dev \ + && apt-get -y install gcc g++ git make python zlib1g-dev \ && rm -rf /var/lib/apt/lists/* -ENV JVMCI_VERSION 19-b04 +ENV JVMCI_VERSION 19.2-b02 WORKDIR /build @@ -21,7 +20,7 @@ RUN set -x \ && cp -r $(/build/mx/mx --primary-suite graal-jvmci-8 jdkhome) /build/jvmcijdk8 RUN git clone https://github.com/oracle/graal.git \ - && git -C graal checkout vm-19.0.2 + && git -C graal checkout vm-19.2.0 WORKDIR /build/graal/vm RUN export JAVA_HOME=/build/jvmcijdk8 \ && /build/mx/mx --dy /substratevm --force-bash-launchers=true --disable-polyglot --disable-libpolyglot build diff --git a/images/build-native/native.version b/images/build-native/native.version index 1d0ba9ea..8f0916f7 100644 --- a/images/build-native/native.version +++ b/images/build-native/native.version @@ -1 +1 @@ -0.4.0 +0.5.0 diff --git a/images/init-native/Dockerfile b/images/init-native/Dockerfile index 5a10991a..ec251021 100644 --- a/images/init-native/Dockerfile +++ b/images/init-native/Dockerfile @@ -3,7 +3,7 @@ LABEL maintainer="tomas.zezula@oracle.com" WORKDIR /function ENV MAVEN_OPTS=-Dmaven.repo.local=/usr/share/maven/ref/repository ADD pom.xml pom.xml -RUN ["mvn", "package", "dependency:copy-dependencies", "-DincludeScope=runtime", "-DskipTests=true", "-Dmdep.prependGroupId=true", "-DoutputDirectory=target", "--fail-never"] +RUN ["mvn", "package", "dependency:copy-dependencies", "-DincludeScope=runtime", "-DskipTests=true", "-Dmdep.prependGroupId=true", "-DoutputDirectory=target"] ADD src src RUN ["mvn", "package"] From 56659c911d9688733a0853e5bf75efb365ae886f Mon Sep 17 00:00:00 2001 From: CI Date: Sun, 25 Aug 2019 20:54:22 +0000 Subject: [PATCH 158/310] fn-java-fdk: post-1.0.100 version bump [skip ci] --- release.version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/release.version b/release.version index eab53e16..f301e1a5 100644 --- a/release.version +++ b/release.version @@ -1 +1 @@ -1.0.100 +1.0.101 From 26d149934bafbe65785c6c5957a374c7ab4ff4c1 Mon Sep 17 00:00:00 2001 From: Harry Smith <33180538+harryjsmith@users.noreply.github.com> Date: Sun, 29 Sep 2019 16:12:41 +0100 Subject: [PATCH 159/310] Bump Jackson version to 2.9.10 (#216) --- examples/async-thumbnails/pom.xml | 2 +- examples/regex-query/pom.xml | 2 +- integration-tests/pom.xml | 2 +- pom.xml | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/examples/async-thumbnails/pom.xml b/examples/async-thumbnails/pom.xml index 6727da9b..c65684ac 100644 --- a/examples/async-thumbnails/pom.xml +++ b/examples/async-thumbnails/pom.xml @@ -10,7 +10,7 @@ 1.0.0-SNAPSHOT 2.8.47 - 2.9.9 + 2.9.10 com.fnproject.fn.examples diff --git a/examples/regex-query/pom.xml b/examples/regex-query/pom.xml index 77ccee8c..d72bc766 100644 --- a/examples/regex-query/pom.xml +++ b/examples/regex-query/pom.xml @@ -9,7 +9,7 @@ UTF-8 1.0.0-SNAPSHOT - 2.9.9 + 2.9.10 com.fnproject.fn.examples diff --git a/integration-tests/pom.xml b/integration-tests/pom.xml index eae2b43a..ec2ccf8b 100644 --- a/integration-tests/pom.xml +++ b/integration-tests/pom.xml @@ -11,7 +11,7 @@ 3.6.2 2.5 - 2.9.9 + 2.9.10 4.12 2.22.1 diff --git a/pom.xml b/pom.xml index 5c26d0d3..187182ee 100644 --- a/pom.xml +++ b/pom.xml @@ -30,7 +30,7 @@ 3.10.0 2.6 4.4.10 - 2.9.9 + 2.9.10 0.8.1 9.4.12.v20180830 4.12 From 4112ea160be7642863d4cf69c39ad163ec539ab3 Mon Sep 17 00:00:00 2001 From: CI Date: Sun, 29 Sep 2019 15:24:41 +0000 Subject: [PATCH 160/310] fn-java-fdk: post-1.0.101 version bump [skip ci] --- release.version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/release.version b/release.version index f301e1a5..d5515c5a 100644 --- a/release.version +++ b/release.version @@ -1 +1 @@ -1.0.101 +1.0.102 From 76324fb9665ca24a9e8a8ae3b4910d497e38117c Mon Sep 17 00:00:00 2001 From: Michael Williams Date: Wed, 2 Oct 2019 11:02:27 -0600 Subject: [PATCH 161/310] Update all names to Function Development Kit for Java per Shaun, per Legal, and for consistency. --- README.md | 16 ++++++---------- 1 file changed, 6 insertions(+), 10 deletions(-) diff --git a/README.md b/README.md index ea9bcc06..b0258aab 100644 --- a/README.md +++ b/README.md @@ -1,10 +1,10 @@ [![CircleCI](https://circleci.com/gh/fnproject/fdk-java.svg?style=svg&circle-token=348bec5610c34421f6c436ab8f6a18e153cb1c01)](https://circleci.com/gh/fnproject/fdk-java) -# Java Function Development Kit (FDK) +# Function Development Kit for Java (FDK-Java) -The Java Function Development Kit (FDK) makes it easy to build and deploy Java functions to Fn with full support for Java 11+ as the default out of the box. +The Function Development Kit for Java (FDK-Java) makes it easy to build and deploy Java functions to Fn with full support for Java 11+ as the default out of the box. -Some of the Java FDK's features include: +Some of the FDK-Java features include: - Parsing input and writing output - Flexible data binding to Java objects @@ -15,14 +15,10 @@ Some of the Java FDK's features include: New to Fn Project? If you want to learn more about using the Fn Project to power your next project, start with the [official documentation](https://github.com/fnproject/docs). -## Using the Java FDK +## Using the Function Development Kit for Java -For detailed instructions on using the Java FDK to build and deploy Java functions to Fn, please see the official Java FDK developer guide in our docs repo here: https://github.com/fnproject/docs/blob/master/fdks/fdk-java/README.md. +For detailed instructions on using FDK-Java to build and deploy Java functions to Fn, please see the official FDK-Java developer guide in our docs repo here: https://github.com/fnproject/docs/blob/master/fdks/fdk-java/README.md. -## Contributing to the Java FDK +## Contributing to the Function Development Kit for Java Please see [CONTRIBUTING.md](CONTRIBUTING.md). - - - - From fa542367d0643f65147d7b16178d2d83cd0d031f Mon Sep 17 00:00:00 2001 From: Michael Williams Date: Wed, 2 Oct 2019 11:41:03 -0600 Subject: [PATCH 162/310] Removed hyphen as best practice seems to be no hyphen --- README.md | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index b0258aab..2faec7da 100644 --- a/README.md +++ b/README.md @@ -1,10 +1,10 @@ [![CircleCI](https://circleci.com/gh/fnproject/fdk-java.svg?style=svg&circle-token=348bec5610c34421f6c436ab8f6a18e153cb1c01)](https://circleci.com/gh/fnproject/fdk-java) -# Function Development Kit for Java (FDK-Java) +# Function Development Kit for Java (FDK Java) -The Function Development Kit for Java (FDK-Java) makes it easy to build and deploy Java functions to Fn with full support for Java 11+ as the default out of the box. +The Function Development Kit for Java (FDK Java) makes it easy to build and deploy Java functions to Fn with full support for Java 11+ as the default out of the box. -Some of the FDK-Java features include: +Some of the FDK Java features include: - Parsing input and writing output - Flexible data binding to Java objects @@ -17,7 +17,7 @@ New to Fn Project? If you want to learn more about using the Fn Project to power ## Using the Function Development Kit for Java -For detailed instructions on using FDK-Java to build and deploy Java functions to Fn, please see the official FDK-Java developer guide in our docs repo here: https://github.com/fnproject/docs/blob/master/fdks/fdk-java/README.md. +For detailed instructions on using FDK Java to build and deploy Java functions to Fn, please see the official FDK Java developer guide in our docs repo here: https://github.com/fnproject/docs/blob/master/fdks/fdk-java/README.md. ## Contributing to the Function Development Kit for Java From 4d900a23ef94ab500c5611678d58d66b51fd2acd Mon Sep 17 00:00:00 2001 From: Michael Williams Date: Thu, 3 Oct 2019 10:11:06 -0600 Subject: [PATCH 163/310] Updating abbrev to FDK for Java --- README.md | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index 2faec7da..de02a132 100644 --- a/README.md +++ b/README.md @@ -1,10 +1,10 @@ [![CircleCI](https://circleci.com/gh/fnproject/fdk-java.svg?style=svg&circle-token=348bec5610c34421f6c436ab8f6a18e153cb1c01)](https://circleci.com/gh/fnproject/fdk-java) -# Function Development Kit for Java (FDK Java) +# Function Development Kit for Java (FDK for Java) -The Function Development Kit for Java (FDK Java) makes it easy to build and deploy Java functions to Fn with full support for Java 11+ as the default out of the box. +The Function Development Kit for Java makes it easy to build and deploy Java functions to Fn with full support for Java 11+ as the default out of the box. -Some of the FDK Java features include: +Some of the FDK for Java features include: - Parsing input and writing output - Flexible data binding to Java objects @@ -17,7 +17,7 @@ New to Fn Project? If you want to learn more about using the Fn Project to power ## Using the Function Development Kit for Java -For detailed instructions on using FDK Java to build and deploy Java functions to Fn, please see the official FDK Java developer guide in our docs repo here: https://github.com/fnproject/docs/blob/master/fdks/fdk-java/README.md. +For detailed instructions on using the FDK to build and deploy Java functions to Fn, please see the official FDK developer guide in our docs repo here: https://github.com/fnproject/docs/blob/master/fdks/fdk-java/README.md. ## Contributing to the Function Development Kit for Java From 821b7337a31b94ed4b3b324114ac4a3cd33f7fe3 Mon Sep 17 00:00:00 2001 From: CI Date: Fri, 4 Oct 2019 17:32:36 +0000 Subject: [PATCH 164/310] fn-java-fdk: post-1.0.102 version bump [skip ci] --- release.version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/release.version b/release.version index d5515c5a..882cfd44 100644 --- a/release.version +++ b/release.version @@ -1 +1 @@ -1.0.102 +1.0.103 From e3a7b07deb3326f3b784ef0f8ee72278c1a3a9b7 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 4 Nov 2019 21:22:40 +0000 Subject: [PATCH 165/310] Bump jackson-databind from 2.9.10 to 2.10.0 Bumps [jackson-databind](https://github.com/FasterXML/jackson) from 2.9.10 to 2.10.0. - [Release notes](https://github.com/FasterXML/jackson/releases) - [Commits](https://github.com/FasterXML/jackson/commits) Signed-off-by: dependabot[bot] --- examples/async-thumbnails/pom.xml | 2 +- examples/regex-query/pom.xml | 2 +- pom.xml | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/examples/async-thumbnails/pom.xml b/examples/async-thumbnails/pom.xml index c65684ac..11950d96 100644 --- a/examples/async-thumbnails/pom.xml +++ b/examples/async-thumbnails/pom.xml @@ -10,7 +10,7 @@ 1.0.0-SNAPSHOT 2.8.47 - 2.9.10 + 2.10.0 com.fnproject.fn.examples diff --git a/examples/regex-query/pom.xml b/examples/regex-query/pom.xml index d72bc766..82d5c683 100644 --- a/examples/regex-query/pom.xml +++ b/examples/regex-query/pom.xml @@ -9,7 +9,7 @@ UTF-8 1.0.0-SNAPSHOT - 2.9.10 + 2.10.0 com.fnproject.fn.examples diff --git a/pom.xml b/pom.xml index 187182ee..f95079dc 100644 --- a/pom.xml +++ b/pom.xml @@ -30,7 +30,7 @@ 3.10.0 2.6 4.4.10 - 2.9.10 + 2.10.0 0.8.1 9.4.12.v20180830 4.12 From 68d2edbd3fcd224df183b1ca0df8249daf6bf6aa Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 4 Nov 2019 22:36:49 +0000 Subject: [PATCH 166/310] Bump jackson.version from 2.9.10 to 2.10.0 in /integration-tests Bumps `jackson.version` from 2.9.10 to 2.10.0. Updates `jackson-databind` from 2.9.10 to 2.10.0 - [Release notes](https://github.com/FasterXML/jackson/releases) - [Commits](https://github.com/FasterXML/jackson/commits) Updates `jackson-core` from 2.9.10 to 2.10.0 - [Release notes](https://github.com/FasterXML/jackson-core/releases) - [Commits](https://github.com/FasterXML/jackson-core/compare/jackson-core-2.9.10...jackson-core-2.10.0) Updates `jackson-annotations` from 2.9.10 to 2.10.0 - [Release notes](https://github.com/FasterXML/jackson/releases) - [Commits](https://github.com/FasterXML/jackson/commits) Signed-off-by: dependabot[bot] --- integration-tests/pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/integration-tests/pom.xml b/integration-tests/pom.xml index ec2ccf8b..11ba547b 100644 --- a/integration-tests/pom.xml +++ b/integration-tests/pom.xml @@ -11,7 +11,7 @@ 3.6.2 2.5 - 2.9.10 + 2.10.0 4.12 2.22.1 From 8182f9a211660e51bca0a522e91b6f2463832e8c Mon Sep 17 00:00:00 2001 From: CI Date: Mon, 4 Nov 2019 22:48:19 +0000 Subject: [PATCH 167/310] fn-java-fdk: post-1.0.103 version bump [skip ci] --- release.version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/release.version b/release.version index 882cfd44..1f4f633c 100644 --- a/release.version +++ b/release.version @@ -1 +1 @@ -1.0.103 +1.0.104 From 8b4207f3fbb7695948bff6089c45b1c754e34783 Mon Sep 17 00:00:00 2001 From: CI Date: Mon, 4 Nov 2019 23:05:20 +0000 Subject: [PATCH 168/310] fn-java-fdk: post-1.0.104 version bump [skip ci] --- release.version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/release.version b/release.version index 1f4f633c..32f6174a 100644 --- a/release.version +++ b/release.version @@ -1 +1 @@ -1.0.104 +1.0.105 From f364f4bfd16ca8b5641ab7cefc8ba6ec31f47670 Mon Sep 17 00:00:00 2001 From: Owen Cliffe Date: Fri, 17 Jan 2020 19:53:40 +0000 Subject: [PATCH 169/310] Remove HTTPMime dependency and just depend on AHC (#221) --- flow-runtime/pom.xml | 2 +- pom.xml | 2 +- runtime/pom.xml | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/flow-runtime/pom.xml b/flow-runtime/pom.xml index 532686fe..cec1e629 100644 --- a/flow-runtime/pom.xml +++ b/flow-runtime/pom.xml @@ -46,7 +46,7 @@ org.apache.httpcomponents - httpmime + httpclient test diff --git a/pom.xml b/pom.xml index f95079dc..634caf16 100644 --- a/pom.xml +++ b/pom.xml @@ -94,7 +94,7 @@ org.apache.httpcomponents - httpmime + httpclient 4.5.6 diff --git a/runtime/pom.xml b/runtime/pom.xml index dca46c91..beaa5ada 100644 --- a/runtime/pom.xml +++ b/runtime/pom.xml @@ -54,7 +54,7 @@ org.apache.httpcomponents - httpmime + httpclient test From 910dce001d0e70785ec3bbefe42809ecf7f48f65 Mon Sep 17 00:00:00 2001 From: CI Date: Fri, 17 Jan 2020 20:04:52 +0000 Subject: [PATCH 170/310] fn-java-fdk: post-1.0.105 version bump [skip ci] --- release.version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/release.version b/release.version index 32f6174a..1b46b8b8 100644 --- a/release.version +++ b/release.version @@ -1 +1 @@ -1.0.105 +1.0.106 From 628f08b7a2f625fe39edfa9988ad42971f242e1a Mon Sep 17 00:00:00 2001 From: Owen Cliffe Date: Tue, 25 Feb 2020 11:04:16 +0100 Subject: [PATCH 171/310] Add Fn-Fdk-Version to java fdk --- build.sh | 10 +- .../fn/integrationtest/FunctionsTest.java | 49 +++++++-- runtime/pom.xml | 24 +++++ .../com/fnproject/fn/runtime/Version.java | 14 +++ .../com/fnproject/fn/runtime/EntryPoint.java | 47 +++++--- .../fnproject/fn/runtime/HTTPStreamCodec.java | 70 ++++++++---- .../fn/runtime/HTTPStreamCodecTest.java | 102 +++++++++--------- 7 files changed, 215 insertions(+), 101 deletions(-) create mode 100644 runtime/src/main/java-filtered/com/fnproject/fn/runtime/Version.java diff --git a/build.sh b/build.sh index b19ac5a0..019982f6 100755 --- a/build.sh +++ b/build.sh @@ -26,22 +26,22 @@ mvn -B deploy -DaltDeploymentRepository=localStagingDir::default::file://${REP ( cd images/build - ./docker-build.sh -t fnproject/fn-java-fdk-build:${BUILD_VERSION} . + ./docker-build.sh --no-cache -t fnproject/fn-java-fdk-build:${BUILD_VERSION} . ) ( cd images/build - ./docker-build.sh -f Dockerfile-jdk11 -t fnproject/fn-java-fdk-build:jdk11-${BUILD_VERSION} . + ./docker-build.sh --no-cache -f Dockerfile-jdk11 -t fnproject/fn-java-fdk-build:jdk11-${BUILD_VERSION} . ) ( cd runtime - docker build -t fnproject/fn-java-fdk:${BUILD_VERSION} -f ../images/runtime/Dockerfile . + docker build --no-cache -t fnproject/fn-java-fdk:${BUILD_VERSION} -f ../images/runtime/Dockerfile . ) ( cd runtime - docker build -f ../images/runtime/Dockerfile-jre11 -t fnproject/fn-java-fdk:jre11-${BUILD_VERSION} . + docker build --no-cache -f ../images/runtime/Dockerfile-jre11 -t fnproject/fn-java-fdk:jre11-${BUILD_VERSION} . ) ( @@ -53,4 +53,4 @@ mvn -B deploy -DaltDeploymentRepository=localStagingDir::default::file://${REP ( cd images/init-native ./docker-build.sh -) \ No newline at end of file +) diff --git a/integration-tests/src/test/java/com/fnproject/fn/integrationtest/FunctionsTest.java b/integration-tests/src/test/java/com/fnproject/fn/integrationtest/FunctionsTest.java index ab73d8b8..eb09f7de 100644 --- a/integration-tests/src/test/java/com/fnproject/fn/integrationtest/FunctionsTest.java +++ b/integration-tests/src/test/java/com/fnproject/fn/integrationtest/FunctionsTest.java @@ -1,18 +1,18 @@ package com.fnproject.fn.integrationtest; -import com.fasterxml.jackson.annotation.JsonIgnoreProperties; -import com.fasterxml.jackson.databind.ObjectMapper; -import com.fnproject.fn.integrationtest.IntegrationTestRule.CmdResult; -import org.junit.Rule; -import org.junit.Test; - import java.net.HttpURLConnection; +import java.net.Proxy; import java.net.URI; import java.net.URL; import java.util.HashMap; +import java.util.List; import java.util.Map; -import java.util.logging.Logger; -import java.util.logging.Level; + +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.databind.ObjectMapper; +import com.fnproject.fn.integrationtest.IntegrationTestRule.CmdResult; +import org.junit.Rule; +import org.junit.Test; import static org.assertj.core.api.Assertions.assertThat; @@ -45,8 +45,8 @@ public void shouldCallExistingFn() throws Exception { @Test() public void checkBoilerPlate() throws Exception { - for (String runtime : new String[]{"java8", "java11"}) { - IntegrationTestRule.TestContext tc = testRule.newTest(); + for (String runtime : new String[] {"java8", "java11"}) { + IntegrationTestRule.TestContext tc = testRule.newTest(); String fnName = "bp" + runtime; tc.runFn("init", "--runtime", runtime, "--name", fnName); tc.rewritePOM(); @@ -83,7 +83,7 @@ public void shouldHandleTrigger() throws Exception { HttpURLConnection con = (HttpURLConnection) invokeURL.openConnection(); con.setRequestMethod("POST"); - con.addRequestProperty("Foo","bar"); + con.addRequestProperty("Foo", "bar"); assertThat(con.getResponseCode()).isEqualTo(202); @@ -94,4 +94,31 @@ public void shouldHandleTrigger() throws Exception { } + @Test + public void shouldGetFDKVersion() throws Exception { + IntegrationTestRule.TestContext tc = testRule.newTest(); + tc.withDirFrom("funcs/simpleFunc").rewritePOM(); + + tc.runFn("--verbose", "deploy", "--create-app", "--app", tc.appName(), "--local"); + tc.runFn("config", "app", tc.appName(), "GREETING", "Salutations"); + + CmdResult r1 = tc.runFn("inspect", "function", tc.appName(), "simplefunc", "--endpoint"); + + String url = r1.getStdout().trim(); + + HttpURLConnection conn = (HttpURLConnection) (new URL(url).openConnection(Proxy.NO_PROXY)); + conn.setRequestMethod("POST"); + conn.setRequestProperty("Content-Type", "application/json; utf-8"); + conn.setDoInput(true); + conn.setDoOutput(true); + conn.getOutputStream().write(new byte[0]); + Map> headers = conn.getHeaderFields(); + + assertThat(headers).hasEntrySatisfying("Fn-Fdk-Version", (val) -> { + assertThat(val).isNotEmpty(); + assertThat(val.get(0)).matches("fdk-java/\\d+\\.\\d+\\.\\d+(-SNAPSHOT)? \\(jvm=.*, jvmv=.*\\)"); + }); + + } + } diff --git a/runtime/pom.xml b/runtime/pom.xml index beaa5ada..3a87f28d 100644 --- a/runtime/pom.xml +++ b/runtime/pom.xml @@ -75,6 +75,13 @@ + + + src/main/java-filtered + ${build.directory}/version-sources + true + + maven-dependency-plugin @@ -93,6 +100,23 @@ + + org.codehaus.mojo + build-helper-maven-plugin + + + generate-sources + + add-source + + + + ${project.build.directory}/version-sources + + + + + diff --git a/runtime/src/main/java-filtered/com/fnproject/fn/runtime/Version.java b/runtime/src/main/java-filtered/com/fnproject/fn/runtime/Version.java new file mode 100644 index 00000000..48b07c8a --- /dev/null +++ b/runtime/src/main/java-filtered/com/fnproject/fn/runtime/Version.java @@ -0,0 +1,14 @@ +package com.fnproject.fn.runtime; + +/** + * This uses maven-resource filtering rather than conventional manifest versioning as it's more robust against resource changes than using standard META-INF/MANIFEST.MF + * versioning. For native image functions this negates the need for extra configuration to include manifest resources. + * + * Created on 18/02/2020. + *

    + * + * (c) 2020 Oracle Corporation + */ +public class Version { + public static final String FDK_VERSION="${project.version}"; +} diff --git a/runtime/src/main/java/com/fnproject/fn/runtime/EntryPoint.java b/runtime/src/main/java/com/fnproject/fn/runtime/EntryPoint.java index 76ca4b3b..c9fa4523 100644 --- a/runtime/src/main/java/com/fnproject/fn/runtime/EntryPoint.java +++ b/runtime/src/main/java/com/fnproject/fn/runtime/EntryPoint.java @@ -1,7 +1,23 @@ package com.fnproject.fn.runtime; -import com.fnproject.fn.api.*; +import java.io.IOException; +import java.io.PrintStream; +import java.util.Arrays; +import java.util.Collections; +import java.util.HashMap; +import java.util.HashSet; +import java.util.Map; +import java.util.Set; +import java.util.concurrent.atomic.AtomicInteger; +import java.util.regex.Pattern; + +import com.fnproject.fn.api.FnFeature; +import com.fnproject.fn.api.FnFeatures; +import com.fnproject.fn.api.InputEvent; +import com.fnproject.fn.api.MethodWrapper; +import com.fnproject.fn.api.OutputEvent; +import com.fnproject.fn.api.RuntimeFeature; import com.fnproject.fn.api.exception.FunctionInputHandlingException; import com.fnproject.fn.api.exception.FunctionLoadException; import com.fnproject.fn.api.exception.FunctionOutputHandlingException; @@ -9,27 +25,30 @@ import com.fnproject.fn.runtime.exception.InternalFunctionInvocationException; import com.fnproject.fn.runtime.exception.InvalidEntryPointException; -import java.io.IOException; -import java.io.PrintStream; -import java.util.*; -import java.util.concurrent.atomic.AtomicInteger; - /** * Main entry point */ public class EntryPoint { - public static void main(String... args) throws Exception { + // regex to sanitize version properties on the off chance they fall outside of acceptable header values + private static final Pattern safeVersion = Pattern.compile("[^\\w ()._-]+"); + + public static void main(String... args) { PrintStream originalSystemOut = System.out; - // Override stdout while the function is running, so that the function result can be serialized to stdout - // without interference from the user printing stuff to what they believe is stdout. System.setOut(System.err); String format = System.getenv("FN_FORMAT"); EventCodec codec; if (format.equals(HTTPStreamCodec.HTTP_STREAM_FORMAT)) { - codec = new HTTPStreamCodec(System.getenv()); + // reduce risk of confusion due to non-header like system properties + String jvmName = safeVersion.matcher(System.getProperty("java.vm.name")).replaceAll(""); + String jvmVersion = safeVersion.matcher(System.getProperty("java.version")).replaceAll(""); + String fdkVersion = "fdk-java/" + Version.FDK_VERSION + + " (jvm=" + (jvmName + ", jvmv=" + + jvmVersion + ")"); + + codec = new HTTPStreamCodec(System.getenv(), fdkVersion); } else { throw new FunctionInputHandlingException("Unsupported function format:" + format); } @@ -77,7 +96,7 @@ public int run(Map env, EventCodec codec, PrintStream loggingOut FnFeatures fs = method.getTargetClass().getAnnotation(FnFeatures.class); if (fs != null) { for (FnFeature fnFeature : fs.value()) { - enableFeature(runtimeContext,fnFeature); + enableFeature(runtimeContext, fnFeature); } } @@ -182,14 +201,14 @@ private void addExceptionToStringBuilder(StringBuilder sb, Throwable t) { // This elides the FQCN of the exception class if it's from our runtime. sb.append(t.getMessage()); } else { - sb.append("Caused by: " + t.toString()); + sb.append("Caused by: ").append(t.toString()); } for (StackTraceElement elem : t.getStackTrace()) { if (elem.getClassName().startsWith("com.fnproject.fn")) { break; } - sb.append("\n at " + elem.toString()); + sb.append("\n at ").append(elem.toString()); } sb.append("\n"); @@ -202,7 +221,7 @@ private void addExceptionToStringBuilder(StringBuilder sb, Throwable t) { */ private Map excludeInternalConfigAndHeaders(Map env) { Set nonConfigEnvKeys = new HashSet<>(Arrays.asList("fn_app_name", "fn_path", "fn_method", "fn_request_url", - "fn_format", "content-length", "fn_call_id")); + "fn_format", "content-length", "fn_call_id")); Map config = new HashMap<>(); for (Map.Entry entry : env.entrySet()) { String lowerCaseKey = entry.getKey().toLowerCase(); diff --git a/runtime/src/main/java/com/fnproject/fn/runtime/HTTPStreamCodec.java b/runtime/src/main/java/com/fnproject/fn/runtime/HTTPStreamCodec.java index a28d9ccd..512fb8bf 100644 --- a/runtime/src/main/java/com/fnproject/fn/runtime/HTTPStreamCodec.java +++ b/runtime/src/main/java/com/fnproject/fn/runtime/HTTPStreamCodec.java @@ -1,6 +1,25 @@ package com.fnproject.fn.runtime; +import java.io.ByteArrayOutputStream; +import java.io.Closeable; +import java.io.File; +import java.io.IOException; +import java.io.InputStream; +import java.nio.file.Files; +import java.nio.file.attribute.PosixFilePermissions; +import java.time.Instant; +import java.time.format.DateTimeParseException; +import java.time.temporal.ChronoUnit; +import java.util.Collections; +import java.util.HashSet; +import java.util.Map; +import java.util.Objects; +import java.util.Random; +import java.util.Set; +import java.util.concurrent.CompletableFuture; +import java.util.concurrent.atomic.AtomicBoolean; + import com.fasterxml.jackson.core.io.CharTypes; import com.fnproject.fn.api.Headers; import com.fnproject.fn.api.InputEvent; @@ -11,7 +30,15 @@ import com.fnproject.fn.runtime.exception.FunctionInitializationException; import com.fnproject.fn.runtime.ntv.UnixServerSocket; import com.fnproject.fn.runtime.ntv.UnixSocket; -import org.apache.http.*; +import org.apache.http.Header; +import org.apache.http.HttpEntityEnclosingRequest; +import org.apache.http.HttpException; +import org.apache.http.HttpRequest; +import org.apache.http.HttpRequestInterceptor; +import org.apache.http.HttpResponse; +import org.apache.http.HttpResponseInterceptor; +import org.apache.http.HttpVersion; +import org.apache.http.ParseException; import org.apache.http.entity.ByteArrayEntity; import org.apache.http.entity.ContentType; import org.apache.http.entity.StringEntity; @@ -24,16 +51,6 @@ import org.apache.http.protocol.ImmutableHttpProcessor; import org.apache.http.protocol.UriHttpRequestHandlerMapper; -import java.io.*; -import java.nio.file.Files; -import java.nio.file.attribute.PosixFilePermissions; -import java.time.Instant; -import java.time.format.DateTimeParseException; -import java.time.temporal.ChronoUnit; -import java.util.*; -import java.util.concurrent.CompletableFuture; -import java.util.concurrent.atomic.AtomicBoolean; - /** * Fn HTTP Stream over Unix domain sockets codec *

    @@ -53,6 +70,7 @@ public final class HTTPStreamCodec implements EventCodec, Closeable { private static final Set stripInputHeaders; private static final Set stripOutputHeaders; private final Map env; + private final String fdkVersion; private final AtomicBoolean stopping = new AtomicBoolean(false); private final File socketFile; private final CompletableFuture stopped = new CompletableFuture<>(); @@ -75,11 +93,12 @@ public final class HTTPStreamCodec implements EventCodec, Closeable { hout.add("Content-Length"); hout.add("Transfer-Encoding"); hout.add("Connection"); + hout.add("Fn-Fdk-Version"); + stripOutputHeaders = Collections.unmodifiableSet(hout); } - private String randomString() { int leftLimit = 97; int rightLimit = 122; @@ -88,19 +107,22 @@ private String randomString() { StringBuilder buffer = new StringBuilder(targetStringLength); for (int i = 0; i < targetStringLength; i++) { int randomLimitedInt = leftLimit + (int) - (random.nextFloat() * (rightLimit - leftLimit + 1)); + (random.nextFloat() * (rightLimit - leftLimit + 1)); buffer.append((char) randomLimitedInt); } return buffer.toString(); } + /** * Construct a new HTTPStreamCodec based on the environment * - * @param env an env map + * @param env an env map + * @param fdkVersion the version to report to the runtime */ - HTTPStreamCodec(Map env) { + HTTPStreamCodec(Map env, String fdkVersion) { this.env = Objects.requireNonNull(env, "env"); + this.fdkVersion = Objects.requireNonNull(fdkVersion, "fdkVersion"); String listenerAddress = getRequiredEnv(FN_LISTENER); if (!listenerAddress.startsWith("unix:/")) { @@ -167,7 +189,7 @@ public void runCodec(Handler h) { evt = readEvent(request); } catch (FunctionInputHandlingException e) { response.setStatusCode(500); - response.setEntity(new StringEntity(jsonError("Invalid input for function", e.getMessage()), ContentType.APPLICATION_JSON)); + response.setEntity(new StringEntity(jsonError("Invalid input for function", e.getMessage()), ContentType.APPLICATION_JSON)); return; } @@ -177,7 +199,7 @@ public void runCodec(Handler h) { outEvt = h.handle(evt); } catch (Exception e) { response.setStatusCode(500); - response.setEntity(new StringEntity(jsonError("Unhandled internal error in FDK",e.getMessage()), ContentType.APPLICATION_JSON)); + response.setEntity(new StringEntity(jsonError("Unhandled internal error in FDK", e.getMessage()), ContentType.APPLICATION_JSON)); return; } @@ -186,7 +208,7 @@ public void runCodec(Handler h) { } catch (Exception e) { // TODO strange edge cases might appear with headers where the response is half written here response.setStatusCode(500); - response.setEntity(new StringEntity(jsonError("Unhandled internal error while writing FDK response",e.getMessage()), ContentType.APPLICATION_JSON)); + response.setEntity(new StringEntity(jsonError("Unhandled internal error while writing FDK response", e.getMessage()), ContentType.APPLICATION_JSON)); } } )); @@ -306,11 +328,11 @@ private InputEvent readEvent(HttpRequest request) { private void writeEvent(OutputEvent evt, HttpResponse response) { evt.getHeaders().asMap() - .entrySet() - .stream() - .filter(e -> !stripOutputHeaders.contains(e.getKey())) - .flatMap(e -> e.getValue().stream().map((v) -> new BasicHeader(e.getKey(), v))) - .forEachOrdered(response::addHeader); + .entrySet() + .stream() + .filter(e -> !stripOutputHeaders.contains(e.getKey())) + .flatMap(e -> e.getValue().stream().map((v) -> new BasicHeader(e.getKey(), v))) + .forEachOrdered(response::addHeader); ContentType contentType = evt.getContentType().map(c -> { try { @@ -321,6 +343,8 @@ private void writeEvent(OutputEvent evt, HttpResponse response) { }).orElse(ContentType.DEFAULT_BINARY); response.setHeader("Content-Type", contentType.toString()); + response.setHeader("Fn-Fdk-Version", fdkVersion); + response.setStatusLine(new BasicStatusLine(HttpVersion.HTTP_1_1, evt.getStatus().getCode(), evt.getStatus().name())); ByteArrayOutputStream bos = new ByteArrayOutputStream(); // TODO remove output buffering here - possibly change OutputEvent contract to support providing an InputStream? diff --git a/runtime/src/test/java/com/fnproject/fn/runtime/HTTPStreamCodecTest.java b/runtime/src/test/java/com/fnproject/fn/runtime/HTTPStreamCodecTest.java index 2b3c07ed..3b07af84 100644 --- a/runtime/src/test/java/com/fnproject/fn/runtime/HTTPStreamCodecTest.java +++ b/runtime/src/test/java/com/fnproject/fn/runtime/HTTPStreamCodecTest.java @@ -1,6 +1,22 @@ package com.fnproject.fn.runtime; +import java.io.File; +import java.io.IOException; +import java.nio.file.Files; +import java.nio.file.attribute.PosixFilePermissions; +import java.security.MessageDigest; +import java.util.ArrayList; +import java.util.Collections; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Random; +import java.util.concurrent.CompletableFuture; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.atomic.AtomicInteger; +import java.util.concurrent.atomic.AtomicReference; + import com.fnproject.fn.api.Headers; import com.fnproject.fn.api.InputEvent; import com.fnproject.fn.api.OutputEvent; @@ -17,17 +33,6 @@ import org.junit.Test; import org.junit.rules.Timeout; -import java.io.File; -import java.io.IOException; -import java.nio.file.Files; -import java.nio.file.attribute.PosixFilePermissions; -import java.security.MessageDigest; -import java.util.*; -import java.util.concurrent.CompletableFuture; -import java.util.concurrent.TimeUnit; -import java.util.concurrent.atomic.AtomicInteger; -import java.util.concurrent.atomic.AtomicReference; - import static org.assertj.core.api.Assertions.assertThat; /** @@ -39,6 +44,7 @@ public class HTTPStreamCodecTest { + private static final String VERSION = "FDK_TEST_VERSION"; @Rule public final Timeout to = Timeout.builder().withTimeout(60, TimeUnit.SECONDS).withLookingForStuckThread(true).build(); @@ -46,13 +52,13 @@ public class HTTPStreamCodecTest { private final List cleanups = new ArrayList<>(); private static File generateSocketFile() { - File f ; + File f; try { f = File.createTempFile("socket", ".sock"); f.delete(); f.deleteOnExit(); } catch (IOException e) { - throw new RuntimeException("Error creating socket file",e); + throw new RuntimeException("Error creating socket file", e); } return f; @@ -86,29 +92,28 @@ private HttpClient createClient(File unixSocket) throws Exception { private Request defaultRequest(HttpClient httpClient) { return httpClient.newRequest("http://localhost/call") - .method("POST") - .header("Fn-Call-Id", "callID") - .header("Fn-Deadline", "2002-10-02T10:00:00.992Z") - .header("Custom-header", "v1") - .header("Custom-header", "v2") - .header("Content-Type", "text/plain") - .content(new StringContentProvider("hello ")); + .method("POST") + .header("Fn-Call-Id", "callID") + .header("Fn-Deadline", "2002-10-02T10:00:00.992Z") + .header("Custom-header", "v1") + .header("Custom-header", "v2") + .header("Content-Type", "text/plain") + .content(new StringContentProvider("hello ")); } @After - public void cleanup() throws Exception { + public void cleanup() { cleanups.forEach(Runnable::run); } - File startCodec(Map env, EventCodec.Handler h) { Map newEnv = new HashMap<>(env); File socket = generateSocketFile(); newEnv.put("FN_LISTENER", "unix:" + socket.getAbsolutePath()); - HTTPStreamCodec codec = new HTTPStreamCodec(newEnv); + HTTPStreamCodec codec = new HTTPStreamCodec(newEnv, VERSION); Thread t = new Thread(() -> codec.runCodec(h)); t.start(); @@ -133,17 +138,18 @@ public void shouldAcceptDataOnHttp() throws Exception { HttpClient client = createClient(socketFile); ContentResponse resp = client.newRequest("http://localhost/call") - .method("POST") - .header("Fn-Call-Id", "callID") - .header("Fn-Deadline", "2002-10-02T10:00:00.992Z") - .header("Custom-header", "v1") - .header("Custom-header", "v2") - .header("Content-Type", "text/plain") - .content(new StringContentProvider("hello ")).send(); + .method("POST") + .header("Fn-Call-Id", "callID") + .header("Fn-Deadline", "2002-10-02T10:00:00.992Z") + .header("Custom-header", "v1") + .header("Custom-header", "v2") + .header("Content-Type", "text/plain") + .content(new StringContentProvider("hello ")).send(); assertThat(resp.getStatus()).isEqualTo(200); assertThat(resp.getContent()).isEqualTo("hello".getBytes()); assertThat(resp.getHeaders().get("x-test")).isEqualTo("bar"); + assertThat(resp.getHeaders().get("fn-fdk-version")).isEqualTo(VERSION); InputEvent evt = lastEvent.get(1, TimeUnit.MILLISECONDS); assertThat(evt.getCallID()).isEqualTo("callID"); @@ -152,6 +158,7 @@ public void shouldAcceptDataOnHttp() throws Exception { } + @Test public void shouldRejectFnMissingHeaders() throws Exception { @@ -165,13 +172,13 @@ public void shouldRejectFnMissingHeaders() throws Exception { HttpClient client = createClient(socket); Request positive = client.newRequest("http://localhost/call") - .method("POST"); + .method("POST"); headers.forEach(positive::header); assertThat(positive.send().getStatus()).withFailMessage("Expecting req with mandatory headers to pass").isEqualTo(200); for (String h : headers.keySet()) { Request r = client.newRequest("http://localhost/call") - .method("POST"); + .method("POST"); headers.forEach((k, v) -> { if (!k.equals(h)) { r.header(k, v); @@ -209,13 +216,13 @@ public void shouldHandleMultipleRequests() throws Exception { for (int i = 0; i < 200; i++) { byte[] body = randomBytes(i * 1997); ContentResponse resp = httpClient.newRequest("http://localhost/call") - .method("POST") - .header("Fn-Call-Id", "callID") - .header("Fn-Deadline", "2002-10-02T10:00:00.992Z") - .header("Custom-header", "v1") - .header("Custom-header", "v2") - .header("Content-Type", "text/plain") - .content(new BytesContentProvider(body)).send(); + .method("POST") + .header("Fn-Call-Id", "callID") + .header("Fn-Deadline", "2002-10-02T10:00:00.992Z") + .header("Custom-header", "v1") + .header("Custom-header", "v2") + .header("Content-Type", "text/plain") + .content(new BytesContentProvider(body)).send(); assertThat(resp.getStatus()).isEqualTo(200); assertThat(resp.getContent()).isEqualTo(body); @@ -249,9 +256,9 @@ public void shouldHandleLargeBodies() throws Exception { CompletableFuture cdl = new CompletableFuture<>(); MessageDigest readDigest = MessageDigest.getInstance("SHA-256"); defaultRequest(client) - .content(new BytesContentProvider(randomString)) - .onResponseContent((response, byteBuffer) -> readDigest.update(byteBuffer)) - .send(cdl::complete); + .content(new BytesContentProvider(randomString)) + .onResponseContent((response, byteBuffer) -> readDigest.update(byteBuffer)) + .send(cdl::complete); Result r = cdl.get(); assertThat(r.getResponse().getStatus()).isEqualTo(200); assertThat(readDigest.digest()).isEqualTo(inDigest); @@ -263,8 +270,8 @@ private byte[] randomBytes(int sz) { sr.nextBytes(part); // Make random ascii for convenience in debugging - for(int i = 0 ; i < part.length; i++){ - part[i] = (byte)((part[i]%26) + 65); + for (int i = 0; i < part.length; i++) { + part[i] = (byte) ((part[i] % 26) + 65); } byte[] randomString = new byte[sz]; @@ -300,9 +307,9 @@ public void shouldConvertStatusResponses() throws Exception { @Test public void shouldStripHopToHopHeadersFromFunctionInput() throws Exception { - for (String header[] : new String[][]{ - {"Transfer-encoding", "chunked"}, - {"Connection", "close"}, + for (String[] header : new String[][] { + {"Transfer-encoding", "chunked"}, + {"Connection", "close"}, }) { CompletableFuture lastEvent = new CompletableFuture<>(); @@ -314,7 +321,6 @@ public void shouldStripHopToHopHeadersFromFunctionInput() throws Exception { ContentResponse resp = defaultRequest(client).send(); assertThat(resp.getHeaders().get(header[0])).isNull(); - } } From 13e609e1df49cdde3266e047093c76005e533deb Mon Sep 17 00:00:00 2001 From: CI Date: Fri, 6 Mar 2020 23:21:39 +0000 Subject: [PATCH 172/310] fn-java-fdk: post-1.0.106 version bump [skip ci] --- release.version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/release.version b/release.version index 1b46b8b8..f91c959f 100644 --- a/release.version +++ b/release.version @@ -1 +1 @@ -1.0.106 +1.0.107 From 4357189c9290d531d8b3d5981a4dfe9f67312a19 Mon Sep 17 00:00:00 2001 From: Owen Cliffe Date: Tue, 10 Mar 2020 09:45:03 +0000 Subject: [PATCH 173/310] bump to jackson 2.10.3 (#224) --- examples/async-thumbnails/pom.xml | 2 +- examples/regex-query/pom.xml | 2 +- images/init-native/pom.xml | 2 +- integration-tests/pom.xml | 2 +- pom.xml | 2 +- 5 files changed, 5 insertions(+), 5 deletions(-) diff --git a/examples/async-thumbnails/pom.xml b/examples/async-thumbnails/pom.xml index 11950d96..01e0f8f4 100644 --- a/examples/async-thumbnails/pom.xml +++ b/examples/async-thumbnails/pom.xml @@ -10,7 +10,7 @@ 1.0.0-SNAPSHOT 2.8.47 - 2.10.0 + 2.10.3 com.fnproject.fn.examples diff --git a/examples/regex-query/pom.xml b/examples/regex-query/pom.xml index 82d5c683..870d78ae 100644 --- a/examples/regex-query/pom.xml +++ b/examples/regex-query/pom.xml @@ -9,7 +9,7 @@ UTF-8 1.0.0-SNAPSHOT - 2.10.0 + 2.10.3 com.fnproject.fn.examples diff --git a/images/init-native/pom.xml b/images/init-native/pom.xml index 4d8e2703..f90e190b 100644 --- a/images/init-native/pom.xml +++ b/images/init-native/pom.xml @@ -5,7 +5,7 @@ 4.0.0 UTF-8 - 1.0.0-SNAPSHOT + 1.0.107 com.example.fn hello diff --git a/integration-tests/pom.xml b/integration-tests/pom.xml index 11ba547b..983d9efa 100644 --- a/integration-tests/pom.xml +++ b/integration-tests/pom.xml @@ -11,7 +11,7 @@ 3.6.2 2.5 - 2.10.0 + 2.10.3 4.12 2.22.1 diff --git a/pom.xml b/pom.xml index 634caf16..b5d36dd0 100644 --- a/pom.xml +++ b/pom.xml @@ -30,7 +30,7 @@ 3.10.0 2.6 4.4.10 - 2.10.0 + 2.10.3 0.8.1 9.4.12.v20180830 4.12 From a8b44387b989ce82474d9e5d4faf36321dc953bc Mon Sep 17 00:00:00 2001 From: CI Date: Tue, 10 Mar 2020 09:57:02 +0000 Subject: [PATCH 174/310] fn-java-fdk: post-1.0.107 version bump [skip ci] --- release.version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/release.version b/release.version index f91c959f..572da0ab 100644 --- a/release.version +++ b/release.version @@ -1 +1 @@ -1.0.107 +1.0.108 From 5770a42ef86060bdf8e6cbb17ef690d6737bc394 Mon Sep 17 00:00:00 2001 From: Owen Cliffe Date: Mon, 23 Mar 2020 15:18:23 +0000 Subject: [PATCH 175/310] Add third party license files (#225) Adds third party license files to repo and to jar --- THIRD_PARTY_LICENSES.txt | 303 +++++++++++++++++++++++++++++++++++++++ pom.xml | 30 ++++ 2 files changed, 333 insertions(+) create mode 100644 THIRD_PARTY_LICENSES.txt diff --git a/THIRD_PARTY_LICENSES.txt b/THIRD_PARTY_LICENSES.txt new file mode 100644 index 00000000..17e271cb --- /dev/null +++ b/THIRD_PARTY_LICENSES.txt @@ -0,0 +1,303 @@ +oci-java-sdk is dual-licensed to you under the Universal Permissive License (UPL) 1.0 or Apache License 2.0. See below for license terms. You may choose either license. +Copyright (c) 2016, 2018, Oracle and/or its affiliates. All rights reserved. +License: Copies of the Apache License V2 and the Universal Permissive License 1.0 are included at the end of this file. + +-------------------------------------------------------------------------------- + +fdk-java is licensed under the Apache License, Version 2.0. +License: A copy of the Apache License V2 is included at the end of this file. + +-------------------------------------------------------------------------------- + +Apache Commons Logging +Copyright 2003-2016 The Apache Software Foundation + +This product includes software developed at +The Apache Software Foundation (http://www.apache.org/). +License: Apache License 2.0, a copy of the license is included at the end of this file. + +-------------------------------------------------------------------------------- + +Apache Commons IO +Copyright 2002-2017 The Apache Software Foundation + +This product includes software developed at +The Apache Software Foundation (http://www.apache.org/). +License: Apache License 2.0, a copy of the license is included at the end of this file. + +-------------------------------------------------------------------------------- + +Apache HttpComponents Core +Copyright 2005-2020 The Apache Software Foundation + +This product includes software developed at +The Apache Software Foundation (http://www.apache.org/). + +License: Apache License 2.0, a copy of the license is included at the end of this file. + +-------------------------------------------------------------------------------- + +Apache HttpComponents Client (including HttpMime) +Copyright 1999-2018 The Apache Software Foundation + +This product includes software developed at +The Apache Software Foundation (http://www.apache.org/). + +License: Apache License 2.0, a copy of the license is included at the end of this file. + +-------------------------------------------------------------------------------- + +Jackson Databind +Copyright (c) 2019 Tatu Saloranta + +License: Apache License 2.0, a copy of the license is included at the end of this file. + +-------------------------------------------------------------------------------- + +Typetools +Copyright 2010-2019 Jonathan Halterman and friends. Released under the Apache 2.0 license. +License: Apache License 2.0, a copy of the license is included at the end of this file. + +-------------------------------------------------------------------------------- + + + +================================================================================ + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright 2017 Oracle Corporation + + 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. + + + +================================================================================ +The Universal Permissive License (UPL), Version 1.0 + +Subject to the condition set forth below, permission is hereby granted to any +person obtaining a copy of this software, associated documentation and/or data +(collectively the "Software"), free of charge and under any and all copyright +rights in the Software, and any and all patent rights owned or freely +licensable by each licensor hereunder covering either (i) the unmodified +Software as contributed to or provided by such licensor, or (ii) the Larger +Works (as defined below), to deal in both + +(a) the Software, and +(b) any piece of software and/or hardware listed in the lrgrwrks.txt file if +one is included with the Software (each a "Larger Work" to which the Software +is contributed by such licensors), + +without restriction, including without limitation the rights to copy, create +derivative works of, display, perform, and distribute the Software and make, +use, sell, offer for sale, import, export, have made, and have sold the +Software and the Larger Work(s), and to sublicense the foregoing rights on +either these or other terms. + +This license is subject to the following condition: +The above copyright notice and either this complete permission notice or at +a minimum a reference to the UPL must be included in all copies or +substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/pom.xml b/pom.xml index b5d36dd0..58e33406 100644 --- a/pom.xml +++ b/pom.xml @@ -164,6 +164,11 @@ pitest-maven ${pitest.version} + + org.apache.maven.plugins + maven-resources-plugin + 3.1.0 + @@ -203,6 +208,31 @@ + + maven-resources-plugin + 3.1.0 + + + copy-resources + validate + + copy-resources + + + ${project.basedir}/target/classes/META-INF/ + + + ${user.dir} + + THIRD_PARTY_LICENSES.txt + LICENSE + + + + + + + org.jacoco jacoco-maven-plugin From 829f8b074a97db365508be045374ddd573425211 Mon Sep 17 00:00:00 2001 From: CI Date: Mon, 23 Mar 2020 15:30:48 +0000 Subject: [PATCH 176/310] fn-java-fdk: post-1.0.108 version bump [skip ci] --- release.version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/release.version b/release.version index 572da0ab..0264dcd1 100644 --- a/release.version +++ b/release.version @@ -1 +1 @@ -1.0.108 +1.0.109 From 62c35be59ec969ecb6d40738e95bcd1ab1e4540e Mon Sep 17 00:00:00 2001 From: Harsh Pai Date: Fri, 15 May 2020 10:45:54 -0700 Subject: [PATCH 177/310] Refresh the Java FDK dependencies to more recent versions. (#227) --- CONTRIBUTING.md | 5 +++++ examples/async-thumbnails/pom.xml | 4 ++-- examples/regex-query/pom.xml | 2 +- images/init-native/pom.xml | 2 +- integration-tests/funcs/flowAllFeatures/pom.xml | 2 +- integration-tests/pom.xml | 6 +++--- pom.xml | 12 ++++++------ 7 files changed, 19 insertions(+), 14 deletions(-) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 9fce1768..619755d2 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -16,4 +16,9 @@ We welcome all contributions! * Don't make breaking changes to the public APIs. * Write tests - especially for public APIs. * Make sure that changes to `api` are backwards compatible with `runtime` and vice-versa. + +## Note for mac users + #### If you run into build failures, try the steps below: + * Install `cmake`, if you don't have it already by running `brew install cmake` + * Go to `fdk-java/runtime/src/main/c` folder and run `./buildit.sh` diff --git a/examples/async-thumbnails/pom.xml b/examples/async-thumbnails/pom.xml index 01e0f8f4..b08f101d 100644 --- a/examples/async-thumbnails/pom.xml +++ b/examples/async-thumbnails/pom.xml @@ -9,8 +9,8 @@ UTF-8 1.0.0-SNAPSHOT - 2.8.47 - 2.10.3 + 3.3.3 + 2.11.0 com.fnproject.fn.examples diff --git a/examples/regex-query/pom.xml b/examples/regex-query/pom.xml index 870d78ae..c85f7289 100644 --- a/examples/regex-query/pom.xml +++ b/examples/regex-query/pom.xml @@ -9,7 +9,7 @@ UTF-8 1.0.0-SNAPSHOT - 2.10.3 + 2.11.0 com.fnproject.fn.examples diff --git a/images/init-native/pom.xml b/images/init-native/pom.xml index f90e190b..4d8e2703 100644 --- a/images/init-native/pom.xml +++ b/images/init-native/pom.xml @@ -5,7 +5,7 @@ 4.0.0 UTF-8 - 1.0.107 + 1.0.0-SNAPSHOT com.example.fn hello diff --git a/integration-tests/funcs/flowAllFeatures/pom.xml b/integration-tests/funcs/flowAllFeatures/pom.xml index 55361cbb..1796dc28 100644 --- a/integration-tests/funcs/flowAllFeatures/pom.xml +++ b/integration-tests/funcs/flowAllFeatures/pom.xml @@ -49,7 +49,7 @@ commons-io commons-io - 2.5 + 2.6 diff --git a/integration-tests/pom.xml b/integration-tests/pom.xml index 983d9efa..1903493a 100644 --- a/integration-tests/pom.xml +++ b/integration-tests/pom.xml @@ -9,9 +9,9 @@ integration-tests 1.0.0-SNAPSHOT - 3.6.2 - 2.5 - 2.10.3 + 3.16.1 + 2.6 + 2.11.0 4.12 2.22.1 diff --git a/pom.xml b/pom.xml index 58e33406..5dd36cc0 100644 --- a/pom.xml +++ b/pom.xml @@ -27,14 +27,14 @@ UTF-8 UTF-8 - 3.10.0 + 3.16.1 2.6 - 4.4.10 - 2.10.3 + 4.4.13 + 2.11.0 0.8.1 9.4.12.v20180830 4.12 - 2.21.0 + 3.3.3 1.4.0 1.7.25 2.22.1 @@ -95,7 +95,7 @@ org.apache.httpcomponents httpclient - 4.5.6 + 4.5.12 commons-io @@ -110,7 +110,7 @@ net.jodah typetools - 0.5.0 + 0.6.2 From 62fad105116dafaed913eeabe3d8e0ce75e7ac76 Mon Sep 17 00:00:00 2001 From: CI Date: Fri, 15 May 2020 17:56:58 +0000 Subject: [PATCH 178/310] fn-java-fdk: post-1.0.109 version bump [skip ci] --- release.version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/release.version b/release.version index 0264dcd1..9a8c8209 100644 --- a/release.version +++ b/release.version @@ -1 +1 @@ -1.0.109 +1.0.110 From 89aadb9bfed6c63dec36c01cfb7dee4abb4a5be6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tom=C3=A1=C5=A1=20Zezula?= Date: Fri, 31 Jul 2020 10:30:33 +0200 Subject: [PATCH 179/310] Updated to GraalVM 20.1.0. (#226) * Updated to GraalVM 20.1.0 * Added GraalVM JDK 11 images * Moved to Debian buster base image for GraalVM --- .circleci/release.sh | 11 ++++++- images/build-native/Dockerfile | 27 +++++++---------- images/build-native/Dockerfile-jdk11 | 38 ++++++++++++++++++++++++ images/build-native/docker-build.sh | 30 ++++++++++++++----- images/build-native/native.version | 2 +- images/init-native/Dockerfile | 3 -- images/init-native/Dockerfile-init-image | 3 +- images/init-native/docker-build.sh | 7 +++++ 8 files changed, 89 insertions(+), 32 deletions(-) create mode 100644 images/build-native/Dockerfile-jdk11 diff --git a/.circleci/release.sh b/.circleci/release.sh index 7a8b83ad..90b50550 100755 --- a/.circleci/release.sh +++ b/.circleci/release.sh @@ -82,12 +82,21 @@ git push origin "$release_version" ) ( + ## native jdk8 build image if [ -f images/build-native/native_build.image ] ; then native_build_image=$(cat images/build-native/native_build.image) docker tag ${native_build_image} ${USER}/${NATIVE_BUILD_IMAGE}:latest docker push ${USER}/${NATIVE_BUILD_IMAGE}:latest docker push ${native_build_image} - fi + fi + + ## native jdk11 build image + if [ -f images/build-native/native_build_11.image ] ; then + native_build_image=$(cat images/build-native/native_build_11.image) + docker tag ${native_build_image} ${USER}/${NATIVE_BUILD_IMAGE}:jdk11-latest + docker push ${USER}/${NATIVE_BUILD_IMAGE}:jdk11-latest + docker push ${native_build_image} + fi ) diff --git a/images/build-native/Dockerfile b/images/build-native/Dockerfile index e50f84dc..a11af5d9 100644 --- a/images/build-native/Dockerfile +++ b/images/build-native/Dockerfile @@ -1,29 +1,23 @@ -FROM openjdk:8-jdk-slim as build -LABEL maintainer="tomas.zezula@oracle.com" +FROM debian:buster-slim as build RUN set -x \ && apt-get -y update \ - && apt-get -y install gcc g++ git make python zlib1g-dev \ + && apt-get -y install gcc g++ git make python zlib1g-dev wget \ && rm -rf /var/lib/apt/lists/* -ENV JVMCI_VERSION 19.2-b02 - WORKDIR /build RUN set -x \ - && git clone https://github.com/graalvm/mx.git \ - && git clone https://github.com/graalvm/graal-jvmci-8.git \ - && git -C graal-jvmci-8 checkout jvmci-${JVMCI_VERSION} \ - && mx/mx --primary-suite graal-jvmci-8 --vm=server build -DFULL_DEBUG_SYMBOLS=0 \ - && mx/mx --primary-suite graal-jvmci-8 --vm=server -v vm -version \ - && mx/mx --primary-suite graal-jvmci-8 --vm=server -v unittest \ - && cp -r $(/build/mx/mx --primary-suite graal-jvmci-8 jdkhome) /build/jvmcijdk8 - -RUN git clone https://github.com/oracle/graal.git \ - && git -C graal checkout vm-19.2.0 + && git clone --depth 1 https://github.com/graalvm/mx.git \ + && wget -q --output-document jvmcijdk.tar.gz https://github.com/graalvm/openjdk8-jvmci-builder/releases/download/jvmci-20.1-b02/openjdk-8u252+09-jvmci-20.1-b02-linux-amd64.tar.gz \ + && mkdir jvmcijdk8 \ + && tar -xz --strip 1 -f jvmcijdk.tar.gz -C /build/jvmcijdk8 \ + && rm jvmcijdk.tar.gz + +RUN git clone --depth 1 --single-branch https://github.com/oracle/graal.git --branch release/graal-vm/20.1 WORKDIR /build/graal/vm RUN export JAVA_HOME=/build/jvmcijdk8 \ - && /build/mx/mx --dy /substratevm --force-bash-launchers=true --disable-polyglot --disable-libpolyglot build + && /build/mx/mx --dy /substratevm --force-bash-launchers=true --disable-polyglot --skip-libraries=true build WORKDIR /build/graal/vm/latest_graalvm RUN LONG_NAME=$(ls) \ @@ -31,7 +25,6 @@ RUN LONG_NAME=$(ls) \ && mv $LONG_NAME $SHORT_NAME FROM debian:stretch-slim as final -LABEL maintainer="tomas.zezula@oracle.com" RUN set -x \ && apt-get -y update \ diff --git a/images/build-native/Dockerfile-jdk11 b/images/build-native/Dockerfile-jdk11 new file mode 100644 index 00000000..81231419 --- /dev/null +++ b/images/build-native/Dockerfile-jdk11 @@ -0,0 +1,38 @@ +FROM debian:buster-slim as build + +RUN set -x \ + && apt-get -y update \ + && apt-get -y install gcc g++ git make python zlib1g-dev wget \ + && rm -rf /var/lib/apt/lists/* + +WORKDIR /build + +RUN set -x \ + && git clone --depth 1 https://github.com/graalvm/mx.git \ + && wget -q --output-document jvmcijdk.tar.gz https://github.com/graalvm/labs-openjdk-11/releases/download/jvmci-20.1-b02/labsjdk-ce-11.0.7+10-jvmci-20.1-b02-linux-amd64.tar.gz \ + && mkdir jvmcijdk11 \ + && tar -xz --strip 1 -f jvmcijdk.tar.gz -C /build/jvmcijdk11 \ + && rm jvmcijdk.tar.gz + +RUN git clone --depth 1 --single-branch https://github.com/oracle/graal.git --branch release/graal-vm/20.1 +WORKDIR /build/graal/vm +RUN export JAVA_HOME=/build/jvmcijdk11 \ + && /build/mx/mx --dy /substratevm --force-bash-launchers=true --disable-polyglot --skip-libraries=true build + +WORKDIR /build/graal/vm/latest_graalvm +RUN LONG_NAME=$(ls) \ + && SHORT_NAME=graalvm \ + && mv $LONG_NAME $SHORT_NAME + +FROM debian:stretch-slim as final + +RUN set -x \ + && apt-get -y update \ + && apt-get -y install gcc zlib1g-dev + +COPY --from=build /build/graal/vm/latest_graalvm/graalvm /usr/local/graalvm +COPY src/main/c/libfnunixsocket.so /function/runtime/lib/ + + +ENV GRAALVM_HOME=/usr/local/graalvm +WORKDIR /function diff --git a/images/build-native/docker-build.sh b/images/build-native/docker-build.sh index 9e5625bc..3ea15fb5 100755 --- a/images/build-native/docker-build.sh +++ b/images/build-native/docker-build.sh @@ -7,15 +7,29 @@ fi native_version=$(cat native.version) set -e +workdir=${1} +dockerfiledir=$(pwd) + +# Build JDK 8 native_image="fnproject/fn-java-native:${native_version}" +if docker pull ${native_image} ; then + echo ${native_image} already exists, skipping native build +else + ( + cd ${workdir} + docker build -f ${dockerfiledir}/Dockerfile -t "${native_image}" . + ) + echo "${native_image}" > native_build.image +fi + +# Build JDK 11 +native_image="fnproject/fn-java-native:jdk11-${native_version}" if docker pull ${native_image} ; then echo ${native_image} already exists, skipping native build - exit 0 +else + ( + cd ${workdir} + docker build -f ${dockerfiledir}/Dockerfile-jdk11 -t "${native_image}" . + ) + echo "${native_image}" > native_build_11.image fi -workdir=${1} -dockerfiledir=$(pwd) -( - cd ${workdir} - docker build -f ${dockerfiledir}/Dockerfile -t "fnproject/fn-java-native:${native_version}" . -) -echo "fnproject/fn-java-native:${native_version}" > native_build.image diff --git a/images/build-native/native.version b/images/build-native/native.version index 8f0916f7..a918a2aa 100644 --- a/images/build-native/native.version +++ b/images/build-native/native.version @@ -1 +1 @@ -0.5.0 +0.6.0 diff --git a/images/init-native/Dockerfile b/images/init-native/Dockerfile index ec251021..ef9e608b 100644 --- a/images/init-native/Dockerfile +++ b/images/init-native/Dockerfile @@ -1,5 +1,4 @@ FROM fnproject/fn-java-fdk-build:latest as build -LABEL maintainer="tomas.zezula@oracle.com" WORKDIR /function ENV MAVEN_OPTS=-Dmaven.repo.local=/usr/share/maven/ref/repository ADD pom.xml pom.xml @@ -8,7 +7,6 @@ ADD src src RUN ["mvn", "package"] FROM fnproject/fn-java-native:latest as build-native-image -LABEL maintainer="tomas.zezula@oracle.com" WORKDIR /function COPY --from=build /function/target/*.jar target/ COPY --from=build /function/src/main/conf/reflection.json reflection.json @@ -27,7 +25,6 @@ RUN /usr/local/graalvm/bin/native-image \ FROM busybox:glibc -LABEL maintainer="tomas.zezula@oracle.com" WORKDIR /function COPY --from=build-native-image /function/func func COPY --from=build-native-image /function/runtime/lib/* . diff --git a/images/init-native/Dockerfile-init-image b/images/init-native/Dockerfile-init-image index 0850e955..5c899bfb 100644 --- a/images/init-native/Dockerfile-init-image +++ b/images/init-native/Dockerfile-init-image @@ -1,11 +1,10 @@ FROM alpine:latest -LABEL maintainer="tomas.zezula@oracle.com" WORKDIR /build COPY src src COPY pom.xml . COPY func.init.yaml . -COPY Dockerfile . +COPY Dockerfile.build Dockerfile RUN echo $'#!/bin/sh\n\ if [ -n ${FN_FUNCTION_NAME} ]\n\ diff --git a/images/init-native/docker-build.sh b/images/init-native/docker-build.sh index 4aea7a2b..36a59caa 100755 --- a/images/init-native/docker-build.sh +++ b/images/init-native/docker-build.sh @@ -3,4 +3,11 @@ if [ -z "${FN_FDK_VERSION}" ]; then FN_FDK_VERSION=$(cat ../../release.version) fi sed -i.bak -e "s|.*|${FN_FDK_VERSION}|" pom.xml && rm pom.xml.bak +cp Dockerfile Dockerfile.build docker build -t fnproject/fn-java-native-init:${FN_FDK_VERSION} -f Dockerfile-init-image . + +cp Dockerfile Dockerfile.build +sed -i.bak -e "s|fnproject/fn-java-fdk-build:latest|fnproject/fn-java-fdk-build:jdk11-latest|" Dockerfile.build && rm Dockerfile.build.bak +sed -i.bak -e "s|fnproject/fn-java-native:latest|fnproject/fn-java-native:jdk11-latest|" Dockerfile.build && rm Dockerfile.build.bak +docker build -t fnproject/fn-java-native-init:jdk11-${FN_FDK_VERSION} -f Dockerfile-init-image . +rm Dockerfile.build \ No newline at end of file From 5edbd1310025219d785450d2170205531da0a93e Mon Sep 17 00:00:00 2001 From: Tom Coupland Date: Tue, 11 Aug 2020 18:50:40 +0100 Subject: [PATCH 180/310] Upgrade spring cloud functions to 2.3.1.RELEASE --- fn-spring-cloud-function/pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/fn-spring-cloud-function/pom.xml b/fn-spring-cloud-function/pom.xml index 9acec1ba..02478598 100644 --- a/fn-spring-cloud-function/pom.xml +++ b/fn-spring-cloud-function/pom.xml @@ -12,7 +12,7 @@ fn-spring-cloud-function - 1.0.0.RELEASE + 2.3.1.RELEASE From c8684f4d06fcdad9b1f811c0ad66ff7cba87287b Mon Sep 17 00:00:00 2001 From: Tom Coupland Date: Tue, 11 Aug 2020 19:05:12 +0100 Subject: [PATCH 181/310] Update pom.xml --- fn-spring-cloud-function/pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/fn-spring-cloud-function/pom.xml b/fn-spring-cloud-function/pom.xml index 02478598..7af1a1ff 100644 --- a/fn-spring-cloud-function/pom.xml +++ b/fn-spring-cloud-function/pom.xml @@ -12,7 +12,7 @@ fn-spring-cloud-function - 2.3.1.RELEASE + 2.1.1.RELEASE From 11e30e469aeacdd3e4f392542013d732f4c04c85 Mon Sep 17 00:00:00 2001 From: Tom Coupland Date: Tue, 11 Aug 2020 19:36:04 +0100 Subject: [PATCH 182/310] Update SpringCloudFunctionInvoker.java --- .../springframework/function/SpringCloudFunctionInvoker.java | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/fn-spring-cloud-function/src/main/java/com/fnproject/springframework/function/SpringCloudFunctionInvoker.java b/fn-spring-cloud-function/src/main/java/com/fnproject/springframework/function/SpringCloudFunctionInvoker.java index 3519bc1e..ca39d908 100644 --- a/fn-spring-cloud-function/src/main/java/com/fnproject/springframework/function/SpringCloudFunctionInvoker.java +++ b/fn-spring-cloud-function/src/main/java/com/fnproject/springframework/function/SpringCloudFunctionInvoker.java @@ -4,6 +4,8 @@ import com.fnproject.fn.api.exception.FunctionInputHandlingException; import com.fnproject.fn.api.exception.FunctionOutputHandlingException; import com.fnproject.springframework.function.functions.SpringCloudMethod; + +import org.springframework.boot.WebApplicationType; import org.springframework.boot.builder.SpringApplicationBuilder; import org.springframework.context.ConfigurableApplicationContext; import reactor.core.publisher.Flux; @@ -37,7 +39,7 @@ public class SpringCloudFunctionInvoker implements FunctionInvoker, Closeable { */ public SpringCloudFunctionInvoker(Class configClass) { SpringApplicationBuilder builder = new SpringApplicationBuilder(configClass); - applicationContext = builder.web(false).run(); + applicationContext = builder.web(WebApplicationType.SERVLET).run(); loader = applicationContext.getAutowireCapableBeanFactory().createBean(SpringCloudFunctionLoader.class); loader.loadFunction(); } From 6c727b1b0da23e0c000f80bd2897175a31191e30 Mon Sep 17 00:00:00 2001 From: Tom Coupland Date: Tue, 11 Aug 2020 19:42:10 +0100 Subject: [PATCH 183/310] Update SpringCloudFunctionInvoker.java --- .../springframework/function/SpringCloudFunctionInvoker.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/fn-spring-cloud-function/src/main/java/com/fnproject/springframework/function/SpringCloudFunctionInvoker.java b/fn-spring-cloud-function/src/main/java/com/fnproject/springframework/function/SpringCloudFunctionInvoker.java index ca39d908..034cb068 100644 --- a/fn-spring-cloud-function/src/main/java/com/fnproject/springframework/function/SpringCloudFunctionInvoker.java +++ b/fn-spring-cloud-function/src/main/java/com/fnproject/springframework/function/SpringCloudFunctionInvoker.java @@ -39,7 +39,7 @@ public class SpringCloudFunctionInvoker implements FunctionInvoker, Closeable { */ public SpringCloudFunctionInvoker(Class configClass) { SpringApplicationBuilder builder = new SpringApplicationBuilder(configClass); - applicationContext = builder.web(WebApplicationType.SERVLET).run(); + applicationContext = builder.web(WebApplicationType.NONE.run(); loader = applicationContext.getAutowireCapableBeanFactory().createBean(SpringCloudFunctionLoader.class); loader.loadFunction(); } From ebe42477d1b855428837b569a8ceacda092073eb Mon Sep 17 00:00:00 2001 From: Tom Coupland Date: Tue, 11 Aug 2020 19:52:11 +0100 Subject: [PATCH 184/310] Update SpringCloudFunctionInvoker.java --- .../springframework/function/SpringCloudFunctionInvoker.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/fn-spring-cloud-function/src/main/java/com/fnproject/springframework/function/SpringCloudFunctionInvoker.java b/fn-spring-cloud-function/src/main/java/com/fnproject/springframework/function/SpringCloudFunctionInvoker.java index 034cb068..706fbd42 100644 --- a/fn-spring-cloud-function/src/main/java/com/fnproject/springframework/function/SpringCloudFunctionInvoker.java +++ b/fn-spring-cloud-function/src/main/java/com/fnproject/springframework/function/SpringCloudFunctionInvoker.java @@ -39,7 +39,7 @@ public class SpringCloudFunctionInvoker implements FunctionInvoker, Closeable { */ public SpringCloudFunctionInvoker(Class configClass) { SpringApplicationBuilder builder = new SpringApplicationBuilder(configClass); - applicationContext = builder.web(WebApplicationType.NONE.run(); + applicationContext = builder.web(WebApplicationType.NONE).run(); loader = applicationContext.getAutowireCapableBeanFactory().createBean(SpringCloudFunctionLoader.class); loader.loadFunction(); } From 61e597c5b9a8b1ed4e3ce11003776ed1e9145d60 Mon Sep 17 00:00:00 2001 From: CI Date: Tue, 11 Aug 2020 21:01:59 +0000 Subject: [PATCH 185/310] fn-java-fdk: post-1.0.110 version bump [skip ci] --- release.version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/release.version b/release.version index 9a8c8209..0983ece2 100644 --- a/release.version +++ b/release.version @@ -1 +1 @@ -1.0.110 +1.0.111 From 990a45619281c82855c218d79ed263e24f37b705 Mon Sep 17 00:00:00 2001 From: Isaac Lipszyc Date: Mon, 5 Oct 2020 10:49:37 +0100 Subject: [PATCH 186/310] Added copyright headers, added NOTICE.txt file, updated LICENSE.txt and updated THIRD_PARTY_LICENSES.txt Fixed typo in NOTICE.txt Added jackson databind notice to THIRD_PARTY_LICENSES.txt --- LICENSE | 2 +- NOTICE.txt | 23 + THIRD_PARTY_LICENSES.txt | 698 +++++++++++++++++- api/pom.xml | 18 + .../com/fnproject/fn/api/FnConfiguration.java | 16 + .../java/com/fnproject/fn/api/FnFeature.java | 16 + .../java/com/fnproject/fn/api/FnFeatures.java | 16 + .../com/fnproject/fn/api/FunctionInvoker.java | 16 + .../java/com/fnproject/fn/api/Headers.java | 16 + .../com/fnproject/fn/api/InputBinding.java | 16 + .../com/fnproject/fn/api/InputCoercion.java | 16 + .../java/com/fnproject/fn/api/InputEvent.java | 16 + .../fnproject/fn/api/InvocationContext.java | 16 + .../fnproject/fn/api/InvocationListener.java | 16 + .../com/fnproject/fn/api/MethodWrapper.java | 16 + .../com/fnproject/fn/api/OutputBinding.java | 16 + .../com/fnproject/fn/api/OutputCoercion.java | 16 + .../com/fnproject/fn/api/OutputEvent.java | 16 + .../com/fnproject/fn/api/QueryParameters.java | 16 + .../com/fnproject/fn/api/RuntimeContext.java | 16 + .../com/fnproject/fn/api/RuntimeFeature.java | 16 + .../com/fnproject/fn/api/TypeWrapper.java | 16 + .../FunctionConfigurationException.java | 16 + .../FunctionInputHandlingException.java | 16 + .../api/exception/FunctionLoadException.java | 16 + .../FunctionOutputHandlingException.java | 16 + .../api/httpgateway/HTTPGatewayContext.java | 16 + .../com/fnproject/fn/api/HeadersTest.java | 16 + build.sh | 15 + build_in_docker.sh | 16 + examples/async-thumbnails/func.yaml | 16 + examples/async-thumbnails/pom.xml | 18 + examples/async-thumbnails/run.sh | 16 + .../setup/resize128/Dockerfile | 16 + .../setup/resize128/func.yaml | 16 + .../setup/resize256/Dockerfile | 16 + .../setup/resize256/func.yaml | 16 + .../setup/resize512/Dockerfile | 16 + .../setup/resize512/func.yaml | 16 + examples/async-thumbnails/setup/setup.sh | 16 + .../fn/examples/ThumbnailsFunction.java | 16 + .../fn/examples/ThumbnailsFunctionTest.java | 16 + examples/gradle-build/Dockerfile | 16 + examples/gradle-build/build.gradle | 16 + examples/gradle-build/func.yaml | 16 + .../java/com/example/fn/HelloFunction.java | 16 + .../com/example/fn/HelloFunctionTest.java | 16 + examples/pom.xml | 18 + examples/qr-code/example.html | 18 + examples/qr-code/func.yaml | 16 + examples/qr-code/pom.xml | 18 + .../java/com/fnproject/fn/examples/QRGen.java | 16 + .../com/fnproject/fn/examples/QRGenTest.java | 16 + examples/regex-query/func.yaml | 16 + examples/regex-query/pom.xml | 18 + .../java/com/fnproject/fn/examples/Match.java | 16 + .../java/com/fnproject/fn/examples/Query.java | 16 + .../com/fnproject/fn/examples/RegexQuery.java | 16 + .../com/fnproject/fn/examples/Response.java | 16 + .../fn/examples/RegexQueryTests.java | 16 + examples/string-reverse/func.yaml | 16 + examples/string-reverse/pom.xml | 18 + .../java/com/example/fn/StringReverse.java | 16 + .../example/fn/testing/StringReverseTest.java | 16 + flow-api/pom.xml | 18 + .../java/com/fnproject/fn/api/flow/Flow.java | 16 + .../fn/api/flow/FlowCompletionException.java | 16 + .../com/fnproject/fn/api/flow/FlowFuture.java | 16 + .../java/com/fnproject/fn/api/flow/Flows.java | 16 + .../api/flow/FunctionInvocationException.java | 16 + .../flow/FunctionInvokeFailedException.java | 16 + .../fn/api/flow/FunctionTimeoutException.java | 16 + .../com/fnproject/fn/api/flow/HttpMethod.java | 16 + .../fnproject/fn/api/flow/HttpRequest.java | 16 + .../fnproject/fn/api/flow/HttpResponse.java | 16 + .../flow/InvalidStageResponseException.java | 16 + .../flow/LambdaSerializationException.java | 16 + .../fn/api/flow/PlatformException.java | 16 + .../flow/ResultSerializationException.java | 16 + .../api/flow/StageInvokeFailedException.java | 16 + .../fn/api/flow/StageLostException.java | 16 + .../fn/api/flow/StageTimeoutException.java | 16 + .../fn/api/flow/WrappedFunctionException.java | 16 + .../fnproject/fn/api/flow/package-info.java | 16 + .../com/fnproject/fn/api/flow/FlowsTest.java | 16 + flow-runtime/pom.xml | 18 + .../fnproject/fn/runtime/flow/APIModel.java | 16 + .../fn/runtime/flow/BlobResponse.java | 16 + .../fn/runtime/flow/BlobStoreClient.java | 16 + .../fn/runtime/flow/CodeLocation.java | 16 + .../fn/runtime/flow/CompleterClient.java | 16 + .../runtime/flow/CompleterClientFactory.java | 16 + .../fn/runtime/flow/CompletionId.java | 16 + .../fn/runtime/flow/DefaultHttpResponse.java | 16 + .../fn/runtime/flow/EntityReader.java | 16 + .../runtime/flow/FlowContinuationInvoker.java | 16 + .../fn/runtime/flow/FlowFeature.java | 16 + .../fn/runtime/flow/FlowFutureSource.java | 16 + .../com/fnproject/fn/runtime/flow/FlowId.java | 16 + .../fn/runtime/flow/FlowRuntimeGlobals.java | 16 + .../fnproject/fn/runtime/flow/HttpClient.java | 16 + .../fnproject/fn/runtime/flow/JsonInvoke.java | 16 + .../runtime/flow/RemoteBlobStoreClient.java | 16 + .../fnproject/fn/runtime/flow/RemoteFlow.java | 16 + .../fn/runtime/flow/RemoteFlowApiClient.java | 16 + .../flow/FlowsContinuationInvokerTest.java | 16 + .../runtime/flow/RemoteFlowApiClientTest.java | 16 + .../fn/runtime/flow/TestBlobStore.java | 16 + .../testing/flowtestfns/FnFlowsFunction.java | 16 + flow-testing/pom.xml | 18 + .../fn/testing/flow/FlowTesting.java | 16 + .../testing/flow/FnFunctionStubBuilder.java | 16 + .../fn/testing/flow/InMemCompleter.java | 16 + .../fn/testing/flow/ResultException.java | 16 + .../testing/flow/FnTestingRuleFlowsTest.java | 16 + .../fn/testing/flow/IntegrationTest.java | 16 + .../fn/testing/flow/MultipleEventsTest.java | 16 + .../fn/testing/flow/WhenCompleteTest.java | 16 + .../flowtestfns/ExerciseEverything.java | 16 + fn-spring-cloud-function/pom.xml | 18 + .../function/SimpleTypeWrapper.java | 16 + .../function/SpringCloudFunctionFeature.java | 16 + .../function/SpringCloudFunctionInvoker.java | 16 + .../function/SpringCloudFunctionLoader.java | 16 + .../SpringCloudFunctionNotFoundException.java | 16 + .../functions/SpringCloudConsumer.java | 16 + .../functions/SpringCloudFunction.java | 16 + .../function/functions/SpringCloudMethod.java | 16 + .../functions/SpringCloudSupplier.java | 16 + .../function/SimpleFunctionInspector.java | 16 + ...ngCloudFunctionInvokerIntegrationTest.java | 16 + .../SpringCloudFunctionInvokerTest.java | 16 + .../SpringCloudFunctionLoaderTest.java | 16 + .../function/testfns/EmptyFunctionConfig.java | 16 + .../function/testfns/FunctionConfig.java | 16 + images/build-native/Dockerfile | 16 + images/build-native/Dockerfile-jdk11 | 16 + images/build-native/docker-build.sh | 16 + images/build/Dockerfile | 16 + images/build/Dockerfile-jdk11 | 16 + images/build/cache-deps.sh | 16 + images/build/docker-build.sh | 16 + images/build/pom.xml | 18 + .../java/com/example/fn/HelloFunction.java | 16 + .../com/example/fn/HelloFunctionTest.java | 16 + images/init-native/Dockerfile | 16 + images/init-native/Dockerfile-init-image | 16 + images/init-native/docker-build.sh | 16 + images/init-native/func.init.yaml | 16 + images/init-native/pom.xml | 18 + .../java/com/example/fn/HelloFunction.java | 16 + .../com/example/fn/HelloFunctionTest.java | 16 + images/runtime/Dockerfile | 16 + images/runtime/Dockerfile-jre11 | 16 + infra/provision/Jenkinsfile | 16 + .../completer-integration-environment.yaml | 16 + infra/provision/create-k8s-entities.sh | 16 + infra/provision/delete-k8s-entities.sh | 16 + infra/provision/registry.yaml | 16 + infra/provision/validate-functions-files.sh | 16 + infra/update/functions/Jenkinsfile | 16 + .../funcs/flowAllFeatures/func.yaml | 16 + .../funcs/flowAllFeatures/pom.xml | 18 + .../fn/integration/ExerciseEverything.java | 16 + .../com/fnproject/fn/integration/Test.java | 16 + integration-tests/funcs/flowBasic/func.yaml | 16 + integration-tests/funcs/flowBasic/pom.xml | 18 + .../integration/test_1/CompleterFunction.java | 16 + .../funcs/flowBasicJDK8/func.yaml | 16 + integration-tests/funcs/flowBasicJDK8/pom.xml | 18 + .../integration/test_1/CompleterFunction.java | 16 + .../funcs/flowExitHooks/func.yaml | 16 + integration-tests/funcs/flowExitHooks/pom.xml | 18 + .../integration/test_5/CompleterFunction.java | 16 + .../funcs/flowTimeouts/func.yaml | 16 + integration-tests/funcs/flowTimeouts/pom.xml | 18 + .../integration/test_6/CompleterFunction.java | 16 + .../funcs/helloFunc/func-proto.yaml | 16 + integration-tests/funcs/helloFunc/pom.xml | 18 + .../fn/integration/hello/HelloFunction.java | 16 + integration-tests/funcs/httpgwfunc/func.yaml | 16 + integration-tests/funcs/httpgwfunc/pom.xml | 18 + .../java/com/example/fn/TriggerFunction.java | 16 + .../com/example/fn/TriggerFunctionTest.java | 16 + integration-tests/funcs/simpleFunc/func.yaml | 16 + integration-tests/funcs/simpleFunc/pom.xml | 18 + .../fn/integration/test2/PlainFunction.java | 16 + .../integration/test2/PlainFunctionTest.java | 16 + integration-tests/pom.xml | 18 + integration-tests/run_tests_ci.sh | 16 + .../integrationtest/IntegrationTestRule.java | 16 + .../fn/integrationtest/FlowTest.java | 16 + .../fn/integrationtest/FunctionsTest.java | 16 + pom.xml | 18 + runtime/pom.xml | 18 + runtime/smith.yaml | 16 + runtime/src/main/c/Dockerfile-buildimage | 16 + runtime/src/main/c/buildit.sh | 16 + runtime/src/main/c/rebuild_so.sh | 16 +- runtime/src/main/c/unix_socket.c | 16 + .../com/fnproject/fn/runtime/Version.java | 16 + .../fn/runtime/DefaultMethodWrapper.java | 16 + .../com/fnproject/fn/runtime/EntryPoint.java | 16 + .../com/fnproject/fn/runtime/EventCodec.java | 16 + .../fn/runtime/FunctionConfigurer.java | 16 + .../runtime/FunctionInvocationCallback.java | 16 + .../fn/runtime/FunctionInvocationContext.java | 16 + .../fnproject/fn/runtime/FunctionLoader.java | 16 + .../fn/runtime/FunctionRuntimeContext.java | 16 + .../fnproject/fn/runtime/HTTPStreamCodec.java | 16 + .../fn/runtime/MethodFunctionInvoker.java | 16 + .../fn/runtime/MethodTypeWrapper.java | 16 + .../fn/runtime/PrimitiveTypeResolver.java | 16 + .../fn/runtime/ReadOnceInputEvent.java | 16 + .../runtime/coercion/ByteArrayCoercion.java | 16 + .../fn/runtime/coercion/ContextCoercion.java | 16 + .../runtime/coercion/InputEventCoercion.java | 16 + .../runtime/coercion/OutputEventCoercion.java | 16 + .../fn/runtime/coercion/StringCoercion.java | 16 + .../fn/runtime/coercion/VoidCoercion.java | 16 + .../coercion/jackson/JacksonCoercion.java | 16 + .../FunctionClassInstantiationException.java | 16 + .../exception/FunctionIOException.java | 16 + .../FunctionInitializationException.java | 16 + .../InternalFunctionInvocationException.java | 16 + .../exception/InvalidEntryPointException.java | 16 + .../InvalidFunctionDefinitionException.java | 16 + .../PlatformCommunicationException.java | 16 + .../FunctionHTTPGatewayContext.java | 16 + .../httpgateway/QueryParametersImpl.java | 16 + .../httpgateway/QueryParametersParser.java | 16 + .../fn/runtime/ntv/UnixServerSocket.java | 16 + .../fnproject/fn/runtime/ntv/UnixSocket.java | 16 + .../fn/runtime/ntv/UnixSocketException.java | 16 + .../fn/runtime/ntv/UnixSocketNative.java | 16 + .../fn/runtime/ConfigurationMethodsTest.java | 16 + .../fnproject/fn/runtime/DataBindingTest.java | 16 + .../fn/runtime/EndToEndInvokeTest.java | 16 + .../fn/runtime/ErrorMessagesTest.java | 16 + .../fnproject/fn/runtime/FnTestHarness.java | 16 + .../fn/runtime/FunctionConstructionTest.java | 16 + .../fn/runtime/HTTPStreamCodecTest.java | 16 + .../fnproject/fn/runtime/HeaderBuilder.java | 16 + .../fn/runtime/JacksonCoercionTest.java | 16 + .../fn/runtime/MethodWrapperTests.java | 16 + .../fn/runtime/QueryParametersParserTest.java | 16 + .../FunctionHTTPGatewayContextTest.java | 16 + .../fn/runtime/ntv/UnixSocketNativeTest.java | 16 + .../fn/runtime/ntv/UnixSocketTest.java | 16 + .../fnproject/fn/runtime/testfns/Animal.java | 16 + .../testfns/BadTestFnDuplicateMethods.java | 16 + .../CustomDataBindingFnInputOutput.java | 16 + .../CustomDataBindingFnWithAnnotation.java | 16 + ...mDataBindingFnWithAnnotationAndConfig.java | 16 + .../CustomDataBindingFnWithConfig.java | 16 + .../CustomDataBindingFnWithDudCoercion.java | 16 + ...tomDataBindingFnWithMultipleCoercions.java | 16 + ...ustomDataBindingFnWithNoUserCoercions.java | 16 + ...stomOutputDataBindingFnWithAnnotation.java | 16 + .../CustomOutputDataBindingFnWithConfig.java | 16 + ...tomOutputDataBindingFnWithDudCoercion.java | 16 + ...putDataBindingFnWithMultipleCoercions.java | 16 + ...utputDataBindingFnWithNoUserCoercions.java | 16 + .../fn/runtime/testfns/ErrorMessages.java | 16 + .../fnproject/fn/runtime/testfns/TestFn.java | 16 + .../runtime/testfns/TestFnConstructors.java | 16 + .../TestFnWithConfigurationMethods.java | 16 + .../testfns/coercions/DudCoercion.java | 16 + .../coercions/StringReversalCoercion.java | 16 + .../coercions/StringUpperCaseCoercion.java | 16 + .../fn/StacktraceFilteringTestFunctions.java | 16 + settings-deploy.xml | 18 + testing-core/pom.xml | 18 + .../fnproject/fn/testing/FnEventBuilder.java | 16 + .../fn/testing/FnHttpEventBuilder.java | 16 + .../com/fnproject/fn/testing/FnResult.java | 16 + .../fn/testing/FnTestingClassLoader.java | 16 + .../fnproject/fn/testing/FunctionError.java | 16 + .../fnproject/fn/testing/HeaderWriter.java | 16 + .../fnproject/fn/testing/PlatformError.java | 16 + testing-junit4/pom.xml | 18 + .../fn/testing/FnEventBuilderJUnit4.java | 16 + .../fnproject/fn/testing/FnTestingRule.java | 16 + .../fn/testing/FnTestingRuleFeature.java | 16 + .../fn/testing/FnTestingRuleTest.java | 16 + testing/pom.xml | 18 + 286 files changed, 5303 insertions(+), 3 deletions(-) create mode 100644 NOTICE.txt diff --git a/LICENSE b/LICENSE index 97ee2c36..151b7eab 100644 --- a/LICENSE +++ b/LICENSE @@ -187,7 +187,7 @@ same "printed page" as the copyright notice for easier identification within third-party archives. - Copyright 2017 Oracle Corporation + Copyright {yyyy} {name of copyright owner} Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. diff --git a/NOTICE.txt b/NOTICE.txt new file mode 100644 index 00000000..4b371e6c --- /dev/null +++ b/NOTICE.txt @@ -0,0 +1,23 @@ + Fn Project + ============ + +Copyright (c) 2019, 2020 Oracle and/or its affiliates. All rights reserved. + +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. + +========================================================================== +Third Party Dependencies +========================================================================== + +This project includes or depends on code from third party projects. +Attributions are contained in THIRD_PARTY_LICENSES.txt \ No newline at end of file diff --git a/THIRD_PARTY_LICENSES.txt b/THIRD_PARTY_LICENSES.txt index 17e271cb..12003c06 100644 --- a/THIRD_PARTY_LICENSES.txt +++ b/THIRD_PARTY_LICENSES.txt @@ -1,3 +1,20 @@ +Third Party Attributions + +The following software (or subsets of the software) are dependencies +of this product. They are identified by the Fn Project Java FDK module(s) that use +them. + +The first section ("Third Party Runtime Dependencies") contains dependencies +that might be used at runtime by an Fn Project Java FDK application. + +The second section ("Third Party Attributions for Examples, Tests, Builds, etc") +contains dependencies that are used in examples and to test and build Fn Project Java FDK. +They are likely not needed at runtime by an Fn Project Java FDK application. + +=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-= +Third Party Runtime Dependencies +=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-= + oci-java-sdk is dual-licensed to you under the Universal Permissive License (UPL) 1.0 or Apache License 2.0. See below for license terms. You may choose either license. Copyright (c) 2016, 2018, Oracle and/or its affiliates. All rights reserved. License: Copies of the Apache License V2 and the Universal Permissive License 1.0 are included at the end of this file. @@ -52,15 +69,141 @@ Copyright (c) 2019 Tatu Saloranta License: Apache License 2.0, a copy of the license is included at the end of this file. +NOTICE FILE: +=============== +# Jackson JSON processor + +Jackson is a high-performance, Free/Open Source JSON processing library. +It was originally written by Tatu Saloranta (tatu.saloranta@iki.fi), and has +been in development since 2007. +It is currently developed by a community of developers, as well as supported +commercially by FasterXML.com. + +## Licensing + +Jackson core and extension components may be licensed under different licenses. +To find the details that apply to this artifact see the accompanying LICENSE file. +For more information, including possible other licensing options, contact +FasterXML.com (http://fasterxml.com). + +## Credits + +A list of contributors may be found from CREDITS file, which is included +in some artifacts (usually source distributions); but is always available +from the source code management (SCM) system project uses. + -------------------------------------------------------------------------------- Typetools Copyright 2010-2019 Jonathan Halterman and friends. Released under the Apache 2.0 license. License: Apache License 2.0, a copy of the license is included at the end of this file. +=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-= +Third Party Attributions for Examples, Tests, Builds, etc + +The following software (or subsets of the software) is used when building the +Fn Project Java FDK, or in the examples and tests. They are generally not required by +users of the Fn Project Java FDK and not required during runtime. +=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-= + +Mockito Core +Copyright (c) 2007 Mockito contributors +The MIT License + +License: The MIT License, a copy of the license is included at the end of this file. + +................................................................................ + +Fourth Party Dependencies + +Byte Buddy (without dependencies) +Copyright 2014 - 2020 Rafael Winterhalter +Apache License Version 2.0 + + +Byte Buddy Java agent +Copyright 2014 - 2020 Rafael Winterhalter +Apache License Version 2.0 + +Objenesis +Copyright 2006-2020 the original author or authors. +Apache License Version 2.0 + +License: Apache License 2.0, a copy of the license is included at the end of this file. + +-------------------------------------------------------------------------------- + +AssertJ Core + +Copyright 2012-2020 the original author or authors. +Apache License Version 2.0 + +License: Apache License 2.0, a copy of the license is included at the end of this file. + +................................................................................ + +Fourth Party Dependencies + +Byte Buddy (without dependencies) +Copyright 2014 - 2020 Rafael Winterhalter +Apache License Version 2.0 + +Byte Buddy Java agent +Copyright 2014 - 2020 Rafael Winterhalter +Apache License Version 2.0 + +opentest4j +Copyright 2015-2018 the original author or authors. +Apache License Version 2.0 + +License: Apache License 2.0, a copy of the license is included at the end of this file. + + +Hamcrest +Copyright (c) 2000-2015 www.hamcrest.org +BSD License + +License: BSD License, a copy of the license is included at the end of this file. + + +JUnit 4 +Copyright (c) JUnit. All Rights Reserved. +Eclipse Public License - v 1.0 +THE ACCOMPANYING PROGRAM IS PROVIDED UNDER THE +TERMS OF THIS ECLIPSE PUBLIC LICENSE ("AGREEMENT"). ANY USE, REPRODUCTION OR +DISTRIBUTION OF THE PROGRAM CONSTITUTES RECIPIENT'S ACCEPTANCE OF THIS +AGREEMENT. + +License: Eclipse Public License - v 1.0, a copy of the license is included at the end of this file. + + +JUnit Jupiter API +Copyright 2015-2020 the original author or authors. +Eclipse Public License - v 2.0 + +License: Eclipse Public License - v 2.0, a copy of the license is included at the end of this file. + -------------------------------------------------------------------------------- +JUnit 4 +Copyright (c) JUnit. All Rights Reserved. +Eclipse Public License - v 1.0 +THE ACCOMPANYING PROGRAM IS PROVIDED UNDER THE +TERMS OF THIS ECLIPSE PUBLIC LICENSE ("AGREEMENT"). ANY USE, REPRODUCTION OR +DISTRIBUTION OF THE PROGRAM CONSTITUTES RECIPIENT'S ACCEPTANCE OF THIS +AGREEMENT. + +License: Eclipse Public License - v 1.0, a copy of the license is included at the end of this file. + +................................................................................ + +Fourth Party Dependencies + +Hamcrest +Copyright (c) 2000-2015 www.hamcrest.org +BSD License +License: BSD License, a copy of the license is included at the end of this file. ================================================================================ Apache License @@ -251,7 +394,7 @@ License: Apache License 2.0, a copy of the license is included at the end of thi same "printed page" as the copyright notice for easier identification within third-party archives. - Copyright 2017 Oracle Corporation + Copyright {yyyy} {name of copyright owner} Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. @@ -301,3 +444,556 @@ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +================================================================================ +The MIT License + +Copyright (c) + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. + +================================================================================ +BSD License + +Copyright (c) +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + +Redistributions of source code must retain the above copyright notice, this list of +conditions and the following disclaimer. Redistributions in binary form must reproduce +the above copyright notice, this list of conditions and the following disclaimer in +the documentation and/or other materials provided with the distribution. + +Neither the name of Hamcrest nor the names of its contributors may be used to endorse +or promote products derived from this software without specific prior written +permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY +EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES +OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT +SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED +TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR +BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY +WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH +DAMAGE. + +================================================================================ +Common Public License Version 1.0 (CPL) +(NOTE: This license has been superseded by the Eclipse Public License) + +Eclipse Public License - v 1.0 + +THE ACCOMPANYING PROGRAM IS PROVIDED UNDER THE TERMS OF THIS COMMON PUBLIC +LICENSE ("AGREEMENT"). ANY USE, REPRODUCTION OR DISTRIBUTION OF THE PROGRAM +CONSTITUTES RECIPIENT'S ACCEPTANCE OF THIS AGREEMENT. + +1. DEFINITIONS + +"Contribution" means: + +a) in the case of the initial Contributor, the initial code and documentation +distributed under this Agreement, and + +b) in the case of each subsequent Contributor: + +i) changes to the Program, and + +ii) additions to the Program; + +where such changes and/or additions to the Program originate from and are +distributed by that particular Contributor. A Contribution 'originates' from +a Contributor if it was added to the Program by such Contributor itself or +anyone acting on such Contributor's behalf. Contributions do not include +additions to the Program which: (i) are separate modules of software +distributed in conjunction with the Program under their own license agreement, +and (ii) are not derivative works of the Program. + +"Contributor" means any person or entity that distributes the Program. + +"Licensed Patents " mean patent claims licensable by a Contributor which are +necessarily infringed by the use or sale of its Contribution alone or when +combined with the Program. + +"Program" means the Contributions distributed in accordance with this +Agreement. + +"Recipient" means anyone who receives the Program under this Agreement, +including all Contributors. + +2. GRANT OF RIGHTS + +a) Subject to the terms of this Agreement, each Contributor hereby grants +Recipient a non-exclusive, worldwide, royalty-free copyright license to +reproduce, prepare derivative works of, publicly display, publicly perform, +distribute and sublicense the Contribution of such Contributor, if any, and +such derivative works, in source code and object code form. + +b) Subject to the terms of this Agreement, each Contributor hereby grants +Recipient a non-exclusive, worldwide, royalty-free patent license under +Licensed Patents to make, use, sell, offer to sell, import and otherwise +transfer the Contribution of such Contributor, if any, in source code and +object code form. This patent license shall apply to the combination of the +Contribution and the Program if, at the time the Contribution is added by the +Contributor, such addition of the Contribution causes such combination to be +covered by the Licensed Patents. The patent license shall not apply to any +other combinations which include the Contribution. No hardware per se is +licensed hereunder. + +c) Recipient understands that although each Contributor grants the licenses to +its Contributions set forth herein, no assurances are provided by any +Contributor that the Program does not infringe the patent or other intellectual +property rights of any other entity. Each Contributor disclaims any liability +to Recipient for claims brought by any other entity based on infringement of +intellectual property rights or otherwise. As a condition to exercising the +rights and licenses granted hereunder, each Recipient hereby assumes sole +responsibility to secure any other intellectual property rights needed, if any. +For example, if a third party patent license is required to allow Recipient to +distribute the Program, it is Recipient's responsibility to acquire that +license before distributing the Program. + +d) Each Contributor represents that to its knowledge it has sufficient +copyright rights in its Contribution, if any, to grant the copyright license +set forth in this Agreement. + +3. REQUIREMENTS + +A Contributor may choose to distribute the Program in object code form under +its own license agreement, provided that: + +a) it complies with the terms and conditions of this Agreement; and + +b) its license agreement: + +i) effectively disclaims on behalf of all Contributors all warranties and +conditions, express and implied, including warranties or conditions of title +and non-infringement, and implied warranties or conditions of merchantability +and fitness for a particular purpose; + +ii) effectively excludes on behalf of all Contributors all liability for +damages, including direct, indirect, special, incidental and consequential +damages, such as lost profits; + +iii) states that any provisions which differ from this Agreement are offered by +that Contributor alone and not by any other party; and + +iv) states that source code for the Program is available from such Contributor, +and informs licensees how to obtain it in a reasonable manner on or through a +medium customarily used for software exchange. + +When the Program is made available in source code form: + +a) it must be made available under this Agreement; and + +b) a copy of this Agreement must be included with each copy of the Program. + +Contributors may not remove or alter any copyright notices contained within the +Program. + +Each Contributor must identify itself as the originator of its Contribution, if +any, in a manner that reasonably allows subsequent Recipients to identify the +originator of the Contribution. + +4. COMMERCIAL DISTRIBUTION + +Commercial distributors of software may accept certain responsibilities with +respect to end users, business partners and the like. While this license is +intended to facilitate the commercial use of the Program, the Contributor who +includes the Program in a commercial product offering should do so in a manner +which does not create potential liability for other Contributors. Therefore, if +a Contributor includes the Program in a commercial product offering, such +Contributor ("Commercial Contributor") hereby agrees to defend and indemnify +every other Contributor ("Indemnified Contributor") against any losses, damages +and costs (collectively "Losses") arising from claims, lawsuits and other legal +actions brought by a third party against the Indemnified Contributor to the +extent caused by the acts or omissions of such Commercial Contributor in +connection with its distribution of the Program in a commercial product +offering. The obligations in this section do not apply to any claims or Losses +relating to any actual or alleged intellectual property infringement. In order +to qualify, an Indemnified Contributor must: a) promptly notify the Commercial +Contributor in writing of such claim, and b) allow the Commercial Contributor +to control, and cooperate with the Commercial Contributor in, the defense and +any related settlement negotiations. The Indemnified Contributor may +participate in any such claim at its own expense. + +For example, a Contributor might include the Program in a commercial product +offering, Product X. That Contributor is then a Commercial Contributor. If that +Commercial Contributor then makes performance claims, or offers warranties +related to Product X, those performance claims and warranties are such +Commercial Contributor's responsibility alone. Under this section, the +Commercial Contributor would have to defend claims against the other +Contributors related to those performance claims and warranties, and if a court +requires any other Contributor to pay any damages as a result, the Commercial +Contributor must pay those damages. + +5. NO WARRANTY + +EXCEPT AS EXPRESSLY SET FORTH IN THIS AGREEMENT, THE PROGRAM IS PROVIDED ON AN +"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, EITHER EXPRESS OR +IMPLIED INCLUDING, WITHOUT LIMITATION, ANY WARRANTIES OR CONDITIONS OF TITLE, +NON-INFRINGEMENT, MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. Each +Recipient is solely responsible for determining the appropriateness of using +and distributing the Program and assumes all risks associated with its +exercise of rights under this Agreement, including but not limited to the +risks and costs of program errors, compliance with applicable laws, damage to +or loss of data, programs or equipment, and unavailability or interruption of +operations. + +6. DISCLAIMER OF LIABILITY + +EXCEPT AS EXPRESSLY SET FORTH IN THIS AGREEMENT, NEITHER RECIPIENT NOR ANY +CONTRIBUTORS SHALL HAVE ANY LIABILITY FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING WITHOUT LIMITATION +LOST PROFITS), HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING +IN ANY WAY OUT OF THE USE OR DISTRIBUTION OF THE PROGRAM OR THE EXERCISE OF ANY +RIGHTS GRANTED HEREUNDER, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. + +7. GENERAL + +If any provision of this Agreement is invalid or unenforceable under applicable +law, it shall not affect the validity or enforceability of the remainder of the +terms of this Agreement, and without further action by the parties hereto, such +provision shall be reformed to the minimum extent necessary to make such +provision valid and enforceable. + +If Recipient institutes patent litigation against a Contributor with respect to +a patent applicable to software (including a cross-claim or counterclaim in a +lawsuit), then any patent licenses granted by that Contributor to such +Recipient under this Agreement shall terminate as of the date such litigation +is filed. In addition, if Recipient institutes patent litigation against any +entity (including a cross-claim or counterclaim in a lawsuit) alleging that the +Program itself (excluding combinations of the Program with other software or +hardware) infringes such Recipient's patent(s), then such Recipient's rights +granted under Section 2(b) shall terminate as of the date such litigation is +filed. + +All Recipient's rights under this Agreement shall terminate if it fails to +comply with any of the material terms or conditions of this Agreement and does +not cure such failure in a reasonable period of time after becoming aware of +such noncompliance. If all Recipient's rights under this Agreement terminate, +Recipient agrees to cease use and distribution of the Program as soon as +reasonably practicable. However, Recipient's obligations under this Agreement +and any licenses granted by Recipient relating to the Program shall continue +and survive. + +Everyone is permitted to copy and distribute copies of this Agreement, but in +order to avoid inconsistency the Agreement is copyrighted and may only be +modified in the following manner. The Agreement Steward reserves the right to +publish new versions (including revisions) of this Agreement from time to time. +No one other than the Agreement Steward has the right to modify this Agreement. +IBM is the initial Agreement Steward. IBM may assign the responsibility to +serve as the Agreement Steward to a suitable separate entity. Each new version +of the Agreement will be given a distinguishing version number. The Program +(including Contributions) may always be distributed subject to the version of +the Agreement under which it was received. In addition, after a new version of +the Agreement is published, Contributor may elect to distribute the Program +(including its Contributions) under the new version. Except as expressly stated +in Sections 2(a) and 2(b) above, Recipient receives no rights or licenses to +the intellectual property of any Contributor under this Agreement, whether +expressly, by implication, estoppel or otherwise. All rights in the Program not +expressly granted under this Agreement are reserved. + +This Agreement is governed by the laws of the State of New York and the +intellectual property laws of the United States of America. No party to this +Agreement will bring a legal action under this Agreement more than one year +after the cause of action arose. Each party waives its rights to a jury trial +in any resulting litigation. + +================================================================================ +Eclipse Public License - v 2.0 + + THE ACCOMPANYING PROGRAM IS PROVIDED UNDER THE TERMS OF THIS ECLIPSE + PUBLIC LICENSE ("AGREEMENT"). ANY USE, REPRODUCTION OR DISTRIBUTION + OF THE PROGRAM CONSTITUTES RECIPIENT'S ACCEPTANCE OF THIS AGREEMENT. + +1. DEFINITIONS + +"Contribution" means: + + a) in the case of the initial Contributor, the initial content + Distributed under this Agreement, and + + b) in the case of each subsequent Contributor: + i) changes to the Program, and + ii) additions to the Program; + where such changes and/or additions to the Program originate from + and are Distributed by that particular Contributor. A Contribution + "originates" from a Contributor if it was added to the Program by + such Contributor itself or anyone acting on such Contributor's behalf. + Contributions do not include changes or additions to the Program that + are not Modified Works. + +"Contributor" means any person or entity that Distributes the Program. + +"Licensed Patents" mean patent claims licensable by a Contributor which +are necessarily infringed by the use or sale of its Contribution alone +or when combined with the Program. + +"Program" means the Contributions Distributed in accordance with this +Agreement. + +"Recipient" means anyone who receives the Program under this Agreement +or any Secondary License (as applicable), including Contributors. + +"Derivative Works" shall mean any work, whether in Source Code or other +form, that is based on (or derived from) the Program and for which the +editorial revisions, annotations, elaborations, or other modifications +represent, as a whole, an original work of authorship. + +"Modified Works" shall mean any work in Source Code or other form that +results from an addition to, deletion from, or modification of the +contents of the Program, including, for purposes of clarity any new file +in Source Code form that contains any contents of the Program. Modified +Works shall not include works that contain only declarations, +interfaces, types, classes, structures, or files of the Program solely +in each case in order to link to, bind by name, or subclass the Program +or Modified Works thereof. + +"Distribute" means the acts of a) distributing or b) making available +in any manner that enables the transfer of a copy. + +"Source Code" means the form of a Program preferred for making +modifications, including but not limited to software source code, +documentation source, and configuration files. + +"Secondary License" means either the GNU General Public License, +Version 2.0, or any later versions of that license, including any +exceptions or additional permissions as identified by the initial +Contributor. + +2. GRANT OF RIGHTS + + a) Subject to the terms of this Agreement, each Contributor hereby + grants Recipient a non-exclusive, worldwide, royalty-free copyright + license to reproduce, prepare Derivative Works of, publicly display, + publicly perform, Distribute and sublicense the Contribution of such + Contributor, if any, and such Derivative Works. + + b) Subject to the terms of this Agreement, each Contributor hereby + grants Recipient a non-exclusive, worldwide, royalty-free patent + license under Licensed Patents to make, use, sell, offer to sell, + import and otherwise transfer the Contribution of such Contributor, + if any, in Source Code or other form. This patent license shall + apply to the combination of the Contribution and the Program if, at + the time the Contribution is added by the Contributor, such addition + of the Contribution causes such combination to be covered by the + Licensed Patents. The patent license shall not apply to any other + combinations which include the Contribution. No hardware per se is + licensed hereunder. + + c) Recipient understands that although each Contributor grants the + licenses to its Contributions set forth herein, no assurances are + provided by any Contributor that the Program does not infringe the + patent or other intellectual property rights of any other entity. + Each Contributor disclaims any liability to Recipient for claims + brought by any other entity based on infringement of intellectual + property rights or otherwise. As a condition to exercising the + rights and licenses granted hereunder, each Recipient hereby + assumes sole responsibility to secure any other intellectual + property rights needed, if any. For example, if a third party + patent license is required to allow Recipient to Distribute the + Program, it is Recipient's responsibility to acquire that license + before distributing the Program. + + d) Each Contributor represents that to its knowledge it has + sufficient copyright rights in its Contribution, if any, to grant + the copyright license set forth in this Agreement. + + e) Notwithstanding the terms of any Secondary License, no + Contributor makes additional grants to any Recipient (other than + those set forth in this Agreement) as a result of such Recipient's + receipt of the Program under the terms of a Secondary License + (if permitted under the terms of Section 3). + +3. REQUIREMENTS + +3.1 If a Contributor Distributes the Program in any form, then: + + a) the Program must also be made available as Source Code, in + accordance with section 3.2, and the Contributor must accompany + the Program with a statement that the Source Code for the Program + is available under this Agreement, and informs Recipients how to + obtain it in a reasonable manner on or through a medium customarily + used for software exchange; and + + b) the Contributor may Distribute the Program under a license + different than this Agreement, provided that such license: + i) effectively disclaims on behalf of all other Contributors all + warranties and conditions, express and implied, including + warranties or conditions of title and non-infringement, and + implied warranties or conditions of merchantability and fitness + for a particular purpose; + + ii) effectively excludes on behalf of all other Contributors all + liability for damages, including direct, indirect, special, + incidental and consequential damages, such as lost profits; + + iii) does not attempt to limit or alter the recipients' rights + in the Source Code under section 3.2; and + + iv) requires any subsequent distribution of the Program by any + party to be under a license that satisfies the requirements + of this section 3. + +3.2 When the Program is Distributed as Source Code: + + a) it must be made available under this Agreement, or if the + Program (i) is combined with other material in a separate file or + files made available under a Secondary License, and (ii) the initial + Contributor attached to the Source Code the notice described in + Exhibit A of this Agreement, then the Program may be made available + under the terms of such Secondary Licenses, and + + b) a copy of this Agreement must be included with each copy of + the Program. + +3.3 Contributors may not remove or alter any copyright, patent, +trademark, attribution notices, disclaimers of warranty, or limitations +of liability ("notices") contained within the Program from any copy of +the Program which they Distribute, provided that Contributors may add +their own appropriate notices. + +4. COMMERCIAL DISTRIBUTION + +Commercial distributors of software may accept certain responsibilities +with respect to end users, business partners and the like. While this +license is intended to facilitate the commercial use of the Program, +the Contributor who includes the Program in a commercial product +offering should do so in a manner which does not create potential +liability for other Contributors. Therefore, if a Contributor includes +the Program in a commercial product offering, such Contributor +("Commercial Contributor") hereby agrees to defend and indemnify every +other Contributor ("Indemnified Contributor") against any losses, +damages and costs (collectively "Losses") arising from claims, lawsuits +and other legal actions brought by a third party against the Indemnified +Contributor to the extent caused by the acts or omissions of such +Commercial Contributor in connection with its distribution of the Program +in a commercial product offering. The obligations in this section do not +apply to any claims or Losses relating to any actual or alleged +intellectual property infringement. In order to qualify, an Indemnified +Contributor must: a) promptly notify the Commercial Contributor in +writing of such claim, and b) allow the Commercial Contributor to control, +and cooperate with the Commercial Contributor in, the defense and any +related settlement negotiations. The Indemnified Contributor may +participate in any such claim at its own expense. + +For example, a Contributor might include the Program in a commercial +product offering, Product X. That Contributor is then a Commercial +Contributor. If that Commercial Contributor then makes performance +claims, or offers warranties related to Product X, those performance +claims and warranties are such Commercial Contributor's responsibility +alone. Under this section, the Commercial Contributor would have to +defend claims against the other Contributors related to those performance +claims and warranties, and if a court requires any other Contributor to +pay any damages as a result, the Commercial Contributor must pay +those damages. + +5. NO WARRANTY + +EXCEPT AS EXPRESSLY SET FORTH IN THIS AGREEMENT, AND TO THE EXTENT +PERMITTED BY APPLICABLE LAW, THE PROGRAM IS PROVIDED ON AN "AS IS" +BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, EITHER EXPRESS OR +IMPLIED INCLUDING, WITHOUT LIMITATION, ANY WARRANTIES OR CONDITIONS OF +TITLE, NON-INFRINGEMENT, MERCHANTABILITY OR FITNESS FOR A PARTICULAR +PURPOSE. Each Recipient is solely responsible for determining the +appropriateness of using and distributing the Program and assumes all +risks associated with its exercise of rights under this Agreement, +including but not limited to the risks and costs of program errors, +compliance with applicable laws, damage to or loss of data, programs +or equipment, and unavailability or interruption of operations. + +6. DISCLAIMER OF LIABILITY + +EXCEPT AS EXPRESSLY SET FORTH IN THIS AGREEMENT, AND TO THE EXTENT +PERMITTED BY APPLICABLE LAW, NEITHER RECIPIENT NOR ANY CONTRIBUTORS +SHALL HAVE ANY LIABILITY FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, +EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING WITHOUT LIMITATION LOST +PROFITS), HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +ARISING IN ANY WAY OUT OF THE USE OR DISTRIBUTION OF THE PROGRAM OR THE +EXERCISE OF ANY RIGHTS GRANTED HEREUNDER, EVEN IF ADVISED OF THE +POSSIBILITY OF SUCH DAMAGES. + +7. GENERAL + +If any provision of this Agreement is invalid or unenforceable under +applicable law, it shall not affect the validity or enforceability of +the remainder of the terms of this Agreement, and without further +action by the parties hereto, such provision shall be reformed to the +minimum extent necessary to make such provision valid and enforceable. + +If Recipient institutes patent litigation against any entity +(including a cross-claim or counterclaim in a lawsuit) alleging that the +Program itself (excluding combinations of the Program with other software +or hardware) infringes such Recipient's patent(s), then such Recipient's +rights granted under Section 2(b) shall terminate as of the date such +litigation is filed. + +All Recipient's rights under this Agreement shall terminate if it +fails to comply with any of the material terms or conditions of this +Agreement and does not cure such failure in a reasonable period of +time after becoming aware of such noncompliance. If all Recipient's +rights under this Agreement terminate, Recipient agrees to cease use +and distribution of the Program as soon as reasonably practicable. +However, Recipient's obligations under this Agreement and any licenses +granted by Recipient relating to the Program shall continue and survive. + +Everyone is permitted to copy and distribute copies of this Agreement, +but in order to avoid inconsistency the Agreement is copyrighted and +may only be modified in the following manner. The Agreement Steward +reserves the right to publish new versions (including revisions) of +this Agreement from time to time. No one other than the Agreement +Steward has the right to modify this Agreement. The Eclipse Foundation +is the initial Agreement Steward. The Eclipse Foundation may assign the +responsibility to serve as the Agreement Steward to a suitable separate +entity. Each new version of the Agreement will be given a distinguishing +version number. The Program (including Contributions) may always be +Distributed subject to the version of the Agreement under which it was +received. In addition, after a new version of the Agreement is published, +Contributor may elect to Distribute the Program (including its +Contributions) under the new version. + +Except as expressly stated in Sections 2(a) and 2(b) above, Recipient +receives no rights or licenses to the intellectual property of any +Contributor under this Agreement, whether expressly, by implication, +estoppel or otherwise. All rights in the Program not expressly granted +under this Agreement are reserved. Nothing in this Agreement is intended +to be enforceable by any entity that is not a Contributor or Recipient. +No third-party beneficiary rights are created under this Agreement. + +Exhibit A - Form of Secondary Licenses Notice + +"This Source Code may also be made available under the following +Secondary Licenses when the conditions for such availability set forth +in the Eclipse Public License, v. 2.0 are satisfied: {name license(s), +version(s), and exceptions or additional permissions here}." + + Simply including a copy of this Agreement, including this Exhibit A + is not sufficient to license the Source Code under Secondary Licenses. + + If it is not possible or desirable to put the notice in a particular + file, then You may include the notice in a location (such as a LICENSE + file in a relevant directory) where a recipient would be likely to + look for such a notice. + + You may add additional accurate notices of copyright ownership. diff --git a/api/pom.xml b/api/pom.xml index a7a27704..44ad20fa 100644 --- a/api/pom.xml +++ b/api/pom.xml @@ -1,4 +1,22 @@ + + diff --git a/api/src/main/java/com/fnproject/fn/api/FnConfiguration.java b/api/src/main/java/com/fnproject/fn/api/FnConfiguration.java index 62a70a13..52273461 100644 --- a/api/src/main/java/com/fnproject/fn/api/FnConfiguration.java +++ b/api/src/main/java/com/fnproject/fn/api/FnConfiguration.java @@ -1,3 +1,19 @@ +/* + * Copyright (c) 2019, 2020 Oracle and/or its affiliates. All rights reserved. + * + * 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. + */ + package com.fnproject.fn.api; import java.lang.annotation.ElementType; diff --git a/api/src/main/java/com/fnproject/fn/api/FnFeature.java b/api/src/main/java/com/fnproject/fn/api/FnFeature.java index 83f9dd77..6b9165be 100644 --- a/api/src/main/java/com/fnproject/fn/api/FnFeature.java +++ b/api/src/main/java/com/fnproject/fn/api/FnFeature.java @@ -1,3 +1,19 @@ +/* + * Copyright (c) 2019, 2020 Oracle and/or its affiliates. All rights reserved. + * + * 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. + */ + package com.fnproject.fn.api; import java.lang.annotation.*; diff --git a/api/src/main/java/com/fnproject/fn/api/FnFeatures.java b/api/src/main/java/com/fnproject/fn/api/FnFeatures.java index 3db2a4dc..edb021f0 100644 --- a/api/src/main/java/com/fnproject/fn/api/FnFeatures.java +++ b/api/src/main/java/com/fnproject/fn/api/FnFeatures.java @@ -1,3 +1,19 @@ +/* + * Copyright (c) 2019, 2020 Oracle and/or its affiliates. All rights reserved. + * + * 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. + */ + package com.fnproject.fn.api; import java.lang.annotation.ElementType; diff --git a/api/src/main/java/com/fnproject/fn/api/FunctionInvoker.java b/api/src/main/java/com/fnproject/fn/api/FunctionInvoker.java index 70b9fd5d..691e6a90 100644 --- a/api/src/main/java/com/fnproject/fn/api/FunctionInvoker.java +++ b/api/src/main/java/com/fnproject/fn/api/FunctionInvoker.java @@ -1,3 +1,19 @@ +/* + * Copyright (c) 2019, 2020 Oracle and/or its affiliates. All rights reserved. + * + * 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. + */ + package com.fnproject.fn.api; import java.util.Optional; diff --git a/api/src/main/java/com/fnproject/fn/api/Headers.java b/api/src/main/java/com/fnproject/fn/api/Headers.java index 7029e909..52618d2c 100644 --- a/api/src/main/java/com/fnproject/fn/api/Headers.java +++ b/api/src/main/java/com/fnproject/fn/api/Headers.java @@ -1,3 +1,19 @@ +/* + * Copyright (c) 2019, 2020 Oracle and/or its affiliates. All rights reserved. + * + * 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. + */ + package com.fnproject.fn.api; import java.io.Serializable; diff --git a/api/src/main/java/com/fnproject/fn/api/InputBinding.java b/api/src/main/java/com/fnproject/fn/api/InputBinding.java index ddb2b009..a884cf88 100644 --- a/api/src/main/java/com/fnproject/fn/api/InputBinding.java +++ b/api/src/main/java/com/fnproject/fn/api/InputBinding.java @@ -1,3 +1,19 @@ +/* + * Copyright (c) 2019, 2020 Oracle and/or its affiliates. All rights reserved. + * + * 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. + */ + package com.fnproject.fn.api; import java.lang.annotation.ElementType; diff --git a/api/src/main/java/com/fnproject/fn/api/InputCoercion.java b/api/src/main/java/com/fnproject/fn/api/InputCoercion.java index f8e6af06..a5559105 100644 --- a/api/src/main/java/com/fnproject/fn/api/InputCoercion.java +++ b/api/src/main/java/com/fnproject/fn/api/InputCoercion.java @@ -1,3 +1,19 @@ +/* + * Copyright (c) 2019, 2020 Oracle and/or its affiliates. All rights reserved. + * + * 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. + */ + package com.fnproject.fn.api; import java.util.Optional; diff --git a/api/src/main/java/com/fnproject/fn/api/InputEvent.java b/api/src/main/java/com/fnproject/fn/api/InputEvent.java index cda6cca3..ef4e840a 100644 --- a/api/src/main/java/com/fnproject/fn/api/InputEvent.java +++ b/api/src/main/java/com/fnproject/fn/api/InputEvent.java @@ -1,3 +1,19 @@ +/* + * Copyright (c) 2019, 2020 Oracle and/or its affiliates. All rights reserved. + * + * 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. + */ + package com.fnproject.fn.api; import java.io.Closeable; diff --git a/api/src/main/java/com/fnproject/fn/api/InvocationContext.java b/api/src/main/java/com/fnproject/fn/api/InvocationContext.java index 080e3bc6..245d582d 100644 --- a/api/src/main/java/com/fnproject/fn/api/InvocationContext.java +++ b/api/src/main/java/com/fnproject/fn/api/InvocationContext.java @@ -1,3 +1,19 @@ +/* + * Copyright (c) 2019, 2020 Oracle and/or its affiliates. All rights reserved. + * + * 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. + */ + package com.fnproject.fn.api; diff --git a/api/src/main/java/com/fnproject/fn/api/InvocationListener.java b/api/src/main/java/com/fnproject/fn/api/InvocationListener.java index 7c9d46fa..1e8b6b29 100644 --- a/api/src/main/java/com/fnproject/fn/api/InvocationListener.java +++ b/api/src/main/java/com/fnproject/fn/api/InvocationListener.java @@ -1,3 +1,19 @@ +/* + * Copyright (c) 2019, 2020 Oracle and/or its affiliates. All rights reserved. + * + * 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. + */ + package com.fnproject.fn.api; import java.util.EventListener; diff --git a/api/src/main/java/com/fnproject/fn/api/MethodWrapper.java b/api/src/main/java/com/fnproject/fn/api/MethodWrapper.java index 8ed0644f..655c28db 100644 --- a/api/src/main/java/com/fnproject/fn/api/MethodWrapper.java +++ b/api/src/main/java/com/fnproject/fn/api/MethodWrapper.java @@ -1,3 +1,19 @@ +/* + * Copyright (c) 2019, 2020 Oracle and/or its affiliates. All rights reserved. + * + * 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. + */ + package com.fnproject.fn.api; import java.lang.reflect.Method; diff --git a/api/src/main/java/com/fnproject/fn/api/OutputBinding.java b/api/src/main/java/com/fnproject/fn/api/OutputBinding.java index 1355e529..4bf05577 100644 --- a/api/src/main/java/com/fnproject/fn/api/OutputBinding.java +++ b/api/src/main/java/com/fnproject/fn/api/OutputBinding.java @@ -1,3 +1,19 @@ +/* + * Copyright (c) 2019, 2020 Oracle and/or its affiliates. All rights reserved. + * + * 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. + */ + package com.fnproject.fn.api; import java.lang.annotation.ElementType; diff --git a/api/src/main/java/com/fnproject/fn/api/OutputCoercion.java b/api/src/main/java/com/fnproject/fn/api/OutputCoercion.java index ac8e9ac4..44e3cc79 100644 --- a/api/src/main/java/com/fnproject/fn/api/OutputCoercion.java +++ b/api/src/main/java/com/fnproject/fn/api/OutputCoercion.java @@ -1,3 +1,19 @@ +/* + * Copyright (c) 2019, 2020 Oracle and/or its affiliates. All rights reserved. + * + * 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. + */ + package com.fnproject.fn.api; import java.util.Optional; diff --git a/api/src/main/java/com/fnproject/fn/api/OutputEvent.java b/api/src/main/java/com/fnproject/fn/api/OutputEvent.java index 0b93b68f..c6ab4143 100644 --- a/api/src/main/java/com/fnproject/fn/api/OutputEvent.java +++ b/api/src/main/java/com/fnproject/fn/api/OutputEvent.java @@ -1,3 +1,19 @@ +/* + * Copyright (c) 2019, 2020 Oracle and/or its affiliates. All rights reserved. + * + * 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. + */ + package com.fnproject.fn.api; diff --git a/api/src/main/java/com/fnproject/fn/api/QueryParameters.java b/api/src/main/java/com/fnproject/fn/api/QueryParameters.java index f0dacd05..0de6ca34 100644 --- a/api/src/main/java/com/fnproject/fn/api/QueryParameters.java +++ b/api/src/main/java/com/fnproject/fn/api/QueryParameters.java @@ -1,3 +1,19 @@ +/* + * Copyright (c) 2019, 2020 Oracle and/or its affiliates. All rights reserved. + * + * 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. + */ + package com.fnproject.fn.api; import java.util.List; diff --git a/api/src/main/java/com/fnproject/fn/api/RuntimeContext.java b/api/src/main/java/com/fnproject/fn/api/RuntimeContext.java index 08466cb7..de628f10 100644 --- a/api/src/main/java/com/fnproject/fn/api/RuntimeContext.java +++ b/api/src/main/java/com/fnproject/fn/api/RuntimeContext.java @@ -1,3 +1,19 @@ +/* + * Copyright (c) 2019, 2020 Oracle and/or its affiliates. All rights reserved. + * + * 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. + */ + package com.fnproject.fn.api; diff --git a/api/src/main/java/com/fnproject/fn/api/RuntimeFeature.java b/api/src/main/java/com/fnproject/fn/api/RuntimeFeature.java index 43365794..f57a3c1d 100644 --- a/api/src/main/java/com/fnproject/fn/api/RuntimeFeature.java +++ b/api/src/main/java/com/fnproject/fn/api/RuntimeFeature.java @@ -1,3 +1,19 @@ +/* + * Copyright (c) 2019, 2020 Oracle and/or its affiliates. All rights reserved. + * + * 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. + */ + package com.fnproject.fn.api; /** diff --git a/api/src/main/java/com/fnproject/fn/api/TypeWrapper.java b/api/src/main/java/com/fnproject/fn/api/TypeWrapper.java index d757c411..b693446c 100644 --- a/api/src/main/java/com/fnproject/fn/api/TypeWrapper.java +++ b/api/src/main/java/com/fnproject/fn/api/TypeWrapper.java @@ -1,3 +1,19 @@ +/* + * Copyright (c) 2019, 2020 Oracle and/or its affiliates. All rights reserved. + * + * 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. + */ + package com.fnproject.fn.api; /** diff --git a/api/src/main/java/com/fnproject/fn/api/exception/FunctionConfigurationException.java b/api/src/main/java/com/fnproject/fn/api/exception/FunctionConfigurationException.java index e8c85889..6cb90cf9 100644 --- a/api/src/main/java/com/fnproject/fn/api/exception/FunctionConfigurationException.java +++ b/api/src/main/java/com/fnproject/fn/api/exception/FunctionConfigurationException.java @@ -1,3 +1,19 @@ +/* + * Copyright (c) 2019, 2020 Oracle and/or its affiliates. All rights reserved. + * + * 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. + */ + package com.fnproject.fn.api.exception; /** diff --git a/api/src/main/java/com/fnproject/fn/api/exception/FunctionInputHandlingException.java b/api/src/main/java/com/fnproject/fn/api/exception/FunctionInputHandlingException.java index 9762e6c4..984e871c 100644 --- a/api/src/main/java/com/fnproject/fn/api/exception/FunctionInputHandlingException.java +++ b/api/src/main/java/com/fnproject/fn/api/exception/FunctionInputHandlingException.java @@ -1,3 +1,19 @@ +/* + * Copyright (c) 2019, 2020 Oracle and/or its affiliates. All rights reserved. + * + * 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. + */ + package com.fnproject.fn.api.exception; /** diff --git a/api/src/main/java/com/fnproject/fn/api/exception/FunctionLoadException.java b/api/src/main/java/com/fnproject/fn/api/exception/FunctionLoadException.java index 095875cc..c911db0e 100644 --- a/api/src/main/java/com/fnproject/fn/api/exception/FunctionLoadException.java +++ b/api/src/main/java/com/fnproject/fn/api/exception/FunctionLoadException.java @@ -1,3 +1,19 @@ +/* + * Copyright (c) 2019, 2020 Oracle and/or its affiliates. All rights reserved. + * + * 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. + */ + package com.fnproject.fn.api.exception; /** diff --git a/api/src/main/java/com/fnproject/fn/api/exception/FunctionOutputHandlingException.java b/api/src/main/java/com/fnproject/fn/api/exception/FunctionOutputHandlingException.java index 9467f8ae..587b4aa3 100644 --- a/api/src/main/java/com/fnproject/fn/api/exception/FunctionOutputHandlingException.java +++ b/api/src/main/java/com/fnproject/fn/api/exception/FunctionOutputHandlingException.java @@ -1,3 +1,19 @@ +/* + * Copyright (c) 2019, 2020 Oracle and/or its affiliates. All rights reserved. + * + * 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. + */ + package com.fnproject.fn.api.exception; /** diff --git a/api/src/main/java/com/fnproject/fn/api/httpgateway/HTTPGatewayContext.java b/api/src/main/java/com/fnproject/fn/api/httpgateway/HTTPGatewayContext.java index d97c0edb..fdbde96b 100644 --- a/api/src/main/java/com/fnproject/fn/api/httpgateway/HTTPGatewayContext.java +++ b/api/src/main/java/com/fnproject/fn/api/httpgateway/HTTPGatewayContext.java @@ -1,3 +1,19 @@ +/* + * Copyright (c) 2019, 2020 Oracle and/or its affiliates. All rights reserved. + * + * 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. + */ + package com.fnproject.fn.api.httpgateway; import com.fnproject.fn.api.Headers; diff --git a/api/src/test/java/com/fnproject/fn/api/HeadersTest.java b/api/src/test/java/com/fnproject/fn/api/HeadersTest.java index 946ed305..7143c34a 100644 --- a/api/src/test/java/com/fnproject/fn/api/HeadersTest.java +++ b/api/src/test/java/com/fnproject/fn/api/HeadersTest.java @@ -1,3 +1,19 @@ +/* + * Copyright (c) 2019, 2020 Oracle and/or its affiliates. All rights reserved. + * + * 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. + */ + package com.fnproject.fn.api; import org.junit.Test; diff --git a/build.sh b/build.sh index 019982f6..bf8e3083 100755 --- a/build.sh +++ b/build.sh @@ -1,4 +1,19 @@ #!/usr/bin/env bash +# +# Copyright (c) 2019, 2020 Oracle and/or its affiliates. All rights reserved. +# +# 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. +# set -e set -x diff --git a/build_in_docker.sh b/build_in_docker.sh index c9f5aee9..2081b9fc 100644 --- a/build_in_docker.sh +++ b/build_in_docker.sh @@ -1,2 +1,18 @@ #!/usr/bin/env bash +# +# Copyright (c) 2019, 2020 Oracle and/or its affiliates. All rights reserved. +# +# 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. +# + docker run --rm --name compile -v "$(pwd)":/usr/src/mymaven -w /usr/src/mymaven svenruppert/maven-3.5-jdk-08 mvn clean install diff --git a/examples/async-thumbnails/func.yaml b/examples/async-thumbnails/func.yaml index 7bd97826..1f1f0d05 100644 --- a/examples/async-thumbnails/func.yaml +++ b/examples/async-thumbnails/func.yaml @@ -1,3 +1,19 @@ +# +# Copyright (c) 2019, 2020 Oracle and/or its affiliates. All rights reserved. +# +# 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. +# + schema_version: 20180708 name: async-thumbnails version: 0.0.8 diff --git a/examples/async-thumbnails/pom.xml b/examples/async-thumbnails/pom.xml index b08f101d..043cbe17 100644 --- a/examples/async-thumbnails/pom.xml +++ b/examples/async-thumbnails/pom.xml @@ -1,4 +1,22 @@ + + diff --git a/examples/async-thumbnails/run.sh b/examples/async-thumbnails/run.sh index 68bd6574..9744fd5c 100755 --- a/examples/async-thumbnails/run.sh +++ b/examples/async-thumbnails/run.sh @@ -1,4 +1,20 @@ #!/bin/bash +# +# Copyright (c) 2019, 2020 Oracle and/or its affiliates. All rights reserved. +# +# 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. +# + set -e fn --verbose deploy --app myapp --local diff --git a/examples/async-thumbnails/setup/resize128/Dockerfile b/examples/async-thumbnails/setup/resize128/Dockerfile index 20f55eec..65442048 100644 --- a/examples/async-thumbnails/setup/resize128/Dockerfile +++ b/examples/async-thumbnails/setup/resize128/Dockerfile @@ -1,3 +1,19 @@ +# +# Copyright (c) 2019, 2020 Oracle and/or its affiliates. All rights reserved. +# +# 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. +# + FROM debian RUN apt-get update RUN apt-get install -y imagemagick diff --git a/examples/async-thumbnails/setup/resize128/func.yaml b/examples/async-thumbnails/setup/resize128/func.yaml index 27013369..4f6ea681 100644 --- a/examples/async-thumbnails/setup/resize128/func.yaml +++ b/examples/async-thumbnails/setup/resize128/func.yaml @@ -1,3 +1,19 @@ +# +# Copyright (c) 2019, 2020 Oracle and/or its affiliates. All rights reserved. +# +# 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. +# + schema_version: 20180708 name: resize128 version: 0.0.5 diff --git a/examples/async-thumbnails/setup/resize256/Dockerfile b/examples/async-thumbnails/setup/resize256/Dockerfile index 433e17e1..4cb095ff 100644 --- a/examples/async-thumbnails/setup/resize256/Dockerfile +++ b/examples/async-thumbnails/setup/resize256/Dockerfile @@ -1,3 +1,19 @@ +# +# Copyright (c) 2019, 2020 Oracle and/or its affiliates. All rights reserved. +# +# 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. +# + FROM debian RUN apt-get update RUN apt-get install -y imagemagick diff --git a/examples/async-thumbnails/setup/resize256/func.yaml b/examples/async-thumbnails/setup/resize256/func.yaml index cd5b4032..2e655c82 100644 --- a/examples/async-thumbnails/setup/resize256/func.yaml +++ b/examples/async-thumbnails/setup/resize256/func.yaml @@ -1,3 +1,19 @@ +# +# Copyright (c) 2019, 2020 Oracle and/or its affiliates. All rights reserved. +# +# 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. +# + schema_version: 20180708 name: resize256 version: 0.0.5 diff --git a/examples/async-thumbnails/setup/resize512/Dockerfile b/examples/async-thumbnails/setup/resize512/Dockerfile index 52a2b407..56469980 100644 --- a/examples/async-thumbnails/setup/resize512/Dockerfile +++ b/examples/async-thumbnails/setup/resize512/Dockerfile @@ -1,3 +1,19 @@ +# +# Copyright (c) 2019, 2020 Oracle and/or its affiliates. All rights reserved. +# +# 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. +# + FROM debian RUN apt-get update RUN apt-get install -y imagemagick diff --git a/examples/async-thumbnails/setup/resize512/func.yaml b/examples/async-thumbnails/setup/resize512/func.yaml index 82d9a844..bf9712ab 100644 --- a/examples/async-thumbnails/setup/resize512/func.yaml +++ b/examples/async-thumbnails/setup/resize512/func.yaml @@ -1,3 +1,19 @@ +# +# Copyright (c) 2019, 2020 Oracle and/or its affiliates. All rights reserved. +# +# 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. +# + schema_version: 20180708 name: resize512 version: 0.0.8 diff --git a/examples/async-thumbnails/setup/setup.sh b/examples/async-thumbnails/setup/setup.sh index 96c3e3a4..6902145e 100755 --- a/examples/async-thumbnails/setup/setup.sh +++ b/examples/async-thumbnails/setup/setup.sh @@ -1,4 +1,20 @@ #!/bin/bash +# +# Copyright (c) 2019, 2020 Oracle and/or its affiliates. All rights reserved. +# +# 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. +# + set -e SCRIPT_DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )" STORAGE_DIR="/tmp/example-storage-server-files" diff --git a/examples/async-thumbnails/src/main/java/com/fnproject/fn/examples/ThumbnailsFunction.java b/examples/async-thumbnails/src/main/java/com/fnproject/fn/examples/ThumbnailsFunction.java index 5f6c1dee..76a24521 100644 --- a/examples/async-thumbnails/src/main/java/com/fnproject/fn/examples/ThumbnailsFunction.java +++ b/examples/async-thumbnails/src/main/java/com/fnproject/fn/examples/ThumbnailsFunction.java @@ -1,3 +1,19 @@ +/* + * Copyright (c) 2019, 2020 Oracle and/or its affiliates. All rights reserved. + * + * 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. + */ + package com.fnproject.fn.examples; import com.fnproject.fn.api.FnFeature; diff --git a/examples/async-thumbnails/src/test/java/com/fnproject/fn/examples/ThumbnailsFunctionTest.java b/examples/async-thumbnails/src/test/java/com/fnproject/fn/examples/ThumbnailsFunctionTest.java index 8179ea10..8914acc5 100644 --- a/examples/async-thumbnails/src/test/java/com/fnproject/fn/examples/ThumbnailsFunctionTest.java +++ b/examples/async-thumbnails/src/test/java/com/fnproject/fn/examples/ThumbnailsFunctionTest.java @@ -1,3 +1,19 @@ +/* + * Copyright (c) 2019, 2020 Oracle and/or its affiliates. All rights reserved. + * + * 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. + */ + package com.fnproject.fn.examples; import com.fnproject.fn.testing.FnTestingRule; diff --git a/examples/gradle-build/Dockerfile b/examples/gradle-build/Dockerfile index 859cc232..cca84dbb 100644 --- a/examples/gradle-build/Dockerfile +++ b/examples/gradle-build/Dockerfile @@ -1,3 +1,19 @@ +# +# Copyright (c) 2019, 2020 Oracle and/or its affiliates. All rights reserved. +# +# 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. +# + FROM gradle:4.5.1-jdk8 as build-stage WORKDIR /function # needed for gradle? diff --git a/examples/gradle-build/build.gradle b/examples/gradle-build/build.gradle index c15e3fc0..6fb0925a 100644 --- a/examples/gradle-build/build.gradle +++ b/examples/gradle-build/build.gradle @@ -1,3 +1,19 @@ +/* + * Copyright (c) 2019, 2020 Oracle and/or its affiliates. All rights reserved. + * + * 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. + */ + apply plugin: 'java' ext { diff --git a/examples/gradle-build/func.yaml b/examples/gradle-build/func.yaml index 2f82680d..bc23a27a 100644 --- a/examples/gradle-build/func.yaml +++ b/examples/gradle-build/func.yaml @@ -1,3 +1,19 @@ +# +# Copyright (c) 2019, 2020 Oracle and/or its affiliates. All rights reserved. +# +# 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. +# + name: gradle_build version: 0.0.3 runtime: docker diff --git a/examples/gradle-build/src/main/java/com/example/fn/HelloFunction.java b/examples/gradle-build/src/main/java/com/example/fn/HelloFunction.java index 8aa7fef7..c335e147 100644 --- a/examples/gradle-build/src/main/java/com/example/fn/HelloFunction.java +++ b/examples/gradle-build/src/main/java/com/example/fn/HelloFunction.java @@ -1,3 +1,19 @@ +/* + * Copyright (c) 2019, 2020 Oracle and/or its affiliates. All rights reserved. + * + * 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. + */ + package com.example.fn; public class HelloFunction { diff --git a/examples/gradle-build/src/test/java/com/example/fn/HelloFunctionTest.java b/examples/gradle-build/src/test/java/com/example/fn/HelloFunctionTest.java index bd46e52d..5a036a2a 100644 --- a/examples/gradle-build/src/test/java/com/example/fn/HelloFunctionTest.java +++ b/examples/gradle-build/src/test/java/com/example/fn/HelloFunctionTest.java @@ -1,3 +1,19 @@ +/* + * Copyright (c) 2019, 2020 Oracle and/or its affiliates. All rights reserved. + * + * 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. + */ + package com.example.fn; import static org.junit.Assert.*; diff --git a/examples/pom.xml b/examples/pom.xml index c00977ea..9f058115 100644 --- a/examples/pom.xml +++ b/examples/pom.xml @@ -1,4 +1,22 @@ + + diff --git a/examples/qr-code/example.html b/examples/qr-code/example.html index fb7d1f6a..d4d964c2 100644 --- a/examples/qr-code/example.html +++ b/examples/qr-code/example.html @@ -1,3 +1,21 @@ + + diff --git a/examples/qr-code/func.yaml b/examples/qr-code/func.yaml index ccff7c49..4ca1732e 100644 --- a/examples/qr-code/func.yaml +++ b/examples/qr-code/func.yaml @@ -1,3 +1,19 @@ +# +# Copyright (c) 2019, 2020 Oracle and/or its affiliates. All rights reserved. +# +# 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. +# + name: fn-example/qr-code-gen version: 0.0.1 runtime: java diff --git a/examples/qr-code/pom.xml b/examples/qr-code/pom.xml index f2a60dfc..b5c14942 100644 --- a/examples/qr-code/pom.xml +++ b/examples/qr-code/pom.xml @@ -1,4 +1,22 @@ + + diff --git a/examples/qr-code/src/main/java/com/fnproject/fn/examples/QRGen.java b/examples/qr-code/src/main/java/com/fnproject/fn/examples/QRGen.java index 9f233e29..99b886b9 100644 --- a/examples/qr-code/src/main/java/com/fnproject/fn/examples/QRGen.java +++ b/examples/qr-code/src/main/java/com/fnproject/fn/examples/QRGen.java @@ -1,3 +1,19 @@ +/* + * Copyright (c) 2019, 2020 Oracle and/or its affiliates. All rights reserved. + * + * 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. + */ + package com.fnproject.fn.examples; import com.fnproject.fn.api.RuntimeContext; diff --git a/examples/qr-code/src/test/java/com/fnproject/fn/examples/QRGenTest.java b/examples/qr-code/src/test/java/com/fnproject/fn/examples/QRGenTest.java index c23ec6c2..cb376482 100644 --- a/examples/qr-code/src/test/java/com/fnproject/fn/examples/QRGenTest.java +++ b/examples/qr-code/src/test/java/com/fnproject/fn/examples/QRGenTest.java @@ -1,3 +1,19 @@ +/* + * Copyright (c) 2019, 2020 Oracle and/or its affiliates. All rights reserved. + * + * 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. + */ + package com.fnproject.fn.examples; import com.fnproject.fn.testing.FnTestingRule; diff --git a/examples/regex-query/func.yaml b/examples/regex-query/func.yaml index b216f06e..d14a3f37 100644 --- a/examples/regex-query/func.yaml +++ b/examples/regex-query/func.yaml @@ -1,3 +1,19 @@ +# +# Copyright (c) 2019, 2020 Oracle and/or its affiliates. All rights reserved. +# +# 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. +# + name: fn-example/regex-query version: 0.0.1 runtime: java diff --git a/examples/regex-query/pom.xml b/examples/regex-query/pom.xml index c85f7289..ab7db867 100644 --- a/examples/regex-query/pom.xml +++ b/examples/regex-query/pom.xml @@ -1,4 +1,22 @@ + + diff --git a/examples/regex-query/src/main/java/com/fnproject/fn/examples/Match.java b/examples/regex-query/src/main/java/com/fnproject/fn/examples/Match.java index d4b1188c..f2bb4f90 100644 --- a/examples/regex-query/src/main/java/com/fnproject/fn/examples/Match.java +++ b/examples/regex-query/src/main/java/com/fnproject/fn/examples/Match.java @@ -1,3 +1,19 @@ +/* + * Copyright (c) 2019, 2020 Oracle and/or its affiliates. All rights reserved. + * + * 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. + */ + package com.fnproject.fn.examples; import com.fasterxml.jackson.annotation.JsonCreator; diff --git a/examples/regex-query/src/main/java/com/fnproject/fn/examples/Query.java b/examples/regex-query/src/main/java/com/fnproject/fn/examples/Query.java index e927400e..fe5a9256 100644 --- a/examples/regex-query/src/main/java/com/fnproject/fn/examples/Query.java +++ b/examples/regex-query/src/main/java/com/fnproject/fn/examples/Query.java @@ -1,3 +1,19 @@ +/* + * Copyright (c) 2019, 2020 Oracle and/or its affiliates. All rights reserved. + * + * 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. + */ + package com.fnproject.fn.examples; import com.fasterxml.jackson.annotation.JsonCreator; diff --git a/examples/regex-query/src/main/java/com/fnproject/fn/examples/RegexQuery.java b/examples/regex-query/src/main/java/com/fnproject/fn/examples/RegexQuery.java index cbfd993e..aab1c7bb 100644 --- a/examples/regex-query/src/main/java/com/fnproject/fn/examples/RegexQuery.java +++ b/examples/regex-query/src/main/java/com/fnproject/fn/examples/RegexQuery.java @@ -1,3 +1,19 @@ +/* + * Copyright (c) 2019, 2020 Oracle and/or its affiliates. All rights reserved. + * + * 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. + */ + package com.fnproject.fn.examples; import java.util.ArrayList; diff --git a/examples/regex-query/src/main/java/com/fnproject/fn/examples/Response.java b/examples/regex-query/src/main/java/com/fnproject/fn/examples/Response.java index af939b9f..0f7330a5 100644 --- a/examples/regex-query/src/main/java/com/fnproject/fn/examples/Response.java +++ b/examples/regex-query/src/main/java/com/fnproject/fn/examples/Response.java @@ -1,3 +1,19 @@ +/* + * Copyright (c) 2019, 2020 Oracle and/or its affiliates. All rights reserved. + * + * 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. + */ + package com.fnproject.fn.examples; import com.fasterxml.jackson.annotation.JsonCreator; diff --git a/examples/regex-query/src/test/java/com/fnproject/fn/examples/RegexQueryTests.java b/examples/regex-query/src/test/java/com/fnproject/fn/examples/RegexQueryTests.java index 6ccdce56..d0e241d5 100644 --- a/examples/regex-query/src/test/java/com/fnproject/fn/examples/RegexQueryTests.java +++ b/examples/regex-query/src/test/java/com/fnproject/fn/examples/RegexQueryTests.java @@ -1,3 +1,19 @@ +/* + * Copyright (c) 2019, 2020 Oracle and/or its affiliates. All rights reserved. + * + * 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. + */ + package com.fnproject.fn.examples; import com.fnproject.fn.testing.FnTestingRule; diff --git a/examples/string-reverse/func.yaml b/examples/string-reverse/func.yaml index 4d56d44f..06045be1 100644 --- a/examples/string-reverse/func.yaml +++ b/examples/string-reverse/func.yaml @@ -1,3 +1,19 @@ +# +# Copyright (c) 2019, 2020 Oracle and/or its affiliates. All rights reserved. +# +# 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. +# + schema_version: 20180708 name: string-reverse version: 0.0.2 diff --git a/examples/string-reverse/pom.xml b/examples/string-reverse/pom.xml index 916d988d..b48ff3b5 100644 --- a/examples/string-reverse/pom.xml +++ b/examples/string-reverse/pom.xml @@ -1,4 +1,22 @@ + + diff --git a/examples/string-reverse/src/main/java/com/example/fn/StringReverse.java b/examples/string-reverse/src/main/java/com/example/fn/StringReverse.java index 46d0f5fb..6c66f8b2 100644 --- a/examples/string-reverse/src/main/java/com/example/fn/StringReverse.java +++ b/examples/string-reverse/src/main/java/com/example/fn/StringReverse.java @@ -1,3 +1,19 @@ +/* + * Copyright (c) 2019, 2020 Oracle and/or its affiliates. All rights reserved. + * + * 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. + */ + package com.example.fn; public class StringReverse { diff --git a/examples/string-reverse/src/test/java/com/example/fn/testing/StringReverseTest.java b/examples/string-reverse/src/test/java/com/example/fn/testing/StringReverseTest.java index e9b59af0..19c2af40 100644 --- a/examples/string-reverse/src/test/java/com/example/fn/testing/StringReverseTest.java +++ b/examples/string-reverse/src/test/java/com/example/fn/testing/StringReverseTest.java @@ -1,3 +1,19 @@ +/* + * Copyright (c) 2019, 2020 Oracle and/or its affiliates. All rights reserved. + * + * 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. + */ + package com.example.fn.testing; import com.example.fn.StringReverse; diff --git a/flow-api/pom.xml b/flow-api/pom.xml index b965bdb4..1c1dd563 100644 --- a/flow-api/pom.xml +++ b/flow-api/pom.xml @@ -1,4 +1,22 @@ + + diff --git a/flow-api/src/main/java/com/fnproject/fn/api/flow/Flow.java b/flow-api/src/main/java/com/fnproject/fn/api/flow/Flow.java index b366e361..11cfc9f2 100644 --- a/flow-api/src/main/java/com/fnproject/fn/api/flow/Flow.java +++ b/flow-api/src/main/java/com/fnproject/fn/api/flow/Flow.java @@ -1,3 +1,19 @@ +/* + * Copyright (c) 2019, 2020 Oracle and/or its affiliates. All rights reserved. + * + * 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. + */ + package com.fnproject.fn.api.flow; import com.fnproject.fn.api.Headers; diff --git a/flow-api/src/main/java/com/fnproject/fn/api/flow/FlowCompletionException.java b/flow-api/src/main/java/com/fnproject/fn/api/flow/FlowCompletionException.java index 3f3e017c..051a0f32 100644 --- a/flow-api/src/main/java/com/fnproject/fn/api/flow/FlowCompletionException.java +++ b/flow-api/src/main/java/com/fnproject/fn/api/flow/FlowCompletionException.java @@ -1,3 +1,19 @@ +/* + * Copyright (c) 2019, 2020 Oracle and/or its affiliates. All rights reserved. + * + * 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. + */ + package com.fnproject.fn.api.flow; diff --git a/flow-api/src/main/java/com/fnproject/fn/api/flow/FlowFuture.java b/flow-api/src/main/java/com/fnproject/fn/api/flow/FlowFuture.java index 6dd82fdb..1bbc36cc 100644 --- a/flow-api/src/main/java/com/fnproject/fn/api/flow/FlowFuture.java +++ b/flow-api/src/main/java/com/fnproject/fn/api/flow/FlowFuture.java @@ -1,3 +1,19 @@ +/* + * Copyright (c) 2019, 2020 Oracle and/or its affiliates. All rights reserved. + * + * 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. + */ + package com.fnproject.fn.api.flow; import java.io.Serializable; diff --git a/flow-api/src/main/java/com/fnproject/fn/api/flow/Flows.java b/flow-api/src/main/java/com/fnproject/fn/api/flow/Flows.java index 5845671b..14097465 100644 --- a/flow-api/src/main/java/com/fnproject/fn/api/flow/Flows.java +++ b/flow-api/src/main/java/com/fnproject/fn/api/flow/Flows.java @@ -1,3 +1,19 @@ +/* + * Copyright (c) 2019, 2020 Oracle and/or its affiliates. All rights reserved. + * + * 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. + */ + package com.fnproject.fn.api.flow; diff --git a/flow-api/src/main/java/com/fnproject/fn/api/flow/FunctionInvocationException.java b/flow-api/src/main/java/com/fnproject/fn/api/flow/FunctionInvocationException.java index b3cc78c5..5c8c1e14 100644 --- a/flow-api/src/main/java/com/fnproject/fn/api/flow/FunctionInvocationException.java +++ b/flow-api/src/main/java/com/fnproject/fn/api/flow/FunctionInvocationException.java @@ -1,3 +1,19 @@ +/* + * Copyright (c) 2019, 2020 Oracle and/or its affiliates. All rights reserved. + * + * 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. + */ + package com.fnproject.fn.api.flow; /** diff --git a/flow-api/src/main/java/com/fnproject/fn/api/flow/FunctionInvokeFailedException.java b/flow-api/src/main/java/com/fnproject/fn/api/flow/FunctionInvokeFailedException.java index db8ce8b6..731fae5d 100644 --- a/flow-api/src/main/java/com/fnproject/fn/api/flow/FunctionInvokeFailedException.java +++ b/flow-api/src/main/java/com/fnproject/fn/api/flow/FunctionInvokeFailedException.java @@ -1,3 +1,19 @@ +/* + * Copyright (c) 2019, 2020 Oracle and/or its affiliates. All rights reserved. + * + * 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. + */ + package com.fnproject.fn.api.flow; /** diff --git a/flow-api/src/main/java/com/fnproject/fn/api/flow/FunctionTimeoutException.java b/flow-api/src/main/java/com/fnproject/fn/api/flow/FunctionTimeoutException.java index 5cf3eec9..b38317a9 100644 --- a/flow-api/src/main/java/com/fnproject/fn/api/flow/FunctionTimeoutException.java +++ b/flow-api/src/main/java/com/fnproject/fn/api/flow/FunctionTimeoutException.java @@ -1,3 +1,19 @@ +/* + * Copyright (c) 2019, 2020 Oracle and/or its affiliates. All rights reserved. + * + * 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. + */ + package com.fnproject.fn.api.flow; /** diff --git a/flow-api/src/main/java/com/fnproject/fn/api/flow/HttpMethod.java b/flow-api/src/main/java/com/fnproject/fn/api/flow/HttpMethod.java index 8ec66fd6..b5109343 100644 --- a/flow-api/src/main/java/com/fnproject/fn/api/flow/HttpMethod.java +++ b/flow-api/src/main/java/com/fnproject/fn/api/flow/HttpMethod.java @@ -1,3 +1,19 @@ +/* + * Copyright (c) 2019, 2020 Oracle and/or its affiliates. All rights reserved. + * + * 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. + */ + package com.fnproject.fn.api.flow; /** diff --git a/flow-api/src/main/java/com/fnproject/fn/api/flow/HttpRequest.java b/flow-api/src/main/java/com/fnproject/fn/api/flow/HttpRequest.java index 0f8e710a..c7e4b3f1 100644 --- a/flow-api/src/main/java/com/fnproject/fn/api/flow/HttpRequest.java +++ b/flow-api/src/main/java/com/fnproject/fn/api/flow/HttpRequest.java @@ -1,3 +1,19 @@ +/* + * Copyright (c) 2019, 2020 Oracle and/or its affiliates. All rights reserved. + * + * 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. + */ + package com.fnproject.fn.api.flow; import com.fnproject.fn.api.Headers; diff --git a/flow-api/src/main/java/com/fnproject/fn/api/flow/HttpResponse.java b/flow-api/src/main/java/com/fnproject/fn/api/flow/HttpResponse.java index 1df7b86f..f994b9ed 100644 --- a/flow-api/src/main/java/com/fnproject/fn/api/flow/HttpResponse.java +++ b/flow-api/src/main/java/com/fnproject/fn/api/flow/HttpResponse.java @@ -1,3 +1,19 @@ +/* + * Copyright (c) 2019, 2020 Oracle and/or its affiliates. All rights reserved. + * + * 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. + */ + package com.fnproject.fn.api.flow; import com.fnproject.fn.api.Headers; diff --git a/flow-api/src/main/java/com/fnproject/fn/api/flow/InvalidStageResponseException.java b/flow-api/src/main/java/com/fnproject/fn/api/flow/InvalidStageResponseException.java index e3ef054a..852f6c4f 100644 --- a/flow-api/src/main/java/com/fnproject/fn/api/flow/InvalidStageResponseException.java +++ b/flow-api/src/main/java/com/fnproject/fn/api/flow/InvalidStageResponseException.java @@ -1,3 +1,19 @@ +/* + * Copyright (c) 2019, 2020 Oracle and/or its affiliates. All rights reserved. + * + * 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. + */ + package com.fnproject.fn.api.flow; /** diff --git a/flow-api/src/main/java/com/fnproject/fn/api/flow/LambdaSerializationException.java b/flow-api/src/main/java/com/fnproject/fn/api/flow/LambdaSerializationException.java index d1085179..6a4af778 100644 --- a/flow-api/src/main/java/com/fnproject/fn/api/flow/LambdaSerializationException.java +++ b/flow-api/src/main/java/com/fnproject/fn/api/flow/LambdaSerializationException.java @@ -1,3 +1,19 @@ +/* + * Copyright (c) 2019, 2020 Oracle and/or its affiliates. All rights reserved. + * + * 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. + */ + package com.fnproject.fn.api.flow; /** diff --git a/flow-api/src/main/java/com/fnproject/fn/api/flow/PlatformException.java b/flow-api/src/main/java/com/fnproject/fn/api/flow/PlatformException.java index cb1932e7..9d90277c 100644 --- a/flow-api/src/main/java/com/fnproject/fn/api/flow/PlatformException.java +++ b/flow-api/src/main/java/com/fnproject/fn/api/flow/PlatformException.java @@ -1,3 +1,19 @@ +/* + * Copyright (c) 2019, 2020 Oracle and/or its affiliates. All rights reserved. + * + * 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. + */ + package com.fnproject.fn.api.flow; /** diff --git a/flow-api/src/main/java/com/fnproject/fn/api/flow/ResultSerializationException.java b/flow-api/src/main/java/com/fnproject/fn/api/flow/ResultSerializationException.java index e2fad467..2eafb9c9 100644 --- a/flow-api/src/main/java/com/fnproject/fn/api/flow/ResultSerializationException.java +++ b/flow-api/src/main/java/com/fnproject/fn/api/flow/ResultSerializationException.java @@ -1,3 +1,19 @@ +/* + * Copyright (c) 2019, 2020 Oracle and/or its affiliates. All rights reserved. + * + * 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. + */ + package com.fnproject.fn.api.flow; /** diff --git a/flow-api/src/main/java/com/fnproject/fn/api/flow/StageInvokeFailedException.java b/flow-api/src/main/java/com/fnproject/fn/api/flow/StageInvokeFailedException.java index b4770bbc..9bd5b04c 100644 --- a/flow-api/src/main/java/com/fnproject/fn/api/flow/StageInvokeFailedException.java +++ b/flow-api/src/main/java/com/fnproject/fn/api/flow/StageInvokeFailedException.java @@ -1,3 +1,19 @@ +/* + * Copyright (c) 2019, 2020 Oracle and/or its affiliates. All rights reserved. + * + * 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. + */ + package com.fnproject.fn.api.flow; /** diff --git a/flow-api/src/main/java/com/fnproject/fn/api/flow/StageLostException.java b/flow-api/src/main/java/com/fnproject/fn/api/flow/StageLostException.java index 5131ff5f..2e86d650 100644 --- a/flow-api/src/main/java/com/fnproject/fn/api/flow/StageLostException.java +++ b/flow-api/src/main/java/com/fnproject/fn/api/flow/StageLostException.java @@ -1,3 +1,19 @@ +/* + * Copyright (c) 2019, 2020 Oracle and/or its affiliates. All rights reserved. + * + * 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. + */ + package com.fnproject.fn.api.flow; /** diff --git a/flow-api/src/main/java/com/fnproject/fn/api/flow/StageTimeoutException.java b/flow-api/src/main/java/com/fnproject/fn/api/flow/StageTimeoutException.java index 5de3c6d3..5f84f7a8 100644 --- a/flow-api/src/main/java/com/fnproject/fn/api/flow/StageTimeoutException.java +++ b/flow-api/src/main/java/com/fnproject/fn/api/flow/StageTimeoutException.java @@ -1,3 +1,19 @@ +/* + * Copyright (c) 2019, 2020 Oracle and/or its affiliates. All rights reserved. + * + * 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. + */ + package com.fnproject.fn.api.flow; /** diff --git a/flow-api/src/main/java/com/fnproject/fn/api/flow/WrappedFunctionException.java b/flow-api/src/main/java/com/fnproject/fn/api/flow/WrappedFunctionException.java index 065e6ee7..0bd7e7fa 100644 --- a/flow-api/src/main/java/com/fnproject/fn/api/flow/WrappedFunctionException.java +++ b/flow-api/src/main/java/com/fnproject/fn/api/flow/WrappedFunctionException.java @@ -1,3 +1,19 @@ +/* + * Copyright (c) 2019, 2020 Oracle and/or its affiliates. All rights reserved. + * + * 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. + */ + package com.fnproject.fn.api.flow; import java.io.Serializable; diff --git a/flow-api/src/main/java/com/fnproject/fn/api/flow/package-info.java b/flow-api/src/main/java/com/fnproject/fn/api/flow/package-info.java index 0d21dcaf..f4a567b1 100644 --- a/flow-api/src/main/java/com/fnproject/fn/api/flow/package-info.java +++ b/flow-api/src/main/java/com/fnproject/fn/api/flow/package-info.java @@ -1,3 +1,19 @@ +/* + * Copyright (c) 2019, 2020 Oracle and/or its affiliates. All rights reserved. + * + * 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. + */ + /** * SDK for creating and running asynchronous processes from within fn for Java. */ diff --git a/flow-api/src/test/java/com/fnproject/fn/api/flow/FlowsTest.java b/flow-api/src/test/java/com/fnproject/fn/api/flow/FlowsTest.java index aed5b7eb..778ccf1c 100644 --- a/flow-api/src/test/java/com/fnproject/fn/api/flow/FlowsTest.java +++ b/flow-api/src/test/java/com/fnproject/fn/api/flow/FlowsTest.java @@ -1,3 +1,19 @@ +/* + * Copyright (c) 2019, 2020 Oracle and/or its affiliates. All rights reserved. + * + * 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. + */ + package com.fnproject.fn.api.flow; import org.junit.Test; diff --git a/flow-runtime/pom.xml b/flow-runtime/pom.xml index cec1e629..73a64d00 100644 --- a/flow-runtime/pom.xml +++ b/flow-runtime/pom.xml @@ -1,4 +1,22 @@ + + diff --git a/flow-runtime/src/main/java/com/fnproject/fn/runtime/flow/APIModel.java b/flow-runtime/src/main/java/com/fnproject/fn/runtime/flow/APIModel.java index c5cb2b1b..886d093c 100644 --- a/flow-runtime/src/main/java/com/fnproject/fn/runtime/flow/APIModel.java +++ b/flow-runtime/src/main/java/com/fnproject/fn/runtime/flow/APIModel.java @@ -1,3 +1,19 @@ +/* + * Copyright (c) 2019, 2020 Oracle and/or its affiliates. All rights reserved. + * + * 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. + */ + package com.fnproject.fn.runtime.flow; import com.fasterxml.jackson.annotation.JsonProperty; diff --git a/flow-runtime/src/main/java/com/fnproject/fn/runtime/flow/BlobResponse.java b/flow-runtime/src/main/java/com/fnproject/fn/runtime/flow/BlobResponse.java index 21503bf2..4adcb02c 100644 --- a/flow-runtime/src/main/java/com/fnproject/fn/runtime/flow/BlobResponse.java +++ b/flow-runtime/src/main/java/com/fnproject/fn/runtime/flow/BlobResponse.java @@ -1,3 +1,19 @@ +/* + * Copyright (c) 2019, 2020 Oracle and/or its affiliates. All rights reserved. + * + * 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. + */ + package com.fnproject.fn.runtime.flow; import com.fasterxml.jackson.annotation.JsonProperty; diff --git a/flow-runtime/src/main/java/com/fnproject/fn/runtime/flow/BlobStoreClient.java b/flow-runtime/src/main/java/com/fnproject/fn/runtime/flow/BlobStoreClient.java index a002ba93..9b898adf 100644 --- a/flow-runtime/src/main/java/com/fnproject/fn/runtime/flow/BlobStoreClient.java +++ b/flow-runtime/src/main/java/com/fnproject/fn/runtime/flow/BlobStoreClient.java @@ -1,3 +1,19 @@ +/* + * Copyright (c) 2019, 2020 Oracle and/or its affiliates. All rights reserved. + * + * 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. + */ + package com.fnproject.fn.runtime.flow; import java.io.InputStream; diff --git a/flow-runtime/src/main/java/com/fnproject/fn/runtime/flow/CodeLocation.java b/flow-runtime/src/main/java/com/fnproject/fn/runtime/flow/CodeLocation.java index 341cc647..721161c9 100644 --- a/flow-runtime/src/main/java/com/fnproject/fn/runtime/flow/CodeLocation.java +++ b/flow-runtime/src/main/java/com/fnproject/fn/runtime/flow/CodeLocation.java @@ -1,3 +1,19 @@ +/* + * Copyright (c) 2019, 2020 Oracle and/or its affiliates. All rights reserved. + * + * 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. + */ + package com.fnproject.fn.runtime.flow; diff --git a/flow-runtime/src/main/java/com/fnproject/fn/runtime/flow/CompleterClient.java b/flow-runtime/src/main/java/com/fnproject/fn/runtime/flow/CompleterClient.java index cee4a055..4224cbf8 100644 --- a/flow-runtime/src/main/java/com/fnproject/fn/runtime/flow/CompleterClient.java +++ b/flow-runtime/src/main/java/com/fnproject/fn/runtime/flow/CompleterClient.java @@ -1,3 +1,19 @@ +/* + * Copyright (c) 2019, 2020 Oracle and/or its affiliates. All rights reserved. + * + * 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. + */ + package com.fnproject.fn.runtime.flow; import com.fnproject.fn.api.Headers; diff --git a/flow-runtime/src/main/java/com/fnproject/fn/runtime/flow/CompleterClientFactory.java b/flow-runtime/src/main/java/com/fnproject/fn/runtime/flow/CompleterClientFactory.java index 752210c1..4fdb118b 100644 --- a/flow-runtime/src/main/java/com/fnproject/fn/runtime/flow/CompleterClientFactory.java +++ b/flow-runtime/src/main/java/com/fnproject/fn/runtime/flow/CompleterClientFactory.java @@ -1,3 +1,19 @@ +/* + * Copyright (c) 2019, 2020 Oracle and/or its affiliates. All rights reserved. + * + * 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. + */ + package com.fnproject.fn.runtime.flow; import java.io.Serializable; diff --git a/flow-runtime/src/main/java/com/fnproject/fn/runtime/flow/CompletionId.java b/flow-runtime/src/main/java/com/fnproject/fn/runtime/flow/CompletionId.java index c533ec5e..5cc5d0ea 100644 --- a/flow-runtime/src/main/java/com/fnproject/fn/runtime/flow/CompletionId.java +++ b/flow-runtime/src/main/java/com/fnproject/fn/runtime/flow/CompletionId.java @@ -1,3 +1,19 @@ +/* + * Copyright (c) 2019, 2020 Oracle and/or its affiliates. All rights reserved. + * + * 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. + */ + package com.fnproject.fn.runtime.flow; import java.io.Serializable; diff --git a/flow-runtime/src/main/java/com/fnproject/fn/runtime/flow/DefaultHttpResponse.java b/flow-runtime/src/main/java/com/fnproject/fn/runtime/flow/DefaultHttpResponse.java index 5aac5105..6caacaa5 100644 --- a/flow-runtime/src/main/java/com/fnproject/fn/runtime/flow/DefaultHttpResponse.java +++ b/flow-runtime/src/main/java/com/fnproject/fn/runtime/flow/DefaultHttpResponse.java @@ -1,3 +1,19 @@ +/* + * Copyright (c) 2019, 2020 Oracle and/or its affiliates. All rights reserved. + * + * 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. + */ + package com.fnproject.fn.runtime.flow; import com.fnproject.fn.api.Headers; diff --git a/flow-runtime/src/main/java/com/fnproject/fn/runtime/flow/EntityReader.java b/flow-runtime/src/main/java/com/fnproject/fn/runtime/flow/EntityReader.java index 4b837109..42728b8e 100644 --- a/flow-runtime/src/main/java/com/fnproject/fn/runtime/flow/EntityReader.java +++ b/flow-runtime/src/main/java/com/fnproject/fn/runtime/flow/EntityReader.java @@ -1,3 +1,19 @@ +/* + * Copyright (c) 2019, 2020 Oracle and/or its affiliates. All rights reserved. + * + * 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. + */ + package com.fnproject.fn.runtime.flow; import java.io.InputStream; diff --git a/flow-runtime/src/main/java/com/fnproject/fn/runtime/flow/FlowContinuationInvoker.java b/flow-runtime/src/main/java/com/fnproject/fn/runtime/flow/FlowContinuationInvoker.java index 177b2e89..bbd2e3a9 100644 --- a/flow-runtime/src/main/java/com/fnproject/fn/runtime/flow/FlowContinuationInvoker.java +++ b/flow-runtime/src/main/java/com/fnproject/fn/runtime/flow/FlowContinuationInvoker.java @@ -1,3 +1,19 @@ +/* + * Copyright (c) 2019, 2020 Oracle and/or its affiliates. All rights reserved. + * + * 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. + */ + package com.fnproject.fn.runtime.flow; import com.fasterxml.jackson.core.JsonProcessingException; diff --git a/flow-runtime/src/main/java/com/fnproject/fn/runtime/flow/FlowFeature.java b/flow-runtime/src/main/java/com/fnproject/fn/runtime/flow/FlowFeature.java index 27a79f0b..10118c1c 100644 --- a/flow-runtime/src/main/java/com/fnproject/fn/runtime/flow/FlowFeature.java +++ b/flow-runtime/src/main/java/com/fnproject/fn/runtime/flow/FlowFeature.java @@ -1,3 +1,19 @@ +/* + * Copyright (c) 2019, 2020 Oracle and/or its affiliates. All rights reserved. + * + * 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. + */ + package com.fnproject.fn.runtime.flow; import com.fnproject.fn.api.FunctionInvoker; diff --git a/flow-runtime/src/main/java/com/fnproject/fn/runtime/flow/FlowFutureSource.java b/flow-runtime/src/main/java/com/fnproject/fn/runtime/flow/FlowFutureSource.java index 7561e66b..9f7cdacb 100644 --- a/flow-runtime/src/main/java/com/fnproject/fn/runtime/flow/FlowFutureSource.java +++ b/flow-runtime/src/main/java/com/fnproject/fn/runtime/flow/FlowFutureSource.java @@ -1,3 +1,19 @@ +/* + * Copyright (c) 2019, 2020 Oracle and/or its affiliates. All rights reserved. + * + * 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. + */ + package com.fnproject.fn.runtime.flow; import com.fnproject.fn.api.flow.FlowFuture; diff --git a/flow-runtime/src/main/java/com/fnproject/fn/runtime/flow/FlowId.java b/flow-runtime/src/main/java/com/fnproject/fn/runtime/flow/FlowId.java index ced213f0..65481eb9 100644 --- a/flow-runtime/src/main/java/com/fnproject/fn/runtime/flow/FlowId.java +++ b/flow-runtime/src/main/java/com/fnproject/fn/runtime/flow/FlowId.java @@ -1,3 +1,19 @@ +/* + * Copyright (c) 2019, 2020 Oracle and/or its affiliates. All rights reserved. + * + * 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. + */ + package com.fnproject.fn.runtime.flow; import java.io.Serializable; diff --git a/flow-runtime/src/main/java/com/fnproject/fn/runtime/flow/FlowRuntimeGlobals.java b/flow-runtime/src/main/java/com/fnproject/fn/runtime/flow/FlowRuntimeGlobals.java index 66e61456..b341c26c 100644 --- a/flow-runtime/src/main/java/com/fnproject/fn/runtime/flow/FlowRuntimeGlobals.java +++ b/flow-runtime/src/main/java/com/fnproject/fn/runtime/flow/FlowRuntimeGlobals.java @@ -1,3 +1,19 @@ +/* + * Copyright (c) 2019, 2020 Oracle and/or its affiliates. All rights reserved. + * + * 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. + */ + package com.fnproject.fn.runtime.flow; import com.fasterxml.jackson.databind.ObjectMapper; diff --git a/flow-runtime/src/main/java/com/fnproject/fn/runtime/flow/HttpClient.java b/flow-runtime/src/main/java/com/fnproject/fn/runtime/flow/HttpClient.java index 99637d3c..557fc336 100644 --- a/flow-runtime/src/main/java/com/fnproject/fn/runtime/flow/HttpClient.java +++ b/flow-runtime/src/main/java/com/fnproject/fn/runtime/flow/HttpClient.java @@ -1,3 +1,19 @@ +/* + * Copyright (c) 2019, 2020 Oracle and/or its affiliates. All rights reserved. + * + * 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. + */ + package com.fnproject.fn.runtime.flow; import org.apache.commons.io.IOUtils; diff --git a/flow-runtime/src/main/java/com/fnproject/fn/runtime/flow/JsonInvoke.java b/flow-runtime/src/main/java/com/fnproject/fn/runtime/flow/JsonInvoke.java index d6e20272..64d1fc60 100644 --- a/flow-runtime/src/main/java/com/fnproject/fn/runtime/flow/JsonInvoke.java +++ b/flow-runtime/src/main/java/com/fnproject/fn/runtime/flow/JsonInvoke.java @@ -1,3 +1,19 @@ +/* + * Copyright (c) 2019, 2020 Oracle and/or its affiliates. All rights reserved. + * + * 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. + */ + package com.fnproject.fn.runtime.flow; import com.fasterxml.jackson.core.JsonProcessingException; diff --git a/flow-runtime/src/main/java/com/fnproject/fn/runtime/flow/RemoteBlobStoreClient.java b/flow-runtime/src/main/java/com/fnproject/fn/runtime/flow/RemoteBlobStoreClient.java index b4274d93..86762868 100644 --- a/flow-runtime/src/main/java/com/fnproject/fn/runtime/flow/RemoteBlobStoreClient.java +++ b/flow-runtime/src/main/java/com/fnproject/fn/runtime/flow/RemoteBlobStoreClient.java @@ -1,3 +1,19 @@ +/* + * Copyright (c) 2019, 2020 Oracle and/or its affiliates. All rights reserved. + * + * 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. + */ + package com.fnproject.fn.runtime.flow; import com.fnproject.fn.runtime.exception.PlatformCommunicationException; diff --git a/flow-runtime/src/main/java/com/fnproject/fn/runtime/flow/RemoteFlow.java b/flow-runtime/src/main/java/com/fnproject/fn/runtime/flow/RemoteFlow.java index 48c2f429..f9535139 100644 --- a/flow-runtime/src/main/java/com/fnproject/fn/runtime/flow/RemoteFlow.java +++ b/flow-runtime/src/main/java/com/fnproject/fn/runtime/flow/RemoteFlow.java @@ -1,3 +1,19 @@ +/* + * Copyright (c) 2019, 2020 Oracle and/or its affiliates. All rights reserved. + * + * 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. + */ + package com.fnproject.fn.runtime.flow; import com.fnproject.fn.api.Headers; diff --git a/flow-runtime/src/main/java/com/fnproject/fn/runtime/flow/RemoteFlowApiClient.java b/flow-runtime/src/main/java/com/fnproject/fn/runtime/flow/RemoteFlowApiClient.java index a60bf452..39783de8 100644 --- a/flow-runtime/src/main/java/com/fnproject/fn/runtime/flow/RemoteFlowApiClient.java +++ b/flow-runtime/src/main/java/com/fnproject/fn/runtime/flow/RemoteFlowApiClient.java @@ -1,3 +1,19 @@ +/* + * Copyright (c) 2019, 2020 Oracle and/or its affiliates. All rights reserved. + * + * 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. + */ + package com.fnproject.fn.runtime.flow; import com.fasterxml.jackson.databind.ObjectMapper; diff --git a/flow-runtime/src/test/java/com/fnproject/fn/runtime/flow/FlowsContinuationInvokerTest.java b/flow-runtime/src/test/java/com/fnproject/fn/runtime/flow/FlowsContinuationInvokerTest.java index e38dfe45..227b507b 100644 --- a/flow-runtime/src/test/java/com/fnproject/fn/runtime/flow/FlowsContinuationInvokerTest.java +++ b/flow-runtime/src/test/java/com/fnproject/fn/runtime/flow/FlowsContinuationInvokerTest.java @@ -1,3 +1,19 @@ +/* + * Copyright (c) 2019, 2020 Oracle and/or its affiliates. All rights reserved. + * + * 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. + */ + package com.fnproject.fn.runtime.flow; import com.fasterxml.jackson.core.JsonProcessingException; diff --git a/flow-runtime/src/test/java/com/fnproject/fn/runtime/flow/RemoteFlowApiClientTest.java b/flow-runtime/src/test/java/com/fnproject/fn/runtime/flow/RemoteFlowApiClientTest.java index 72388243..10deb29f 100644 --- a/flow-runtime/src/test/java/com/fnproject/fn/runtime/flow/RemoteFlowApiClientTest.java +++ b/flow-runtime/src/test/java/com/fnproject/fn/runtime/flow/RemoteFlowApiClientTest.java @@ -1,3 +1,19 @@ +/* + * Copyright (c) 2019, 2020 Oracle and/or its affiliates. All rights reserved. + * + * 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. + */ + package com.fnproject.fn.runtime.flow; import com.fasterxml.jackson.databind.ObjectMapper; diff --git a/flow-runtime/src/test/java/com/fnproject/fn/runtime/flow/TestBlobStore.java b/flow-runtime/src/test/java/com/fnproject/fn/runtime/flow/TestBlobStore.java index e3559348..1b537c06 100644 --- a/flow-runtime/src/test/java/com/fnproject/fn/runtime/flow/TestBlobStore.java +++ b/flow-runtime/src/test/java/com/fnproject/fn/runtime/flow/TestBlobStore.java @@ -1,3 +1,19 @@ +/* + * Copyright (c) 2019, 2020 Oracle and/or its affiliates. All rights reserved. + * + * 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. + */ + package com.fnproject.fn.runtime.flow; import java.io.*; diff --git a/flow-runtime/src/test/java/com/fnproject/fn/testing/flowtestfns/FnFlowsFunction.java b/flow-runtime/src/test/java/com/fnproject/fn/testing/flowtestfns/FnFlowsFunction.java index 23ad312d..2e6cf98a 100644 --- a/flow-runtime/src/test/java/com/fnproject/fn/testing/flowtestfns/FnFlowsFunction.java +++ b/flow-runtime/src/test/java/com/fnproject/fn/testing/flowtestfns/FnFlowsFunction.java @@ -1,3 +1,19 @@ +/* + * Copyright (c) 2019, 2020 Oracle and/or its affiliates. All rights reserved. + * + * 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. + */ + package com.fnproject.fn.testing.flowtestfns; import com.fnproject.fn.api.FnFeature; diff --git a/flow-testing/pom.xml b/flow-testing/pom.xml index 03d2d9a3..e6cede00 100644 --- a/flow-testing/pom.xml +++ b/flow-testing/pom.xml @@ -1,4 +1,22 @@ + + diff --git a/flow-testing/src/main/java/com/fnproject/fn/testing/flow/FlowTesting.java b/flow-testing/src/main/java/com/fnproject/fn/testing/flow/FlowTesting.java index c8dfa8d2..54cc16b0 100644 --- a/flow-testing/src/main/java/com/fnproject/fn/testing/flow/FlowTesting.java +++ b/flow-testing/src/main/java/com/fnproject/fn/testing/flow/FlowTesting.java @@ -1,3 +1,19 @@ +/* + * Copyright (c) 2019, 2020 Oracle and/or its affiliates. All rights reserved. + * + * 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. + */ + package com.fnproject.fn.testing.flow; import com.fasterxml.jackson.core.JsonProcessingException; diff --git a/flow-testing/src/main/java/com/fnproject/fn/testing/flow/FnFunctionStubBuilder.java b/flow-testing/src/main/java/com/fnproject/fn/testing/flow/FnFunctionStubBuilder.java index c694be1f..e0c02719 100644 --- a/flow-testing/src/main/java/com/fnproject/fn/testing/flow/FnFunctionStubBuilder.java +++ b/flow-testing/src/main/java/com/fnproject/fn/testing/flow/FnFunctionStubBuilder.java @@ -1,3 +1,19 @@ +/* + * Copyright (c) 2019, 2020 Oracle and/or its affiliates. All rights reserved. + * + * 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. + */ + package com.fnproject.fn.testing.flow; import com.fnproject.fn.testing.FunctionError; diff --git a/flow-testing/src/main/java/com/fnproject/fn/testing/flow/InMemCompleter.java b/flow-testing/src/main/java/com/fnproject/fn/testing/flow/InMemCompleter.java index c2c93649..b695e959 100644 --- a/flow-testing/src/main/java/com/fnproject/fn/testing/flow/InMemCompleter.java +++ b/flow-testing/src/main/java/com/fnproject/fn/testing/flow/InMemCompleter.java @@ -1,3 +1,19 @@ +/* + * Copyright (c) 2019, 2020 Oracle and/or its affiliates. All rights reserved. + * + * 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. + */ + package com.fnproject.fn.testing.flow; import com.fnproject.fn.api.Headers; diff --git a/flow-testing/src/main/java/com/fnproject/fn/testing/flow/ResultException.java b/flow-testing/src/main/java/com/fnproject/fn/testing/flow/ResultException.java index be910af7..3400ccf4 100644 --- a/flow-testing/src/main/java/com/fnproject/fn/testing/flow/ResultException.java +++ b/flow-testing/src/main/java/com/fnproject/fn/testing/flow/ResultException.java @@ -1,3 +1,19 @@ +/* + * Copyright (c) 2019, 2020 Oracle and/or its affiliates. All rights reserved. + * + * 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. + */ + package com.fnproject.fn.testing.flow; import com.fnproject.fn.runtime.flow.APIModel; diff --git a/flow-testing/src/test/java/com/fnproject/fn/testing/flow/FnTestingRuleFlowsTest.java b/flow-testing/src/test/java/com/fnproject/fn/testing/flow/FnTestingRuleFlowsTest.java index f2e6a03b..61ef8349 100644 --- a/flow-testing/src/test/java/com/fnproject/fn/testing/flow/FnTestingRuleFlowsTest.java +++ b/flow-testing/src/test/java/com/fnproject/fn/testing/flow/FnTestingRuleFlowsTest.java @@ -1,3 +1,19 @@ +/* + * Copyright (c) 2019, 2020 Oracle and/or its affiliates. All rights reserved. + * + * 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. + */ + package com.fnproject.fn.testing.flow; import com.fnproject.fn.api.*; diff --git a/flow-testing/src/test/java/com/fnproject/fn/testing/flow/IntegrationTest.java b/flow-testing/src/test/java/com/fnproject/fn/testing/flow/IntegrationTest.java index 61e86171..341335dd 100644 --- a/flow-testing/src/test/java/com/fnproject/fn/testing/flow/IntegrationTest.java +++ b/flow-testing/src/test/java/com/fnproject/fn/testing/flow/IntegrationTest.java @@ -1,3 +1,19 @@ +/* + * Copyright (c) 2019, 2020 Oracle and/or its affiliates. All rights reserved. + * + * 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. + */ + package com.fnproject.fn.testing.flow; import com.fnproject.fn.testing.FnTestingRule; diff --git a/flow-testing/src/test/java/com/fnproject/fn/testing/flow/MultipleEventsTest.java b/flow-testing/src/test/java/com/fnproject/fn/testing/flow/MultipleEventsTest.java index a6b23eec..7109e4a6 100644 --- a/flow-testing/src/test/java/com/fnproject/fn/testing/flow/MultipleEventsTest.java +++ b/flow-testing/src/test/java/com/fnproject/fn/testing/flow/MultipleEventsTest.java @@ -1,3 +1,19 @@ +/* + * Copyright (c) 2019, 2020 Oracle and/or its affiliates. All rights reserved. + * + * 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. + */ + package com.fnproject.fn.testing.flow; import com.fnproject.fn.api.FnFeature; diff --git a/flow-testing/src/test/java/com/fnproject/fn/testing/flow/WhenCompleteTest.java b/flow-testing/src/test/java/com/fnproject/fn/testing/flow/WhenCompleteTest.java index d219061f..da04b1ca 100644 --- a/flow-testing/src/test/java/com/fnproject/fn/testing/flow/WhenCompleteTest.java +++ b/flow-testing/src/test/java/com/fnproject/fn/testing/flow/WhenCompleteTest.java @@ -1,3 +1,19 @@ +/* + * Copyright (c) 2019, 2020 Oracle and/or its affiliates. All rights reserved. + * + * 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. + */ + package com.fnproject.fn.testing.flow; import com.fnproject.fn.api.FnFeature; diff --git a/flow-testing/src/test/java/com/fnproject/fn/testing/flowtestfns/ExerciseEverything.java b/flow-testing/src/test/java/com/fnproject/fn/testing/flowtestfns/ExerciseEverything.java index 8807dacc..729c18cd 100644 --- a/flow-testing/src/test/java/com/fnproject/fn/testing/flowtestfns/ExerciseEverything.java +++ b/flow-testing/src/test/java/com/fnproject/fn/testing/flowtestfns/ExerciseEverything.java @@ -1,3 +1,19 @@ +/* + * Copyright (c) 2019, 2020 Oracle and/or its affiliates. All rights reserved. + * + * 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. + */ + package com.fnproject.fn.testing.flowtestfns; import com.fnproject.fn.api.*; diff --git a/fn-spring-cloud-function/pom.xml b/fn-spring-cloud-function/pom.xml index 7af1a1ff..f81ae91b 100644 --- a/fn-spring-cloud-function/pom.xml +++ b/fn-spring-cloud-function/pom.xml @@ -1,4 +1,22 @@ + + diff --git a/fn-spring-cloud-function/src/main/java/com/fnproject/springframework/function/SimpleTypeWrapper.java b/fn-spring-cloud-function/src/main/java/com/fnproject/springframework/function/SimpleTypeWrapper.java index 1c0e949e..178490e4 100644 --- a/fn-spring-cloud-function/src/main/java/com/fnproject/springframework/function/SimpleTypeWrapper.java +++ b/fn-spring-cloud-function/src/main/java/com/fnproject/springframework/function/SimpleTypeWrapper.java @@ -1,3 +1,19 @@ +/* + * Copyright (c) 2019, 2020 Oracle and/or its affiliates. All rights reserved. + * + * 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. + */ + package com.fnproject.springframework.function; import com.fnproject.fn.api.TypeWrapper; diff --git a/fn-spring-cloud-function/src/main/java/com/fnproject/springframework/function/SpringCloudFunctionFeature.java b/fn-spring-cloud-function/src/main/java/com/fnproject/springframework/function/SpringCloudFunctionFeature.java index 87d51d4d..04638028 100644 --- a/fn-spring-cloud-function/src/main/java/com/fnproject/springframework/function/SpringCloudFunctionFeature.java +++ b/fn-spring-cloud-function/src/main/java/com/fnproject/springframework/function/SpringCloudFunctionFeature.java @@ -1,3 +1,19 @@ +/* + * Copyright (c) 2019, 2020 Oracle and/or its affiliates. All rights reserved. + * + * 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. + */ + package com.fnproject.springframework.function; import com.fnproject.fn.api.FunctionInvoker; diff --git a/fn-spring-cloud-function/src/main/java/com/fnproject/springframework/function/SpringCloudFunctionInvoker.java b/fn-spring-cloud-function/src/main/java/com/fnproject/springframework/function/SpringCloudFunctionInvoker.java index 706fbd42..88702bf6 100644 --- a/fn-spring-cloud-function/src/main/java/com/fnproject/springframework/function/SpringCloudFunctionInvoker.java +++ b/fn-spring-cloud-function/src/main/java/com/fnproject/springframework/function/SpringCloudFunctionInvoker.java @@ -1,3 +1,19 @@ +/* + * Copyright (c) 2019, 2020 Oracle and/or its affiliates. All rights reserved. + * + * 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. + */ + package com.fnproject.springframework.function; import com.fnproject.fn.api.*; diff --git a/fn-spring-cloud-function/src/main/java/com/fnproject/springframework/function/SpringCloudFunctionLoader.java b/fn-spring-cloud-function/src/main/java/com/fnproject/springframework/function/SpringCloudFunctionLoader.java index e6a2209c..e064934a 100644 --- a/fn-spring-cloud-function/src/main/java/com/fnproject/springframework/function/SpringCloudFunctionLoader.java +++ b/fn-spring-cloud-function/src/main/java/com/fnproject/springframework/function/SpringCloudFunctionLoader.java @@ -1,3 +1,19 @@ +/* + * Copyright (c) 2019, 2020 Oracle and/or its affiliates. All rights reserved. + * + * 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. + */ + package com.fnproject.springframework.function; import com.fnproject.springframework.function.exception.SpringCloudFunctionNotFoundException; diff --git a/fn-spring-cloud-function/src/main/java/com/fnproject/springframework/function/exception/SpringCloudFunctionNotFoundException.java b/fn-spring-cloud-function/src/main/java/com/fnproject/springframework/function/exception/SpringCloudFunctionNotFoundException.java index 37c6dba7..5c5d8504 100644 --- a/fn-spring-cloud-function/src/main/java/com/fnproject/springframework/function/exception/SpringCloudFunctionNotFoundException.java +++ b/fn-spring-cloud-function/src/main/java/com/fnproject/springframework/function/exception/SpringCloudFunctionNotFoundException.java @@ -1,3 +1,19 @@ +/* + * Copyright (c) 2019, 2020 Oracle and/or its affiliates. All rights reserved. + * + * 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. + */ + package com.fnproject.springframework.function.exception; import com.fnproject.fn.api.exception.FunctionLoadException; diff --git a/fn-spring-cloud-function/src/main/java/com/fnproject/springframework/function/functions/SpringCloudConsumer.java b/fn-spring-cloud-function/src/main/java/com/fnproject/springframework/function/functions/SpringCloudConsumer.java index 720f58ae..1e635f76 100644 --- a/fn-spring-cloud-function/src/main/java/com/fnproject/springframework/function/functions/SpringCloudConsumer.java +++ b/fn-spring-cloud-function/src/main/java/com/fnproject/springframework/function/functions/SpringCloudConsumer.java @@ -1,3 +1,19 @@ +/* + * Copyright (c) 2019, 2020 Oracle and/or its affiliates. All rights reserved. + * + * 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. + */ + package com.fnproject.springframework.function.functions; import com.fnproject.fn.api.TypeWrapper; diff --git a/fn-spring-cloud-function/src/main/java/com/fnproject/springframework/function/functions/SpringCloudFunction.java b/fn-spring-cloud-function/src/main/java/com/fnproject/springframework/function/functions/SpringCloudFunction.java index dfbf40ea..57d79644 100644 --- a/fn-spring-cloud-function/src/main/java/com/fnproject/springframework/function/functions/SpringCloudFunction.java +++ b/fn-spring-cloud-function/src/main/java/com/fnproject/springframework/function/functions/SpringCloudFunction.java @@ -1,3 +1,19 @@ +/* + * Copyright (c) 2019, 2020 Oracle and/or its affiliates. All rights reserved. + * + * 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. + */ + package com.fnproject.springframework.function.functions; import org.springframework.cloud.function.context.catalog.FunctionInspector; diff --git a/fn-spring-cloud-function/src/main/java/com/fnproject/springframework/function/functions/SpringCloudMethod.java b/fn-spring-cloud-function/src/main/java/com/fnproject/springframework/function/functions/SpringCloudMethod.java index e2daffcc..c9a5f483 100644 --- a/fn-spring-cloud-function/src/main/java/com/fnproject/springframework/function/functions/SpringCloudMethod.java +++ b/fn-spring-cloud-function/src/main/java/com/fnproject/springframework/function/functions/SpringCloudMethod.java @@ -1,3 +1,19 @@ +/* + * Copyright (c) 2019, 2020 Oracle and/or its affiliates. All rights reserved. + * + * 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. + */ + package com.fnproject.springframework.function.functions; import com.fnproject.fn.api.MethodWrapper; diff --git a/fn-spring-cloud-function/src/main/java/com/fnproject/springframework/function/functions/SpringCloudSupplier.java b/fn-spring-cloud-function/src/main/java/com/fnproject/springframework/function/functions/SpringCloudSupplier.java index 52554b44..a74f6841 100644 --- a/fn-spring-cloud-function/src/main/java/com/fnproject/springframework/function/functions/SpringCloudSupplier.java +++ b/fn-spring-cloud-function/src/main/java/com/fnproject/springframework/function/functions/SpringCloudSupplier.java @@ -1,3 +1,19 @@ +/* + * Copyright (c) 2019, 2020 Oracle and/or its affiliates. All rights reserved. + * + * 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. + */ + package com.fnproject.springframework.function.functions; import com.fnproject.fn.api.TypeWrapper; diff --git a/fn-spring-cloud-function/src/test/java/com/fnproject/springframework/function/SimpleFunctionInspector.java b/fn-spring-cloud-function/src/test/java/com/fnproject/springframework/function/SimpleFunctionInspector.java index 9e52b6f1..9cd5f365 100644 --- a/fn-spring-cloud-function/src/test/java/com/fnproject/springframework/function/SimpleFunctionInspector.java +++ b/fn-spring-cloud-function/src/test/java/com/fnproject/springframework/function/SimpleFunctionInspector.java @@ -1,3 +1,19 @@ +/* + * Copyright (c) 2019, 2020 Oracle and/or its affiliates. All rights reserved. + * + * 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. + */ + package com.fnproject.springframework.function; import net.jodah.typetools.TypeResolver; diff --git a/fn-spring-cloud-function/src/test/java/com/fnproject/springframework/function/SpringCloudFunctionInvokerIntegrationTest.java b/fn-spring-cloud-function/src/test/java/com/fnproject/springframework/function/SpringCloudFunctionInvokerIntegrationTest.java index eb859b2e..1d5d0269 100644 --- a/fn-spring-cloud-function/src/test/java/com/fnproject/springframework/function/SpringCloudFunctionInvokerIntegrationTest.java +++ b/fn-spring-cloud-function/src/test/java/com/fnproject/springframework/function/SpringCloudFunctionInvokerIntegrationTest.java @@ -1,3 +1,19 @@ +/* + * Copyright (c) 2019, 2020 Oracle and/or its affiliates. All rights reserved. + * + * 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. + */ + package com.fnproject.springframework.function; import com.fnproject.fn.testing.FnTestingRule; diff --git a/fn-spring-cloud-function/src/test/java/com/fnproject/springframework/function/SpringCloudFunctionInvokerTest.java b/fn-spring-cloud-function/src/test/java/com/fnproject/springframework/function/SpringCloudFunctionInvokerTest.java index 0ed3b1fa..64fa2c16 100644 --- a/fn-spring-cloud-function/src/test/java/com/fnproject/springframework/function/SpringCloudFunctionInvokerTest.java +++ b/fn-spring-cloud-function/src/test/java/com/fnproject/springframework/function/SpringCloudFunctionInvokerTest.java @@ -1,3 +1,19 @@ +/* + * Copyright (c) 2019, 2020 Oracle and/or its affiliates. All rights reserved. + * + * 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. + */ + package com.fnproject.springframework.function; import com.fnproject.springframework.function.functions.SpringCloudFunction; diff --git a/fn-spring-cloud-function/src/test/java/com/fnproject/springframework/function/SpringCloudFunctionLoaderTest.java b/fn-spring-cloud-function/src/test/java/com/fnproject/springframework/function/SpringCloudFunctionLoaderTest.java index 6e2bbf02..20c2b1a9 100644 --- a/fn-spring-cloud-function/src/test/java/com/fnproject/springframework/function/SpringCloudFunctionLoaderTest.java +++ b/fn-spring-cloud-function/src/test/java/com/fnproject/springframework/function/SpringCloudFunctionLoaderTest.java @@ -1,3 +1,19 @@ +/* + * Copyright (c) 2019, 2020 Oracle and/or its affiliates. All rights reserved. + * + * 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. + */ + package com.fnproject.springframework.function; import com.fnproject.springframework.function.functions.SpringCloudMethod; diff --git a/fn-spring-cloud-function/src/test/java/com/fnproject/springframework/function/testfns/EmptyFunctionConfig.java b/fn-spring-cloud-function/src/test/java/com/fnproject/springframework/function/testfns/EmptyFunctionConfig.java index 0f650d22..50b8b09c 100644 --- a/fn-spring-cloud-function/src/test/java/com/fnproject/springframework/function/testfns/EmptyFunctionConfig.java +++ b/fn-spring-cloud-function/src/test/java/com/fnproject/springframework/function/testfns/EmptyFunctionConfig.java @@ -1,3 +1,19 @@ +/* + * Copyright (c) 2019, 2020 Oracle and/or its affiliates. All rights reserved. + * + * 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. + */ + package com.fnproject.springframework.function.testfns; import com.fnproject.fn.api.FnConfiguration; diff --git a/fn-spring-cloud-function/src/test/java/com/fnproject/springframework/function/testfns/FunctionConfig.java b/fn-spring-cloud-function/src/test/java/com/fnproject/springframework/function/testfns/FunctionConfig.java index fb8dbeb7..ea24cdc9 100644 --- a/fn-spring-cloud-function/src/test/java/com/fnproject/springframework/function/testfns/FunctionConfig.java +++ b/fn-spring-cloud-function/src/test/java/com/fnproject/springframework/function/testfns/FunctionConfig.java @@ -1,3 +1,19 @@ +/* + * Copyright (c) 2019, 2020 Oracle and/or its affiliates. All rights reserved. + * + * 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. + */ + package com.fnproject.springframework.function.testfns; import com.fnproject.fn.api.FnConfiguration; diff --git a/images/build-native/Dockerfile b/images/build-native/Dockerfile index a11af5d9..b3b85db4 100644 --- a/images/build-native/Dockerfile +++ b/images/build-native/Dockerfile @@ -1,3 +1,19 @@ +# +# Copyright (c) 2019, 2020 Oracle and/or its affiliates. All rights reserved. +# +# 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. +# + FROM debian:buster-slim as build RUN set -x \ diff --git a/images/build-native/Dockerfile-jdk11 b/images/build-native/Dockerfile-jdk11 index 81231419..64dbe26c 100644 --- a/images/build-native/Dockerfile-jdk11 +++ b/images/build-native/Dockerfile-jdk11 @@ -1,3 +1,19 @@ +# +# Copyright (c) 2019, 2020 Oracle and/or its affiliates. All rights reserved. +# +# 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. +# + FROM debian:buster-slim as build RUN set -x \ diff --git a/images/build-native/docker-build.sh b/images/build-native/docker-build.sh index 3ea15fb5..01f2987c 100755 --- a/images/build-native/docker-build.sh +++ b/images/build-native/docker-build.sh @@ -1,4 +1,20 @@ #!/bin/sh +# +# Copyright (c) 2019, 2020 Oracle and/or its affiliates. All rights reserved. +# +# 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. +# + if [ -z "$1" ] then echo "Needs runtime folder as an argument" diff --git a/images/build/Dockerfile b/images/build/Dockerfile index 38424406..398d8540 100644 --- a/images/build/Dockerfile +++ b/images/build/Dockerfile @@ -1,3 +1,19 @@ +# +# Copyright (c) 2019, 2020 Oracle and/or its affiliates. All rights reserved. +# +# 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. +# + FROM maven:3-jdk-8-slim ARG FN_REPO_URL ADD pom.xml /tmp/cache-deps/pom.xml diff --git a/images/build/Dockerfile-jdk11 b/images/build/Dockerfile-jdk11 index e8b96ddc..dac01823 100644 --- a/images/build/Dockerfile-jdk11 +++ b/images/build/Dockerfile-jdk11 @@ -1,3 +1,19 @@ +# +# Copyright (c) 2019, 2020 Oracle and/or its affiliates. All rights reserved. +# +# 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. +# + FROM maven:3-jdk-11-slim ARG FN_REPO_URL diff --git a/images/build/cache-deps.sh b/images/build/cache-deps.sh index 4a8a7eeb..784fefb8 100755 --- a/images/build/cache-deps.sh +++ b/images/build/cache-deps.sh @@ -1,4 +1,20 @@ #!/bin/bash -ex +# +# Copyright (c) 2019, 2020 Oracle and/or its affiliates. All rights reserved. +# +# 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. +# + set -x set -e diff --git a/images/build/docker-build.sh b/images/build/docker-build.sh index c8685a89..eaa78a5e 100755 --- a/images/build/docker-build.sh +++ b/images/build/docker-build.sh @@ -1,4 +1,20 @@ #!/bin/bash -ex +# +# Copyright (c) 2019, 2020 Oracle and/or its affiliates. All rights reserved. +# +# 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. +# + if [ -z ${REPOSITORY_LOCATION} ] ; then echo no REPOSITORY_LOCATION set exit 1; diff --git a/images/build/pom.xml b/images/build/pom.xml index 0a5ab9ad..c28fcf94 100644 --- a/images/build/pom.xml +++ b/images/build/pom.xml @@ -1,4 +1,22 @@ + + diff --git a/images/build/src/main/java/com/example/fn/HelloFunction.java b/images/build/src/main/java/com/example/fn/HelloFunction.java index 8c581e76..e1b10b7a 100644 --- a/images/build/src/main/java/com/example/fn/HelloFunction.java +++ b/images/build/src/main/java/com/example/fn/HelloFunction.java @@ -1,3 +1,19 @@ +/* + * Copyright (c) 2019, 2020 Oracle and/or its affiliates. All rights reserved. + * + * 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. + */ + package com.example.fn; public class HelloFunction { diff --git a/images/build/src/test/java/com/example/fn/HelloFunctionTest.java b/images/build/src/test/java/com/example/fn/HelloFunctionTest.java index ee9f2a1f..a5da7b66 100644 --- a/images/build/src/test/java/com/example/fn/HelloFunctionTest.java +++ b/images/build/src/test/java/com/example/fn/HelloFunctionTest.java @@ -1,3 +1,19 @@ +/* + * Copyright (c) 2019, 2020 Oracle and/or its affiliates. All rights reserved. + * + * 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. + */ + package com.example.fn; import com.fnproject.fn.testing.FnResult; diff --git a/images/init-native/Dockerfile b/images/init-native/Dockerfile index ef9e608b..25e078e6 100644 --- a/images/init-native/Dockerfile +++ b/images/init-native/Dockerfile @@ -1,3 +1,19 @@ +# +# Copyright (c) 2019, 2020 Oracle and/or its affiliates. All rights reserved. +# +# 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. +# + FROM fnproject/fn-java-fdk-build:latest as build WORKDIR /function ENV MAVEN_OPTS=-Dmaven.repo.local=/usr/share/maven/ref/repository diff --git a/images/init-native/Dockerfile-init-image b/images/init-native/Dockerfile-init-image index 5c899bfb..2e349735 100644 --- a/images/init-native/Dockerfile-init-image +++ b/images/init-native/Dockerfile-init-image @@ -1,3 +1,19 @@ +# +# Copyright (c) 2019, 2020 Oracle and/or its affiliates. All rights reserved. +# +# 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. +# + FROM alpine:latest WORKDIR /build diff --git a/images/init-native/docker-build.sh b/images/init-native/docker-build.sh index 36a59caa..f2850812 100755 --- a/images/init-native/docker-build.sh +++ b/images/init-native/docker-build.sh @@ -1,4 +1,20 @@ #!/bin/sh +# +# Copyright (c) 2019, 2020 Oracle and/or its affiliates. All rights reserved. +# +# 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. +# + if [ -z "${FN_FDK_VERSION}" ]; then FN_FDK_VERSION=$(cat ../../release.version) fi diff --git a/images/init-native/func.init.yaml b/images/init-native/func.init.yaml index e69de29b..4d0c5b62 100644 --- a/images/init-native/func.init.yaml +++ b/images/init-native/func.init.yaml @@ -0,0 +1,16 @@ +# +# Copyright (c) 2019, 2020 Oracle and/or its affiliates. All rights reserved. +# +# 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. +# + diff --git a/images/init-native/pom.xml b/images/init-native/pom.xml index 4d8e2703..d4436461 100644 --- a/images/init-native/pom.xml +++ b/images/init-native/pom.xml @@ -1,4 +1,22 @@ + + diff --git a/images/init-native/src/main/java/com/example/fn/HelloFunction.java b/images/init-native/src/main/java/com/example/fn/HelloFunction.java index 8c581e76..e1b10b7a 100644 --- a/images/init-native/src/main/java/com/example/fn/HelloFunction.java +++ b/images/init-native/src/main/java/com/example/fn/HelloFunction.java @@ -1,3 +1,19 @@ +/* + * Copyright (c) 2019, 2020 Oracle and/or its affiliates. All rights reserved. + * + * 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. + */ + package com.example.fn; public class HelloFunction { diff --git a/images/init-native/src/test/java/com/example/fn/HelloFunctionTest.java b/images/init-native/src/test/java/com/example/fn/HelloFunctionTest.java index e6b7a5e3..4bf9a72f 100644 --- a/images/init-native/src/test/java/com/example/fn/HelloFunctionTest.java +++ b/images/init-native/src/test/java/com/example/fn/HelloFunctionTest.java @@ -1,3 +1,19 @@ +/* + * Copyright (c) 2019, 2020 Oracle and/or its affiliates. All rights reserved. + * + * 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. + */ + package com.example.fn; import com.fnproject.fn.testing.*; diff --git a/images/runtime/Dockerfile b/images/runtime/Dockerfile index bdad842f..d14e990f 100644 --- a/images/runtime/Dockerfile +++ b/images/runtime/Dockerfile @@ -1,3 +1,19 @@ +# +# Copyright (c) 2019, 2020 Oracle and/or its affiliates. All rights reserved. +# +# 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. +# + FROM openjdk:8-jre-slim COPY target/runtime-*.jar target/dependency/*.jar /function/runtime/ COPY src/main/c/libfnunixsocket.so /function/runtime/lib/ diff --git a/images/runtime/Dockerfile-jre11 b/images/runtime/Dockerfile-jre11 index 2f704297..ea8391c6 100644 --- a/images/runtime/Dockerfile-jre11 +++ b/images/runtime/Dockerfile-jre11 @@ -1,3 +1,19 @@ +# +# Copyright (c) 2019, 2020 Oracle and/or its affiliates. All rights reserved. +# +# 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. +# + FROM openjdk:11-jre-slim COPY target/runtime-*.jar target/dependency/*.jar /function/runtime/ COPY src/main/c/libfnunixsocket.so /function/runtime/lib/ diff --git a/infra/provision/Jenkinsfile b/infra/provision/Jenkinsfile index 98d1f423..02fdc8c4 100644 --- a/infra/provision/Jenkinsfile +++ b/infra/provision/Jenkinsfile @@ -1,3 +1,19 @@ +/* + * Copyright (c) 2019, 2020 Oracle and/or its affiliates. All rights reserved. + * + * 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. + */ + pipeline { agent any diff --git a/infra/provision/completer-integration-environment.yaml b/infra/provision/completer-integration-environment.yaml index b95b2b15..7ba3caaa 100644 --- a/infra/provision/completer-integration-environment.yaml +++ b/infra/provision/completer-integration-environment.yaml @@ -1,3 +1,19 @@ +# +# Copyright (c) 2019, 2020 Oracle and/or its affiliates. All rights reserved. +# +# 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. +# + # This is run once, at cluster creation time. It creates and sets up the # components of the flow service, and assumes that the functions service # is already provisioned from: diff --git a/infra/provision/create-k8s-entities.sh b/infra/provision/create-k8s-entities.sh index 291abf11..070ce154 100755 --- a/infra/provision/create-k8s-entities.sh +++ b/infra/provision/create-k8s-entities.sh @@ -1,4 +1,20 @@ #!/bin/bash +# +# Copyright (c) 2019, 2020 Oracle and/or its affiliates. All rights reserved. +# +# 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. +# + PROVISION_DIR=$1 FUNCTIONS_SERVICE_DIR=$2 diff --git a/infra/provision/delete-k8s-entities.sh b/infra/provision/delete-k8s-entities.sh index cef836df..c2b2238b 100755 --- a/infra/provision/delete-k8s-entities.sh +++ b/infra/provision/delete-k8s-entities.sh @@ -1,4 +1,20 @@ #!/bin/bash +# +# Copyright (c) 2019, 2020 Oracle and/or its affiliates. All rights reserved. +# +# 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. +# + PROVISION_DIR=$1 FUNCTIONS_SERVICE_DIR=$2 diff --git a/infra/provision/registry.yaml b/infra/provision/registry.yaml index 1bd9cdd0..c1b1172a 100644 --- a/infra/provision/registry.yaml +++ b/infra/provision/registry.yaml @@ -1,3 +1,19 @@ +# +# Copyright (c) 2019, 2020 Oracle and/or its affiliates. All rights reserved. +# +# 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. +# + # This is run once, at cluster creation time and it creates a deployment and a # service based on the latest functions image. # diff --git a/infra/provision/validate-functions-files.sh b/infra/provision/validate-functions-files.sh index b997208d..83668022 100755 --- a/infra/provision/validate-functions-files.sh +++ b/infra/provision/validate-functions-files.sh @@ -1,4 +1,20 @@ #!/bin/bash +# +# Copyright (c) 2019, 2020 Oracle and/or its affiliates. All rights reserved. +# +# 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. +# + FUNCTIONS_SERVICE_DIR=$1 set -ex diff --git a/infra/update/functions/Jenkinsfile b/infra/update/functions/Jenkinsfile index 8162ef57..7ba6c01f 100644 --- a/infra/update/functions/Jenkinsfile +++ b/infra/update/functions/Jenkinsfile @@ -1,3 +1,19 @@ +/* + * Copyright (c) 2019, 2020 Oracle and/or its affiliates. All rights reserved. + * + * 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. + */ + pipeline { agent any parameters { diff --git a/integration-tests/funcs/flowAllFeatures/func.yaml b/integration-tests/funcs/flowAllFeatures/func.yaml index 9a41741c..20d9e86a 100644 --- a/integration-tests/funcs/flowAllFeatures/func.yaml +++ b/integration-tests/funcs/flowAllFeatures/func.yaml @@ -1,3 +1,19 @@ +# +# Copyright (c) 2019, 2020 Oracle and/or its affiliates. All rights reserved. +# +# 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. +# + schema_version: 20180708 name: flowallfeatures version: 0.0.15 diff --git a/integration-tests/funcs/flowAllFeatures/pom.xml b/integration-tests/funcs/flowAllFeatures/pom.xml index 1796dc28..4bcd99e1 100644 --- a/integration-tests/funcs/flowAllFeatures/pom.xml +++ b/integration-tests/funcs/flowAllFeatures/pom.xml @@ -1,4 +1,22 @@ + + diff --git a/integration-tests/funcs/flowAllFeatures/src/main/java/com/fnproject/fn/integration/ExerciseEverything.java b/integration-tests/funcs/flowAllFeatures/src/main/java/com/fnproject/fn/integration/ExerciseEverything.java index 55d12da3..b5f2b36c 100644 --- a/integration-tests/funcs/flowAllFeatures/src/main/java/com/fnproject/fn/integration/ExerciseEverything.java +++ b/integration-tests/funcs/flowAllFeatures/src/main/java/com/fnproject/fn/integration/ExerciseEverything.java @@ -1,3 +1,19 @@ +/* + * Copyright (c) 2019, 2020 Oracle and/or its affiliates. All rights reserved. + * + * 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. + */ + package com.fnproject.fn.integration; import com.fnproject.fn.api.FnFeature; diff --git a/integration-tests/funcs/flowAllFeatures/src/main/java/com/fnproject/fn/integration/Test.java b/integration-tests/funcs/flowAllFeatures/src/main/java/com/fnproject/fn/integration/Test.java index 46380a7c..5e71649b 100644 --- a/integration-tests/funcs/flowAllFeatures/src/main/java/com/fnproject/fn/integration/Test.java +++ b/integration-tests/funcs/flowAllFeatures/src/main/java/com/fnproject/fn/integration/Test.java @@ -1,3 +1,19 @@ +/* + * Copyright (c) 2019, 2020 Oracle and/or its affiliates. All rights reserved. + * + * 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. + */ + package com.fnproject.fn.integration; import java.lang.annotation.Repeatable; diff --git a/integration-tests/funcs/flowBasic/func.yaml b/integration-tests/funcs/flowBasic/func.yaml index 6022a127..c9f6f3bc 100644 --- a/integration-tests/funcs/flowBasic/func.yaml +++ b/integration-tests/funcs/flowBasic/func.yaml @@ -1,3 +1,19 @@ +# +# Copyright (c) 2019, 2020 Oracle and/or its affiliates. All rights reserved. +# +# 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. +# + schema_version: 20180708 name: flowbasic version: 0.0.7 diff --git a/integration-tests/funcs/flowBasic/pom.xml b/integration-tests/funcs/flowBasic/pom.xml index 6cac356e..18642b39 100644 --- a/integration-tests/funcs/flowBasic/pom.xml +++ b/integration-tests/funcs/flowBasic/pom.xml @@ -1,4 +1,22 @@ + + diff --git a/integration-tests/funcs/flowBasic/src/main/java/com/fnproject/fn/integration/test_1/CompleterFunction.java b/integration-tests/funcs/flowBasic/src/main/java/com/fnproject/fn/integration/test_1/CompleterFunction.java index 0740d8ba..2cf9161c 100644 --- a/integration-tests/funcs/flowBasic/src/main/java/com/fnproject/fn/integration/test_1/CompleterFunction.java +++ b/integration-tests/funcs/flowBasic/src/main/java/com/fnproject/fn/integration/test_1/CompleterFunction.java @@ -1,3 +1,19 @@ +/* + * Copyright (c) 2019, 2020 Oracle and/or its affiliates. All rights reserved. + * + * 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. + */ + package com.fnproject.fn.integration.test_1; import com.fnproject.fn.api.FnFeature; diff --git a/integration-tests/funcs/flowBasicJDK8/func.yaml b/integration-tests/funcs/flowBasicJDK8/func.yaml index 143565c7..af6328d2 100644 --- a/integration-tests/funcs/flowBasicJDK8/func.yaml +++ b/integration-tests/funcs/flowBasicJDK8/func.yaml @@ -1,3 +1,19 @@ +# +# Copyright (c) 2019, 2020 Oracle and/or its affiliates. All rights reserved. +# +# 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. +# + schema_version: 20180708 name: flowbasicj8 version: 0.0.3 diff --git a/integration-tests/funcs/flowBasicJDK8/pom.xml b/integration-tests/funcs/flowBasicJDK8/pom.xml index e674247f..717b8b9a 100644 --- a/integration-tests/funcs/flowBasicJDK8/pom.xml +++ b/integration-tests/funcs/flowBasicJDK8/pom.xml @@ -1,4 +1,22 @@ + + diff --git a/integration-tests/funcs/flowBasicJDK8/src/main/java/com/fnproject/fn/integration/test_1/CompleterFunction.java b/integration-tests/funcs/flowBasicJDK8/src/main/java/com/fnproject/fn/integration/test_1/CompleterFunction.java index 0740d8ba..2cf9161c 100644 --- a/integration-tests/funcs/flowBasicJDK8/src/main/java/com/fnproject/fn/integration/test_1/CompleterFunction.java +++ b/integration-tests/funcs/flowBasicJDK8/src/main/java/com/fnproject/fn/integration/test_1/CompleterFunction.java @@ -1,3 +1,19 @@ +/* + * Copyright (c) 2019, 2020 Oracle and/or its affiliates. All rights reserved. + * + * 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. + */ + package com.fnproject.fn.integration.test_1; import com.fnproject.fn.api.FnFeature; diff --git a/integration-tests/funcs/flowExitHooks/func.yaml b/integration-tests/funcs/flowExitHooks/func.yaml index 52034a1e..3c55914e 100644 --- a/integration-tests/funcs/flowExitHooks/func.yaml +++ b/integration-tests/funcs/flowExitHooks/func.yaml @@ -1,3 +1,19 @@ +# +# Copyright (c) 2019, 2020 Oracle and/or its affiliates. All rights reserved. +# +# 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. +# + schema_version: 20180708 name: flowexithooks version: 0.0.3 diff --git a/integration-tests/funcs/flowExitHooks/pom.xml b/integration-tests/funcs/flowExitHooks/pom.xml index 2b9bc0f7..fa0e4163 100644 --- a/integration-tests/funcs/flowExitHooks/pom.xml +++ b/integration-tests/funcs/flowExitHooks/pom.xml @@ -1,4 +1,22 @@ + + diff --git a/integration-tests/funcs/flowExitHooks/src/main/java/com/fnproject/fn/integration/test_5/CompleterFunction.java b/integration-tests/funcs/flowExitHooks/src/main/java/com/fnproject/fn/integration/test_5/CompleterFunction.java index 57c0c0ce..8d4c96bc 100644 --- a/integration-tests/funcs/flowExitHooks/src/main/java/com/fnproject/fn/integration/test_5/CompleterFunction.java +++ b/integration-tests/funcs/flowExitHooks/src/main/java/com/fnproject/fn/integration/test_5/CompleterFunction.java @@ -1,3 +1,19 @@ +/* + * Copyright (c) 2019, 2020 Oracle and/or its affiliates. All rights reserved. + * + * 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. + */ + package com.fnproject.fn.integration.test_5; import com.fnproject.fn.api.FnFeature; diff --git a/integration-tests/funcs/flowTimeouts/func.yaml b/integration-tests/funcs/flowTimeouts/func.yaml index 6d83f8ec..cc694a91 100644 --- a/integration-tests/funcs/flowTimeouts/func.yaml +++ b/integration-tests/funcs/flowTimeouts/func.yaml @@ -1,3 +1,19 @@ +# +# Copyright (c) 2019, 2020 Oracle and/or its affiliates. All rights reserved. +# +# 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. +# + schema_version: 20180708 name: flowtimeouts version: 0.0.3 diff --git a/integration-tests/funcs/flowTimeouts/pom.xml b/integration-tests/funcs/flowTimeouts/pom.xml index 011e9853..46df8cb3 100644 --- a/integration-tests/funcs/flowTimeouts/pom.xml +++ b/integration-tests/funcs/flowTimeouts/pom.xml @@ -1,4 +1,22 @@ + + diff --git a/integration-tests/funcs/flowTimeouts/src/main/java/com/fnproject/fn/integration/test_6/CompleterFunction.java b/integration-tests/funcs/flowTimeouts/src/main/java/com/fnproject/fn/integration/test_6/CompleterFunction.java index bb603493..f6f2b301 100644 --- a/integration-tests/funcs/flowTimeouts/src/main/java/com/fnproject/fn/integration/test_6/CompleterFunction.java +++ b/integration-tests/funcs/flowTimeouts/src/main/java/com/fnproject/fn/integration/test_6/CompleterFunction.java @@ -1,3 +1,19 @@ +/* + * Copyright (c) 2019, 2020 Oracle and/or its affiliates. All rights reserved. + * + * 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. + */ + package com.fnproject.fn.integration.test_6; import com.fnproject.fn.api.FnFeature; diff --git a/integration-tests/funcs/helloFunc/func-proto.yaml b/integration-tests/funcs/helloFunc/func-proto.yaml index e43cf9f4..63a5398b 100644 --- a/integration-tests/funcs/helloFunc/func-proto.yaml +++ b/integration-tests/funcs/helloFunc/func-proto.yaml @@ -1,3 +1,19 @@ +# +# Copyright (c) 2019, 2020 Oracle and/or its affiliates. All rights reserved. +# +# 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. +# + schema_version: 20180708 name: hellofunc version: 0.0.1 diff --git a/integration-tests/funcs/helloFunc/pom.xml b/integration-tests/funcs/helloFunc/pom.xml index f53da8dd..d95f6c38 100644 --- a/integration-tests/funcs/helloFunc/pom.xml +++ b/integration-tests/funcs/helloFunc/pom.xml @@ -1,4 +1,22 @@ + + diff --git a/integration-tests/funcs/helloFunc/src-proto/main/java/com/fnproject/fn/integration/hello/HelloFunction.java b/integration-tests/funcs/helloFunc/src-proto/main/java/com/fnproject/fn/integration/hello/HelloFunction.java index 7efa98ab..409a42e0 100644 --- a/integration-tests/funcs/helloFunc/src-proto/main/java/com/fnproject/fn/integration/hello/HelloFunction.java +++ b/integration-tests/funcs/helloFunc/src-proto/main/java/com/fnproject/fn/integration/hello/HelloFunction.java @@ -1,3 +1,19 @@ +/* + * Copyright (c) 2019, 2020 Oracle and/or its affiliates. All rights reserved. + * + * 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. + */ + package com.fnproject.fn.integration.hello; public class HelloFunction { diff --git a/integration-tests/funcs/httpgwfunc/func.yaml b/integration-tests/funcs/httpgwfunc/func.yaml index 8380eb34..af45f447 100644 --- a/integration-tests/funcs/httpgwfunc/func.yaml +++ b/integration-tests/funcs/httpgwfunc/func.yaml @@ -1,3 +1,19 @@ +# +# Copyright (c) 2019, 2020 Oracle and/or its affiliates. All rights reserved. +# +# 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. +# + schema_version: 20180708 name: httpgwfunc version: 0.0.1 diff --git a/integration-tests/funcs/httpgwfunc/pom.xml b/integration-tests/funcs/httpgwfunc/pom.xml index 28d3df65..18737290 100644 --- a/integration-tests/funcs/httpgwfunc/pom.xml +++ b/integration-tests/funcs/httpgwfunc/pom.xml @@ -1,4 +1,22 @@ + + diff --git a/integration-tests/funcs/httpgwfunc/src/main/java/com/example/fn/TriggerFunction.java b/integration-tests/funcs/httpgwfunc/src/main/java/com/example/fn/TriggerFunction.java index 4d45661f..09426c54 100644 --- a/integration-tests/funcs/httpgwfunc/src/main/java/com/example/fn/TriggerFunction.java +++ b/integration-tests/funcs/httpgwfunc/src/main/java/com/example/fn/TriggerFunction.java @@ -1,3 +1,19 @@ +/* + * Copyright (c) 2019, 2020 Oracle and/or its affiliates. All rights reserved. + * + * 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. + */ + package com.example.fn; import com.fnproject.fn.api.InvocationContext; diff --git a/integration-tests/funcs/httpgwfunc/src/test/java/com/example/fn/TriggerFunctionTest.java b/integration-tests/funcs/httpgwfunc/src/test/java/com/example/fn/TriggerFunctionTest.java index 2c46f1e8..4dea0c13 100644 --- a/integration-tests/funcs/httpgwfunc/src/test/java/com/example/fn/TriggerFunctionTest.java +++ b/integration-tests/funcs/httpgwfunc/src/test/java/com/example/fn/TriggerFunctionTest.java @@ -1,3 +1,19 @@ +/* + * Copyright (c) 2019, 2020 Oracle and/or its affiliates. All rights reserved. + * + * 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. + */ + package com.example.fn; import com.fnproject.fn.testing.FnResult; diff --git a/integration-tests/funcs/simpleFunc/func.yaml b/integration-tests/funcs/simpleFunc/func.yaml index c0c9c79b..f6533e4b 100644 --- a/integration-tests/funcs/simpleFunc/func.yaml +++ b/integration-tests/funcs/simpleFunc/func.yaml @@ -1,3 +1,19 @@ +# +# Copyright (c) 2019, 2020 Oracle and/or its affiliates. All rights reserved. +# +# 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. +# + schema_version: 20180708 name: simplefunc version: 0.0.3 diff --git a/integration-tests/funcs/simpleFunc/pom.xml b/integration-tests/funcs/simpleFunc/pom.xml index 60e2ab1c..d02a960c 100644 --- a/integration-tests/funcs/simpleFunc/pom.xml +++ b/integration-tests/funcs/simpleFunc/pom.xml @@ -1,4 +1,22 @@ + + diff --git a/integration-tests/funcs/simpleFunc/src/main/java/com/fnproject/fn/integration/test2/PlainFunction.java b/integration-tests/funcs/simpleFunc/src/main/java/com/fnproject/fn/integration/test2/PlainFunction.java index 60aeff69..6b769602 100644 --- a/integration-tests/funcs/simpleFunc/src/main/java/com/fnproject/fn/integration/test2/PlainFunction.java +++ b/integration-tests/funcs/simpleFunc/src/main/java/com/fnproject/fn/integration/test2/PlainFunction.java @@ -1,3 +1,19 @@ +/* + * Copyright (c) 2019, 2020 Oracle and/or its affiliates. All rights reserved. + * + * 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. + */ + package com.fnproject.fn.integration.test2; import com.fnproject.fn.api.FnConfiguration; diff --git a/integration-tests/funcs/simpleFunc/src/test/java/com/fnproject/fn/integration/test2/PlainFunctionTest.java b/integration-tests/funcs/simpleFunc/src/test/java/com/fnproject/fn/integration/test2/PlainFunctionTest.java index bdc91fd2..501b6bcb 100644 --- a/integration-tests/funcs/simpleFunc/src/test/java/com/fnproject/fn/integration/test2/PlainFunctionTest.java +++ b/integration-tests/funcs/simpleFunc/src/test/java/com/fnproject/fn/integration/test2/PlainFunctionTest.java @@ -1,3 +1,19 @@ +/* + * Copyright (c) 2019, 2020 Oracle and/or its affiliates. All rights reserved. + * + * 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. + */ + package com.fnproject.fn.integration.test2; import com.fnproject.fn.testing.FnResult; diff --git a/integration-tests/pom.xml b/integration-tests/pom.xml index 1903493a..22b83ee7 100644 --- a/integration-tests/pom.xml +++ b/integration-tests/pom.xml @@ -1,4 +1,22 @@ + + diff --git a/integration-tests/run_tests_ci.sh b/integration-tests/run_tests_ci.sh index 21145e79..1d9fac50 100755 --- a/integration-tests/run_tests_ci.sh +++ b/integration-tests/run_tests_ci.sh @@ -1,4 +1,20 @@ #!/usr/bin/env bash +# +# Copyright (c) 2019, 2020 Oracle and/or its affiliates. All rights reserved. +# +# 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. +# + set -e set -x diff --git a/integration-tests/src/main/java/com/fnproject/fn/integrationtest/IntegrationTestRule.java b/integration-tests/src/main/java/com/fnproject/fn/integrationtest/IntegrationTestRule.java index ed2463f8..abe6b243 100644 --- a/integration-tests/src/main/java/com/fnproject/fn/integrationtest/IntegrationTestRule.java +++ b/integration-tests/src/main/java/com/fnproject/fn/integrationtest/IntegrationTestRule.java @@ -1,3 +1,19 @@ +/* + * Copyright (c) 2019, 2020 Oracle and/or its affiliates. All rights reserved. + * + * 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. + */ + package com.fnproject.fn.integrationtest; import org.apache.commons.io.FileUtils; diff --git a/integration-tests/src/test/java/com/fnproject/fn/integrationtest/FlowTest.java b/integration-tests/src/test/java/com/fnproject/fn/integrationtest/FlowTest.java index 45dd0bc9..59a8938b 100644 --- a/integration-tests/src/test/java/com/fnproject/fn/integrationtest/FlowTest.java +++ b/integration-tests/src/test/java/com/fnproject/fn/integrationtest/FlowTest.java @@ -1,3 +1,19 @@ +/* + * Copyright (c) 2019, 2020 Oracle and/or its affiliates. All rights reserved. + * + * 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. + */ + package com.fnproject.fn.integrationtest; import com.fnproject.fn.integrationtest.IntegrationTestRule.CmdResult; diff --git a/integration-tests/src/test/java/com/fnproject/fn/integrationtest/FunctionsTest.java b/integration-tests/src/test/java/com/fnproject/fn/integrationtest/FunctionsTest.java index eb09f7de..2d64d06d 100644 --- a/integration-tests/src/test/java/com/fnproject/fn/integrationtest/FunctionsTest.java +++ b/integration-tests/src/test/java/com/fnproject/fn/integrationtest/FunctionsTest.java @@ -1,3 +1,19 @@ +/* + * Copyright (c) 2019, 2020 Oracle and/or its affiliates. All rights reserved. + * + * 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. + */ + package com.fnproject.fn.integrationtest; import java.net.HttpURLConnection; diff --git a/pom.xml b/pom.xml index 5dd36cc0..155ac254 100644 --- a/pom.xml +++ b/pom.xml @@ -1,4 +1,22 @@ + + diff --git a/runtime/pom.xml b/runtime/pom.xml index 3a87f28d..75674e9a 100644 --- a/runtime/pom.xml +++ b/runtime/pom.xml @@ -1,4 +1,22 @@ + + diff --git a/runtime/smith.yaml b/runtime/smith.yaml index 707b88a4..91aa5168 100644 --- a/runtime/smith.yaml +++ b/runtime/smith.yaml @@ -1,3 +1,19 @@ +# +# Copyright (c) 2019, 2020 Oracle and/or its affiliates. All rights reserved. +# +# 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. +# + package: https://registry-1.docker.io/library/openjdk:8-slim type: oci paths: diff --git a/runtime/src/main/c/Dockerfile-buildimage b/runtime/src/main/c/Dockerfile-buildimage index 7cd37f95..bab55644 100644 --- a/runtime/src/main/c/Dockerfile-buildimage +++ b/runtime/src/main/c/Dockerfile-buildimage @@ -1,3 +1,19 @@ +# +# Copyright (c) 2019, 2020 Oracle and/or its affiliates. All rights reserved. +# +# 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. +# + FROM oraclelinux:7.5 RUN yum install -y gcc cmake java-1.8.0-openjdk-devel.x86_64 make diff --git a/runtime/src/main/c/buildit.sh b/runtime/src/main/c/buildit.sh index 09958c0a..c5af89ea 100755 --- a/runtime/src/main/c/buildit.sh +++ b/runtime/src/main/c/buildit.sh @@ -1,4 +1,20 @@ #!/usr/bin/env bash +# +# Copyright (c) 2019, 2020 Oracle and/or its affiliates. All rights reserved. +# +# 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. +# + set -e src_dir=$(pwd) diff --git a/runtime/src/main/c/rebuild_so.sh b/runtime/src/main/c/rebuild_so.sh index 05c6edfd..90be5534 100755 --- a/runtime/src/main/c/rebuild_so.sh +++ b/runtime/src/main/c/rebuild_so.sh @@ -1,5 +1,19 @@ #!/usr/bin/env bash - +# +# Copyright (c) 2019, 2020 Oracle and/or its affiliates. All rights reserved. +# +# 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. +# mydir=$(cd "$(dirname "$0")"; pwd) cd ${mydir} diff --git a/runtime/src/main/c/unix_socket.c b/runtime/src/main/c/unix_socket.c index f773d715..18952c44 100644 --- a/runtime/src/main/c/unix_socket.c +++ b/runtime/src/main/c/unix_socket.c @@ -1,3 +1,19 @@ +/* + * Copyright (c) 2019, 2020 Oracle and/or its affiliates. All rights reserved. + * + * 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. + */ + #include #include diff --git a/runtime/src/main/java-filtered/com/fnproject/fn/runtime/Version.java b/runtime/src/main/java-filtered/com/fnproject/fn/runtime/Version.java index 48b07c8a..1872aa4c 100644 --- a/runtime/src/main/java-filtered/com/fnproject/fn/runtime/Version.java +++ b/runtime/src/main/java-filtered/com/fnproject/fn/runtime/Version.java @@ -1,3 +1,19 @@ +/* + * Copyright (c) 2019, 2020 Oracle and/or its affiliates. All rights reserved. + * + * 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. + */ + package com.fnproject.fn.runtime; /** diff --git a/runtime/src/main/java/com/fnproject/fn/runtime/DefaultMethodWrapper.java b/runtime/src/main/java/com/fnproject/fn/runtime/DefaultMethodWrapper.java index 98a61a2c..4a5a7e41 100644 --- a/runtime/src/main/java/com/fnproject/fn/runtime/DefaultMethodWrapper.java +++ b/runtime/src/main/java/com/fnproject/fn/runtime/DefaultMethodWrapper.java @@ -1,3 +1,19 @@ +/* + * Copyright (c) 2019, 2020 Oracle and/or its affiliates. All rights reserved. + * + * 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. + */ + package com.fnproject.fn.runtime; import com.fnproject.fn.api.MethodWrapper; diff --git a/runtime/src/main/java/com/fnproject/fn/runtime/EntryPoint.java b/runtime/src/main/java/com/fnproject/fn/runtime/EntryPoint.java index c9fa4523..1e9f739e 100644 --- a/runtime/src/main/java/com/fnproject/fn/runtime/EntryPoint.java +++ b/runtime/src/main/java/com/fnproject/fn/runtime/EntryPoint.java @@ -1,3 +1,19 @@ +/* + * Copyright (c) 2019, 2020 Oracle and/or its affiliates. All rights reserved. + * + * 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. + */ + package com.fnproject.fn.runtime; diff --git a/runtime/src/main/java/com/fnproject/fn/runtime/EventCodec.java b/runtime/src/main/java/com/fnproject/fn/runtime/EventCodec.java index 9a7a9885..1f3c46e8 100644 --- a/runtime/src/main/java/com/fnproject/fn/runtime/EventCodec.java +++ b/runtime/src/main/java/com/fnproject/fn/runtime/EventCodec.java @@ -1,3 +1,19 @@ +/* + * Copyright (c) 2019, 2020 Oracle and/or its affiliates. All rights reserved. + * + * 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. + */ + package com.fnproject.fn.runtime; import com.fnproject.fn.api.InputEvent; diff --git a/runtime/src/main/java/com/fnproject/fn/runtime/FunctionConfigurer.java b/runtime/src/main/java/com/fnproject/fn/runtime/FunctionConfigurer.java index f9a1b939..7f355176 100644 --- a/runtime/src/main/java/com/fnproject/fn/runtime/FunctionConfigurer.java +++ b/runtime/src/main/java/com/fnproject/fn/runtime/FunctionConfigurer.java @@ -1,3 +1,19 @@ +/* + * Copyright (c) 2019, 2020 Oracle and/or its affiliates. All rights reserved. + * + * 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. + */ + package com.fnproject.fn.runtime; import com.fnproject.fn.api.FnConfiguration; diff --git a/runtime/src/main/java/com/fnproject/fn/runtime/FunctionInvocationCallback.java b/runtime/src/main/java/com/fnproject/fn/runtime/FunctionInvocationCallback.java index 9c1c5772..7f8ee6ba 100644 --- a/runtime/src/main/java/com/fnproject/fn/runtime/FunctionInvocationCallback.java +++ b/runtime/src/main/java/com/fnproject/fn/runtime/FunctionInvocationCallback.java @@ -1,3 +1,19 @@ +/* + * Copyright (c) 2019, 2020 Oracle and/or its affiliates. All rights reserved. + * + * 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. + */ + package com.fnproject.fn.runtime; public interface FunctionInvocationCallback { diff --git a/runtime/src/main/java/com/fnproject/fn/runtime/FunctionInvocationContext.java b/runtime/src/main/java/com/fnproject/fn/runtime/FunctionInvocationContext.java index 9103726d..3cd8595d 100644 --- a/runtime/src/main/java/com/fnproject/fn/runtime/FunctionInvocationContext.java +++ b/runtime/src/main/java/com/fnproject/fn/runtime/FunctionInvocationContext.java @@ -1,3 +1,19 @@ +/* + * Copyright (c) 2019, 2020 Oracle and/or its affiliates. All rights reserved. + * + * 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. + */ + package com.fnproject.fn.runtime; import com.fnproject.fn.api.Headers; diff --git a/runtime/src/main/java/com/fnproject/fn/runtime/FunctionLoader.java b/runtime/src/main/java/com/fnproject/fn/runtime/FunctionLoader.java index 30b10101..c2bb23cd 100644 --- a/runtime/src/main/java/com/fnproject/fn/runtime/FunctionLoader.java +++ b/runtime/src/main/java/com/fnproject/fn/runtime/FunctionLoader.java @@ -1,3 +1,19 @@ +/* + * Copyright (c) 2019, 2020 Oracle and/or its affiliates. All rights reserved. + * + * 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. + */ + package com.fnproject.fn.runtime; import com.fnproject.fn.api.MethodWrapper; diff --git a/runtime/src/main/java/com/fnproject/fn/runtime/FunctionRuntimeContext.java b/runtime/src/main/java/com/fnproject/fn/runtime/FunctionRuntimeContext.java index 24c53e43..b86220e0 100644 --- a/runtime/src/main/java/com/fnproject/fn/runtime/FunctionRuntimeContext.java +++ b/runtime/src/main/java/com/fnproject/fn/runtime/FunctionRuntimeContext.java @@ -1,3 +1,19 @@ +/* + * Copyright (c) 2019, 2020 Oracle and/or its affiliates. All rights reserved. + * + * 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. + */ + package com.fnproject.fn.runtime; import com.fnproject.fn.api.*; diff --git a/runtime/src/main/java/com/fnproject/fn/runtime/HTTPStreamCodec.java b/runtime/src/main/java/com/fnproject/fn/runtime/HTTPStreamCodec.java index 512fb8bf..b6b5b317 100644 --- a/runtime/src/main/java/com/fnproject/fn/runtime/HTTPStreamCodec.java +++ b/runtime/src/main/java/com/fnproject/fn/runtime/HTTPStreamCodec.java @@ -1,3 +1,19 @@ +/* + * Copyright (c) 2019, 2020 Oracle and/or its affiliates. All rights reserved. + * + * 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. + */ + package com.fnproject.fn.runtime; diff --git a/runtime/src/main/java/com/fnproject/fn/runtime/MethodFunctionInvoker.java b/runtime/src/main/java/com/fnproject/fn/runtime/MethodFunctionInvoker.java index 04192a37..1e5b679a 100644 --- a/runtime/src/main/java/com/fnproject/fn/runtime/MethodFunctionInvoker.java +++ b/runtime/src/main/java/com/fnproject/fn/runtime/MethodFunctionInvoker.java @@ -1,3 +1,19 @@ +/* + * Copyright (c) 2019, 2020 Oracle and/or its affiliates. All rights reserved. + * + * 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. + */ + package com.fnproject.fn.runtime; diff --git a/runtime/src/main/java/com/fnproject/fn/runtime/MethodTypeWrapper.java b/runtime/src/main/java/com/fnproject/fn/runtime/MethodTypeWrapper.java index 3972784f..a0f243f3 100644 --- a/runtime/src/main/java/com/fnproject/fn/runtime/MethodTypeWrapper.java +++ b/runtime/src/main/java/com/fnproject/fn/runtime/MethodTypeWrapper.java @@ -1,3 +1,19 @@ +/* + * Copyright (c) 2019, 2020 Oracle and/or its affiliates. All rights reserved. + * + * 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. + */ + package com.fnproject.fn.runtime; import com.fnproject.fn.api.MethodWrapper; diff --git a/runtime/src/main/java/com/fnproject/fn/runtime/PrimitiveTypeResolver.java b/runtime/src/main/java/com/fnproject/fn/runtime/PrimitiveTypeResolver.java index 5f2f8e3f..b5e6dea1 100644 --- a/runtime/src/main/java/com/fnproject/fn/runtime/PrimitiveTypeResolver.java +++ b/runtime/src/main/java/com/fnproject/fn/runtime/PrimitiveTypeResolver.java @@ -1,3 +1,19 @@ +/* + * Copyright (c) 2019, 2020 Oracle and/or its affiliates. All rights reserved. + * + * 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. + */ + package com.fnproject.fn.runtime; import java.util.HashMap; diff --git a/runtime/src/main/java/com/fnproject/fn/runtime/ReadOnceInputEvent.java b/runtime/src/main/java/com/fnproject/fn/runtime/ReadOnceInputEvent.java index 7bfb4cde..f9cac12e 100644 --- a/runtime/src/main/java/com/fnproject/fn/runtime/ReadOnceInputEvent.java +++ b/runtime/src/main/java/com/fnproject/fn/runtime/ReadOnceInputEvent.java @@ -1,3 +1,19 @@ +/* + * Copyright (c) 2019, 2020 Oracle and/or its affiliates. All rights reserved. + * + * 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. + */ + package com.fnproject.fn.runtime; import com.fnproject.fn.api.Headers; diff --git a/runtime/src/main/java/com/fnproject/fn/runtime/coercion/ByteArrayCoercion.java b/runtime/src/main/java/com/fnproject/fn/runtime/coercion/ByteArrayCoercion.java index 401791d2..88391323 100644 --- a/runtime/src/main/java/com/fnproject/fn/runtime/coercion/ByteArrayCoercion.java +++ b/runtime/src/main/java/com/fnproject/fn/runtime/coercion/ByteArrayCoercion.java @@ -1,3 +1,19 @@ +/* + * Copyright (c) 2019, 2020 Oracle and/or its affiliates. All rights reserved. + * + * 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. + */ + package com.fnproject.fn.runtime.coercion; import com.fnproject.fn.api.*; diff --git a/runtime/src/main/java/com/fnproject/fn/runtime/coercion/ContextCoercion.java b/runtime/src/main/java/com/fnproject/fn/runtime/coercion/ContextCoercion.java index 9bea4611..f4e22070 100644 --- a/runtime/src/main/java/com/fnproject/fn/runtime/coercion/ContextCoercion.java +++ b/runtime/src/main/java/com/fnproject/fn/runtime/coercion/ContextCoercion.java @@ -1,3 +1,19 @@ +/* + * Copyright (c) 2019, 2020 Oracle and/or its affiliates. All rights reserved. + * + * 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. + */ + package com.fnproject.fn.runtime.coercion; import com.fnproject.fn.api.*; diff --git a/runtime/src/main/java/com/fnproject/fn/runtime/coercion/InputEventCoercion.java b/runtime/src/main/java/com/fnproject/fn/runtime/coercion/InputEventCoercion.java index 1a04e7e5..fcb4f47b 100644 --- a/runtime/src/main/java/com/fnproject/fn/runtime/coercion/InputEventCoercion.java +++ b/runtime/src/main/java/com/fnproject/fn/runtime/coercion/InputEventCoercion.java @@ -1,3 +1,19 @@ +/* + * Copyright (c) 2019, 2020 Oracle and/or its affiliates. All rights reserved. + * + * 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. + */ + package com.fnproject.fn.runtime.coercion; diff --git a/runtime/src/main/java/com/fnproject/fn/runtime/coercion/OutputEventCoercion.java b/runtime/src/main/java/com/fnproject/fn/runtime/coercion/OutputEventCoercion.java index 93baeb40..fb111f2b 100644 --- a/runtime/src/main/java/com/fnproject/fn/runtime/coercion/OutputEventCoercion.java +++ b/runtime/src/main/java/com/fnproject/fn/runtime/coercion/OutputEventCoercion.java @@ -1,3 +1,19 @@ +/* + * Copyright (c) 2019, 2020 Oracle and/or its affiliates. All rights reserved. + * + * 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. + */ + package com.fnproject.fn.runtime.coercion; import com.fnproject.fn.api.InvocationContext; diff --git a/runtime/src/main/java/com/fnproject/fn/runtime/coercion/StringCoercion.java b/runtime/src/main/java/com/fnproject/fn/runtime/coercion/StringCoercion.java index b51b9d14..d71d9af9 100644 --- a/runtime/src/main/java/com/fnproject/fn/runtime/coercion/StringCoercion.java +++ b/runtime/src/main/java/com/fnproject/fn/runtime/coercion/StringCoercion.java @@ -1,3 +1,19 @@ +/* + * Copyright (c) 2019, 2020 Oracle and/or its affiliates. All rights reserved. + * + * 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. + */ + package com.fnproject.fn.runtime.coercion; import com.fnproject.fn.api.*; diff --git a/runtime/src/main/java/com/fnproject/fn/runtime/coercion/VoidCoercion.java b/runtime/src/main/java/com/fnproject/fn/runtime/coercion/VoidCoercion.java index 3586e8dc..206dfde5 100644 --- a/runtime/src/main/java/com/fnproject/fn/runtime/coercion/VoidCoercion.java +++ b/runtime/src/main/java/com/fnproject/fn/runtime/coercion/VoidCoercion.java @@ -1,3 +1,19 @@ +/* + * Copyright (c) 2019, 2020 Oracle and/or its affiliates. All rights reserved. + * + * 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. + */ + package com.fnproject.fn.runtime.coercion; import com.fnproject.fn.api.InvocationContext; diff --git a/runtime/src/main/java/com/fnproject/fn/runtime/coercion/jackson/JacksonCoercion.java b/runtime/src/main/java/com/fnproject/fn/runtime/coercion/jackson/JacksonCoercion.java index 50a1f8d3..9688b74f 100644 --- a/runtime/src/main/java/com/fnproject/fn/runtime/coercion/jackson/JacksonCoercion.java +++ b/runtime/src/main/java/com/fnproject/fn/runtime/coercion/jackson/JacksonCoercion.java @@ -1,3 +1,19 @@ +/* + * Copyright (c) 2019, 2020 Oracle and/or its affiliates. All rights reserved. + * + * 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. + */ + package com.fnproject.fn.runtime.coercion.jackson; import com.fasterxml.jackson.core.JsonProcessingException; diff --git a/runtime/src/main/java/com/fnproject/fn/runtime/exception/FunctionClassInstantiationException.java b/runtime/src/main/java/com/fnproject/fn/runtime/exception/FunctionClassInstantiationException.java index 9014c3d6..0ca4a729 100644 --- a/runtime/src/main/java/com/fnproject/fn/runtime/exception/FunctionClassInstantiationException.java +++ b/runtime/src/main/java/com/fnproject/fn/runtime/exception/FunctionClassInstantiationException.java @@ -1,3 +1,19 @@ +/* + * Copyright (c) 2019, 2020 Oracle and/or its affiliates. All rights reserved. + * + * 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. + */ + package com.fnproject.fn.runtime.exception; import com.fnproject.fn.api.exception.FunctionLoadException; diff --git a/runtime/src/main/java/com/fnproject/fn/runtime/exception/FunctionIOException.java b/runtime/src/main/java/com/fnproject/fn/runtime/exception/FunctionIOException.java index 7b99da89..5d982f5b 100644 --- a/runtime/src/main/java/com/fnproject/fn/runtime/exception/FunctionIOException.java +++ b/runtime/src/main/java/com/fnproject/fn/runtime/exception/FunctionIOException.java @@ -1,3 +1,19 @@ +/* + * Copyright (c) 2019, 2020 Oracle and/or its affiliates. All rights reserved. + * + * 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. + */ + package com.fnproject.fn.runtime.exception; /** diff --git a/runtime/src/main/java/com/fnproject/fn/runtime/exception/FunctionInitializationException.java b/runtime/src/main/java/com/fnproject/fn/runtime/exception/FunctionInitializationException.java index 7bbc9323..f3571353 100644 --- a/runtime/src/main/java/com/fnproject/fn/runtime/exception/FunctionInitializationException.java +++ b/runtime/src/main/java/com/fnproject/fn/runtime/exception/FunctionInitializationException.java @@ -1,3 +1,19 @@ +/* + * Copyright (c) 2019, 2020 Oracle and/or its affiliates. All rights reserved. + * + * 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. + */ + package com.fnproject.fn.runtime.exception; /** diff --git a/runtime/src/main/java/com/fnproject/fn/runtime/exception/InternalFunctionInvocationException.java b/runtime/src/main/java/com/fnproject/fn/runtime/exception/InternalFunctionInvocationException.java index 40ca5d80..9c661a3c 100644 --- a/runtime/src/main/java/com/fnproject/fn/runtime/exception/InternalFunctionInvocationException.java +++ b/runtime/src/main/java/com/fnproject/fn/runtime/exception/InternalFunctionInvocationException.java @@ -1,3 +1,19 @@ +/* + * Copyright (c) 2019, 2020 Oracle and/or its affiliates. All rights reserved. + * + * 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. + */ + package com.fnproject.fn.runtime.exception; import com.fnproject.fn.api.OutputEvent; diff --git a/runtime/src/main/java/com/fnproject/fn/runtime/exception/InvalidEntryPointException.java b/runtime/src/main/java/com/fnproject/fn/runtime/exception/InvalidEntryPointException.java index 2e7e03c6..6bcafdb2 100644 --- a/runtime/src/main/java/com/fnproject/fn/runtime/exception/InvalidEntryPointException.java +++ b/runtime/src/main/java/com/fnproject/fn/runtime/exception/InvalidEntryPointException.java @@ -1,3 +1,19 @@ +/* + * Copyright (c) 2019, 2020 Oracle and/or its affiliates. All rights reserved. + * + * 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. + */ + package com.fnproject.fn.runtime.exception; import com.fnproject.fn.api.exception.FunctionLoadException; diff --git a/runtime/src/main/java/com/fnproject/fn/runtime/exception/InvalidFunctionDefinitionException.java b/runtime/src/main/java/com/fnproject/fn/runtime/exception/InvalidFunctionDefinitionException.java index 763666ab..bbc2064e 100644 --- a/runtime/src/main/java/com/fnproject/fn/runtime/exception/InvalidFunctionDefinitionException.java +++ b/runtime/src/main/java/com/fnproject/fn/runtime/exception/InvalidFunctionDefinitionException.java @@ -1,3 +1,19 @@ +/* + * Copyright (c) 2019, 2020 Oracle and/or its affiliates. All rights reserved. + * + * 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. + */ + package com.fnproject.fn.runtime.exception; import com.fnproject.fn.api.exception.FunctionLoadException; diff --git a/runtime/src/main/java/com/fnproject/fn/runtime/exception/PlatformCommunicationException.java b/runtime/src/main/java/com/fnproject/fn/runtime/exception/PlatformCommunicationException.java index 09db0863..f4da0254 100644 --- a/runtime/src/main/java/com/fnproject/fn/runtime/exception/PlatformCommunicationException.java +++ b/runtime/src/main/java/com/fnproject/fn/runtime/exception/PlatformCommunicationException.java @@ -1,3 +1,19 @@ +/* + * Copyright (c) 2019, 2020 Oracle and/or its affiliates. All rights reserved. + * + * 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. + */ + package com.fnproject.fn.runtime.exception; /** diff --git a/runtime/src/main/java/com/fnproject/fn/runtime/httpgateway/FunctionHTTPGatewayContext.java b/runtime/src/main/java/com/fnproject/fn/runtime/httpgateway/FunctionHTTPGatewayContext.java index a0f1c8be..e3a259dc 100644 --- a/runtime/src/main/java/com/fnproject/fn/runtime/httpgateway/FunctionHTTPGatewayContext.java +++ b/runtime/src/main/java/com/fnproject/fn/runtime/httpgateway/FunctionHTTPGatewayContext.java @@ -1,3 +1,19 @@ +/* + * Copyright (c) 2019, 2020 Oracle and/or its affiliates. All rights reserved. + * + * 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. + */ + package com.fnproject.fn.runtime.httpgateway; import com.fnproject.fn.api.Headers; diff --git a/runtime/src/main/java/com/fnproject/fn/runtime/httpgateway/QueryParametersImpl.java b/runtime/src/main/java/com/fnproject/fn/runtime/httpgateway/QueryParametersImpl.java index 885be4c3..2f9cfe82 100644 --- a/runtime/src/main/java/com/fnproject/fn/runtime/httpgateway/QueryParametersImpl.java +++ b/runtime/src/main/java/com/fnproject/fn/runtime/httpgateway/QueryParametersImpl.java @@ -1,3 +1,19 @@ +/* + * Copyright (c) 2019, 2020 Oracle and/or its affiliates. All rights reserved. + * + * 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. + */ + package com.fnproject.fn.runtime.httpgateway; import com.fnproject.fn.api.QueryParameters; diff --git a/runtime/src/main/java/com/fnproject/fn/runtime/httpgateway/QueryParametersParser.java b/runtime/src/main/java/com/fnproject/fn/runtime/httpgateway/QueryParametersParser.java index 51242f06..e708d792 100644 --- a/runtime/src/main/java/com/fnproject/fn/runtime/httpgateway/QueryParametersParser.java +++ b/runtime/src/main/java/com/fnproject/fn/runtime/httpgateway/QueryParametersParser.java @@ -1,3 +1,19 @@ +/* + * Copyright (c) 2019, 2020 Oracle and/or its affiliates. All rights reserved. + * + * 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. + */ + package com.fnproject.fn.runtime.httpgateway; import com.fnproject.fn.api.QueryParameters; diff --git a/runtime/src/main/java/com/fnproject/fn/runtime/ntv/UnixServerSocket.java b/runtime/src/main/java/com/fnproject/fn/runtime/ntv/UnixServerSocket.java index a4fb310b..020bc386 100644 --- a/runtime/src/main/java/com/fnproject/fn/runtime/ntv/UnixServerSocket.java +++ b/runtime/src/main/java/com/fnproject/fn/runtime/ntv/UnixServerSocket.java @@ -1,3 +1,19 @@ +/* + * Copyright (c) 2019, 2020 Oracle and/or its affiliates. All rights reserved. + * + * 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. + */ + package com.fnproject.fn.runtime.ntv; import java.io.Closeable; diff --git a/runtime/src/main/java/com/fnproject/fn/runtime/ntv/UnixSocket.java b/runtime/src/main/java/com/fnproject/fn/runtime/ntv/UnixSocket.java index 26ca8457..c1266407 100644 --- a/runtime/src/main/java/com/fnproject/fn/runtime/ntv/UnixSocket.java +++ b/runtime/src/main/java/com/fnproject/fn/runtime/ntv/UnixSocket.java @@ -1,3 +1,19 @@ +/* + * Copyright (c) 2019, 2020 Oracle and/or its affiliates. All rights reserved. + * + * 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. + */ + package com.fnproject.fn.runtime.ntv; import java.io.IOException; diff --git a/runtime/src/main/java/com/fnproject/fn/runtime/ntv/UnixSocketException.java b/runtime/src/main/java/com/fnproject/fn/runtime/ntv/UnixSocketException.java index 32803bae..e30707d0 100644 --- a/runtime/src/main/java/com/fnproject/fn/runtime/ntv/UnixSocketException.java +++ b/runtime/src/main/java/com/fnproject/fn/runtime/ntv/UnixSocketException.java @@ -1,3 +1,19 @@ +/* + * Copyright (c) 2019, 2020 Oracle and/or its affiliates. All rights reserved. + * + * 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. + */ + package com.fnproject.fn.runtime.ntv; import java.net.SocketException; diff --git a/runtime/src/main/java/com/fnproject/fn/runtime/ntv/UnixSocketNative.java b/runtime/src/main/java/com/fnproject/fn/runtime/ntv/UnixSocketNative.java index 0dd06fda..2891f08b 100644 --- a/runtime/src/main/java/com/fnproject/fn/runtime/ntv/UnixSocketNative.java +++ b/runtime/src/main/java/com/fnproject/fn/runtime/ntv/UnixSocketNative.java @@ -1,3 +1,19 @@ +/* + * Copyright (c) 2019, 2020 Oracle and/or its affiliates. All rights reserved. + * + * 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. + */ + package com.fnproject.fn.runtime.ntv; diff --git a/runtime/src/test/java/com/fnproject/fn/runtime/ConfigurationMethodsTest.java b/runtime/src/test/java/com/fnproject/fn/runtime/ConfigurationMethodsTest.java index 6b9816d1..b95a34bf 100644 --- a/runtime/src/test/java/com/fnproject/fn/runtime/ConfigurationMethodsTest.java +++ b/runtime/src/test/java/com/fnproject/fn/runtime/ConfigurationMethodsTest.java @@ -1,3 +1,19 @@ +/* + * Copyright (c) 2019, 2020 Oracle and/or its affiliates. All rights reserved. + * + * 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. + */ + package com.fnproject.fn.runtime; import com.fnproject.fn.runtime.testfns.TestFnWithConfigurationMethods; diff --git a/runtime/src/test/java/com/fnproject/fn/runtime/DataBindingTest.java b/runtime/src/test/java/com/fnproject/fn/runtime/DataBindingTest.java index 16095e8a..47c3398b 100644 --- a/runtime/src/test/java/com/fnproject/fn/runtime/DataBindingTest.java +++ b/runtime/src/test/java/com/fnproject/fn/runtime/DataBindingTest.java @@ -1,3 +1,19 @@ +/* + * Copyright (c) 2019, 2020 Oracle and/or its affiliates. All rights reserved. + * + * 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. + */ + package com.fnproject.fn.runtime; import com.fnproject.fn.runtime.testfns.*; diff --git a/runtime/src/test/java/com/fnproject/fn/runtime/EndToEndInvokeTest.java b/runtime/src/test/java/com/fnproject/fn/runtime/EndToEndInvokeTest.java index a028c368..a7778d47 100644 --- a/runtime/src/test/java/com/fnproject/fn/runtime/EndToEndInvokeTest.java +++ b/runtime/src/test/java/com/fnproject/fn/runtime/EndToEndInvokeTest.java @@ -1,3 +1,19 @@ +/* + * Copyright (c) 2019, 2020 Oracle and/or its affiliates. All rights reserved. + * + * 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. + */ + package com.fnproject.fn.runtime; import com.fnproject.fn.api.InputEvent; diff --git a/runtime/src/test/java/com/fnproject/fn/runtime/ErrorMessagesTest.java b/runtime/src/test/java/com/fnproject/fn/runtime/ErrorMessagesTest.java index 49c472e8..ccd2b202 100644 --- a/runtime/src/test/java/com/fnproject/fn/runtime/ErrorMessagesTest.java +++ b/runtime/src/test/java/com/fnproject/fn/runtime/ErrorMessagesTest.java @@ -1,3 +1,19 @@ +/* + * Copyright (c) 2019, 2020 Oracle and/or its affiliates. All rights reserved. + * + * 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. + */ + package com.fnproject.fn.runtime; import com.fnproject.fn.runtime.testfns.ErrorMessages; diff --git a/runtime/src/test/java/com/fnproject/fn/runtime/FnTestHarness.java b/runtime/src/test/java/com/fnproject/fn/runtime/FnTestHarness.java index 6c5561b6..b9d06ad3 100644 --- a/runtime/src/test/java/com/fnproject/fn/runtime/FnTestHarness.java +++ b/runtime/src/test/java/com/fnproject/fn/runtime/FnTestHarness.java @@ -1,3 +1,19 @@ +/* + * Copyright (c) 2019, 2020 Oracle and/or its affiliates. All rights reserved. + * + * 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. + */ + package com.fnproject.fn.runtime; diff --git a/runtime/src/test/java/com/fnproject/fn/runtime/FunctionConstructionTest.java b/runtime/src/test/java/com/fnproject/fn/runtime/FunctionConstructionTest.java index 4d439175..847b203d 100644 --- a/runtime/src/test/java/com/fnproject/fn/runtime/FunctionConstructionTest.java +++ b/runtime/src/test/java/com/fnproject/fn/runtime/FunctionConstructionTest.java @@ -1,3 +1,19 @@ +/* + * Copyright (c) 2019, 2020 Oracle and/or its affiliates. All rights reserved. + * + * 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. + */ + package com.fnproject.fn.runtime; import com.fnproject.fn.runtime.testfns.TestFnConstructors; diff --git a/runtime/src/test/java/com/fnproject/fn/runtime/HTTPStreamCodecTest.java b/runtime/src/test/java/com/fnproject/fn/runtime/HTTPStreamCodecTest.java index 3b07af84..e117b4de 100644 --- a/runtime/src/test/java/com/fnproject/fn/runtime/HTTPStreamCodecTest.java +++ b/runtime/src/test/java/com/fnproject/fn/runtime/HTTPStreamCodecTest.java @@ -1,3 +1,19 @@ +/* + * Copyright (c) 2019, 2020 Oracle and/or its affiliates. All rights reserved. + * + * 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. + */ + package com.fnproject.fn.runtime; diff --git a/runtime/src/test/java/com/fnproject/fn/runtime/HeaderBuilder.java b/runtime/src/test/java/com/fnproject/fn/runtime/HeaderBuilder.java index 69c3fc7c..9b684725 100644 --- a/runtime/src/test/java/com/fnproject/fn/runtime/HeaderBuilder.java +++ b/runtime/src/test/java/com/fnproject/fn/runtime/HeaderBuilder.java @@ -1,3 +1,19 @@ +/* + * Copyright (c) 2019, 2020 Oracle and/or its affiliates. All rights reserved. + * + * 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. + */ + package com.fnproject.fn.runtime; import com.fnproject.fn.api.Headers; diff --git a/runtime/src/test/java/com/fnproject/fn/runtime/JacksonCoercionTest.java b/runtime/src/test/java/com/fnproject/fn/runtime/JacksonCoercionTest.java index 35b3cba4..49edd95e 100644 --- a/runtime/src/test/java/com/fnproject/fn/runtime/JacksonCoercionTest.java +++ b/runtime/src/test/java/com/fnproject/fn/runtime/JacksonCoercionTest.java @@ -1,3 +1,19 @@ +/* + * Copyright (c) 2019, 2020 Oracle and/or its affiliates. All rights reserved. + * + * 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. + */ + package com.fnproject.fn.runtime; import com.fnproject.fn.api.Headers; diff --git a/runtime/src/test/java/com/fnproject/fn/runtime/MethodWrapperTests.java b/runtime/src/test/java/com/fnproject/fn/runtime/MethodWrapperTests.java index 7f8341ad..c1f1047d 100644 --- a/runtime/src/test/java/com/fnproject/fn/runtime/MethodWrapperTests.java +++ b/runtime/src/test/java/com/fnproject/fn/runtime/MethodWrapperTests.java @@ -1,3 +1,19 @@ +/* + * Copyright (c) 2019, 2020 Oracle and/or its affiliates. All rights reserved. + * + * 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. + */ + package com.fnproject.fn.runtime; import com.fnproject.fn.api.MethodWrapper; diff --git a/runtime/src/test/java/com/fnproject/fn/runtime/QueryParametersParserTest.java b/runtime/src/test/java/com/fnproject/fn/runtime/QueryParametersParserTest.java index 72d39463..14cb92b7 100644 --- a/runtime/src/test/java/com/fnproject/fn/runtime/QueryParametersParserTest.java +++ b/runtime/src/test/java/com/fnproject/fn/runtime/QueryParametersParserTest.java @@ -1,3 +1,19 @@ +/* + * Copyright (c) 2019, 2020 Oracle and/or its affiliates. All rights reserved. + * + * 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. + */ + package com.fnproject.fn.runtime; import com.fnproject.fn.api.QueryParameters; diff --git a/runtime/src/test/java/com/fnproject/fn/runtime/httpgateway/FunctionHTTPGatewayContextTest.java b/runtime/src/test/java/com/fnproject/fn/runtime/httpgateway/FunctionHTTPGatewayContextTest.java index 93ac7015..f6b478e3 100644 --- a/runtime/src/test/java/com/fnproject/fn/runtime/httpgateway/FunctionHTTPGatewayContextTest.java +++ b/runtime/src/test/java/com/fnproject/fn/runtime/httpgateway/FunctionHTTPGatewayContextTest.java @@ -1,3 +1,19 @@ +/* + * Copyright (c) 2019, 2020 Oracle and/or its affiliates. All rights reserved. + * + * 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. + */ + package com.fnproject.fn.runtime.httpgateway; import com.fnproject.fn.api.Headers; diff --git a/runtime/src/test/java/com/fnproject/fn/runtime/ntv/UnixSocketNativeTest.java b/runtime/src/test/java/com/fnproject/fn/runtime/ntv/UnixSocketNativeTest.java index 436da667..805c668a 100644 --- a/runtime/src/test/java/com/fnproject/fn/runtime/ntv/UnixSocketNativeTest.java +++ b/runtime/src/test/java/com/fnproject/fn/runtime/ntv/UnixSocketNativeTest.java @@ -1,3 +1,19 @@ +/* + * Copyright (c) 2019, 2020 Oracle and/or its affiliates. All rights reserved. + * + * 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. + */ + package com.fnproject.fn.runtime.ntv; import org.junit.BeforeClass; diff --git a/runtime/src/test/java/com/fnproject/fn/runtime/ntv/UnixSocketTest.java b/runtime/src/test/java/com/fnproject/fn/runtime/ntv/UnixSocketTest.java index 050b9ba9..8f17ee43 100644 --- a/runtime/src/test/java/com/fnproject/fn/runtime/ntv/UnixSocketTest.java +++ b/runtime/src/test/java/com/fnproject/fn/runtime/ntv/UnixSocketTest.java @@ -1,3 +1,19 @@ +/* + * Copyright (c) 2019, 2020 Oracle and/or its affiliates. All rights reserved. + * + * 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. + */ + package com.fnproject.fn.runtime.ntv; import org.assertj.core.api.Assertions; diff --git a/runtime/src/test/java/com/fnproject/fn/runtime/testfns/Animal.java b/runtime/src/test/java/com/fnproject/fn/runtime/testfns/Animal.java index 1760598e..38448c02 100644 --- a/runtime/src/test/java/com/fnproject/fn/runtime/testfns/Animal.java +++ b/runtime/src/test/java/com/fnproject/fn/runtime/testfns/Animal.java @@ -1,3 +1,19 @@ +/* + * Copyright (c) 2019, 2020 Oracle and/or its affiliates. All rights reserved. + * + * 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. + */ + package com.fnproject.fn.runtime.testfns; import com.fasterxml.jackson.annotation.JsonCreator; diff --git a/runtime/src/test/java/com/fnproject/fn/runtime/testfns/BadTestFnDuplicateMethods.java b/runtime/src/test/java/com/fnproject/fn/runtime/testfns/BadTestFnDuplicateMethods.java index dd883e52..98a53e4a 100644 --- a/runtime/src/test/java/com/fnproject/fn/runtime/testfns/BadTestFnDuplicateMethods.java +++ b/runtime/src/test/java/com/fnproject/fn/runtime/testfns/BadTestFnDuplicateMethods.java @@ -1,3 +1,19 @@ +/* + * Copyright (c) 2019, 2020 Oracle and/or its affiliates. All rights reserved. + * + * 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. + */ + package com.fnproject.fn.runtime.testfns; /** diff --git a/runtime/src/test/java/com/fnproject/fn/runtime/testfns/CustomDataBindingFnInputOutput.java b/runtime/src/test/java/com/fnproject/fn/runtime/testfns/CustomDataBindingFnInputOutput.java index a5813281..260aab80 100644 --- a/runtime/src/test/java/com/fnproject/fn/runtime/testfns/CustomDataBindingFnInputOutput.java +++ b/runtime/src/test/java/com/fnproject/fn/runtime/testfns/CustomDataBindingFnInputOutput.java @@ -1,3 +1,19 @@ +/* + * Copyright (c) 2019, 2020 Oracle and/or its affiliates. All rights reserved. + * + * 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. + */ + package com.fnproject.fn.runtime.testfns; import com.fnproject.fn.api.FnConfiguration; diff --git a/runtime/src/test/java/com/fnproject/fn/runtime/testfns/CustomDataBindingFnWithAnnotation.java b/runtime/src/test/java/com/fnproject/fn/runtime/testfns/CustomDataBindingFnWithAnnotation.java index a6116aee..362984c2 100644 --- a/runtime/src/test/java/com/fnproject/fn/runtime/testfns/CustomDataBindingFnWithAnnotation.java +++ b/runtime/src/test/java/com/fnproject/fn/runtime/testfns/CustomDataBindingFnWithAnnotation.java @@ -1,3 +1,19 @@ +/* + * Copyright (c) 2019, 2020 Oracle and/or its affiliates. All rights reserved. + * + * 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. + */ + package com.fnproject.fn.runtime.testfns; import com.fnproject.fn.api.InputBinding; diff --git a/runtime/src/test/java/com/fnproject/fn/runtime/testfns/CustomDataBindingFnWithAnnotationAndConfig.java b/runtime/src/test/java/com/fnproject/fn/runtime/testfns/CustomDataBindingFnWithAnnotationAndConfig.java index 59691b8d..151eb18f 100644 --- a/runtime/src/test/java/com/fnproject/fn/runtime/testfns/CustomDataBindingFnWithAnnotationAndConfig.java +++ b/runtime/src/test/java/com/fnproject/fn/runtime/testfns/CustomDataBindingFnWithAnnotationAndConfig.java @@ -1,3 +1,19 @@ +/* + * Copyright (c) 2019, 2020 Oracle and/or its affiliates. All rights reserved. + * + * 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. + */ + package com.fnproject.fn.runtime.testfns; import com.fnproject.fn.api.FnConfiguration; diff --git a/runtime/src/test/java/com/fnproject/fn/runtime/testfns/CustomDataBindingFnWithConfig.java b/runtime/src/test/java/com/fnproject/fn/runtime/testfns/CustomDataBindingFnWithConfig.java index 5117d0ed..f1d70df5 100644 --- a/runtime/src/test/java/com/fnproject/fn/runtime/testfns/CustomDataBindingFnWithConfig.java +++ b/runtime/src/test/java/com/fnproject/fn/runtime/testfns/CustomDataBindingFnWithConfig.java @@ -1,3 +1,19 @@ +/* + * Copyright (c) 2019, 2020 Oracle and/or its affiliates. All rights reserved. + * + * 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. + */ + package com.fnproject.fn.runtime.testfns; import com.fnproject.fn.api.FnConfiguration; diff --git a/runtime/src/test/java/com/fnproject/fn/runtime/testfns/CustomDataBindingFnWithDudCoercion.java b/runtime/src/test/java/com/fnproject/fn/runtime/testfns/CustomDataBindingFnWithDudCoercion.java index 9e13224c..a6a40a1d 100644 --- a/runtime/src/test/java/com/fnproject/fn/runtime/testfns/CustomDataBindingFnWithDudCoercion.java +++ b/runtime/src/test/java/com/fnproject/fn/runtime/testfns/CustomDataBindingFnWithDudCoercion.java @@ -1,3 +1,19 @@ +/* + * Copyright (c) 2019, 2020 Oracle and/or its affiliates. All rights reserved. + * + * 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. + */ + package com.fnproject.fn.runtime.testfns; import com.fnproject.fn.api.FnConfiguration; diff --git a/runtime/src/test/java/com/fnproject/fn/runtime/testfns/CustomDataBindingFnWithMultipleCoercions.java b/runtime/src/test/java/com/fnproject/fn/runtime/testfns/CustomDataBindingFnWithMultipleCoercions.java index cb7d35db..1da6b54f 100644 --- a/runtime/src/test/java/com/fnproject/fn/runtime/testfns/CustomDataBindingFnWithMultipleCoercions.java +++ b/runtime/src/test/java/com/fnproject/fn/runtime/testfns/CustomDataBindingFnWithMultipleCoercions.java @@ -1,3 +1,19 @@ +/* + * Copyright (c) 2019, 2020 Oracle and/or its affiliates. All rights reserved. + * + * 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. + */ + package com.fnproject.fn.runtime.testfns; import com.fnproject.fn.api.FnConfiguration; diff --git a/runtime/src/test/java/com/fnproject/fn/runtime/testfns/CustomDataBindingFnWithNoUserCoercions.java b/runtime/src/test/java/com/fnproject/fn/runtime/testfns/CustomDataBindingFnWithNoUserCoercions.java index 6902cdf0..f6f7b3a6 100644 --- a/runtime/src/test/java/com/fnproject/fn/runtime/testfns/CustomDataBindingFnWithNoUserCoercions.java +++ b/runtime/src/test/java/com/fnproject/fn/runtime/testfns/CustomDataBindingFnWithNoUserCoercions.java @@ -1,3 +1,19 @@ +/* + * Copyright (c) 2019, 2020 Oracle and/or its affiliates. All rights reserved. + * + * 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. + */ + package com.fnproject.fn.runtime.testfns; import com.fnproject.fn.api.FnConfiguration; diff --git a/runtime/src/test/java/com/fnproject/fn/runtime/testfns/CustomOutputDataBindingFnWithAnnotation.java b/runtime/src/test/java/com/fnproject/fn/runtime/testfns/CustomOutputDataBindingFnWithAnnotation.java index 738ff335..19630a68 100644 --- a/runtime/src/test/java/com/fnproject/fn/runtime/testfns/CustomOutputDataBindingFnWithAnnotation.java +++ b/runtime/src/test/java/com/fnproject/fn/runtime/testfns/CustomOutputDataBindingFnWithAnnotation.java @@ -1,3 +1,19 @@ +/* + * Copyright (c) 2019, 2020 Oracle and/or its affiliates. All rights reserved. + * + * 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. + */ + package com.fnproject.fn.runtime.testfns; import com.fnproject.fn.api.OutputBinding; diff --git a/runtime/src/test/java/com/fnproject/fn/runtime/testfns/CustomOutputDataBindingFnWithConfig.java b/runtime/src/test/java/com/fnproject/fn/runtime/testfns/CustomOutputDataBindingFnWithConfig.java index 63af1473..d35d8032 100644 --- a/runtime/src/test/java/com/fnproject/fn/runtime/testfns/CustomOutputDataBindingFnWithConfig.java +++ b/runtime/src/test/java/com/fnproject/fn/runtime/testfns/CustomOutputDataBindingFnWithConfig.java @@ -1,3 +1,19 @@ +/* + * Copyright (c) 2019, 2020 Oracle and/or its affiliates. All rights reserved. + * + * 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. + */ + package com.fnproject.fn.runtime.testfns; import com.fnproject.fn.api.FnConfiguration; diff --git a/runtime/src/test/java/com/fnproject/fn/runtime/testfns/CustomOutputDataBindingFnWithDudCoercion.java b/runtime/src/test/java/com/fnproject/fn/runtime/testfns/CustomOutputDataBindingFnWithDudCoercion.java index 072e23c9..e3a91da9 100644 --- a/runtime/src/test/java/com/fnproject/fn/runtime/testfns/CustomOutputDataBindingFnWithDudCoercion.java +++ b/runtime/src/test/java/com/fnproject/fn/runtime/testfns/CustomOutputDataBindingFnWithDudCoercion.java @@ -1,3 +1,19 @@ +/* + * Copyright (c) 2019, 2020 Oracle and/or its affiliates. All rights reserved. + * + * 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. + */ + package com.fnproject.fn.runtime.testfns; import com.fnproject.fn.api.FnConfiguration; diff --git a/runtime/src/test/java/com/fnproject/fn/runtime/testfns/CustomOutputDataBindingFnWithMultipleCoercions.java b/runtime/src/test/java/com/fnproject/fn/runtime/testfns/CustomOutputDataBindingFnWithMultipleCoercions.java index 8b2f36d5..acd92e88 100644 --- a/runtime/src/test/java/com/fnproject/fn/runtime/testfns/CustomOutputDataBindingFnWithMultipleCoercions.java +++ b/runtime/src/test/java/com/fnproject/fn/runtime/testfns/CustomOutputDataBindingFnWithMultipleCoercions.java @@ -1,3 +1,19 @@ +/* + * Copyright (c) 2019, 2020 Oracle and/or its affiliates. All rights reserved. + * + * 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. + */ + package com.fnproject.fn.runtime.testfns; import com.fnproject.fn.api.FnConfiguration; diff --git a/runtime/src/test/java/com/fnproject/fn/runtime/testfns/CustomOutputDataBindingFnWithNoUserCoercions.java b/runtime/src/test/java/com/fnproject/fn/runtime/testfns/CustomOutputDataBindingFnWithNoUserCoercions.java index 39b1ec80..1048ee4a 100644 --- a/runtime/src/test/java/com/fnproject/fn/runtime/testfns/CustomOutputDataBindingFnWithNoUserCoercions.java +++ b/runtime/src/test/java/com/fnproject/fn/runtime/testfns/CustomOutputDataBindingFnWithNoUserCoercions.java @@ -1,3 +1,19 @@ +/* + * Copyright (c) 2019, 2020 Oracle and/or its affiliates. All rights reserved. + * + * 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. + */ + package com.fnproject.fn.runtime.testfns; import com.fnproject.fn.api.FnConfiguration; diff --git a/runtime/src/test/java/com/fnproject/fn/runtime/testfns/ErrorMessages.java b/runtime/src/test/java/com/fnproject/fn/runtime/testfns/ErrorMessages.java index 1ed20e30..23371c5a 100644 --- a/runtime/src/test/java/com/fnproject/fn/runtime/testfns/ErrorMessages.java +++ b/runtime/src/test/java/com/fnproject/fn/runtime/testfns/ErrorMessages.java @@ -1,3 +1,19 @@ +/* + * Copyright (c) 2019, 2020 Oracle and/or its affiliates. All rights reserved. + * + * 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. + */ + package com.fnproject.fn.runtime.testfns; public class ErrorMessages { diff --git a/runtime/src/test/java/com/fnproject/fn/runtime/testfns/TestFn.java b/runtime/src/test/java/com/fnproject/fn/runtime/testfns/TestFn.java index 306bce2e..abe6635e 100644 --- a/runtime/src/test/java/com/fnproject/fn/runtime/testfns/TestFn.java +++ b/runtime/src/test/java/com/fnproject/fn/runtime/testfns/TestFn.java @@ -1,3 +1,19 @@ +/* + * Copyright (c) 2019, 2020 Oracle and/or its affiliates. All rights reserved. + * + * 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. + */ + package com.fnproject.fn.runtime.testfns; import com.fnproject.fn.api.InputEvent; diff --git a/runtime/src/test/java/com/fnproject/fn/runtime/testfns/TestFnConstructors.java b/runtime/src/test/java/com/fnproject/fn/runtime/testfns/TestFnConstructors.java index 73f41d44..ba9e6433 100644 --- a/runtime/src/test/java/com/fnproject/fn/runtime/testfns/TestFnConstructors.java +++ b/runtime/src/test/java/com/fnproject/fn/runtime/testfns/TestFnConstructors.java @@ -1,3 +1,19 @@ +/* + * Copyright (c) 2019, 2020 Oracle and/or its affiliates. All rights reserved. + * + * 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. + */ + package com.fnproject.fn.runtime.testfns; import com.fnproject.fn.api.RuntimeContext; diff --git a/runtime/src/test/java/com/fnproject/fn/runtime/testfns/TestFnWithConfigurationMethods.java b/runtime/src/test/java/com/fnproject/fn/runtime/testfns/TestFnWithConfigurationMethods.java index a6e28862..9fc0a22e 100644 --- a/runtime/src/test/java/com/fnproject/fn/runtime/testfns/TestFnWithConfigurationMethods.java +++ b/runtime/src/test/java/com/fnproject/fn/runtime/testfns/TestFnWithConfigurationMethods.java @@ -1,3 +1,19 @@ +/* + * Copyright (c) 2019, 2020 Oracle and/or its affiliates. All rights reserved. + * + * 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. + */ + package com.fnproject.fn.runtime.testfns; import com.fnproject.fn.api.FnConfiguration; diff --git a/runtime/src/test/java/com/fnproject/fn/runtime/testfns/coercions/DudCoercion.java b/runtime/src/test/java/com/fnproject/fn/runtime/testfns/coercions/DudCoercion.java index af9d3547..b6c68e8a 100644 --- a/runtime/src/test/java/com/fnproject/fn/runtime/testfns/coercions/DudCoercion.java +++ b/runtime/src/test/java/com/fnproject/fn/runtime/testfns/coercions/DudCoercion.java @@ -1,3 +1,19 @@ +/* + * Copyright (c) 2019, 2020 Oracle and/or its affiliates. All rights reserved. + * + * 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. + */ + package com.fnproject.fn.runtime.testfns.coercions; import com.fnproject.fn.api.*; diff --git a/runtime/src/test/java/com/fnproject/fn/runtime/testfns/coercions/StringReversalCoercion.java b/runtime/src/test/java/com/fnproject/fn/runtime/testfns/coercions/StringReversalCoercion.java index 9994b3d2..67e37d37 100644 --- a/runtime/src/test/java/com/fnproject/fn/runtime/testfns/coercions/StringReversalCoercion.java +++ b/runtime/src/test/java/com/fnproject/fn/runtime/testfns/coercions/StringReversalCoercion.java @@ -1,3 +1,19 @@ +/* + * Copyright (c) 2019, 2020 Oracle and/or its affiliates. All rights reserved. + * + * 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. + */ + package com.fnproject.fn.runtime.testfns.coercions; import com.fnproject.fn.api.*; diff --git a/runtime/src/test/java/com/fnproject/fn/runtime/testfns/coercions/StringUpperCaseCoercion.java b/runtime/src/test/java/com/fnproject/fn/runtime/testfns/coercions/StringUpperCaseCoercion.java index 3ac217fd..7afcf314 100644 --- a/runtime/src/test/java/com/fnproject/fn/runtime/testfns/coercions/StringUpperCaseCoercion.java +++ b/runtime/src/test/java/com/fnproject/fn/runtime/testfns/coercions/StringUpperCaseCoercion.java @@ -1,3 +1,19 @@ +/* + * Copyright (c) 2019, 2020 Oracle and/or its affiliates. All rights reserved. + * + * 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. + */ + package com.fnproject.fn.runtime.testfns.coercions; import com.fnproject.fn.api.*; diff --git a/runtime/src/test/java/not/in/com/fnproject/fn/StacktraceFilteringTestFunctions.java b/runtime/src/test/java/not/in/com/fnproject/fn/StacktraceFilteringTestFunctions.java index 9a6620f4..daf95794 100644 --- a/runtime/src/test/java/not/in/com/fnproject/fn/StacktraceFilteringTestFunctions.java +++ b/runtime/src/test/java/not/in/com/fnproject/fn/StacktraceFilteringTestFunctions.java @@ -1,3 +1,19 @@ +/* + * Copyright (c) 2019, 2020 Oracle and/or its affiliates. All rights reserved. + * + * 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. + */ + package not.in.com.fnproject.fn; import com.fnproject.fn.api.FnConfiguration; diff --git a/settings-deploy.xml b/settings-deploy.xml index ee487f49..833ea868 100644 --- a/settings-deploy.xml +++ b/settings-deploy.xml @@ -1,3 +1,21 @@ + + + + diff --git a/testing-core/src/main/java/com/fnproject/fn/testing/FnEventBuilder.java b/testing-core/src/main/java/com/fnproject/fn/testing/FnEventBuilder.java index 21804284..61cb3725 100644 --- a/testing-core/src/main/java/com/fnproject/fn/testing/FnEventBuilder.java +++ b/testing-core/src/main/java/com/fnproject/fn/testing/FnEventBuilder.java @@ -1,3 +1,19 @@ +/* + * Copyright (c) 2019, 2020 Oracle and/or its affiliates. All rights reserved. + * + * 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. + */ + package com.fnproject.fn.testing; import java.io.IOException; diff --git a/testing-core/src/main/java/com/fnproject/fn/testing/FnHttpEventBuilder.java b/testing-core/src/main/java/com/fnproject/fn/testing/FnHttpEventBuilder.java index 0813ce5b..75762da0 100644 --- a/testing-core/src/main/java/com/fnproject/fn/testing/FnHttpEventBuilder.java +++ b/testing-core/src/main/java/com/fnproject/fn/testing/FnHttpEventBuilder.java @@ -1,3 +1,19 @@ +/* + * Copyright (c) 2019, 2020 Oracle and/or its affiliates. All rights reserved. + * + * 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. + */ + package com.fnproject.fn.testing; import com.fnproject.fn.api.Headers; diff --git a/testing-core/src/main/java/com/fnproject/fn/testing/FnResult.java b/testing-core/src/main/java/com/fnproject/fn/testing/FnResult.java index 6c660013..814067a3 100644 --- a/testing-core/src/main/java/com/fnproject/fn/testing/FnResult.java +++ b/testing-core/src/main/java/com/fnproject/fn/testing/FnResult.java @@ -1,3 +1,19 @@ +/* + * Copyright (c) 2019, 2020 Oracle and/or its affiliates. All rights reserved. + * + * 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. + */ + package com.fnproject.fn.testing; import com.fnproject.fn.api.OutputEvent; diff --git a/testing-core/src/main/java/com/fnproject/fn/testing/FnTestingClassLoader.java b/testing-core/src/main/java/com/fnproject/fn/testing/FnTestingClassLoader.java index ff45abec..af0ea446 100644 --- a/testing-core/src/main/java/com/fnproject/fn/testing/FnTestingClassLoader.java +++ b/testing-core/src/main/java/com/fnproject/fn/testing/FnTestingClassLoader.java @@ -1,3 +1,19 @@ +/* + * Copyright (c) 2019, 2020 Oracle and/or its affiliates. All rights reserved. + * + * 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. + */ + package com.fnproject.fn.testing; import com.fnproject.fn.runtime.EntryPoint; diff --git a/testing-core/src/main/java/com/fnproject/fn/testing/FunctionError.java b/testing-core/src/main/java/com/fnproject/fn/testing/FunctionError.java index 840a969a..5cf5cbc9 100644 --- a/testing-core/src/main/java/com/fnproject/fn/testing/FunctionError.java +++ b/testing-core/src/main/java/com/fnproject/fn/testing/FunctionError.java @@ -1,3 +1,19 @@ +/* + * Copyright (c) 2019, 2020 Oracle and/or its affiliates. All rights reserved. + * + * 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. + */ + package com.fnproject.fn.testing; /** diff --git a/testing-core/src/main/java/com/fnproject/fn/testing/HeaderWriter.java b/testing-core/src/main/java/com/fnproject/fn/testing/HeaderWriter.java index d8f9f227..7ef2f8b8 100644 --- a/testing-core/src/main/java/com/fnproject/fn/testing/HeaderWriter.java +++ b/testing-core/src/main/java/com/fnproject/fn/testing/HeaderWriter.java @@ -1,3 +1,19 @@ +/* + * Copyright (c) 2019, 2020 Oracle and/or its affiliates. All rights reserved. + * + * 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. + */ + package com.fnproject.fn.testing; import java.io.IOException; diff --git a/testing-core/src/main/java/com/fnproject/fn/testing/PlatformError.java b/testing-core/src/main/java/com/fnproject/fn/testing/PlatformError.java index 559d0e2c..2255cd74 100644 --- a/testing-core/src/main/java/com/fnproject/fn/testing/PlatformError.java +++ b/testing-core/src/main/java/com/fnproject/fn/testing/PlatformError.java @@ -1,3 +1,19 @@ +/* + * Copyright (c) 2019, 2020 Oracle and/or its affiliates. All rights reserved. + * + * 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. + */ + package com.fnproject.fn.testing; /** diff --git a/testing-junit4/pom.xml b/testing-junit4/pom.xml index 1e8f9c37..c55e5d08 100644 --- a/testing-junit4/pom.xml +++ b/testing-junit4/pom.xml @@ -1,4 +1,22 @@ + + diff --git a/testing-junit4/src/main/java/com/fnproject/fn/testing/FnEventBuilderJUnit4.java b/testing-junit4/src/main/java/com/fnproject/fn/testing/FnEventBuilderJUnit4.java index 80a2312d..343d97f2 100644 --- a/testing-junit4/src/main/java/com/fnproject/fn/testing/FnEventBuilderJUnit4.java +++ b/testing-junit4/src/main/java/com/fnproject/fn/testing/FnEventBuilderJUnit4.java @@ -1,3 +1,19 @@ +/* + * Copyright (c) 2019, 2020 Oracle and/or its affiliates. All rights reserved. + * + * 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. + */ + package com.fnproject.fn.testing; public interface FnEventBuilderJUnit4 extends FnEventBuilder { diff --git a/testing-junit4/src/main/java/com/fnproject/fn/testing/FnTestingRule.java b/testing-junit4/src/main/java/com/fnproject/fn/testing/FnTestingRule.java index 367cf5be..e8246ef5 100644 --- a/testing-junit4/src/main/java/com/fnproject/fn/testing/FnTestingRule.java +++ b/testing-junit4/src/main/java/com/fnproject/fn/testing/FnTestingRule.java @@ -1,3 +1,19 @@ +/* + * Copyright (c) 2019, 2020 Oracle and/or its affiliates. All rights reserved. + * + * 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. + */ + package com.fnproject.fn.testing; import com.fasterxml.jackson.databind.ObjectMapper; diff --git a/testing-junit4/src/main/java/com/fnproject/fn/testing/FnTestingRuleFeature.java b/testing-junit4/src/main/java/com/fnproject/fn/testing/FnTestingRuleFeature.java index 42b25454..adbf3c8f 100644 --- a/testing-junit4/src/main/java/com/fnproject/fn/testing/FnTestingRuleFeature.java +++ b/testing-junit4/src/main/java/com/fnproject/fn/testing/FnTestingRuleFeature.java @@ -1,3 +1,19 @@ +/* + * Copyright (c) 2019, 2020 Oracle and/or its affiliates. All rights reserved. + * + * 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. + */ + package com.fnproject.fn.testing; import java.io.PrintStream; diff --git a/testing-junit4/src/test/java/com/fnproject/fn/testing/FnTestingRuleTest.java b/testing-junit4/src/test/java/com/fnproject/fn/testing/FnTestingRuleTest.java index 03df8764..e8d8be43 100644 --- a/testing-junit4/src/test/java/com/fnproject/fn/testing/FnTestingRuleTest.java +++ b/testing-junit4/src/test/java/com/fnproject/fn/testing/FnTestingRuleTest.java @@ -1,3 +1,19 @@ +/* + * Copyright (c) 2019, 2020 Oracle and/or its affiliates. All rights reserved. + * + * 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. + */ + package com.fnproject.fn.testing; import com.fnproject.fn.api.Headers; diff --git a/testing/pom.xml b/testing/pom.xml index 41d1c188..8ee86d46 100644 --- a/testing/pom.xml +++ b/testing/pom.xml @@ -1,4 +1,22 @@ + + From ee8852fe3ad70f7a7e6b3f654b8ad2bf1c4578a7 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 13 Oct 2020 10:23:24 +0000 Subject: [PATCH 187/310] build(deps-dev): bump junit from 4.12 to 4.13.1 in /images/init-native Bumps [junit](https://github.com/junit-team/junit4) from 4.12 to 4.13.1. - [Release notes](https://github.com/junit-team/junit4/releases) - [Changelog](https://github.com/junit-team/junit4/blob/main/doc/ReleaseNotes4.12.md) - [Commits](https://github.com/junit-team/junit4/compare/r4.12...r4.13.1) Signed-off-by: dependabot[bot] --- images/init-native/pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/images/init-native/pom.xml b/images/init-native/pom.xml index d4436461..f33f0125 100644 --- a/images/init-native/pom.xml +++ b/images/init-native/pom.xml @@ -63,7 +63,7 @@ junit junit - 4.12 + 4.13.1 test From 8568fdfbef3727fbe7bf368f8ce939d3f61f8c56 Mon Sep 17 00:00:00 2001 From: CI Date: Tue, 13 Oct 2020 11:05:06 +0000 Subject: [PATCH 188/310] fn-java-fdk: post-1.0.111 version bump [skip ci] --- release.version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/release.version b/release.version index 0983ece2..44b7bfd1 100644 --- a/release.version +++ b/release.version @@ -1 +1 @@ -1.0.111 +1.0.112 From 408ee1a8f5398618921d54ef43900201118ea946 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 21 Oct 2020 09:52:02 +0000 Subject: [PATCH 189/310] build(deps): bump junit from 4.12 to 4.13.1 in /images/build Bumps [junit](https://github.com/junit-team/junit4) from 4.12 to 4.13.1. - [Release notes](https://github.com/junit-team/junit4/releases) - [Changelog](https://github.com/junit-team/junit4/blob/main/doc/ReleaseNotes4.12.md) - [Commits](https://github.com/junit-team/junit4/compare/r4.12...r4.13.1) Signed-off-by: dependabot[bot] --- images/build/pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/images/build/pom.xml b/images/build/pom.xml index c28fcf94..6814ae86 100644 --- a/images/build/pom.xml +++ b/images/build/pom.xml @@ -58,7 +58,7 @@ junit junit - 4.12 + 4.13.1 From 1e2882cf7ca9bd363b0f44879783392f656b614d Mon Sep 17 00:00:00 2001 From: CI Date: Wed, 21 Oct 2020 10:04:27 +0000 Subject: [PATCH 190/310] fn-java-fdk: post-1.0.112 version bump [skip ci] --- release.version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/release.version b/release.version index 44b7bfd1..c57dafa3 100644 --- a/release.version +++ b/release.version @@ -1 +1 @@ -1.0.112 +1.0.113 From 9226261b3a6b876a7959ea37da6e56afe27cd845 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 21 Oct 2020 10:22:26 +0000 Subject: [PATCH 191/310] build(deps): bump junit from 4.12 to 4.13.1 Bumps [junit](https://github.com/junit-team/junit4) from 4.12 to 4.13.1. - [Release notes](https://github.com/junit-team/junit4/releases) - [Changelog](https://github.com/junit-team/junit4/blob/main/doc/ReleaseNotes4.12.md) - [Commits](https://github.com/junit-team/junit4/compare/r4.12...r4.13.1) Signed-off-by: dependabot[bot] --- examples/async-thumbnails/pom.xml | 2 +- examples/regex-query/pom.xml | 2 +- examples/string-reverse/pom.xml | 2 +- pom.xml | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/examples/async-thumbnails/pom.xml b/examples/async-thumbnails/pom.xml index 043cbe17..b43fb037 100644 --- a/examples/async-thumbnails/pom.xml +++ b/examples/async-thumbnails/pom.xml @@ -83,7 +83,7 @@ junit junit - 4.12 + 4.13.1 test diff --git a/examples/regex-query/pom.xml b/examples/regex-query/pom.xml index ab7db867..a7e6819e 100644 --- a/examples/regex-query/pom.xml +++ b/examples/regex-query/pom.xml @@ -48,7 +48,7 @@ junit junit - 4.12 + 4.13.1 test diff --git a/examples/string-reverse/pom.xml b/examples/string-reverse/pom.xml index b48ff3b5..2b571930 100644 --- a/examples/string-reverse/pom.xml +++ b/examples/string-reverse/pom.xml @@ -63,7 +63,7 @@ junit junit - 4.12 + 4.13.1 test diff --git a/pom.xml b/pom.xml index 155ac254..80423263 100644 --- a/pom.xml +++ b/pom.xml @@ -51,7 +51,7 @@ 2.11.0 0.8.1 9.4.12.v20180830 - 4.12 + 4.13.1 3.3.3 1.4.0 1.7.25 From 718882e127ff31006f9a066b7999c67fcf7b65dd Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 21 Oct 2020 12:11:59 +0000 Subject: [PATCH 192/310] build(deps): bump junit from 4.12 to 4.13.1 in /integration-tests Bumps [junit](https://github.com/junit-team/junit4) from 4.12 to 4.13.1. - [Release notes](https://github.com/junit-team/junit4/releases) - [Changelog](https://github.com/junit-team/junit4/blob/main/doc/ReleaseNotes4.12.md) - [Commits](https://github.com/junit-team/junit4/compare/r4.12...r4.13.1) Signed-off-by: dependabot[bot] --- integration-tests/pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/integration-tests/pom.xml b/integration-tests/pom.xml index 22b83ee7..b58b37b8 100644 --- a/integration-tests/pom.xml +++ b/integration-tests/pom.xml @@ -30,7 +30,7 @@ 3.16.1 2.6 2.11.0 - 4.12 + 4.13.1 2.22.1 jar From 13a4d00d0e5c29c7e78907dad701771e4396d925 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 21 Oct 2020 12:12:00 +0000 Subject: [PATCH 193/310] build(deps-dev): bump junit in /integration-tests/funcs/httpgwfunc Bumps [junit](https://github.com/junit-team/junit4) from 4.12 to 4.13.1. - [Release notes](https://github.com/junit-team/junit4/releases) - [Changelog](https://github.com/junit-team/junit4/blob/main/doc/ReleaseNotes4.12.md) - [Commits](https://github.com/junit-team/junit4/compare/r4.12...r4.13.1) Signed-off-by: dependabot[bot] --- integration-tests/funcs/httpgwfunc/pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/integration-tests/funcs/httpgwfunc/pom.xml b/integration-tests/funcs/httpgwfunc/pom.xml index 18737290..bf4fcd84 100644 --- a/integration-tests/funcs/httpgwfunc/pom.xml +++ b/integration-tests/funcs/httpgwfunc/pom.xml @@ -57,7 +57,7 @@ junit junit - 4.12 + 4.13.1 test From 8cf0459c7f2eed7af1aa4e35589e5545ad283d31 Mon Sep 17 00:00:00 2001 From: CI Date: Wed, 21 Oct 2020 12:22:27 +0000 Subject: [PATCH 194/310] fn-java-fdk: post-1.0.113 version bump [skip ci] --- release.version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/release.version b/release.version index c57dafa3..f12d81c2 100644 --- a/release.version +++ b/release.version @@ -1 +1 @@ -1.0.113 +1.0.114 From 616a5cd7701b28754670ca338f46439ebc999c9f Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 21 Oct 2020 13:00:43 +0000 Subject: [PATCH 195/310] build(deps-dev): bump junit from 4.12 to 4.13.1 in /examples/qr-code Bumps [junit](https://github.com/junit-team/junit4) from 4.12 to 4.13.1. - [Release notes](https://github.com/junit-team/junit4/releases) - [Changelog](https://github.com/junit-team/junit4/blob/main/doc/ReleaseNotes4.12.md) - [Commits](https://github.com/junit-team/junit4/compare/r4.12...r4.13.1) Signed-off-by: dependabot[bot] --- examples/qr-code/pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/qr-code/pom.xml b/examples/qr-code/pom.xml index b5c14942..b9cec937 100644 --- a/examples/qr-code/pom.xml +++ b/examples/qr-code/pom.xml @@ -48,7 +48,7 @@ junit junit - 4.12 + 4.13.1 test From ed2fb606df59e005a7277c11d40cd6845b1a9173 Mon Sep 17 00:00:00 2001 From: CI Date: Wed, 21 Oct 2020 13:12:29 +0000 Subject: [PATCH 196/310] fn-java-fdk: post-1.0.114 version bump [skip ci] --- release.version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/release.version b/release.version index f12d81c2..b7eefcab 100644 --- a/release.version +++ b/release.version @@ -1 +1 @@ -1.0.114 +1.0.115 From 529d06f43aaf559153aa53a80fed095436f3bcde Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 21 Oct 2020 15:21:58 +0000 Subject: [PATCH 197/310] build(deps-dev): bump junit in /integration-tests/funcs/flowExitHooks Bumps [junit](https://github.com/junit-team/junit4) from 4.12 to 4.13.1. - [Release notes](https://github.com/junit-team/junit4/releases) - [Changelog](https://github.com/junit-team/junit4/blob/main/doc/ReleaseNotes4.12.md) - [Commits](https://github.com/junit-team/junit4/compare/r4.12...r4.13.1) Signed-off-by: dependabot[bot] --- integration-tests/funcs/flowExitHooks/pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/integration-tests/funcs/flowExitHooks/pom.xml b/integration-tests/funcs/flowExitHooks/pom.xml index fa0e4163..e8082fe8 100644 --- a/integration-tests/funcs/flowExitHooks/pom.xml +++ b/integration-tests/funcs/flowExitHooks/pom.xml @@ -58,7 +58,7 @@ junit junit - 4.12 + 4.13.1 test From f53dd40109f078480cf52f8d19e710bd588cd140 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 21 Oct 2020 15:24:25 +0000 Subject: [PATCH 198/310] build(deps-dev): bump junit in /integration-tests/funcs/simpleFunc Bumps [junit](https://github.com/junit-team/junit4) from 4.12 to 4.13.1. - [Release notes](https://github.com/junit-team/junit4/releases) - [Changelog](https://github.com/junit-team/junit4/blob/main/doc/ReleaseNotes4.12.md) - [Commits](https://github.com/junit-team/junit4/compare/r4.12...r4.13.1) Signed-off-by: dependabot[bot] --- integration-tests/funcs/simpleFunc/pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/integration-tests/funcs/simpleFunc/pom.xml b/integration-tests/funcs/simpleFunc/pom.xml index d02a960c..1c9fe9f2 100644 --- a/integration-tests/funcs/simpleFunc/pom.xml +++ b/integration-tests/funcs/simpleFunc/pom.xml @@ -48,7 +48,7 @@ junit junit - 4.12 + 4.13.1 test From 08006262b14b2518c69fb8288b625aba19303a16 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 21 Oct 2020 15:50:14 +0000 Subject: [PATCH 199/310] build(deps-dev): bump junit in /integration-tests/funcs/flowTimeouts Bumps [junit](https://github.com/junit-team/junit4) from 4.12 to 4.13.1. - [Release notes](https://github.com/junit-team/junit4/releases) - [Changelog](https://github.com/junit-team/junit4/blob/main/doc/ReleaseNotes4.12.md) - [Commits](https://github.com/junit-team/junit4/compare/r4.12...r4.13.1) Signed-off-by: dependabot[bot] --- integration-tests/funcs/flowTimeouts/pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/integration-tests/funcs/flowTimeouts/pom.xml b/integration-tests/funcs/flowTimeouts/pom.xml index 46df8cb3..1e8cf1eb 100644 --- a/integration-tests/funcs/flowTimeouts/pom.xml +++ b/integration-tests/funcs/flowTimeouts/pom.xml @@ -57,7 +57,7 @@ junit junit - 4.12 + 4.13.1 test From cbec3ce9a2e778da9153a0327b222920f8324431 Mon Sep 17 00:00:00 2001 From: CI Date: Wed, 21 Oct 2020 16:02:26 +0000 Subject: [PATCH 200/310] fn-java-fdk: post-1.0.115 version bump [skip ci] --- release.version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/release.version b/release.version index b7eefcab..c486e863 100644 --- a/release.version +++ b/release.version @@ -1 +1 @@ -1.0.115 +1.0.116 From 08b34e787b8490b1e0926aca2ca300305080f1d4 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 21 Oct 2020 16:34:51 +0000 Subject: [PATCH 201/310] build(deps-dev): bump junit in /integration-tests/funcs/flowAllFeatures Bumps [junit](https://github.com/junit-team/junit4) from 4.12 to 4.13.1. - [Release notes](https://github.com/junit-team/junit4/releases) - [Changelog](https://github.com/junit-team/junit4/blob/main/doc/ReleaseNotes4.12.md) - [Commits](https://github.com/junit-team/junit4/compare/r4.12...r4.13.1) Signed-off-by: dependabot[bot] --- integration-tests/funcs/flowAllFeatures/pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/integration-tests/funcs/flowAllFeatures/pom.xml b/integration-tests/funcs/flowAllFeatures/pom.xml index 4bcd99e1..e1ccaaae 100644 --- a/integration-tests/funcs/flowAllFeatures/pom.xml +++ b/integration-tests/funcs/flowAllFeatures/pom.xml @@ -61,7 +61,7 @@ junit junit - 4.12 + 4.13.1 test From 5cca57debb308cf87961ad87dba28e16bffacd14 Mon Sep 17 00:00:00 2001 From: CI Date: Wed, 21 Oct 2020 16:45:05 +0000 Subject: [PATCH 202/310] fn-java-fdk: post-1.0.116 version bump [skip ci] --- release.version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/release.version b/release.version index c486e863..86ec33ae 100644 --- a/release.version +++ b/release.version @@ -1 +1 @@ -1.0.116 +1.0.117 From e57e05656a815ceedb8215c442d388d17f9b2e44 Mon Sep 17 00:00:00 2001 From: Pavol Gressa Date: Wed, 6 Jan 2021 12:55:00 +0100 Subject: [PATCH 203/310] Add resources to classpath --- images/runtime/Dockerfile | 2 +- images/runtime/Dockerfile-jre11 | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/images/runtime/Dockerfile b/images/runtime/Dockerfile index d14e990f..03312f01 100644 --- a/images/runtime/Dockerfile +++ b/images/runtime/Dockerfile @@ -34,4 +34,4 @@ RUN addgroup --system --gid 1000 fn && adduser --uid 1000 --gid 1000 fn # # The max memory value obtained with these args seem to be okay for most memory limits. The exception is when the # memory limit is set to 128MiB, in which case maxMemory returns roughly half. -ENTRYPOINT [ "java", "-XX:+UnlockExperimentalVMOptions", "-XX:+UseCGroupMemoryLimitForHeap", "-XX:-UsePerfData", "-XX:MaxRAMFraction=2", "-XX:+UseSerialGC", "-Xshare:on", "-Djava.library.path=/function/runtime/lib", "-cp", "/function/app/*:/function/runtime/*", "com.fnproject.fn.runtime.EntryPoint" ] +ENTRYPOINT [ "java", "-XX:+UnlockExperimentalVMOptions", "-XX:+UseCGroupMemoryLimitForHeap", "-XX:-UsePerfData", "-XX:MaxRAMFraction=2", "-XX:+UseSerialGC", "-Xshare:on", "-Djava.library.path=/function/runtime/lib", "-cp", "/function/app/*:/function/runtime/*:/function/app:/function/app/resources", "com.fnproject.fn.runtime.EntryPoint" ] diff --git a/images/runtime/Dockerfile-jre11 b/images/runtime/Dockerfile-jre11 index ea8391c6..ad81ea20 100644 --- a/images/runtime/Dockerfile-jre11 +++ b/images/runtime/Dockerfile-jre11 @@ -32,5 +32,5 @@ RUN addgroup --system --gid 1000 fn && adduser --uid 1000 --gid 1000 fn ENTRYPOINT [ "/usr/local/openjdk-11/bin/java", "-XX:-UsePerfData", "-XX:+UseSerialGC", "-Xshare:on", \ "-Djava.awt.headless=true" , \ "-Djava.library.path=/function/runtime/lib", \ - "-cp", "/function/app/*:/function/runtime/*", \ + "-cp", "/function/app/*:/function/runtime/*:/function/app:/function/app/resources", \ "com.fnproject.fn.runtime.EntryPoint" ] From 806852ae54564d515fe4006cefca77586f4568c9 Mon Sep 17 00:00:00 2001 From: CI Date: Wed, 13 Jan 2021 01:35:23 +0000 Subject: [PATCH 204/310] fn-java-fdk: post-1.0.117 version bump [skip ci] --- release.version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/release.version b/release.version index 86ec33ae..32846de8 100644 --- a/release.version +++ b/release.version @@ -1 +1 @@ -1.0.117 +1.0.118 From 740b95dd5756ecafc37e85de9ec75ddb8ad72de4 Mon Sep 17 00:00:00 2001 From: CI Date: Tue, 26 Jan 2021 15:58:02 +0000 Subject: [PATCH 205/310] fn-java-fdk: post-1.0.118 version bump [skip ci] --- release.version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/release.version b/release.version index 32846de8..b0978b85 100644 --- a/release.version +++ b/release.version @@ -1 +1 @@ -1.0.118 +1.0.119 From 976e6c90de2d84129530f2d8899142474a609394 Mon Sep 17 00:00:00 2001 From: Owen Cliffe Date: Fri, 12 Feb 2021 14:15:57 +0000 Subject: [PATCH 206/310] Always log errors during functions startup (#245) --- .../funcs/flowAllFeatures/pom.xml | 3 +- .../com/fnproject/fn/runtime/EntryPoint.java | 145 ++++++++++++------ .../fn/runtime/MethodFunctionInvoker.java | 33 ++-- .../fn/runtime/ConfigurationMethodsTest.java | 9 +- .../fn/runtime/EndToEndInvokeTest.java | 16 +- .../fn/runtime/ErrorMessagesTest.java | 9 +- .../fn/runtime/FunctionConstructionTest.java | 8 + 7 files changed, 137 insertions(+), 86 deletions(-) diff --git a/integration-tests/funcs/flowAllFeatures/pom.xml b/integration-tests/funcs/flowAllFeatures/pom.xml index e1ccaaae..7efee1dd 100644 --- a/integration-tests/funcs/flowAllFeatures/pom.xml +++ b/integration-tests/funcs/flowAllFeatures/pom.xml @@ -24,6 +24,7 @@ UTF-8 1.0.0-SNAPSHOT + 4.13.1 com.fnproject.fn integration-test-4 @@ -61,7 +62,7 @@ junit junit - 4.13.1 + ${junit.version} test diff --git a/runtime/src/main/java/com/fnproject/fn/runtime/EntryPoint.java b/runtime/src/main/java/com/fnproject/fn/runtime/EntryPoint.java index 1e9f739e..7efa3497 100644 --- a/runtime/src/main/java/com/fnproject/fn/runtime/EntryPoint.java +++ b/runtime/src/main/java/com/fnproject/fn/runtime/EntryPoint.java @@ -26,6 +26,7 @@ import java.util.Map; import java.util.Set; import java.util.concurrent.atomic.AtomicInteger; +import java.util.function.Consumer; import java.util.regex.Pattern; import com.fnproject.fn.api.FnFeature; @@ -74,6 +75,31 @@ public static void main(String... args) { System.exit(exitCode); } + + /* + * If enabled, print the logging framing content otherwise do nothing + */ + private Consumer logFramer(Map config) { + String framer = config.getOrDefault("FN_LOGFRAME_NAME", ""); + + if (!framer.isEmpty()) { + String valueSrc = config.getOrDefault("FN_LOGFRAME_HDR", ""); + + if (!valueSrc.isEmpty()) { + return (evt) -> { + String id = evt.getHeaders().get(valueSrc).orElse(""); + if (!id.isEmpty()) { + System.out.println("\n" + framer + "=" + id + "\n"); + System.err.println("\n" + framer + "=" + id + "\n"); + } + + }; + } + } + return (event) -> { + }; + } + /** * Entry point runner - this executes the whole lifecycle of the fn Java FDK runtime - including multiple invocations in the function for hot functions * @@ -100,66 +126,83 @@ public int run(Map env, EventCodec codec, PrintStream loggingOut final AtomicInteger lastStatus = new AtomicInteger(); try { final Map configFromEnvVars = Collections.unmodifiableMap(excludeInternalConfigAndHeaders(env)); + Consumer logFramer = logFramer(configFromEnvVars); + codec.runCodec(new EventCodec.Handler() { + FunctionRuntimeContext _runtimeContext; + + // Create runtime context within first call to ensure that init errors are propagated + private FunctionRuntimeContext getRuntimeContext() { + if (_runtimeContext == null) { + FunctionLoader functionLoader = new FunctionLoader(); + + MethodWrapper method = functionLoader.loadClass(cls, mth); + FunctionRuntimeContext runtimeContext = new FunctionRuntimeContext(method, configFromEnvVars); + FnFeature f = method.getTargetClass().getAnnotation(FnFeature.class); + if (f != null) { + enableFeature(runtimeContext, f); + } + FnFeatures fs = method.getTargetClass().getAnnotation(FnFeatures.class); + if (fs != null) { + for (FnFeature fnFeature : fs.value()) { + enableFeature(runtimeContext, fnFeature); + } + } - FunctionLoader functionLoader = new FunctionLoader(); - - MethodWrapper method = functionLoader.loadClass(cls, mth); - FunctionRuntimeContext runtimeContext = new FunctionRuntimeContext(method, configFromEnvVars); - FnFeature f = method.getTargetClass().getAnnotation(FnFeature.class); - if (f != null) { - enableFeature(runtimeContext, f); - } - FnFeatures fs = method.getTargetClass().getAnnotation(FnFeatures.class); - if (fs != null) { - for (FnFeature fnFeature : fs.value()) { - enableFeature(runtimeContext, fnFeature); + FunctionConfigurer functionConfigurer = new FunctionConfigurer(); + functionConfigurer.configure(runtimeContext); + _runtimeContext = runtimeContext; + } + return _runtimeContext; } - } - - FunctionConfigurer functionConfigurer = new FunctionConfigurer(); - functionConfigurer.configure(runtimeContext); - - codec.runCodec((evt) -> { - try { - FunctionInvocationContext fic = runtimeContext.newInvocationContext(evt); - try (InputEvent myEvt = evt) { - OutputEvent output = runtimeContext.tryInvoke(evt, fic); - if (output == null) { - throw new FunctionInputHandlingException("No invoker found for input event"); - } - if (output.isSuccess()) { - lastStatus.set(0); - fic.fireOnSuccessfulInvocation(); - } else { - lastStatus.set(1); + @Override + public OutputEvent handle(InputEvent evt) { + try { + // output log frame prior to any user code execution + logFramer.accept(evt); + FunctionRuntimeContext runtimeContext = getRuntimeContext(); + FunctionInvocationContext fic = runtimeContext.newInvocationContext(evt); + try (InputEvent myEvt = evt) { + OutputEvent output = runtimeContext.tryInvoke(evt, fic); + if (output == null) { + throw new FunctionInputHandlingException("No invoker found for input event"); + } + if (output.isSuccess()) { + lastStatus.set(0); + fic.fireOnSuccessfulInvocation(); + } else { + lastStatus.set(1); + fic.fireOnFailedInvocation(); + } + + return output.withHeaders(output.getHeaders().setHeaders(fic.getAdditionalResponseHeaders())); + + + } catch (IOException err) { + fic.fireOnFailedInvocation(); + throw new FunctionInputHandlingException("Error closing function input", err); + } catch (Exception e) { + // Make sure we commit any pending Flows, then rethrow fic.fireOnFailedInvocation(); + throw e; } - - return output.withHeaders(output.getHeaders().setHeaders(fic.getAdditionalResponseHeaders())); - - - } catch (IOException err) { - fic.fireOnFailedInvocation(); - throw new FunctionInputHandlingException("Error closing function input", err); - } catch (Exception e) { - // Make sure we commit any pending Flows, then rethrow - fic.fireOnFailedInvocation(); - throw e; + } catch (InternalFunctionInvocationException fie) { + loggingOutput.println("An error occurred in function: " + filterStackTraceToOnlyIncludeUsersCode(fie)); + loggingOutput.flush(); + // Here: completer-invoked continuations are *always* reported as successful to the Fn platform; + // the completer interprets the embedded HTTP-framed response. + lastStatus.set(fie.toOutput().isSuccess() ? 0 : 1); + return fie.toOutput(); + } catch (FunctionLoadException | FunctionInputHandlingException | FunctionOutputHandlingException e) { + // catch all block; + loggingOutput.println(filterStackTraceToOnlyIncludeUsersCode(e)); + loggingOutput.flush(); + lastStatus.set(2); + return new InternalFunctionInvocationException("Error initializing function", e).toOutput(); } - } catch (InternalFunctionInvocationException fie) { - loggingOutput.println("An error occurred in function: " + filterStackTraceToOnlyIncludeUsersCode(fie)); - // Here: completer-invoked continuations are *always* reported as successful to the Fn platform; - // the completer interprets the embedded HTTP-framed response. - lastStatus.set(fie.toOutput().isSuccess() ? 0 : 1); - return fie.toOutput(); } }); - } catch (FunctionLoadException | FunctionInputHandlingException | FunctionOutputHandlingException e) { - // catch all block; - loggingOutput.println(filterStackTraceToOnlyIncludeUsersCode(e)); - return 2; } catch (Exception ee) { loggingOutput.println("An unexpected error occurred:"); ee.printStackTrace(loggingOutput); diff --git a/runtime/src/main/java/com/fnproject/fn/runtime/MethodFunctionInvoker.java b/runtime/src/main/java/com/fnproject/fn/runtime/MethodFunctionInvoker.java index 1e5b679a..0729ff37 100644 --- a/runtime/src/main/java/com/fnproject/fn/runtime/MethodFunctionInvoker.java +++ b/runtime/src/main/java/com/fnproject/fn/runtime/MethodFunctionInvoker.java @@ -17,14 +17,19 @@ package com.fnproject.fn.runtime; -import com.fnproject.fn.api.*; +import java.lang.reflect.InvocationTargetException; +import java.util.Optional; + +import com.fnproject.fn.api.FunctionInvoker; +import com.fnproject.fn.api.InputEvent; +import com.fnproject.fn.api.InvocationContext; +import com.fnproject.fn.api.MethodWrapper; +import com.fnproject.fn.api.OutputEvent; +import com.fnproject.fn.api.RuntimeContext; import com.fnproject.fn.api.exception.FunctionInputHandlingException; import com.fnproject.fn.api.exception.FunctionOutputHandlingException; import com.fnproject.fn.runtime.exception.InternalFunctionInvocationException; -import java.lang.reflect.InvocationTargetException; -import java.util.Optional; - /** * Method function invoker *

    @@ -33,25 +38,6 @@ */ public class MethodFunctionInvoker implements FunctionInvoker { - /* - * If enabled, print the logging framing content - */ - public void logFramer(FunctionRuntimeContext rctx, InputEvent evt) { - String framer = rctx.getConfigurationByKey("FN_LOGFRAME_NAME").orElse(""); - - if (framer != "") { - String valueSrc = rctx.getConfigurationByKey("FN_LOGFRAME_HDR").orElse(""); - - if (valueSrc != "") { - String id = evt.getHeaders().get(valueSrc).orElse(""); - if (id != "") { - System.out.println("\n" + framer + "=" + id + "\n"); - System.err.println("\n" + framer + "=" + id + "\n"); - } - } - } - } - /** * Invoke the function wrapped by this loader @@ -69,7 +55,6 @@ public Optional tryInvoke(InvocationContext ctx, InputEvent evt) th Object rawResult; - logFramer(runtimeContext, evt); try { rawResult = method.getTargetMethod().invoke(ctx.getRuntimeContext().getInvokeInstance().orElse(null), userFunctionParams); diff --git a/runtime/src/test/java/com/fnproject/fn/runtime/ConfigurationMethodsTest.java b/runtime/src/test/java/com/fnproject/fn/runtime/ConfigurationMethodsTest.java index b95a34bf..bc7a6e1e 100644 --- a/runtime/src/test/java/com/fnproject/fn/runtime/ConfigurationMethodsTest.java +++ b/runtime/src/test/java/com/fnproject/fn/runtime/ConfigurationMethodsTest.java @@ -16,6 +16,7 @@ package com.fnproject.fn.runtime; +import com.fnproject.fn.api.OutputEvent; import com.fnproject.fn.runtime.testfns.TestFnWithConfigurationMethods; import org.junit.Rule; import org.junit.Test; @@ -84,7 +85,7 @@ public void staticTargetWithInstanceConfigurationIsAnError() throws Exception { fn.thenRun(TestFnWithConfigurationMethods.StaticTargetInstanceConfiguration.class, "echo"); - assertThat(fn.getOutputs()).isEmpty(); + assertThat(fn.getOutputs()).hasSize(1).allSatisfy(testOutput -> assertThat(testOutput.getStatus()).isEqualTo(OutputEvent.Status.FunctionError)); assertThat(fn.getStdErrAsString()).startsWith(expectedMessage); assertThat(fn.exitStatus()).isEqualTo(2); } @@ -143,7 +144,7 @@ public void shouldReturnDefaultParameterIfNotProvided() { } @Test - public void shouldReturnSetConfigParameterWhenProvided() { + public void shouldReturnSetConfigParameterWhenProvided() { String value = "value"; fn.setConfig("PARAM", value); fn.givenEvent().enqueue(); @@ -163,7 +164,9 @@ public void nonVoidConfigurationMethodIsAnError() throws Exception { "'config'" + " does not have a void return type"; - assertThat(fn.getOutputs()).isEmpty(); + assertThat(fn.getOutputs()).hasSize(1).allSatisfy(testOutput -> { + assertThat(testOutput.getStatus()).isEqualTo(OutputEvent.Status.FunctionError); + }); assertThat(fn.getStdErrAsString()).startsWith(expectedMessage); assertThat(fn.exitStatus()).isEqualTo(2); } diff --git a/runtime/src/test/java/com/fnproject/fn/runtime/EndToEndInvokeTest.java b/runtime/src/test/java/com/fnproject/fn/runtime/EndToEndInvokeTest.java index a7778d47..95162fbe 100644 --- a/runtime/src/test/java/com/fnproject/fn/runtime/EndToEndInvokeTest.java +++ b/runtime/src/test/java/com/fnproject/fn/runtime/EndToEndInvokeTest.java @@ -16,16 +16,17 @@ package com.fnproject.fn.runtime; +import java.util.Arrays; +import java.util.List; + import com.fnproject.fn.api.InputEvent; +import com.fnproject.fn.api.OutputEvent; import com.fnproject.fn.runtime.testfns.BadTestFnDuplicateMethods; import com.fnproject.fn.runtime.testfns.TestFn; import org.junit.BeforeClass; import org.junit.Rule; import org.junit.Test; -import java.util.Arrays; -import java.util.List; - import static org.assertj.core.api.Assertions.assertThat; /** @@ -149,20 +150,22 @@ public void shouldHandledStreamedHotInputEvent() throws Exception { @Test public void shouldPrintErrorOnUnknownMethod() throws Exception { + fn.givenEvent().enqueue(); fn.thenRun(TestFn.class, "unknownMethod"); assertThat(fn.exitStatus()).isEqualTo(2); - assertThat(fn.getOutputs()).isEmpty(); + assertThat(fn.getOutputs()).hasSize(1).allSatisfy(testOutput -> assertThat(testOutput.getStatus()).isEqualTo(OutputEvent.Status.FunctionError)); assertThat(fn.getStdErrAsString()).startsWith("Method 'unknownMethod' was not found in class 'com.fnproject.fn.runtime.testfns.TestFn'"); } @Test public void shouldPrintErrorOnUnknownClass() throws Exception { + fn.givenEvent().enqueue(); fn.thenRun("com.fnproject.unknown.Class", "unknownMethod"); assertThat(fn.exitStatus()).isEqualTo(2); - assertThat(fn.getOutputs()).hasSize(0); + assertThat(fn.getOutputs()).hasSize(1).allSatisfy(testOutput -> assertThat(testOutput.getStatus()).isEqualTo(OutputEvent.Status.FunctionError)); assertThat(fn.getStdErrAsString()).startsWith("Class 'com.fnproject.unknown.Class' not found in function jar"); } @@ -255,10 +258,11 @@ public void shouldWriteBytesOnDefaultCodec() throws Exception { @Test public void shouldRejectDuplicateMethodsInFunctionClass() throws Exception { + fn.givenEvent().enqueue(); fn.thenRun(BadTestFnDuplicateMethods.class, "fn"); - assertThat(fn.getOutputs()).isEmpty(); assertThat(fn.exitStatus()).isEqualTo(2); + assertThat(fn.getOutputs()).hasSize(1).allSatisfy(testOutput -> assertThat(testOutput.getStatus()).isEqualTo(OutputEvent.Status.FunctionError)); assertThat(fn.getStdErrAsString()).startsWith("Multiple methods match"); } diff --git a/runtime/src/test/java/com/fnproject/fn/runtime/ErrorMessagesTest.java b/runtime/src/test/java/com/fnproject/fn/runtime/ErrorMessagesTest.java index ccd2b202..b24125da 100644 --- a/runtime/src/test/java/com/fnproject/fn/runtime/ErrorMessagesTest.java +++ b/runtime/src/test/java/com/fnproject/fn/runtime/ErrorMessagesTest.java @@ -16,12 +16,14 @@ package com.fnproject.fn.runtime; +import com.fnproject.fn.api.OutputEvent; import com.fnproject.fn.runtime.testfns.ErrorMessages; import not.in.com.fnproject.fn.StacktraceFilteringTestFunctions; +import org.assertj.core.api.Assertions; import org.junit.Rule; import org.junit.Test; -import static org.assertj.core.api.AssertionsForClassTypes.assertThat; +import static org.assertj.core.api.Assertions.assertThat; public class ErrorMessagesTest { @@ -30,12 +32,14 @@ public class ErrorMessagesTest { private void assertIsErrorWithoutStacktrace(String errorMessage) { assertThat(fn.exitStatus()).isEqualTo(2); + assertThat(fn.getOutputs()).hasSize(1).allSatisfy(testOutput -> Assertions.assertThat(testOutput.getStatus()).isEqualTo(OutputEvent.Status.FunctionError)); assertThat(fn.getStdErrAsString()).contains(errorMessage); assertThat(fn.getStdErrAsString().split(System.getProperty("line.separator")).length).isEqualTo(1); } private void assertIsEntryPointErrorWithStacktrace(String errorMessage) { assertThat(fn.exitStatus()).isEqualTo(2); + assertThat(fn.getOutputs()).hasSize(1).allSatisfy(testOutput -> Assertions.assertThat(testOutput.getStatus()).isEqualTo(OutputEvent.Status.FunctionError)); assertThat(fn.getStdErrAsString()).contains(errorMessage); assertThat(fn.getStdErrAsString().split(System.getProperty("line.separator")).length).isGreaterThan(1); assertThat(fn.getStdErrAsString()).doesNotContain("at com.fnproject.fn.runtime"); @@ -52,18 +56,21 @@ private void assertIsFunctionErrorWithStacktrace(String errorMessage) { @Test public void userSpecifiesNonExistentClass(){ + fn.givenEvent().enqueue(); fn.thenRun("NonExistentClass", "method"); assertIsErrorWithoutStacktrace("Class 'NonExistentClass' not found in function jar. It's likely that the 'cmd' entry in func.yaml is incorrect."); } @Test public void userSpecifiesClassWithNoMethods(){ + fn.givenEvent().enqueue(); fn.thenRun(ErrorMessages.NoMethodsClass.class, "thisClassHasNoMethods"); assertIsErrorWithoutStacktrace("Method 'thisClassHasNoMethods' was not found in class 'com.fnproject.fn.runtime.testfns.ErrorMessages.NoMethodsClass'. Available functions were: []"); } @Test public void userSpecifiesMethodWhichDoesNotExist(){ + fn.givenEvent().enqueue(); fn.thenRun(ErrorMessages.OneMethodClass.class, "notTheMethod"); assertIsErrorWithoutStacktrace("Method 'notTheMethod' was not found in class 'com.fnproject.fn.runtime.testfns.ErrorMessages.OneMethodClass'. Available functions were: [theMethod]"); } diff --git a/runtime/src/test/java/com/fnproject/fn/runtime/FunctionConstructionTest.java b/runtime/src/test/java/com/fnproject/fn/runtime/FunctionConstructionTest.java index 847b203d..b0b26ba8 100644 --- a/runtime/src/test/java/com/fnproject/fn/runtime/FunctionConstructionTest.java +++ b/runtime/src/test/java/com/fnproject/fn/runtime/FunctionConstructionTest.java @@ -16,7 +16,9 @@ package com.fnproject.fn.runtime; +import com.fnproject.fn.api.OutputEvent; import com.fnproject.fn.runtime.testfns.TestFnConstructors; +import org.assertj.core.api.Assertions; import org.junit.Rule; import org.junit.Test; @@ -59,6 +61,7 @@ public void shouldFailWithInaccessibleConstructor() { fn.givenEvent().enqueue(); fn.thenRun(TestFnConstructors.BadConstructorNotAccessible.class, "invoke"); assertThat(fn.exitStatus()).isEqualTo(2); + assertThat(fn.getOutputs()).hasSize(1).allSatisfy(testOutput -> Assertions.assertThat(testOutput.getStatus()).isEqualTo(OutputEvent.Status.FunctionError)); assertThat(fn.getStdErrAsString()).contains("cannot be instantiated as it has no public constructors"); } @@ -67,6 +70,7 @@ public void shouldFailFunctionWithTooManyConstructorArgs() { fn.givenEvent().enqueue(); fn.thenRun(TestFnConstructors.BadConstructorTooManyArgs.class, "invoke"); assertThat(fn.exitStatus()).isEqualTo(2); + assertThat(fn.getOutputs()).hasSize(1).allSatisfy(testOutput -> Assertions.assertThat(testOutput.getStatus()).isEqualTo(OutputEvent.Status.FunctionError)); assertThat(fn.getStdErrAsString()).contains("cannot be instantiated as its constructor takes more than one argument"); } @@ -75,6 +79,7 @@ public void shouldFailFunctionWithAmbiguousConstructors() { fn.givenEvent().enqueue(); fn.thenRun(TestFnConstructors.BadConstructorAmbiguousConstructors.class, "invoke"); assertThat(fn.exitStatus()).isEqualTo(2); + assertThat(fn.getOutputs()).hasSize(1).allSatisfy(testOutput -> Assertions.assertThat(testOutput.getStatus()).isEqualTo(OutputEvent.Status.FunctionError)); assertThat(fn.getStdErrAsString()).contains("cannot be instantiated as it has multiple public constructors"); } @@ -83,6 +88,7 @@ public void shouldFailFunctionWithErrorInConstructor() { fn.givenEvent().enqueue(); fn.thenRun(TestFnConstructors.BadConstructorThrowsException.class, "invoke"); assertThat(fn.exitStatus()).isEqualTo(2); + assertThat(fn.getOutputs()).hasSize(1).allSatisfy(testOutput -> Assertions.assertThat(testOutput.getStatus()).isEqualTo(OutputEvent.Status.FunctionError)); assertThat(fn.getStdErrAsString()).contains("An error occurred in the function constructor while instantiating class"); } @@ -91,6 +97,7 @@ public void shouldFailFunctionWithBadSingleConstructConstructorArg() { fn.givenEvent().enqueue(); fn.thenRun(TestFnConstructors.BadConstructorUnrecognisedArg.class, "invoke"); assertThat(fn.exitStatus()).isEqualTo(2); + assertThat(fn.getOutputs()).hasSize(1).allSatisfy(testOutput -> Assertions.assertThat(testOutput.getStatus()).isEqualTo(OutputEvent.Status.FunctionError)); assertThat(fn.getStdErrAsString()).contains("cannot be instantiated as its constructor takes an unrecognized argument of type int"); } @@ -100,6 +107,7 @@ public void shouldFailNonStaticInnerClassWithANiceMessage(){ fn.givenEvent().enqueue(); fn.thenRun(TestFnConstructors.NonStaticInnerClass.class, "invoke"); assertThat(fn.exitStatus()).isEqualTo(2); + assertThat(fn.getOutputs()).hasSize(1).allSatisfy(testOutput -> Assertions.assertThat(testOutput.getStatus()).isEqualTo(OutputEvent.Status.FunctionError)); assertThat(fn.getStdErrAsString()).contains("cannot be instantiated as it is a non-static inner class"); } } From ec3ddc07d204d1a55dbb2d47f787b4711cdf71e6 Mon Sep 17 00:00:00 2001 From: CI Date: Fri, 12 Feb 2021 14:29:05 +0000 Subject: [PATCH 207/310] fn-java-fdk: post-1.0.119 version bump [skip ci] --- release.version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/release.version b/release.version index b0978b85..e37d60d5 100644 --- a/release.version +++ b/release.version @@ -1 +1 @@ -1.0.119 +1.0.120 From 8a8dc9a6a1be09709699b631b2df4f065af96130 Mon Sep 17 00:00:00 2001 From: Owen Cliffe Date: Fri, 12 Feb 2021 16:44:29 +0000 Subject: [PATCH 208/310] Upgraded native image support to GraalVM Community Edition 21.0.0 based on published container images. (#248) Updated Dockerfile FROM dependencies to use specified FDK version, not latest Used FDK version in tag of native image build and init-image so default build command now does not modify source. Replaced sed with Dockerfile ARG for parameters. Added GraalVM version env var to Circle Ci build. Removed debug output from script. Updated tag/push logic for native images. Removed unused variable in build.sh. Use build version by default for graal Added a native integration test Co-authored-by: Shaun Smith --- .circleci/config.yml | 1 + .circleci/release.sh | 53 ++++++++++-------- build.sh | 11 +--- graalvm.version | 1 + images/build-native/Dockerfile | 40 ++------------ images/build-native/Dockerfile-jdk11 | 54 ------------------- images/build-native/README.md | 4 +- images/build-native/docker-build.sh | 28 ++++++---- images/build-native/native.version | 1 - images/init-native/Dockerfile | 6 +-- images/init-native/docker-build.sh | 27 ++++++---- .../integrationtest/IntegrationTestRule.java | 8 ++- .../fn/integrationtest/FunctionsTest.java | 16 ++++++ 13 files changed, 102 insertions(+), 148 deletions(-) create mode 100644 graalvm.version delete mode 100644 images/build-native/Dockerfile-jdk11 delete mode 100644 images/build-native/native.version diff --git a/.circleci/config.yml b/.circleci/config.yml index e8a142bf..698e1171 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -35,6 +35,7 @@ jobs: name: Build and Test FDK command: | export FN_FDK_VERSION=$(cat ./release.version) + export GRAALVM_VERSION=$(cat ./graalvm.version) ./build.sh - run: name: Run integration tests diff --git a/.circleci/release.sh b/.circleci/release.sh index 90b50550..bd4a9a07 100755 --- a/.circleci/release.sh +++ b/.circleci/release.sh @@ -6,8 +6,8 @@ USER=fnproject SERVICE=fn-java-fdk RUNTIME_IMAGE=${SERVICE} BUILD_IMAGE=${SERVICE}-build -NATIVE_INIT_IMAGE=fn-java-native-init NATIVE_BUILD_IMAGE=fn-java-native +NATIVE_INIT_IMAGE=${NATIVE_BUILD_IMAGE}-init release_version=$(cat release.version) if [[ ${release_version} =~ ^[0-9]+\.[0-9]+\.[0-9]+$ ]] ; then @@ -17,6 +17,7 @@ else exit 1 fi +graalvm_version=$(cat graalvm.version) # Calculate new version version_parts=(${release_version//./ }) @@ -72,31 +73,41 @@ git push origin "$release_version" docker push ${USER}/${BUILD_IMAGE}:jdk11-${release_version} docker push ${USER}/${BUILD_IMAGE}:jdk11-${moving_version} - ## native init image + ## native jdk8 build image + docker tag ${USER}/${NATIVE_BUILD_IMAGE}:${release_version} ${USER}/${NATIVE_BUILD_IMAGE}:latest + docker tag ${USER}/${NATIVE_BUILD_IMAGE}:${release_version} ${USER}/${NATIVE_BUILD_IMAGE}:${moving_version} + docker tag ${USER}/${NATIVE_BUILD_IMAGE}:${release_version} ${USER}/${NATIVE_BUILD_IMAGE}:${release_version}-graalvm-ce-${graalvm_version} + docker push ${USER}/${NATIVE_BUILD_IMAGE}:latest + docker push ${USER}/${NATIVE_BUILD_IMAGE}:${release_version} + docker push ${USER}/${NATIVE_BUILD_IMAGE}:${moving_version} + docker push ${USER}/${NATIVE_BUILD_IMAGE}:${release_version}-graalvm-ce-${graalvm_version} + + ## native jdk11 build image + docker tag ${USER}/${NATIVE_BUILD_IMAGE}:jdk11-${release_version} ${USER}/${NATIVE_BUILD_IMAGE}:jdk11-latest + docker tag ${USER}/${NATIVE_BUILD_IMAGE}:jdk11-${release_version} ${USER}/${NATIVE_BUILD_IMAGE}:jdk11-${moving_version} + docker tag ${USER}/${NATIVE_BUILD_IMAGE}:jdk11-${release_version} ${USER}/${NATIVE_BUILD_IMAGE}:jdk11-${release_version}-graalvm-ce-${graalvm_version} + docker push ${USER}/${NATIVE_BUILD_IMAGE}:jdk11-latest + docker push ${USER}/${NATIVE_BUILD_IMAGE}:jdk11-${release_version} + docker push ${USER}/${NATIVE_BUILD_IMAGE}:jdk11-${moving_version} + docker push ${USER}/${NATIVE_BUILD_IMAGE}:jdk11-${release_version}-graalvm-ce-${graalvm_version} + + ## jdk8 native init image docker tag ${USER}/${NATIVE_INIT_IMAGE}:${release_version} ${USER}/${NATIVE_INIT_IMAGE}:latest docker tag ${USER}/${NATIVE_INIT_IMAGE}:${release_version} ${USER}/${NATIVE_INIT_IMAGE}:${moving_version} + docker tag ${USER}/${NATIVE_INIT_IMAGE}:${release_version} ${USER}/${NATIVE_INIT_IMAGE}:${release_version}-graalvm-ce-${graalvm_version} docker push ${USER}/${NATIVE_INIT_IMAGE}:latest docker push ${USER}/${NATIVE_INIT_IMAGE}:${release_version} docker push ${USER}/${NATIVE_INIT_IMAGE}:${moving_version} - -) - -( - ## native jdk8 build image - if [ -f images/build-native/native_build.image ] ; then - native_build_image=$(cat images/build-native/native_build.image) - docker tag ${native_build_image} ${USER}/${NATIVE_BUILD_IMAGE}:latest - docker push ${USER}/${NATIVE_BUILD_IMAGE}:latest - docker push ${native_build_image} - fi - - ## native jdk11 build image - if [ -f images/build-native/native_build_11.image ] ; then - native_build_image=$(cat images/build-native/native_build_11.image) - docker tag ${native_build_image} ${USER}/${NATIVE_BUILD_IMAGE}:jdk11-latest - docker push ${USER}/${NATIVE_BUILD_IMAGE}:jdk11-latest - docker push ${native_build_image} - fi + docker push ${USER}/${NATIVE_INIT_IMAGE}:${release_version}-graalvm-ce-${graalvm_version} + + ## jdk11 native init image + docker tag ${USER}/${NATIVE_INIT_IMAGE}:jdk11-${release_version} ${USER}/${NATIVE_INIT_IMAGE}:jdk11-latest + docker tag ${USER}/${NATIVE_INIT_IMAGE}:jdk11-${release_version} ${USER}/${NATIVE_INIT_IMAGE}:jdk11-${moving_version} + docker tag ${USER}/${NATIVE_INIT_IMAGE}:jdk11-${release_version} ${USER}/${NATIVE_INIT_IMAGE}:jdk11-${release_version}-graalvm-ce-${graalvm_version} + docker push ${USER}/${NATIVE_INIT_IMAGE}:jdk11-latest + docker push ${USER}/${NATIVE_INIT_IMAGE}:jdk11-${release_version} + docker push ${USER}/${NATIVE_INIT_IMAGE}:jdk11-${moving_version} + docker push ${USER}/${NATIVE_INIT_IMAGE}:jdk11-${release_version}-graalvm-ce-${graalvm_version} ) diff --git a/build.sh b/build.sh index bf8e3083..fc8f976e 100755 --- a/build.sh +++ b/build.sh @@ -21,18 +21,9 @@ mkdir -p /tmp/staging_repo rm -rf /tmp/staging_repo/* BUILD_VERSION=${FN_FDK_VERSION:-1.0.0-SNAPSHOT} +export BUILD_VERSION export REPOSITORY_LOCATION=${REPOSITORY_LOCATION:-/tmp/staging_repo} -while [ $# -ne 0 ] -do - case "$1" in - --build-native-java) - BUILD_NATIVE_JAVA=true - ;; - esac - shift -done - ( runtime/src/main/c/rebuild_so.sh ) diff --git a/graalvm.version b/graalvm.version new file mode 100644 index 00000000..2ad7925f --- /dev/null +++ b/graalvm.version @@ -0,0 +1 @@ +21.0.0 \ No newline at end of file diff --git a/images/build-native/Dockerfile b/images/build-native/Dockerfile index b3b85db4..509de251 100644 --- a/images/build-native/Dockerfile +++ b/images/build-native/Dockerfile @@ -13,42 +13,8 @@ # See the License for the specific language governing permissions and # limitations under the License. # +ARG GRAALVM_VERSION +FROM ghcr.io/graalvm/graalvm-ce:${GRAALVM_VERSION} -FROM debian:buster-slim as build - -RUN set -x \ - && apt-get -y update \ - && apt-get -y install gcc g++ git make python zlib1g-dev wget \ - && rm -rf /var/lib/apt/lists/* - -WORKDIR /build - -RUN set -x \ - && git clone --depth 1 https://github.com/graalvm/mx.git \ - && wget -q --output-document jvmcijdk.tar.gz https://github.com/graalvm/openjdk8-jvmci-builder/releases/download/jvmci-20.1-b02/openjdk-8u252+09-jvmci-20.1-b02-linux-amd64.tar.gz \ - && mkdir jvmcijdk8 \ - && tar -xz --strip 1 -f jvmcijdk.tar.gz -C /build/jvmcijdk8 \ - && rm jvmcijdk.tar.gz - -RUN git clone --depth 1 --single-branch https://github.com/oracle/graal.git --branch release/graal-vm/20.1 -WORKDIR /build/graal/vm -RUN export JAVA_HOME=/build/jvmcijdk8 \ - && /build/mx/mx --dy /substratevm --force-bash-launchers=true --disable-polyglot --skip-libraries=true build - -WORKDIR /build/graal/vm/latest_graalvm -RUN LONG_NAME=$(ls) \ - && SHORT_NAME=graalvm \ - && mv $LONG_NAME $SHORT_NAME - -FROM debian:stretch-slim as final - -RUN set -x \ - && apt-get -y update \ - && apt-get -y install gcc zlib1g-dev - -COPY --from=build /build/graal/vm/latest_graalvm/graalvm /usr/local/graalvm +RUN gu install native-image COPY src/main/c/libfnunixsocket.so /function/runtime/lib/ - - -ENV GRAALVM_HOME=/usr/local/graalvm -WORKDIR /function diff --git a/images/build-native/Dockerfile-jdk11 b/images/build-native/Dockerfile-jdk11 deleted file mode 100644 index 64dbe26c..00000000 --- a/images/build-native/Dockerfile-jdk11 +++ /dev/null @@ -1,54 +0,0 @@ -# -# Copyright (c) 2019, 2020 Oracle and/or its affiliates. All rights reserved. -# -# 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. -# - -FROM debian:buster-slim as build - -RUN set -x \ - && apt-get -y update \ - && apt-get -y install gcc g++ git make python zlib1g-dev wget \ - && rm -rf /var/lib/apt/lists/* - -WORKDIR /build - -RUN set -x \ - && git clone --depth 1 https://github.com/graalvm/mx.git \ - && wget -q --output-document jvmcijdk.tar.gz https://github.com/graalvm/labs-openjdk-11/releases/download/jvmci-20.1-b02/labsjdk-ce-11.0.7+10-jvmci-20.1-b02-linux-amd64.tar.gz \ - && mkdir jvmcijdk11 \ - && tar -xz --strip 1 -f jvmcijdk.tar.gz -C /build/jvmcijdk11 \ - && rm jvmcijdk.tar.gz - -RUN git clone --depth 1 --single-branch https://github.com/oracle/graal.git --branch release/graal-vm/20.1 -WORKDIR /build/graal/vm -RUN export JAVA_HOME=/build/jvmcijdk11 \ - && /build/mx/mx --dy /substratevm --force-bash-launchers=true --disable-polyglot --skip-libraries=true build - -WORKDIR /build/graal/vm/latest_graalvm -RUN LONG_NAME=$(ls) \ - && SHORT_NAME=graalvm \ - && mv $LONG_NAME $SHORT_NAME - -FROM debian:stretch-slim as final - -RUN set -x \ - && apt-get -y update \ - && apt-get -y install gcc zlib1g-dev - -COPY --from=build /build/graal/vm/latest_graalvm/graalvm /usr/local/graalvm -COPY src/main/c/libfnunixsocket.so /function/runtime/lib/ - - -ENV GRAALVM_HOME=/usr/local/graalvm -WORKDIR /function diff --git a/images/build-native/README.md b/images/build-native/README.md index 11d3eb0a..320b04d1 100644 --- a/images/build-native/README.md +++ b/images/build-native/README.md @@ -1,5 +1,5 @@ # Native Build image -This rebuilds the substrate build image for native java functions - this build does not run by default on all builds +This rebuilds the GraalVM native image build image -To update the build image, make a change to `native.version` (the target version for the release image) on a branch and merge into master. \ No newline at end of file +To update the build image, make a change to `../../graalvm.version` \ No newline at end of file diff --git a/images/build-native/docker-build.sh b/images/build-native/docker-build.sh index 01f2987c..8cadcec5 100755 --- a/images/build-native/docker-build.sh +++ b/images/build-native/docker-build.sh @@ -20,32 +20,42 @@ then echo "Needs runtime folder as an argument" exit 1 fi -native_version=$(cat native.version) -set -e -workdir=${1} +set -ex + +# If not defined, read the FDK and GraalVM versions +BUILD_VERSION=${BUILD_VERSION:-1.0.0-SNAPSHOT} + +if [ -z "${GRAALVM_VERSION}" ]; then + GRAALVM_VERSION=$(cat ../../graalvm.version) +fi + +# The path to the FDK runtime root folder +fdk_runtime_root=${1} + dockerfiledir=$(pwd) +# Build the Dockerfiles in the runtime root--it pulls in needed libs +cd ${fdk_runtime_root} + # Build JDK 8 -native_image="fnproject/fn-java-native:${native_version}" +native_image="fnproject/fn-java-native:${BUILD_VERSION}" if docker pull ${native_image} ; then echo ${native_image} already exists, skipping native build else ( - cd ${workdir} - docker build -f ${dockerfiledir}/Dockerfile -t "${native_image}" . + docker build -f ${dockerfiledir}/Dockerfile --build-arg GRAALVM_VERSION="java8-${GRAALVM_VERSION}" -t "${native_image}" . ) echo "${native_image}" > native_build.image fi # Build JDK 11 -native_image="fnproject/fn-java-native:jdk11-${native_version}" +native_image="fnproject/fn-java-native:jdk11-${BUILD_VERSION}" if docker pull ${native_image} ; then echo ${native_image} already exists, skipping native build else ( - cd ${workdir} - docker build -f ${dockerfiledir}/Dockerfile-jdk11 -t "${native_image}" . + docker build -f ${dockerfiledir}/Dockerfile --build-arg GRAALVM_VERSION="java11-${GRAALVM_VERSION}" -t "${native_image}" . ) echo "${native_image}" > native_build_11.image fi diff --git a/images/build-native/native.version b/images/build-native/native.version deleted file mode 100644 index a918a2aa..00000000 --- a/images/build-native/native.version +++ /dev/null @@ -1 +0,0 @@ -0.6.0 diff --git a/images/init-native/Dockerfile b/images/init-native/Dockerfile index 25e078e6..1292ea9a 100644 --- a/images/init-native/Dockerfile +++ b/images/init-native/Dockerfile @@ -14,7 +14,7 @@ # limitations under the License. # -FROM fnproject/fn-java-fdk-build:latest as build +FROM fnproject/fn-java-fdk-build:##FN_FDK_VERSION## as build WORKDIR /function ENV MAVEN_OPTS=-Dmaven.repo.local=/usr/share/maven/ref/repository ADD pom.xml pom.xml @@ -22,12 +22,12 @@ RUN ["mvn", "package", "dependency:copy-dependencies", "-DincludeScope=runtime", ADD src src RUN ["mvn", "package"] -FROM fnproject/fn-java-native:latest as build-native-image +FROM fnproject/fn-java-native:##FN_FDK_VERSION## as build-native-image WORKDIR /function COPY --from=build /function/target/*.jar target/ COPY --from=build /function/src/main/conf/reflection.json reflection.json COPY --from=build /function/src/main/conf/jni.json jni.json -RUN /usr/local/graalvm/bin/native-image \ +RUN /usr/bin/native-image \ --static \ --no-fallback \ --initialize-at-build-time= \ diff --git a/images/init-native/docker-build.sh b/images/init-native/docker-build.sh index f2850812..30610cd9 100755 --- a/images/init-native/docker-build.sh +++ b/images/init-native/docker-build.sh @@ -15,15 +15,24 @@ # limitations under the License. # -if [ -z "${FN_FDK_VERSION}" ]; then - FN_FDK_VERSION=$(cat ../../release.version) -fi -sed -i.bak -e "s|.*|${FN_FDK_VERSION}|" pom.xml && rm pom.xml.bak +BUILD_VERSION=${BUILD_VERSION:-1.0.0-SNAPSHOT} + +set -e + +# Update pom.xml with current FDK version +sed -i.bak -e "s|.*|${BUILD_VERSION}|" pom.xml && rm pom.xml.bak + +# Create Dockerfile with current FDK build tag (Java 8) cp Dockerfile Dockerfile.build -docker build -t fnproject/fn-java-native-init:${FN_FDK_VERSION} -f Dockerfile-init-image . +sed -i.bak -e "s|##FN_FDK_VERSION##|${BUILD_VERSION}|" Dockerfile.build && rm Dockerfile.build.bak +# Build init image packaging created Dockerfile (Java 8) +docker build -t fnproject/fn-java-native-init:${BUILD_VERSION} -f Dockerfile-init-image . + +# Create Dockerfile with current FDK build tag (Java 11) cp Dockerfile Dockerfile.build -sed -i.bak -e "s|fnproject/fn-java-fdk-build:latest|fnproject/fn-java-fdk-build:jdk11-latest|" Dockerfile.build && rm Dockerfile.build.bak -sed -i.bak -e "s|fnproject/fn-java-native:latest|fnproject/fn-java-native:jdk11-latest|" Dockerfile.build && rm Dockerfile.build.bak -docker build -t fnproject/fn-java-native-init:jdk11-${FN_FDK_VERSION} -f Dockerfile-init-image . -rm Dockerfile.build \ No newline at end of file +sed -i.bak -e "s|##FN_FDK_VERSION##|jdk11-${BUILD_VERSION}|" Dockerfile.build && rm Dockerfile.build.bak + +# Build init image packaging created Dockerfile (Java 11) +docker build -t fnproject/fn-java-native-init:jdk11-${BUILD_VERSION} -f Dockerfile-init-image . +rm Dockerfile.build diff --git a/integration-tests/src/main/java/com/fnproject/fn/integrationtest/IntegrationTestRule.java b/integration-tests/src/main/java/com/fnproject/fn/integrationtest/IntegrationTestRule.java index abe6b243..53def9d7 100644 --- a/integration-tests/src/main/java/com/fnproject/fn/integrationtest/IntegrationTestRule.java +++ b/integration-tests/src/main/java/com/fnproject/fn/integrationtest/IntegrationTestRule.java @@ -87,7 +87,11 @@ private String getLocalFnRepo() { } - private String getProjectVersion() { + /** + * Returns the current FDK version for this build + * @return A the FDK version (e.g. 1.0.112 or 1.0.0-SNAPSHOT) + */ + public String getFdkVersion() { String version = System.getenv("FN_JAVA_FDK_VERSION"); if (version == null) { @@ -266,7 +270,7 @@ public TestContext rewritePOM() throws Exception { String newPomContent = pomFileContent.replace(repoPlaceholder, "" + getLocalFnRepo() + ""); Assertions.assertThat(newPomContent).withFailMessage("No placeholder found in POM").isNotEqualTo(pomFileContent); - String versionPomContent = newPomContent.replace(versionPlaceholder, "" + getProjectVersion() + ""); + String versionPomContent = newPomContent.replace(versionPlaceholder, "" + getFdkVersion() + ""); versionPomContent = versionPomContent.replaceFirst(snapshotPlaceholderRegex, "true"); diff --git a/integration-tests/src/test/java/com/fnproject/fn/integrationtest/FunctionsTest.java b/integration-tests/src/test/java/com/fnproject/fn/integrationtest/FunctionsTest.java index 2d64d06d..ac3d158b 100644 --- a/integration-tests/src/test/java/com/fnproject/fn/integrationtest/FunctionsTest.java +++ b/integration-tests/src/test/java/com/fnproject/fn/integrationtest/FunctionsTest.java @@ -72,6 +72,22 @@ public void checkBoilerPlate() throws Exception { } } + + @Test() + public void runNativeFunction() throws Exception { + + int i = 0; + for(String version : new String[]{"jdk11-" + testRule.getFdkVersion(),testRule.getFdkVersion()}) { + IntegrationTestRule.TestContext tc = testRule.newTest(); + String fnName = "graaltest" + i++; + tc.runFn("init", "--init-image", "fnproject/fn-java-native-init:" + version, "--name", fnName); + tc.rewritePOM(); + tc.runFn("--verbose", "deploy", "--create-app", "--app", tc.appName(), "--local"); + CmdResult rs = tc.runFnWithInput("wibble", "invoke", tc.appName(), fnName); + assertThat(rs.getStdout()).contains("Hello, wibble!"); + } + } + @JsonIgnoreProperties(ignoreUnknown = true) public static class InspectResponse { From 4676a2a1946af20dd4ce8fe2a788314be8445f4e Mon Sep 17 00:00:00 2001 From: CI Date: Fri, 12 Feb 2021 17:12:32 +0000 Subject: [PATCH 209/310] fn-java-fdk: post-1.0.120 version bump [skip ci] --- release.version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/release.version b/release.version index e37d60d5..4fc47b2b 100644 --- a/release.version +++ b/release.version @@ -1 +1 @@ -1.0.120 +1.0.121 From 741dff8c0b3e307b83c117a47d1140e600b5aef0 Mon Sep 17 00:00:00 2001 From: Owen Cliffe Date: Wed, 17 Feb 2021 14:47:52 +0000 Subject: [PATCH 210/310] Adding initial experimental support for assisted graal native builds on functions : (#249) This adds basic graal configuration for commonly used libraries in Oracle Cloud (Jersey, BouncyCastle) and also adds a Jackson assistance feature that automatically adds reflection -referenced classes to the native binary from jackson annotations. --- experimental-native-image-support/README.md | 50 +++ experimental-native-image-support/pom.xml | 63 ++++ .../fn/nativeimagesupport/JacksonFeature.java | 138 ++++++++ .../jersey-support/reflect-config.json | 243 +++++++++++++ .../jersey-support/resource-config.json | 6 + .../oci-client-support/reflect-config.json | 335 ++++++++++++++++++ .../oci-client-support/resource-config.json | 6 + .../JacksonFeatureTest.java | 77 ++++ images/build/pom.xml | 5 + images/init-native/Dockerfile | 10 +- images/init-native/Dockerfile-init-image | 2 +- images/init-native/pom.xml | 2 +- .../fnfunction/reflect-config.json} | 0 pom.xml | 2 + .../com.fnproject.fn/runtime/jni-config.json | 0 15 files changed, 932 insertions(+), 7 deletions(-) create mode 100644 experimental-native-image-support/README.md create mode 100644 experimental-native-image-support/pom.xml create mode 100644 experimental-native-image-support/src/main/java/com/fnproject/fn/nativeimagesupport/JacksonFeature.java create mode 100644 experimental-native-image-support/src/main/resources/META-INF/native-image/com.fnproject.fn/nativeimagesupport/jersey-support/reflect-config.json create mode 100644 experimental-native-image-support/src/main/resources/META-INF/native-image/com.fnproject.fn/nativeimagesupport/jersey-support/resource-config.json create mode 100644 experimental-native-image-support/src/main/resources/META-INF/native-image/com.fnproject.fn/nativeimagesupport/oci-client-support/reflect-config.json create mode 100644 experimental-native-image-support/src/main/resources/META-INF/native-image/com.fnproject.fn/nativeimagesupport/oci-client-support/resource-config.json create mode 100644 experimental-native-image-support/src/test/java/com/fnproject/fn/nativeimagesupport/JacksonFeatureTest.java rename images/init-native/src/main/{conf/reflection.json => resources/META-INF/native-image/fnfunction/reflect-config.json} (100%) rename images/init-native/src/main/conf/jni.json => runtime/src/main/resources/META-INF/native-image/com.fnproject.fn/runtime/jni-config.json (100%) diff --git a/experimental-native-image-support/README.md b/experimental-native-image-support/README.md new file mode 100644 index 00000000..123fe625 --- /dev/null +++ b/experimental-native-image-support/README.md @@ -0,0 +1,50 @@ +# Experimental support tools for functions native images + +This is an optional module that can be added to native-image builds that resolves some common issues related to +native-image handling in oracle functions. + +This library is _experimental_ - it may change in behaviour and may not work in many cases. + +Currently, this contains graal native-image configuration files which enable common use cases for : + +* Oracle Cloud Infrastructure java client support in native images +* General Jersey client support (specifically tested for the OCI client use case, may work in other cases) +* Support for BouncyCastle crypto in native images + +It also includes : + +* A dynamic graal-native feature which automatically adds classes referenced in Jackson-databind annotations - this removes the need to have to manually add model classes that are referenced via Jackson annotations like `@JsonSubTypes.Type` `@JsonDeserlize` etc. + +# Enabling the feature in a native build: + +Generate a native build function (replace 1.0.121 with the appropriate fdk-java version): + +``` +fn init --init-image fnproject/fn-java-native-init:jdk11-1.0.121 graalfn +``` + +Edit your pom file and add this library as a dependency: + +```xml + + com.fnproject.fn + experimental-native-image-support + ${fdk.version} + runtime + +``` + +Edit the generated `Dockerfile` and add the following to enable the feature: + +``` + --features=com.fnproject.fn.nativeimagesupport.JacksonFeature \ +``` +You may also need to add the following flags if they are not already set: +``` + --allow-incomplete-classpath \ + --enable-all-security-services \ + --enable-url-protocols=https \ + --report-unsupported-elements-at-runtime \ +``` + +You may see "WARNING:..." messages during the build, these are expected and should not cause issues. diff --git a/experimental-native-image-support/pom.xml b/experimental-native-image-support/pom.xml new file mode 100644 index 00000000..b9acd970 --- /dev/null +++ b/experimental-native-image-support/pom.xml @@ -0,0 +1,63 @@ + + + + + + fdk + com.fnproject.fn + 1.0.0-SNAPSHOT + + 4.0.0 + + experimental-native-image-support + + + + com.fasterxml.jackson.core + jackson-databind + + + + junit + junit + test + + + org.graalvm.nativeimage + graal-hotspot-library + ${graalvm.version} + provided + true + + + org.assertj + assertj-core + test + + + + org.mockito + mockito-core + test + + + + diff --git a/experimental-native-image-support/src/main/java/com/fnproject/fn/nativeimagesupport/JacksonFeature.java b/experimental-native-image-support/src/main/java/com/fnproject/fn/nativeimagesupport/JacksonFeature.java new file mode 100644 index 00000000..8bab1e3f --- /dev/null +++ b/experimental-native-image-support/src/main/java/com/fnproject/fn/nativeimagesupport/JacksonFeature.java @@ -0,0 +1,138 @@ +/* + * Copyright (c) 2019, 2020, 2021 Oracle and/or its affiliates. All rights reserved. + * + * 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. + */ + +package com.fnproject.fn.nativeimagesupport; + +import java.lang.annotation.Annotation; +import java.lang.reflect.InvocationTargetException; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; +import java.util.stream.Stream; + +import com.fasterxml.jackson.annotation.JacksonAnnotation; +import com.oracle.svm.reflect.hosted.ReflectionFeature; +import org.graalvm.nativeimage.ImageSingletons; +import org.graalvm.nativeimage.hosted.Feature; +import org.graalvm.nativeimage.impl.RuntimeReflectionSupport; + +/** + * This is a graal-native feature that automatically includes any classes referenced as literals in Jackson Annotations + * from included classes. + *

    + * This is not likely to be complete and may skip annotations in some cases + * Known gaps: + * * Annotations on Jackson type super-classes + */ +public class JacksonFeature implements Feature { + + static { + + System.err.println("FnProject experimental Jackson feature loaded"); + System.err.println("Graal native image support is *experimental* it may not be stable and there may be cases where it does not work as expected"); + } + + private static final String JACKSON_PACKAGE_PREFIX = "com.fasterxml.jackson"; + + + private static boolean shouldIncludeClass(Class clz) { + return clz != Void.class + && !clz.getPackage().getName().startsWith(JACKSON_PACKAGE_PREFIX); + } + + private static boolean isJacksonAnnotation(Annotation a) { + return a.annotationType().getAnnotation(JacksonAnnotation.class) != null; + } + + private static Stream> extractLiteralAnnotationRefs(Annotation a) { + Class aClass = a.annotationType(); + return Arrays.stream(aClass.getDeclaredMethods()) + .flatMap(m -> { + Object val; + // get annotation value + try { + val = m.invoke(a); + } catch (IllegalAccessException | InvocationTargetException | IllegalArgumentException e) { + throw new IllegalStateException("Failed to retrieve annotation value from annotation" + a + " method " + m, e); + } + // technically annotations can't be null but just in case + if (val == null) { + return Stream.empty(); + } + + if (val.getClass().isAnnotation()) { // annotation param on an annotation - descend + return extractLiteralAnnotationRefs((Annotation) val); + } else if (val.getClass().isArray()) { + Class innerType = val.getClass().getComponentType(); + if (innerType.isAnnotation()) { // list of annotations - descend + return Arrays.stream((Annotation[]) val) + .flatMap(JacksonFeature::extractLiteralAnnotationRefs); + } + return Arrays.stream((Object[]) val) // add class literals in array ref + .filter(arrayVal -> arrayVal instanceof Class).map(arrayVal -> (Class) arrayVal); + } else if (val instanceof Class) { + return Stream.of((Class) val); + } + return Stream.empty(); + + + }); + } + + // VisibleForTesting + protected static Stream> expandAnnotationReferencesForClass(Class clazz) { + try { + return Stream.concat(Stream.concat( + Arrays.stream(clazz.getAnnotations()), + Arrays.stream(clazz.getDeclaredFields()).flatMap(f -> Arrays.stream(f.getAnnotations()))), + Arrays.stream(clazz.getDeclaredMethods()).flatMap(m -> Arrays.stream(m.getAnnotations())) + ) + .filter(JacksonFeature::isJacksonAnnotation) + .flatMap(JacksonFeature::extractLiteralAnnotationRefs) + .filter(JacksonFeature::shouldIncludeClass) + .peek((clz) -> System.err.println("Extending search for Jackson-referenced class " + clz + " from " + clazz)); + } catch (NoClassDefFoundError expected) { + System.err.println("WARNING: Found unknown class while expanding " + clazz + ":" + expected); + return Stream.empty(); + } + } + + @Override + public List> getRequiredFeatures() { + List> fs = new ArrayList<>(); + fs.add(ReflectionFeature.class); + return fs; + } + + @Override + public void beforeAnalysis(BeforeAnalysisAccess access) { + + ClassLoader cl = access.getApplicationClassLoader(); + RuntimeReflectionSupport rrs = ImageSingletons.lookup(RuntimeReflectionSupport.class); + + access.registerSubtypeReachabilityHandler((acc, sourceClazz) -> + expandAnnotationReferencesForClass(sourceClazz) + .forEach((referencedClazz) -> { + System.err.println("adding extra Jackson annotated " + referencedClazz + " from " + sourceClazz); + acc.registerAsUsed(referencedClazz); + acc.registerAsInHeap(referencedClazz); + rrs.register(referencedClazz); + rrs.register(referencedClazz.getDeclaredConstructors()); + rrs.register(referencedClazz.getDeclaredMethods()); + Arrays.stream(referencedClazz.getDeclaredFields()).forEach(f -> rrs.register(false, false, f)); + }), Object.class); + } +} diff --git a/experimental-native-image-support/src/main/resources/META-INF/native-image/com.fnproject.fn/nativeimagesupport/jersey-support/reflect-config.json b/experimental-native-image-support/src/main/resources/META-INF/native-image/com.fnproject.fn/nativeimagesupport/jersey-support/reflect-config.json new file mode 100644 index 00000000..027b4313 --- /dev/null +++ b/experimental-native-image-support/src/main/resources/META-INF/native-image/com.fnproject.fn/nativeimagesupport/jersey-support/reflect-config.json @@ -0,0 +1,243 @@ +[ +{ + "name":"java.awt.image.RenderedImage" +}, +{ + "name":"javax.inject.Named", + "allDeclaredMethods":true +}, +{ + "name":"javax.inject.Singleton", + "allDeclaredMethods":true +}, +{ + "name":"javax.naming.InitialContext", + "methods":[ + {"name":"","parameterTypes":[] }, + {"name":"lookup","parameterTypes":["java.lang.String"] } + ] +}, +{ + "name":"javax.xml.transform.Source" +}, +{ + "name":"javax.xml.transform.dom.DOMSource" +}, +{ + "name":"javax.xml.transform.sax.SAXSource" +}, +{ + "name":"javax.xml.transform.stream.StreamSource" +}, +{ + "name":"org.glassfish.hk2.internal.PerThreadContext", + "allDeclaredFields":true, + "allDeclaredMethods":true, + "allDeclaredConstructors":true +}, +{ + "name":"org.glassfish.jersey.client.ChunkedInputReader", + "allDeclaredFields":true, + "allDeclaredMethods":true, + "allDeclaredConstructors":true +}, +{ + "name":"org.glassfish.jersey.client.ClientAsyncExecutor", + "allDeclaredMethods":true +}, +{ + "name":"org.glassfish.jersey.client.ClientBackgroundScheduler", + "allDeclaredMethods":true +}, +{ + "name":"org.glassfish.jersey.client.JerseyClientBuilder", + "methods":[{"name":"","parameterTypes":[] }] +}, +{ + "name":"org.glassfish.jersey.inject.hk2.ContextInjectionResolverImpl", + "allDeclaredFields":true, + "allDeclaredMethods":true, + "allDeclaredConstructors":true +}, +{ + "name":"org.glassfish.jersey.inject.hk2.Hk2InjectionManagerFactory", + "methods":[{"name":"","parameterTypes":[] }] +}, +{ + "name":"org.glassfish.jersey.inject.hk2.Hk2RequestScope", + "allDeclaredFields":true, + "allDeclaredMethods":true, + "allDeclaredConstructors":true +}, +{ + "name":"org.glassfish.jersey.inject.hk2.InstanceSupplierFactoryBridge", + "methods":[{"name":"provide","parameterTypes":[] }] +}, +{ + "name":"org.glassfish.jersey.inject.hk2.JerseyErrorService", + "allDeclaredFields":true, + "allDeclaredMethods":true, + "allDeclaredConstructors":true +}, +{ + "name":"org.glassfish.jersey.inject.hk2.RequestContext", + "allDeclaredFields":true, + "allDeclaredMethods":true, + "allDeclaredConstructors":true +}, +{ + "name":"org.glassfish.jersey.internal.RuntimeDelegateImpl", + "methods":[{"name":"","parameterTypes":[] }] +}, +{ + "name":"org.glassfish.jersey.internal.config.ExternalPropertiesAutoDiscoverable", + "allDeclaredFields":true, + "allDeclaredMethods":true, + "allDeclaredConstructors":true +}, +{ + "name":"org.glassfish.jersey.internal.config.ExternalPropertiesConfigurationFeature", + "allDeclaredFields":true, + "allDeclaredMethods":true, + "allDeclaredConstructors":true +}, +{ + "name":"org.glassfish.jersey.internal.inject.Custom", + "allDeclaredMethods":true +}, +{ + "name":"org.glassfish.jersey.jackson.JacksonFeature", + "allDeclaredFields":true, + "allDeclaredMethods":true, + "allDeclaredConstructors":true +}, +{ + "name":"org.glassfish.jersey.jackson.internal.JacksonAutoDiscoverable", + "allDeclaredFields":true, + "allDeclaredMethods":true, + "allDeclaredConstructors":true +}, +{ + "name":"org.glassfish.jersey.logging.LoggingFeatureAutoDiscoverable", + "allDeclaredFields":true, + "allDeclaredMethods":true, + "allDeclaredConstructors":true +}, +{ + "name":"org.glassfish.jersey.message.internal.AbstractFormProvider", + "allDeclaredFields":true, + "allDeclaredMethods":true +}, +{ + "name":"org.glassfish.jersey.message.internal.AbstractMessageReaderWriterProvider", + "allDeclaredFields":true, + "allDeclaredMethods":true +}, +{ + "name":"org.glassfish.jersey.message.internal.BasicTypesMessageProvider", + "allDeclaredFields":true, + "allDeclaredMethods":true, + "allDeclaredConstructors":true +}, +{ + "name":"org.glassfish.jersey.message.internal.ByteArrayProvider", + "allDeclaredFields":true, + "allDeclaredMethods":true, + "allDeclaredConstructors":true +}, +{ + "name":"org.glassfish.jersey.message.internal.DataSourceProvider", + "allDeclaredFields":true, + "allDeclaredMethods":true, + "allDeclaredConstructors":true +}, +{ + "name":"org.glassfish.jersey.message.internal.FileProvider", + "allDeclaredFields":true, + "allDeclaredMethods":true, + "allDeclaredConstructors":true +}, +{ + "name":"org.glassfish.jersey.message.internal.FormMultivaluedMapProvider", + "allDeclaredFields":true, + "allDeclaredMethods":true, + "allDeclaredConstructors":true +}, +{ + "name":"org.glassfish.jersey.message.internal.FormProvider", + "allDeclaredFields":true, + "allDeclaredMethods":true, + "allDeclaredConstructors":true +}, +{ + "name":"org.glassfish.jersey.message.internal.InputStreamProvider", + "allDeclaredFields":true, + "allDeclaredMethods":true, + "allDeclaredConstructors":true +}, +{ + "name":"org.glassfish.jersey.message.internal.ReaderProvider", + "allDeclaredFields":true, + "allDeclaredMethods":true, + "allDeclaredConstructors":true +}, +{ + "name":"org.glassfish.jersey.message.internal.RenderedImageProvider", + "allDeclaredFields":true, + "allDeclaredMethods":true, + "allDeclaredConstructors":true +}, +{ + "name":"org.glassfish.jersey.message.internal.SourceProvider$DomSourceReader", + "allDeclaredFields":true, + "allDeclaredMethods":true, + "allDeclaredConstructors":true +}, +{ + "name":"org.glassfish.jersey.message.internal.SourceProvider$SaxSourceReader", + "allDeclaredFields":true, + "allDeclaredMethods":true, + "allDeclaredConstructors":true +}, +{ + "name":"org.glassfish.jersey.message.internal.SourceProvider$SourceWriter", + "allDeclaredFields":true, + "allDeclaredMethods":true, + "allDeclaredConstructors":true +}, +{ + "name":"org.glassfish.jersey.message.internal.SourceProvider$StreamSourceReader", + "allDeclaredFields":true, + "allDeclaredMethods":true, + "allDeclaredConstructors":true +}, +{ + "name":"org.glassfish.jersey.message.internal.StreamingOutputProvider", + "allDeclaredFields":true, + "allDeclaredMethods":true, + "allDeclaredConstructors":true +}, +{ + "name":"org.glassfish.jersey.message.internal.StringMessageProvider", + "allDeclaredFields":true, + "allDeclaredMethods":true, + "allDeclaredConstructors":true +}, +{ + "name":"org.glassfish.jersey.process.internal.RequestScope", + "allDeclaredFields":true, + "allDeclaredMethods":true +}, +{ + "name":"org.jvnet.hk2.internal.DynamicConfigurationServiceImpl", + "allDeclaredFields":true, + "allDeclaredMethods":true, + "allDeclaredConstructors":true +}, +{ + "name":"org.jvnet.hk2.internal.ServiceLocatorRuntimeImpl", + "allDeclaredFields":true, + "allDeclaredMethods":true, + "allDeclaredConstructors":true +} +] diff --git a/experimental-native-image-support/src/main/resources/META-INF/native-image/com.fnproject.fn/nativeimagesupport/jersey-support/resource-config.json b/experimental-native-image-support/src/main/resources/META-INF/native-image/com.fnproject.fn/nativeimagesupport/jersey-support/resource-config.json new file mode 100644 index 00000000..fa9ff0a2 --- /dev/null +++ b/experimental-native-image-support/src/main/resources/META-INF/native-image/com.fnproject.fn/nativeimagesupport/jersey-support/resource-config.json @@ -0,0 +1,6 @@ +{ + "resources":{ + "includes":[ + {"pattern":"\\QMETA-INF/services/.*\\E"} + ]} +} diff --git a/experimental-native-image-support/src/main/resources/META-INF/native-image/com.fnproject.fn/nativeimagesupport/oci-client-support/reflect-config.json b/experimental-native-image-support/src/main/resources/META-INF/native-image/com.fnproject.fn/nativeimagesupport/oci-client-support/reflect-config.json new file mode 100644 index 00000000..8fcb17c5 --- /dev/null +++ b/experimental-native-image-support/src/main/resources/META-INF/native-image/com.fnproject.fn/nativeimagesupport/oci-client-support/reflect-config.json @@ -0,0 +1,335 @@ +[ + { + "name": "org.slf4j.impl.StaticLoggerBinder", + "allDeclaredFields": true, + "allDeclaredConstructors": true + }, +{ + "name":"com.fasterxml.jackson.databind.ext.Java7SupportImpl", + "methods":[{"name":"","parameterTypes":[] }] +}, +{ + "name":"org.bouncycastle.jcajce.provider.asymmetric.DH$Mappings", + "methods":[{"name":"","parameterTypes":[] }] +}, +{ + "name":"org.bouncycastle.jcajce.provider.asymmetric.DSA$Mappings", + "methods":[{"name":"","parameterTypes":[] }] +}, +{ + "name":"org.bouncycastle.jcajce.provider.asymmetric.DSTU4145$Mappings", + "methods":[{"name":"","parameterTypes":[] }] +}, +{ + "name":"org.bouncycastle.jcajce.provider.asymmetric.EC$Mappings", + "methods":[{"name":"","parameterTypes":[] }] +}, +{ + "name":"org.bouncycastle.jcajce.provider.asymmetric.ECGOST$Mappings", + "methods":[{"name":"","parameterTypes":[] }] +}, +{ + "name":"org.bouncycastle.jcajce.provider.asymmetric.ElGamal$Mappings", + "methods":[{"name":"","parameterTypes":[] }] +}, +{ + "name":"org.bouncycastle.jcajce.provider.asymmetric.GM$Mappings", + "methods":[{"name":"","parameterTypes":[] }] +}, +{ + "name":"org.bouncycastle.jcajce.provider.asymmetric.GOST$Mappings", + "methods":[{"name":"","parameterTypes":[] }] +}, +{ + "name":"org.bouncycastle.jcajce.provider.asymmetric.IES$Mappings", + "methods":[{"name":"","parameterTypes":[] }] +}, +{ + "name":"org.bouncycastle.jcajce.provider.asymmetric.RSA$Mappings", + "methods":[{"name":"","parameterTypes":[] }] +}, +{ + "name":"org.bouncycastle.jcajce.provider.asymmetric.X509$Mappings", + "methods":[{"name":"","parameterTypes":[] }] +}, +{ + "name":"org.bouncycastle.jcajce.provider.digest.Blake2b$Mappings", + "methods":[{"name":"","parameterTypes":[] }] +}, +{ + "name":"org.bouncycastle.jcajce.provider.digest.Blake2s$Mappings", + "methods":[{"name":"","parameterTypes":[] }] +}, +{ + "name":"org.bouncycastle.jcajce.provider.digest.DSTU7564$Mappings", + "methods":[{"name":"","parameterTypes":[] }] +}, +{ + "name":"org.bouncycastle.jcajce.provider.digest.GOST3411$Mappings", + "methods":[{"name":"","parameterTypes":[] }] +}, +{ + "name":"org.bouncycastle.jcajce.provider.digest.Keccak$Mappings", + "methods":[{"name":"","parameterTypes":[] }] +}, +{ + "name":"org.bouncycastle.jcajce.provider.digest.MD2$Mappings", + "methods":[{"name":"","parameterTypes":[] }] +}, +{ + "name":"org.bouncycastle.jcajce.provider.digest.MD4$Mappings", + "methods":[{"name":"","parameterTypes":[] }] +}, +{ + "name":"org.bouncycastle.jcajce.provider.digest.MD5$Mappings", + "methods":[{"name":"","parameterTypes":[] }] +}, +{ + "name":"org.bouncycastle.jcajce.provider.digest.RIPEMD128$Mappings", + "methods":[{"name":"","parameterTypes":[] }] +}, +{ + "name":"org.bouncycastle.jcajce.provider.digest.RIPEMD160$Mappings", + "methods":[{"name":"","parameterTypes":[] }] +}, +{ + "name":"org.bouncycastle.jcajce.provider.digest.RIPEMD256$Mappings", + "methods":[{"name":"","parameterTypes":[] }] +}, +{ + "name":"org.bouncycastle.jcajce.provider.digest.RIPEMD320$Mappings", + "methods":[{"name":"","parameterTypes":[] }] +}, +{ + "name":"org.bouncycastle.jcajce.provider.digest.SHA1$Mappings", + "methods":[{"name":"","parameterTypes":[] }] +}, +{ + "name":"org.bouncycastle.jcajce.provider.digest.SHA224$Mappings", + "methods":[{"name":"","parameterTypes":[] }] +}, +{ + "name":"org.bouncycastle.jcajce.provider.digest.SHA256$Mappings", + "methods":[{"name":"","parameterTypes":[] }] +}, +{ + "name":"org.bouncycastle.jcajce.provider.digest.SHA3$Mappings", + "methods":[{"name":"","parameterTypes":[] }] +}, +{ + "name":"org.bouncycastle.jcajce.provider.digest.SHA384$Mappings", + "methods":[{"name":"","parameterTypes":[] }] +}, +{ + "name":"org.bouncycastle.jcajce.provider.digest.SHA512$Mappings", + "methods":[{"name":"","parameterTypes":[] }] +}, +{ + "name":"org.bouncycastle.jcajce.provider.digest.SM3$Mappings", + "methods":[{"name":"","parameterTypes":[] }] +}, +{ + "name":"org.bouncycastle.jcajce.provider.digest.Skein$Mappings", + "methods":[{"name":"","parameterTypes":[] }] +}, +{ + "name":"org.bouncycastle.jcajce.provider.digest.Tiger$Mappings", + "methods":[{"name":"","parameterTypes":[] }] +}, +{ + "name":"org.bouncycastle.jcajce.provider.digest.Whirlpool$Mappings", + "methods":[{"name":"","parameterTypes":[] }] +}, +{ + "name":"org.bouncycastle.jcajce.provider.drbg.DRBG$Mappings", + "methods":[{"name":"","parameterTypes":[] }] +}, +{ + "name":"org.bouncycastle.jcajce.provider.keystore.BC$Mappings", + "methods":[{"name":"","parameterTypes":[] }] +}, +{ + "name":"org.bouncycastle.jcajce.provider.keystore.BCFKS$Mappings", + "methods":[{"name":"","parameterTypes":[] }] +}, +{ + "name":"org.bouncycastle.jcajce.provider.keystore.PKCS12$Mappings", + "methods":[{"name":"","parameterTypes":[] }] +}, +{ + "name":"org.bouncycastle.jcajce.provider.symmetric.AES$Mappings", + "methods":[{"name":"","parameterTypes":[] }] +}, +{ + "name":"org.bouncycastle.jcajce.provider.symmetric.ARC4$Mappings", + "methods":[{"name":"","parameterTypes":[] }] +}, +{ + "name":"org.bouncycastle.jcajce.provider.symmetric.ARIA$Mappings", + "methods":[{"name":"","parameterTypes":[] }] +}, +{ + "name":"org.bouncycastle.jcajce.provider.symmetric.Blowfish$Mappings", + "methods":[{"name":"","parameterTypes":[] }] +}, +{ + "name":"org.bouncycastle.jcajce.provider.symmetric.CAST5$Mappings", + "methods":[{"name":"","parameterTypes":[] }] +}, +{ + "name":"org.bouncycastle.jcajce.provider.symmetric.CAST6$Mappings", + "methods":[{"name":"","parameterTypes":[] }] +}, +{ + "name":"org.bouncycastle.jcajce.provider.symmetric.Camellia$Mappings", + "methods":[{"name":"","parameterTypes":[] }] +}, +{ + "name":"org.bouncycastle.jcajce.provider.symmetric.ChaCha$Mappings", + "methods":[{"name":"","parameterTypes":[] }] +}, +{ + "name":"org.bouncycastle.jcajce.provider.symmetric.DES$Mappings", + "methods":[{"name":"","parameterTypes":[] }] +}, +{ + "name":"org.bouncycastle.jcajce.provider.symmetric.DESede$Mappings", + "methods":[{"name":"","parameterTypes":[] }] +}, +{ + "name":"org.bouncycastle.jcajce.provider.symmetric.DSTU7624$Mappings", + "methods":[{"name":"","parameterTypes":[] }] +}, +{ + "name":"org.bouncycastle.jcajce.provider.symmetric.GOST28147$Mappings", + "methods":[{"name":"","parameterTypes":[] }] +}, +{ + "name":"org.bouncycastle.jcajce.provider.symmetric.GOST3412_2015$Mappings", + "methods":[{"name":"","parameterTypes":[] }] +}, +{ + "name":"org.bouncycastle.jcajce.provider.symmetric.Grain128$Mappings", + "methods":[{"name":"","parameterTypes":[] }] +}, +{ + "name":"org.bouncycastle.jcajce.provider.symmetric.Grainv1$Mappings", + "methods":[{"name":"","parameterTypes":[] }] +}, +{ + "name":"org.bouncycastle.jcajce.provider.symmetric.HC128$Mappings", + "methods":[{"name":"","parameterTypes":[] }] +}, +{ + "name":"org.bouncycastle.jcajce.provider.symmetric.HC256$Mappings", + "methods":[{"name":"","parameterTypes":[] }] +}, +{ + "name":"org.bouncycastle.jcajce.provider.symmetric.IDEA$Mappings", + "methods":[{"name":"","parameterTypes":[] }] +}, +{ + "name":"org.bouncycastle.jcajce.provider.symmetric.Noekeon$Mappings", + "methods":[{"name":"","parameterTypes":[] }] +}, +{ + "name":"org.bouncycastle.jcajce.provider.symmetric.OpenSSLPBKDF$Mappings", + "methods":[{"name":"","parameterTypes":[] }] +}, +{ + "name":"org.bouncycastle.jcajce.provider.symmetric.PBEPBKDF1$Mappings", + "methods":[{"name":"","parameterTypes":[] }] +}, +{ + "name":"org.bouncycastle.jcajce.provider.symmetric.PBEPBKDF2$Mappings", + "methods":[{"name":"","parameterTypes":[] }] +}, +{ + "name":"org.bouncycastle.jcajce.provider.symmetric.PBEPKCS12$Mappings", + "methods":[{"name":"","parameterTypes":[] }] +}, +{ + "name":"org.bouncycastle.jcajce.provider.symmetric.Poly1305$Mappings", + "methods":[{"name":"","parameterTypes":[] }] +}, +{ + "name":"org.bouncycastle.jcajce.provider.symmetric.RC2$Mappings", + "methods":[{"name":"","parameterTypes":[] }] +}, +{ + "name":"org.bouncycastle.jcajce.provider.symmetric.RC5$Mappings", + "methods":[{"name":"","parameterTypes":[] }] +}, +{ + "name":"org.bouncycastle.jcajce.provider.symmetric.RC6$Mappings", + "methods":[{"name":"","parameterTypes":[] }] +}, +{ + "name":"org.bouncycastle.jcajce.provider.symmetric.Rijndael$Mappings", + "methods":[{"name":"","parameterTypes":[] }] +}, +{ + "name":"org.bouncycastle.jcajce.provider.symmetric.SCRYPT$Mappings", + "methods":[{"name":"","parameterTypes":[] }] +}, +{ + "name":"org.bouncycastle.jcajce.provider.symmetric.SEED$Mappings", + "methods":[{"name":"","parameterTypes":[] }] +}, +{ + "name":"org.bouncycastle.jcajce.provider.symmetric.SM4$Mappings", + "methods":[{"name":"","parameterTypes":[] }] +}, +{ + "name":"org.bouncycastle.jcajce.provider.symmetric.Salsa20$Mappings", + "methods":[{"name":"","parameterTypes":[] }] +}, +{ + "name":"org.bouncycastle.jcajce.provider.symmetric.Serpent$Mappings", + "methods":[{"name":"","parameterTypes":[] }] +}, +{ + "name":"org.bouncycastle.jcajce.provider.symmetric.Shacal2$Mappings", + "methods":[{"name":"","parameterTypes":[] }] +}, +{ + "name":"org.bouncycastle.jcajce.provider.symmetric.SipHash$Mappings", + "methods":[{"name":"","parameterTypes":[] }] +}, +{ + "name":"org.bouncycastle.jcajce.provider.symmetric.Skipjack$Mappings", + "methods":[{"name":"","parameterTypes":[] }] +}, +{ + "name":"org.bouncycastle.jcajce.provider.symmetric.TEA$Mappings", + "methods":[{"name":"","parameterTypes":[] }] +}, +{ + "name":"org.bouncycastle.jcajce.provider.symmetric.TLSKDF$Mappings", + "methods":[{"name":"","parameterTypes":[] }] +}, +{ + "name":"org.bouncycastle.jcajce.provider.symmetric.Threefish$Mappings", + "methods":[{"name":"","parameterTypes":[] }] +}, +{ + "name":"org.bouncycastle.jcajce.provider.symmetric.Twofish$Mappings", + "methods":[{"name":"","parameterTypes":[] }] +}, +{ + "name":"org.bouncycastle.jcajce.provider.symmetric.VMPC$Mappings", + "methods":[{"name":"","parameterTypes":[] }] +}, +{ + "name":"org.bouncycastle.jcajce.provider.symmetric.VMPCKSA3$Mappings", + "methods":[{"name":"","parameterTypes":[] }] +}, +{ + "name":"org.bouncycastle.jcajce.provider.symmetric.XSalsa20$Mappings", + "methods":[{"name":"","parameterTypes":[] }] +}, +{ + "name":"org.bouncycastle.jcajce.provider.symmetric.XTEA$Mappings", + "methods":[{"name":"","parameterTypes":[] }] +} +] diff --git a/experimental-native-image-support/src/main/resources/META-INF/native-image/com.fnproject.fn/nativeimagesupport/oci-client-support/resource-config.json b/experimental-native-image-support/src/main/resources/META-INF/native-image/com.fnproject.fn/nativeimagesupport/oci-client-support/resource-config.json new file mode 100644 index 00000000..b46bdb8c --- /dev/null +++ b/experimental-native-image-support/src/main/resources/META-INF/native-image/com.fnproject.fn/nativeimagesupport/oci-client-support/resource-config.json @@ -0,0 +1,6 @@ +{ + "resources":{ + "includes":[ + {"pattern":"\\Qcom/oracle/bmc/sdk.properties\\E"} + ]} +} diff --git a/experimental-native-image-support/src/test/java/com/fnproject/fn/nativeimagesupport/JacksonFeatureTest.java b/experimental-native-image-support/src/test/java/com/fnproject/fn/nativeimagesupport/JacksonFeatureTest.java new file mode 100644 index 00000000..e0f2905e --- /dev/null +++ b/experimental-native-image-support/src/test/java/com/fnproject/fn/nativeimagesupport/JacksonFeatureTest.java @@ -0,0 +1,77 @@ +package com.fnproject.fn.nativeimagesupport; + +import java.math.BigInteger; + +import com.fasterxml.jackson.annotation.JsonSubTypes; +import com.fasterxml.jackson.annotation.JsonTypeInfo; +import com.fasterxml.jackson.databind.annotation.JsonDeserialize; +import com.fasterxml.jackson.databind.annotation.JsonPOJOBuilder; +import com.fasterxml.jackson.databind.annotation.JsonSerialize; +import org.junit.Test; + +import static org.assertj.core.api.Assertions.assertThat; + +/** + * Created on 16/02/2021. + *

    + * (c) 2021 Oracle Corporation + */ +public class JacksonFeatureTest { + + + @Test + public void shouldWalkAnnotations() { + assertThat(JacksonFeature.expandAnnotationReferencesForClass(AbstractBase.class)).containsExactly(ConcreteSubType.class); + assertThat(JacksonFeature.expandAnnotationReferencesForClass(InterfaceBase.class)).containsExactly(InterfaceImpl.class); + assertThat(JacksonFeature.expandAnnotationReferencesForClass(UsesJacksonFeatures.class)).containsExactly(UsesJacksonFeatures.Builder.class); + assertThat(JacksonFeature.expandAnnotationReferencesForClass(AnnotationsOnFields.class)).containsExactly(BigInteger.class); + assertThat(JacksonFeature.expandAnnotationReferencesForClass(AnnotationsOnMethods.class)).containsExactly(BigInteger.class); + } + + + + @JsonTypeInfo(use = JsonTypeInfo.Id.NAME, include = JsonTypeInfo.As.PROPERTY) + @JsonSubTypes({ + @JsonSubTypes.Type(value = ConcreteSubType.class, name = "c1") + }) + public abstract static class AbstractBase { + + } + + public static class ConcreteSubType extends AbstractBase { + int id; + } + + public static class InterfaceImpl implements InterfaceBase { + } + + /** + * Created on 15/02/2021. + *

    + * (c) 2021 Oracle Corporation + */ + @JsonDeserialize(as = InterfaceImpl.class) + public interface InterfaceBase { + } + + + @JsonDeserialize(builder = UsesJacksonFeatures.Builder.class) + public static class UsesJacksonFeatures { + @JsonPOJOBuilder + public static class Builder { + } + } + + public static class AnnotationsOnFields { + @JsonSerialize(as = BigInteger.class) + private int number; + } + + + public static class AnnotationsOnMethods { + @JsonSerialize(as = BigInteger.class) + public int getNumber() { + return 1; + } + } +} diff --git a/images/build/pom.xml b/images/build/pom.xml index 6814ae86..5adb2b8c 100644 --- a/images/build/pom.xml +++ b/images/build/pom.xml @@ -43,6 +43,11 @@ api ${fdk.version} + + com.fnproject.fn + experimental-native-image-support + ${fdk.version} + com.fnproject.fn testing-core diff --git a/images/init-native/Dockerfile b/images/init-native/Dockerfile index 1292ea9a..1424b9cf 100644 --- a/images/init-native/Dockerfile +++ b/images/init-native/Dockerfile @@ -25,17 +25,17 @@ RUN ["mvn", "package"] FROM fnproject/fn-java-native:##FN_FDK_VERSION## as build-native-image WORKDIR /function COPY --from=build /function/target/*.jar target/ -COPY --from=build /function/src/main/conf/reflection.json reflection.json -COPY --from=build /function/src/main/conf/jni.json jni.json + RUN /usr/bin/native-image \ --static \ --no-fallback \ --initialize-at-build-time= \ --initialize-at-run-time=com.fnproject.fn.runtime.ntv.UnixSocketNative \ + --allow-incomplete-classpath \ + --enable-all-security-services \ + --enable-url-protocols=https,http \ + --report-unsupported-elements-at-runtime \ -H:Name=func \ - -H:+ReportUnsupportedElementsAtRuntime \ - -H:ReflectionConfigurationFiles=reflection.json \ - -H:JNIConfigurationFiles=jni.json \ -classpath "target/*"\ com.fnproject.fn.runtime.EntryPoint diff --git a/images/init-native/Dockerfile-init-image b/images/init-native/Dockerfile-init-image index 2e349735..8e0d73bf 100644 --- a/images/init-native/Dockerfile-init-image +++ b/images/init-native/Dockerfile-init-image @@ -28,7 +28,7 @@ if [ -n ${FN_FUNCTION_NAME} ]\n\ JAVA_NAME=$(echo ${FN_FUNCTION_NAME:0:1} | tr "[:lower:]" "[:upper:]")${FN_FUNCTION_NAME:1}\n\ sed -i -e "s|hello|${FN_FUNCTION_NAME}|" pom.xml\n\ sed -i -e "s|com.example.fn.HelloFunction|com.example.fn.${JAVA_NAME}|" Dockerfile\n\ - sed -i -e "s|com.example.fn.HelloFunction|com.example.fn.${JAVA_NAME}|" src/main/conf/reflection.json\n\ + sed -i -e "s|com.example.fn.HelloFunction|com.example.fn.${JAVA_NAME}|" src/main/resources/META-INF/native-image/fnfunction/reflect-config.json\n\ sed -i -e "s|HelloFunction|${JAVA_NAME}|" src/main/java/com/example/fn/HelloFunction.java\n\ mv src/main/java/com/example/fn/HelloFunction.java "src/main/java/com/example/fn/${JAVA_NAME}.java"\n\ sed -i -e "s|HelloFunction|${JAVA_NAME}|" src/test/java/com/example/fn/HelloFunctionTest.java\n\ diff --git a/images/init-native/pom.xml b/images/init-native/pom.xml index f33f0125..f0664d10 100644 --- a/images/init-native/pom.xml +++ b/images/init-native/pom.xml @@ -14,7 +14,7 @@ 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. - + --> flow-testing fn-spring-cloud-function examples + experimental-native-image-support @@ -57,6 +58,7 @@ 1.7.25 2.22.1 1.16.0 + 21.0.0 diff --git a/images/init-native/src/main/conf/jni.json b/runtime/src/main/resources/META-INF/native-image/com.fnproject.fn/runtime/jni-config.json similarity index 100% rename from images/init-native/src/main/conf/jni.json rename to runtime/src/main/resources/META-INF/native-image/com.fnproject.fn/runtime/jni-config.json From 751117f9185f4585229e995634b8b40ea909d54c Mon Sep 17 00:00:00 2001 From: CI Date: Wed, 17 Feb 2021 15:07:24 +0000 Subject: [PATCH 211/310] fn-java-fdk: post-1.0.121 version bump [skip ci] --- release.version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/release.version b/release.version index 4fc47b2b..d10644b3 100644 --- a/release.version +++ b/release.version @@ -1 +1 @@ -1.0.121 +1.0.122 From 42bee6b762b8a171010f2f0528983be80cbb4729 Mon Sep 17 00:00:00 2001 From: Owen Cliffe Date: Thu, 18 Feb 2021 21:08:27 +0000 Subject: [PATCH 212/310] Extend Jackson feature to match and add reflection for classes that have jackson annotations as well as the classes that are referenced from them (#250) --- .../fn/nativeimagesupport/JacksonFeature.java | 78 +++++++++++-------- .../JacksonFeatureTest.java | 10 +-- images/init-native/Dockerfile | 2 - 3 files changed, 51 insertions(+), 39 deletions(-) diff --git a/experimental-native-image-support/src/main/java/com/fnproject/fn/nativeimagesupport/JacksonFeature.java b/experimental-native-image-support/src/main/java/com/fnproject/fn/nativeimagesupport/JacksonFeature.java index 8bab1e3f..c4282dd1 100644 --- a/experimental-native-image-support/src/main/java/com/fnproject/fn/nativeimagesupport/JacksonFeature.java +++ b/experimental-native-image-support/src/main/java/com/fnproject/fn/nativeimagesupport/JacksonFeature.java @@ -21,6 +21,7 @@ import java.util.ArrayList; import java.util.Arrays; import java.util.List; +import java.util.stream.Collectors; import java.util.stream.Stream; import com.fasterxml.jackson.annotation.JacksonAnnotation; @@ -30,19 +31,22 @@ import org.graalvm.nativeimage.impl.RuntimeReflectionSupport; /** - * This is a graal-native feature that automatically includes any classes referenced as literals in Jackson Annotations + * This is a graal native-image feature that automatically includes any classes referenced as literals in Jackson Annotations * from included classes. *

    - * This is not likely to be complete and may skip annotations in some cases - * Known gaps: - * * Annotations on Jackson type super-classes + * The process assumes that the following classes require full reflective acceess (all fields/methods/constructors) : + *

      + *
    • Classes with Jackson annotations (any jackson annotation on the class or in a member)
    • + *
    • Any Class literals referenced from jackson annotations or their descendents (e.g. Serializers, dispatch types)
    • + *
    + *

    + * This is not likely to be complete and may skip annotations in some cases, notably there are cases where super classes may not be correctly accounted for. */ public class JacksonFeature implements Feature { - static { - - System.err.println("FnProject experimental Jackson feature loaded"); - System.err.println("Graal native image support is *experimental* it may not be stable and there may be cases where it does not work as expected"); + public JacksonFeature() { + System.out.println("JacksonFeature: FnProject experimental Jackson feature loaded"); + System.out.println("JacksonFeature: Graal native image support is *experimental* it may not be stable and there may be cases where it does not work as expected"); } private static final String JACKSON_PACKAGE_PREFIX = "com.fasterxml.jackson"; @@ -57,17 +61,18 @@ private static boolean isJacksonAnnotation(Annotation a) { return a.annotationType().getAnnotation(JacksonAnnotation.class) != null; } - private static Stream> extractLiteralAnnotationRefs(Annotation a) { + protected static Stream> extractLiteralAnnotationRefs(Annotation a) { Class aClass = a.annotationType(); return Arrays.stream(aClass.getDeclaredMethods()) .flatMap(m -> { Object val; - // get annotation value + // get annotation attribute value try { val = m.invoke(a); } catch (IllegalAccessException | InvocationTargetException | IllegalArgumentException e) { throw new IllegalStateException("Failed to retrieve annotation value from annotation" + a + " method " + m, e); } + // technically annotations can't be null but just in case if (val == null) { return Stream.empty(); @@ -87,27 +92,34 @@ private static Stream> extractLiteralAnnotationRefs(Annotation a) { return Stream.of((Class) val); } return Stream.empty(); - - }); } + // VisibleForTesting - protected static Stream> expandAnnotationReferencesForClass(Class clazz) { + protected static Stream> expandClassesToMarkForReflection(Class clazz) { + List jacksonAnnotations; try { - return Stream.concat(Stream.concat( + jacksonAnnotations = Stream.concat(Stream.concat( Arrays.stream(clazz.getAnnotations()), Arrays.stream(clazz.getDeclaredFields()).flatMap(f -> Arrays.stream(f.getAnnotations()))), Arrays.stream(clazz.getDeclaredMethods()).flatMap(m -> Arrays.stream(m.getAnnotations())) - ) - .filter(JacksonFeature::isJacksonAnnotation) - .flatMap(JacksonFeature::extractLiteralAnnotationRefs) - .filter(JacksonFeature::shouldIncludeClass) - .peek((clz) -> System.err.println("Extending search for Jackson-referenced class " + clz + " from " + clazz)); - } catch (NoClassDefFoundError expected) { - System.err.println("WARNING: Found unknown class while expanding " + clazz + ":" + expected); + ).filter(JacksonFeature::isJacksonAnnotation).collect(Collectors.toList()); + } catch (NoClassDefFoundError ignored) { + // we skip the whole class if any of its members are unresolvable - this is assumed safe as jackson won't be able to load the class here anyway return Stream.empty(); } + + // if no jackson classes present, skip the whole class + if (jacksonAnnotations.isEmpty()) { + return Stream.empty(); + } + + // otherwise include the class and any descendent classes referenced within those annotations + return Stream.concat(Stream.of(clazz), jacksonAnnotations.stream() + .flatMap(JacksonFeature::extractLiteralAnnotationRefs) + .filter(JacksonFeature::shouldIncludeClass)); + } @Override @@ -123,16 +135,18 @@ public void beforeAnalysis(BeforeAnalysisAccess access) { ClassLoader cl = access.getApplicationClassLoader(); RuntimeReflectionSupport rrs = ImageSingletons.lookup(RuntimeReflectionSupport.class); - access.registerSubtypeReachabilityHandler((acc, sourceClazz) -> - expandAnnotationReferencesForClass(sourceClazz) - .forEach((referencedClazz) -> { - System.err.println("adding extra Jackson annotated " + referencedClazz + " from " + sourceClazz); - acc.registerAsUsed(referencedClazz); - acc.registerAsInHeap(referencedClazz); - rrs.register(referencedClazz); - rrs.register(referencedClazz.getDeclaredConstructors()); - rrs.register(referencedClazz.getDeclaredMethods()); - Arrays.stream(referencedClazz.getDeclaredFields()).forEach(f -> rrs.register(false, false, f)); - }), Object.class); + access.registerSubtypeReachabilityHandler((acc, sourceClazz) -> { + expandClassesToMarkForReflection(sourceClazz) + .forEach((referencedClazz) -> { + System.out.println("JacksonFeature: adding extra Jackson annotated " + referencedClazz); + acc.registerAsUsed(referencedClazz); + acc.registerAsInHeap(referencedClazz); + rrs.register(referencedClazz); + rrs.register(referencedClazz.getDeclaredConstructors()); + rrs.register(referencedClazz.getDeclaredMethods()); + Arrays.stream(referencedClazz.getDeclaredFields()).forEach(f -> rrs.register(false, false, f)); + }); + }, Object.class); } + } diff --git a/experimental-native-image-support/src/test/java/com/fnproject/fn/nativeimagesupport/JacksonFeatureTest.java b/experimental-native-image-support/src/test/java/com/fnproject/fn/nativeimagesupport/JacksonFeatureTest.java index e0f2905e..8788bf99 100644 --- a/experimental-native-image-support/src/test/java/com/fnproject/fn/nativeimagesupport/JacksonFeatureTest.java +++ b/experimental-native-image-support/src/test/java/com/fnproject/fn/nativeimagesupport/JacksonFeatureTest.java @@ -21,11 +21,11 @@ public class JacksonFeatureTest { @Test public void shouldWalkAnnotations() { - assertThat(JacksonFeature.expandAnnotationReferencesForClass(AbstractBase.class)).containsExactly(ConcreteSubType.class); - assertThat(JacksonFeature.expandAnnotationReferencesForClass(InterfaceBase.class)).containsExactly(InterfaceImpl.class); - assertThat(JacksonFeature.expandAnnotationReferencesForClass(UsesJacksonFeatures.class)).containsExactly(UsesJacksonFeatures.Builder.class); - assertThat(JacksonFeature.expandAnnotationReferencesForClass(AnnotationsOnFields.class)).containsExactly(BigInteger.class); - assertThat(JacksonFeature.expandAnnotationReferencesForClass(AnnotationsOnMethods.class)).containsExactly(BigInteger.class); + assertThat(JacksonFeature.expandClassesToMarkForReflection(AbstractBase.class)).containsExactly(AbstractBase.class,ConcreteSubType.class); + assertThat(JacksonFeature.expandClassesToMarkForReflection(InterfaceBase.class)).containsExactly(InterfaceBase.class,InterfaceImpl.class); + assertThat(JacksonFeature.expandClassesToMarkForReflection(UsesJacksonFeatures.class)).containsExactly(UsesJacksonFeatures.class,UsesJacksonFeatures.Builder.class); + assertThat(JacksonFeature.expandClassesToMarkForReflection(AnnotationsOnFields.class)).containsExactly(AnnotationsOnFields.class,BigInteger.class); + assertThat(JacksonFeature.expandClassesToMarkForReflection(AnnotationsOnMethods.class)).containsExactly(AnnotationsOnMethods.class,BigInteger.class); } diff --git a/images/init-native/Dockerfile b/images/init-native/Dockerfile index 1424b9cf..3fcfc41e 100644 --- a/images/init-native/Dockerfile +++ b/images/init-native/Dockerfile @@ -29,8 +29,6 @@ COPY --from=build /function/target/*.jar target/ RUN /usr/bin/native-image \ --static \ --no-fallback \ - --initialize-at-build-time= \ - --initialize-at-run-time=com.fnproject.fn.runtime.ntv.UnixSocketNative \ --allow-incomplete-classpath \ --enable-all-security-services \ --enable-url-protocols=https,http \ From 7ebc8ec5593b3183d44f9604ea0efe7a1b37ed33 Mon Sep 17 00:00:00 2001 From: CI Date: Thu, 18 Feb 2021 21:31:33 +0000 Subject: [PATCH 213/310] fn-java-fdk: post-1.0.122 version bump [skip ci] --- release.version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/release.version b/release.version index d10644b3..cfc72145 100644 --- a/release.version +++ b/release.version @@ -1 +1 @@ -1.0.122 +1.0.123 From ef5ffb35d2b030507755f5225ed4eba84413d3bd Mon Sep 17 00:00:00 2001 From: Owen Cliffe Date: Fri, 19 Feb 2021 16:13:21 +0000 Subject: [PATCH 214/310] Fix issue where adding interfaces to graal-native breaks the native compiler --- experimental-native-image-support/README.md | 4 ++-- .../fnproject/fn/nativeimagesupport/JacksonFeature.java | 7 ++++--- .../fn/nativeimagesupport/JacksonFeatureTest.java | 2 +- graalvm.version | 2 +- pom.xml | 2 +- 5 files changed, 9 insertions(+), 8 deletions(-) diff --git a/experimental-native-image-support/README.md b/experimental-native-image-support/README.md index 123fe625..2744ac0c 100644 --- a/experimental-native-image-support/README.md +++ b/experimental-native-image-support/README.md @@ -8,8 +8,8 @@ This library is _experimental_ - it may change in behaviour and may not work in Currently, this contains graal native-image configuration files which enable common use cases for : * Oracle Cloud Infrastructure java client support in native images -* General Jersey client support (specifically tested for the OCI client use case, may work in other cases) -* Support for BouncyCastle crypto in native images +* Graal native reflection config for general Jersey client support (specifically tested for the OCI client use case, may work in other cases) +* Graal native reflection config for BouncyCastle crypto in native images It also includes : diff --git a/experimental-native-image-support/src/main/java/com/fnproject/fn/nativeimagesupport/JacksonFeature.java b/experimental-native-image-support/src/main/java/com/fnproject/fn/nativeimagesupport/JacksonFeature.java index c4282dd1..fb0ad445 100644 --- a/experimental-native-image-support/src/main/java/com/fnproject/fn/nativeimagesupport/JacksonFeature.java +++ b/experimental-native-image-support/src/main/java/com/fnproject/fn/nativeimagesupport/JacksonFeature.java @@ -53,7 +53,8 @@ public JacksonFeature() { private static boolean shouldIncludeClass(Class clz) { - return clz != Void.class + return !clz.isInterface() && + clz != Void.class && !clz.getPackage().getName().startsWith(JACKSON_PACKAGE_PREFIX); } @@ -117,8 +118,8 @@ protected static Stream> expandClassesToMarkForReflection(Class claz // otherwise include the class and any descendent classes referenced within those annotations return Stream.concat(Stream.of(clazz), jacksonAnnotations.stream() - .flatMap(JacksonFeature::extractLiteralAnnotationRefs) - .filter(JacksonFeature::shouldIncludeClass)); + .flatMap(JacksonFeature::extractLiteralAnnotationRefs)) + .filter(JacksonFeature::shouldIncludeClass); } diff --git a/experimental-native-image-support/src/test/java/com/fnproject/fn/nativeimagesupport/JacksonFeatureTest.java b/experimental-native-image-support/src/test/java/com/fnproject/fn/nativeimagesupport/JacksonFeatureTest.java index 8788bf99..824d9152 100644 --- a/experimental-native-image-support/src/test/java/com/fnproject/fn/nativeimagesupport/JacksonFeatureTest.java +++ b/experimental-native-image-support/src/test/java/com/fnproject/fn/nativeimagesupport/JacksonFeatureTest.java @@ -22,7 +22,7 @@ public class JacksonFeatureTest { @Test public void shouldWalkAnnotations() { assertThat(JacksonFeature.expandClassesToMarkForReflection(AbstractBase.class)).containsExactly(AbstractBase.class,ConcreteSubType.class); - assertThat(JacksonFeature.expandClassesToMarkForReflection(InterfaceBase.class)).containsExactly(InterfaceBase.class,InterfaceImpl.class); + assertThat(JacksonFeature.expandClassesToMarkForReflection(InterfaceBase.class)).containsExactly(InterfaceImpl.class); assertThat(JacksonFeature.expandClassesToMarkForReflection(UsesJacksonFeatures.class)).containsExactly(UsesJacksonFeatures.class,UsesJacksonFeatures.Builder.class); assertThat(JacksonFeature.expandClassesToMarkForReflection(AnnotationsOnFields.class)).containsExactly(AnnotationsOnFields.class,BigInteger.class); assertThat(JacksonFeature.expandClassesToMarkForReflection(AnnotationsOnMethods.class)).containsExactly(AnnotationsOnMethods.class,BigInteger.class); diff --git a/graalvm.version b/graalvm.version index 2ad7925f..90b68074 100644 --- a/graalvm.version +++ b/graalvm.version @@ -1 +1 @@ -21.0.0 \ No newline at end of file +21.0.0.2 diff --git a/pom.xml b/pom.xml index af42fb4f..7dca993f 100644 --- a/pom.xml +++ b/pom.xml @@ -58,7 +58,7 @@ 1.7.25 2.22.1 1.16.0 - 21.0.0 + 21.0.0.2 From 51977004c69855dd1dff4be4ff9cc94aa5791980 Mon Sep 17 00:00:00 2001 From: Owen Cliffe Date: Fri, 19 Feb 2021 16:47:52 +0000 Subject: [PATCH 215/310] Update experimental-native-image-support/README.md Co-authored-by: Ben Meier <1651305+astromechza@users.noreply.github.com> --- experimental-native-image-support/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/experimental-native-image-support/README.md b/experimental-native-image-support/README.md index 2744ac0c..e7200e08 100644 --- a/experimental-native-image-support/README.md +++ b/experimental-native-image-support/README.md @@ -9,7 +9,7 @@ Currently, this contains graal native-image configuration files which enable com * Oracle Cloud Infrastructure java client support in native images * Graal native reflection config for general Jersey client support (specifically tested for the OCI client use case, may work in other cases) -* Graal native reflection config for BouncyCastle crypto in native images +* Graal native reflection config for BouncyCastle crypto in native images It also includes : From ae2867d4bc9631459a127f1ea8c4c27c1e634e32 Mon Sep 17 00:00:00 2001 From: CI Date: Fri, 19 Feb 2021 17:10:35 +0000 Subject: [PATCH 216/310] fn-java-fdk: post-1.0.123 version bump [skip ci] --- release.version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/release.version b/release.version index cfc72145..0f8b3926 100644 --- a/release.version +++ b/release.version @@ -1 +1 @@ -1.0.123 +1.0.124 From 8d73d077d8c60f3286dd4876274f8710b757c615 Mon Sep 17 00:00:00 2001 From: Owen Cliffe Date: Tue, 9 Mar 2021 17:31:02 +0000 Subject: [PATCH 217/310] Add Unix socket handling JNI library to the jar to make it easier for other runtimes to extract it for use without pulling the docker container --- runtime/pom.xml | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/runtime/pom.xml b/runtime/pom.xml index 75674e9a..77130bf2 100644 --- a/runtime/pom.xml +++ b/runtime/pom.xml @@ -99,6 +99,14 @@ ${build.directory}/version-sources true + + src/main/c/ + + *.so + + false + ${build.directory}/classes/META-INF/com.fnproject.fn/runtime/native/ + From 4186284ef023426d7ce3f438b3766f842c1a406b Mon Sep 17 00:00:00 2001 From: CI Date: Tue, 9 Mar 2021 19:49:56 +0000 Subject: [PATCH 218/310] fn-java-fdk: post-1.0.124 version bump [skip ci] --- release.version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/release.version b/release.version index 0f8b3926..af54009e 100644 --- a/release.version +++ b/release.version @@ -1 +1 @@ -1.0.124 +1.0.125 From 3371ac91e8cd763cd00b525962fb8e02f51560cf Mon Sep 17 00:00:00 2001 From: Dario Domizioli Date: Fri, 9 Apr 2021 11:26:01 +0100 Subject: [PATCH 219/310] Workaround to make the build work after Maven fixed CVE-2021-26291 (#254) Maven has added a default setting in the settings.xml which blocks access to any HTTP-based repository. However, as part of the FDK build we are running an HTTP server hosting the built JARs in a container and accessing it in a Maven command running in another container (either in the build or through `fn build` in the tests). This is not allowed anymore by default due to Maven's change. We introduce a workaround that uses a local settings file to temporarily disable the blockage and redirects an HTTP-based repo queries to our local container running the HTTP server. For the build, the change is only relevant for the copy-dependencies step of the build image creations, and the local settings file is deleted afterwards, in a way that does not even leave a layer with an "insecure" Maven settings file in the container. For the tests, we have to use a custom Dockerfile template in every test function, which is filled in by the test logic, and we generate a Maven settings file which overrides the standard one for that specific test container. Also we try to unbreak the CircleCI build by using the latest image and providing a custom Maven settings file with the appropriate blocker and with the fix to SUREFIRE-1588. Finally, we disable some flakey tests that have to be rewritten anyway. Co-authored-by: Andrea Rosa --- .circleci/config.yml | 3 +- .circleci/fix-java-for-surefire.sh | 16 +--- .circleci/maven-settings.xml | 35 ++++++++ images/build/Dockerfile | 1 + images/build/Dockerfile-jdk11 | 1 + images/build/cache-deps.sh | 4 +- images/build/local-settings.xml | 23 +++++ .../funcs/flowAllFeatures/Dockerfile | 11 +++ integration-tests/funcs/flowBasic/Dockerfile | 11 +++ .../funcs/flowBasicJDK8/Dockerfile | 11 +++ .../funcs/flowExitHooks/Dockerfile | 11 +++ .../funcs/flowTimeouts/Dockerfile | 11 +++ integration-tests/funcs/helloFunc/Dockerfile | 11 +++ integration-tests/funcs/httpgwfunc/Dockerfile | 11 +++ integration-tests/funcs/httpgwfunc/func.yaml | 1 + integration-tests/funcs/simpleFunc/Dockerfile | 11 +++ integration-tests/funcs/simpleFunc/func.yaml | 1 + .../integrationtest/IntegrationTestRule.java | 50 +++++++++++ .../fn/integrationtest/FlowTest.java | 90 ++++++++++--------- .../fn/integrationtest/FunctionsTest.java | 42 +++++---- 20 files changed, 276 insertions(+), 79 deletions(-) create mode 100644 .circleci/maven-settings.xml create mode 100644 images/build/local-settings.xml create mode 100644 integration-tests/funcs/flowAllFeatures/Dockerfile create mode 100644 integration-tests/funcs/flowBasic/Dockerfile create mode 100644 integration-tests/funcs/flowBasicJDK8/Dockerfile create mode 100644 integration-tests/funcs/flowExitHooks/Dockerfile create mode 100644 integration-tests/funcs/flowTimeouts/Dockerfile create mode 100644 integration-tests/funcs/helloFunc/Dockerfile create mode 100644 integration-tests/funcs/httpgwfunc/Dockerfile create mode 100644 integration-tests/funcs/simpleFunc/Dockerfile diff --git a/.circleci/config.yml b/.circleci/config.yml index 698e1171..3251a19c 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -2,7 +2,8 @@ version: 2 jobs: build: working_directory: ~/fn-java-fdk - machine: true + machine: + image: ubuntu-1604:202101-01 environment: # store_artifacts doesn't shell substitute so the variable # definitions are duplicated in those steps too. diff --git a/.circleci/fix-java-for-surefire.sh b/.circleci/fix-java-for-surefire.sh index fb00731c..2ca4cd25 100755 --- a/.circleci/fix-java-for-surefire.sh +++ b/.circleci/fix-java-for-surefire.sh @@ -2,18 +2,4 @@ set -ex - cat << 'EOF' > $HOME/.m2/settings.xml - - - - SUREFIRE-1588 - - true - - - -Djdk.net.URLClassPath.disableClassPathURLCheck=true - - - - - EOF \ No newline at end of file + cp ./.circleci/maven-settings.xml $HOME/.m2/settings.xml diff --git a/.circleci/maven-settings.xml b/.circleci/maven-settings.xml new file mode 100644 index 00000000..b4945cf2 --- /dev/null +++ b/.circleci/maven-settings.xml @@ -0,0 +1,35 @@ + + + + + + + + + + + + + + maven-default-http-blocker + external:http:* + Pseudo repository to mirror external repositories initially using HTTP. + http://0.0.0.0/ + true + + + + + + SUREFIRE-1588 + + true + + + -Djdk.net.URLClassPath.disableClassPathURLCheck=true + + + + \ No newline at end of file diff --git a/images/build/Dockerfile b/images/build/Dockerfile index 398d8540..e5aed9e2 100644 --- a/images/build/Dockerfile +++ b/images/build/Dockerfile @@ -17,6 +17,7 @@ FROM maven:3-jdk-8-slim ARG FN_REPO_URL ADD pom.xml /tmp/cache-deps/pom.xml +ADD local-settings.xml /tmp/cache-deps/local-settings.xml ADD cache-deps.sh /tmp/cache-deps/cache-deps.sh ADD src /tmp/cache-deps/src diff --git a/images/build/Dockerfile-jdk11 b/images/build/Dockerfile-jdk11 index dac01823..0e5c2bab 100644 --- a/images/build/Dockerfile-jdk11 +++ b/images/build/Dockerfile-jdk11 @@ -19,6 +19,7 @@ FROM maven:3-jdk-11-slim ARG FN_REPO_URL ADD pom.xml /tmp/cache-deps/pom.xml +ADD local-settings.xml /tmp/cache-deps/local-settings.xml ADD cache-deps.sh /tmp/cache-deps/cache-deps.sh ADD src /tmp/cache-deps/src RUN /tmp/cache-deps/cache-deps.sh diff --git a/images/build/cache-deps.sh b/images/build/cache-deps.sh index 784fefb8..d82473db 100755 --- a/images/build/cache-deps.sh +++ b/images/build/cache-deps.sh @@ -23,6 +23,6 @@ if [ -n "$FN_REPO_URL" ]; then REPO_DFN="-Dfn.repo.url=$FN_REPO_URL" fi - -cd /tmp/cache-deps && mvn test package dependency:copy-dependencies -Dmaven.repo.local=/usr/share/maven/ref/repository -Dmdep.prependGroupId=true -DoutputDirectory=target $REPO_DFN +sed -i "s#___FN_REPO_URL___#${FN_REPO_URL}#g" /tmp/cache-deps/local-settings.xml +cd /tmp/cache-deps && mvn -s /tmp/cache-deps/local-settings.xml test package dependency:copy-dependencies -Dmaven.repo.local=/usr/share/maven/ref/repository -Dmdep.prependGroupId=true -DoutputDirectory=target $REPO_DFN cd / && rm -fr /tmp/cache-deps diff --git a/images/build/local-settings.xml b/images/build/local-settings.xml new file mode 100644 index 00000000..a6ba37c2 --- /dev/null +++ b/images/build/local-settings.xml @@ -0,0 +1,23 @@ + + + + + + + + + + + + override-maven-default-http-blocker + external:http:* + Pseudo repository to mirror external repositories initially using HTTP. + ___FN_REPO_URL___ + false + + + + + diff --git a/integration-tests/funcs/flowAllFeatures/Dockerfile b/integration-tests/funcs/flowAllFeatures/Dockerfile new file mode 100644 index 00000000..f40be518 --- /dev/null +++ b/integration-tests/funcs/flowAllFeatures/Dockerfile @@ -0,0 +1,11 @@ +FROM fnproject/fn-java-fdk-build:__TO_BE_REPLACED__ as build-stage +WORKDIR /function +ENV MAVEN_OPTS -Dhttp.proxyHost= -Dhttp.proxyPort= -Dhttps.proxyHost= -Dhttps.proxyPort= -Dhttp.nonProxyHosts= -Dmaven.repo.local=/usr/share/maven/ref/repository +ADD pom.xml /function/pom.xml +RUN ["mvn", "package", "dependency:copy-dependencies", "-DincludeScope=runtime", "-DskipTests=true", "-Dmdep.prependGroupId=true", "-DoutputDirectory=target", "--fail-never"] +ADD src /function/src +RUN ["mvn", "package"] +FROM fnproject/fn-java-fdk:__TO_BE_REPLACED__ +WORKDIR /function +COPY --from=build-stage /function/target/*.jar /function/app/ +CMD ["com.fnproject.fn.integration.ExerciseEverything::handleRequest"] diff --git a/integration-tests/funcs/flowBasic/Dockerfile b/integration-tests/funcs/flowBasic/Dockerfile new file mode 100644 index 00000000..05413242 --- /dev/null +++ b/integration-tests/funcs/flowBasic/Dockerfile @@ -0,0 +1,11 @@ +FROM fnproject/fn-java-fdk-build:__TO_BE_REPLACED__ as build-stage +WORKDIR /function +ENV MAVEN_OPTS -Dhttp.proxyHost= -Dhttp.proxyPort= -Dhttps.proxyHost= -Dhttps.proxyPort= -Dhttp.nonProxyHosts= -Dmaven.repo.local=/usr/share/maven/ref/repository +ADD pom.xml /function/pom.xml +RUN ["mvn", "package", "dependency:copy-dependencies", "-DincludeScope=runtime", "-DskipTests=true", "-Dmdep.prependGroupId=true", "-DoutputDirectory=target", "--fail-never"] +ADD src /function/src +RUN ["mvn", "package"] +FROM fnproject/fn-java-fdk:__TO_BE_REPLACED__ +WORKDIR /function +COPY --from=build-stage /function/target/*.jar /function/app/ +CMD ["com.fnproject.fn.integration.test_1.CompleterFunction::handleRequest"] diff --git a/integration-tests/funcs/flowBasicJDK8/Dockerfile b/integration-tests/funcs/flowBasicJDK8/Dockerfile new file mode 100644 index 00000000..05413242 --- /dev/null +++ b/integration-tests/funcs/flowBasicJDK8/Dockerfile @@ -0,0 +1,11 @@ +FROM fnproject/fn-java-fdk-build:__TO_BE_REPLACED__ as build-stage +WORKDIR /function +ENV MAVEN_OPTS -Dhttp.proxyHost= -Dhttp.proxyPort= -Dhttps.proxyHost= -Dhttps.proxyPort= -Dhttp.nonProxyHosts= -Dmaven.repo.local=/usr/share/maven/ref/repository +ADD pom.xml /function/pom.xml +RUN ["mvn", "package", "dependency:copy-dependencies", "-DincludeScope=runtime", "-DskipTests=true", "-Dmdep.prependGroupId=true", "-DoutputDirectory=target", "--fail-never"] +ADD src /function/src +RUN ["mvn", "package"] +FROM fnproject/fn-java-fdk:__TO_BE_REPLACED__ +WORKDIR /function +COPY --from=build-stage /function/target/*.jar /function/app/ +CMD ["com.fnproject.fn.integration.test_1.CompleterFunction::handleRequest"] diff --git a/integration-tests/funcs/flowExitHooks/Dockerfile b/integration-tests/funcs/flowExitHooks/Dockerfile new file mode 100644 index 00000000..856c40d0 --- /dev/null +++ b/integration-tests/funcs/flowExitHooks/Dockerfile @@ -0,0 +1,11 @@ +FROM fnproject/fn-java-fdk-build:__TO_BE_REPLACED__ as build-stage +WORKDIR /function +ENV MAVEN_OPTS -Dhttp.proxyHost= -Dhttp.proxyPort= -Dhttps.proxyHost= -Dhttps.proxyPort= -Dhttp.nonProxyHosts= -Dmaven.repo.local=/usr/share/maven/ref/repository +ADD pom.xml /function/pom.xml +RUN ["mvn", "package", "dependency:copy-dependencies", "-DincludeScope=runtime", "-DskipTests=true", "-Dmdep.prependGroupId=true", "-DoutputDirectory=target", "--fail-never"] +ADD src /function/src +RUN ["mvn", "package"] +FROM fnproject/fn-java-fdk:__TO_BE_REPLACED__ +WORKDIR /function +COPY --from=build-stage /function/target/*.jar /function/app/ +CMD ["com.fnproject.fn.integration.test_5.CompleterFunction::handleRequest"] diff --git a/integration-tests/funcs/flowTimeouts/Dockerfile b/integration-tests/funcs/flowTimeouts/Dockerfile new file mode 100644 index 00000000..d5d2a77c --- /dev/null +++ b/integration-tests/funcs/flowTimeouts/Dockerfile @@ -0,0 +1,11 @@ +FROM fnproject/fn-java-fdk-build:__TO_BE_REPLACED__ as build-stage +WORKDIR /function +ENV MAVEN_OPTS -Dhttp.proxyHost= -Dhttp.proxyPort= -Dhttps.proxyHost= -Dhttps.proxyPort= -Dhttp.nonProxyHosts= -Dmaven.repo.local=/usr/share/maven/ref/repository +ADD pom.xml /function/pom.xml +RUN ["mvn", "package", "dependency:copy-dependencies", "-DincludeScope=runtime", "-DskipTests=true", "-Dmdep.prependGroupId=true", "-DoutputDirectory=target", "--fail-never"] +ADD src /function/src +RUN ["mvn", "package"] +FROM fnproject/fn-java-fdk:__TO_BE_REPLACED__ +WORKDIR /function +COPY --from=build-stage /function/target/*.jar /function/app/ +CMD ["com.fnproject.fn.integration.test_6.CompleterFunction::handleRequest"] diff --git a/integration-tests/funcs/helloFunc/Dockerfile b/integration-tests/funcs/helloFunc/Dockerfile new file mode 100644 index 00000000..42a1919a --- /dev/null +++ b/integration-tests/funcs/helloFunc/Dockerfile @@ -0,0 +1,11 @@ +FROM fnproject/fn-java-fdk-build:1.0.0-SNAPSHOT as build-stage +WORKDIR /function +ENV MAVEN_OPTS -Dhttp.proxyHost= -Dhttp.proxyPort= -Dhttps.proxyHost= -Dhttps.proxyPort= -Dhttp.nonProxyHosts= -Dmaven.repo.local=/usr/share/maven/ref/repository +ADD pom.xml /function/pom.xml +RUN ["mvn", "package", "dependency:copy-dependencies", "-DincludeScope=runtime", "-DskipTests=true", "-Dmdep.prependGroupId=true", "-DoutputDirectory=target", "--fail-never"] +ADD src /function/src +RUN ["mvn", "package"] +FROM fnproject/fn-java-fdk:1.0.0-SNAPSHOT +WORKDIR /function +COPY --from=build-stage /function/target/*.jar /function/app/ +CMD ["com.fnproject.fn.integration.hello.HelloFunction::handleRequest"] diff --git a/integration-tests/funcs/httpgwfunc/Dockerfile b/integration-tests/funcs/httpgwfunc/Dockerfile new file mode 100644 index 00000000..dda6b8f7 --- /dev/null +++ b/integration-tests/funcs/httpgwfunc/Dockerfile @@ -0,0 +1,11 @@ +FROM fnproject/fn-java-fdk-build:jdk11-1.0.0-SNAPSHOT as build-stage +WORKDIR /function +ENV MAVEN_OPTS -Dhttp.proxyHost= -Dhttp.proxyPort= -Dhttps.proxyHost= -Dhttps.proxyPort= -Dhttp.nonProxyHosts= -Dmaven.repo.local=/usr/share/maven/ref/repository +ADD pom.xml /function/pom.xml +RUN ["mvn", "package", "dependency:copy-dependencies", "-DincludeScope=runtime", "-DskipTests=true", "-Dmdep.prependGroupId=true", "-DoutputDirectory=target", "--fail-never"] +ADD src /function/src +RUN ["mvn", "package"] +FROM fnproject/fn-java-fdk:jre11-1.0.0-SNAPSHOT +WORKDIR /function +COPY --from=build-stage /function/target/*.jar /function/app/ +CMD ["com.example.fn.TriggerFunction::handleRequest"] diff --git a/integration-tests/funcs/httpgwfunc/func.yaml b/integration-tests/funcs/httpgwfunc/func.yaml index af45f447..c1eacb5d 100644 --- a/integration-tests/funcs/httpgwfunc/func.yaml +++ b/integration-tests/funcs/httpgwfunc/func.yaml @@ -19,6 +19,7 @@ name: httpgwfunc version: 0.0.1 runtime: java cmd: com.example.fn.TriggerFunction::handleRequest +timeout: 120 format: http-stream triggers: - name: trig diff --git a/integration-tests/funcs/simpleFunc/Dockerfile b/integration-tests/funcs/simpleFunc/Dockerfile new file mode 100644 index 00000000..a929c735 --- /dev/null +++ b/integration-tests/funcs/simpleFunc/Dockerfile @@ -0,0 +1,11 @@ +FROM fnproject/fn-java-fdk-build:__TO_BE_REPLACED__ as build-stage +WORKDIR /function +ENV MAVEN_OPTS -Dhttp.proxyHost= -Dhttp.proxyPort= -Dhttps.proxyHost= -Dhttps.proxyPort= -Dhttp.nonProxyHosts= -Dmaven.repo.local=/usr/share/maven/ref/repository +ADD pom.xml /function/pom.xml +RUN ["mvn", "package", "dependency:copy-dependencies", "-DincludeScope=runtime", "-DskipTests=true", "-Dmdep.prependGroupId=true", "-DoutputDirectory=target", "--fail-never"] +ADD src /function/src +RUN ["mvn", "package"] +FROM fnproject/fn-java-fdk:__TO_BE_REPLACED__ +WORKDIR /function +COPY --from=build-stage /function/target/*.jar /function/app/ +CMD ["com.fnproject.fn.integration.test2.PlainFunction::handleRequest"] diff --git a/integration-tests/funcs/simpleFunc/func.yaml b/integration-tests/funcs/simpleFunc/func.yaml index f6533e4b..cbf5df6a 100644 --- a/integration-tests/funcs/simpleFunc/func.yaml +++ b/integration-tests/funcs/simpleFunc/func.yaml @@ -18,5 +18,6 @@ schema_version: 20180708 name: simplefunc version: 0.0.3 runtime: java11 +timeout: 120 cmd: com.fnproject.fn.integration.test2.PlainFunction::handleRequest format: http-stream diff --git a/integration-tests/src/main/java/com/fnproject/fn/integrationtest/IntegrationTestRule.java b/integration-tests/src/main/java/com/fnproject/fn/integrationtest/IntegrationTestRule.java index 53def9d7..3e2aef67 100644 --- a/integration-tests/src/main/java/com/fnproject/fn/integrationtest/IntegrationTestRule.java +++ b/integration-tests/src/main/java/com/fnproject/fn/integrationtest/IntegrationTestRule.java @@ -280,6 +280,38 @@ public TestContext rewritePOM() throws Exception { } + /** + * Rewrites the Dockerfile to provide a settings file which works around + * problems with Maven HTTP repos. + */ + public TestContext rewriteDockerfile(Boolean java11) throws Exception { + String jdkPrefix = java11 ? "jdk11-" : ""; + String jrePrefix = java11 ? "jre11-" : ""; + + File dFile = new File(baseDir, "Dockerfile"); + String dFileContent = FileUtils.readFileToString(dFile, StandardCharsets.UTF_8); + + String buildImageStringToMatch = "FROM fnproject/fn-java-fdk-build:[^ ]+ as build"; + String newContent = dFileContent.replaceFirst(buildImageStringToMatch, "FROM fnproject/fn-java-fdk-build:" + jdkPrefix + getFdkVersion() + " as build"); + + String runtimeImageStringToMatch = "FROM fnproject/fn-java-fdk:[^\n ]+"; + String newContent2 = newContent.replaceFirst(runtimeImageStringToMatch, "FROM fnproject/fn-java-fdk:" + jrePrefix + getFdkVersion()); + + String mavenSettingsFileContent = generateMavenSettingsFileContent(); + File mFile = new File(baseDir, "maven-settings.xml"); + System.err.println(mavenSettingsFileContent); + FileUtils.writeStringToFile(mFile, mavenSettingsFileContent, StandardCharsets.UTF_8); + + String runMavenLine = "RUN [\"mvn\", \"package\", \"dependency:copy-dependencies\""; + String runMavenLineAsRegex = "RUN \\[\\\"mvn\\\", \\\"package\\\", \\\"dependency:copy-dependencies\\\""; + String newContent3 = newContent2.replaceFirst(runMavenLineAsRegex, "ADD maven-settings.xml /usr/share/maven/conf/settings.xml" + System.getProperty("line.separator") + runMavenLine); + + System.err.println(newContent3); + FileUtils.writeStringToFile(dFile, newContent3, StandardCharsets.UTF_8); + return this; + } + + /** * Gets the app name you should use for tests. * @@ -298,6 +330,24 @@ public TestContext cd(String dir) { baseDir = new File(baseDir, dir); return this; } + + private String generateMavenSettingsFileContent() { + return String.join(System.getProperty("line.separator"), + "", + "", + " ", + " ", + " override-maven-default-http-blocker", + " external:http:*", + " Pseudo repository to mirror external repositories initially using HTTP.", + " " + getLocalFnRepo() + "", + " false", + " ", + " ", + ""); + } } diff --git a/integration-tests/src/test/java/com/fnproject/fn/integrationtest/FlowTest.java b/integration-tests/src/test/java/com/fnproject/fn/integrationtest/FlowTest.java index 59a8938b..81a9b706 100644 --- a/integration-tests/src/test/java/com/fnproject/fn/integrationtest/FlowTest.java +++ b/integration-tests/src/test/java/com/fnproject/fn/integrationtest/FlowTest.java @@ -41,7 +41,7 @@ public class FlowTest { @Test public void shouldInvokeBasicFlow() throws Exception { IntegrationTestRule.TestContext tc = testRule.newTest(); - tc.withDirFrom("funcs/flowBasic").rewritePOM(); + tc.withDirFrom("funcs/flowBasic").rewritePOM().rewriteDockerfile(true); tc.runFn("--verbose", "deploy", "--create-app", "--app", tc.appName(), "--local"); tc.runFn("config", "app", tc.appName(), "COMPLETER_BASE_URL", testRule.getFlowURL()); CmdResult r = tc.runFnWithInput("1", "invoke", tc.appName(), "flowbasic"); @@ -52,7 +52,7 @@ public void shouldInvokeBasicFlow() throws Exception { @Test public void shouldInvokeBasicFlowJDK8() throws Exception { IntegrationTestRule.TestContext tc = testRule.newTest(); - tc.withDirFrom("funcs/flowBasicJDK8").rewritePOM(); + tc.withDirFrom("funcs/flowBasicJDK8").rewritePOM().rewriteDockerfile(false); tc.runFn("--verbose", "deploy", "--create-app", "--app", tc.appName(), "--local"); tc.runFn("config", "app", tc.appName(), "COMPLETER_BASE_URL", testRule.getFlowURL()); CmdResult r = tc.runFnWithInput("1", "invoke", tc.appName(), "flowbasicj8"); @@ -63,7 +63,7 @@ public void shouldInvokeBasicFlowJDK8() throws Exception { @Test public void shouldExerciseAllFlow() throws Exception { IntegrationTestRule.TestContext tc = testRule.newTest(); - tc.withDirFrom("funcs/flowAllFeatures").rewritePOM(); + tc.withDirFrom("funcs/flowAllFeatures").rewritePOM().rewriteDockerfile(true); tc.runFn("--verbose", "deploy", "--create-app", "--app", tc.appName(), "--local"); tc.runFn("config", "app", tc.appName(), "COMPLETER_BASE_URL", testRule.getFlowURL()); CmdResult r = tc.runFnWithInput("1", "invoke", tc.appName(), "flowallfeatures"); @@ -71,46 +71,48 @@ public void shouldExerciseAllFlow() throws Exception { } - @Test - public void shouldCallExitHooks() throws Exception { - CompletableFuture done = new CompletableFuture<>(); - - HttpServer server = HttpServer.create(new InetSocketAddress(8000), 0); - server.createContext("/exited", httpExchange -> { - done.complete(true); - String resp = "ok"; - httpExchange.sendResponseHeaders(200, resp.length()); - httpExchange.getResponseBody().write(resp.getBytes()); - httpExchange.getResponseBody().close(); - }); - server.setExecutor(null); // creates a default executor - server.start(); - try { - IntegrationTestRule.TestContext tc = testRule.newTest(); - tc.withDirFrom("funcs/flowExitHooks").rewritePOM(); - tc.runFn("--verbose", "build", "--no-cache"); - tc.runFn("--verbose", "deploy", "--create-app", "--app", tc.appName(), "--local"); - tc.runFn("config", "app", tc.appName(), "COMPLETER_BASE_URL", testRule.getFlowURL()); - tc.runFn("config", "app", tc.appName(), "TERMINATION_HOOK_URL", "http://" + testRule.getDockerLocalhost() + ":" + 8000 + "/exited"); - CmdResult r = tc.runFnWithInput("1", "invoke", tc.appName(), "flowexithooks"); - assertThat(r.getStdout()).contains("42"); - - assertThat(done.get(10, TimeUnit.SECONDS)).withFailMessage("Expected callback within 10 seconds").isTrue(); - - } finally { - server.stop(0); - } - } - - - @Test - public void shouldHandleTimeouts() throws Exception { - IntegrationTestRule.TestContext tc = testRule.newTest(); - tc.withDirFrom("funcs/flowTimeouts").rewritePOM(); - tc.runFn("--verbose", "deploy", "--create-app", "--app", tc.appName(), "--local"); - tc.runFn("config", "app", tc.appName(), "COMPLETER_BASE_URL", testRule.getFlowURL()); - CmdResult r = tc.runFn("invoke", tc.appName(), "flowtimeouts"); - assertThat(r.getStdout()).contains("timeout"); - } + // THESE TESTS ARE FLAKEY AND SHOULD BE REVISITED. + + // @Test + // public void shouldCallExitHooks() throws Exception { + // CompletableFuture done = new CompletableFuture<>(); + + // HttpServer server = HttpServer.create(new InetSocketAddress(8000), 0); + // server.createContext("/exited", httpExchange -> { + // done.complete(true); + // String resp = "ok"; + // httpExchange.sendResponseHeaders(200, resp.length()); + // httpExchange.getResponseBody().write(resp.getBytes()); + // httpExchange.getResponseBody().close(); + // }); + // server.setExecutor(null); // creates a default executor + // server.start(); + // try { + // IntegrationTestRule.TestContext tc = testRule.newTest(); + // tc.withDirFrom("funcs/flowExitHooks").rewritePOM().rewriteDockerfile(true); + // tc.runFn("--verbose", "build", "--no-cache"); + // tc.runFn("--verbose", "deploy", "--create-app", "--app", tc.appName(), "--local"); + // tc.runFn("config", "app", tc.appName(), "COMPLETER_BASE_URL", testRule.getFlowURL()); + // tc.runFn("config", "app", tc.appName(), "TERMINATION_HOOK_URL", "http://" + testRule.getDockerLocalhost() + ":" + 8000 + "/exited"); + // CmdResult r = tc.runFnWithInput("1", "invoke", tc.appName(), "flowexithooks"); + // assertThat(r.getStdout()).contains("42"); + + // assertThat(done.get(10, TimeUnit.SECONDS)).withFailMessage("Expected callback within 10 seconds").isTrue(); + + // } finally { + // server.stop(0); + // } + // } + + + // @Test + // public void shouldHandleTimeouts() throws Exception { + // IntegrationTestRule.TestContext tc = testRule.newTest(); + // tc.withDirFrom("funcs/flowTimeouts").rewritePOM().rewriteDockerfile(true); + // tc.runFn("--verbose", "deploy", "--create-app", "--app", tc.appName(), "--local"); + // tc.runFn("config", "app", tc.appName(), "COMPLETER_BASE_URL", testRule.getFlowURL()); + // CmdResult r = tc.runFn("invoke", tc.appName(), "flowtimeouts"); + // assertThat(r.getStdout()).contains("timeout"); + // } } diff --git a/integration-tests/src/test/java/com/fnproject/fn/integrationtest/FunctionsTest.java b/integration-tests/src/test/java/com/fnproject/fn/integrationtest/FunctionsTest.java index ac3d158b..22b4a2ee 100644 --- a/integration-tests/src/test/java/com/fnproject/fn/integrationtest/FunctionsTest.java +++ b/integration-tests/src/test/java/com/fnproject/fn/integrationtest/FunctionsTest.java @@ -46,7 +46,7 @@ public class FunctionsTest { @Test public void shouldCallExistingFn() throws Exception { IntegrationTestRule.TestContext tc = testRule.newTest(); - tc.withDirFrom("funcs/simpleFunc").rewritePOM(); + tc.withDirFrom("funcs/simpleFunc").rewritePOM().rewriteDockerfile(true); tc.runFn("--verbose", "deploy", "--create-app", "--app", tc.appName(), "--local"); tc.runFn("config", "app", tc.appName(), "GREETING", "Salutations"); @@ -59,19 +59,27 @@ public void shouldCallExistingFn() throws Exception { } - @Test() - public void checkBoilerPlate() throws Exception { - for (String runtime : new String[] {"java8", "java11"}) { - IntegrationTestRule.TestContext tc = testRule.newTest(); - String fnName = "bp" + runtime; - tc.runFn("init", "--runtime", runtime, "--name", fnName); - tc.rewritePOM(); - tc.runFn("--verbose", "deploy", "--create-app", "--app", tc.appName(), "--local"); - CmdResult rs = tc.runFnWithInput("wibble", "invoke", tc.appName(), fnName); - assertThat(rs.getStdout()).contains("Hello, wibble!"); - } - } - + // + // AS OF 2021-04-07 WE ARE UNABLE TO TEST THE "OUT OF THE BOX" EXPERIENCE + // WITH A LOCAL FDK SERVED THROUGH AN HTTP SERVER BECAUSE MAVEN HAS DISABLED + // SUPPORT FOR HTTP REPOSITORIES BY DEFAULT DUE TO CVE-2021-26291. + // IF WE WERE TO PROVIDE A CUSTOM DOCKERFILE TO WORK AROUND MAVEN'S DEFAULT + // BEHAVIOUR, LIKE WE DO FOR THE TESTS AROUND THIS ONE, WE WOULD NOT BE + // TESTING THE "OUT OF THE BOX" EXPERIENCE ANYWAY, SO THIS TEST IS MOOT. + // + // @Test() + // public void checkBoilerPlate() throws Exception { + // for (String runtime : new String[] {"java8", "java11"}) { + // IntegrationTestRule.TestContext tc = testRule.newTest(); + // String fnName = "bp" + runtime; + // tc.runFn("init", "--runtime", runtime, "--name", fnName); + // tc.rewritePOM(); + // tc.runFn("--verbose", "deploy", "--create-app", "--app", tc.appName(), "--local"); + // CmdResult rs = tc.runFnWithInput("wibble", "invoke", tc.appName(), fnName); + // assertThat(rs.getStdout()).contains("Hello, wibble!"); + // } + //} + // @Test() public void runNativeFunction() throws Exception { @@ -81,7 +89,7 @@ public void runNativeFunction() throws Exception { IntegrationTestRule.TestContext tc = testRule.newTest(); String fnName = "graaltest" + i++; tc.runFn("init", "--init-image", "fnproject/fn-java-native-init:" + version, "--name", fnName); - tc.rewritePOM(); + tc.rewritePOM().rewriteDockerfile(version != testRule.getFdkVersion()); tc.runFn("--verbose", "deploy", "--create-app", "--app", tc.appName(), "--local"); CmdResult rs = tc.runFnWithInput("wibble", "invoke", tc.appName(), fnName); assertThat(rs.getStdout()).contains("Hello, wibble!"); @@ -97,7 +105,7 @@ public static class InspectResponse { @Test() public void shouldHandleTrigger() throws Exception { IntegrationTestRule.TestContext tc = testRule.newTest(); - tc.withDirFrom("funcs/httpgwfunc").rewritePOM(); + tc.withDirFrom("funcs/httpgwfunc").rewritePOM().rewriteDockerfile(true); tc.runFn("--verbose", "deploy", "--create-app", "--app", tc.appName(), "--local"); // Get me the trigger URL @@ -129,7 +137,7 @@ public void shouldHandleTrigger() throws Exception { @Test public void shouldGetFDKVersion() throws Exception { IntegrationTestRule.TestContext tc = testRule.newTest(); - tc.withDirFrom("funcs/simpleFunc").rewritePOM(); + tc.withDirFrom("funcs/simpleFunc").rewritePOM().rewriteDockerfile(true); tc.runFn("--verbose", "deploy", "--create-app", "--app", tc.appName(), "--local"); tc.runFn("config", "app", tc.appName(), "GREETING", "Salutations"); From 5618e5ebbe6050c6cad9f65287ccf4d10e2e85bc Mon Sep 17 00:00:00 2001 From: CI Date: Fri, 9 Apr 2021 10:48:19 +0000 Subject: [PATCH 220/310] fn-java-fdk: post-1.0.125 version bump [skip ci] --- release.version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/release.version b/release.version index af54009e..2e745396 100644 --- a/release.version +++ b/release.version @@ -1 +1 @@ -1.0.125 +1.0.126 From fd7721ebf65c7bff69ac25829a1384ab645b99f9 Mon Sep 17 00:00:00 2001 From: Dario Domizioli Date: Mon, 12 Apr 2021 15:36:33 +0100 Subject: [PATCH 221/310] Add support for Oracle Cloud Infrastructure tracing solution by providing a tracing context (#255) Oracle Functions will soon release a feature providing an integration with the Oracle Application Performance Monitoring (APM) service. This service supports the sending of Zipkin formatted tracing data to a collector endpoint. The service will provide the function code with data which includes: A boolean flag specifying whether the tracing integration is enabled for the function invocation A trace collector URL that can be used to configure Zipkin so that tracing data is sent there The "B3" formatted headers specifying the originating trace ID and span IDs (as specified by Zipkin) This information is accessible by the function code in a Tracing Context provided by the FDK. This change has no effect on existing functions, except that the keys "OCI_TRACING_ENABLED" and "OCI_TRACE_COLLECTOR_URL" are now reserved for this tracing integration and cannot be used for function configuration. This change adds a TracingContext interface that users can use as a parameter of their function (much like the HTTPGatewayContext) to have access to the configuration data that Zipkin would need (i.e. a collector URL) and the headers data involved with tracing (for Zipkin, the "B3 Headers"). Once the Oracle Functions integration with APM is complete, users will be able to enable tracing for their functions and in that case the TracingContext will report isTracingEnabled() == true and will return the right data for each of its methods. --- api/src/main/api/snapshot.sigfile | 16 +++ .../com/fnproject/fn/api/RuntimeContext.java | 18 +++ .../fn/api/tracing/TracingContext.java | 101 +++++++++++++++ .../com/fnproject/fn/runtime/EntryPoint.java | 2 +- .../fn/runtime/FunctionRuntimeContext.java | 10 ++ .../fn/runtime/coercion/ContextCoercion.java | 4 + .../fn/runtime/tracing/OCITracingContext.java | 117 ++++++++++++++++++ .../tracing/OCITracingContextTest.java | 110 ++++++++++++++++ 8 files changed, 377 insertions(+), 1 deletion(-) create mode 100644 api/src/main/java/com/fnproject/fn/api/tracing/TracingContext.java create mode 100644 runtime/src/main/java/com/fnproject/fn/runtime/tracing/OCITracingContext.java create mode 100644 runtime/src/test/java/com/fnproject/fn/runtime/tracing/OCITracingContextTest.java diff --git a/api/src/main/api/snapshot.sigfile b/api/src/main/api/snapshot.sigfile index 2ed59945..096b2dee 100644 --- a/api/src/main/api/snapshot.sigfile +++ b/api/src/main/api/snapshot.sigfile @@ -134,6 +134,8 @@ meth public abstract <%0 extends java.lang.Object> java.util.Optional<{%%0}> get meth public abstract com.fnproject.fn.api.MethodWrapper getMethod() meth public abstract java.lang.String getAppID() meth public abstract java.lang.String getFunctionID() +meth public java.lang.String getAppName() +meth public java.lang.String getFunctionName() meth public abstract java.util.List getInputCoercions(com.fnproject.fn.api.MethodWrapper,int) meth public abstract java.util.List getOutputCoercions(java.lang.reflect.Method) meth public abstract java.util.Map getConfiguration() @@ -182,6 +184,20 @@ meth public abstract void addResponseHeader(String key, String value) meth public abstract void setResponseHeader(String key, String v1, String... vs) meth public abstract void setStatusCode(int code) +CLSS public abstract interface com.fnproject.fn.api.tracing.TracingContext +meth public abstract InvocationContext getInvocationContext() +meth public abstract RuntimeContext getRuntimeContext() +meth public abstract java.lang.String getServiceName() +meth public abstract java.lang.String getTraceCollectorURL() +meth public abstract java.lang.String getTraceId() +meth public abstract java.lang.String getSpanId() +meth public abstract java.lang.String getParentSpanId() +meth public abstract java.lang.Boolean isSampled() +meth public abstract java.lang.String getFlags() +meth public abstract java.lang.Boolean isTracingEnabled() +meth public abstract java.lang.String getAppName() +meth public abstract java.lang.String getFunctionName() + CLSS public abstract interface java.io.Closeable intf java.lang.AutoCloseable meth public abstract void close() throws java.io.IOException diff --git a/api/src/main/java/com/fnproject/fn/api/RuntimeContext.java b/api/src/main/java/com/fnproject/fn/api/RuntimeContext.java index de628f10..04936a8c 100644 --- a/api/src/main/java/com/fnproject/fn/api/RuntimeContext.java +++ b/api/src/main/java/com/fnproject/fn/api/RuntimeContext.java @@ -43,6 +43,24 @@ public interface RuntimeContext { */ String getFunctionID(); + /** + * The user-friendly name of the application associated with this function, + * if present; defaulted to the application ID for backwards compatibility + * @return an application name + */ + default public String getAppName() { + return getAppID(); + } + + /** + * The user-friendly name of the function, if present; defaulted to the + * function ID for backwards compatibility + * @return a function name + */ + default public String getFunctionName() { + return getFunctionID(); + } + /** * Create an instance of the user specified class on which the target function to invoke is declared. * diff --git a/api/src/main/java/com/fnproject/fn/api/tracing/TracingContext.java b/api/src/main/java/com/fnproject/fn/api/tracing/TracingContext.java new file mode 100644 index 00000000..36ac377c --- /dev/null +++ b/api/src/main/java/com/fnproject/fn/api/tracing/TracingContext.java @@ -0,0 +1,101 @@ +package com.fnproject.fn.api.tracing; + +import com.fnproject.fn.api.InvocationContext; +import com.fnproject.fn.api.RuntimeContext; + +public interface TracingContext { + + /** + * Returns the underlying invocation context behind this Tracing context + * + * @return an invocation context related to this function + */ + InvocationContext getInvocationContext(); + + /** + * Returns the {@link RuntimeContext} associated with this invocation context + * + * @return a runtime context + */ + RuntimeContext getRuntimeContext(); + + /** + * Returns true if tracing is enabled for this function invocation + * + * @return whether tracing is enabled + */ + Boolean isTracingEnabled(); + + /** + * Returns the user-friendly name of the application associated with the + * function; shorthand for getRuntimeContext().getAppName() + * + * @return the user-friendly name of the application associated with the + * function + */ + String getAppName(); + + /** + * Returns the user-friendly name of the function; shorthand for + * getRuntimeContext().getFunctionName() + * + * @return the user-friendly name of the function + */ + String getFunctionName(); + + /** + * Returns a standard constructed "service name" to be used in tracing + * libraries to identify the function + * + * @return a standard constructed "service name" + */ + String getServiceName(); + + /** + * Returns the URL to be used in tracing libraries as the destination for + * the tracing data + * + * @return a string containing the trace collector URL + */ + String getTraceCollectorURL(); + + /** + * Returns the current trace ID as extracted from Zipkin B3 headers if they + * are present on the request + * + * @return the trace ID as a string + */ + String getTraceId(); + + /** + * Returns the current span ID as extracted from Zipkin B3 headers if they + * are present on the request + * + * @return the span ID as a string + */ + String getSpanId(); + + /** + * Returns the parent span ID as extracted from Zipkin B3 headers if they + * are present on the request + * + * @return the parent span ID as a string + */ + String getParentSpanId(); + + /** + * Returns the value of the Sampled header of the Zipkin B3 headers if they + * are present on the request + * + * @return true if sampling is enabled for the request + */ + Boolean isSampled(); + + /** + * Returns the value of the Flags header of the Zipkin B3 headers if they + * are present on the request + * + * @return the verbatim value of the X-B3-Flags header + */ + String getFlags(); +} diff --git a/runtime/src/main/java/com/fnproject/fn/runtime/EntryPoint.java b/runtime/src/main/java/com/fnproject/fn/runtime/EntryPoint.java index 7efa3497..418540a8 100644 --- a/runtime/src/main/java/com/fnproject/fn/runtime/EntryPoint.java +++ b/runtime/src/main/java/com/fnproject/fn/runtime/EntryPoint.java @@ -279,7 +279,7 @@ private void addExceptionToStringBuilder(StringBuilder sb, Throwable t) { * any headers that were added to env. Headers are identified as being variables prepended with 'HEADER_'. */ private Map excludeInternalConfigAndHeaders(Map env) { - Set nonConfigEnvKeys = new HashSet<>(Arrays.asList("fn_app_name", "fn_path", "fn_method", "fn_request_url", + Set nonConfigEnvKeys = new HashSet<>(Arrays.asList("fn_path", "fn_method", "fn_request_url", "fn_format", "content-length", "fn_call_id")); Map config = new HashMap<>(); for (Map.Entry entry : env.entrySet()) { diff --git a/runtime/src/main/java/com/fnproject/fn/runtime/FunctionRuntimeContext.java b/runtime/src/main/java/com/fnproject/fn/runtime/FunctionRuntimeContext.java index b86220e0..cdc5b313 100644 --- a/runtime/src/main/java/com/fnproject/fn/runtime/FunctionRuntimeContext.java +++ b/runtime/src/main/java/com/fnproject/fn/runtime/FunctionRuntimeContext.java @@ -61,6 +61,16 @@ public String getFunctionID() { return config.getOrDefault("FN_FN_ID", ""); } + @Override + public String getAppName() { + return config.getOrDefault("FN_APP_NAME", ""); + } + + @Override + public String getFunctionName() { + return config.getOrDefault("FN_FN_NAME", ""); + } + @Override public Optional getInvokeInstance() { if (!Modifier.isStatic(getMethod().getTargetMethod().getModifiers())) { diff --git a/runtime/src/main/java/com/fnproject/fn/runtime/coercion/ContextCoercion.java b/runtime/src/main/java/com/fnproject/fn/runtime/coercion/ContextCoercion.java index f4e22070..abd80b87 100644 --- a/runtime/src/main/java/com/fnproject/fn/runtime/coercion/ContextCoercion.java +++ b/runtime/src/main/java/com/fnproject/fn/runtime/coercion/ContextCoercion.java @@ -18,7 +18,9 @@ import com.fnproject.fn.api.*; import com.fnproject.fn.api.httpgateway.HTTPGatewayContext; +import com.fnproject.fn.api.tracing.TracingContext; import com.fnproject.fn.runtime.httpgateway.FunctionHTTPGatewayContext; +import com.fnproject.fn.runtime.tracing.OCITracingContext; import java.util.Optional; @@ -37,6 +39,8 @@ public Optional tryCoerceParam(InvocationContext currentContext, int arg return Optional.of(currentContext); } else if (paramClass.equals(HTTPGatewayContext.class)) { return Optional.of(new FunctionHTTPGatewayContext(currentContext)); + } else if (paramClass.equals(TracingContext.class)) { + return Optional.of(new OCITracingContext(currentContext, currentContext.getRuntimeContext())); } else { return Optional.empty(); } diff --git a/runtime/src/main/java/com/fnproject/fn/runtime/tracing/OCITracingContext.java b/runtime/src/main/java/com/fnproject/fn/runtime/tracing/OCITracingContext.java new file mode 100644 index 00000000..42ad1672 --- /dev/null +++ b/runtime/src/main/java/com/fnproject/fn/runtime/tracing/OCITracingContext.java @@ -0,0 +1,117 @@ +package com.fnproject.fn.runtime.tracing; + +import com.fnproject.fn.api.Headers; +import com.fnproject.fn.api.InvocationContext; +import com.fnproject.fn.api.RuntimeContext; +import com.fnproject.fn.api.tracing.TracingContext; + +public class OCITracingContext implements TracingContext { + private final InvocationContext invocationContext; + private final RuntimeContext runtimeContext; + private String traceCollectorURL; + private String traceId; + private String spanId; + private String parentSpanId; + private Boolean sampled = true; + private String flags; + private Boolean tracingEnabled; + private String appName; + private String fnName; + + public OCITracingContext(InvocationContext invocationContext, RuntimeContext runtimeContext) { + this.invocationContext = invocationContext; + this.runtimeContext = runtimeContext; + + configure(runtimeContext); + + if(tracingEnabled) + configure(invocationContext.getRequestHeaders()); + } + + private void configure(RuntimeContext runtimeContext) { + if(runtimeContext != null && runtimeContext.getConfigurationByKey("OCI_TRACE_COLLECTOR_URL").get() != null + && runtimeContext.getConfigurationByKey("OCI_TRACING_ENABLED").get() != null) { + this.traceCollectorURL = runtimeContext.getConfigurationByKey("OCI_TRACE_COLLECTOR_URL").get(); + try { + Integer tracingEnabledAsInt = Integer.parseInt(runtimeContext.getConfigurationByKey("OCI_TRACING_ENABLED").get()); + this.tracingEnabled = tracingEnabledAsInt != 0; + } catch(java.lang.NumberFormatException ex) { + this.tracingEnabled = false; + } + this.appName = runtimeContext.getAppName(); + this.fnName = runtimeContext.getFunctionName(); + } + } + + private void configure(Headers headers) { + this.flags = headers.get("x-b3-flags").orElse(""); + if (headers.get("x-b3-sampled").isPresent() && Integer.parseInt(headers.get("x-b3-sampled").get()) == 0) { + this.sampled = false; + return; + } + this.sampled = true; + this.traceId = headers.get("x-b3-traceid").orElse(""); + this.spanId = headers.get("x-b3-spanid").orElse(""); + this.parentSpanId = headers.get("x-b3-parentspanid").orElse(""); + } + + @Override + public InvocationContext getInvocationContext() { + return invocationContext; + } + + @Override + public RuntimeContext getRuntimeContext() { + return runtimeContext; + } + + @Override + public String getServiceName() { + return this.appName.toLowerCase() + "::" + this.fnName.toLowerCase(); + } + + @Override + public String getTraceCollectorURL() { + return traceCollectorURL; + } + + @Override + public String getTraceId() { + return traceId; + } + + @Override + public String getSpanId() { + return spanId; + } + + @Override + public String getParentSpanId() { + return parentSpanId; + } + + @Override + public Boolean isSampled() { + return sampled; + } + + @Override + public String getFlags() { + return flags; + } + + @Override + public Boolean isTracingEnabled() { + return tracingEnabled; + } + + @Override + public String getAppName() { + return appName; + } + + @Override + public String getFunctionName() { + return fnName; + } +} diff --git a/runtime/src/test/java/com/fnproject/fn/runtime/tracing/OCITracingContextTest.java b/runtime/src/test/java/com/fnproject/fn/runtime/tracing/OCITracingContextTest.java new file mode 100644 index 00000000..d964421b --- /dev/null +++ b/runtime/src/test/java/com/fnproject/fn/runtime/tracing/OCITracingContextTest.java @@ -0,0 +1,110 @@ +package com.fnproject.fn.runtime.tracing; + +import com.fnproject.fn.api.Headers; +import com.fnproject.fn.api.InvocationContext; +import com.fnproject.fn.api.MethodWrapper; +import com.fnproject.fn.runtime.FunctionRuntimeContext; +import org.junit.Rule; +import org.junit.Test; +import org.mockito.Mock; +import org.mockito.Mockito; +import org.mockito.junit.MockitoJUnit; +import org.mockito.junit.MockitoRule; + +import java.util.Collections; +import java.util.HashMap; +import java.util.Map; + +import static org.assertj.core.api.Assertions.assertThat; + +public class OCITracingContextTest { + + @Rule + public MockitoRule rule = MockitoJUnit.rule(); + + @Mock + InvocationContext ctxMock; + + @Mock + FunctionRuntimeContext runtimeContextMock; + + @Mock + MethodWrapper methodWrapperMock; + + private Map getConfig(Boolean enabled) { + Map env = new HashMap<>(); + env.put("FN_APP_NAME", "myapp"); + env.put("FN_FN_NAME", "myFunction"); + env.put("OCI_TRACE_COLLECTOR_URL", "tracingPath"); + env.put("OCI_TRACING_ENABLED", enabled ? "1" : "0"); + return Collections.unmodifiableMap(env); + } + + @Test + public void configureRuntimeContext() { + Map config = getConfig(false); + runtimeContextMock = new FunctionRuntimeContext(methodWrapperMock, config); + + OCITracingContext tracingContext = new OCITracingContext(ctxMock, runtimeContextMock); + assertThat(tracingContext.isTracingEnabled()).isEqualTo(false); + assertThat(tracingContext.getAppName()).isEqualToIgnoringCase("myapp"); + assertThat(tracingContext.getFunctionName()).isEqualToIgnoringCase("myFunction"); + assertThat(tracingContext.getTraceCollectorURL()).isEqualToIgnoringCase("tracingPath"); + } + + @Test + public void getServiceName() { + Map config = getConfig(false); + runtimeContextMock = new FunctionRuntimeContext(methodWrapperMock, config); + + OCITracingContext tracingContext = new OCITracingContext(ctxMock, runtimeContextMock); + assertThat(tracingContext.getServiceName()).isEqualToIgnoringCase("myapp::myFunction"); + } + + @Test + public void shouldAbleToConfigureWithNoHeaderData() { + Map config = getConfig(true); + runtimeContextMock = new FunctionRuntimeContext(methodWrapperMock, config); + Mockito.when(ctxMock.getRequestHeaders()).thenReturn(Headers.emptyHeaders()); + + OCITracingContext tracingContext = new OCITracingContext(ctxMock, runtimeContextMock); + assertThat(tracingContext.isSampled()).isEqualTo(true); + assertThat(tracingContext.getTraceId()).isEmpty(); + assertThat(tracingContext.getSpanId()).isEmpty(); + assertThat(tracingContext.getParentSpanId()).isEmpty(); + } + + @Test + public void shouldAbleToConfigureWithHeaderDataNotSampled() { + Map config = getConfig(true); + runtimeContextMock = new FunctionRuntimeContext(methodWrapperMock, config); + Map headerData = new HashMap(); + headerData.put("x-b3-sampled","0"); + Headers headers = Headers.fromMap(headerData); + Mockito.when(ctxMock.getRequestHeaders()).thenReturn(headers); + + OCITracingContext tracingContext = new OCITracingContext(ctxMock, runtimeContextMock); + assertThat(tracingContext.isSampled()).isEqualTo(false); + } + + @Test + public void shouldAbleToConfigureWithHeaderData() { + Map config = getConfig(true); + runtimeContextMock = new FunctionRuntimeContext(methodWrapperMock, config); + Map headerData = new HashMap(); + headerData.put("x-b3-sampled","1"); + headerData.put("x-b3-flags",""); + headerData.put("x-b3-traceid","213454321432"); + headerData.put("x-b3-spanid","244342r343"); + headerData.put("x-b3-parentspanid","32142r231242"); + Headers headers = Headers.fromMap(headerData); + Mockito.when(ctxMock.getRequestHeaders()).thenReturn(headers); + + OCITracingContext tracingContext = new OCITracingContext(ctxMock, runtimeContextMock); + assertThat(tracingContext.isSampled()).isEqualTo(true); + assertThat(tracingContext.getTraceId()).isEqualTo("213454321432"); + assertThat(tracingContext.getSpanId()).isEqualTo("244342r343"); + assertThat(tracingContext.getParentSpanId()).isEqualTo("32142r231242"); + assertThat(tracingContext.getFlags()).isEqualTo(""); + } +} From fb43a83dfa6c792dbdc07e7350733b9084b32f51 Mon Sep 17 00:00:00 2001 From: CI Date: Mon, 12 Apr 2021 14:59:10 +0000 Subject: [PATCH 222/310] fn-java-fdk: post-1.0.126 version bump [skip ci] --- release.version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/release.version b/release.version index 2e745396..840c6ce1 100644 --- a/release.version +++ b/release.version @@ -1 +1 @@ -1.0.126 +1.0.127 From 69a0822151a1ef624e7113078d7aeea0867b17ea Mon Sep 17 00:00:00 2001 From: Dario Domizioli Date: Tue, 13 Apr 2021 01:34:20 +0100 Subject: [PATCH 223/310] Dummy commit to force a master rebuild (#256) We need to force We need to force a rebuild of master after the Bintray brownout, but the update to release.version fails if we just retrigger a build (because the build retriggers with an older git commit than the one that is currently on master). So I'm creating a PR with a dummy commit to merge it and force a master rebuild.a rebuild of master after the Bintray brownout, but the update to release.version fails if we just retrigger a build (because the build retriggers with an older git commit than the one that is currently on master). So I'm creating a PR with a dummy commit to merge it and force a master rebuild. --- README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README.md b/README.md index de02a132..029f5628 100644 --- a/README.md +++ b/README.md @@ -22,3 +22,4 @@ For detailed instructions on using the FDK to build and deploy Java functions to ## Contributing to the Function Development Kit for Java Please see [CONTRIBUTING.md](CONTRIBUTING.md). + From 8bbc3f677a689fa4f2a614ed3031929acb6beddf Mon Sep 17 00:00:00 2001 From: CI Date: Tue, 13 Apr 2021 00:57:25 +0000 Subject: [PATCH 224/310] fn-java-fdk: post-1.0.127 version bump [skip ci] --- release.version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/release.version b/release.version index 840c6ce1..56559d31 100644 --- a/release.version +++ b/release.version @@ -1 +1 @@ -1.0.127 +1.0.128 From ce0b9b6364384de172258c2b3401b74b255e29b1 Mon Sep 17 00:00:00 2001 From: Rishabh Srivastav Date: Wed, 14 Apr 2021 18:34:02 +0530 Subject: [PATCH 225/310] Changes for enable and disable tracing --- .../fn/runtime/tracing/OCITracingContext.java | 19 +++++++++++-------- .../tracing/OCITracingContextTest.java | 6 +++--- 2 files changed, 14 insertions(+), 11 deletions(-) diff --git a/runtime/src/main/java/com/fnproject/fn/runtime/tracing/OCITracingContext.java b/runtime/src/main/java/com/fnproject/fn/runtime/tracing/OCITracingContext.java index 42ad1672..b2f9c71d 100644 --- a/runtime/src/main/java/com/fnproject/fn/runtime/tracing/OCITracingContext.java +++ b/runtime/src/main/java/com/fnproject/fn/runtime/tracing/OCITracingContext.java @@ -8,10 +8,10 @@ public class OCITracingContext implements TracingContext { private final InvocationContext invocationContext; private final RuntimeContext runtimeContext; - private String traceCollectorURL; - private String traceId; - private String spanId; - private String parentSpanId; + private String traceCollectorURL = "http://localhost:9411/api/v2/span"; + private String traceId="1"; + private String spanId="1"; + private String parentSpanId="1"; private Boolean sampled = true; private String flags; private Boolean tracingEnabled; @@ -31,7 +31,10 @@ public OCITracingContext(InvocationContext invocationContext, RuntimeContext run private void configure(RuntimeContext runtimeContext) { if(runtimeContext != null && runtimeContext.getConfigurationByKey("OCI_TRACE_COLLECTOR_URL").get() != null && runtimeContext.getConfigurationByKey("OCI_TRACING_ENABLED").get() != null) { - this.traceCollectorURL = runtimeContext.getConfigurationByKey("OCI_TRACE_COLLECTOR_URL").get(); + this.traceCollectorURL = + runtimeContext.getConfigurationByKey("OCI_TRACE_COLLECTOR_URL").get().isEmpty() + ?traceCollectorURL + :runtimeContext.getConfigurationByKey("OCI_TRACE_COLLECTOR_URL").get(); try { Integer tracingEnabledAsInt = Integer.parseInt(runtimeContext.getConfigurationByKey("OCI_TRACING_ENABLED").get()); this.tracingEnabled = tracingEnabledAsInt != 0; @@ -50,9 +53,9 @@ private void configure(Headers headers) { return; } this.sampled = true; - this.traceId = headers.get("x-b3-traceid").orElse(""); - this.spanId = headers.get("x-b3-spanid").orElse(""); - this.parentSpanId = headers.get("x-b3-parentspanid").orElse(""); + this.traceId = headers.get("x-b3-traceid").orElse("1"); + this.spanId = headers.get("x-b3-spanid").orElse("1"); + this.parentSpanId = headers.get("x-b3-parentspanid").orElse("1"); } @Override diff --git a/runtime/src/test/java/com/fnproject/fn/runtime/tracing/OCITracingContextTest.java b/runtime/src/test/java/com/fnproject/fn/runtime/tracing/OCITracingContextTest.java index d964421b..68c2712f 100644 --- a/runtime/src/test/java/com/fnproject/fn/runtime/tracing/OCITracingContextTest.java +++ b/runtime/src/test/java/com/fnproject/fn/runtime/tracing/OCITracingContextTest.java @@ -69,9 +69,9 @@ public void shouldAbleToConfigureWithNoHeaderData() { OCITracingContext tracingContext = new OCITracingContext(ctxMock, runtimeContextMock); assertThat(tracingContext.isSampled()).isEqualTo(true); - assertThat(tracingContext.getTraceId()).isEmpty(); - assertThat(tracingContext.getSpanId()).isEmpty(); - assertThat(tracingContext.getParentSpanId()).isEmpty(); + assertThat(tracingContext.getTraceId()).isEqualTo("1"); + assertThat(tracingContext.getSpanId()).isEqualTo("1"); + assertThat(tracingContext.getParentSpanId()).isEqualTo("1"); } @Test From a80f06b879098c0a6626a226d0770ca0f7cc98ef Mon Sep 17 00:00:00 2001 From: Rishabh Srivastav Date: Fri, 16 Apr 2021 10:33:21 +0530 Subject: [PATCH 226/310] As per the review comment constant strings has been added which can be used as a placeholder if data is not present. Changes has been implemented and tested --- .../fn/runtime/tracing/OCITracingContext.java | 27 +++++++++++++------ 1 file changed, 19 insertions(+), 8 deletions(-) diff --git a/runtime/src/main/java/com/fnproject/fn/runtime/tracing/OCITracingContext.java b/runtime/src/main/java/com/fnproject/fn/runtime/tracing/OCITracingContext.java index b2f9c71d..d4bf5226 100644 --- a/runtime/src/main/java/com/fnproject/fn/runtime/tracing/OCITracingContext.java +++ b/runtime/src/main/java/com/fnproject/fn/runtime/tracing/OCITracingContext.java @@ -8,32 +8,43 @@ public class OCITracingContext implements TracingContext { private final InvocationContext invocationContext; private final RuntimeContext runtimeContext; - private String traceCollectorURL = "http://localhost:9411/api/v2/span"; - private String traceId="1"; - private String spanId="1"; - private String parentSpanId="1"; + private String traceCollectorURL; + private String traceId; + private String spanId; + private String parentSpanId; private Boolean sampled = true; private String flags; private Boolean tracingEnabled; private String appName; private String fnName; + private static final String PLACEHOLDER_TRACE_COLLECTOR_URL = "http://localhost:9411/api/v2/span"; + private static final String PLACEHOLDER_TRACE_ID = "1"; + public OCITracingContext(InvocationContext invocationContext, RuntimeContext runtimeContext) { this.invocationContext = invocationContext; this.runtimeContext = runtimeContext; + configureDefaultValue(); configure(runtimeContext); if(tracingEnabled) configure(invocationContext.getRequestHeaders()); } + private void configureDefaultValue() { + this.traceCollectorURL = PLACEHOLDER_TRACE_COLLECTOR_URL; + this.traceId = PLACEHOLDER_TRACE_ID; + this.spanId = PLACEHOLDER_TRACE_ID; + this.parentSpanId = PLACEHOLDER_TRACE_ID; + } + private void configure(RuntimeContext runtimeContext) { if(runtimeContext != null && runtimeContext.getConfigurationByKey("OCI_TRACE_COLLECTOR_URL").get() != null && runtimeContext.getConfigurationByKey("OCI_TRACING_ENABLED").get() != null) { this.traceCollectorURL = runtimeContext.getConfigurationByKey("OCI_TRACE_COLLECTOR_URL").get().isEmpty() - ?traceCollectorURL + ?PLACEHOLDER_TRACE_COLLECTOR_URL :runtimeContext.getConfigurationByKey("OCI_TRACE_COLLECTOR_URL").get(); try { Integer tracingEnabledAsInt = Integer.parseInt(runtimeContext.getConfigurationByKey("OCI_TRACING_ENABLED").get()); @@ -53,9 +64,9 @@ private void configure(Headers headers) { return; } this.sampled = true; - this.traceId = headers.get("x-b3-traceid").orElse("1"); - this.spanId = headers.get("x-b3-spanid").orElse("1"); - this.parentSpanId = headers.get("x-b3-parentspanid").orElse("1"); + this.traceId = headers.get("x-b3-traceid").orElse(PLACEHOLDER_TRACE_ID); + this.spanId = headers.get("x-b3-spanid").orElse(PLACEHOLDER_TRACE_ID); + this.parentSpanId = headers.get("x-b3-parentspanid").orElse(PLACEHOLDER_TRACE_ID); } @Override From b939a782e64ee431912716941295adc769928bc3 Mon Sep 17 00:00:00 2001 From: Rishabh Srivastav <49639815+rishabhsri18@users.noreply.github.com> Date: Mon, 26 Apr 2021 15:18:29 +0530 Subject: [PATCH 227/310] Build failure, Version update required (#259) Co-authored-by: Rishabh Srivastav --- release.version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/release.version b/release.version index 56559d31..949ebc3f 100644 --- a/release.version +++ b/release.version @@ -1 +1 @@ -1.0.128 +1.0.129 From e2c15a27dd90522fa6111bf0bf49532bbfd8fe81 Mon Sep 17 00:00:00 2001 From: CI Date: Mon, 26 Apr 2021 10:37:54 +0000 Subject: [PATCH 228/310] fn-java-fdk: post-1.0.129 version bump [skip ci] --- release.version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/release.version b/release.version index 949ebc3f..9b86951c 100644 --- a/release.version +++ b/release.version @@ -1 +1 @@ -1.0.129 +1.0.130 From 45b6a99c2aa0bcbafabc628e7fa55f2740d69ec9 Mon Sep 17 00:00:00 2001 From: Roneet Shaw Date: Tue, 27 Apr 2021 09:02:19 +0530 Subject: [PATCH 229/310] Maven central update (#258) * Roneet | changing groupid to io * Updated config.yml * Updated config.yml * Updated config.yml * Updated config.yml * Updated config.yml * Roneet | version change * Updated config.yml * Updated config.yml * Roneet | circleci maven central deployment changes * Roneet | CircleCI changes for io.fnproject.fn * Roneet | load user maven settings * Roneet | maven settings fix * Roneet | com.fnproject.fn changes * Roneet | update pom.xml version * Roneet | update pom.xml version * Roneet | migration script changes * Roneet | global maven setting.xml changes * Roneet | CircleCI fix * Roneet | CircleCI fix * Roneet | CircleCI fix * Roneet | 128 release * fn-java-fdk: post-1.0.128 version bump [skip ci] * Roneet | 128 release * Roneet | 128 release * Roneet | 128 release * Roneet | 128 release * fn-java-fdk: post-1.0.128 version bump [skip ci] * Roneet | 128 release * Roneet | 128 release * fn-java-fdk: post-1.0.128 version bump [skip ci] * Roneet | CircleCI build fix * Roneet | version file removal * Roneet | conditional release to Maven * Roneet | build fix * Roneet | build fix * Roneet | build fix Co-authored-by: CI --- .circleci/config.yml | 10 +- .circleci/maven-settings.xml | 17 +- .circleci/release.sh | 9 +- bin/scripts/migration/flag | 1 + .../migration/migrate_to_maven_central.sh | 393 ++++++++++++++++++ examples/string-reverse/pom.xml | 13 - experimental-native-image-support/pom.xml | 17 + flow-runtime/pom.xml | 12 + .../fn/runtime/flow/CompleterClient.java | 8 +- .../fn/runtime/flow/FlowFeature.java | 2 +- .../fn/runtime/flow/FlowRuntimeGlobals.java | 2 +- flow-testing/pom.xml | 2 +- fn-spring-cloud-function/pom.xml | 17 + .../function/SpringCloudFunctionLoader.java | 2 +- .../function/functions/SpringCloudMethod.java | 4 +- images/build/cache-deps.sh | 2 +- pom.xml | 77 +++- runtime/pom.xml | 12 + testing-core/pom.xml | 20 +- testing-junit4/pom.xml | 19 +- 20 files changed, 603 insertions(+), 36 deletions(-) create mode 100644 bin/scripts/migration/flag create mode 100644 bin/scripts/migration/migrate_to_maven_central.sh diff --git a/.circleci/config.yml b/.circleci/config.yml index 3251a19c..79b62cc6 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -13,8 +13,14 @@ jobs: steps: - checkout - run: - name: Update Docker to latest - command: ./.circleci/install-docker.sh + name: Update Docker to latest + command: ./.circleci/install-docker.sh + - run: + name: Import GPG Owner Trust + command: echo $GPG_OWNERTRUST | base64 --decode | gpg --import-ownertrust + - run: + name: Import GPG key + command: echo $GPG_SECRET_KEYS | base64 --decode | gpg --import --no-tty --batch --yes - run: name: Install fn binary (as it is needed for the integration tests) command: ./.circleci/install-fn.sh diff --git a/.circleci/maven-settings.xml b/.circleci/maven-settings.xml index b4945cf2..4a004862 100644 --- a/.circleci/maven-settings.xml +++ b/.circleci/maven-settings.xml @@ -9,6 +9,11 @@ + + ossrh + ${env.SERVER_OSSRH_USERNAME} + ${env.SERVER_OSSRH_PASSWORD} + @@ -30,6 +35,16 @@ -Djdk.net.URLClassPath.disableClassPathURLCheck=true - + + + ossrh + + true + + + gpg + ${env.GPG_PASSPHRASE} + + \ No newline at end of file diff --git a/.circleci/release.sh b/.circleci/release.sh index bd4a9a07..61c33d82 100755 --- a/.circleci/release.sh +++ b/.circleci/release.sh @@ -111,10 +111,5 @@ git push origin "$release_version" ) -# Deploy to bintray -mvn -s ./settings-deploy.xml \ - -DskipTests \ - -DaltDeploymentRepository="fnproject-release-repo::default::${MVN_RELEASE_REPO}" \ - -Dfnproject-release-repo.username="${MVN_RELEASE_USER}" \ - -Dfnproject-release-repo.password="${MVN_RELEASE_PASSWORD}" \ - clean deploy +# Deploy to Maven Central OSSRH +mvn -DskipTests clean deploy -Pci-cd -Dauto.release=true diff --git a/bin/scripts/migration/flag b/bin/scripts/migration/flag new file mode 100644 index 00000000..4a3b60a2 --- /dev/null +++ b/bin/scripts/migration/flag @@ -0,0 +1 @@ +0 0 \ No newline at end of file diff --git a/bin/scripts/migration/migrate_to_maven_central.sh b/bin/scripts/migration/migrate_to_maven_central.sh new file mode 100644 index 00000000..3a015295 --- /dev/null +++ b/bin/scripts/migration/migrate_to_maven_central.sh @@ -0,0 +1,393 @@ +#!/bin/bash + +set -euo pipefail + +destdir=flag +POM_PLACEHOLDER=".*>" +POM_REPLACEMENT="4.0.0 + + + The Apache License, Version 2.0 + http://www.apache.org/licenses/LICENSE-2.0.txt + + + + oracle + https://www.oracle.com/ + + + + fnproject/core + roneet.shaw@oracle.com + oracle + https://www.oracle.com/ + + + + scm:git:git://github.com/fnproject/fdk-java.git + scm:git:ssh://github.com:fnproject/fdk-java.git + https://github.com/fnproject/fdk-java + + + + ossrh + https://s01.oss.sonatype.org/service/local/staging/deploy/maven2/ + + + ossrh + https://s01.oss.sonatype.org/content/repositories/snapshots + + + fdk-java + The Function Development Kit for Java makes it easy to build and deploy Java functions to Fn + https://fnproject.io/tutorials/JavaFDKIntroduction/ + " + +# Constants +MAVEN_CENTRAL_STAGINGURL="https://s01.oss.sonatype.org/service/local/staging/deploy/maven2" +MAVEN_CENTRAL_REPOID="ossrh" +OUTPUT_DIR="output" + +# TODO: add versions e.g. (1.0.0 1.0.1 1.0.2) 10*1+ 5+2+1 + +VERSIONS=(1.0.107 1.0.106 1.0.105 1.0.104 1.0.103 1.0.102 1.0.101 1.0.100 1.0.99 1.0.98 1.0.97 1.0.96 1.0.95 1.0.94 1.0.93 1.0.92 1.0.91 1.0.90 1.0.89 1.0.88) + +#VERSIONS=(1.0.127 1.0.87 1.0.86 1.0.85 1.0.84 1.0.83 1.0.82 1.0.81 1.0.80 1.0.79 1.0.78 1.0.77 1.0.76 1.0.75 1.0.74 1.0.72 1.0.71 1.0.70 1.0.64 1.0.63 1.0.62 1.0.61 1.0.60 1.0.59 1.0.58 1.0.57 1.0.56 1.0.55 1.0.54 1.0.53 1.0.52 1.0.51 1.0.50 1.0.49 1.0.48 1.0.47 1.0.46 1.0.45 1.0.44 1.0.43 1.0.42 1.0.41 1.0.40 1.0.39 1.0.38 1.0.37 1.0.36 1.0.35 1.0.34 1.0.33 1.0.32 1.0.31 1.0.30 1.0.29 1.0.28 1.0.27 1.0.26 1.0.25 1.0.24 1.0.23 1.0.22 1.0.21 1.0.20 1.0.19 1.0.18 1.0.17 1.0.16 1.0.15 1.0.14 1.0.13 1.0.11 1.0.10 1.0.9 1.0.8 1.0.7 1.0.6 1.0.5 1.0.4 1.0.3 1.0.2 1.0.1) + +#VERSIONS=(1.0.127 1.0.125 1.0.124 1.0.123 1.0.122 1.0.121 1.0.120 1.0.119 1.0.118 1.0.117 1.0.116 1.0.115 1.0.114 1.0.113 1.0.112 1.0.111 1.0.110 1.0.109 1.0.108 1.0.107 1.0.106 1.0.105 1.0.104 1.0.103 1.0.102 1.0.101 1.0.100 1.0.99 1.0.98 1.0.97 1.0.96 1.0.95 1.0.94 1.0.93 1.0.92 1.0.91 1.0.90 1.0.89 1.0.88 1.0.87 1.0.86 1.0.85 1.0.84 1.0.83 1.0.82 1.0.81 1.0.80 1.0.79 1.0.78 1.0.77 1.0.76 1.0.75 1.0.74 1.0.72 1.0.71 1.0.70 1.0.64 1.0.63 1.0.62 1.0.61 1.0.60 1.0.59 1.0.58 1.0.57 1.0.56 1.0.55 1.0.54 1.0.53 1.0.52 1.0.51 1.0.50 1.0.49 1.0.48 1.0.47 1.0.46 1.0.45 1.0.44 1.0.43 1.0.42 1.0.41 1.0.40 1.0.39 1.0.38 1.0.37 1.0.36 1.0.35 1.0.34 1.0.33 1.0.32 1.0.31 1.0.30 1.0.29 1.0.28 1.0.27 1.0.26 1.0.25 1.0.24 1.0.23 1.0.22 1.0.21 1.0.20 1.0.19 1.0.18 1.0.17 1.0.16 1.0.15 1.0.14 1.0.13 1.0.11 1.0.10 1.0.9 1.0.8 1.0.7 1.0.6 1.0.5 1.0.4 1.0.3 1.0.2 1.0.1 1.0.0) + +# TODO: https://dl.bintray.com//// +BINTRAYURL="http://dl.bintray.com/fnproject/fnproject/com/fnproject/fn/" + +#IFS=$' ' read -d '' -r -a START_VER < $destdir + +IFS=$' ' GLOBIGNORE='*' command eval 'START_VER=($(cat flag))' + +# TODO : add artifact Id +ARTIFACT_IDs=(fdk api experimental-native-image-support flow-api flow-runtime flow-testing fn-spring-cloud-function jrestless-handler runtime testing-core testing-junit4 testing) +#ARTIFACT_IDs=(fdk api ) + + +#parameters $1: url to test +function ping_url() { + status_code=$(curl --head --write-out '%{http_code}\n' --silent --output /dev/null $1) + echo $status_code +} + +# Utilities +function escape_pom() { + echo "$1" | sed 's#/#\\/#g' | tr '\n' '@' +} + +function xml_encode() { + echo $1 | sed 's/&/\&/g; s//\>/g; s/"/\"/g; s/'"'"'/\'/g' +} + +#parameters $1: artifact_id, $2: version +function download_and_save(){ + #copy javadoc + + if [ $( ping_url $BINTRAYURL/$1/$2/$1-$2-javadoc.jar ) == 200 ] + then + mkdir -p $OUTPUT_DIR/$1/$2 + curl -L $BINTRAYURL/$1/$2/$1-$2-javadoc.jar \ + -o $OUTPUT_DIR/$1/$2/$1-$2-javadoc.jar + fi + + if [ $( ping_url $BINTRAYURL/$1/$2/$1-$2-javadoc.jar.md5 ) == 200 ] + then + mkdir -p $OUTPUT_DIR/$1/$2 + curl -L $BINTRAYURL/$1/$2/$1-$2-javadoc.jar.md5 \ + -o $OUTPUT_DIR/$1/$2/$1-$2-javadoc.jar.md5 + fi + + #copy sources + if [ $( ping_url $BINTRAYURL/$1/$2/$1-$2-sources.jar ) == 200 ] + then + mkdir -p $OUTPUT_DIR/$1/$2 + curl -L $BINTRAYURL/$1/$2/$1-$2-sources.jar \ + -o $OUTPUT_DIR/$1/$2/$1-$2-sources.jar + fi + + if [ $( ping_url $BINTRAYURL/$1/$2/$1-$2-sources.jar.md5 ) == 200 ] + then + mkdir -p $OUTPUT_DIR/$1/$2 + curl -L $BINTRAYURL/$1/$2/$1-$2-sources.jar.md5 \ + -o $OUTPUT_DIR/$1/$2/$1-$2-sources.jar.md5 + fi + + #copy jar + if [ $( ping_url $BINTRAYURL/$1/$2/$1-$2.jar ) == 200 ] + then + mkdir -p $OUTPUT_DIR/$1/$2 + curl -L $BINTRAYURL/$1/$2/$1-$2.jar \ + -o $OUTPUT_DIR/$1/$2/$1-$2.jar + fi + + if [ $( ping_url $BINTRAYURL/$1/$2/$1-$2.jar.md5 ) == 200 ] + then + mkdir -p $OUTPUT_DIR/$1/$2 + curl -L $BINTRAYURL/$1/$2/$1-$2.jar.md5 \ + -o $OUTPUT_DIR/$1/$2/$1-$2.jar.md5 + fi + + #copy pom + if [ $( ping_url $BINTRAYURL/$1/$2/$1-$2.pom ) == 200 ] + then + mkdir -p $OUTPUT_DIR/$1/$2 + curl -L $BINTRAYURL/$1/$2/$1-$2.pom \ + -o $OUTPUT_DIR/$1/$2/$1-$2.pom + fi + + if [ $( ping_url $BINTRAYURL/$1/$2/$1-$2.pom.md5 ) == 200 ] + then + mkdir -p $OUTPUT_DIR/$1/$2 + curl -L $BINTRAYURL/$1/$2/$1-$2.pom.md5 \ + -o $OUTPUT_DIR/$1/$2/$1-$2.pom.md5 + fi + +} + +function save_flag() { + echo "$1 $2" > "$destdir" +} + +function download_all_versions(){ + for (( i=${START_VER[0]}; i<${#ARTIFACT_IDs[@]}; i++ )); do + for (( j=${START_VER[1]}; j<${#VERSIONS[@]}; j++ )); do + aid=${ARTIFACT_IDs[$i]} + ver=${VERSIONS[$j]} + + echo "Downloading version $ver $aid" + download_and_save $aid $ver + save_flag $i $j + done + START_VER[1]=0 + done +} + +function prepare_pom() { + echo "Preparing $1" + EXAMPLE_MODULE="examples<\/module>" + EXP_MODULE="integration-tests<\/module>" + NEW=" " + PLUGINS="" + SCM_PLUGIN=" + + + org.sonatype.plugins + nexus-staging-maven-plugin + 1.6.7 + true + + ossrh + https://s01.oss.sonatype.org/ + true + + + " + for (( i=${START_VER[0]}; i<${#ARTIFACT_IDs[@]}; i++ )); do + for (( j=${START_VER[1]}; j<${#VERSIONS[@]}; j++ )); do + aid=${ARTIFACT_IDs[$i]} + ver=${VERSIONS[$j]} + + echo $aid $ver + #if [ $ver = $2 ]; then + pom=$OUTPUT_DIR/$aid/$ver/$aid-$ver.pom + if [ -f "$pom" ]; then + if [ $aid = "fdk" ]; then + newPom=$1/$aid/$ver/pom.xml + mkdir -p $1/$aid/$ver + sed -e "s/$POM_PLACEHOLDER/$(escape_pom "$POM_REPLACEMENT")/g; s/$EXAMPLE_MODULE/$NEW/g; s/$EXP_MODULE/$NEW/g; s/$PLUGINS/$(escape_pom "$SCM_PLUGIN")/1;" \ + $pom |\ + tr '@' '\n' > temp.txt + mv temp.txt $newPom + else + newPom=$1/fdk/$ver/$aid/pom.xml + mkdir -p $1/fdk/$ver/$aid + + #Copy pom + cp $pom $1/fdk/$ver/$aid/ + mv $1/fdk/$ver/$aid/$aid-$ver.pom $newPom + fi + fi + #fi + done + done + +} + + +function modify_group_id() { + echo "Changing $1" + OLD_GROUP_ID="com.fnproject.fn<\/groupId>" + NEW_GROUP_ID="$1" + EXAMPLE_MODULE="examples<\/module>" + EXP_MODULE="integration-tests<\/module>" + NEW=" " + + PLUGINS="" + SCM_PLUGIN=" + + + org.sonatype.plugins + nexus-staging-maven-plugin + 1.6.7 + true + + ossrh + https://s01.oss.sonatype.org/ + true + + + " + for (( i=${START_VER[0]}; i<${#ARTIFACT_IDs[@]}; i++ )); do + for (( j=${START_VER[1]}; j<${#VERSIONS[@]}; j++ )); do + aid=${ARTIFACT_IDs[$i]} + ver=${VERSIONS[$j]} + + echo $aid $ver + if [ $ver = $2 ]; then + pom=$OUTPUT_DIR/$aid/$ver/$aid-$ver.pom + if [ -f "$pom" ]; then + if [ $aid = "fdk" ]; then + newPom=$1/$aid/$ver/pom.xml + mkdir -p $1/$aid/$ver + sed -e "s/$OLD_GROUP_ID/$(escape_pom "$NEW_GROUP_ID")/g; s/$POM_PLACEHOLDER/$(escape_pom "$POM_REPLACEMENT")/g; s/$EXAMPLE_MODULE/$NEW/g; s/$EXP_MODULE/$NEW/g; s/$PLUGINS/$(escape_pom "$SCM_PLUGIN")/1;" \ + $pom |\ + tr '@' '\n' > temp.txt + mv temp.txt $newPom + else + newPom=$1/fdk/$ver/$aid/pom.xml + mkdir -p $1/fdk/$ver/$aid + sed -e "s/$OLD_GROUP_ID/$(escape_pom "$NEW_GROUP_ID")/g" \ + $pom |\ + tr '@' '\n' > temp.txt + mv temp.txt $newPom + fi + fi + fi + done + done + +} + +function deploy() { + for (( i=${START_VER[0]}; i<${#ARTIFACT_IDs[@]}; i++ )); do + for (( j=${START_VER[1]}; j<${#VERSIONS[@]}; j++ )); do + aid=${ARTIFACT_IDs[$i]} + ver=${VERSIONS[$j]} + + #if [ $ver = $2 ]; then + # Add required metadata to pom.xml + if [ $aid = "fdk" ]; then + pom=$1/$aid/$ver/pom.xml + if [ -f "$pom" ]; then + echo "pom maven fdk" + echo $pom + mvn -s ./user-settings.xml gpg:sign-and-deploy-file \ + -Durl=$MAVEN_CENTRAL_STAGINGURL \ + -DrepositoryId=$MAVEN_CENTRAL_REPOID \ + -DpomFile=$pom \ + -Dfile=$pom + fi + else + pom=$1/fdk/$ver/$aid/pom.xml + if [ -f "$pom" ]; then + echo "pom maven other" + mvn -s ./user-settings.xml gpg:sign-and-deploy-file \ + -Durl=$MAVEN_CENTRAL_STAGINGURL \ + -DrepositoryId=$MAVEN_CENTRAL_REPOID \ + -DpomFile=$pom \ + -Dfile=$pom + fi + echo "Singing jar" + echo $pom + + #sign jar files + if [ -f "$pom" ] && [ -f $OUTPUT_DIR/$aid/$ver/$aid-$ver.jar ]; then + echo "After jar inside if" + echo $pom + mvn -s ./user-settings.xml gpg:sign-and-deploy-file \ + -Durl=$MAVEN_CENTRAL_STAGINGURL \ + -DrepositoryId=$MAVEN_CENTRAL_REPOID \ + -DpomFile=$pom \ + -Dfile=$OUTPUT_DIR/$aid/$ver/$aid-$ver.jar + fi + + echo "Singing sources" + echo $pom + #Sign sources.jar + if [ -f "$pom" ] && [ -f $OUTPUT_DIR/$aid/$ver/$aid-$ver-sources.jar ]; then + echo "sources" + mvn -s ./user-settings.xml gpg:sign-and-deploy-file \ + -Durl=$MAVEN_CENTRAL_STAGINGURL \ + -DrepositoryId=$MAVEN_CENTRAL_REPOID \ + -DpomFile=$pom \ + -Dfile=$OUTPUT_DIR/$aid/$ver/$aid-$ver-sources.jar \ + -Dclassifier=sources + elif [ -d $OUTPUT_DIR/$aid/$ver ] && [ $aid != "fdk" ]; then + if [ -f fallback/$aid-sources.jar ]; then + echo "Fallback sourcess" + echo $OUTPUT_DIR/$aid/$ver + cp fallback/$aid-sources.jar $1/fdk/$ver/$aid/ + mv $1/fdk/$ver/$aid/$aid-sources.jar $1/fdk/$ver/$aid/$aid-$ver-sources.jar + mvn -s ./user-settings.xml gpg:sign-and-deploy-file \ + -Durl=$MAVEN_CENTRAL_STAGINGURL \ + -DrepositoryId=$MAVEN_CENTRAL_REPOID \ + -DpomFile=$pom \ + -Dfile=$1/fdk/$ver/$aid/$aid-$ver-sources.jar \ + -Dclassifier=sources + fi + fi + echo "Singing Javadocs" + echo $pom + + #sign javadoc.jar + if [ -f "$pom" ] && [ -f $OUTPUT_DIR/$aid/$ver/$aid-$ver-javadoc.jar ]; then + echo "javadocs" + mvn -s ./user-settings.xml gpg:sign-and-deploy-file \ + -Durl=$MAVEN_CENTRAL_STAGINGURL \ + -DrepositoryId=$MAVEN_CENTRAL_REPOID \ + -DpomFile=$pom \ + -Dfile=$OUTPUT_DIR/$aid/$ver/$aid-$ver-javadoc.jar \ + -Dclassifier=javadoc + elif [ -d $OUTPUT_DIR/$aid/$ver ] && [ $aid != "fdk" ]; then + if [ -f fallback/$aid-javadoc.jar ]; then + echo "Fallback javadocs2" + echo $OUTPUT_DIR/$aid/$ver + cp fallback/$aid-javadoc.jar $1/fdk/$ver/$aid/ + mv $1/fdk/$ver/$aid/$aid-javadoc.jar $1/fdk/$ver/$aid/$aid-$ver-javadoc.jar + mvn -s ./user-settings.xml gpg:sign-and-deploy-file \ + -Durl=$MAVEN_CENTRAL_STAGINGURL \ + -DrepositoryId=$MAVEN_CENTRAL_REPOID \ + -DpomFile=$pom \ + -Dfile=$1/fdk/$ver/$aid/$aid-$ver-javadoc.jar \ + -Dclassifier=javadoc + fi + fi + fi + #fi + #save_flag $i $j + done + START_VER[1]=0 + done +} + +#main +#Script execution will start from here +if [[ $1 = "-d" ]]; then + echo "Downloading fdk-java version from Bintray" + download_all_versions + save_flag $i $j +elif [[ $1 = "-c" ]]; then + echo "Changing groupId to $2" + modify_group_id $2 $3 + deploy $2 $3 +else + echo "Sign and Deploy to Maven Central" + echo $1 + prepare_pom $1 + deploy $1 +fi +exit 0 diff --git a/examples/string-reverse/pom.xml b/examples/string-reverse/pom.xml index 2b571930..92c5eff7 100644 --- a/examples/string-reverse/pom.xml +++ b/examples/string-reverse/pom.xml @@ -29,19 +29,6 @@ string-reverse 1.0.0 - - - fn-release-repo - https://dl.bintray.com/fnproject/fnproject - - true - - - false - - - - com.fnproject.fn diff --git a/experimental-native-image-support/pom.xml b/experimental-native-image-support/pom.xml index b9acd970..61334781 100644 --- a/experimental-native-image-support/pom.xml +++ b/experimental-native-image-support/pom.xml @@ -60,4 +60,21 @@ + + + + org.apache.maven.plugins + maven-javadoc-plugin + + + attach-javadocs + + jar + + + + + + + diff --git a/flow-runtime/pom.xml b/flow-runtime/pom.xml index 73a64d00..f9c6577e 100644 --- a/flow-runtime/pom.xml +++ b/flow-runtime/pom.xml @@ -89,6 +89,18 @@ + + org.apache.maven.plugins + maven-javadoc-plugin + + + attach-javadocs + + jar + + + + diff --git a/flow-runtime/src/main/java/com/fnproject/fn/runtime/flow/CompleterClient.java b/flow-runtime/src/main/java/com/fnproject/fn/runtime/flow/CompleterClient.java index 4224cbf8..235115a0 100644 --- a/flow-runtime/src/main/java/com/fnproject/fn/runtime/flow/CompleterClient.java +++ b/flow-runtime/src/main/java/com/fnproject/fn/runtime/flow/CompleterClient.java @@ -32,8 +32,8 @@ public interface CompleterClient { /** * create a new flow against the flow service * - * @param functionId - * @return + * @param functionId Id of the function for which flow needs to be created + * @return a FlowId */ FlowId createFlow(String functionId); @@ -49,6 +49,10 @@ public interface CompleterClient { * Compose a function into the tree * The transmitted function is wrapped to convert th ElvisFuture into it's completion iD * + * @param flowId flowId for thenCompose + * @param completionId completionId for thenCompose + * @param fn fn for thenCompose + * @param codeLocation codeLocation for thenCompose * @return a completion ID that completes when the completion returned by the inner function completes */ CompletionId thenCompose(FlowId flowId, CompletionId completionId, Serializable fn, CodeLocation codeLocation); diff --git a/flow-runtime/src/main/java/com/fnproject/fn/runtime/flow/FlowFeature.java b/flow-runtime/src/main/java/com/fnproject/fn/runtime/flow/FlowFeature.java index 10118c1c..42df40c7 100644 --- a/flow-runtime/src/main/java/com/fnproject/fn/runtime/flow/FlowFeature.java +++ b/flow-runtime/src/main/java/com/fnproject/fn/runtime/flow/FlowFeature.java @@ -29,7 +29,7 @@ * import com.fnproject.fn.api.FnFeature; * import com.fnproject.fn.runtime.flow.FlowFeature; * - * @FnFeature(FlowFeature.class) + * {@literal @}FnFeature(FlowFeature.class) * public class MyFunction { * * diff --git a/flow-runtime/src/main/java/com/fnproject/fn/runtime/flow/FlowRuntimeGlobals.java b/flow-runtime/src/main/java/com/fnproject/fn/runtime/flow/FlowRuntimeGlobals.java index b341c26c..405af273 100644 --- a/flow-runtime/src/main/java/com/fnproject/fn/runtime/flow/FlowRuntimeGlobals.java +++ b/flow-runtime/src/main/java/com/fnproject/fn/runtime/flow/FlowRuntimeGlobals.java @@ -80,7 +80,7 @@ public static void setCompleterClientFactory(CompleterClientFactory currentClien /** * return the current Fn Flow client factory; * - * @return + * @return a factory of CompleterClient */ public static CompleterClientFactory getCompleterClientFactory() { return completerClientFactory; diff --git a/flow-testing/pom.xml b/flow-testing/pom.xml index e6cede00..07abef8b 100644 --- a/flow-testing/pom.xml +++ b/flow-testing/pom.xml @@ -79,7 +79,7 @@ - + diff --git a/fn-spring-cloud-function/pom.xml b/fn-spring-cloud-function/pom.xml index f81ae91b..cf7cddfa 100644 --- a/fn-spring-cloud-function/pom.xml +++ b/fn-spring-cloud-function/pom.xml @@ -119,4 +119,21 @@ + + + + org.apache.maven.plugins + maven-javadoc-plugin + + + attach-javadocs + + jar + + + + + + + diff --git a/fn-spring-cloud-function/src/main/java/com/fnproject/springframework/function/SpringCloudFunctionLoader.java b/fn-spring-cloud-function/src/main/java/com/fnproject/springframework/function/SpringCloudFunctionLoader.java index e064934a..84663d94 100644 --- a/fn-spring-cloud-function/src/main/java/com/fnproject/springframework/function/SpringCloudFunctionLoader.java +++ b/fn-spring-cloud-function/src/main/java/com/fnproject/springframework/function/SpringCloudFunctionLoader.java @@ -34,7 +34,7 @@ * The Loader for Spring Cloud Functions *

    * Looks up Functions from the {@link FunctionCatalog} (which is likely populated by your - * function class, see {@link SpringCloudFunctionInvoker#SpringCloudFunctionInvoker(Class)}) + * function class, see {@link SpringCloudFunctionInvoker#SpringCloudFunctionInvoker(SpringCloudFunctionLoader)}) *

    * Lookup is in the following order: *

    diff --git a/fn-spring-cloud-function/src/main/java/com/fnproject/springframework/function/functions/SpringCloudMethod.java b/fn-spring-cloud-function/src/main/java/com/fnproject/springframework/function/functions/SpringCloudMethod.java index c9a5f483..b1ef8867 100644 --- a/fn-spring-cloud-function/src/main/java/com/fnproject/springframework/function/functions/SpringCloudMethod.java +++ b/fn-spring-cloud-function/src/main/java/com/fnproject/springframework/function/functions/SpringCloudMethod.java @@ -84,8 +84,8 @@ public TypeWrapper getReturnType() { /** * Invoke the target function object * - * @param arg - * @return + * @param arg fuction invoke arguments + * @return Flux type object */ public abstract Flux invoke(Flux arg); } diff --git a/images/build/cache-deps.sh b/images/build/cache-deps.sh index d82473db..47a1c32b 100755 --- a/images/build/cache-deps.sh +++ b/images/build/cache-deps.sh @@ -24,5 +24,5 @@ if [ -n "$FN_REPO_URL" ]; then fi sed -i "s#___FN_REPO_URL___#${FN_REPO_URL}#g" /tmp/cache-deps/local-settings.xml -cd /tmp/cache-deps && mvn -s /tmp/cache-deps/local-settings.xml test package dependency:copy-dependencies -Dmaven.repo.local=/usr/share/maven/ref/repository -Dmdep.prependGroupId=true -DoutputDirectory=target $REPO_DFN +cd /tmp/cache-deps && mvn -s /tmp/cache-deps/local-settings.xml test package dependency:copy-dependencies -Dmdep.prependGroupId=true -DoutputDirectory=target $REPO_DFN cd / && rm -fr /tmp/cache-deps diff --git a/pom.xml b/pom.xml index 7dca993f..ac4dbddc 100644 --- a/pom.xml +++ b/pom.xml @@ -26,7 +26,42 @@ com.fnproject.fn pom 1.0.0-SNAPSHOT + fdk-java + The Function Development Kit for Java makes it easy to build and deploy Java functions to Fn + https://fnproject.io/tutorials/JavaFDKIntroduction/ + + + The Apache License, Version 2.0 + http://www.apache.org/licenses/LICENSE-2.0.txt + + + + + + fnproject/core + roneet.shaw@oracle.com + oracle + https://www.oracle.com/ + + + + + scm:git:git://github.com/fnproject/fdk-java.git + scm:git:ssh://github.com:fnproject/fdk-java.git + https://github.com/fnproject/fdk-java + + + + + ossrh + https://s01.oss.sonatype.org/service/local/staging/deploy/maven2/ + + + ossrh + https://s01.oss.sonatype.org/content/repositories/snapshots + + api @@ -59,6 +94,7 @@ 2.22.1 1.16.0 21.0.0.2 + false @@ -164,6 +200,14 @@ org.apache.maven.plugins maven-javadoc-plugin 3.0.1 + + + attach-javadocs + + jar + + + org.apache.maven.plugins @@ -293,7 +337,6 @@ pitest-maven ${pitest.version} - @@ -321,5 +364,37 @@ + + ci-cd + + + + org.apache.maven.plugins + maven-gpg-plugin + 1.6 + + + sign-artifacts + verify + + sign + + + + + + org.sonatype.plugins + nexus-staging-maven-plugin + 1.6.7 + true + + ossrh + https://s01.oss.sonatype.org/ + ${auto.release} + + + + + diff --git a/runtime/pom.xml b/runtime/pom.xml index 77130bf2..0aca8f27 100644 --- a/runtime/pom.xml +++ b/runtime/pom.xml @@ -143,6 +143,18 @@ + + org.apache.maven.plugins + maven-javadoc-plugin + + + attach-javadocs + + jar + + + + diff --git a/testing-core/pom.xml b/testing-core/pom.xml index 277c25c0..d88d989d 100644 --- a/testing-core/pom.xml +++ b/testing-core/pom.xml @@ -36,5 +36,21 @@ - - \ No newline at end of file + + + + org.apache.maven.plugins + maven-javadoc-plugin + + + attach-javadocs + + jar + + + + + + + + diff --git a/testing-junit4/pom.xml b/testing-junit4/pom.xml index c55e5d08..12554a1a 100644 --- a/testing-junit4/pom.xml +++ b/testing-junit4/pom.xml @@ -51,4 +51,21 @@ - \ No newline at end of file + + + + org.apache.maven.plugins + maven-javadoc-plugin + + + attach-javadocs + + jar + + + + + + + + From 6d6ef1f0f80db1045c930fa61656e5d568993006 Mon Sep 17 00:00:00 2001 From: CI Date: Tue, 27 Apr 2021 03:55:11 +0000 Subject: [PATCH 230/310] fn-java-fdk: post-1.0.130 version bump [skip ci] --- release.version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/release.version b/release.version index 9b86951c..8fa58783 100644 --- a/release.version +++ b/release.version @@ -1 +1 @@ -1.0.130 +1.0.131 From 5ee81a44f8beabb9827b8c17b57df038c078f50d Mon Sep 17 00:00:00 2001 From: Mohit Mangal Date: Mon, 5 Jul 2021 20:18:39 +0530 Subject: [PATCH 231/310] Java FDK dependency version updates --- examples/async-thumbnails/pom.xml | 8 ++++---- examples/regex-query/pom.xml | 2 +- examples/string-reverse/pom.xml | 2 +- fn-spring-cloud-function/pom.xml | 4 ++-- pom.xml | 4 ++-- 5 files changed, 10 insertions(+), 10 deletions(-) diff --git a/examples/async-thumbnails/pom.xml b/examples/async-thumbnails/pom.xml index b43fb037..0b5bcec9 100644 --- a/examples/async-thumbnails/pom.xml +++ b/examples/async-thumbnails/pom.xml @@ -50,7 +50,7 @@ commons-net commons-net - 3.6 + 3.8.0 com.fasterxml.jackson.core @@ -60,7 +60,7 @@ io.minio minio - 5.0.1 + 8.2.2 com.fnproject.fn @@ -83,14 +83,14 @@ junit junit - 4.13.1 + 4.13.2 test com.github.tomakehurst wiremock - 2.19.0 + 2.27.2 diff --git a/examples/regex-query/pom.xml b/examples/regex-query/pom.xml index a7e6819e..f4d62eae 100644 --- a/examples/regex-query/pom.xml +++ b/examples/regex-query/pom.xml @@ -48,7 +48,7 @@ junit junit - 4.13.1 + 4.13.2 test diff --git a/examples/string-reverse/pom.xml b/examples/string-reverse/pom.xml index 92c5eff7..b42f354b 100644 --- a/examples/string-reverse/pom.xml +++ b/examples/string-reverse/pom.xml @@ -50,7 +50,7 @@ junit junit - 4.13.1 + 4.13.2 test diff --git a/fn-spring-cloud-function/pom.xml b/fn-spring-cloud-function/pom.xml index cf7cddfa..246dc860 100644 --- a/fn-spring-cloud-function/pom.xml +++ b/fn-spring-cloud-function/pom.xml @@ -49,7 +49,7 @@ io.projectreactor reactor-core - 3.2.0.M3 + 3.4.7 @@ -94,7 +94,7 @@ com.github.stefanbirkner system-rules - 1.18.0 + 1.19.0 test diff --git a/pom.xml b/pom.xml index ac4dbddc..a53479e3 100644 --- a/pom.xml +++ b/pom.xml @@ -151,7 +151,7 @@ org.apache.httpcomponents httpclient - 4.5.12 + 4.5.13 commons-io @@ -166,7 +166,7 @@ net.jodah typetools - 0.6.2 + 0.6.3 From f284469e9b32a828f5d47230e9e0f91727c0a94a Mon Sep 17 00:00:00 2001 From: Mohit Mangal Date: Tue, 6 Jul 2021 14:19:19 +0530 Subject: [PATCH 232/310] removing minio version update --- examples/async-thumbnails/pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/async-thumbnails/pom.xml b/examples/async-thumbnails/pom.xml index 0b5bcec9..410b00f8 100644 --- a/examples/async-thumbnails/pom.xml +++ b/examples/async-thumbnails/pom.xml @@ -60,7 +60,7 @@ io.minio minio - 8.2.2 + 5.0.1 com.fnproject.fn From dcf647274d3b34d6af41b8af178b4d678ee4d2b0 Mon Sep 17 00:00:00 2001 From: Mohit Mangal Date: Tue, 6 Jul 2021 15:04:51 +0530 Subject: [PATCH 233/310] commons-io version update --- integration-tests/funcs/flowAllFeatures/pom.xml | 2 +- integration-tests/pom.xml | 2 +- pom.xml | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/integration-tests/funcs/flowAllFeatures/pom.xml b/integration-tests/funcs/flowAllFeatures/pom.xml index 7efee1dd..b17a6ba5 100644 --- a/integration-tests/funcs/flowAllFeatures/pom.xml +++ b/integration-tests/funcs/flowAllFeatures/pom.xml @@ -68,7 +68,7 @@ commons-io commons-io - 2.6 + 2.10.0 diff --git a/integration-tests/pom.xml b/integration-tests/pom.xml index b58b37b8..1cc72169 100644 --- a/integration-tests/pom.xml +++ b/integration-tests/pom.xml @@ -28,7 +28,7 @@ 1.0.0-SNAPSHOT 3.16.1 - 2.6 + 2.10.0 2.11.0 4.13.1 2.22.1 diff --git a/pom.xml b/pom.xml index a53479e3..103526b6 100644 --- a/pom.xml +++ b/pom.xml @@ -82,7 +82,7 @@ UTF-8 3.16.1 - 2.6 + 2.10.0 4.4.13 2.11.0 0.8.1 From c1a29eeef3c9df7b0f68447a357c171930349dd5 Mon Sep 17 00:00:00 2001 From: CI Date: Thu, 8 Jul 2021 12:36:26 +0000 Subject: [PATCH 234/310] fn-java-fdk: post-1.0.131 version bump [skip ci] --- release.version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/release.version b/release.version index 8fa58783..08900bc8 100644 --- a/release.version +++ b/release.version @@ -1 +1 @@ -1.0.131 +1.0.132 From e8529b56059e9fa6ae3c292bf5650c64ddf884c5 Mon Sep 17 00:00:00 2001 From: CI Date: Fri, 30 Jul 2021 06:18:38 +0000 Subject: [PATCH 235/310] Releasing version 1.0.132 --- .circleci/config.yml | 15 -- examples/string-reverse/pom.xml | 2 +- infra/provision/Jenkinsfile | 51 ----- .../completer-integration-environment.yaml | 190 ------------------ infra/provision/create-k8s-entities.sh | 45 ----- infra/provision/delete-k8s-entities.sh | 37 ---- infra/provision/registry.yaml | 38 ---- infra/provision/validate-functions-files.sh | 31 --- integration-tests/run_tests_ci.sh | 49 ++--- .../fn/integrationtest/FlowTest.java | 70 ++++--- runtime/pom.xml | 10 + runtime/src/main/c/Dockerfile-buildimage | 2 +- .../fn/runtime/HTTPStreamCodecTest.java | 8 +- .../fn/runtime/ntv/UnixSocketNativeTest.java | 6 +- .../fn/runtime/ntv/UnixSocketTest.java | 6 +- 15 files changed, 92 insertions(+), 468 deletions(-) delete mode 100644 infra/provision/Jenkinsfile delete mode 100644 infra/provision/completer-integration-environment.yaml delete mode 100755 infra/provision/create-k8s-entities.sh delete mode 100755 infra/provision/delete-k8s-entities.sh delete mode 100644 infra/provision/registry.yaml delete mode 100755 infra/provision/validate-functions-files.sh diff --git a/.circleci/config.yml b/.circleci/config.yml index 79b62cc6..c6cbbbeb 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -50,21 +50,6 @@ jobs: export FN_JAVA_FDK_VERSION=$(cat release.version) ./integration-tests/run_tests_ci.sh timeout: 1200 - - run: - name: Login to Docker - command: | - if [[ "${CIRCLE_BRANCH}" == "master" && -z "${CIRCLE_PR_REPONAME}" ]]; then - docker login -u $DOCKER_USER -p $DOCKER_PASS - fi - - deploy: - name: Release new version - command: | - if [[ "${CIRCLE_BRANCH}" == "master" && -z "${CIRCLE_PR_REPONAME}" ]]; then - git config --global user.email "ci@fnproject.com" - git config --global user.name "CI" - git branch --set-upstream-to=origin/${CIRCLE_BRANCH} ${CIRCLE_BRANCH} - ./.circleci/release.sh - fi - run: name: Gather test results when: always diff --git a/examples/string-reverse/pom.xml b/examples/string-reverse/pom.xml index b42f354b..918b4054 100644 --- a/examples/string-reverse/pom.xml +++ b/examples/string-reverse/pom.xml @@ -23,7 +23,7 @@ 4.0.0 UTF-8 - 1.0.87 + 1.0.0-SNAPSHOT com.example.fn string-reverse diff --git a/infra/provision/Jenkinsfile b/infra/provision/Jenkinsfile deleted file mode 100644 index 02fdc8c4..00000000 --- a/infra/provision/Jenkinsfile +++ /dev/null @@ -1,51 +0,0 @@ -/* - * Copyright (c) 2019, 2020 Oracle and/or its affiliates. All rights reserved. - * - * 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. - */ - -pipeline { - agent any - - stages { - stage ('Get the infra files from functions-service') { - steps { - sh ". /home/mjg/proxy ; rm -rf functions-service ; git clone git@gitlab-odx.oracle.com:odx/functions-service.git functions-service" - } - } - stage ('Validate the infra files from functions-service so we do not get surprises when running them for real') { - steps { - sh ". /home/mjg/proxy ; infra/provision/validate-functions-files.sh functions-service" - } - } - stage ('Delete existing k8s entities') { - steps { - sh ". /home/mjg/proxy ; infra/provision/delete-k8s-entities.sh infra/provision functions-service" - } - } - stage ('Provision the whole infrastructure') { - steps { - sh ". /home/mjg/proxy ; infra/provision/create-k8s-entities.sh infra/provision functions-service" - } - } - } - - post { - success { - mattermostSend color: 'good', endpoint: 'https://odx.stengpoc.ucfc2z3b.usdv1.oraclecloud.com/hooks/eqxe7mqgrbrqiryu47wnrjzppy', message: ":poodle: :camel: Provisioned dev environment: ${env.JOB_NAME} ${env.BUILD_NUMBER} (<${env.BUILD_URL}|Open>) :camel: :poodle:" - } - failure { - mattermostSend color: 'danger', endpoint: 'https://odx.stengpoc.ucfc2z3b.usdv1.oraclecloud.com/hooks/eqxe7mqgrbrqiryu47wnrjzppy', message: ":boom: :boom: Failed to provision dev environment: ${env.JOB_NAME} ${env.BUILD_NUMBER} (<${env.BUILD_URL}|Open>) :boom: :boom:" - } - } -} diff --git a/infra/provision/completer-integration-environment.yaml b/infra/provision/completer-integration-environment.yaml deleted file mode 100644 index 7ba3caaa..00000000 --- a/infra/provision/completer-integration-environment.yaml +++ /dev/null @@ -1,190 +0,0 @@ -# -# Copyright (c) 2019, 2020 Oracle and/or its affiliates. All rights reserved. -# -# 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. -# - -# This is run once, at cluster creation time. It creates and sets up the -# components of the flow service, and assumes that the functions service -# is already provisioned from: -# -# https://gitlab-odx.oracle.com/odx/functions-service/tree/master/scripts/fn-service.yml -# -# The created service has persistent storage to a single-stage MySQL database. -# -# Updates are done by: -# -# $ kubectl set image deployment/completer-service completer-service=NEW_IMAGE_FULL_PATH -# ---- -apiVersion: v1 -kind: Secret -metadata: - name: completer-mysql-secret -type: Opaque -data: - MYSQL_DATABASE: YWtrYQ== - MYSQL_USER: cXNSaFVNWVo1NXFDdWg4T29lbVo0c2hxQndEYzNo - MYSQL_PASSWORD: eXF2cEhEUFliU3lyWU9VdHVsb08zQThXTWtKVGFKdmIzTnQ3dFVaZkE4NHlFWnBueXlpUEF3 - MYSQL_ROOT_PASSWORD: N1ZSRWlUSFRXMDlQbnhETzRIQUVQWkxhREEwSHZVQ1pBNWZuVDl3akdEd3ExSk5yRmE3TUhn ---- -apiVersion: v1 -kind: ConfigMap -metadata: - name: completer-persistence-schema-file -data: - schema-file.sql: | - USE akka; - CREATE TABLE IF NOT EXISTS journal ( - ordering SERIAL, - persistence_id VARCHAR(255) NOT NULL, - sequence_number BIGINT NOT NULL, - deleted BOOLEAN DEFAULT FALSE, - tags VARCHAR(255) DEFAULT NULL, - message BLOB NOT NULL, - PRIMARY KEY(persistence_id, sequence_number) - ); - CREATE TABLE IF NOT EXISTS snapshot ( - persistence_id VARCHAR(255) NOT NULL, - sequence_number BIGINT NOT NULL, - created BIGINT NOT NULL, - snapshot BLOB NOT NULL, - PRIMARY KEY (persistence_id, sequence_number) - ); - ---- -apiVersion: v1 -kind: Service -metadata: - name: completer-persistence-mysql - labels: - app: completer-mysql - role: datastore -spec: - ports: - - port: 3306 - targetPort: 3306 - selector: - app: completer-mysql - role: datastore ---- -apiVersion: apps/v1beta1 -kind: Deployment -metadata: - name: completer-persistence-mysql -spec: - replicas: 1 - template: - metadata: - labels: - app: completer-mysql - role: datastore - spec: - terminationGracePeriodSeconds: 1 - containers: - - name: completer-mysql - image: mysql:5.7 - imagePullPolicy: Always - args: - - "--max-connections=500" - ports: - - containerPort: 3306 - env: - - name: MYSQL_ROOT_PASSWORD - valueFrom: - secretKeyRef: - name: completer-mysql-secret - key: MYSQL_ROOT_PASSWORD - - name: MYSQL_USER - valueFrom: - secretKeyRef: - name: completer-mysql-secret - key: MYSQL_USER - - name: MYSQL_PASSWORD - valueFrom: - secretKeyRef: - name: completer-mysql-secret - key: MYSQL_PASSWORD - - name: MYSQL_DATABASE - valueFrom: - secretKeyRef: - name: completer-mysql-secret - key: MYSQL_DATABASE - volumeMounts: - - mountPath: /docker-entrypoint-initdb.d - name: schema-file - volumes: - - name: schema-file - configMap: - name: completer-persistence-schema-file ---- -apiVersion: apps/v1beta1 # for versions before 1.6.0 use extensions/v1beta1 -kind: Deployment -metadata: - name: completer-service -spec: - replicas: 1 - template: - metadata: - labels: - app: completer-service - spec: - containers: - - name: completer-service - image: registry.oracledx.com/skeppare/cloud-completer:latest - imagePullPolicy: Always - ports: - - containerPort: 8081 - name: http-server - env: - - name: CONFIG_RESOURCE - value: prod.conf - - name: MYSQL_HOST - value: completer-persistence-mysql - - name: MYSQL_USER - valueFrom: - secretKeyRef: - name: completer-mysql-secret - key: MYSQL_USER - - name: MYSQL_PASSWORD - valueFrom: - secretKeyRef: - name: completer-mysql-secret - key: MYSQL_PASSWORD - - name: MYSQL_DATABASE - valueFrom: - secretKeyRef: - name: completer-mysql-secret - key: MYSQL_DATABASE - - name: FN_HOST - value: fn-service - - name: FN_PORT - value: "8080" - imagePullSecrets: - - name: odx-registry-secret ---- -kind: Service -apiVersion: v1 -metadata: - name: completer-service - labels: - app: completer-service -spec: - clusterIP: 10.32.0.66 - ports: - - port: 8081 - targetPort: http-server - nodePort: 31750 - selector: - app: completer-service - type: NodePort diff --git a/infra/provision/create-k8s-entities.sh b/infra/provision/create-k8s-entities.sh deleted file mode 100755 index 070ce154..00000000 --- a/infra/provision/create-k8s-entities.sh +++ /dev/null @@ -1,45 +0,0 @@ -#!/bin/bash -# -# Copyright (c) 2019, 2020 Oracle and/or its affiliates. All rights reserved. -# -# 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. -# - -PROVISION_DIR=$1 -FUNCTIONS_SERVICE_DIR=$2 - -set -ex - -if [[ -z "${PROVISION_DIR// }" ]]; then - echo "ERROR: must specify the jfaas/infra/provision directory as the first argument" - exit 2 -fi -if [[ -z "${FUNCTIONS_SERVICE_DIR// }" ]]; then - echo "ERROR: must specify the location of the functions-service local repository as the second argument" - exit 2 -fi - -# HACK! Apparently even the functions guys have issues pulling some SRE images. -# We're just changing them to pause containers because they are only used for -# metrics and we don't need them. -# Also we set the pulling strategy to Always so we can pull the latest image. -sed "s/imagePullPolicy: IfNotPresent/imagePullPolicy: Always/" $FUNCTIONS_SERVICE_DIR/scripts/fn-service.yml -i -sed s/registry.oracledx.com\\/odxsre\\/core-services-statsd-exporter/kubernetes\\/pause/ $FUNCTIONS_SERVICE_DIR/scripts/fn-service.yml -i -sed s/registry.oracledx.com\\/odxsre\\/core-services-prometheus-pusher/kubernetes\\/pause/ $FUNCTIONS_SERVICE_DIR/scripts/fn-service.yml -i -kubectl create -f $FUNCTIONS_SERVICE_DIR/scripts/docker-reg-secret.yml -kubectl create -f $FUNCTIONS_SERVICE_DIR/scripts/zipkin-service.yml -kubectl create -f $FUNCTIONS_SERVICE_DIR/scripts/fn-service.yml - -kubectl create -f $PROVISION_DIR/registry.yaml -sleep 1 -kubectl create -f $PROVISION_DIR/completer-integration-environment.yaml diff --git a/infra/provision/delete-k8s-entities.sh b/infra/provision/delete-k8s-entities.sh deleted file mode 100755 index c2b2238b..00000000 --- a/infra/provision/delete-k8s-entities.sh +++ /dev/null @@ -1,37 +0,0 @@ -#!/bin/bash -# -# Copyright (c) 2019, 2020 Oracle and/or its affiliates. All rights reserved. -# -# 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. -# - -PROVISION_DIR=$1 -FUNCTIONS_SERVICE_DIR=$2 - -set -ex - -if [[ -z "${PROVISION_DIR// }" ]]; then - echo "ERROR: must specify the jfaas/infra/provision directory as the first argument" - exit 2 -fi -if [[ -z "${FUNCTIONS_SERVICE_DIR// }" ]]; then - echo "ERROR: must specify the location of the functions-service local repository as the second argument" - exit 2 -fi - -kubectl delete -f $PROVISION_DIR/completer-integration-environment.yaml || true -kubectl delete -f $PROVISION_DIR/registry.yaml || true - -kubectl delete -f $FUNCTIONS_SERVICE_DIR/scripts/fn-service.yml || true -kubectl delete -f $FUNCTIONS_SERVICE_DIR/scripts/zipkin-service.yml || true -kubectl delete -f $FUNCTIONS_SERVICE_DIR/scripts/docker-reg-secret.yml || true diff --git a/infra/provision/registry.yaml b/infra/provision/registry.yaml deleted file mode 100644 index c1b1172a..00000000 --- a/infra/provision/registry.yaml +++ /dev/null @@ -1,38 +0,0 @@ -# -# Copyright (c) 2019, 2020 Oracle and/or its affiliates. All rights reserved. -# -# 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. -# - -# This is run once, at cluster creation time and it creates a deployment and a -# service based on the latest functions image. -# -# The created server is configured so that it does NOT have persistent storage. -# It is only intended to be used as a test server and data can be thrown away. -# -# Updates are done by: -# $ kubectl set image deployment/functions-master functions=NEW_IMAGE_FULL_PATH - ---- -# This may or may not be repeatable. Apparently registry.oracledx.com hands -# out the same auth token every time for the same combination of user/pass, -# so this should work, but we have no guarantees. The problem is that if we -# don't create the secret in a yaml file we have to have a manual process to -# create it, which is not ideal. -kind: Secret -apiVersion: v1 -metadata: - name: odx-registry-secret -type: kubernetes.io/dockercfg -data: - .dockercfg: eyJyZWdpc3RyeS5vcmFjbGVkeC5jb20iOnsidXNlcm5hbWUiOiJhZ2VudCIsInBhc3N3b3JkIjoiZ2YyMVx1MDAyNjU0RyIsImVtYWlsIjoiZGFyaW8uZG9taXppb2xpQG9yYWNsZS5jb20iLCJhdXRoIjoiWVdkbGJuUTZaMll5TVNZMU5FYz0ifX0= diff --git a/infra/provision/validate-functions-files.sh b/infra/provision/validate-functions-files.sh deleted file mode 100755 index 83668022..00000000 --- a/infra/provision/validate-functions-files.sh +++ /dev/null @@ -1,31 +0,0 @@ -#!/bin/bash -# -# Copyright (c) 2019, 2020 Oracle and/or its affiliates. All rights reserved. -# -# 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. -# - -FUNCTIONS_SERVICE_DIR=$1 - -set -ex - -if [[ -z "${FUNCTIONS_SERVICE_DIR// }" ]]; then - echo "ERROR: must specify the location of the functions-service local repository as the argument" - exit 2 -fi - -# This dry run validation is performed so that we don't delete our environment and then fail to recreate it. -kubectl create --dry-run -f $FUNCTIONS_SERVICE_DIR/scripts/docker-reg-secret.yml -kubectl create --dry-run -f $FUNCTIONS_SERVICE_DIR/scripts/zipkin-service.yml -kubectl create --dry-run -f $FUNCTIONS_SERVICE_DIR/scripts/fn-service.yml - diff --git a/integration-tests/run_tests_ci.sh b/integration-tests/run_tests_ci.sh index 1d9fac50..399722a0 100755 --- a/integration-tests/run_tests_ci.sh +++ b/integration-tests/run_tests_ci.sh @@ -60,21 +60,27 @@ FNSERVER_IP=$(docker inspect --type container -f '{{.NetworkSettings.IPAddress}} -docker rm -f flowserver || true -docker run --rm -d \ - -p 8081:8081 \ - -e API_URL="http://${FNSERVER_IP}:8080/invoke" \ - -e no_proxy=${FNSERVER_IP} \ - --name flowserver \ - fnproject/flow:latest - -until $(curl --output /dev/null --silent --fail http://localhost:8081/ping); do - printf '.' - sleep 1 -done -export FLOW_LOG_FILE=/tmp/flow.log - -docker logs -f flowserver >& ${FLOW_LOG_FILE} & +# These tests are Fn flow which never got productionized. Commenting these +# tests as we had to remove the infra/provision directory to eliminate +# security findings - https://jira-sd.mc1.oracleiaas.com/browse/FAAS-13105 +# We need to re-implement most of flow functionalities from scratch if +# we decide to productionize it. + +# docker rm -f flowserver || true +# docker run --rm -d \ +# -p 8081:8081 \ +# -e API_URL="http://${FNSERVER_IP}:8080/invoke" \ +# -e no_proxy=${FNSERVER_IP} \ +# --name flowserver \ +# fnproject/flow:latest + +# until $(curl --output /dev/null --silent --fail http://localhost:8081/ping); do +# printf '.' +# sleep 1 +# done +# export FLOW_LOG_FILE=/tmp/flow.log + +# docker logs -f flowserver >& ${FLOW_LOG_FILE} & set +e @@ -89,14 +95,11 @@ export DOCKER_LOCALHOST REPO_IP=$(docker inspect --type container -f '{{.NetworkSettings.IPAddress}}' fn_mvn_repo) MAVEN_REPOSITORY="http://${REPO_IP}:18080" export MAVEN_REPOSITORY -COMPLETER_IP=$(docker inspect --type container -f '{{.NetworkSettings.IPAddress}}' flowserver) -COMPLETER_BASE_URL="http://${COMPLETER_IP}:8081" -export COMPLETER_BASE_URL - -export no_proxy="${no_proxy},${DOCKER_LOCALHOST},${COMPLETER_IP},${REPO_IP}" - - +# COMPLETER_IP=$(docker inspect --type container -f '{{.NetworkSettings.IPAddress}}' flowserver) +# COMPLETER_BASE_URL="http://${COMPLETER_IP}:8081" +# export COMPLETER_BASE_URL +export no_proxy="${no_proxy},${DOCKER_LOCALHOST},${REPO_IP}" echo "Running tests" mvn test @@ -104,7 +107,7 @@ result=$? -docker rm -f flowserver +# docker rm -f flowserver docker rm -f fnserver docker rm -rf fn_mvn_repo diff --git a/integration-tests/src/test/java/com/fnproject/fn/integrationtest/FlowTest.java b/integration-tests/src/test/java/com/fnproject/fn/integrationtest/FlowTest.java index 81a9b706..e1028fbb 100644 --- a/integration-tests/src/test/java/com/fnproject/fn/integrationtest/FlowTest.java +++ b/integration-tests/src/test/java/com/fnproject/fn/integrationtest/FlowTest.java @@ -37,38 +37,44 @@ public class FlowTest { @Rule public final IntegrationTestRule testRule = new IntegrationTestRule(); - - @Test - public void shouldInvokeBasicFlow() throws Exception { - IntegrationTestRule.TestContext tc = testRule.newTest(); - tc.withDirFrom("funcs/flowBasic").rewritePOM().rewriteDockerfile(true); - tc.runFn("--verbose", "deploy", "--create-app", "--app", tc.appName(), "--local"); - tc.runFn("config", "app", tc.appName(), "COMPLETER_BASE_URL", testRule.getFlowURL()); - CmdResult r = tc.runFnWithInput("1", "invoke", tc.appName(), "flowbasic"); - assertThat(r.getStdout()).isEqualTo("4"); - } - - - @Test - public void shouldInvokeBasicFlowJDK8() throws Exception { - IntegrationTestRule.TestContext tc = testRule.newTest(); - tc.withDirFrom("funcs/flowBasicJDK8").rewritePOM().rewriteDockerfile(false); - tc.runFn("--verbose", "deploy", "--create-app", "--app", tc.appName(), "--local"); - tc.runFn("config", "app", tc.appName(), "COMPLETER_BASE_URL", testRule.getFlowURL()); - CmdResult r = tc.runFnWithInput("1", "invoke", tc.appName(), "flowbasicj8"); - assertThat(r.getStdout()).isEqualTo("4"); - } - - - @Test - public void shouldExerciseAllFlow() throws Exception { - IntegrationTestRule.TestContext tc = testRule.newTest(); - tc.withDirFrom("funcs/flowAllFeatures").rewritePOM().rewriteDockerfile(true); - tc.runFn("--verbose", "deploy", "--create-app", "--app", tc.appName(), "--local"); - tc.runFn("config", "app", tc.appName(), "COMPLETER_BASE_URL", testRule.getFlowURL()); - CmdResult r = tc.runFnWithInput("1", "invoke", tc.appName(), "flowallfeatures"); - assertThat(r.getStdout()).contains("Everything worked"); - } + //These tests are Fn flow which never got productionized. Commenting these + //tests as we had to remove the infra/provision directory to eliminate + //security findings - https://jira-sd.mc1.oracleiaas.com/browse/FAAS-13105 + + //We need to re-implement most of flow functionalities from scratch if + //we decide to productionize it. + + //@Test + //public void shouldInvokeBasicFlow() throws Exception { + // IntegrationTestRule.TestContext tc = testRule.newTest(); + // tc.withDirFrom("funcs/flowBasic").rewritePOM().rewriteDockerfile(true); + // tc.runFn("--verbose", "deploy", "--create-app", "--app", tc.appName(), "--local"); + // tc.runFn("config", "app", tc.appName(), "COMPLETER_BASE_URL", testRule.getFlowURL()); + // CmdResult r = tc.runFnWithInput("1", "invoke", tc.appName(), "flowbasic"); + // assertThat(r.getStdout()).isEqualTo("4"); + //} + + + //@Test + //public void shouldInvokeBasicFlowJDK8() throws Exception { + // IntegrationTestRule.TestContext tc = testRule.newTest(); + // tc.withDirFrom("funcs/flowBasicJDK8").rewritePOM().rewriteDockerfile(false); + // tc.runFn("--verbose", "deploy", "--create-app", "--app", tc.appName(), "--local"); + // tc.runFn("config", "app", tc.appName(), "COMPLETER_BASE_URL", testRule.getFlowURL()); + // CmdResult r = tc.runFnWithInput("1", "invoke", tc.appName(), "flowbasicj8"); + // assertThat(r.getStdout()).isEqualTo("4"); + //} + + + //@Test + //public void shouldExerciseAllFlow() throws Exception { + // IntegrationTestRule.TestContext tc = testRule.newTest(); + // tc.withDirFrom("funcs/flowAllFeatures").rewritePOM().rewriteDockerfile(true); + // tc.runFn("--verbose", "deploy", "--create-app", "--app", tc.appName(), "--local"); + // tc.runFn("config", "app", tc.appName(), "COMPLETER_BASE_URL", testRule.getFlowURL()); + // CmdResult r = tc.runFnWithInput("1", "invoke", tc.appName(), "flowallfeatures"); + // assertThat(r.getStdout()).contains("Everything worked"); + //} // THESE TESTS ARE FLAKEY AND SHOULD BE REVISITED. diff --git a/runtime/pom.xml b/runtime/pom.xml index 0aca8f27..a15085b3 100644 --- a/runtime/pom.xml +++ b/runtime/pom.xml @@ -155,6 +155,16 @@ + + org.apache.maven.plugins + maven-surefire-plugin + 2.22.1 + + + ${user.dir} + + + diff --git a/runtime/src/main/c/Dockerfile-buildimage b/runtime/src/main/c/Dockerfile-buildimage index bab55644..96b3bd2d 100644 --- a/runtime/src/main/c/Dockerfile-buildimage +++ b/runtime/src/main/c/Dockerfile-buildimage @@ -14,7 +14,7 @@ # limitations under the License. # -FROM oraclelinux:7.5 +FROM container-registry.oracle.com/os/oraclelinux:7.5 RUN yum install -y gcc cmake java-1.8.0-openjdk-devel.x86_64 make RUN yum install -y gcc-c++ diff --git a/runtime/src/test/java/com/fnproject/fn/runtime/HTTPStreamCodecTest.java b/runtime/src/test/java/com/fnproject/fn/runtime/HTTPStreamCodecTest.java index e117b4de..8abcac12 100644 --- a/runtime/src/test/java/com/fnproject/fn/runtime/HTTPStreamCodecTest.java +++ b/runtime/src/test/java/com/fnproject/fn/runtime/HTTPStreamCodecTest.java @@ -81,11 +81,15 @@ private static File generateSocketFile() { } static { - System.setProperty("com.fnproject.java.native.libdir", new File("src/main/c/").getAbsolutePath()); + if (System.getenv("RUNTIME_BUILD_DIR") == null) { + System.setProperty("com.fnproject.java.native.libdir", new File("src/main/c/").getAbsolutePath()); + }else{ + System.setProperty("com.fnproject.java.native.libdir", new File(System.getenv("RUNTIME_BUILD_DIR")).getAbsolutePath()); + } + System.setProperty("org.eclipse.jetty.util.log.class", "org.eclipse.jetty.util.log.StdErrLog"); System.setProperty("org.eclipse.jetty.LEVEL", "WARN"); - Map env = new HashMap<>(); env.put("FN_APP_NAME", "myapp"); env.put("FN_PATH", "mypath"); diff --git a/runtime/src/test/java/com/fnproject/fn/runtime/ntv/UnixSocketNativeTest.java b/runtime/src/test/java/com/fnproject/fn/runtime/ntv/UnixSocketNativeTest.java index 805c668a..228af289 100644 --- a/runtime/src/test/java/com/fnproject/fn/runtime/ntv/UnixSocketNativeTest.java +++ b/runtime/src/test/java/com/fnproject/fn/runtime/ntv/UnixSocketNativeTest.java @@ -38,7 +38,11 @@ public class UnixSocketNativeTest { @BeforeClass public static void init() { - System.setProperty("com.fnproject.java.native.libdir", new File("src/main/c/").getAbsolutePath()); + if (System.getenv("RUNTIME_BUILD_DIR") == null) { + System.setProperty("com.fnproject.java.native.libdir", new File("src/main/c/").getAbsolutePath()); + }else{ + System.setProperty("com.fnproject.java.native.libdir", new File(System.getenv("RUNTIME_BUILD_DIR")).getAbsolutePath()); + } } File createSocketFile() throws IOException { diff --git a/runtime/src/test/java/com/fnproject/fn/runtime/ntv/UnixSocketTest.java b/runtime/src/test/java/com/fnproject/fn/runtime/ntv/UnixSocketTest.java index 8f17ee43..1e8dc233 100644 --- a/runtime/src/test/java/com/fnproject/fn/runtime/ntv/UnixSocketTest.java +++ b/runtime/src/test/java/com/fnproject/fn/runtime/ntv/UnixSocketTest.java @@ -36,7 +36,11 @@ public class UnixSocketTest { @BeforeClass public static void setup() { - System.setProperty("com.fnproject.java.native.libdir", new File("src/main/c/").getAbsolutePath()); + if (System.getenv("RUNTIME_BUILD_DIR") == null) { + System.setProperty("com.fnproject.java.native.libdir", new File("src/main/c/").getAbsolutePath()); + }else{ + System.setProperty("com.fnproject.java.native.libdir", new File(System.getenv("RUNTIME_BUILD_DIR")).getAbsolutePath()); + } } File createSocketFile() throws IOException { From e60fba33f23f7a97b9b05f56633bba73f576fd98 Mon Sep 17 00:00:00 2001 From: CI Date: Wed, 1 Sep 2021 04:45:21 +0000 Subject: [PATCH 236/310] Releasing version 1.0.133 --- .../com/fnproject/fn/integrationtest/FunctionsTest.java | 5 ++++- pom.xml | 2 +- release.version | 2 +- .../src/main/java/com/fnproject/fn/runtime/EntryPoint.java | 3 ++- .../main/java/com/fnproject/fn/runtime/HTTPStreamCodec.java | 6 +++++- .../java/com/fnproject/fn/runtime/HTTPStreamCodecTest.java | 4 +++- 6 files changed, 16 insertions(+), 6 deletions(-) diff --git a/integration-tests/src/test/java/com/fnproject/fn/integrationtest/FunctionsTest.java b/integration-tests/src/test/java/com/fnproject/fn/integrationtest/FunctionsTest.java index 22b4a2ee..dc9ec597 100644 --- a/integration-tests/src/test/java/com/fnproject/fn/integrationtest/FunctionsTest.java +++ b/integration-tests/src/test/java/com/fnproject/fn/integrationtest/FunctionsTest.java @@ -159,6 +159,9 @@ public void shouldGetFDKVersion() throws Exception { assertThat(val.get(0)).matches("fdk-java/\\d+\\.\\d+\\.\\d+(-SNAPSHOT)? \\(jvm=.*, jvmv=.*\\)"); }); + assertThat(headers).hasEntrySatisfying("Fn-Fdk-Runtime", (val) -> { + assertThat(val).isNotEmpty(); + assertThat(val.get(0)).matches("java/.+\\ .+"); + }); } - } diff --git a/pom.xml b/pom.xml index 103526b6..7fe32908 100644 --- a/pom.xml +++ b/pom.xml @@ -87,7 +87,7 @@ 2.11.0 0.8.1 9.4.12.v20180830 - 4.13.1 + 4.13.2 3.3.3 1.4.0 1.7.25 diff --git a/release.version b/release.version index 08900bc8..40c74875 100644 --- a/release.version +++ b/release.version @@ -1 +1 @@ -1.0.132 +1.0.133 diff --git a/runtime/src/main/java/com/fnproject/fn/runtime/EntryPoint.java b/runtime/src/main/java/com/fnproject/fn/runtime/EntryPoint.java index 418540a8..bd76a6e7 100644 --- a/runtime/src/main/java/com/fnproject/fn/runtime/EntryPoint.java +++ b/runtime/src/main/java/com/fnproject/fn/runtime/EntryPoint.java @@ -64,8 +64,9 @@ public static void main(String... args) { String fdkVersion = "fdk-java/" + Version.FDK_VERSION + " (jvm=" + (jvmName + ", jvmv=" + jvmVersion + ")"); + String runtimeVersion = "java/" + jvmName + " " + jvmVersion; - codec = new HTTPStreamCodec(System.getenv(), fdkVersion); + codec = new HTTPStreamCodec(System.getenv(), fdkVersion, runtimeVersion); } else { throw new FunctionInputHandlingException("Unsupported function format:" + format); } diff --git a/runtime/src/main/java/com/fnproject/fn/runtime/HTTPStreamCodec.java b/runtime/src/main/java/com/fnproject/fn/runtime/HTTPStreamCodec.java index b6b5b317..4b442783 100644 --- a/runtime/src/main/java/com/fnproject/fn/runtime/HTTPStreamCodec.java +++ b/runtime/src/main/java/com/fnproject/fn/runtime/HTTPStreamCodec.java @@ -87,6 +87,7 @@ public final class HTTPStreamCodec implements EventCodec, Closeable { private static final Set stripOutputHeaders; private final Map env; private final String fdkVersion; + private final String runtimeVersion; private final AtomicBoolean stopping = new AtomicBoolean(false); private final File socketFile; private final CompletableFuture stopped = new CompletableFuture<>(); @@ -135,10 +136,12 @@ private String randomString() { * * @param env an env map * @param fdkVersion the version to report to the runtime + * @param runtimeVersion underlying JVM version to report to the runtime */ - HTTPStreamCodec(Map env, String fdkVersion) { + HTTPStreamCodec(Map env, String fdkVersion, String runtimeVersion) { this.env = Objects.requireNonNull(env, "env"); this.fdkVersion = Objects.requireNonNull(fdkVersion, "fdkVersion"); + this.runtimeVersion = Objects.requireNonNull(runtimeVersion, "runtimeVersion"); String listenerAddress = getRequiredEnv(FN_LISTENER); if (!listenerAddress.startsWith("unix:/")) { @@ -360,6 +363,7 @@ private void writeEvent(OutputEvent evt, HttpResponse response) { response.setHeader("Content-Type", contentType.toString()); response.setHeader("Fn-Fdk-Version", fdkVersion); + response.setHeader("Fn-Fdk-Runtime", runtimeVersion); response.setStatusLine(new BasicStatusLine(HttpVersion.HTTP_1_1, evt.getStatus().getCode(), evt.getStatus().name())); ByteArrayOutputStream bos = new ByteArrayOutputStream(); diff --git a/runtime/src/test/java/com/fnproject/fn/runtime/HTTPStreamCodecTest.java b/runtime/src/test/java/com/fnproject/fn/runtime/HTTPStreamCodecTest.java index 8abcac12..7e68816d 100644 --- a/runtime/src/test/java/com/fnproject/fn/runtime/HTTPStreamCodecTest.java +++ b/runtime/src/test/java/com/fnproject/fn/runtime/HTTPStreamCodecTest.java @@ -61,6 +61,7 @@ public class HTTPStreamCodecTest { private static final String VERSION = "FDK_TEST_VERSION"; + private static final String RUNTIME_VERSION = "FDK_TEST_RUNTIME"; @Rule public final Timeout to = Timeout.builder().withTimeout(60, TimeUnit.SECONDS).withLookingForStuckThread(true).build(); @@ -133,7 +134,7 @@ File startCodec(Map env, EventCodec.Handler h) { File socket = generateSocketFile(); newEnv.put("FN_LISTENER", "unix:" + socket.getAbsolutePath()); - HTTPStreamCodec codec = new HTTPStreamCodec(newEnv, VERSION); + HTTPStreamCodec codec = new HTTPStreamCodec(newEnv, VERSION, RUNTIME_VERSION); Thread t = new Thread(() -> codec.runCodec(h)); t.start(); @@ -170,6 +171,7 @@ public void shouldAcceptDataOnHttp() throws Exception { assertThat(resp.getContent()).isEqualTo("hello".getBytes()); assertThat(resp.getHeaders().get("x-test")).isEqualTo("bar"); assertThat(resp.getHeaders().get("fn-fdk-version")).isEqualTo(VERSION); + assertThat(resp.getHeaders().get("fn-fdk-runtime")).isEqualTo(RUNTIME_VERSION); InputEvent evt = lastEvent.get(1, TimeUnit.MILLISECONDS); assertThat(evt.getCallID()).isEqualTo("callID"); From e66cfbe29771963f9c76f88cb1f07f814a839951 Mon Sep 17 00:00:00 2001 From: CI Date: Thu, 7 Oct 2021 16:01:12 +0000 Subject: [PATCH 237/310] Releasing version 1.0.134 --- release.version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/release.version b/release.version index 40c74875..e7dc0f8f 100644 --- a/release.version +++ b/release.version @@ -1 +1 @@ -1.0.133 +1.0.134 From 28ed9f674ba3fbc1de4f6488edf719831dc5a425 Mon Sep 17 00:00:00 2001 From: CI Date: Wed, 13 Oct 2021 06:16:14 +0000 Subject: [PATCH 238/310] Releasing version 1.0.135 --- examples/async-thumbnails/pom.xml | 2 +- examples/regex-query/pom.xml | 2 +- .../fn/nativeimagesupport/JacksonFeature.java | 2 +- fn-spring-cloud-function/pom.xml | 2 +- pom.xml | 15 ++++++++------- release.version | 2 +- runtime/pom.xml | 2 +- 7 files changed, 14 insertions(+), 13 deletions(-) diff --git a/examples/async-thumbnails/pom.xml b/examples/async-thumbnails/pom.xml index 410b00f8..2d866229 100644 --- a/examples/async-thumbnails/pom.xml +++ b/examples/async-thumbnails/pom.xml @@ -28,7 +28,7 @@ 1.0.0-SNAPSHOT 3.3.3 - 2.11.0 + 2.13.0 com.fnproject.fn.examples diff --git a/examples/regex-query/pom.xml b/examples/regex-query/pom.xml index f4d62eae..8c72849d 100644 --- a/examples/regex-query/pom.xml +++ b/examples/regex-query/pom.xml @@ -27,7 +27,7 @@ UTF-8 1.0.0-SNAPSHOT - 2.11.0 + 2.13.0 com.fnproject.fn.examples diff --git a/experimental-native-image-support/src/main/java/com/fnproject/fn/nativeimagesupport/JacksonFeature.java b/experimental-native-image-support/src/main/java/com/fnproject/fn/nativeimagesupport/JacksonFeature.java index fb0ad445..a5d7e6d1 100644 --- a/experimental-native-image-support/src/main/java/com/fnproject/fn/nativeimagesupport/JacksonFeature.java +++ b/experimental-native-image-support/src/main/java/com/fnproject/fn/nativeimagesupport/JacksonFeature.java @@ -145,7 +145,7 @@ public void beforeAnalysis(BeforeAnalysisAccess access) { rrs.register(referencedClazz); rrs.register(referencedClazz.getDeclaredConstructors()); rrs.register(referencedClazz.getDeclaredMethods()); - Arrays.stream(referencedClazz.getDeclaredFields()).forEach(f -> rrs.register(false, false, f)); + Arrays.stream(referencedClazz.getDeclaredFields()).forEach(f -> rrs.register(false, f)); }); }, Object.class); } diff --git a/fn-spring-cloud-function/pom.xml b/fn-spring-cloud-function/pom.xml index 246dc860..baae1df7 100644 --- a/fn-spring-cloud-function/pom.xml +++ b/fn-spring-cloud-function/pom.xml @@ -49,7 +49,7 @@ io.projectreactor reactor-core - 3.4.7 + 3.4.10 diff --git a/pom.xml b/pom.xml index 7fe32908..4ede77ee 100644 --- a/pom.xml +++ b/pom.xml @@ -81,19 +81,20 @@ UTF-8 UTF-8 - 3.16.1 - 2.10.0 - 4.4.13 - 2.11.0 + 3.21.0 + 2.11.0 + 4.4.14 + 2.13.0 0.8.1 - 9.4.12.v20180830 + 9.4.44.v20210927 + 9.4.44.v20210927 4.13.2 - 3.3.3 + 4.0.0 1.4.0 1.7.25 2.22.1 1.16.0 - 21.0.0.2 + 21.2.0 false diff --git a/release.version b/release.version index e7dc0f8f..874b2e60 100644 --- a/release.version +++ b/release.version @@ -1 +1 @@ -1.0.134 +1.0.135 diff --git a/runtime/pom.xml b/runtime/pom.xml index a15085b3..df77c3bd 100644 --- a/runtime/pom.xml +++ b/runtime/pom.xml @@ -85,7 +85,7 @@ org.eclipse.jetty jetty-unixsocket - ${jetty.version} + ${jetty.unixsocketversion} test From 2a13fae699f69a80ce912e0e570e6cc1c9a81885 Mon Sep 17 00:00:00 2001 From: CI Date: Wed, 13 Oct 2021 11:50:39 +0000 Subject: [PATCH 239/310] Releasing version 1.0.136 --- release.version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/release.version b/release.version index 874b2e60..36e38bdf 100644 --- a/release.version +++ b/release.version @@ -1 +1 @@ -1.0.135 +1.0.136 From 50b46d3089e2eb6c897dda6b2b0b5526f6c552be Mon Sep 17 00:00:00 2001 From: CI Date: Wed, 13 Oct 2021 13:30:51 +0000 Subject: [PATCH 240/310] Releasing version 1.0.137 --- pom.xml | 3 +-- release.version | 2 +- runtime/pom.xml | 2 +- 3 files changed, 3 insertions(+), 4 deletions(-) diff --git a/pom.xml b/pom.xml index 4ede77ee..a14013e1 100644 --- a/pom.xml +++ b/pom.xml @@ -86,8 +86,7 @@ 4.4.14 2.13.0 0.8.1 - 9.4.44.v20210927 - 9.4.44.v20210927 + 9.4.12.v20180830 4.13.2 4.0.0 1.4.0 diff --git a/release.version b/release.version index 36e38bdf..4cf8fd6f 100644 --- a/release.version +++ b/release.version @@ -1 +1 @@ -1.0.136 +1.0.137 diff --git a/runtime/pom.xml b/runtime/pom.xml index df77c3bd..a15085b3 100644 --- a/runtime/pom.xml +++ b/runtime/pom.xml @@ -85,7 +85,7 @@ org.eclipse.jetty jetty-unixsocket - ${jetty.unixsocketversion} + ${jetty.version} test From 2ebd19ac36c5a87bccabd4dc423d203d810a2b6c Mon Sep 17 00:00:00 2001 From: CI Date: Thu, 21 Oct 2021 07:37:07 +0000 Subject: [PATCH 241/310] Releasing version 1.0.138 --- release.version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/release.version b/release.version index 4cf8fd6f..82d042d9 100644 --- a/release.version +++ b/release.version @@ -1 +1 @@ -1.0.137 +1.0.138 From 7c060daa857048ffe6d7ef5cd2b4cbbce830610a Mon Sep 17 00:00:00 2001 From: CI Date: Tue, 26 Oct 2021 06:59:10 +0000 Subject: [PATCH 242/310] Releasing version 1.0.139 --- .circleci/config.yml | 61 -- .circleci/fix-java-for-surefire.sh | 5 - .circleci/install-docker.sh | 8 - .circleci/install-fn.sh | 24 - .circleci/lib.sh | 6 - .circleci/maven-settings.xml | 50 -- .circleci/release.sh | 115 ---- .circleci/update-versions.sh | 24 - build.sh | 62 -- images/build-native/Dockerfile | 20 - images/build-native/README.md | 5 - images/build-native/docker-build.sh | 61 -- images/build/Dockerfile | 24 - images/build/Dockerfile-jdk11 | 25 - images/build/cache-deps.sh | 28 - images/build/docker-build.sh | 37 -- images/build/local-settings.xml | 23 - images/build/pom.xml | 110 ---- .../java/com/example/fn/HelloFunction.java | 27 - .../com/example/fn/HelloFunctionTest.java | 40 -- images/init-native/Dockerfile | 46 -- images/init-native/Dockerfile-init-image | 40 -- images/init-native/README.md | 2 - images/init-native/docker-build.sh | 38 -- images/init-native/func.init.yaml | 16 - images/init-native/pom.xml | 106 ---- .../java/com/example/fn/HelloFunction.java | 27 - .../fnfunction/reflect-config.json | 9 - .../com/example/fn/HelloFunctionTest.java | 38 -- images/runtime/Dockerfile | 37 -- images/runtime/Dockerfile-jre11 | 36 -- images/runtime/README.md | 3 - integration-tests/README.md | 29 - integration-tests/fnserver.env | 3 - .../funcs/flowAllFeatures/Dockerfile | 11 - .../funcs/flowAllFeatures/README.md | 19 - .../funcs/flowAllFeatures/func.yaml | 26 - .../funcs/flowAllFeatures/pom.xml | 103 ---- .../fn/integration/ExerciseEverything.java | 582 ------------------ .../com/fnproject/fn/integration/Test.java | 42 -- integration-tests/funcs/flowBasic/Dockerfile | 11 - integration-tests/funcs/flowBasic/func.yaml | 23 - integration-tests/funcs/flowBasic/pom.xml | 76 --- .../integration/test_1/CompleterFunction.java | 34 - .../funcs/flowBasicJDK8/Dockerfile | 11 - .../funcs/flowBasicJDK8/func.yaml | 23 - integration-tests/funcs/flowBasicJDK8/pom.xml | 75 --- .../integration/test_1/CompleterFunction.java | 34 - .../funcs/flowExitHooks/Dockerfile | 11 - .../funcs/flowExitHooks/func.yaml | 23 - integration-tests/funcs/flowExitHooks/pom.xml | 94 --- .../integration/test_5/CompleterFunction.java | 61 -- .../funcs/flowTimeouts/Dockerfile | 11 - .../funcs/flowTimeouts/func.yaml | 23 - integration-tests/funcs/flowTimeouts/pom.xml | 93 --- .../integration/test_6/CompleterFunction.java | 43 -- integration-tests/funcs/helloFunc/Dockerfile | 11 - .../funcs/helloFunc/func-proto.yaml | 22 - integration-tests/funcs/helloFunc/pom.xml | 86 --- .../fn/integration/hello/HelloFunction.java | 24 - integration-tests/funcs/httpgwfunc/Dockerfile | 11 - integration-tests/funcs/httpgwfunc/func.yaml | 27 - integration-tests/funcs/httpgwfunc/pom.xml | 78 --- .../java/com/example/fn/TriggerFunction.java | 43 -- .../com/example/fn/TriggerFunctionTest.java | 56 -- integration-tests/funcs/simpleFunc/Dockerfile | 11 - integration-tests/funcs/simpleFunc/func.yaml | 23 - integration-tests/funcs/simpleFunc/pom.xml | 84 --- .../fn/integration/test2/PlainFunction.java | 38 -- .../integration/test2/PlainFunctionTest.java | 46 -- integration-tests/pom.xml | 100 --- integration-tests/run_tests_ci.sh | 114 ---- .../integrationtest/IntegrationTestRule.java | 421 ------------- .../fn/integrationtest/FlowTest.java | 124 ---- .../fn/integrationtest/FunctionsTest.java | 167 ----- release.version | 2 +- runtime/src/main/c/CMakeLists.txt | 3 + 77 files changed, 4 insertions(+), 4101 deletions(-) delete mode 100644 .circleci/config.yml delete mode 100755 .circleci/fix-java-for-surefire.sh delete mode 100755 .circleci/install-docker.sh delete mode 100755 .circleci/install-fn.sh delete mode 100644 .circleci/lib.sh delete mode 100644 .circleci/maven-settings.xml delete mode 100755 .circleci/release.sh delete mode 100755 .circleci/update-versions.sh delete mode 100755 build.sh delete mode 100644 images/build-native/Dockerfile delete mode 100644 images/build-native/README.md delete mode 100755 images/build-native/docker-build.sh delete mode 100644 images/build/Dockerfile delete mode 100644 images/build/Dockerfile-jdk11 delete mode 100755 images/build/cache-deps.sh delete mode 100755 images/build/docker-build.sh delete mode 100644 images/build/local-settings.xml delete mode 100644 images/build/pom.xml delete mode 100644 images/build/src/main/java/com/example/fn/HelloFunction.java delete mode 100644 images/build/src/test/java/com/example/fn/HelloFunctionTest.java delete mode 100644 images/init-native/Dockerfile delete mode 100644 images/init-native/Dockerfile-init-image delete mode 100644 images/init-native/README.md delete mode 100755 images/init-native/docker-build.sh delete mode 100644 images/init-native/func.init.yaml delete mode 100644 images/init-native/pom.xml delete mode 100644 images/init-native/src/main/java/com/example/fn/HelloFunction.java delete mode 100644 images/init-native/src/main/resources/META-INF/native-image/fnfunction/reflect-config.json delete mode 100644 images/init-native/src/test/java/com/example/fn/HelloFunctionTest.java delete mode 100644 images/runtime/Dockerfile delete mode 100644 images/runtime/Dockerfile-jre11 delete mode 100644 images/runtime/README.md delete mode 100644 integration-tests/README.md delete mode 100644 integration-tests/fnserver.env delete mode 100644 integration-tests/funcs/flowAllFeatures/Dockerfile delete mode 100644 integration-tests/funcs/flowAllFeatures/README.md delete mode 100644 integration-tests/funcs/flowAllFeatures/func.yaml delete mode 100644 integration-tests/funcs/flowAllFeatures/pom.xml delete mode 100644 integration-tests/funcs/flowAllFeatures/src/main/java/com/fnproject/fn/integration/ExerciseEverything.java delete mode 100644 integration-tests/funcs/flowAllFeatures/src/main/java/com/fnproject/fn/integration/Test.java delete mode 100644 integration-tests/funcs/flowBasic/Dockerfile delete mode 100644 integration-tests/funcs/flowBasic/func.yaml delete mode 100644 integration-tests/funcs/flowBasic/pom.xml delete mode 100644 integration-tests/funcs/flowBasic/src/main/java/com/fnproject/fn/integration/test_1/CompleterFunction.java delete mode 100644 integration-tests/funcs/flowBasicJDK8/Dockerfile delete mode 100644 integration-tests/funcs/flowBasicJDK8/func.yaml delete mode 100644 integration-tests/funcs/flowBasicJDK8/pom.xml delete mode 100644 integration-tests/funcs/flowBasicJDK8/src/main/java/com/fnproject/fn/integration/test_1/CompleterFunction.java delete mode 100644 integration-tests/funcs/flowExitHooks/Dockerfile delete mode 100644 integration-tests/funcs/flowExitHooks/func.yaml delete mode 100644 integration-tests/funcs/flowExitHooks/pom.xml delete mode 100644 integration-tests/funcs/flowExitHooks/src/main/java/com/fnproject/fn/integration/test_5/CompleterFunction.java delete mode 100644 integration-tests/funcs/flowTimeouts/Dockerfile delete mode 100644 integration-tests/funcs/flowTimeouts/func.yaml delete mode 100644 integration-tests/funcs/flowTimeouts/pom.xml delete mode 100644 integration-tests/funcs/flowTimeouts/src/main/java/com/fnproject/fn/integration/test_6/CompleterFunction.java delete mode 100644 integration-tests/funcs/helloFunc/Dockerfile delete mode 100644 integration-tests/funcs/helloFunc/func-proto.yaml delete mode 100644 integration-tests/funcs/helloFunc/pom.xml delete mode 100644 integration-tests/funcs/helloFunc/src-proto/main/java/com/fnproject/fn/integration/hello/HelloFunction.java delete mode 100644 integration-tests/funcs/httpgwfunc/Dockerfile delete mode 100644 integration-tests/funcs/httpgwfunc/func.yaml delete mode 100644 integration-tests/funcs/httpgwfunc/pom.xml delete mode 100644 integration-tests/funcs/httpgwfunc/src/main/java/com/example/fn/TriggerFunction.java delete mode 100644 integration-tests/funcs/httpgwfunc/src/test/java/com/example/fn/TriggerFunctionTest.java delete mode 100644 integration-tests/funcs/simpleFunc/Dockerfile delete mode 100644 integration-tests/funcs/simpleFunc/func.yaml delete mode 100644 integration-tests/funcs/simpleFunc/pom.xml delete mode 100644 integration-tests/funcs/simpleFunc/src/main/java/com/fnproject/fn/integration/test2/PlainFunction.java delete mode 100644 integration-tests/funcs/simpleFunc/src/test/java/com/fnproject/fn/integration/test2/PlainFunctionTest.java delete mode 100644 integration-tests/pom.xml delete mode 100755 integration-tests/run_tests_ci.sh delete mode 100644 integration-tests/src/main/java/com/fnproject/fn/integrationtest/IntegrationTestRule.java delete mode 100644 integration-tests/src/test/java/com/fnproject/fn/integrationtest/FlowTest.java delete mode 100644 integration-tests/src/test/java/com/fnproject/fn/integrationtest/FunctionsTest.java diff --git a/.circleci/config.yml b/.circleci/config.yml deleted file mode 100644 index c6cbbbeb..00000000 --- a/.circleci/config.yml +++ /dev/null @@ -1,61 +0,0 @@ -version: 2 -jobs: - build: - working_directory: ~/fn-java-fdk - machine: - image: ubuntu-1604:202101-01 - environment: - # store_artifacts doesn't shell substitute so the variable - # definitions are duplicated in those steps too. - FDK_ARTIFACT_DIR: /tmp/artifacts/fdk - TEST_ARTIFACT_DIR: /tmp/artifacts/tests - REPOSITORY_LOCATION: /tmp/staging_repo - steps: - - checkout - - run: - name: Update Docker to latest - command: ./.circleci/install-docker.sh - - run: - name: Import GPG Owner Trust - command: echo $GPG_OWNERTRUST | base64 --decode | gpg --import-ownertrust - - run: - name: Import GPG key - command: echo $GPG_SECRET_KEYS | base64 --decode | gpg --import --no-tty --batch --yes - - run: - name: Install fn binary (as it is needed for the integration tests) - command: ./.circleci/install-fn.sh - - run: - name: Workaround for https://issues.apache.org/jira/browse/SUREFIRE-1588 - command: ./.circleci/fix-java-for-surefire.sh - - run: - name: Install junit-merge - command: npm install -g junit-merge - - run: - name: Set release to latest branch version - command: | - git checkout origin/${CIRCLE_BRANCH} release.version - echo next release version is $(cat release.version) - - run: - name: Determine the release version - command: ./.circleci/update-versions.sh - - run: - name: Build and Test FDK - command: | - export FN_FDK_VERSION=$(cat ./release.version) - export GRAALVM_VERSION=$(cat ./graalvm.version) - ./build.sh - - run: - name: Run integration tests - command: | - export FN_JAVA_FDK_VERSION=$(cat release.version) - ./integration-tests/run_tests_ci.sh - timeout: 1200 - - run: - name: Gather test results - when: always - command: | - junit-merge $(find . -wholename "*/target/surefire-reports/*.xml") --createDir -o test_results/merged_results.xml - - store_test_results: - when: always - path: test_results - diff --git a/.circleci/fix-java-for-surefire.sh b/.circleci/fix-java-for-surefire.sh deleted file mode 100755 index 2ca4cd25..00000000 --- a/.circleci/fix-java-for-surefire.sh +++ /dev/null @@ -1,5 +0,0 @@ -#!/usr/bin/env bash - - set -ex - - cp ./.circleci/maven-settings.xml $HOME/.m2/settings.xml diff --git a/.circleci/install-docker.sh b/.circleci/install-docker.sh deleted file mode 100755 index 688d53a1..00000000 --- a/.circleci/install-docker.sh +++ /dev/null @@ -1,8 +0,0 @@ -#!/usr/bin/env bash - -set -ex - -docker version || true -sudo service docker stop || true -curl -fsSL https://get.docker.com/ | sudo sh -docker version diff --git a/.circleci/install-fn.sh b/.circleci/install-fn.sh deleted file mode 100755 index 615a4ff7..00000000 --- a/.circleci/install-fn.sh +++ /dev/null @@ -1,24 +0,0 @@ -#!/usr/bin/env bash -set -ex - -source "$(dirname $0)/lib.sh" - -check_command_exists jq -check_command_exists git - -: "${FN_CLI_BINARY:=fn_linux}" -: "${INSTALL_DIR:=/usr/local/bin}" - -FN_BINARY_LOCATION="$(\ - curl -s https://api.github.com/repos/fnproject/cli/releases/latest \ - | jq -r ".assets[] \ - | select(.name | test(\"${FN_CLI_BINARY}\")) \ - | .browser_download_url"\ -)" - -echo "Download fn from $FN_BINARY_LOCATION" -# --location = follow redirects -curl -f --location "$FN_BINARY_LOCATION" --output fn -chmod +x fn -./fn || true # show fn version -sudo cp fn "${INSTALL_DIR}/fn" diff --git a/.circleci/lib.sh b/.circleci/lib.sh deleted file mode 100644 index d6c3e1fe..00000000 --- a/.circleci/lib.sh +++ /dev/null @@ -1,6 +0,0 @@ -check_command_exists() { - local command="$1"; shift - if ! command -v "$command" 2>&1 > /dev/null; then - echo "'$command' is not installed, please install it" >&2 - fi -} diff --git a/.circleci/maven-settings.xml b/.circleci/maven-settings.xml deleted file mode 100644 index 4a004862..00000000 --- a/.circleci/maven-settings.xml +++ /dev/null @@ -1,50 +0,0 @@ - - - - - - - - - - - ossrh - ${env.SERVER_OSSRH_USERNAME} - ${env.SERVER_OSSRH_PASSWORD} - - - - - - maven-default-http-blocker - external:http:* - Pseudo repository to mirror external repositories initially using HTTP. - http://0.0.0.0/ - true - - - - - - SUREFIRE-1588 - - true - - - -Djdk.net.URLClassPath.disableClassPathURLCheck=true - - - - ossrh - - true - - - gpg - ${env.GPG_PASSPHRASE} - - - - \ No newline at end of file diff --git a/.circleci/release.sh b/.circleci/release.sh deleted file mode 100755 index 61c33d82..00000000 --- a/.circleci/release.sh +++ /dev/null @@ -1,115 +0,0 @@ -#!/bin/bash - -set -e -USER=fnproject - -SERVICE=fn-java-fdk -RUNTIME_IMAGE=${SERVICE} -BUILD_IMAGE=${SERVICE}-build -NATIVE_BUILD_IMAGE=fn-java-native -NATIVE_INIT_IMAGE=${NATIVE_BUILD_IMAGE}-init - -release_version=$(cat release.version) -if [[ ${release_version} =~ ^[0-9]+\.[0-9]+\.[0-9]+$ ]] ; then - echo "Deploying version $release_version" -else - echo Invalid version $release_version - exit 1 -fi - -graalvm_version=$(cat graalvm.version) - -# Calculate new version -version_parts=(${release_version//./ }) -new_minor=$((${version_parts[2]}+1)) -new_version="${version_parts[0]}.${version_parts[1]}.$new_minor" - -if [[ ${new_version} =~ ^[0-9]+\.[0-9]+\.[0-9]+$ ]] ; then - echo "Next version $new_version" -else - echo Invalid new version ${new_version} - exit 1 -fi - -# Push result to git - -echo ${new_version} > release.version -git tag -a "$release_version" -m "version $release_version" -git add release.version -git commit -m "$SERVICE: post-$release_version version bump [skip ci]" -git push -git push origin "$release_version" - - -# Regenerate runtime and build images and push them -( - moving_version=${release_version%.*}-latest - - ## jdk8 runtime - docker tag ${USER}/${RUNTIME_IMAGE}:${release_version} ${USER}/${RUNTIME_IMAGE}:latest - docker tag ${USER}/${RUNTIME_IMAGE}:${release_version} ${USER}/${RUNTIME_IMAGE}:${moving_version} - docker push ${USER}/${RUNTIME_IMAGE}:latest - docker push ${USER}/${RUNTIME_IMAGE}:${release_version} - docker push ${USER}/${RUNTIME_IMAGE}:${moving_version} - - ## jdk8 build - docker tag ${USER}/${BUILD_IMAGE}:${release_version} ${USER}/${BUILD_IMAGE}:latest - docker tag ${USER}/${BUILD_IMAGE}:${release_version} ${USER}/${BUILD_IMAGE}:${moving_version} - docker push ${USER}/${BUILD_IMAGE}:latest - docker push ${USER}/${BUILD_IMAGE}:${release_version} - docker push ${USER}/${BUILD_IMAGE}:${moving_version} - - ## jre11 runtime - docker tag ${USER}/${RUNTIME_IMAGE}:jre11-${release_version} ${USER}/${RUNTIME_IMAGE}:jre11-latest - docker tag ${USER}/${RUNTIME_IMAGE}:jre11-${release_version} ${USER}/${RUNTIME_IMAGE}:jre11-${moving_version} - docker push ${USER}/${RUNTIME_IMAGE}:jre11-latest - docker push ${USER}/${RUNTIME_IMAGE}:jre11-${release_version} - docker push ${USER}/${RUNTIME_IMAGE}:jre11-${moving_version} - - ## jdk11 build - docker tag ${USER}/${BUILD_IMAGE}:jdk11-${release_version} ${USER}/${BUILD_IMAGE}:jdk11-latest - docker tag ${USER}/${BUILD_IMAGE}:jdk11-${release_version} ${USER}/${BUILD_IMAGE}:jdk11-${moving_version} - docker push ${USER}/${BUILD_IMAGE}:jdk11-latest - docker push ${USER}/${BUILD_IMAGE}:jdk11-${release_version} - docker push ${USER}/${BUILD_IMAGE}:jdk11-${moving_version} - - ## native jdk8 build image - docker tag ${USER}/${NATIVE_BUILD_IMAGE}:${release_version} ${USER}/${NATIVE_BUILD_IMAGE}:latest - docker tag ${USER}/${NATIVE_BUILD_IMAGE}:${release_version} ${USER}/${NATIVE_BUILD_IMAGE}:${moving_version} - docker tag ${USER}/${NATIVE_BUILD_IMAGE}:${release_version} ${USER}/${NATIVE_BUILD_IMAGE}:${release_version}-graalvm-ce-${graalvm_version} - docker push ${USER}/${NATIVE_BUILD_IMAGE}:latest - docker push ${USER}/${NATIVE_BUILD_IMAGE}:${release_version} - docker push ${USER}/${NATIVE_BUILD_IMAGE}:${moving_version} - docker push ${USER}/${NATIVE_BUILD_IMAGE}:${release_version}-graalvm-ce-${graalvm_version} - - ## native jdk11 build image - docker tag ${USER}/${NATIVE_BUILD_IMAGE}:jdk11-${release_version} ${USER}/${NATIVE_BUILD_IMAGE}:jdk11-latest - docker tag ${USER}/${NATIVE_BUILD_IMAGE}:jdk11-${release_version} ${USER}/${NATIVE_BUILD_IMAGE}:jdk11-${moving_version} - docker tag ${USER}/${NATIVE_BUILD_IMAGE}:jdk11-${release_version} ${USER}/${NATIVE_BUILD_IMAGE}:jdk11-${release_version}-graalvm-ce-${graalvm_version} - docker push ${USER}/${NATIVE_BUILD_IMAGE}:jdk11-latest - docker push ${USER}/${NATIVE_BUILD_IMAGE}:jdk11-${release_version} - docker push ${USER}/${NATIVE_BUILD_IMAGE}:jdk11-${moving_version} - docker push ${USER}/${NATIVE_BUILD_IMAGE}:jdk11-${release_version}-graalvm-ce-${graalvm_version} - - ## jdk8 native init image - docker tag ${USER}/${NATIVE_INIT_IMAGE}:${release_version} ${USER}/${NATIVE_INIT_IMAGE}:latest - docker tag ${USER}/${NATIVE_INIT_IMAGE}:${release_version} ${USER}/${NATIVE_INIT_IMAGE}:${moving_version} - docker tag ${USER}/${NATIVE_INIT_IMAGE}:${release_version} ${USER}/${NATIVE_INIT_IMAGE}:${release_version}-graalvm-ce-${graalvm_version} - docker push ${USER}/${NATIVE_INIT_IMAGE}:latest - docker push ${USER}/${NATIVE_INIT_IMAGE}:${release_version} - docker push ${USER}/${NATIVE_INIT_IMAGE}:${moving_version} - docker push ${USER}/${NATIVE_INIT_IMAGE}:${release_version}-graalvm-ce-${graalvm_version} - - ## jdk11 native init image - docker tag ${USER}/${NATIVE_INIT_IMAGE}:jdk11-${release_version} ${USER}/${NATIVE_INIT_IMAGE}:jdk11-latest - docker tag ${USER}/${NATIVE_INIT_IMAGE}:jdk11-${release_version} ${USER}/${NATIVE_INIT_IMAGE}:jdk11-${moving_version} - docker tag ${USER}/${NATIVE_INIT_IMAGE}:jdk11-${release_version} ${USER}/${NATIVE_INIT_IMAGE}:jdk11-${release_version}-graalvm-ce-${graalvm_version} - docker push ${USER}/${NATIVE_INIT_IMAGE}:jdk11-latest - docker push ${USER}/${NATIVE_INIT_IMAGE}:jdk11-${release_version} - docker push ${USER}/${NATIVE_INIT_IMAGE}:jdk11-${moving_version} - docker push ${USER}/${NATIVE_INIT_IMAGE}:jdk11-${release_version}-graalvm-ce-${graalvm_version} -) - - -# Deploy to Maven Central OSSRH -mvn -DskipTests clean deploy -Pci-cd -Dauto.release=true diff --git a/.circleci/update-versions.sh b/.circleci/update-versions.sh deleted file mode 100755 index 394a3b76..00000000 --- a/.circleci/update-versions.sh +++ /dev/null @@ -1,24 +0,0 @@ -#!/bin/bash -# -# this is instead for the maven release plugin (which sucks) - this sets the versions across the project before a build -# for branch builds these are ignored (nothing is deployed) -# For master releases this sets the latest version that this branch would be released as -# - -release_version=$(cat release.version) -if [[ $release_version =~ ^[0-9]+\.[0-9]+\.[0-9]+$ ]] ; then - echo "Deploying version $release_version" -else - echo Invalid version $release_version - exit 1 -fi - -mvn versions:set -D newVersion=${release_version} versions:update-child-modules - - -# We need to replace the example dependency versions also -# (sed syntax for portability between MacOS and gnu) -find . -name pom.xml | - xargs -n 1 sed -i.bak -e "s|.*|${release_version}|" -find . -name pom.xml.bak -delete - diff --git a/build.sh b/build.sh deleted file mode 100755 index fc8f976e..00000000 --- a/build.sh +++ /dev/null @@ -1,62 +0,0 @@ -#!/usr/bin/env bash -# -# Copyright (c) 2019, 2020 Oracle and/or its affiliates. All rights reserved. -# -# 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. -# - -set -e -set -x -mkdir -p /tmp/staging_repo -rm -rf /tmp/staging_repo/* - -BUILD_VERSION=${FN_FDK_VERSION:-1.0.0-SNAPSHOT} -export BUILD_VERSION -export REPOSITORY_LOCATION=${REPOSITORY_LOCATION:-/tmp/staging_repo} - -( - runtime/src/main/c/rebuild_so.sh -) - -mvn -B deploy -DaltDeploymentRepository=localStagingDir::default::file://${REPOSITORY_LOCATION} - -( - cd images/build - ./docker-build.sh --no-cache -t fnproject/fn-java-fdk-build:${BUILD_VERSION} . -) - -( - cd images/build - ./docker-build.sh --no-cache -f Dockerfile-jdk11 -t fnproject/fn-java-fdk-build:jdk11-${BUILD_VERSION} . -) - -( - cd runtime - docker build --no-cache -t fnproject/fn-java-fdk:${BUILD_VERSION} -f ../images/runtime/Dockerfile . -) - -( - cd runtime - docker build --no-cache -f ../images/runtime/Dockerfile-jre11 -t fnproject/fn-java-fdk:jre11-${BUILD_VERSION} . -) - -( - workdir=$(pwd)/runtime - cd images/build-native - ./docker-build.sh ${workdir} -) - -( - cd images/init-native - ./docker-build.sh -) diff --git a/images/build-native/Dockerfile b/images/build-native/Dockerfile deleted file mode 100644 index 509de251..00000000 --- a/images/build-native/Dockerfile +++ /dev/null @@ -1,20 +0,0 @@ -# -# Copyright (c) 2019, 2020 Oracle and/or its affiliates. All rights reserved. -# -# 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. -# -ARG GRAALVM_VERSION -FROM ghcr.io/graalvm/graalvm-ce:${GRAALVM_VERSION} - -RUN gu install native-image -COPY src/main/c/libfnunixsocket.so /function/runtime/lib/ diff --git a/images/build-native/README.md b/images/build-native/README.md deleted file mode 100644 index 320b04d1..00000000 --- a/images/build-native/README.md +++ /dev/null @@ -1,5 +0,0 @@ -# Native Build image - -This rebuilds the GraalVM native image build image - -To update the build image, make a change to `../../graalvm.version` \ No newline at end of file diff --git a/images/build-native/docker-build.sh b/images/build-native/docker-build.sh deleted file mode 100755 index 8cadcec5..00000000 --- a/images/build-native/docker-build.sh +++ /dev/null @@ -1,61 +0,0 @@ -#!/bin/sh -# -# Copyright (c) 2019, 2020 Oracle and/or its affiliates. All rights reserved. -# -# 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. -# - -if [ -z "$1" ] -then - echo "Needs runtime folder as an argument" - exit 1 -fi - -set -ex - -# If not defined, read the FDK and GraalVM versions -BUILD_VERSION=${BUILD_VERSION:-1.0.0-SNAPSHOT} - -if [ -z "${GRAALVM_VERSION}" ]; then - GRAALVM_VERSION=$(cat ../../graalvm.version) -fi - -# The path to the FDK runtime root folder -fdk_runtime_root=${1} - -dockerfiledir=$(pwd) - -# Build the Dockerfiles in the runtime root--it pulls in needed libs -cd ${fdk_runtime_root} - -# Build JDK 8 -native_image="fnproject/fn-java-native:${BUILD_VERSION}" -if docker pull ${native_image} ; then - echo ${native_image} already exists, skipping native build -else - ( - docker build -f ${dockerfiledir}/Dockerfile --build-arg GRAALVM_VERSION="java8-${GRAALVM_VERSION}" -t "${native_image}" . - ) - echo "${native_image}" > native_build.image -fi - -# Build JDK 11 -native_image="fnproject/fn-java-native:jdk11-${BUILD_VERSION}" -if docker pull ${native_image} ; then - echo ${native_image} already exists, skipping native build -else - ( - docker build -f ${dockerfiledir}/Dockerfile --build-arg GRAALVM_VERSION="java11-${GRAALVM_VERSION}" -t "${native_image}" . - ) - echo "${native_image}" > native_build_11.image -fi diff --git a/images/build/Dockerfile b/images/build/Dockerfile deleted file mode 100644 index e5aed9e2..00000000 --- a/images/build/Dockerfile +++ /dev/null @@ -1,24 +0,0 @@ -# -# Copyright (c) 2019, 2020 Oracle and/or its affiliates. All rights reserved. -# -# 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. -# - -FROM maven:3-jdk-8-slim -ARG FN_REPO_URL -ADD pom.xml /tmp/cache-deps/pom.xml -ADD local-settings.xml /tmp/cache-deps/local-settings.xml -ADD cache-deps.sh /tmp/cache-deps/cache-deps.sh -ADD src /tmp/cache-deps/src - -RUN /tmp/cache-deps/cache-deps.sh diff --git a/images/build/Dockerfile-jdk11 b/images/build/Dockerfile-jdk11 deleted file mode 100644 index 0e5c2bab..00000000 --- a/images/build/Dockerfile-jdk11 +++ /dev/null @@ -1,25 +0,0 @@ -# -# Copyright (c) 2019, 2020 Oracle and/or its affiliates. All rights reserved. -# -# 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. -# - -FROM maven:3-jdk-11-slim - -ARG FN_REPO_URL - -ADD pom.xml /tmp/cache-deps/pom.xml -ADD local-settings.xml /tmp/cache-deps/local-settings.xml -ADD cache-deps.sh /tmp/cache-deps/cache-deps.sh -ADD src /tmp/cache-deps/src -RUN /tmp/cache-deps/cache-deps.sh diff --git a/images/build/cache-deps.sh b/images/build/cache-deps.sh deleted file mode 100755 index 47a1c32b..00000000 --- a/images/build/cache-deps.sh +++ /dev/null @@ -1,28 +0,0 @@ -#!/bin/bash -ex -# -# Copyright (c) 2019, 2020 Oracle and/or its affiliates. All rights reserved. -# -# 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. -# - - -set -x -set -e - -if [ -n "$FN_REPO_URL" ]; then - REPO_DFN="-Dfn.repo.url=$FN_REPO_URL" -fi - -sed -i "s#___FN_REPO_URL___#${FN_REPO_URL}#g" /tmp/cache-deps/local-settings.xml -cd /tmp/cache-deps && mvn -s /tmp/cache-deps/local-settings.xml test package dependency:copy-dependencies -Dmdep.prependGroupId=true -DoutputDirectory=target $REPO_DFN -cd / && rm -fr /tmp/cache-deps diff --git a/images/build/docker-build.sh b/images/build/docker-build.sh deleted file mode 100755 index eaa78a5e..00000000 --- a/images/build/docker-build.sh +++ /dev/null @@ -1,37 +0,0 @@ -#!/bin/bash -ex -# -# Copyright (c) 2019, 2020 Oracle and/or its affiliates. All rights reserved. -# -# 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. -# - -if [ -z ${REPOSITORY_LOCATION} ] ; then - echo no REPOSITORY_LOCATION set - exit 1; -fi - -docker rm -f fn_mvn_repo || true -docker run -d \ - -v "${REPOSITORY_LOCATION}":/repo:ro \ - -w /repo \ - --name fn_mvn_repo \ - python:2.7 \ - python -mSimpleHTTPServer 18080 - - -DOCKER_LOCALHOST=$(docker inspect --type container -f '{{.NetworkSettings.IPAddress}}' fn_mvn_repo) -REPO_ENV="--build-arg FN_REPO_URL=http://${DOCKER_LOCALHOST}:18080" - -docker build $REPO_ENV $* - -docker rm -f fn_mvn_repo \ No newline at end of file diff --git a/images/build/local-settings.xml b/images/build/local-settings.xml deleted file mode 100644 index a6ba37c2..00000000 --- a/images/build/local-settings.xml +++ /dev/null @@ -1,23 +0,0 @@ - - - - - - - - - - - - override-maven-default-http-blocker - external:http:* - Pseudo repository to mirror external repositories initially using HTTP. - ___FN_REPO_URL___ - false - - - - - diff --git a/images/build/pom.xml b/images/build/pom.xml deleted file mode 100644 index 5adb2b8c..00000000 --- a/images/build/pom.xml +++ /dev/null @@ -1,110 +0,0 @@ - - - - - 4.0.0 - - - - UTF-8 - UTF-8 - - 1.0.0-SNAPSHOT - http://172.17.0.1:18080 - - - - - com.fnproject.fn - build-image - 1.0.0 - - - - com.fnproject.fn - api - ${fdk.version} - - - com.fnproject.fn - experimental-native-image-support - ${fdk.version} - - - com.fnproject.fn - testing-core - ${fdk.version} - test - - - com.fnproject.fn - testing-junit4 - ${fdk.version} - test - - - junit - junit - 4.13.1 - - - - - - - org.apache.maven.plugins - maven-compiler-plugin - 3.8.0 - - 1.8 - 1.8 - - - - org.apache.maven.plugins - maven-surefire-plugin - 2.22.1 - - false - - - - org.apache.maven.plugins - maven-deploy-plugin - 2.8.2 - - true - - - - - - - - - fn-maven-releases - ${fn.repo.url} - - - diff --git a/images/build/src/main/java/com/example/fn/HelloFunction.java b/images/build/src/main/java/com/example/fn/HelloFunction.java deleted file mode 100644 index e1b10b7a..00000000 --- a/images/build/src/main/java/com/example/fn/HelloFunction.java +++ /dev/null @@ -1,27 +0,0 @@ -/* - * Copyright (c) 2019, 2020 Oracle and/or its affiliates. All rights reserved. - * - * 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. - */ - -package com.example.fn; - -public class HelloFunction { - - public String handleRequest(String input) { - String name = (input == null || input.isEmpty()) ? "world" : input; - - return "Hello, " + name + "!"; - } - -} \ No newline at end of file diff --git a/images/build/src/test/java/com/example/fn/HelloFunctionTest.java b/images/build/src/test/java/com/example/fn/HelloFunctionTest.java deleted file mode 100644 index a5da7b66..00000000 --- a/images/build/src/test/java/com/example/fn/HelloFunctionTest.java +++ /dev/null @@ -1,40 +0,0 @@ -/* - * Copyright (c) 2019, 2020 Oracle and/or its affiliates. All rights reserved. - * - * 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. - */ - -package com.example.fn; - -import com.fnproject.fn.testing.FnResult; -import com.fnproject.fn.testing.FnTestingRule; -import org.junit.Rule; -import org.junit.Test; - -import static org.junit.Assert.*; - -public class HelloFunctionTest { - - @Rule - public final FnTestingRule testing = FnTestingRule.createDefault(); - - @Test - public void shouldReturnGreeting() { - testing.givenEvent().enqueue(); - testing.thenRun(HelloFunction.class, "handleRequest"); - - FnResult result = testing.getOnlyResult(); - assertEquals("Hello, world!", result.getBodyAsString()); - } - -} \ No newline at end of file diff --git a/images/init-native/Dockerfile b/images/init-native/Dockerfile deleted file mode 100644 index 3fcfc41e..00000000 --- a/images/init-native/Dockerfile +++ /dev/null @@ -1,46 +0,0 @@ -# -# Copyright (c) 2019, 2020 Oracle and/or its affiliates. All rights reserved. -# -# 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. -# - -FROM fnproject/fn-java-fdk-build:##FN_FDK_VERSION## as build -WORKDIR /function -ENV MAVEN_OPTS=-Dmaven.repo.local=/usr/share/maven/ref/repository -ADD pom.xml pom.xml -RUN ["mvn", "package", "dependency:copy-dependencies", "-DincludeScope=runtime", "-DskipTests=true", "-Dmdep.prependGroupId=true", "-DoutputDirectory=target"] -ADD src src -RUN ["mvn", "package"] - -FROM fnproject/fn-java-native:##FN_FDK_VERSION## as build-native-image -WORKDIR /function -COPY --from=build /function/target/*.jar target/ - -RUN /usr/bin/native-image \ - --static \ - --no-fallback \ - --allow-incomplete-classpath \ - --enable-all-security-services \ - --enable-url-protocols=https,http \ - --report-unsupported-elements-at-runtime \ - -H:Name=func \ - -classpath "target/*"\ - com.fnproject.fn.runtime.EntryPoint - - -FROM busybox:glibc -WORKDIR /function -COPY --from=build-native-image /function/func func -COPY --from=build-native-image /function/runtime/lib/* . -ENTRYPOINT ["./func", "-XX:MaximumHeapSizePercent=80"] -CMD [ "com.example.fn.HelloFunction::handleRequest" ] diff --git a/images/init-native/Dockerfile-init-image b/images/init-native/Dockerfile-init-image deleted file mode 100644 index 8e0d73bf..00000000 --- a/images/init-native/Dockerfile-init-image +++ /dev/null @@ -1,40 +0,0 @@ -# -# Copyright (c) 2019, 2020 Oracle and/or its affiliates. All rights reserved. -# -# 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. -# - -FROM alpine:latest - -WORKDIR /build -COPY src src -COPY pom.xml . -COPY func.init.yaml . -COPY Dockerfile.build Dockerfile - -RUN echo $'#!/bin/sh\n\ -if [ -n ${FN_FUNCTION_NAME} ]\n\ - then\n\ - JAVA_NAME=$(echo ${FN_FUNCTION_NAME:0:1} | tr "[:lower:]" "[:upper:]")${FN_FUNCTION_NAME:1}\n\ - sed -i -e "s|hello|${FN_FUNCTION_NAME}|" pom.xml\n\ - sed -i -e "s|com.example.fn.HelloFunction|com.example.fn.${JAVA_NAME}|" Dockerfile\n\ - sed -i -e "s|com.example.fn.HelloFunction|com.example.fn.${JAVA_NAME}|" src/main/resources/META-INF/native-image/fnfunction/reflect-config.json\n\ - sed -i -e "s|HelloFunction|${JAVA_NAME}|" src/main/java/com/example/fn/HelloFunction.java\n\ - mv src/main/java/com/example/fn/HelloFunction.java "src/main/java/com/example/fn/${JAVA_NAME}.java"\n\ - sed -i -e "s|HelloFunction|${JAVA_NAME}|" src/test/java/com/example/fn/HelloFunctionTest.java\n\ - mv src/test/java/com/example/fn/HelloFunctionTest.java "src/test/java/com/example/fn/${JAVA_NAME}Test.java"\n\ -fi\n\ -tar c src pom.xml func.init.yaml Dockerfile\n' > build_init_image.sh \ - && chmod 755 build_init_image.sh - -CMD ["./build_init_image.sh"] diff --git a/images/init-native/README.md b/images/init-native/README.md deleted file mode 100644 index 080f648f..00000000 --- a/images/init-native/README.md +++ /dev/null @@ -1,2 +0,0 @@ -# Native init image - diff --git a/images/init-native/docker-build.sh b/images/init-native/docker-build.sh deleted file mode 100755 index 30610cd9..00000000 --- a/images/init-native/docker-build.sh +++ /dev/null @@ -1,38 +0,0 @@ -#!/bin/sh -# -# Copyright (c) 2019, 2020 Oracle and/or its affiliates. All rights reserved. -# -# 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. -# - -BUILD_VERSION=${BUILD_VERSION:-1.0.0-SNAPSHOT} - -set -e - -# Update pom.xml with current FDK version -sed -i.bak -e "s|.*|${BUILD_VERSION}|" pom.xml && rm pom.xml.bak - -# Create Dockerfile with current FDK build tag (Java 8) -cp Dockerfile Dockerfile.build -sed -i.bak -e "s|##FN_FDK_VERSION##|${BUILD_VERSION}|" Dockerfile.build && rm Dockerfile.build.bak - -# Build init image packaging created Dockerfile (Java 8) -docker build -t fnproject/fn-java-native-init:${BUILD_VERSION} -f Dockerfile-init-image . - -# Create Dockerfile with current FDK build tag (Java 11) -cp Dockerfile Dockerfile.build -sed -i.bak -e "s|##FN_FDK_VERSION##|jdk11-${BUILD_VERSION}|" Dockerfile.build && rm Dockerfile.build.bak - -# Build init image packaging created Dockerfile (Java 11) -docker build -t fnproject/fn-java-native-init:jdk11-${BUILD_VERSION} -f Dockerfile-init-image . -rm Dockerfile.build diff --git a/images/init-native/func.init.yaml b/images/init-native/func.init.yaml deleted file mode 100644 index 4d0c5b62..00000000 --- a/images/init-native/func.init.yaml +++ /dev/null @@ -1,16 +0,0 @@ -# -# Copyright (c) 2019, 2020 Oracle and/or its affiliates. All rights reserved. -# -# 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. -# - diff --git a/images/init-native/pom.xml b/images/init-native/pom.xml deleted file mode 100644 index f0664d10..00000000 --- a/images/init-native/pom.xml +++ /dev/null @@ -1,106 +0,0 @@ - - - - - 4.0.0 - - UTF-8 - 1.0.0-SNAPSHOT - - com.example.fn - hello - 1.0.0 - - - - fn-release-repo - https://dl.bintray.com/fnproject/fnproject - - true - - - false - - - - - - - com.fnproject.fn - api - ${fdk.version} - - - com.fnproject.fn - testing-core - ${fdk.version} - test - - - com.fnproject.fn - testing-junit4 - ${fdk.version} - test - - - junit - junit - 4.13.1 - test - - - com.fnproject.fn - runtime - ${fdk.version} - runtime - - - - - - - org.apache.maven.plugins - maven-compiler-plugin - 3.3 - - 1.8 - 1.8 - - - - org.apache.maven.plugins - maven-surefire-plugin - 2.22.1 - - false - - - - org.apache.maven.plugins - maven-deploy-plugin - 2.8.2 - - true - - - - - diff --git a/images/init-native/src/main/java/com/example/fn/HelloFunction.java b/images/init-native/src/main/java/com/example/fn/HelloFunction.java deleted file mode 100644 index e1b10b7a..00000000 --- a/images/init-native/src/main/java/com/example/fn/HelloFunction.java +++ /dev/null @@ -1,27 +0,0 @@ -/* - * Copyright (c) 2019, 2020 Oracle and/or its affiliates. All rights reserved. - * - * 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. - */ - -package com.example.fn; - -public class HelloFunction { - - public String handleRequest(String input) { - String name = (input == null || input.isEmpty()) ? "world" : input; - - return "Hello, " + name + "!"; - } - -} \ No newline at end of file diff --git a/images/init-native/src/main/resources/META-INF/native-image/fnfunction/reflect-config.json b/images/init-native/src/main/resources/META-INF/native-image/fnfunction/reflect-config.json deleted file mode 100644 index e1e25e08..00000000 --- a/images/init-native/src/main/resources/META-INF/native-image/fnfunction/reflect-config.json +++ /dev/null @@ -1,9 +0,0 @@ -[ - { - "name" : "com.example.fn.HelloFunction", - "methods" : [ - { "name" : "handleRequest" }, - { "name" : "" } - ] - } -] diff --git a/images/init-native/src/test/java/com/example/fn/HelloFunctionTest.java b/images/init-native/src/test/java/com/example/fn/HelloFunctionTest.java deleted file mode 100644 index 4bf9a72f..00000000 --- a/images/init-native/src/test/java/com/example/fn/HelloFunctionTest.java +++ /dev/null @@ -1,38 +0,0 @@ -/* - * Copyright (c) 2019, 2020 Oracle and/or its affiliates. All rights reserved. - * - * 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. - */ - -package com.example.fn; - -import com.fnproject.fn.testing.*; -import org.junit.*; - -import static org.junit.Assert.*; - -public class HelloFunctionTest { - - @Rule - public final FnTestingRule testing = FnTestingRule.createDefault(); - - @Test - public void shouldReturnGreeting() { - testing.givenEvent().enqueue(); - testing.thenRun(HelloFunction.class, "handleRequest"); - - FnResult result = testing.getOnlyResult(); - assertEquals("Hello, world!", result.getBodyAsString()); - } - -} \ No newline at end of file diff --git a/images/runtime/Dockerfile b/images/runtime/Dockerfile deleted file mode 100644 index 03312f01..00000000 --- a/images/runtime/Dockerfile +++ /dev/null @@ -1,37 +0,0 @@ -# -# Copyright (c) 2019, 2020 Oracle and/or its affiliates. All rights reserved. -# -# 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. -# - -FROM openjdk:8-jre-slim -COPY target/runtime-*.jar target/dependency/*.jar /function/runtime/ -COPY src/main/c/libfnunixsocket.so /function/runtime/lib/ - -RUN ["java", "-Xshare:dump"] - -RUN addgroup --system --gid 1000 fn && adduser --uid 1000 --gid 1000 fn - -# UseCGroupMemoryLimitForHeap looks up /sys/fs/cgroup/memory/memory.limit_in_bytes inside the container to determine -# what the heap should be set to. This is an experimental feature at the moment, thus we need to unlock to use it. -# -# MaxRAMFraction is used modify the heap size and it is used as a denominator where the numerator is phys_mem. -# It seems that this value is a uint in the JVM code, thus can only specify 1 => 100%, 2 => 50%, 3 => 33.3%, 4 => 25% -# and so on. -# -# SerialGC is used here as it's likely that we'll be running many JVMs on the same host machine and it's also likely -# that the number of JVMs will outnumber the number of available processors. -# -# The max memory value obtained with these args seem to be okay for most memory limits. The exception is when the -# memory limit is set to 128MiB, in which case maxMemory returns roughly half. -ENTRYPOINT [ "java", "-XX:+UnlockExperimentalVMOptions", "-XX:+UseCGroupMemoryLimitForHeap", "-XX:-UsePerfData", "-XX:MaxRAMFraction=2", "-XX:+UseSerialGC", "-Xshare:on", "-Djava.library.path=/function/runtime/lib", "-cp", "/function/app/*:/function/runtime/*:/function/app:/function/app/resources", "com.fnproject.fn.runtime.EntryPoint" ] diff --git a/images/runtime/Dockerfile-jre11 b/images/runtime/Dockerfile-jre11 deleted file mode 100644 index ad81ea20..00000000 --- a/images/runtime/Dockerfile-jre11 +++ /dev/null @@ -1,36 +0,0 @@ -# -# Copyright (c) 2019, 2020 Oracle and/or its affiliates. All rights reserved. -# -# 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. -# - -FROM openjdk:11-jre-slim -COPY target/runtime-*.jar target/dependency/*.jar /function/runtime/ -COPY src/main/c/libfnunixsocket.so /function/runtime/lib/ - -RUN ["/usr/local/openjdk-11/bin/java", "-Xshare:dump"] - -RUN addgroup --system --gid 1000 fn && adduser --uid 1000 --gid 1000 fn - -# The UseExeperimentalVMOptions, UseCGroupMemoryLimitForHeap and MaxRAMFraction options that were used in the JDK 9 builds are -# no longer supported in JDK 11 - so these have been removed. We now rely on the built-in ContainerSupport option that Linux JDKs -# use to configure themselves when detecting they are running in a container. -# -# SerialGC is used here as it's likely that we'll be running many JVMs on the same host machine and it's also likely -# that the number of JVMs will outnumber the number of available processors. -# -ENTRYPOINT [ "/usr/local/openjdk-11/bin/java", "-XX:-UsePerfData", "-XX:+UseSerialGC", "-Xshare:on", \ - "-Djava.awt.headless=true" , \ - "-Djava.library.path=/function/runtime/lib", \ - "-cp", "/function/app/*:/function/runtime/*:/function/app:/function/app/resources", \ - "com.fnproject.fn.runtime.EntryPoint" ] diff --git a/images/runtime/README.md b/images/runtime/README.md deleted file mode 100644 index dfd530a0..00000000 --- a/images/runtime/README.md +++ /dev/null @@ -1,3 +0,0 @@ -# Fn Java runtime base images - -These images are used as a base image for functions - they include a JDK and the latest version of the runtime \ No newline at end of file diff --git a/integration-tests/README.md b/integration-tests/README.md deleted file mode 100644 index 90e881e7..00000000 --- a/integration-tests/README.md +++ /dev/null @@ -1,29 +0,0 @@ -# Java FDK integration tests - -Integration tests should only be used for: - -* Smoke testing of end-to-end features -* Rough validation of features that rely on interactions between the fn service and flow service - -They should _not_ be used for: - -* Feature testing of fn/fdk features that don't need cross-service features -* extensive feature testing (use unit tests) -* Performance/load testing - - -# Running locally - -Build the runtime: -```bash -./build.sh -``` - -Run the integration tests: - -```bash -./integration-tests/run_tests_ci.sh -``` - - -This will start/stop fnserver and flow server \ No newline at end of file diff --git a/integration-tests/fnserver.env b/integration-tests/fnserver.env deleted file mode 100644 index fd6e3b46..00000000 --- a/integration-tests/fnserver.env +++ /dev/null @@ -1,3 +0,0 @@ -FN_MAX_REQUEST_SIZE=6291456 -FN_MAX_RESPONSE_SIZE=6291456 -FN_MAX_HDR_RESPONSE_SIZE=16384 \ No newline at end of file diff --git a/integration-tests/funcs/flowAllFeatures/Dockerfile b/integration-tests/funcs/flowAllFeatures/Dockerfile deleted file mode 100644 index f40be518..00000000 --- a/integration-tests/funcs/flowAllFeatures/Dockerfile +++ /dev/null @@ -1,11 +0,0 @@ -FROM fnproject/fn-java-fdk-build:__TO_BE_REPLACED__ as build-stage -WORKDIR /function -ENV MAVEN_OPTS -Dhttp.proxyHost= -Dhttp.proxyPort= -Dhttps.proxyHost= -Dhttps.proxyPort= -Dhttp.nonProxyHosts= -Dmaven.repo.local=/usr/share/maven/ref/repository -ADD pom.xml /function/pom.xml -RUN ["mvn", "package", "dependency:copy-dependencies", "-DincludeScope=runtime", "-DskipTests=true", "-Dmdep.prependGroupId=true", "-DoutputDirectory=target", "--fail-never"] -ADD src /function/src -RUN ["mvn", "package"] -FROM fnproject/fn-java-fdk:__TO_BE_REPLACED__ -WORKDIR /function -COPY --from=build-stage /function/target/*.jar /function/app/ -CMD ["com.fnproject.fn.integration.ExerciseEverything::handleRequest"] diff --git a/integration-tests/funcs/flowAllFeatures/README.md b/integration-tests/funcs/flowAllFeatures/README.md deleted file mode 100644 index b5d34e12..00000000 --- a/integration-tests/funcs/flowAllFeatures/README.md +++ /dev/null @@ -1,19 +0,0 @@ -# Using this to test - -You should be able to see a trace of the various calls -in the function response. - -## To build the dependencies: - -- package up the api and runtime - -- build a docker image of the runtime - -## To test: - - fn build - fn call --display-call-id myapp /test - -or: - - echo 1, 3 | fn call --display-call-id myapp /test diff --git a/integration-tests/funcs/flowAllFeatures/func.yaml b/integration-tests/funcs/flowAllFeatures/func.yaml deleted file mode 100644 index 20d9e86a..00000000 --- a/integration-tests/funcs/flowAllFeatures/func.yaml +++ /dev/null @@ -1,26 +0,0 @@ -# -# Copyright (c) 2019, 2020 Oracle and/or its affiliates. All rights reserved. -# -# 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. -# - -schema_version: 20180708 -name: flowallfeatures -version: 0.0.15 -runtime: java -cmd: com.fnproject.fn.integration.ExerciseEverything::handleRequest -format: http-stream -timeout: 120 -build: -- mvn package dependency:copy-dependencies -DincludeScope=runtime -DskipTests=true - -Dmdep.prependGroupId=true -DoutputDirectory=target diff --git a/integration-tests/funcs/flowAllFeatures/pom.xml b/integration-tests/funcs/flowAllFeatures/pom.xml deleted file mode 100644 index b17a6ba5..00000000 --- a/integration-tests/funcs/flowAllFeatures/pom.xml +++ /dev/null @@ -1,103 +0,0 @@ - - - - - 4.0.0 - - UTF-8 - 1.0.0-SNAPSHOT - 4.13.1 - - com.fnproject.fn - integration-test-4 - 1.0.0 - - jar - - - - com.fnproject.fn - api - ${fdk.version} - - - - com.fnproject.fn - runtime - ${fdk.version} - - - com.fnproject.fn - flow-runtime - ${fdk.version} - - - com.fnproject.fn - testing-core - ${fdk.version} - - - com.fnproject.fn - testing-junit4 - ${fdk.version} - - - junit - junit - ${junit.version} - test - - - commons-io - commons-io - 2.10.0 - - - - - - - org.apache.maven.plugins - maven-compiler-plugin - 3.3 - - 1.8 - 1.8 - - - - org.apache.maven.plugins - maven-deploy-plugin - 2.8.2 - - true - - - - - - - - fn-maven-releases - https://dl.bintray.com/fnproject/fnproject - - - diff --git a/integration-tests/funcs/flowAllFeatures/src/main/java/com/fnproject/fn/integration/ExerciseEverything.java b/integration-tests/funcs/flowAllFeatures/src/main/java/com/fnproject/fn/integration/ExerciseEverything.java deleted file mode 100644 index b5f2b36c..00000000 --- a/integration-tests/funcs/flowAllFeatures/src/main/java/com/fnproject/fn/integration/ExerciseEverything.java +++ /dev/null @@ -1,582 +0,0 @@ -/* - * Copyright (c) 2019, 2020 Oracle and/or its affiliates. All rights reserved. - * - * 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. - */ - -package com.fnproject.fn.integration; - -import com.fnproject.fn.api.FnFeature; -import com.fnproject.fn.api.Headers; -import com.fnproject.fn.api.InputEvent; -import com.fnproject.fn.api.RuntimeContext; -import com.fnproject.fn.api.flow.*; -import com.fnproject.fn.runtime.flow.FlowFeature; -import org.apache.commons.io.IOUtils; -import org.apache.commons.io.output.TeeOutputStream; - -import java.io.ByteArrayOutputStream; -import java.io.IOException; -import java.io.InputStream; -import java.io.PrintStream; -import java.lang.reflect.InvocationTargetException; -import java.lang.reflect.Method; -import java.util.*; -import java.util.stream.Collectors; - -@SuppressWarnings("unused") -@FnFeature(FlowFeature.class) -public class ExerciseEverything { - - private boolean okay = true; - private ByteArrayOutputStream bos = new ByteArrayOutputStream(); - private PrintStream out = new PrintStream(new TeeOutputStream(System.err, bos)); - private String testSelector = null; - private InputEvent inputEvent; - private List failures = new ArrayList<>(); - private final RuntimeContext runtimeContext; - - public ExerciseEverything(RuntimeContext runtimeContext) { - this.runtimeContext = runtimeContext; - } - - @Test(1) - @Test.Expect("completed value") - public FlowFuture completedValue(Flow fl) { - return fl.completedValue("completed value"); - } - - @Test(2) - @Test.Expect("supply") - public FlowFuture supply(Flow fl) { - return fl.supply(() -> "supply"); - } - - @Test(3) - public FlowFuture allOfWithCompletedValue(Flow fl) { - return fl.allOf( - fl.completedValue(1), - fl.completedValue(2), - fl.completedValue(3) - ); - } - - @Test(4) - public FlowFuture allOfWithSuppliedValue(Flow fl) { - return fl.allOf( - fl.supply(() -> 1), - fl.supply(() -> 2), - fl.supply(() -> 3) - ); - } - - @Test(5) - @Test.Expect("1") - @Test.Expect("2") - @Test.Expect("3") - public FlowFuture anyOfWithCompletedValue(Flow fl) { - return fl.anyOf( - fl.completedValue("1"), - fl.completedValue("2"), - fl.completedValue("3") - ); - } - - @Test(6) - @Test.Expect("1") - @Test.Expect("2") - @Test.Expect("3") - public FlowFuture anyOfWithSuppliedValue(Flow fl) { - return fl.anyOf( - fl.supply(() -> "1"), - fl.supply(() -> "2"), - fl.supply(() -> "3") - ); - } - - @Test(7) - @Test.Expect("test exception") - public FlowFuture completeWithAnException(Flow fl) { - return fl.completedValue(new Exception("test exception")); - } - - @Test(8) - @Test.Catch({FlowCompletionException.class, MyException.class}) - public FlowFuture supplyAnException(Flow fl) { - return fl.supply(() -> { - throw new MyException("test exception"); - }); - } - - public static class MyException extends RuntimeException { - MyException(String m) { - super(m); - } - } - - @Test(9) - @Test.Expect("4") - public FlowFuture chainThenApply(Flow fl) { - FlowFuture cf = fl.completedValue(0); - - for (int i = 0; i < 4; i++) { - cf = cf.thenApply((x) -> x + 1); - } - return cf; - } - - - @Test(10) - @Test.Expect("-3") - public FlowFuture catchBubbledException(Flow fl) { - return fl.completedValue(0) - .thenApply((x) -> x + 1) - .thenApply((x) -> { - if (x == 1) throw new MyException("boom"); - else return x + 1; - }) - .thenApply((x) -> x + 1) - .thenApply((x) -> x + 1) - .exceptionally((e) -> -3); - } - - @Test(11) - @Test.Catch({FlowCompletionException.class, FunctionInvocationException.class}) - public FlowFuture nonexistentExternalEvaluation(Flow fl) { - return fl.invokeFunction("nonexistent/nonexistent", HttpMethod.POST, Headers.emptyHeaders(), new byte[0]); - } - - @Test(12) - @Test.Expect("okay") - public FlowFuture checkPassingExternalInvocation(Flow fl) { - return fl.invokeFunction(runtimeContext.getFunctionID(), HttpMethod.POST, Headers.emptyHeaders(), "PASS".getBytes()) - .thenApply((resp) -> resp.getStatusCode() != 200 ? "failure" : new String(resp.getBodyAsBytes())); - } - - // There is currently no way for a hot function to signal failure in the Fn platform. - // This test will only work in default mode. - @Test(13) - @Test.Catch({FlowCompletionException.class, FunctionInvocationException.class}) - public FlowFuture checkFailingExternalInvocation(Flow fl) { - return fl.invokeFunction(runtimeContext.getFunctionID(), HttpMethod.POST, Headers.emptyHeaders(), "FAIL".getBytes()); - } - - @Test(14) - @Test.Expect("X") - public FlowFuture simpleThenCompose(Flow fl) { - return fl.completedValue("x").thenCompose((s) -> { - System.err.println("I am in the thenCompose stage, s = " + s); - FlowFuture retVal = fl.completedValue(s.toUpperCase()); - System.err.println("my retVal = " + retVal + "; type is " + retVal.getClass()); - return retVal; - }); - } - - @Test(15) - @Test.Expect("hello world") - public FlowFuture thenCompose(Flow fl) { - return fl.completedValue("hello") - .thenCompose((s) -> - fl.supply(() -> s) - .thenApply((s2) -> s2 + " world") - ); - } - - @Test(16) - @Test.Expect("foo") - public FlowFuture thenComposeThenError(Flow fl) { - return fl.completedValue("hello") - .thenCompose((s) -> fl.supply(() -> { - if (s.equals("hello")) throw new MyException("foo"); - else return s; - })) - .exceptionally(Throwable::getMessage); - } - - @Test(17) - @Test.Expect("foo") - public FlowFuture thenComposeWithErrorInBody(Flow fl) { - return fl.completedValue("hello") - .thenCompose((s) -> { - if (s.equals("hello")) throw new MyException("foo"); - else return fl.completedValue(s); - }) - .exceptionally(Throwable::getMessage); - } - - @Test(18) - @Test.Expect("a") - @Test.Expect("b") - public FlowFuture applyToEither(Flow fl) { - return fl.completedValue("a").applyToEither(fl.completedValue("b"), (x) -> x); - } - - @Test(19) - @Test.Expect("a") - @Test.Expect("b") - public FlowFuture applyToEitherLikelyPathB(Flow fl) { - return fl.supply(() -> "a").applyToEither(fl.completedValue("b"), (x) -> x); - } - - @Test(20) - public FlowFuture harmlessAcceptBoth(Flow fl) { - return fl.completedValue("a") - .thenAcceptBoth( - fl.completedValue("b"), - (a, b) -> System.err.println(a + "; " + b) - ); - } - - @Test(21) - @Test.Catch({FlowCompletionException.class, MyException.class}) - @Test.Expect("ab") - public FlowFuture acceptBoth(Flow fl) { - return fl.completedValue("a") - .thenAcceptBoth( - fl.completedValue("b"), - (a, b) -> { - System.err.println("A is " + a + " and B is " + b); - throw new MyException(a + b); - }); - } - - @Test(22) - @Test.Catch({FlowCompletionException.class, MyException.class}) - @Test.Expect("a") - @Test.Expect("b") - public FlowFuture acceptEither(Flow fl) { - return fl.completedValue("a") - .acceptEither( - fl.completedValue("b"), - (x) -> { - throw new MyException(x); - } - ); - } - - @Test(23) - @Test.Expect("foobar") - public FlowFuture thenCombine(Flow fl) { - return fl.completedValue("foo") - .thenCombine(fl.completedValue("bar"), - (a, b) -> a + b); - } - - @Test(24) - @Test.Expect("foo") - public FlowFuture thenCombineE1(Flow fl) { - return fl.supply(() -> { - throw new MyException("foo"); - }) - .thenCombine(fl.completedValue("bar"), - (a, b) -> a + b) - .exceptionally(Throwable::getMessage); - } - - @Test(25) - @Test.Expect("bar") - public FlowFuture thenCombineE2(Flow fl) { - return fl.completedValue("foo") - .thenCombine(fl.supply(() -> { - throw new MyException("bar"); - }), - (a, b) -> a + b) - .exceptionally(Throwable::getMessage); - } - - - @Test(26) - @Test.Expect("foobar") - public FlowFuture thenCombineE3(Flow fl) { - return fl.completedValue("foo") - .thenCombine(fl.completedValue("bar"), - (a, b) -> { - if (!a.equals(b)) throw new MyException(a + b); - else return "baz"; - }) - .exceptionally(Throwable::getMessage); - } - - @Test(27) - @Test.Expect("foo") - public FlowFuture handleNoError(Flow fl) { - return fl.completedValue("foo") - .handle((v, e) -> v); - } - - @Test(28) - @Test.Expect("bar") - public FlowFuture handleWithError(Flow fl) { - return fl.supply(() -> { - throw new MyException("bar"); - }) - .handle((v, e) -> e.getMessage()); - } - - @Test(29) - @Test.Expect("foo") - public FlowFuture whenCompleteNoError(Flow fl) { - return fl.completedValue("foo") - .whenComplete((v, e) -> { - System.err.println("In whenComplete, v=" + v); - throw new MyException(v); - }) - .exceptionally(t -> { - // Should *not* get called. - System.err.println("In whenComplete.exceptionally, t=" + t); - return t.getMessage() + "bar"; - }); - } - - @Test(30) - @Test.Expect("barbaz") - public FlowFuture whenCompleteWithError(Flow fl) { - return fl.supply(() -> { - if (true) throw new MyException("bar"); - else return ""; - }).whenComplete((v, e) -> { - throw new MyException(e.getMessage()); - }).exceptionally(t -> t.getMessage() + "baz"); - } - - @Test(35) - @Test.Expect("foobar") - public FlowFuture exceptionallyComposeHandle(Flow fl) throws IOException { - - return fl.failedFuture(new RuntimeException("foobar")) - .exceptionallyCompose((e) -> fl.completedValue(e.getMessage())); - } - - @Test(36) - @Test.Expect("foobar") - public FlowFuture exceptionallyComposePassThru(Flow fl) throws IOException { - - return fl.completedValue("foobar") - .exceptionallyCompose((e) -> fl.completedValue(e.getMessage())); - } - - - @Test(37) - @Test.Expect("foobar") - public FlowFuture exceptionallyComposePropagateError(Flow fl) throws IOException { - return fl.failedFuture(new RuntimeException("foo")) - .exceptionallyCompose((e) -> { - throw new RuntimeException("foobar"); - }).exceptionally(Throwable::getMessage); - } - - @Test(38) - @Test.Catch({FlowCompletionException.class, MyException.class}) - public FlowFuture allOfWithFailedValue(Flow fl) { - return fl.allOf( - fl.supply(() -> 1), - fl.supply(() -> 2), - fl.supply(() -> { - throw new MyException("foobar"); - }) - ); - } - - - @Test(39) - @Test.Expect("foobar") - public FlowFuture completeFuture(Flow fl) { - FlowFuture a = fl.createFlowFuture(); - FlowFuture b = fl.createFlowFuture(); - - a.complete("foobar"); - - return a.applyToEither(b, (s) -> { - b.cancel(); - return s; - }); - } - - private int id; - - private void fail() { - if (!failures.contains(id)) { - failures.add(id); - } - okay = false; - } - - public String handleRequest(InputEvent ie) { - this.inputEvent = ie; - String selector = ie.consumeBody((InputStream is) -> { - try { - return IOUtils.toString(is, "utf-8"); - } catch (IOException e) { - return "FAIL"; - } - }); - - if ("PASS".equals(selector)) { - return "okay"; - } else if ("FAIL".equals(selector)) { - throw new MyException("failure demanded"); - } - testSelector = selector; - Flow fl = Flows.currentFlow(); - - out.println("In main function"); - Map> awaiting = new TreeMap<>(); - - for (Map.Entry e : findTests(this).entrySet()) { - id = e.getKey(); - Method m = e.getValue(); - - Test.Catch exWanted = m.getAnnotation(Test.Catch.class); - String[] values = expectedValues(m); - - try { - awaiting.put(id, (FlowFuture) m.invoke(this, fl)); - } catch (InvocationTargetException ex) { - out.println("Failure setting up test " + id + ": " + ex.getCause()); - ex.printStackTrace(out); - fail(); - } catch (IllegalAccessException ignored) { - } - } - - for (Map.Entry e : findTests(this).entrySet()) { - id = e.getKey(); - Method m = e.getValue(); - - out.println("Test " + id + ": Start"); - - Test.Catch exWanted = m.getAnnotation(Test.Catch.class); - String[] values = expectedValues(m); - try { - FlowFuture cf = awaiting.get(id); - if (cf == null) { - continue; - } - Object r = cf.get(); - - // Coerce returned value to string - String rv = coerceToString(r); - - if (!huntForValues(rv, values)) { - fail(); - } - - if (exWanted != null) { - out.println("Test " + id + ": Failed: expecting throw of " + Arrays.toString(exWanted.value())); - fail(); - } - } catch (Throwable t) { - if (exWanted != null) { - // We have a series of wrapped exceptions that should follow this containment pattern - boolean found = false; - - for (Class c : exWanted.value()) { - if (t == null) { - out.println("Test" + id + ": Failed: end of exception chain, wanted " + c); - fail(); - break; - } - if (c.isAssignableFrom(t.getClass())) { - String message = coerceToString(t); - found = found || huntForValues(message, values); - } else { - out.println("Test" + id + ": Failed: exception type mismatch: " + t + ", wanted " + c); - t.printStackTrace(out); - fail(); - break; - } - t = t.getCause(); - } - if (!found && values.length > 0) { - out.println("Test" + id + ": Failed: failed comparison, wanted exception with one of " + Arrays.toString(values)); - fail(); - } - } else { - out.println("Test" + id + ": Failed: got an unexpected exception: " + t); - t.printStackTrace(out); - fail(); - } - } - if (!failures.contains(id)) { - out.println("Test " + id + ": Passed"); - } - } - - out.println(okay ? "Everything worked" : "There were failures: " + failures); - out.flush(); - return bos.toString(); - } - - private String coerceToString(Object r) { - if (r == null) { - return null; - } else if (r instanceof String) { - // okay - return (String) r; - } else if (r instanceof Throwable) { - return ((Throwable) r).getMessage(); - } else if (r instanceof HttpRequest) { - return new String(((HttpRequest) r).getBodyAsBytes()); - } else if (r instanceof HttpResponse) { - return new String(((HttpResponse) r).getBodyAsBytes()); - } else { - return r.toString(); - } - } - - private String[] expectedValues(Method m) { - Test.Expected ex = m.getAnnotation(Test.Expected.class); - if (ex != null) { - return Arrays.stream(ex.value()).map(Test.Expect::value).toArray(String[]::new); - } else { - Test.Expect ex2 = m.getAnnotation(Test.Expect.class); - if (ex2 != null) { - return new String[]{ex2.value()}; - } else { - return new String[]{}; - } - } - } - - private boolean huntForValues(String match, String... values) { - for (String v : values) { - if ((v == null && match == null) || (v != null && v.equals(match))) { - return true; - } - } - if (values.length > 0) { - return false; - } - return true; - } - - private Map findTests(Object target) { - Map tests = new TreeMap<>(); - for (Method m : target.getClass().getMethods()) { - Test ann = m.getAnnotation(Test.class); - if (ann == null) - continue; - int id = ann.value(); - tests.put(id, m); - } - if (testSelector == null || testSelector.trim().isEmpty()) { - return tests; - } - - return Arrays.stream(testSelector.split(",")) - .map(String::trim) - .map(Integer::valueOf) - .filter(tests::containsKey) - .collect(Collectors.toMap((x) -> x, tests::get)); - } -} diff --git a/integration-tests/funcs/flowAllFeatures/src/main/java/com/fnproject/fn/integration/Test.java b/integration-tests/funcs/flowAllFeatures/src/main/java/com/fnproject/fn/integration/Test.java deleted file mode 100644 index 5e71649b..00000000 --- a/integration-tests/funcs/flowAllFeatures/src/main/java/com/fnproject/fn/integration/Test.java +++ /dev/null @@ -1,42 +0,0 @@ -/* - * Copyright (c) 2019, 2020 Oracle and/or its affiliates. All rights reserved. - * - * 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. - */ - -package com.fnproject.fn.integration; - -import java.lang.annotation.Repeatable; -import java.lang.annotation.Retention; -import java.lang.annotation.RetentionPolicy; - -@Retention(RetentionPolicy.RUNTIME) -public @interface Test { - int value(); - - @Retention(RetentionPolicy.RUNTIME) - @interface Expected { - Expect[] value(); - } - - @Retention(RetentionPolicy.RUNTIME) - @Repeatable(Expected.class) - @interface Expect { - String value(); - } - - @Retention(RetentionPolicy.RUNTIME) - @interface Catch { - Class[] value(); - } -} diff --git a/integration-tests/funcs/flowBasic/Dockerfile b/integration-tests/funcs/flowBasic/Dockerfile deleted file mode 100644 index 05413242..00000000 --- a/integration-tests/funcs/flowBasic/Dockerfile +++ /dev/null @@ -1,11 +0,0 @@ -FROM fnproject/fn-java-fdk-build:__TO_BE_REPLACED__ as build-stage -WORKDIR /function -ENV MAVEN_OPTS -Dhttp.proxyHost= -Dhttp.proxyPort= -Dhttps.proxyHost= -Dhttps.proxyPort= -Dhttp.nonProxyHosts= -Dmaven.repo.local=/usr/share/maven/ref/repository -ADD pom.xml /function/pom.xml -RUN ["mvn", "package", "dependency:copy-dependencies", "-DincludeScope=runtime", "-DskipTests=true", "-Dmdep.prependGroupId=true", "-DoutputDirectory=target", "--fail-never"] -ADD src /function/src -RUN ["mvn", "package"] -FROM fnproject/fn-java-fdk:__TO_BE_REPLACED__ -WORKDIR /function -COPY --from=build-stage /function/target/*.jar /function/app/ -CMD ["com.fnproject.fn.integration.test_1.CompleterFunction::handleRequest"] diff --git a/integration-tests/funcs/flowBasic/func.yaml b/integration-tests/funcs/flowBasic/func.yaml deleted file mode 100644 index c9f6f3bc..00000000 --- a/integration-tests/funcs/flowBasic/func.yaml +++ /dev/null @@ -1,23 +0,0 @@ -# -# Copyright (c) 2019, 2020 Oracle and/or its affiliates. All rights reserved. -# -# 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. -# - -schema_version: 20180708 -name: flowbasic -version: 0.0.7 -runtime: java -cmd: com.fnproject.fn.integration.test_1.CompleterFunction::handleRequest -format: http-stream -timeout: 120 diff --git a/integration-tests/funcs/flowBasic/pom.xml b/integration-tests/funcs/flowBasic/pom.xml deleted file mode 100644 index 18642b39..00000000 --- a/integration-tests/funcs/flowBasic/pom.xml +++ /dev/null @@ -1,76 +0,0 @@ - - - - - 4.0.0 - - UTF-8 - 1.0.0-SNAPSHOT - - com.fnproject.fn - integration-test-1 - 1.0.0 - - jar - - - - com.fnproject.fn - api - ${fdk.version} - - - com.fnproject.fn - flow-runtime - ${fdk.version} - - - - - - - - org.apache.maven.plugins - maven-compiler-plugin - 3.3 - - 1.8 - 1.8 - - - - org.apache.maven.plugins - maven-deploy-plugin - 2.8.2 - - true - - - - - - - - fn-maven-releases - https://dl.bintray.com/fnproject/fnproject - - - diff --git a/integration-tests/funcs/flowBasic/src/main/java/com/fnproject/fn/integration/test_1/CompleterFunction.java b/integration-tests/funcs/flowBasic/src/main/java/com/fnproject/fn/integration/test_1/CompleterFunction.java deleted file mode 100644 index 2cf9161c..00000000 --- a/integration-tests/funcs/flowBasic/src/main/java/com/fnproject/fn/integration/test_1/CompleterFunction.java +++ /dev/null @@ -1,34 +0,0 @@ -/* - * Copyright (c) 2019, 2020 Oracle and/or its affiliates. All rights reserved. - * - * 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. - */ - -package com.fnproject.fn.integration.test_1; - -import com.fnproject.fn.api.FnFeature; -import com.fnproject.fn.api.flow.Flow; -import com.fnproject.fn.runtime.flow.FlowFeature; -import com.fnproject.fn.api.flow.Flows; - -@FnFeature(FlowFeature.class) -public class CompleterFunction { - - public Integer handleRequest(String input) { - Flow fl = Flows.currentFlow(); - - return fl.supply(() -> Integer.parseInt(input)) - .thenApply((i) -> i + 3) - .get(); - } -} diff --git a/integration-tests/funcs/flowBasicJDK8/Dockerfile b/integration-tests/funcs/flowBasicJDK8/Dockerfile deleted file mode 100644 index 05413242..00000000 --- a/integration-tests/funcs/flowBasicJDK8/Dockerfile +++ /dev/null @@ -1,11 +0,0 @@ -FROM fnproject/fn-java-fdk-build:__TO_BE_REPLACED__ as build-stage -WORKDIR /function -ENV MAVEN_OPTS -Dhttp.proxyHost= -Dhttp.proxyPort= -Dhttps.proxyHost= -Dhttps.proxyPort= -Dhttp.nonProxyHosts= -Dmaven.repo.local=/usr/share/maven/ref/repository -ADD pom.xml /function/pom.xml -RUN ["mvn", "package", "dependency:copy-dependencies", "-DincludeScope=runtime", "-DskipTests=true", "-Dmdep.prependGroupId=true", "-DoutputDirectory=target", "--fail-never"] -ADD src /function/src -RUN ["mvn", "package"] -FROM fnproject/fn-java-fdk:__TO_BE_REPLACED__ -WORKDIR /function -COPY --from=build-stage /function/target/*.jar /function/app/ -CMD ["com.fnproject.fn.integration.test_1.CompleterFunction::handleRequest"] diff --git a/integration-tests/funcs/flowBasicJDK8/func.yaml b/integration-tests/funcs/flowBasicJDK8/func.yaml deleted file mode 100644 index af6328d2..00000000 --- a/integration-tests/funcs/flowBasicJDK8/func.yaml +++ /dev/null @@ -1,23 +0,0 @@ -# -# Copyright (c) 2019, 2020 Oracle and/or its affiliates. All rights reserved. -# -# 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. -# - -schema_version: 20180708 -name: flowbasicj8 -version: 0.0.3 -runtime: java8 -cmd: com.fnproject.fn.integration.test_1.CompleterFunction::handleRequest -format: http-stream -timeout: 120 diff --git a/integration-tests/funcs/flowBasicJDK8/pom.xml b/integration-tests/funcs/flowBasicJDK8/pom.xml deleted file mode 100644 index 717b8b9a..00000000 --- a/integration-tests/funcs/flowBasicJDK8/pom.xml +++ /dev/null @@ -1,75 +0,0 @@ - - - - - 4.0.0 - - UTF-8 - 1.0.0-SNAPSHOT - - com.fnproject.fn - integration-test-1 - 1.0.0 - - jar - - - - com.fnproject.fn - api - ${fdk.version} - - - com.fnproject.fn - flow-runtime - ${fdk.version} - - - - - - - org.apache.maven.plugins - maven-compiler-plugin - 3.3 - - 1.8 - 1.8 - - - - org.apache.maven.plugins - maven-deploy-plugin - 2.8.2 - - true - - - - - - - - fn-maven-releases - https://dl.bintray.com/fnproject/fnproject - - - diff --git a/integration-tests/funcs/flowBasicJDK8/src/main/java/com/fnproject/fn/integration/test_1/CompleterFunction.java b/integration-tests/funcs/flowBasicJDK8/src/main/java/com/fnproject/fn/integration/test_1/CompleterFunction.java deleted file mode 100644 index 2cf9161c..00000000 --- a/integration-tests/funcs/flowBasicJDK8/src/main/java/com/fnproject/fn/integration/test_1/CompleterFunction.java +++ /dev/null @@ -1,34 +0,0 @@ -/* - * Copyright (c) 2019, 2020 Oracle and/or its affiliates. All rights reserved. - * - * 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. - */ - -package com.fnproject.fn.integration.test_1; - -import com.fnproject.fn.api.FnFeature; -import com.fnproject.fn.api.flow.Flow; -import com.fnproject.fn.runtime.flow.FlowFeature; -import com.fnproject.fn.api.flow.Flows; - -@FnFeature(FlowFeature.class) -public class CompleterFunction { - - public Integer handleRequest(String input) { - Flow fl = Flows.currentFlow(); - - return fl.supply(() -> Integer.parseInt(input)) - .thenApply((i) -> i + 3) - .get(); - } -} diff --git a/integration-tests/funcs/flowExitHooks/Dockerfile b/integration-tests/funcs/flowExitHooks/Dockerfile deleted file mode 100644 index 856c40d0..00000000 --- a/integration-tests/funcs/flowExitHooks/Dockerfile +++ /dev/null @@ -1,11 +0,0 @@ -FROM fnproject/fn-java-fdk-build:__TO_BE_REPLACED__ as build-stage -WORKDIR /function -ENV MAVEN_OPTS -Dhttp.proxyHost= -Dhttp.proxyPort= -Dhttps.proxyHost= -Dhttps.proxyPort= -Dhttp.nonProxyHosts= -Dmaven.repo.local=/usr/share/maven/ref/repository -ADD pom.xml /function/pom.xml -RUN ["mvn", "package", "dependency:copy-dependencies", "-DincludeScope=runtime", "-DskipTests=true", "-Dmdep.prependGroupId=true", "-DoutputDirectory=target", "--fail-never"] -ADD src /function/src -RUN ["mvn", "package"] -FROM fnproject/fn-java-fdk:__TO_BE_REPLACED__ -WORKDIR /function -COPY --from=build-stage /function/target/*.jar /function/app/ -CMD ["com.fnproject.fn.integration.test_5.CompleterFunction::handleRequest"] diff --git a/integration-tests/funcs/flowExitHooks/func.yaml b/integration-tests/funcs/flowExitHooks/func.yaml deleted file mode 100644 index 3c55914e..00000000 --- a/integration-tests/funcs/flowExitHooks/func.yaml +++ /dev/null @@ -1,23 +0,0 @@ -# -# Copyright (c) 2019, 2020 Oracle and/or its affiliates. All rights reserved. -# -# 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. -# - -schema_version: 20180708 -name: flowexithooks -version: 0.0.3 -runtime: java11 -cmd: com.fnproject.fn.integration.test_5.CompleterFunction::handleRequest -format: http-stream -timeout: 120 diff --git a/integration-tests/funcs/flowExitHooks/pom.xml b/integration-tests/funcs/flowExitHooks/pom.xml deleted file mode 100644 index e8082fe8..00000000 --- a/integration-tests/funcs/flowExitHooks/pom.xml +++ /dev/null @@ -1,94 +0,0 @@ - - - - - 4.0.0 - - UTF-8 - 1.0.0-SNAPSHOT - - com.fnproject.fn - integration-test-5 - 1.0.0 - - jar - - - - com.fnproject.fn - api - ${fdk.version} - - - com.fnproject.fn - flow-runtime - ${fdk.version} - compile - - - com.fnproject.fn - testing-core - ${fdk.version} - test - - - com.fnproject.fn - testing-junit4 - ${fdk.version} - test - - - junit - junit - 4.13.1 - test - - - - - - - org.apache.maven.plugins - maven-compiler-plugin - 3.3 - - 1.8 - 1.8 - - - - org.apache.maven.plugins - maven-deploy-plugin - 2.8.2 - - true - - - - - - - - fn-maven-releases - https://dl.bintray.com/fnproject/fnproject - - - diff --git a/integration-tests/funcs/flowExitHooks/src/main/java/com/fnproject/fn/integration/test_5/CompleterFunction.java b/integration-tests/funcs/flowExitHooks/src/main/java/com/fnproject/fn/integration/test_5/CompleterFunction.java deleted file mode 100644 index 8d4c96bc..00000000 --- a/integration-tests/funcs/flowExitHooks/src/main/java/com/fnproject/fn/integration/test_5/CompleterFunction.java +++ /dev/null @@ -1,61 +0,0 @@ -/* - * Copyright (c) 2019, 2020 Oracle and/or its affiliates. All rights reserved. - * - * 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. - */ - -package com.fnproject.fn.integration.test_5; - -import com.fnproject.fn.api.FnFeature; -import com.fnproject.fn.api.RuntimeContext; -import com.fnproject.fn.api.flow.Flow; -import com.fnproject.fn.api.flow.Flows; -import com.fnproject.fn.runtime.flow.FlowFeature; - -import java.io.Serializable; -import java.net.HttpURLConnection; -import java.net.URI; -import java.net.URL; - -@FnFeature(FlowFeature.class) -public class CompleterFunction implements Serializable { - - private final URL callbackURL; - - public CompleterFunction(RuntimeContext rtc) throws Exception { - callbackURL = URI.create(rtc.getConfigurationByKey("TERMINATION_HOOK_URL").orElseThrow(() -> new RuntimeException("No config set "))).toURL(); - } - - public Integer handleRequest(String input) { - Flow fl = Flows.currentFlow(); - fl.addTerminationHook((ignored) -> { - try { - HttpURLConnection con = (HttpURLConnection) callbackURL.openConnection(); - - System.err.println("Ran the hook."); - - con.setRequestMethod("GET"); - if (con.getResponseCode() != 200) { - throw new RuntimeException("Got bad code from callback"); - } - } catch (Exception e) { - throw new RuntimeException(e); - } - - }); - return fl.supply(() -> { - return 42; - }).get(); - } - -} diff --git a/integration-tests/funcs/flowTimeouts/Dockerfile b/integration-tests/funcs/flowTimeouts/Dockerfile deleted file mode 100644 index d5d2a77c..00000000 --- a/integration-tests/funcs/flowTimeouts/Dockerfile +++ /dev/null @@ -1,11 +0,0 @@ -FROM fnproject/fn-java-fdk-build:__TO_BE_REPLACED__ as build-stage -WORKDIR /function -ENV MAVEN_OPTS -Dhttp.proxyHost= -Dhttp.proxyPort= -Dhttps.proxyHost= -Dhttps.proxyPort= -Dhttp.nonProxyHosts= -Dmaven.repo.local=/usr/share/maven/ref/repository -ADD pom.xml /function/pom.xml -RUN ["mvn", "package", "dependency:copy-dependencies", "-DincludeScope=runtime", "-DskipTests=true", "-Dmdep.prependGroupId=true", "-DoutputDirectory=target", "--fail-never"] -ADD src /function/src -RUN ["mvn", "package"] -FROM fnproject/fn-java-fdk:__TO_BE_REPLACED__ -WORKDIR /function -COPY --from=build-stage /function/target/*.jar /function/app/ -CMD ["com.fnproject.fn.integration.test_6.CompleterFunction::handleRequest"] diff --git a/integration-tests/funcs/flowTimeouts/func.yaml b/integration-tests/funcs/flowTimeouts/func.yaml deleted file mode 100644 index cc694a91..00000000 --- a/integration-tests/funcs/flowTimeouts/func.yaml +++ /dev/null @@ -1,23 +0,0 @@ -# -# Copyright (c) 2019, 2020 Oracle and/or its affiliates. All rights reserved. -# -# 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. -# - -schema_version: 20180708 -name: flowtimeouts -version: 0.0.3 -runtime: java11 -cmd: com.fnproject.fn.integration.test_6.CompleterFunction::handleRequest -format: http-stream -timeout: 120 diff --git a/integration-tests/funcs/flowTimeouts/pom.xml b/integration-tests/funcs/flowTimeouts/pom.xml deleted file mode 100644 index 1e8cf1eb..00000000 --- a/integration-tests/funcs/flowTimeouts/pom.xml +++ /dev/null @@ -1,93 +0,0 @@ - - - - - 4.0.0 - - UTF-8 - 1.0.0-SNAPSHOT - - com.fnproject.fn - integration-test-6 - 1.0.0 - - jar - - - - com.fnproject.fn - api - ${fdk.version} - - - com.fnproject.fn - flow-runtime - ${fdk.version} - - - com.fnproject.fn - testing-core - ${fdk.version} - test - - - com.fnproject.fn - testing-junit4 - ${fdk.version} - test - - - junit - junit - 4.13.1 - test - - - - - - - org.apache.maven.plugins - maven-compiler-plugin - 3.3 - - 1.8 - 1.8 - - - - org.apache.maven.plugins - maven-deploy-plugin - 2.8.2 - - true - - - - - - - - fn-maven-releases - https://dl.bintray.com/fnproject/fnproject - - - diff --git a/integration-tests/funcs/flowTimeouts/src/main/java/com/fnproject/fn/integration/test_6/CompleterFunction.java b/integration-tests/funcs/flowTimeouts/src/main/java/com/fnproject/fn/integration/test_6/CompleterFunction.java deleted file mode 100644 index f6f2b301..00000000 --- a/integration-tests/funcs/flowTimeouts/src/main/java/com/fnproject/fn/integration/test_6/CompleterFunction.java +++ /dev/null @@ -1,43 +0,0 @@ -/* - * Copyright (c) 2019, 2020 Oracle and/or its affiliates. All rights reserved. - * - * 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. - */ - -package com.fnproject.fn.integration.test_6; - -import com.fnproject.fn.api.FnFeature; -import com.fnproject.fn.api.flow.Flow; -import com.fnproject.fn.api.flow.Flows; -import com.fnproject.fn.runtime.flow.FlowFeature; - -import java.util.concurrent.TimeUnit; -import java.util.concurrent.TimeoutException; - - -@FnFeature(FlowFeature.class) -public class CompleterFunction { - - public String handleRequest(String input) { - Flow fl = Flows.currentFlow(); - try { - return fl.supply(() -> { - Thread.sleep(10000); - return "nope"; - }).get(1000, TimeUnit.MILLISECONDS); - } catch (TimeoutException t) { - return "timeout"; - } - } - -} diff --git a/integration-tests/funcs/helloFunc/Dockerfile b/integration-tests/funcs/helloFunc/Dockerfile deleted file mode 100644 index 42a1919a..00000000 --- a/integration-tests/funcs/helloFunc/Dockerfile +++ /dev/null @@ -1,11 +0,0 @@ -FROM fnproject/fn-java-fdk-build:1.0.0-SNAPSHOT as build-stage -WORKDIR /function -ENV MAVEN_OPTS -Dhttp.proxyHost= -Dhttp.proxyPort= -Dhttps.proxyHost= -Dhttps.proxyPort= -Dhttp.nonProxyHosts= -Dmaven.repo.local=/usr/share/maven/ref/repository -ADD pom.xml /function/pom.xml -RUN ["mvn", "package", "dependency:copy-dependencies", "-DincludeScope=runtime", "-DskipTests=true", "-Dmdep.prependGroupId=true", "-DoutputDirectory=target", "--fail-never"] -ADD src /function/src -RUN ["mvn", "package"] -FROM fnproject/fn-java-fdk:1.0.0-SNAPSHOT -WORKDIR /function -COPY --from=build-stage /function/target/*.jar /function/app/ -CMD ["com.fnproject.fn.integration.hello.HelloFunction::handleRequest"] diff --git a/integration-tests/funcs/helloFunc/func-proto.yaml b/integration-tests/funcs/helloFunc/func-proto.yaml deleted file mode 100644 index 63a5398b..00000000 --- a/integration-tests/funcs/helloFunc/func-proto.yaml +++ /dev/null @@ -1,22 +0,0 @@ -# -# Copyright (c) 2019, 2020 Oracle and/or its affiliates. All rights reserved. -# -# 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. -# - -schema_version: 20180708 -name: hellofunc -version: 0.0.1 -runtime: java8 -cmd: com.fnproject.fn.integration.hello.HelloFunction::handleRequest -format: http-stream \ No newline at end of file diff --git a/integration-tests/funcs/helloFunc/pom.xml b/integration-tests/funcs/helloFunc/pom.xml deleted file mode 100644 index d95f6c38..00000000 --- a/integration-tests/funcs/helloFunc/pom.xml +++ /dev/null @@ -1,86 +0,0 @@ - - - - - 4.0.0 - - UTF-8 - 1.0.0-SNAPSHOT - - com.example.fn - hello-func - 1.0.0 - - - - fn-release-repo - https://dl.bintray.com/fnproject/fnproject - - - - - - com.fnproject.fn - api - ${fdk.version} - - - com.fnproject.fn - testing-core - ${fdk.version} - test - - - com.fnproject.fn - testing-junit4 - ${fdk.version} - test - - - junit - junit - 4.12 - test - - - - - - - org.apache.maven.plugins - maven-compiler-plugin - 3.3 - - 8 - 8 - - - - org.apache.maven.plugins - maven-surefire-plugin - 2.22.1 - - false - - - - - diff --git a/integration-tests/funcs/helloFunc/src-proto/main/java/com/fnproject/fn/integration/hello/HelloFunction.java b/integration-tests/funcs/helloFunc/src-proto/main/java/com/fnproject/fn/integration/hello/HelloFunction.java deleted file mode 100644 index 409a42e0..00000000 --- a/integration-tests/funcs/helloFunc/src-proto/main/java/com/fnproject/fn/integration/hello/HelloFunction.java +++ /dev/null @@ -1,24 +0,0 @@ -/* - * Copyright (c) 2019, 2020 Oracle and/or its affiliates. All rights reserved. - * - * 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. - */ - -package com.fnproject.fn.integration.hello; - -public class HelloFunction { - public String handleRequest(String input) { - String name = (input == null || input.isEmpty()) ? "world" : input; - return "Hello, " + name + "!"; - } -} \ No newline at end of file diff --git a/integration-tests/funcs/httpgwfunc/Dockerfile b/integration-tests/funcs/httpgwfunc/Dockerfile deleted file mode 100644 index dda6b8f7..00000000 --- a/integration-tests/funcs/httpgwfunc/Dockerfile +++ /dev/null @@ -1,11 +0,0 @@ -FROM fnproject/fn-java-fdk-build:jdk11-1.0.0-SNAPSHOT as build-stage -WORKDIR /function -ENV MAVEN_OPTS -Dhttp.proxyHost= -Dhttp.proxyPort= -Dhttps.proxyHost= -Dhttps.proxyPort= -Dhttp.nonProxyHosts= -Dmaven.repo.local=/usr/share/maven/ref/repository -ADD pom.xml /function/pom.xml -RUN ["mvn", "package", "dependency:copy-dependencies", "-DincludeScope=runtime", "-DskipTests=true", "-Dmdep.prependGroupId=true", "-DoutputDirectory=target", "--fail-never"] -ADD src /function/src -RUN ["mvn", "package"] -FROM fnproject/fn-java-fdk:jre11-1.0.0-SNAPSHOT -WORKDIR /function -COPY --from=build-stage /function/target/*.jar /function/app/ -CMD ["com.example.fn.TriggerFunction::handleRequest"] diff --git a/integration-tests/funcs/httpgwfunc/func.yaml b/integration-tests/funcs/httpgwfunc/func.yaml deleted file mode 100644 index c1eacb5d..00000000 --- a/integration-tests/funcs/httpgwfunc/func.yaml +++ /dev/null @@ -1,27 +0,0 @@ -# -# Copyright (c) 2019, 2020 Oracle and/or its affiliates. All rights reserved. -# -# 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. -# - -schema_version: 20180708 -name: httpgwfunc -version: 0.0.1 -runtime: java -cmd: com.example.fn.TriggerFunction::handleRequest -timeout: 120 -format: http-stream -triggers: -- name: trig - type: http - source: /httpgwfunc-trigger diff --git a/integration-tests/funcs/httpgwfunc/pom.xml b/integration-tests/funcs/httpgwfunc/pom.xml deleted file mode 100644 index bf4fcd84..00000000 --- a/integration-tests/funcs/httpgwfunc/pom.xml +++ /dev/null @@ -1,78 +0,0 @@ - - - - - 4.0.0 - - UTF-8 - 1.0.0-SNAPSHOT - - com.example.fn - hello - 1.0.0 - - - - fn-release-repo - https://dl.bintray.com/fnproject/fnproject - - - - - - com.fnproject.fn - api - ${fdk.version} - - - com.fnproject.fn - testing-core - ${fdk.version} - test - - - com.fnproject.fn - testing-junit4 - ${fdk.version} - test - - - junit - junit - 4.13.1 - test - - - - - - - org.apache.maven.plugins - maven-compiler-plugin - 3.3 - - 8 - 8 - - - - - diff --git a/integration-tests/funcs/httpgwfunc/src/main/java/com/example/fn/TriggerFunction.java b/integration-tests/funcs/httpgwfunc/src/main/java/com/example/fn/TriggerFunction.java deleted file mode 100644 index 09426c54..00000000 --- a/integration-tests/funcs/httpgwfunc/src/main/java/com/example/fn/TriggerFunction.java +++ /dev/null @@ -1,43 +0,0 @@ -/* - * Copyright (c) 2019, 2020 Oracle and/or its affiliates. All rights reserved. - * - * 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. - */ - -package com.example.fn; - -import com.fnproject.fn.api.InvocationContext; -import com.fnproject.fn.api.httpgateway.HTTPGatewayContext; - -public class TriggerFunction { - - public String handleRequest(String input, HTTPGatewayContext hctx, InvocationContext ctx) { - String name = (input == null || input.isEmpty()) ? "world" : input; - - - ctx.setResponseHeader("MyRawHeader", "bar"); - ctx.addResponseHeader("MyRawHeader", "bob"); - - - hctx.setResponseHeader("Content-Type", "text/plain"); - hctx.addResponseHeader("MyHTTPHeader", "foo"); - - hctx.addResponseHeader("GotMethod", hctx.getMethod()); - hctx.addResponseHeader("GotURL", hctx.getRequestURL()); - hctx.addResponseHeader("GotHeader", hctx.getHeaders().get("Foo").orElse("nope")); - - hctx.setStatusCode(202); - return "Hello, " + name + "!"; - } - -} \ No newline at end of file diff --git a/integration-tests/funcs/httpgwfunc/src/test/java/com/example/fn/TriggerFunctionTest.java b/integration-tests/funcs/httpgwfunc/src/test/java/com/example/fn/TriggerFunctionTest.java deleted file mode 100644 index 4dea0c13..00000000 --- a/integration-tests/funcs/httpgwfunc/src/test/java/com/example/fn/TriggerFunctionTest.java +++ /dev/null @@ -1,56 +0,0 @@ -/* - * Copyright (c) 2019, 2020 Oracle and/or its affiliates. All rights reserved. - * - * 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. - */ - -package com.example.fn; - -import com.fnproject.fn.testing.FnResult; -import com.fnproject.fn.testing.FnTestingRule; -import org.junit.Rule; -import org.junit.Test; - -import static org.junit.Assert.assertEquals; - -public class TriggerFunctionTest { - - @Rule - public final FnTestingRule testing = FnTestingRule.createDefault(); - - @Test - public void shouldReturnGreeting() { - testing.givenEvent().enqueue(); - testing.thenRun(TriggerFunction.class, "handleRequest"); - - FnResult result = testing.getOnlyResult(); - assertEquals("Hello, world!", result.getBodyAsString()); - } - - - @Test - public void shouldWorkWithHTTP() { - testing.givenEvent() - .withHeader("Fn-Http-Method", "POST") - .withHeader("Fn-Http-H-Foo", "bar") - .withHeader("Fn-Http-Request-Url", "http://mysite.com/?q1=2&q3=4") - .enqueue(); - testing.thenRun(TriggerFunction.class, "handleRequest"); - - FnResult result = testing.getOnlyResult(); - assertEquals("Hello, world!", result.getBodyAsString()); - assertEquals("202", result.getHeaders().get("Fn-Http-Status").orElse("")); - } - - -} \ No newline at end of file diff --git a/integration-tests/funcs/simpleFunc/Dockerfile b/integration-tests/funcs/simpleFunc/Dockerfile deleted file mode 100644 index a929c735..00000000 --- a/integration-tests/funcs/simpleFunc/Dockerfile +++ /dev/null @@ -1,11 +0,0 @@ -FROM fnproject/fn-java-fdk-build:__TO_BE_REPLACED__ as build-stage -WORKDIR /function -ENV MAVEN_OPTS -Dhttp.proxyHost= -Dhttp.proxyPort= -Dhttps.proxyHost= -Dhttps.proxyPort= -Dhttp.nonProxyHosts= -Dmaven.repo.local=/usr/share/maven/ref/repository -ADD pom.xml /function/pom.xml -RUN ["mvn", "package", "dependency:copy-dependencies", "-DincludeScope=runtime", "-DskipTests=true", "-Dmdep.prependGroupId=true", "-DoutputDirectory=target", "--fail-never"] -ADD src /function/src -RUN ["mvn", "package"] -FROM fnproject/fn-java-fdk:__TO_BE_REPLACED__ -WORKDIR /function -COPY --from=build-stage /function/target/*.jar /function/app/ -CMD ["com.fnproject.fn.integration.test2.PlainFunction::handleRequest"] diff --git a/integration-tests/funcs/simpleFunc/func.yaml b/integration-tests/funcs/simpleFunc/func.yaml deleted file mode 100644 index cbf5df6a..00000000 --- a/integration-tests/funcs/simpleFunc/func.yaml +++ /dev/null @@ -1,23 +0,0 @@ -# -# Copyright (c) 2019, 2020 Oracle and/or its affiliates. All rights reserved. -# -# 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. -# - -schema_version: 20180708 -name: simplefunc -version: 0.0.3 -runtime: java11 -timeout: 120 -cmd: com.fnproject.fn.integration.test2.PlainFunction::handleRequest -format: http-stream diff --git a/integration-tests/funcs/simpleFunc/pom.xml b/integration-tests/funcs/simpleFunc/pom.xml deleted file mode 100644 index 1c9fe9f2..00000000 --- a/integration-tests/funcs/simpleFunc/pom.xml +++ /dev/null @@ -1,84 +0,0 @@ - - - - - 4.0.0 - - UTF-8 - 1.0.0-SNAPSHOT - - com.fnproject.fn - integration-test-2 - 1.0.0 - - - - com.fnproject.fn - api - ${fdk.version} - - - com.fnproject.fn - testing-core - ${fdk.version} - - - com.fnproject.fn - testing-junit4 - ${fdk.version} - - - junit - junit - 4.13.1 - test - - - - - - - org.apache.maven.plugins - maven-compiler-plugin - 3.3 - - 1.8 - 1.8 - - - - org.apache.maven.plugins - maven-deploy-plugin - 2.8.2 - - true - - - - - - - - fn-maven-releases - https://dl.bintray.com/fnproject/fnproject - - - diff --git a/integration-tests/funcs/simpleFunc/src/main/java/com/fnproject/fn/integration/test2/PlainFunction.java b/integration-tests/funcs/simpleFunc/src/main/java/com/fnproject/fn/integration/test2/PlainFunction.java deleted file mode 100644 index 6b769602..00000000 --- a/integration-tests/funcs/simpleFunc/src/main/java/com/fnproject/fn/integration/test2/PlainFunction.java +++ /dev/null @@ -1,38 +0,0 @@ -/* - * Copyright (c) 2019, 2020 Oracle and/or its affiliates. All rights reserved. - * - * 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. - */ - -package com.fnproject.fn.integration.test2; - -import com.fnproject.fn.api.FnConfiguration; -import com.fnproject.fn.api.RuntimeContext; - -public class PlainFunction { - - private String greeting; - - @FnConfiguration - public void configuration(RuntimeContext ctx) { - System.err.println("Configuration called"); - this.greeting = ctx.getConfigurationByKey("GREETING") - .orElseThrow(() -> new RuntimeException("Greeting must be set")); - } - - public String handleRequest(String input) { - String name = (input == null || input.isEmpty()) ? "world" : input; - - return greeting + ", " + name + "!"; - } -} diff --git a/integration-tests/funcs/simpleFunc/src/test/java/com/fnproject/fn/integration/test2/PlainFunctionTest.java b/integration-tests/funcs/simpleFunc/src/test/java/com/fnproject/fn/integration/test2/PlainFunctionTest.java deleted file mode 100644 index 501b6bcb..00000000 --- a/integration-tests/funcs/simpleFunc/src/test/java/com/fnproject/fn/integration/test2/PlainFunctionTest.java +++ /dev/null @@ -1,46 +0,0 @@ -/* - * Copyright (c) 2019, 2020 Oracle and/or its affiliates. All rights reserved. - * - * 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. - */ - -package com.fnproject.fn.integration.test2; - -import com.fnproject.fn.testing.FnResult; -import com.fnproject.fn.testing.FnTestingRule; -import org.junit.Before; -import org.junit.Rule; -import org.junit.Test; - -import static org.junit.Assert.assertEquals; - -public class PlainFunctionTest { - - @Rule - public final FnTestingRule testing = FnTestingRule.createDefault(); - - @Before - public void setUp() { - testing.setConfig("GREETING", "Howdy"); - } - - @Test - public void shouldReturnGreeting() { - testing.givenEvent().enqueue(); - testing.thenRun(PlainFunction.class, "handleRequest"); - - FnResult result = testing.getOnlyResult(); - assertEquals("Howdy, world!", result.getBodyAsString()); - } - -} diff --git a/integration-tests/pom.xml b/integration-tests/pom.xml deleted file mode 100644 index 1cc72169..00000000 --- a/integration-tests/pom.xml +++ /dev/null @@ -1,100 +0,0 @@ - - - - - - 4.0.0 - - com.fnproject - integration-tests - 1.0.0-SNAPSHOT - - 3.16.1 - 2.10.0 - 2.11.0 - 4.13.1 - 2.22.1 - - jar - - - - commons-io - commons-io - ${commons-io.version} - - - junit - junit - ${junit.version} - - - org.assertj - assertj-core - ${assertj-core.version} - - - com.fasterxml.jackson.core - jackson-databind - ${jackson.version} - - - com.fasterxml.jackson.core - jackson-core - ${jackson.version} - - - com.fasterxml.jackson.core - jackson-annotations - ${jackson.version} - - - - - - - org.apache.maven.plugins - maven-compiler-plugin - 3.8.0 - - 1.8 - 1.8 - - - - org.apache.maven.plugins - maven-deploy-plugin - 2.8.2 - - true - - - - org.apache.maven.plugins - maven-surefire-plugin - ${surefire.version} - - false - - - - - diff --git a/integration-tests/run_tests_ci.sh b/integration-tests/run_tests_ci.sh deleted file mode 100755 index 399722a0..00000000 --- a/integration-tests/run_tests_ci.sh +++ /dev/null @@ -1,114 +0,0 @@ -#!/usr/bin/env bash -# -# Copyright (c) 2019, 2020 Oracle and/or its affiliates. All rights reserved. -# -# 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. -# - -set -e -set -x - - -cd $(dirname $0) - -if [ -z ${REPOSITORY_LOCATION} ]; then - echo no REPOSITORY_LOCATION is specified in env using /tmp/staging_repo as default - - REPOSITORY_LOCATION=/tmp/staging_repo -fi - - -docker rm -f fn_mvn_repo || true -docker run -d \ - -v "${REPOSITORY_LOCATION}":/repo:ro \ - -w /repo -p18080:18080 \ - --name fn_mvn_repo \ - python:2.7 \ - python -mSimpleHTTPServer 18080 - - -until $(curl --output /dev/null --silent --fail http://localhost:18080); do - printf '.' - sleep 1 -done - - -# Start Fn -fn stop || true -fn start --log-level=debug -d --env-file fnserver.env - -until $(curl --output /dev/null --silent --fail http://localhost:8080/); do - printf '.' - sleep 1 -done - - -export FN_LOG_FILE=/tmp/fn.log -docker logs -f fnserver >& ${FN_LOG_FILE} & - -FNSERVER_IP=$(docker inspect --type container -f '{{.NetworkSettings.IPAddress}}' fnserver) - - - -# These tests are Fn flow which never got productionized. Commenting these -# tests as we had to remove the infra/provision directory to eliminate -# security findings - https://jira-sd.mc1.oracleiaas.com/browse/FAAS-13105 -# We need to re-implement most of flow functionalities from scratch if -# we decide to productionize it. - -# docker rm -f flowserver || true -# docker run --rm -d \ -# -p 8081:8081 \ -# -e API_URL="http://${FNSERVER_IP}:8080/invoke" \ -# -e no_proxy=${FNSERVER_IP} \ -# --name flowserver \ -# fnproject/flow:latest - -# until $(curl --output /dev/null --silent --fail http://localhost:8081/ping); do -# printf '.' -# sleep 1 -# done -# export FLOW_LOG_FILE=/tmp/flow.log - -# docker logs -f flowserver >& ${FLOW_LOG_FILE} & -set +e - - -if [ $(uname -s) == "Darwin" ] ; then - DOCKER_LOCALHOST=docker.for.mac.host.internal -else - DOCKER_LOCALHOST=$(ifconfig eth0| grep -Eo 'inet (addr:)?([0-9]*\.){3}[0-9]*' | grep -Eo '([0-9]*\.){3}[0-9]*' | grep -v '127.0.0.1') -fi - -export DOCKER_LOCALHOST - -REPO_IP=$(docker inspect --type container -f '{{.NetworkSettings.IPAddress}}' fn_mvn_repo) -MAVEN_REPOSITORY="http://${REPO_IP}:18080" -export MAVEN_REPOSITORY -# COMPLETER_IP=$(docker inspect --type container -f '{{.NetworkSettings.IPAddress}}' flowserver) -# COMPLETER_BASE_URL="http://${COMPLETER_IP}:8081" -# export COMPLETER_BASE_URL - -export no_proxy="${no_proxy},${DOCKER_LOCALHOST},${REPO_IP}" - -echo "Running tests" -mvn test -result=$? - - - -# docker rm -f flowserver -docker rm -f fnserver -docker rm -rf fn_mvn_repo - -exit $result diff --git a/integration-tests/src/main/java/com/fnproject/fn/integrationtest/IntegrationTestRule.java b/integration-tests/src/main/java/com/fnproject/fn/integrationtest/IntegrationTestRule.java deleted file mode 100644 index 3e2aef67..00000000 --- a/integration-tests/src/main/java/com/fnproject/fn/integrationtest/IntegrationTestRule.java +++ /dev/null @@ -1,421 +0,0 @@ -/* - * Copyright (c) 2019, 2020 Oracle and/or its affiliates. All rights reserved. - * - * 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. - */ - -package com.fnproject.fn.integrationtest; - -import org.apache.commons.io.FileUtils; -import org.apache.commons.io.input.Tailer; -import org.apache.commons.io.input.TailerListenerAdapter; -import org.assertj.core.api.Assertions; -import org.junit.rules.TestRule; -import org.junit.runner.Description; -import org.junit.runners.model.Statement; - -import java.io.BufferedReader; -import java.io.File; -import java.io.IOException; -import java.io.InputStreamReader; -import java.nio.charset.StandardCharsets; -import java.nio.file.Files; -import java.nio.file.Path; -import java.util.*; -import java.util.concurrent.CompletableFuture; -import java.util.concurrent.TimeUnit; - -/** - * Wrapper around fn cli to invoke function integration tests. - * Created on 14/09/2018. - *

    - * (c) 2018 Oracle Corporation - */ -public class IntegrationTestRule implements TestRule { - - - private static final String repoPlaceholder = "https://dl.bintray.com/fnproject/fnproject"; - private static final String versionPlaceholder = "1.0.0-SNAPSHOT"; - private static final String snapshotPlaceholderRegex = ".*"; - private int appCount = 0; - private String testName; - - - private final List cleanupDirs = new ArrayList<>(); - private final List cleanupApps = new ArrayList<>(); - - public String getFlowURL() { - String url = System.getenv("COMPLETER_BASE_URL"); - if (url == null) { - return "http://" + getDockerLocalhost() + ":8081"; - } - return url; - } - - /** - * Returns a hostname tha resolves to the test host from within a docker container - */ - public String getDockerLocalhost() { - String dockerLocalhost = System.getenv("DOCKER_LOCALHOST"); - if (dockerLocalhost == null) { - String osName = System.getProperty("os.name", "generic").toLowerCase(Locale.ENGLISH); - - if (osName.contains("darwin") || osName.contains("mac")) { - return "docker.for.mac.host.internal"; - } else - throw new RuntimeException("Unable to determine docker localhost address - set 'DOCKER_LOCALHOST' env variable to the docker host network address "); - } - return dockerLocalhost; - } - - private String getLocalFnRepo() { - String envRepo = System.getenv("MAVEN_REPOSITORY"); - if (envRepo == null) { - envRepo = "http://" + getDockerLocalhost() + ":18080"; - } - return envRepo; - } - - - /** - * Returns the current FDK version for this build - * @return A the FDK version (e.g. 1.0.112 or 1.0.0-SNAPSHOT) - */ - public String getFdkVersion() { - String version = System.getenv("FN_JAVA_FDK_VERSION"); - - if (version == null) { - version = "1.0.0-SNAPSHOT"; - } - return version; - } - - private String getFnLogFile() { - return System.getenv("FN_LOG_FILE"); - } - - private String getFlowLogFile() { - return System.getenv("FLOW_LOG_FILE"); - } - - private String getFnCmd() { - String cmd = System.getenv("FN_CMD"); - if (cmd == null) { - return "fn"; - } - return cmd; - } - - - public static class CmdResult { - private final String cmd; - private final boolean success; - private final String stdout; - private final String stderr; - - private CmdResult(String cmd, boolean success, String stdout, String stderr) { - this.success = success; - this.stdout = stdout; - this.stderr = stderr; - this.cmd = cmd; - } - - boolean isSuccess() { - return success; - } - - public String getStdout() { - return stdout; - } - - public String getStderr() { - return stderr; - } - - public String toString() { - return "CmdResult: cmd=" + cmd + ", success=" + success + ", stdout=" + stdout + ", stderr=" + stderr; - } - } - - public class TestContext { - - private File baseDir; - private final String testName; - - public TestContext(File baseDir, String testName) { - this.baseDir = baseDir; - this.testName = testName; - } - - /** - * Copies the contents of a given directory (relative to test root) into the temporary test directory - * - * @param location local directory - * @return - * @throws IOException - */ - public TestContext withDirFrom(String location) throws IOException { - FileUtils.copyDirectory(new File(location), baseDir); - return this; - } - - public CmdResult runFnWithInput(String input, String... args) throws Exception { - CmdResult res = runFnWithInputAllowError(input, args); - - if (res.isSuccess() == false) { - System.err.println("FN FAIL!"); - System.err.println(res.toString()); - } - - Assertions.assertThat(res.isSuccess()).withFailMessage("Expected command '" + res.cmd + "' to return 0." + "FN FAIL: " + res).isTrue(); - return res; - } - - /** - * Runs the configured Fn command with input returning a process result - * - * @param input the input string ot pass as fn stdin - * @param args args to fn (excluding the fn command itself) - * @return a command result to get the result of a command - * @throws Exception - */ - public CmdResult runFnWithInputAllowError(String input, String... args) throws Exception { - List cmd = new ArrayList<>(); - cmd.add(getFnCmd()); - cmd.addAll(Arrays.asList(args)); - - System.err.println("Running '" + String.join(" ", cmd) + "'"); - ProcessBuilder pb = new ProcessBuilder(cmd); - pb.directory(baseDir); - - if (System.getenv("FN_JAVA_FDK_VERSION") == null) { - // this means that FN init will pick up the local version not the latest. - pb.environment().put("FN_JAVA_FDK_VERSION", "1.0.0-SNAPSHOT"); - } - - // Sort of a hack for local mac running with a proxy - String noProxy = Optional.ofNullable(System.getenv("no_proxy")).map((f) -> f + ",").orElse("") + getDockerLocalhost(); - System.err.printf("setting no_proxy '%s'\n",noProxy); - pb.environment().put("no_proxy", noProxy); - - Process p = pb.start(); - - p.getOutputStream().write(input.getBytes()); - p.getOutputStream().close(); - - CompletableFuture stderr = new CompletableFuture<>(); - - new Thread(() -> { - - try { - BufferedReader bri = new BufferedReader - (new InputStreamReader(p.getErrorStream())); - - StringBuilder output = new StringBuilder(); - String line; - while ((line = bri.readLine()) != null) { - System.err.println("FN ERR: " + line); - output.append(line); - } - stderr.complete(output.toString()); - } catch (IOException e) { - stderr.completeExceptionally(e); - } - }).start(); - - BufferedReader bri = new BufferedReader - (new InputStreamReader(p.getInputStream())); - - StringBuilder output = new StringBuilder(); - String line; - while ((line = bri.readLine()) != null) { - System.err.println("FN OUT: " + line); - output.append(line); - } - p.waitFor(600, TimeUnit.SECONDS); - System.err.println("Command '" + String.join(" ", cmd) + "' with code " + p.exitValue()); - - return new CmdResult(String.join(" ", cmd), p.exitValue() == 0, output.toString(), stderr.get()); - } - - /** - * Runs the configure `fn` command with given arguments fails if the command returns without succes - * - * @param args - * @return a command result capturinng the output of fn - * @throws Exception - */ - public CmdResult runFn(String... args) throws Exception { - return runFnWithInput("", args); - } - - - /** - * Rewrites the POM to reflect the correct target repo - */ - public TestContext rewritePOM() throws Exception { - File pomFile = new File(baseDir, "pom.xml"); - - String pomFileContent = FileUtils.readFileToString(pomFile, StandardCharsets.UTF_8); - String newPomContent = pomFileContent.replace(repoPlaceholder, "" + getLocalFnRepo() + ""); - Assertions.assertThat(newPomContent).withFailMessage("No placeholder found in POM").isNotEqualTo(pomFileContent); - - String versionPomContent = newPomContent.replace(versionPlaceholder, "" + getFdkVersion() + ""); - - versionPomContent = versionPomContent.replaceFirst(snapshotPlaceholderRegex, "true"); - - System.err.println(versionPomContent); - FileUtils.writeStringToFile(pomFile, versionPomContent, StandardCharsets.UTF_8); - return this; - } - - - /** - * Rewrites the Dockerfile to provide a settings file which works around - * problems with Maven HTTP repos. - */ - public TestContext rewriteDockerfile(Boolean java11) throws Exception { - String jdkPrefix = java11 ? "jdk11-" : ""; - String jrePrefix = java11 ? "jre11-" : ""; - - File dFile = new File(baseDir, "Dockerfile"); - String dFileContent = FileUtils.readFileToString(dFile, StandardCharsets.UTF_8); - - String buildImageStringToMatch = "FROM fnproject/fn-java-fdk-build:[^ ]+ as build"; - String newContent = dFileContent.replaceFirst(buildImageStringToMatch, "FROM fnproject/fn-java-fdk-build:" + jdkPrefix + getFdkVersion() + " as build"); - - String runtimeImageStringToMatch = "FROM fnproject/fn-java-fdk:[^\n ]+"; - String newContent2 = newContent.replaceFirst(runtimeImageStringToMatch, "FROM fnproject/fn-java-fdk:" + jrePrefix + getFdkVersion()); - - String mavenSettingsFileContent = generateMavenSettingsFileContent(); - File mFile = new File(baseDir, "maven-settings.xml"); - System.err.println(mavenSettingsFileContent); - FileUtils.writeStringToFile(mFile, mavenSettingsFileContent, StandardCharsets.UTF_8); - - String runMavenLine = "RUN [\"mvn\", \"package\", \"dependency:copy-dependencies\""; - String runMavenLineAsRegex = "RUN \\[\\\"mvn\\\", \\\"package\\\", \\\"dependency:copy-dependencies\\\""; - String newContent3 = newContent2.replaceFirst(runMavenLineAsRegex, "ADD maven-settings.xml /usr/share/maven/conf/settings.xml" + System.getProperty("line.separator") + runMavenLine); - - System.err.println(newContent3); - FileUtils.writeStringToFile(dFile, newContent3, StandardCharsets.UTF_8); - return this; - } - - - /** - * Gets the app name you should use for tests. - * - * @return - */ - public String appName() { - return this.testName; - } - - public TestContext mkdir(String name) { - new File(baseDir, name).mkdir(); - return this; - } - - public TestContext cd(String dir) { - baseDir = new File(baseDir, dir); - return this; - } - - private String generateMavenSettingsFileContent() { - return String.join(System.getProperty("line.separator"), - "", - "", - " ", - " ", - " override-maven-default-http-blocker", - " external:http:*", - " Pseudo repository to mirror external repositories initially using HTTP.", - " " + getLocalFnRepo() + "", - " false", - " ", - " ", - ""); - } - } - - - /** - * creates a new test contesxt - * - * @return - * @throws IOException - */ - public TestContext newTest() throws IOException { - Path tmpDir = Files.createTempDirectory("fnitest"); - cleanupDirs.add(tmpDir.toFile()); - String appName = testName + appCount++; - cleanupApps.add(appName); - return new TestContext(tmpDir.toFile(), appName); - } - - - @Override - public Statement apply(Statement statement, Description description) { - - return new Statement() { - @Override - public void evaluate() throws Throwable { - testName = description.getMethodName(); - StringBuilder fnOutput = new StringBuilder(); - StringBuilder flowOutput = new StringBuilder(); - - Tailer fnTailer = null; - if (getFnLogFile() != null) { - fnTailer = Tailer.create(new File(getFnLogFile()), new TailerListenerAdapter() { - @Override - public void handle(final String line) { - System.err.println("FNSRV:" + line); - fnOutput.append(line); - } - }, 10, true); - } - - Tailer flowTailer = null; - - if (getFlowLogFile() != null) { - flowTailer = Tailer.create(new File(getFlowLogFile()), new TailerListenerAdapter() { - @Override - public void handle(final String line) { - System.err.println("FLOW:" + line); - fnOutput.append(line); - } - }, 10, true); - } - - try { - statement.evaluate(); - } finally { - - for (File cleanup : cleanupDirs) { - FileUtils.deleteDirectory(cleanup); - } - - if (fnTailer != null) { - fnTailer.stop(); - } - - if (flowTailer != null) { - flowTailer.stop(); - } - } - } - }; - } -} diff --git a/integration-tests/src/test/java/com/fnproject/fn/integrationtest/FlowTest.java b/integration-tests/src/test/java/com/fnproject/fn/integrationtest/FlowTest.java deleted file mode 100644 index e1028fbb..00000000 --- a/integration-tests/src/test/java/com/fnproject/fn/integrationtest/FlowTest.java +++ /dev/null @@ -1,124 +0,0 @@ -/* - * Copyright (c) 2019, 2020 Oracle and/or its affiliates. All rights reserved. - * - * 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. - */ - -package com.fnproject.fn.integrationtest; - -import com.fnproject.fn.integrationtest.IntegrationTestRule.CmdResult; -import com.sun.net.httpserver.HttpServer; -import org.junit.Rule; -import org.junit.Test; - -import java.net.InetSocketAddress; -import java.util.concurrent.CompletableFuture; -import java.util.concurrent.TimeUnit; - -import static org.assertj.core.api.Assertions.assertThat; - -/** - * Created on 14/09/2018. - *

    - * (c) 2018 Oracle Corporation - */ -public class FlowTest { - - @Rule - public final IntegrationTestRule testRule = new IntegrationTestRule(); - - //These tests are Fn flow which never got productionized. Commenting these - //tests as we had to remove the infra/provision directory to eliminate - //security findings - https://jira-sd.mc1.oracleiaas.com/browse/FAAS-13105 - - //We need to re-implement most of flow functionalities from scratch if - //we decide to productionize it. - - //@Test - //public void shouldInvokeBasicFlow() throws Exception { - // IntegrationTestRule.TestContext tc = testRule.newTest(); - // tc.withDirFrom("funcs/flowBasic").rewritePOM().rewriteDockerfile(true); - // tc.runFn("--verbose", "deploy", "--create-app", "--app", tc.appName(), "--local"); - // tc.runFn("config", "app", tc.appName(), "COMPLETER_BASE_URL", testRule.getFlowURL()); - // CmdResult r = tc.runFnWithInput("1", "invoke", tc.appName(), "flowbasic"); - // assertThat(r.getStdout()).isEqualTo("4"); - //} - - - //@Test - //public void shouldInvokeBasicFlowJDK8() throws Exception { - // IntegrationTestRule.TestContext tc = testRule.newTest(); - // tc.withDirFrom("funcs/flowBasicJDK8").rewritePOM().rewriteDockerfile(false); - // tc.runFn("--verbose", "deploy", "--create-app", "--app", tc.appName(), "--local"); - // tc.runFn("config", "app", tc.appName(), "COMPLETER_BASE_URL", testRule.getFlowURL()); - // CmdResult r = tc.runFnWithInput("1", "invoke", tc.appName(), "flowbasicj8"); - // assertThat(r.getStdout()).isEqualTo("4"); - //} - - - //@Test - //public void shouldExerciseAllFlow() throws Exception { - // IntegrationTestRule.TestContext tc = testRule.newTest(); - // tc.withDirFrom("funcs/flowAllFeatures").rewritePOM().rewriteDockerfile(true); - // tc.runFn("--verbose", "deploy", "--create-app", "--app", tc.appName(), "--local"); - // tc.runFn("config", "app", tc.appName(), "COMPLETER_BASE_URL", testRule.getFlowURL()); - // CmdResult r = tc.runFnWithInput("1", "invoke", tc.appName(), "flowallfeatures"); - // assertThat(r.getStdout()).contains("Everything worked"); - //} - - - // THESE TESTS ARE FLAKEY AND SHOULD BE REVISITED. - - // @Test - // public void shouldCallExitHooks() throws Exception { - // CompletableFuture done = new CompletableFuture<>(); - - // HttpServer server = HttpServer.create(new InetSocketAddress(8000), 0); - // server.createContext("/exited", httpExchange -> { - // done.complete(true); - // String resp = "ok"; - // httpExchange.sendResponseHeaders(200, resp.length()); - // httpExchange.getResponseBody().write(resp.getBytes()); - // httpExchange.getResponseBody().close(); - // }); - // server.setExecutor(null); // creates a default executor - // server.start(); - // try { - // IntegrationTestRule.TestContext tc = testRule.newTest(); - // tc.withDirFrom("funcs/flowExitHooks").rewritePOM().rewriteDockerfile(true); - // tc.runFn("--verbose", "build", "--no-cache"); - // tc.runFn("--verbose", "deploy", "--create-app", "--app", tc.appName(), "--local"); - // tc.runFn("config", "app", tc.appName(), "COMPLETER_BASE_URL", testRule.getFlowURL()); - // tc.runFn("config", "app", tc.appName(), "TERMINATION_HOOK_URL", "http://" + testRule.getDockerLocalhost() + ":" + 8000 + "/exited"); - // CmdResult r = tc.runFnWithInput("1", "invoke", tc.appName(), "flowexithooks"); - // assertThat(r.getStdout()).contains("42"); - - // assertThat(done.get(10, TimeUnit.SECONDS)).withFailMessage("Expected callback within 10 seconds").isTrue(); - - // } finally { - // server.stop(0); - // } - // } - - - // @Test - // public void shouldHandleTimeouts() throws Exception { - // IntegrationTestRule.TestContext tc = testRule.newTest(); - // tc.withDirFrom("funcs/flowTimeouts").rewritePOM().rewriteDockerfile(true); - // tc.runFn("--verbose", "deploy", "--create-app", "--app", tc.appName(), "--local"); - // tc.runFn("config", "app", tc.appName(), "COMPLETER_BASE_URL", testRule.getFlowURL()); - // CmdResult r = tc.runFn("invoke", tc.appName(), "flowtimeouts"); - // assertThat(r.getStdout()).contains("timeout"); - // } - -} diff --git a/integration-tests/src/test/java/com/fnproject/fn/integrationtest/FunctionsTest.java b/integration-tests/src/test/java/com/fnproject/fn/integrationtest/FunctionsTest.java deleted file mode 100644 index dc9ec597..00000000 --- a/integration-tests/src/test/java/com/fnproject/fn/integrationtest/FunctionsTest.java +++ /dev/null @@ -1,167 +0,0 @@ -/* - * Copyright (c) 2019, 2020 Oracle and/or its affiliates. All rights reserved. - * - * 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. - */ - -package com.fnproject.fn.integrationtest; - -import java.net.HttpURLConnection; -import java.net.Proxy; -import java.net.URI; -import java.net.URL; -import java.util.HashMap; -import java.util.List; -import java.util.Map; - -import com.fasterxml.jackson.annotation.JsonIgnoreProperties; -import com.fasterxml.jackson.databind.ObjectMapper; -import com.fnproject.fn.integrationtest.IntegrationTestRule.CmdResult; -import org.junit.Rule; -import org.junit.Test; - -import static org.assertj.core.api.Assertions.assertThat; - -/** - * Created on 14/09/2018. - *

    - * (c) 2018 Oracle Corporation - */ -public class FunctionsTest { - - @Rule - public final IntegrationTestRule testRule = new IntegrationTestRule(); - - - @Test - public void shouldCallExistingFn() throws Exception { - IntegrationTestRule.TestContext tc = testRule.newTest(); - tc.withDirFrom("funcs/simpleFunc").rewritePOM().rewriteDockerfile(true); - - tc.runFn("--verbose", "deploy", "--create-app", "--app", tc.appName(), "--local"); - tc.runFn("config", "app", tc.appName(), "GREETING", "Salutations"); - - CmdResult r1 = tc.runFnWithInput("", "invoke", tc.appName(), "simplefunc"); - assertThat(r1.getStdout()).isEqualTo("Salutations, world!"); - - CmdResult r2 = tc.runFnWithInput("tests", "invoke", tc.appName(), "simplefunc"); - assertThat(r2.getStdout()).isEqualTo("Salutations, tests!"); - - } - - // - // AS OF 2021-04-07 WE ARE UNABLE TO TEST THE "OUT OF THE BOX" EXPERIENCE - // WITH A LOCAL FDK SERVED THROUGH AN HTTP SERVER BECAUSE MAVEN HAS DISABLED - // SUPPORT FOR HTTP REPOSITORIES BY DEFAULT DUE TO CVE-2021-26291. - // IF WE WERE TO PROVIDE A CUSTOM DOCKERFILE TO WORK AROUND MAVEN'S DEFAULT - // BEHAVIOUR, LIKE WE DO FOR THE TESTS AROUND THIS ONE, WE WOULD NOT BE - // TESTING THE "OUT OF THE BOX" EXPERIENCE ANYWAY, SO THIS TEST IS MOOT. - // - // @Test() - // public void checkBoilerPlate() throws Exception { - // for (String runtime : new String[] {"java8", "java11"}) { - // IntegrationTestRule.TestContext tc = testRule.newTest(); - // String fnName = "bp" + runtime; - // tc.runFn("init", "--runtime", runtime, "--name", fnName); - // tc.rewritePOM(); - // tc.runFn("--verbose", "deploy", "--create-app", "--app", tc.appName(), "--local"); - // CmdResult rs = tc.runFnWithInput("wibble", "invoke", tc.appName(), fnName); - // assertThat(rs.getStdout()).contains("Hello, wibble!"); - // } - //} - // - - @Test() - public void runNativeFunction() throws Exception { - - int i = 0; - for(String version : new String[]{"jdk11-" + testRule.getFdkVersion(),testRule.getFdkVersion()}) { - IntegrationTestRule.TestContext tc = testRule.newTest(); - String fnName = "graaltest" + i++; - tc.runFn("init", "--init-image", "fnproject/fn-java-native-init:" + version, "--name", fnName); - tc.rewritePOM().rewriteDockerfile(version != testRule.getFdkVersion()); - tc.runFn("--verbose", "deploy", "--create-app", "--app", tc.appName(), "--local"); - CmdResult rs = tc.runFnWithInput("wibble", "invoke", tc.appName(), fnName); - assertThat(rs.getStdout()).contains("Hello, wibble!"); - } - } - - @JsonIgnoreProperties(ignoreUnknown = true) - public static class InspectResponse { - - public Map annotations = new HashMap<>(); - } - - @Test() - public void shouldHandleTrigger() throws Exception { - IntegrationTestRule.TestContext tc = testRule.newTest(); - tc.withDirFrom("funcs/httpgwfunc").rewritePOM().rewriteDockerfile(true); - tc.runFn("--verbose", "deploy", "--create-app", "--app", tc.appName(), "--local"); - - // Get me the trigger URL - CmdResult output = tc.runFn("inspect", "trigger", tc.appName(), "httpgwfunc", "trig"); - - ObjectMapper om = new ObjectMapper(); - InspectResponse resp = om.readValue(output.getStdout(), InspectResponse.class); - String dest = resp.annotations.get("fnproject.io/trigger/httpEndpoint"); - assertThat(dest).withFailMessage("Missing trigger endpoint annotation").isNotNull(); - - String url = dest + "?q1=a&q2=b"; - URL invokeURL = URI.create(url).toURL(); - - System.out.println("calling " + url); - HttpURLConnection con = (HttpURLConnection) invokeURL.openConnection(); - - con.setRequestMethod("POST"); - con.addRequestProperty("Foo", "bar"); - - - assertThat(con.getResponseCode()).isEqualTo(202); - assertThat(con.getHeaderField("GotMethod")).isEqualTo("POST"); - assertThat(con.getHeaderField("GotURL")).isEqualTo(url); - assertThat(con.getHeaderField("GotHeader")).isEqualTo("bar"); - assertThat(con.getHeaderField("MyHTTPHeader")).isEqualTo("foo"); - - } - - @Test - public void shouldGetFDKVersion() throws Exception { - IntegrationTestRule.TestContext tc = testRule.newTest(); - tc.withDirFrom("funcs/simpleFunc").rewritePOM().rewriteDockerfile(true); - - tc.runFn("--verbose", "deploy", "--create-app", "--app", tc.appName(), "--local"); - tc.runFn("config", "app", tc.appName(), "GREETING", "Salutations"); - - CmdResult r1 = tc.runFn("inspect", "function", tc.appName(), "simplefunc", "--endpoint"); - - String url = r1.getStdout().trim(); - - HttpURLConnection conn = (HttpURLConnection) (new URL(url).openConnection(Proxy.NO_PROXY)); - conn.setRequestMethod("POST"); - conn.setRequestProperty("Content-Type", "application/json; utf-8"); - conn.setDoInput(true); - conn.setDoOutput(true); - conn.getOutputStream().write(new byte[0]); - Map> headers = conn.getHeaderFields(); - - assertThat(headers).hasEntrySatisfying("Fn-Fdk-Version", (val) -> { - assertThat(val).isNotEmpty(); - assertThat(val.get(0)).matches("fdk-java/\\d+\\.\\d+\\.\\d+(-SNAPSHOT)? \\(jvm=.*, jvmv=.*\\)"); - }); - - assertThat(headers).hasEntrySatisfying("Fn-Fdk-Runtime", (val) -> { - assertThat(val).isNotEmpty(); - assertThat(val.get(0)).matches("java/.+\\ .+"); - }); - } -} diff --git a/release.version b/release.version index 82d042d9..75c0b87b 100644 --- a/release.version +++ b/release.version @@ -1 +1 @@ -1.0.138 +1.0.139 diff --git a/runtime/src/main/c/CMakeLists.txt b/runtime/src/main/c/CMakeLists.txt index 8d2746a7..c623430c 100644 --- a/runtime/src/main/c/CMakeLists.txt +++ b/runtime/src/main/c/CMakeLists.txt @@ -1,6 +1,9 @@ cmake_minimum_required(VERSION 2.8) project(fnunixsocket) set(CMAKE_BUILD_TYPE Release) +set(JAVA_AWT_LIBRARY NotNeeded) +set(JAVA_JVM_LIBRARY NotNeeded) +set(JAVA_AWT_INCLUDE_PATH NotNeeded) find_package(JNI REQUIRED) include_directories(${JNI_INCLUDE_DIRS}) set(CMAKE_C_STANDARD 11) From b126d5e7a6ae918f1409acfd576764512e385216 Mon Sep 17 00:00:00 2001 From: CI Date: Wed, 27 Oct 2021 07:08:33 +0000 Subject: [PATCH 243/310] Releasing version 1.0.140 --- examples/async-thumbnails/pom.xml | 67 ++++++++++++++++++- .../fn/examples/ThumbnailsFunction.java | 18 +++-- release.version | 2 +- 3 files changed, 81 insertions(+), 6 deletions(-) diff --git a/examples/async-thumbnails/pom.xml b/examples/async-thumbnails/pom.xml index 2d866229..cb0aab8d 100644 --- a/examples/async-thumbnails/pom.xml +++ b/examples/async-thumbnails/pom.xml @@ -60,7 +60,7 @@ io.minio minio - 5.0.1 + 7.1.3 com.fnproject.fn @@ -91,6 +91,71 @@ com.github.tomakehurst wiremock 2.27.2 + + + com.jayway.jsonpath + json-path + + + com.github.jknack + handlebars + + + org.apache.httpcomponents + httpclient + + + + + + org.eclipse.jetty + jetty-server + 9.4.44.v20210927 + + + org.eclipse.jetty + jetty-servlet + 9.4.44.v20210927 + + + org.eclipse.jetty + jetty-servlets + 9.4.44.v20210927 + + + org.eclipse.jetty + jetty-webapp + 9.4.44.v20210927 + + + + com.jayway.jsonpath + json-path + 2.6.0 + + + + com.github.jknack + handlebars + 4.2.1 + + + + org.apache.httpcomponents + httpclient + 4.5.13 + + + commons-codec + commons-codec + + + + + + commons-codec + commons-codec + 1.15 diff --git a/examples/async-thumbnails/src/main/java/com/fnproject/fn/examples/ThumbnailsFunction.java b/examples/async-thumbnails/src/main/java/com/fnproject/fn/examples/ThumbnailsFunction.java index 76a24521..04b853a8 100644 --- a/examples/async-thumbnails/src/main/java/com/fnproject/fn/examples/ThumbnailsFunction.java +++ b/examples/async-thumbnails/src/main/java/com/fnproject/fn/examples/ThumbnailsFunction.java @@ -23,7 +23,10 @@ import com.fnproject.fn.runtime.flow.FlowFeature; import com.fnproject.fn.api.flow.Flows; import com.fnproject.fn.api.flow.HttpMethod; +import io.minio.BucketExistsArgs; +import io.minio.MakeBucketArgs; import io.minio.MinioClient; +import io.minio.PutObjectArgs; import java.io.ByteArrayInputStream; import java.io.Serializable; @@ -85,15 +88,22 @@ public Response handleRequest(byte[] imageBuffer) { */ private void objectUpload(byte[] imageBuffer, String objectName) { try { - MinioClient minioClient = new MinioClient(storageUrl, storageAccessKey, storageSecretKey); + MinioClient minioClient = MinioClient.builder() + .endpoint(storageUrl).credentials(storageAccessKey, storageSecretKey).build(); // Ensure the bucket exists. - if(!minioClient.bucketExists("alpha")) { - minioClient.makeBucket("alpha"); + BucketExistsArgs bucketExistsArgs = BucketExistsArgs.builder().bucket("alpha").build(); + MakeBucketArgs makeBucketArgs = MakeBucketArgs.builder().bucket("alpha").build(); + if(!minioClient.bucketExists(bucketExistsArgs)) { + minioClient.makeBucket(makeBucketArgs); } + PutObjectArgs putObjectArgs = PutObjectArgs.builder() + .bucket("alpha") + .object(objectName) + .stream(new ByteArrayInputStream(imageBuffer), imageBuffer.length, -1).build(); // Upload the image to the bucket with putObject - minioClient.putObject("alpha", objectName, new ByteArrayInputStream(imageBuffer), imageBuffer.length, "application/octet-stream"); + minioClient.putObject(putObjectArgs); } catch(Exception e) { System.err.println("Error occurred: " + e); e.printStackTrace(); diff --git a/release.version b/release.version index 75c0b87b..9632c46c 100644 --- a/release.version +++ b/release.version @@ -1 +1 @@ -1.0.139 +1.0.140 From 5e772dc2e01b4d8566f3fa12450a42706f3ea16f Mon Sep 17 00:00:00 2001 From: CI Date: Fri, 29 Oct 2021 12:56:29 +0000 Subject: [PATCH 244/310] Releasing version 1.0.141 --- release.version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/release.version b/release.version index 9632c46c..4a063f10 100644 --- a/release.version +++ b/release.version @@ -1 +1 @@ -1.0.140 +1.0.141 From cd479a7be00400b59a4e1a64c245780982e3c547 Mon Sep 17 00:00:00 2001 From: CI Date: Wed, 10 Nov 2021 08:42:07 +0000 Subject: [PATCH 245/310] Releasing version 1.0.142 --- .gitignore | 1 + release.version | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/.gitignore b/.gitignore index 1e68a65a..23d37e5f 100644 --- a/.gitignore +++ b/.gitignore @@ -3,6 +3,7 @@ .DS_Store */dependency-reduced-pom.xml target/ +rpm-package/ *.log \#* .\#* diff --git a/release.version b/release.version index 4a063f10..86738f9d 100644 --- a/release.version +++ b/release.version @@ -1 +1 @@ -1.0.141 +1.0.142 From ba10567067f9995b16d6eaecf95c97eeaba49835 Mon Sep 17 00:00:00 2001 From: CI Date: Wed, 15 Dec 2021 09:20:23 +0000 Subject: [PATCH 246/310] Releasing version 1.0.143 --- release.version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/release.version b/release.version index 86738f9d..70f4b367 100644 --- a/release.version +++ b/release.version @@ -1 +1 @@ -1.0.142 +1.0.143 From f32840716e582e0aa720deafb3eff748b607e4e5 Mon Sep 17 00:00:00 2001 From: CI Date: Mon, 20 Dec 2021 09:41:20 +0000 Subject: [PATCH 247/310] Releasing version 1.0.144 --- examples/async-thumbnails/pom.xml | 11 +++++++++++ release.version | 2 +- 2 files changed, 12 insertions(+), 1 deletion(-) diff --git a/examples/async-thumbnails/pom.xml b/examples/async-thumbnails/pom.xml index cb0aab8d..f9124096 100644 --- a/examples/async-thumbnails/pom.xml +++ b/examples/async-thumbnails/pom.xml @@ -61,6 +61,17 @@ io.minio minio 7.1.3 + + + com.squareup.okhttp3 + okhttp + + + + + com.squareup.okhttp3 + okhttp + 4.9.3 com.fnproject.fn diff --git a/release.version b/release.version index 70f4b367..008b1343 100644 --- a/release.version +++ b/release.version @@ -1 +1 @@ -1.0.143 +1.0.144 From a641d5c9229007089738c519edfb59dff193f24c Mon Sep 17 00:00:00 2001 From: CI Date: Tue, 18 Jan 2022 06:08:45 +0000 Subject: [PATCH 248/310] Releasing version 1.0.145 --- release.version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/release.version b/release.version index 008b1343..46bd1d85 100644 --- a/release.version +++ b/release.version @@ -1 +1 @@ -1.0.144 +1.0.145 From 24bfe9bde5f4afddffd31895d18edaded25f9129 Mon Sep 17 00:00:00 2001 From: CI Date: Fri, 25 Feb 2022 04:43:07 +0000 Subject: [PATCH 249/310] Releasing version 1.0.146 --- release.version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/release.version b/release.version index 46bd1d85..be76a0c6 100644 --- a/release.version +++ b/release.version @@ -1 +1 @@ -1.0.145 +1.0.146 From 1ce564accfeae96881ffed250a90f65f79cdd203 Mon Sep 17 00:00:00 2001 From: CI Date: Thu, 21 Apr 2022 08:33:26 +0000 Subject: [PATCH 250/310] Releasing version 1.0.147 --- fn-spring-cloud-function/pom.xml | 2 +- .../function/SpringCloudFunctionInvoker.java | 4 +- .../function/SpringCloudFunctionLoader.java | 28 +++---- .../functions/SpringCloudConsumer.java | 6 +- .../functions/SpringCloudFunction.java | 6 +- .../function/functions/SpringCloudMethod.java | 12 +-- .../functions/SpringCloudSupplier.java | 6 +- .../function/SimpleFunctionInspector.java | 82 ------------------- ...ngCloudFunctionInvokerIntegrationTest.java | 2 - .../SpringCloudFunctionInvokerTest.java | 11 ++- .../SpringCloudFunctionLoaderTest.java | 18 ++-- .../function/testfns/FunctionConfig.java | 6 +- release.version | 2 +- 13 files changed, 50 insertions(+), 135 deletions(-) delete mode 100644 fn-spring-cloud-function/src/test/java/com/fnproject/springframework/function/SimpleFunctionInspector.java diff --git a/fn-spring-cloud-function/pom.xml b/fn-spring-cloud-function/pom.xml index baae1df7..f85d5525 100644 --- a/fn-spring-cloud-function/pom.xml +++ b/fn-spring-cloud-function/pom.xml @@ -30,7 +30,7 @@ fn-spring-cloud-function - 2.1.1.RELEASE + 3.2.3 diff --git a/fn-spring-cloud-function/src/main/java/com/fnproject/springframework/function/SpringCloudFunctionInvoker.java b/fn-spring-cloud-function/src/main/java/com/fnproject/springframework/function/SpringCloudFunctionInvoker.java index 88702bf6..c7de738d 100644 --- a/fn-spring-cloud-function/src/main/java/com/fnproject/springframework/function/SpringCloudFunctionInvoker.java +++ b/fn-spring-cloud-function/src/main/java/com/fnproject/springframework/function/SpringCloudFunctionInvoker.java @@ -21,13 +21,13 @@ import com.fnproject.fn.api.exception.FunctionOutputHandlingException; import com.fnproject.springframework.function.functions.SpringCloudMethod; +import org.springframework.boot.Banner; import org.springframework.boot.WebApplicationType; import org.springframework.boot.builder.SpringApplicationBuilder; import org.springframework.context.ConfigurableApplicationContext; import reactor.core.publisher.Flux; import java.io.Closeable; -import java.io.IOException; import java.util.ArrayList; import java.util.Collection; import java.util.List; @@ -55,7 +55,7 @@ public class SpringCloudFunctionInvoker implements FunctionInvoker, Closeable { */ public SpringCloudFunctionInvoker(Class configClass) { SpringApplicationBuilder builder = new SpringApplicationBuilder(configClass); - applicationContext = builder.web(WebApplicationType.NONE).run(); + applicationContext = builder.web(WebApplicationType.NONE).bannerMode(Banner.Mode.OFF).run(); loader = applicationContext.getAutowireCapableBeanFactory().createBean(SpringCloudFunctionLoader.class); loader.loadFunction(); } diff --git a/fn-spring-cloud-function/src/main/java/com/fnproject/springframework/function/SpringCloudFunctionLoader.java b/fn-spring-cloud-function/src/main/java/com/fnproject/springframework/function/SpringCloudFunctionLoader.java index 84663d94..ae0f9a6d 100644 --- a/fn-spring-cloud-function/src/main/java/com/fnproject/springframework/function/SpringCloudFunctionLoader.java +++ b/fn-spring-cloud-function/src/main/java/com/fnproject/springframework/function/SpringCloudFunctionLoader.java @@ -23,7 +23,7 @@ import com.fnproject.springframework.function.functions.SpringCloudSupplier; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.cloud.function.context.FunctionCatalog; -import org.springframework.cloud.function.context.catalog.FunctionInspector; +import org.springframework.cloud.function.context.catalog.SimpleFunctionRegistry; import reactor.core.publisher.Flux; import java.util.function.Consumer; @@ -54,16 +54,14 @@ public class SpringCloudFunctionLoader { public static final String ENV_VAR_CONSUMER_NAME = "FN_SPRING_CONSUMER"; public static final String ENV_VAR_SUPPLIER_NAME = "FN_SPRING_SUPPLIER"; - private final FunctionCatalog catalog; - private final FunctionInspector inspector; + private final SimpleFunctionRegistry registry; private Function, Flux> function; private Consumer> consumer; private Supplier> supplier; - SpringCloudFunctionLoader(@Autowired FunctionCatalog catalog, @Autowired FunctionInspector inspector) { - this.catalog = catalog; - this.inspector = inspector; + SpringCloudFunctionLoader(@Autowired SimpleFunctionRegistry registry) { + this.registry = registry; } void loadFunction() { @@ -83,24 +81,24 @@ void loadFunction() { private void loadSpringCloudFunctionFromEnvVars() { String functionName = System.getenv(ENV_VAR_FUNCTION_NAME); if (functionName != null) { - function = this.catalog.lookup(Function.class, functionName); + function = this.registry.lookup(Function.class, functionName); } String consumerName = System.getenv(ENV_VAR_CONSUMER_NAME); if (consumerName != null) { - consumer = this.catalog.lookup(Consumer.class, consumerName); + consumer = this.registry.lookup(Consumer.class, consumerName); } String supplierName = System.getenv(ENV_VAR_SUPPLIER_NAME); if (supplierName != null) { - supplier = this.catalog.lookup(Supplier.class, supplierName); + supplier = this.registry.lookup(Supplier.class, supplierName); } } private void loadSpringCloudFunctionFromDefaults() { - function = this.catalog.lookup(Function.class, DEFAULT_FUNCTION_BEAN); - consumer = this.catalog.lookup(Consumer.class, DEFAULT_CONSUMER_BEAN); - supplier = this.catalog.lookup(Supplier.class, DEFAULT_SUPPLIER_BEAN); + function = this.registry.lookup(Function.class, DEFAULT_FUNCTION_BEAN); + consumer = this.registry.lookup(Consumer.class, DEFAULT_CONSUMER_BEAN); + supplier = this.registry.lookup(Supplier.class, DEFAULT_SUPPLIER_BEAN); } @@ -111,11 +109,11 @@ private boolean noSpringCloudFunctionFound() { SpringCloudMethod getFunction() { if (function != null) { - return new SpringCloudFunction(function, inspector); + return new SpringCloudFunction(function, registry); } else if (consumer != null) { - return new SpringCloudConsumer(consumer, inspector); + return new SpringCloudConsumer(consumer, registry); } else { - return new SpringCloudSupplier(supplier, inspector); + return new SpringCloudSupplier(supplier, registry); } } } diff --git a/fn-spring-cloud-function/src/main/java/com/fnproject/springframework/function/functions/SpringCloudConsumer.java b/fn-spring-cloud-function/src/main/java/com/fnproject/springframework/function/functions/SpringCloudConsumer.java index 1e635f76..bc16a9bb 100644 --- a/fn-spring-cloud-function/src/main/java/com/fnproject/springframework/function/functions/SpringCloudConsumer.java +++ b/fn-spring-cloud-function/src/main/java/com/fnproject/springframework/function/functions/SpringCloudConsumer.java @@ -18,7 +18,7 @@ import com.fnproject.fn.api.TypeWrapper; import com.fnproject.springframework.function.SimpleTypeWrapper; -import org.springframework.cloud.function.context.catalog.FunctionInspector; +import org.springframework.cloud.function.context.catalog.SimpleFunctionRegistry; import reactor.core.publisher.Flux; import java.util.function.Consumer; @@ -29,8 +29,8 @@ public class SpringCloudConsumer extends SpringCloudMethod { private Consumer> consumer; - public SpringCloudConsumer(Consumer> consumer, FunctionInspector inspector) { - super(inspector); + public SpringCloudConsumer(Consumer> consumer, SimpleFunctionRegistry registry) { + super(registry); this.consumer = consumer; } diff --git a/fn-spring-cloud-function/src/main/java/com/fnproject/springframework/function/functions/SpringCloudFunction.java b/fn-spring-cloud-function/src/main/java/com/fnproject/springframework/function/functions/SpringCloudFunction.java index 57d79644..48d99186 100644 --- a/fn-spring-cloud-function/src/main/java/com/fnproject/springframework/function/functions/SpringCloudFunction.java +++ b/fn-spring-cloud-function/src/main/java/com/fnproject/springframework/function/functions/SpringCloudFunction.java @@ -16,7 +16,7 @@ package com.fnproject.springframework.function.functions; -import org.springframework.cloud.function.context.catalog.FunctionInspector; +import org.springframework.cloud.function.context.catalog.SimpleFunctionRegistry; import reactor.core.publisher.Flux; import java.util.function.Function; @@ -27,8 +27,8 @@ public class SpringCloudFunction extends SpringCloudMethod { private Function, Flux> function; - public SpringCloudFunction(Function, Flux> function, FunctionInspector inspector) { - super(inspector); + public SpringCloudFunction(Function, Flux> function, SimpleFunctionRegistry registry) { + super(registry); this.function = function; } diff --git a/fn-spring-cloud-function/src/main/java/com/fnproject/springframework/function/functions/SpringCloudMethod.java b/fn-spring-cloud-function/src/main/java/com/fnproject/springframework/function/functions/SpringCloudMethod.java index b1ef8867..3813fcd5 100644 --- a/fn-spring-cloud-function/src/main/java/com/fnproject/springframework/function/functions/SpringCloudMethod.java +++ b/fn-spring-cloud-function/src/main/java/com/fnproject/springframework/function/functions/SpringCloudMethod.java @@ -19,7 +19,7 @@ import com.fnproject.fn.api.MethodWrapper; import com.fnproject.fn.api.TypeWrapper; import com.fnproject.springframework.function.SimpleTypeWrapper; -import org.springframework.cloud.function.context.catalog.FunctionInspector; +import org.springframework.cloud.function.context.catalog.SimpleFunctionRegistry; import reactor.core.publisher.Flux; import java.lang.reflect.Method; @@ -31,10 +31,10 @@ * Spring Cloud Functions */ public abstract class SpringCloudMethod implements MethodWrapper { - private FunctionInspector inspector; + private SimpleFunctionRegistry registry; - SpringCloudMethod(FunctionInspector inspector) { - this.inspector = inspector; + SpringCloudMethod(SimpleFunctionRegistry registry) { + this.registry = registry; } @Override @@ -73,12 +73,12 @@ public Method getTargetMethod() { @Override public TypeWrapper getParamType(int index) { - return new SimpleTypeWrapper(inspector.getInputType(getFunction())); + return new SimpleTypeWrapper(registry.getInputType(getFunction())); } @Override public TypeWrapper getReturnType() { - return new SimpleTypeWrapper(inspector.getOutputType(getFunction())); + return new SimpleTypeWrapper(registry.getOutputType(getFunction())); } /** diff --git a/fn-spring-cloud-function/src/main/java/com/fnproject/springframework/function/functions/SpringCloudSupplier.java b/fn-spring-cloud-function/src/main/java/com/fnproject/springframework/function/functions/SpringCloudSupplier.java index a74f6841..8cf498f2 100644 --- a/fn-spring-cloud-function/src/main/java/com/fnproject/springframework/function/functions/SpringCloudSupplier.java +++ b/fn-spring-cloud-function/src/main/java/com/fnproject/springframework/function/functions/SpringCloudSupplier.java @@ -18,7 +18,7 @@ import com.fnproject.fn.api.TypeWrapper; import com.fnproject.springframework.function.SimpleTypeWrapper; -import org.springframework.cloud.function.context.catalog.FunctionInspector; +import org.springframework.cloud.function.context.catalog.SimpleFunctionRegistry; import reactor.core.publisher.Flux; import java.util.function.Supplier; @@ -29,8 +29,8 @@ public class SpringCloudSupplier extends SpringCloudMethod { private Supplier> supplier; - public SpringCloudSupplier(Supplier> supplier, FunctionInspector inspector) { - super(inspector); + public SpringCloudSupplier(Supplier> supplier, SimpleFunctionRegistry registry) { + super(registry); this.supplier = supplier; } diff --git a/fn-spring-cloud-function/src/test/java/com/fnproject/springframework/function/SimpleFunctionInspector.java b/fn-spring-cloud-function/src/test/java/com/fnproject/springframework/function/SimpleFunctionInspector.java deleted file mode 100644 index 9cd5f365..00000000 --- a/fn-spring-cloud-function/src/test/java/com/fnproject/springframework/function/SimpleFunctionInspector.java +++ /dev/null @@ -1,82 +0,0 @@ -/* - * Copyright (c) 2019, 2020 Oracle and/or its affiliates. All rights reserved. - * - * 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. - */ - -package com.fnproject.springframework.function; - -import net.jodah.typetools.TypeResolver; -import org.springframework.cloud.function.context.FunctionRegistration; -import org.springframework.cloud.function.context.catalog.FunctionInspector; - -import java.util.function.Consumer; -import java.util.function.Function; -import java.util.function.Supplier; - -public class SimpleFunctionInspector implements FunctionInspector { - @Override - public FunctionRegistration getRegistration(Object function) { - return null; - } - - @Override - public boolean isMessage(Object function) { - throw new IllegalStateException("Not implemented"); - } - - @Override - public Class getInputType(Object function) { - if (function instanceof Function) { - Class[] types = TypeResolver.resolveRawArguments(Function.class, function.getClass()); - return types[0]; - } else if (function instanceof Consumer) { - Class[] types = TypeResolver.resolveRawArguments(Consumer.class, function.getClass()); - return types[0]; - } else if (function instanceof Supplier) { - return Void.class; - } else { - throw new IllegalStateException("You cannot get the input type of a function that doesn't implement one of the java.util.function interfaces"); - } - } - - @Override - public Class getOutputType(Object function) { - if (function instanceof Function) { - Class[] types = TypeResolver.resolveRawArguments(Function.class, function.getClass()); - return types[0]; - } else if (function instanceof Consumer) { - return Void.class; - } else if (function instanceof Supplier) { - Class[] types = TypeResolver.resolveRawArguments(Consumer.class, function.getClass()); - return types[0]; - } else { - throw new IllegalStateException("You cannot get the output type of a function that doesn't implement one of the java.util.function interfaces"); - } - } - - @Override - public Class getInputWrapper(Object function) { - throw new IllegalStateException("Not implemented"); - } - - @Override - public Class getOutputWrapper(Object function) { - throw new IllegalStateException("Not implemented"); - } - - @Override - public String getName(Object function) { - return function.toString(); - } -} diff --git a/fn-spring-cloud-function/src/test/java/com/fnproject/springframework/function/SpringCloudFunctionInvokerIntegrationTest.java b/fn-spring-cloud-function/src/test/java/com/fnproject/springframework/function/SpringCloudFunctionInvokerIntegrationTest.java index 1d5d0269..f2c0054d 100644 --- a/fn-spring-cloud-function/src/test/java/com/fnproject/springframework/function/SpringCloudFunctionInvokerIntegrationTest.java +++ b/fn-spring-cloud-function/src/test/java/com/fnproject/springframework/function/SpringCloudFunctionInvokerIntegrationTest.java @@ -24,8 +24,6 @@ import org.junit.Test; import org.junit.contrib.java.lang.system.EnvironmentVariables; -import java.io.IOException; - import static org.assertj.core.api.Assertions.assertThat; diff --git a/fn-spring-cloud-function/src/test/java/com/fnproject/springframework/function/SpringCloudFunctionInvokerTest.java b/fn-spring-cloud-function/src/test/java/com/fnproject/springframework/function/SpringCloudFunctionInvokerTest.java index 64fa2c16..6c708f69 100644 --- a/fn-spring-cloud-function/src/test/java/com/fnproject/springframework/function/SpringCloudFunctionInvokerTest.java +++ b/fn-spring-cloud-function/src/test/java/com/fnproject/springframework/function/SpringCloudFunctionInvokerTest.java @@ -19,6 +19,8 @@ import com.fnproject.springframework.function.functions.SpringCloudFunction; import org.junit.Before; import org.junit.Test; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.cloud.function.context.catalog.SimpleFunctionRegistry; import java.util.Arrays; import java.util.List; @@ -28,6 +30,9 @@ public class SpringCloudFunctionInvokerTest { private SpringCloudFunctionInvoker invoker; + @Autowired + private SimpleFunctionRegistry registry; + @Before public void setUp() { invoker = new SpringCloudFunctionInvoker((SpringCloudFunctionLoader) null); @@ -35,7 +40,7 @@ public void setUp() { @Test public void invokesFunctionWithEmptyFlux() { - SpringCloudFunction fnWrapper = new SpringCloudFunction(x -> x, new SimpleFunctionInspector()); + SpringCloudFunction fnWrapper = new SpringCloudFunction(x -> x, registry); Object result = invoker.tryInvoke(fnWrapper, new Object[0]); @@ -44,7 +49,7 @@ public void invokesFunctionWithEmptyFlux() { @Test public void invokesFunctionWithFluxOfSingleItem() { - SpringCloudFunction fnWrapper = new SpringCloudFunction(x -> x, new SimpleFunctionInspector()); + SpringCloudFunction fnWrapper = new SpringCloudFunction(x -> x, registry); Object result = invoker.tryInvoke(fnWrapper, new Object[]{ "hello" }); @@ -54,7 +59,7 @@ public void invokesFunctionWithFluxOfSingleItem() { @Test public void invokesFunctionWithFluxOfMultipleItems() { - SpringCloudFunction fnWrapper = new SpringCloudFunction(x -> x, new SimpleFunctionInspector()); + SpringCloudFunction fnWrapper = new SpringCloudFunction(x -> x, registry); Object result = invoker.tryInvoke(fnWrapper, new Object[]{ Arrays.asList("hello", "world") }); diff --git a/fn-spring-cloud-function/src/test/java/com/fnproject/springframework/function/SpringCloudFunctionLoaderTest.java b/fn-spring-cloud-function/src/test/java/com/fnproject/springframework/function/SpringCloudFunctionLoaderTest.java index 20c2b1a9..2be39d5b 100644 --- a/fn-spring-cloud-function/src/test/java/com/fnproject/springframework/function/SpringCloudFunctionLoaderTest.java +++ b/fn-spring-cloud-function/src/test/java/com/fnproject/springframework/function/SpringCloudFunctionLoaderTest.java @@ -24,14 +24,13 @@ import org.junit.runner.RunWith; import org.mockito.Mock; import org.mockito.junit.MockitoJUnitRunner; -import org.springframework.cloud.function.context.catalog.InMemoryFunctionCatalog; +import org.springframework.cloud.function.context.catalog.BeanFactoryAwareFunctionRegistry; import java.util.function.Consumer; import java.util.function.Function; import java.util.function.Supplier; import static org.assertj.core.api.Assertions.assertThat; -import static org.mockito.ArgumentMatchers.any; import static org.mockito.Mockito.when; @RunWith(MockitoJUnitRunner.class) @@ -42,16 +41,11 @@ public class SpringCloudFunctionLoaderTest { private SpringCloudFunctionLoader loader; @Mock - private InMemoryFunctionCatalog catalog; + private BeanFactoryAwareFunctionRegistry registry; @Before public void setUp() { - loader = new SpringCloudFunctionLoader(catalog, null); - setUpCatalogToReturnNullForLookupByDefault(); - } - - private void setUpCatalogToReturnNullForLookupByDefault() { - when(catalog.lookup(any(), any())).thenReturn(null); + loader = new SpringCloudFunctionLoader(registry); } @Test @@ -121,15 +115,15 @@ public void shouldLoadUserSpecifiedFunctionInEnvVarOverDefaultFunction() { } private void stubCatalogToReturnFunction(String beanName, Function function) { - when(catalog.lookup(Function.class, beanName)).thenReturn(function); + when(registry.lookup(Function.class, beanName)).thenReturn(function); } private void stubCatalogToReturnConsumer(String beanName, Consumer consumer) { - when(catalog.lookup(Consumer.class, beanName)).thenReturn(consumer); + when(registry.lookup(Consumer.class, beanName)).thenReturn(consumer); } private void stubCatalogToReturnSupplier(String beanName, Supplier supplier) { - when(catalog.lookup(Supplier.class, beanName)).thenReturn(supplier); + when(registry.lookup(Supplier.class, beanName)).thenReturn(supplier); } private void stubCatalogToReturnSupplier(Supplier supplier) { diff --git a/fn-spring-cloud-function/src/test/java/com/fnproject/springframework/function/testfns/FunctionConfig.java b/fn-spring-cloud-function/src/test/java/com/fnproject/springframework/function/testfns/FunctionConfig.java index ea24cdc9..8c76e911 100644 --- a/fn-spring-cloud-function/src/test/java/com/fnproject/springframework/function/testfns/FunctionConfig.java +++ b/fn-spring-cloud-function/src/test/java/com/fnproject/springframework/function/testfns/FunctionConfig.java @@ -25,6 +25,7 @@ import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.Import; +import reactor.core.publisher.Flux; import java.util.function.Consumer; import java.util.function.Function; @@ -39,8 +40,9 @@ public void handleRequest() { } @Bean - public Supplier supplier() { - return () -> "Hello"; + public Supplier> supplier() { + String str = "Hello"; + return () -> Flux.just(str); } @Bean diff --git a/release.version b/release.version index be76a0c6..1a438091 100644 --- a/release.version +++ b/release.version @@ -1 +1 @@ -1.0.146 +1.0.147 From c2ea50d2c7a876d9d2faae6e198e853e10631aba Mon Sep 17 00:00:00 2001 From: CI Date: Wed, 27 Apr 2022 04:07:08 +0000 Subject: [PATCH 251/310] Releasing version 1.0.148 --- examples/async-thumbnails/pom.xml | 9 +-------- examples/regex-query/pom.xml | 11 ++--------- pom.xml | 2 +- release.version | 2 +- 4 files changed, 5 insertions(+), 19 deletions(-) diff --git a/examples/async-thumbnails/pom.xml b/examples/async-thumbnails/pom.xml index f9124096..0d47b1a0 100644 --- a/examples/async-thumbnails/pom.xml +++ b/examples/async-thumbnails/pom.xml @@ -28,7 +28,7 @@ 1.0.0-SNAPSHOT 3.3.3 - 2.13.0 + 2.13.2.1 com.fnproject.fn.examples @@ -191,11 +191,4 @@ - - - - fn-maven-releases - https://dl.bintray.com/fnproject/fnproject - - diff --git a/examples/regex-query/pom.xml b/examples/regex-query/pom.xml index 8c72849d..5573e516 100644 --- a/examples/regex-query/pom.xml +++ b/examples/regex-query/pom.xml @@ -27,7 +27,7 @@ UTF-8 1.0.0-SNAPSHOT - 2.13.0 + 2.13.2.1 com.fnproject.fn.examples @@ -43,7 +43,7 @@ com.fasterxml.jackson.core jackson-annotations - ${jackson.version} + 2.13.0 junit @@ -92,11 +92,4 @@ - - - - fn-maven-releases - https://dl.bintray.com/fnproject/fnproject - - diff --git a/pom.xml b/pom.xml index a14013e1..ff3438df 100644 --- a/pom.xml +++ b/pom.xml @@ -84,7 +84,7 @@ 3.21.0 2.11.0 4.4.14 - 2.13.0 + 2.13.2.1 0.8.1 9.4.12.v20180830 4.13.2 diff --git a/release.version b/release.version index 1a438091..eac300f7 100644 --- a/release.version +++ b/release.version @@ -1 +1 @@ -1.0.147 +1.0.148 From 4bd4cae03ac4769ef1e2299f5eba64e7378e0870 Mon Sep 17 00:00:00 2001 From: CI Date: Tue, 31 May 2022 05:49:16 +0000 Subject: [PATCH 252/310] Releasing version 1.0.149 --- release.version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/release.version b/release.version index eac300f7..54e242a0 100644 --- a/release.version +++ b/release.version @@ -1 +1 @@ -1.0.148 +1.0.149 From 8edc331a0de01fb5926dc736ab0f2aa4d2ba91c2 Mon Sep 17 00:00:00 2001 From: CI Date: Tue, 9 Aug 2022 04:31:32 +0000 Subject: [PATCH 253/310] Releasing version 1.0.150 --- docs/FAQ.md | 19 +++---------------- release.version | 2 +- 2 files changed, 4 insertions(+), 17 deletions(-) diff --git a/docs/FAQ.md b/docs/FAQ.md index 2477c4ab..4dfcb4aa 100644 --- a/docs/FAQ.md +++ b/docs/FAQ.md @@ -18,23 +18,10 @@ Yes - The FDK implements the IO/contract with the FN service and is required to Fn Flow is a [Java API](https://github.com/fnproject/fn-java-fdk/blob/master/docs/FnFlowsUserGuide.md) and [corresponding service](https://github.com/fnproject/flow) that helps you create complex, long-running, fault-tolerant functions using a promises-style asynchronous API. Check out the [Fn Flow docs](https://github.com/fnproject/fn-java-fdk/blob/master/docs/FnFlowsUserGuide.md) for more information. ### How do I get the FDK? -The FDK is automatically added to your project if you built your function using `fn init --runtime=java`. The `api` and `testing` JARs are published on [our bintray](https://bintray.com/fnproject/fnproject) and the `runtime` is published in our [Docker hub repository](https://hub.docker.com/r/fnproject/fn-java-fdk/). - +The FDK is automatically added to your project if you built your function using `fn init --runtime=java`. The `api` and `testing` JARs are published on [our maven central repository](https://search.maven.org/search?q=g:com.fnproject.fn) and the `runtime` is published in our [Docker hub repository](https://hub.docker.com/r/fnproject/fn-java-fdk/). ### How do I add the FDK to an existing project? - 1. Find the latest release from the [releases page](https://github.com/fnproject/fn-java-fdk/releases). For example `1.0.32`. - 1. The FDK JAR is published on [Bintray](https://bintray.com/fnproject/fnproject). Add the repository to your`pom.xml` `repositories` section: - ```xml - - fn-release-repo - https://dl.bintray.com/fnproject/fnproject - - true - - - false - - - ``` + 1. Find the latest release from the [releases page](https://github.com/fnproject/fn-java-fdk/releases). For example `1.0.149`. + 1. The FDK JAR is published on [Maven Central](https://search.maven.org/search?q=g:com.fnproject.fn). Add the repository to your`pom.xml` `repositories` section: 1. Add the dependency to your `dependency` section. Make sure that the `version` tag matches the latest release that you looked up above. ```xml diff --git a/release.version b/release.version index 54e242a0..cf652ee7 100644 --- a/release.version +++ b/release.version @@ -1 +1 @@ -1.0.149 +1.0.150 From acdb37b3cea617d4001e35665cda19f132a01766 Mon Sep 17 00:00:00 2001 From: CI Date: Thu, 29 Sep 2022 12:52:41 +0000 Subject: [PATCH 254/310] Releasing version 1.0.151 --- release.version | 2 +- runtime/src/main/c/Dockerfile-buildimage | 5 +++-- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/release.version b/release.version index cf652ee7..d9871d3e 100644 --- a/release.version +++ b/release.version @@ -1 +1 @@ -1.0.150 +1.0.151 diff --git a/runtime/src/main/c/Dockerfile-buildimage b/runtime/src/main/c/Dockerfile-buildimage index 96b3bd2d..8e6c25a6 100644 --- a/runtime/src/main/c/Dockerfile-buildimage +++ b/runtime/src/main/c/Dockerfile-buildimage @@ -14,9 +14,10 @@ # limitations under the License. # -FROM container-registry.oracle.com/os/oraclelinux:7.5 +FROM docker-remote.artifactory.oci.oraclecorp.com/oraclelinux:7.5 -RUN yum install -y gcc cmake java-1.8.0-openjdk-devel.x86_64 make + +RUN yum install -y gcc cmake java-1.8.0-openjdk-devel make RUN yum install -y gcc-c++ RUN mkdir /build From 11315cdc2a473c5a45402d29cd299261b9ce91ca Mon Sep 17 00:00:00 2001 From: CI Date: Thu, 10 Nov 2022 13:04:30 +0000 Subject: [PATCH 255/310] Releasing version 1.0.159 --- release.version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/release.version b/release.version index d9871d3e..58d0c601 100644 --- a/release.version +++ b/release.version @@ -1 +1 @@ -1.0.151 +1.0.159 From 3864e258751d91990a872e618e25d80963cd3c3c Mon Sep 17 00:00:00 2001 From: CI Date: Wed, 30 Nov 2022 13:57:58 +0000 Subject: [PATCH 256/310] Releasing version refs/heads/master --- examples/async-thumbnails/pom.xml | 2 +- examples/regex-query/pom.xml | 4 ++-- pom.xml | 2 +- release.version | 2 +- 4 files changed, 5 insertions(+), 5 deletions(-) diff --git a/examples/async-thumbnails/pom.xml b/examples/async-thumbnails/pom.xml index 0d47b1a0..a4802e0a 100644 --- a/examples/async-thumbnails/pom.xml +++ b/examples/async-thumbnails/pom.xml @@ -28,7 +28,7 @@ 1.0.0-SNAPSHOT 3.3.3 - 2.13.2.1 + 2.13.4 com.fnproject.fn.examples diff --git a/examples/regex-query/pom.xml b/examples/regex-query/pom.xml index 5573e516..07c50566 100644 --- a/examples/regex-query/pom.xml +++ b/examples/regex-query/pom.xml @@ -27,7 +27,7 @@ UTF-8 1.0.0-SNAPSHOT - 2.13.2.1 + 2.13.4 com.fnproject.fn.examples @@ -43,7 +43,7 @@ com.fasterxml.jackson.core jackson-annotations - 2.13.0 + 2.13.4 junit diff --git a/pom.xml b/pom.xml index ff3438df..361a8788 100644 --- a/pom.xml +++ b/pom.xml @@ -84,7 +84,7 @@ 3.21.0 2.11.0 4.4.14 - 2.13.2.1 + 2.13.4 0.8.1 9.4.12.v20180830 4.13.2 diff --git a/release.version b/release.version index 58d0c601..15bcce96 100644 --- a/release.version +++ b/release.version @@ -1 +1 @@ -1.0.159 +1.0.161 From da20bd95c59d241aceaae8a193beec09d60d4c54 Mon Sep 17 00:00:00 2001 From: CI Date: Tue, 6 Dec 2022 05:51:48 +0000 Subject: [PATCH 257/310] Releasing version refs/heads/master --- release.version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/release.version b/release.version index 15bcce96..b74bd0d4 100644 --- a/release.version +++ b/release.version @@ -1 +1 @@ -1.0.161 +1.0.162 From bf67eb33238691f837cdb89029c59a18352fc421 Mon Sep 17 00:00:00 2001 From: Denys Makogon Date: Tue, 31 Jan 2023 09:31:17 +0200 Subject: [PATCH 258/310] CVE-2022-42003: bump jackson version to 2.14.2 --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 361a8788..9e938221 100644 --- a/pom.xml +++ b/pom.xml @@ -84,7 +84,7 @@ 3.21.0 2.11.0 4.4.14 - 2.13.4 + 2.14.2 0.8.1 9.4.12.v20180830 4.13.2 From 90b204d2e564592a3f4cb91178e18415ebeac633 Mon Sep 17 00:00:00 2001 From: CI Date: Wed, 8 Feb 2023 08:26:16 +0000 Subject: [PATCH 259/310] Releasing version 1.0.165 --- pom.xml | 2 +- release.version | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/pom.xml b/pom.xml index 9e938221..361a8788 100644 --- a/pom.xml +++ b/pom.xml @@ -84,7 +84,7 @@ 3.21.0 2.11.0 4.4.14 - 2.14.2 + 2.13.4 0.8.1 9.4.12.v20180830 4.13.2 diff --git a/release.version b/release.version index b74bd0d4..d6ea79a7 100644 --- a/release.version +++ b/release.version @@ -1 +1 @@ -1.0.162 +1.0.165 From 14f14e849b0b5dbda492fb1504d72b5528eec38d Mon Sep 17 00:00:00 2001 From: Sunny Sethi Date: Wed, 8 Feb 2023 14:27:37 +0530 Subject: [PATCH 260/310] reverting release version --- release.version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/release.version b/release.version index d6ea79a7..b74bd0d4 100644 --- a/release.version +++ b/release.version @@ -1 +1 @@ -1.0.165 +1.0.162 From 7e118d1ceda60bea5c405af23f507081aa4bea2f Mon Sep 17 00:00:00 2001 From: CI Date: Mon, 27 Feb 2023 08:32:27 +0000 Subject: [PATCH 261/310] Releasing version 1.0.167 --- release.version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/release.version b/release.version index b74bd0d4..e2b5beaa 100644 --- a/release.version +++ b/release.version @@ -1 +1 @@ -1.0.162 +1.0.167 From f5c800540efdabbcec2ca3184320a449959f59bf Mon Sep 17 00:00:00 2001 From: CI Date: Tue, 14 Mar 2023 12:07:46 +0000 Subject: [PATCH 262/310] Releasing version 1.0.169 --- release.version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/release.version b/release.version index e2b5beaa..797f1f67 100644 --- a/release.version +++ b/release.version @@ -1 +1 @@ -1.0.167 +1.0.169 From 733a498aea8f050591c61ee3db7a77977fc1f364 Mon Sep 17 00:00:00 2001 From: CI Date: Thu, 13 Apr 2023 06:23:52 +0000 Subject: [PATCH 263/310] Releasing version 1.0.171 --- release.version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/release.version b/release.version index 797f1f67..a3d10e9a 100644 --- a/release.version +++ b/release.version @@ -1 +1 @@ -1.0.169 +1.0.171 From e198fb67ef8c0b0d766d3c8ef70656ff788cc7aa Mon Sep 17 00:00:00 2001 From: CI Date: Thu, 11 May 2023 08:33:41 +0000 Subject: [PATCH 264/310] Releasing version 1.0.172 --- release.version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/release.version b/release.version index a3d10e9a..0a3b55ec 100644 --- a/release.version +++ b/release.version @@ -1 +1 @@ -1.0.171 +1.0.172 From 7a6ace97736dbd016452a7d076bfa28577ee7c33 Mon Sep 17 00:00:00 2001 From: CI Date: Sun, 14 May 2023 13:32:26 +0000 Subject: [PATCH 265/310] Releasing version 1.0.173 --- release.version | 2 +- runtime/pom.xml | 20 ++++++++++++++++++-- runtime/src/main/c/Dockerfile-buildimage | 1 - runtime/src/main/c/buildit.sh | 1 - runtime/src/main/c/rebuild_so.sh | 10 ++++++++++ 5 files changed, 29 insertions(+), 5 deletions(-) diff --git a/release.version b/release.version index 0a3b55ec..f6e5575a 100644 --- a/release.version +++ b/release.version @@ -1 +1 @@ -1.0.172 +1.0.173 diff --git a/runtime/pom.xml b/runtime/pom.xml index a15085b3..850d4d80 100644 --- a/runtime/pom.xml +++ b/runtime/pom.xml @@ -100,12 +100,28 @@ true - src/main/c/ + src/main/c *.so false - ${build.directory}/classes/META-INF/com.fnproject.fn/runtime/native/ + ${build.directory}/classes/META-INF/com.fnproject.fn/runtime/native + + + src/main/c/amd64 + + *.so + + false + ${build.directory}/classes/META-INF/com.fnproject.fn/runtime/native/amd64 + + + src/main/c/arm64 + + *.so + + false + ${build.directory}/classes/META-INF/com.fnproject.fn/runtime/native/arm64 diff --git a/runtime/src/main/c/Dockerfile-buildimage b/runtime/src/main/c/Dockerfile-buildimage index 8e6c25a6..ddab38ee 100644 --- a/runtime/src/main/c/Dockerfile-buildimage +++ b/runtime/src/main/c/Dockerfile-buildimage @@ -16,7 +16,6 @@ FROM docker-remote.artifactory.oci.oraclecorp.com/oraclelinux:7.5 - RUN yum install -y gcc cmake java-1.8.0-openjdk-devel make RUN yum install -y gcc-c++ diff --git a/runtime/src/main/c/buildit.sh b/runtime/src/main/c/buildit.sh index c5af89ea..23445f46 100755 --- a/runtime/src/main/c/buildit.sh +++ b/runtime/src/main/c/buildit.sh @@ -19,7 +19,6 @@ set -e src_dir=$(pwd) build_dir=${src_dir}/build/$(uname -s| tr '[:upper:]' '[:lower:]') - mkdir -p ${build_dir} ( cd ${build_dir} diff --git a/runtime/src/main/c/rebuild_so.sh b/runtime/src/main/c/rebuild_so.sh index 90be5534..95eeb510 100755 --- a/runtime/src/main/c/rebuild_so.sh +++ b/runtime/src/main/c/rebuild_so.sh @@ -19,6 +19,16 @@ mydir=$(cd "$(dirname "$0")"; pwd) cd ${mydir} set -e + docker build -t fdk_c_build -f Dockerfile-buildimage . docker run -v $(pwd):/build fdk_c_build ./buildit.sh + +if [ $(uname -m) == "x86_64" ] +then + mkdir amd64 + cp libfnunixsocket.so amd64 +else + mkdir arm64 + cp libfnunixsocket.so arm64 +fi From 8fbbf442fb5033377e83cae1c4c66452bc17b2a1 Mon Sep 17 00:00:00 2001 From: CI Date: Thu, 18 May 2023 14:00:58 +0000 Subject: [PATCH 266/310] Releasing version 1.0.174 --- release.version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/release.version b/release.version index f6e5575a..81e489d2 100644 --- a/release.version +++ b/release.version @@ -1 +1 @@ -1.0.173 +1.0.174 From ed7d4488c39eebe81231bd8cf8d719149756bcab Mon Sep 17 00:00:00 2001 From: CI Date: Tue, 20 Jun 2023 08:57:18 +0000 Subject: [PATCH 267/310] Releasing version 1.0.175 --- release.version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/release.version b/release.version index 81e489d2..2418506c 100644 --- a/release.version +++ b/release.version @@ -1 +1 @@ -1.0.174 +1.0.175 From ddb52ebf1706f40bd89e8b4833efc90f6b39e7bd Mon Sep 17 00:00:00 2001 From: CI Date: Mon, 24 Jul 2023 07:54:51 +0000 Subject: [PATCH 268/310] Releasing version 1.0.177 --- release.version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/release.version b/release.version index 2418506c..bd7c3ec3 100644 --- a/release.version +++ b/release.version @@ -1 +1 @@ -1.0.175 +1.0.177 From e841e478ce3c242ab62ccf0b89bd94e79f9236df Mon Sep 17 00:00:00 2001 From: CI Date: Tue, 22 Aug 2023 05:59:09 +0000 Subject: [PATCH 269/310] Releasing version 1.0.178 --- release.version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/release.version b/release.version index bd7c3ec3..5f7bf9cc 100644 --- a/release.version +++ b/release.version @@ -1 +1 @@ -1.0.177 +1.0.178 From 9cb06f4acb224571a8029aab738c1f0117e89ccf Mon Sep 17 00:00:00 2001 From: CI Date: Mon, 2 Oct 2023 09:52:21 +0000 Subject: [PATCH 270/310] Releasing version 1.0.179 --- release.version | 2 +- runtime/src/main/c/Dockerfile-buildimage | 3 ++- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/release.version b/release.version index 5f7bf9cc..754b84ed 100644 --- a/release.version +++ b/release.version @@ -1 +1 @@ -1.0.178 +1.0.179 diff --git a/runtime/src/main/c/Dockerfile-buildimage b/runtime/src/main/c/Dockerfile-buildimage index ddab38ee..190e933d 100644 --- a/runtime/src/main/c/Dockerfile-buildimage +++ b/runtime/src/main/c/Dockerfile-buildimage @@ -14,8 +14,9 @@ # limitations under the License. # -FROM docker-remote.artifactory.oci.oraclecorp.com/oraclelinux:7.5 +FROM iad.ocir.io/oraclefunctionsdevelopm/oraclelinux:7.5 +RUN rm -rf /var/cache/yum/* RUN yum install -y gcc cmake java-1.8.0-openjdk-devel make RUN yum install -y gcc-c++ From 3a20cb1fd46f0bc173cc81c67964cb0015f3cfc2 Mon Sep 17 00:00:00 2001 From: CI Date: Tue, 31 Oct 2023 10:15:37 +0000 Subject: [PATCH 271/310] Releasing version 1.0.180 --- examples/async-thumbnails/pom.xml | 2 +- examples/regex-query/pom.xml | 2 +- pom.xml | 2 +- release.version | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/examples/async-thumbnails/pom.xml b/examples/async-thumbnails/pom.xml index a4802e0a..40475639 100644 --- a/examples/async-thumbnails/pom.xml +++ b/examples/async-thumbnails/pom.xml @@ -28,7 +28,7 @@ 1.0.0-SNAPSHOT 3.3.3 - 2.13.4 + 2.13.4.2 com.fnproject.fn.examples diff --git a/examples/regex-query/pom.xml b/examples/regex-query/pom.xml index 07c50566..7df881ca 100644 --- a/examples/regex-query/pom.xml +++ b/examples/regex-query/pom.xml @@ -27,7 +27,7 @@ UTF-8 1.0.0-SNAPSHOT - 2.13.4 + 2.13.4.2 com.fnproject.fn.examples diff --git a/pom.xml b/pom.xml index 361a8788..f8da0ddb 100644 --- a/pom.xml +++ b/pom.xml @@ -84,7 +84,7 @@ 3.21.0 2.11.0 4.4.14 - 2.13.4 + 2.13.4.2 0.8.1 9.4.12.v20180830 4.13.2 diff --git a/release.version b/release.version index 754b84ed..82bf676a 100644 --- a/release.version +++ b/release.version @@ -1 +1 @@ -1.0.179 +1.0.180 From 45976ae7383145e11a9e55efb861578adc86ff5d Mon Sep 17 00:00:00 2001 From: CI Date: Wed, 22 Nov 2023 10:26:57 +0000 Subject: [PATCH 272/310] Releasing version 1.0.181 --- release.version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/release.version b/release.version index 82bf676a..c2667db0 100644 --- a/release.version +++ b/release.version @@ -1 +1 @@ -1.0.180 +1.0.181 From 7535adfbbf0690c956f85c6ecf159f8957c670f7 Mon Sep 17 00:00:00 2001 From: CI Date: Tue, 12 Dec 2023 11:04:22 +0000 Subject: [PATCH 273/310] Releasing version 1.0.182 --- release.version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/release.version b/release.version index c2667db0..18bae621 100644 --- a/release.version +++ b/release.version @@ -1 +1 @@ -1.0.181 +1.0.182 From 8262455bb1004b03e0c9908bd6738b763e5ec630 Mon Sep 17 00:00:00 2001 From: CI Date: Fri, 2 Feb 2024 12:55:31 +0000 Subject: [PATCH 274/310] Releasing version refs/heads/master --- release.version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/release.version b/release.version index 18bae621..d0771267 100644 --- a/release.version +++ b/release.version @@ -1 +1 @@ -1.0.182 +1.0.183 From 9d3afbc9859a94fec63bacf2bcd8f3bbbd8ccdd4 Mon Sep 17 00:00:00 2001 From: CI Date: Fri, 1 Mar 2024 11:05:21 +0000 Subject: [PATCH 275/310] Releasing version 1.0.184 --- release.version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/release.version b/release.version index d0771267..9a4f35d5 100644 --- a/release.version +++ b/release.version @@ -1 +1 @@ -1.0.183 +1.0.184 From 9e75e936608ae9e6867ea70d2816a48aea4b6e13 Mon Sep 17 00:00:00 2001 From: CI Date: Tue, 5 Mar 2024 06:24:55 +0000 Subject: [PATCH 276/310] Releasing version 1.0.185 --- release.version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/release.version b/release.version index 9a4f35d5..d1b85071 100644 --- a/release.version +++ b/release.version @@ -1 +1 @@ -1.0.184 +1.0.185 From 6ea159ca08760c9c53ede29dc3e6459efbbcf2fd Mon Sep 17 00:00:00 2001 From: CI Date: Wed, 27 Mar 2024 12:44:35 +0000 Subject: [PATCH 277/310] Releasing version 1.0.186 --- examples/async-thumbnails/pom.xml | 2 +- examples/regex-query/pom.xml | 2 +- pom.xml | 2 +- release.version | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/examples/async-thumbnails/pom.xml b/examples/async-thumbnails/pom.xml index 40475639..0a28f5fb 100644 --- a/examples/async-thumbnails/pom.xml +++ b/examples/async-thumbnails/pom.xml @@ -28,7 +28,7 @@ 1.0.0-SNAPSHOT 3.3.3 - 2.13.4.2 + 2.16.1 com.fnproject.fn.examples diff --git a/examples/regex-query/pom.xml b/examples/regex-query/pom.xml index 7df881ca..ac7bead1 100644 --- a/examples/regex-query/pom.xml +++ b/examples/regex-query/pom.xml @@ -27,7 +27,7 @@ UTF-8 1.0.0-SNAPSHOT - 2.13.4.2 + 2.16.1 com.fnproject.fn.examples diff --git a/pom.xml b/pom.xml index f8da0ddb..d97ea5c6 100644 --- a/pom.xml +++ b/pom.xml @@ -84,7 +84,7 @@ 3.21.0 2.11.0 4.4.14 - 2.13.4.2 + 2.16.1 0.8.1 9.4.12.v20180830 4.13.2 diff --git a/release.version b/release.version index d1b85071..309a6e28 100644 --- a/release.version +++ b/release.version @@ -1 +1 @@ -1.0.185 +1.0.186 From 071776d4843a0e18d273c16ff151cbfc8d2b0fbe Mon Sep 17 00:00:00 2001 From: CI Date: Tue, 23 Apr 2024 13:32:11 +0000 Subject: [PATCH 278/310] Releasing version 1.0.187 --- release.version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/release.version b/release.version index 309a6e28..53faade9 100644 --- a/release.version +++ b/release.version @@ -1 +1 @@ -1.0.186 +1.0.187 From b9ac4f1240ce004bf4c3b736d20377cda229d4e7 Mon Sep 17 00:00:00 2001 From: CI Date: Fri, 31 May 2024 11:58:55 +0000 Subject: [PATCH 279/310] Releasing version 1.0.188 --- release.version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/release.version b/release.version index 53faade9..f3f8b218 100644 --- a/release.version +++ b/release.version @@ -1 +1 @@ -1.0.187 +1.0.188 From 94fa604bf9cec85fcea8e0fb3791acaf1f31768a Mon Sep 17 00:00:00 2001 From: CI Date: Thu, 4 Jul 2024 06:43:00 +0000 Subject: [PATCH 280/310] Releasing version 1.0.189 --- release.version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/release.version b/release.version index f3f8b218..da0f58aa 100644 --- a/release.version +++ b/release.version @@ -1 +1 @@ -1.0.188 +1.0.189 From 08e30fdab1b667f5c4573ba9351ce8d89fd0c449 Mon Sep 17 00:00:00 2001 From: CI Date: Tue, 16 Jul 2024 11:53:34 +0000 Subject: [PATCH 281/310] Releasing version 1.0.190 --- release.version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/release.version b/release.version index da0f58aa..153e9072 100644 --- a/release.version +++ b/release.version @@ -1 +1 @@ -1.0.189 +1.0.190 From 3ab9ff2e82289e27eb48920ff63cb0ccf0851d55 Mon Sep 17 00:00:00 2001 From: CI Date: Wed, 21 Aug 2024 16:42:01 +0000 Subject: [PATCH 282/310] Releasing version 1.0.191 --- examples/string-reverse/pom.xml | 4 ++-- release.version | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/examples/string-reverse/pom.xml b/examples/string-reverse/pom.xml index 918b4054..472b033b 100644 --- a/examples/string-reverse/pom.xml +++ b/examples/string-reverse/pom.xml @@ -25,9 +25,9 @@ UTF-8 1.0.0-SNAPSHOT - com.example.fn + com.fnproject.fn.examples string-reverse - 1.0.0 + 1.0.0-SNAPSHOT diff --git a/release.version b/release.version index 153e9072..45dd586c 100644 --- a/release.version +++ b/release.version @@ -1 +1 @@ -1.0.190 +1.0.191 From f0f2b2957a4e90fc1bdac62767cdbb03b9e8c083 Mon Sep 17 00:00:00 2001 From: CI Date: Thu, 22 Aug 2024 13:49:09 +0000 Subject: [PATCH 283/310] Releasing version 1.0.192 --- release.version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/release.version b/release.version index 45dd586c..2a8d962e 100644 --- a/release.version +++ b/release.version @@ -1 +1 @@ -1.0.191 +1.0.192 From 6021a0c72d5cebca9dcff1f5a67b1b25a9175c86 Mon Sep 17 00:00:00 2001 From: CI Date: Tue, 27 Aug 2024 15:19:00 +0000 Subject: [PATCH 284/310] Releasing version 1.0.193 --- release.version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/release.version b/release.version index 2a8d962e..5ff12e7c 100644 --- a/release.version +++ b/release.version @@ -1 +1 @@ -1.0.192 +1.0.193 From e2f5b07014f73075249fef69dd540519c5723f1b Mon Sep 17 00:00:00 2001 From: CI Date: Wed, 2 Oct 2024 13:05:03 +0000 Subject: [PATCH 285/310] Releasing version 1.0.195 --- release.version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/release.version b/release.version index 5ff12e7c..6539411b 100644 --- a/release.version +++ b/release.version @@ -1 +1 @@ -1.0.193 +1.0.195 From fe6675c6a6fb85d60618ac45dbd77d81b3fc03b4 Mon Sep 17 00:00:00 2001 From: CI Date: Mon, 21 Oct 2024 16:08:31 +0000 Subject: [PATCH 286/310] Releasing version 1.0.196 --- pom.xml | 2 +- release.version | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/pom.xml b/pom.xml index d97ea5c6..f7d1846a 100644 --- a/pom.xml +++ b/pom.xml @@ -82,7 +82,7 @@ UTF-8 3.21.0 - 2.11.0 + 2.14.0 4.4.14 2.16.1 0.8.1 diff --git a/release.version b/release.version index 6539411b..a9de7066 100644 --- a/release.version +++ b/release.version @@ -1 +1 @@ -1.0.195 +1.0.196 From 0731b6f01fa95dbda7afbf69eb57e9c13b0fef1a Mon Sep 17 00:00:00 2001 From: CI Date: Mon, 25 Nov 2024 16:39:36 +0000 Subject: [PATCH 287/310] Releasing version 1.0.198 --- release.version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/release.version b/release.version index a9de7066..744b4328 100644 --- a/release.version +++ b/release.version @@ -1 +1 @@ -1.0.196 +1.0.198 From 65c93f45ad93b318d9914b02c71b1d54544865b7 Mon Sep 17 00:00:00 2001 From: CI Date: Mon, 27 Jan 2025 18:37:19 +0000 Subject: [PATCH 288/310] Releasing version 1.0.199 --- release.version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/release.version b/release.version index 744b4328..8a0fc5ea 100644 --- a/release.version +++ b/release.version @@ -1 +1 @@ -1.0.198 +1.0.199 From 470d5133740c2a9aa1dcbfa2ee8bc1c80408930d Mon Sep 17 00:00:00 2001 From: CI Date: Sun, 2 Feb 2025 18:45:47 +0000 Subject: [PATCH 289/310] Releasing version 1.0.200 --- release.version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/release.version b/release.version index 8a0fc5ea..ca8e29fa 100644 --- a/release.version +++ b/release.version @@ -1 +1 @@ -1.0.199 +1.0.200 From 1463f7308c99da223efd04efc79100852c19469b Mon Sep 17 00:00:00 2001 From: CI Date: Fri, 21 Feb 2025 05:39:37 +0000 Subject: [PATCH 290/310] Releasing version 1.0.201 --- release.version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/release.version b/release.version index ca8e29fa..f735e4f2 100644 --- a/release.version +++ b/release.version @@ -1 +1 @@ -1.0.200 +1.0.201 From a79202934656d2a103f5c19dc29024eaed58ac5e Mon Sep 17 00:00:00 2001 From: CI Date: Fri, 14 Mar 2025 11:58:59 +0000 Subject: [PATCH 291/310] Releasing version 1.0.202 --- release.version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/release.version b/release.version index f735e4f2..a92908fe 100644 --- a/release.version +++ b/release.version @@ -1 +1 @@ -1.0.201 +1.0.202 From 32e03a4e8c10eb6a7325679b466786c949167760 Mon Sep 17 00:00:00 2001 From: CI Date: Wed, 23 Apr 2025 23:18:29 +0000 Subject: [PATCH 292/310] Releasing version 1.0.206 --- release.version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/release.version b/release.version index a92908fe..e7484fc4 100644 --- a/release.version +++ b/release.version @@ -1 +1 @@ -1.0.202 +1.0.206 From 468672ebba20aef04fece1984c08121bd909574a Mon Sep 17 00:00:00 2001 From: CI Date: Mon, 28 Apr 2025 16:37:57 +0000 Subject: [PATCH 293/310] Releasing version 1.0.207 --- release.version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/release.version b/release.version index e7484fc4..a3fe60b9 100644 --- a/release.version +++ b/release.version @@ -1 +1 @@ -1.0.206 +1.0.207 From 16b41eb74002f443672de3b9c3a9445fe730bf58 Mon Sep 17 00:00:00 2001 From: CI Date: Tue, 3 Jun 2025 02:17:41 +0000 Subject: [PATCH 294/310] Releasing version 1.0.209 --- release.version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/release.version b/release.version index a3fe60b9..ccd4d2ae 100644 --- a/release.version +++ b/release.version @@ -1 +1 @@ -1.0.207 +1.0.209 From a87c97c023756a70ea69dfe74296a973d88f7ba6 Mon Sep 17 00:00:00 2001 From: CI Date: Tue, 22 Jul 2025 15:54:15 +0000 Subject: [PATCH 295/310] Releasing version 1.0.210 --- .gitignore | 1 + release.version | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/.gitignore b/.gitignore index 23d37e5f..e33dd4d3 100644 --- a/.gitignore +++ b/.gitignore @@ -16,4 +16,5 @@ examples/gradle-build/build **/*.classpath **/*.project **/*.settings +.oca/ diff --git a/release.version b/release.version index ccd4d2ae..47682b67 100644 --- a/release.version +++ b/release.version @@ -1 +1 @@ -1.0.209 +1.0.210 From 6d354ddf3d1a4826bb32c6ceed8eb6a5b78712ff Mon Sep 17 00:00:00 2001 From: CI Date: Mon, 28 Jul 2025 06:41:40 +0000 Subject: [PATCH 296/310] Releasing version 1.0.211 --- release.version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/release.version b/release.version index 47682b67..2be0ce8c 100644 --- a/release.version +++ b/release.version @@ -1 +1 @@ -1.0.210 +1.0.211 From d88ba873ae253ca5150c954bc0e3a3818a1dffd2 Mon Sep 17 00:00:00 2001 From: CI Date: Mon, 22 Sep 2025 12:59:09 +0000 Subject: [PATCH 297/310] Releasing version 1.0.213 --- api/pom.xml | 1 + .../migration/migrate_to_maven_central.sh | 46 ++++++++++--------- examples/pom.xml | 1 + experimental-native-image-support/pom.xml | 2 +- flow-api/pom.xml | 2 +- flow-runtime/pom.xml | 2 +- flow-testing/pom.xml | 2 +- fn-spring-cloud-function/pom.xml | 2 +- pom.xml | 21 +++++---- release.version | 2 +- runtime/pom.xml | 2 +- testing-core/pom.xml | 2 +- testing-junit4/pom.xml | 2 +- testing/pom.xml | 2 +- 14 files changed, 47 insertions(+), 42 deletions(-) diff --git a/api/pom.xml b/api/pom.xml index 44ad20fa..eef37b0c 100644 --- a/api/pom.xml +++ b/api/pom.xml @@ -27,6 +27,7 @@ 4.0.0 + api api diff --git a/bin/scripts/migration/migrate_to_maven_central.sh b/bin/scripts/migration/migrate_to_maven_central.sh index 3a015295..5be056e0 100644 --- a/bin/scripts/migration/migrate_to_maven_central.sh +++ b/bin/scripts/migration/migrate_to_maven_central.sh @@ -29,14 +29,14 @@ POM_REPLACEMENT="4.0.0 https://github.com/fnproject/fdk-java - - ossrh - https://s01.oss.sonatype.org/service/local/staging/deploy/maven2/ - - - ossrh - https://s01.oss.sonatype.org/content/repositories/snapshots - + + central + https://central.sonatype.com/api/v1/staging/deploy/maven2 + + + central + https://central.sonatype.com/repository/maven-snapshots/ + fdk-java The Function Development Kit for Java makes it easy to build and deploy Java functions to Fn @@ -44,8 +44,8 @@ POM_REPLACEMENT="4.0.0 " # Constants -MAVEN_CENTRAL_STAGINGURL="https://s01.oss.sonatype.org/service/local/staging/deploy/maven2" -MAVEN_CENTRAL_REPOID="ossrh" +MAVEN_CENTRAL_STAGINGURL="https://central.sonatype.com/api/v1/staging/deploy/maven2" +MAVEN_CENTRAL_REPOID="central" OUTPUT_DIR="output" # TODO: add versions e.g. (1.0.0 1.0.1 1.0.2) 10*1+ 5+2+1 @@ -175,14 +175,15 @@ function prepare_pom() { SCM_PLUGIN=" - org.sonatype.plugins - nexus-staging-maven-plugin - 1.6.7 + org.sonatype.central + central-publishing-maven-plugin + 0.8.0 true - ossrh - https://s01.oss.sonatype.org/ - true + central + true + published + " @@ -230,14 +231,15 @@ function modify_group_id() { SCM_PLUGIN=" - org.sonatype.plugins - nexus-staging-maven-plugin - 1.6.7 + org.sonatype.central + central-publishing-maven-plugin + 0.8.0 true - ossrh - https://s01.oss.sonatype.org/ - true + central + true + published + " diff --git a/examples/pom.xml b/examples/pom.xml index 9f058115..c9d9be30 100644 --- a/examples/pom.xml +++ b/examples/pom.xml @@ -23,6 +23,7 @@ 4.0.0 pom fdk-examples + fdk-examples com.fnproject.fn.examples diff --git a/experimental-native-image-support/pom.xml b/experimental-native-image-support/pom.xml index 61334781..31fe7592 100644 --- a/experimental-native-image-support/pom.xml +++ b/experimental-native-image-support/pom.xml @@ -26,7 +26,7 @@ 1.0.0-SNAPSHOT 4.0.0 - + experimental-native-image-support experimental-native-image-support diff --git a/flow-api/pom.xml b/flow-api/pom.xml index 1c1dd563..81e25e32 100644 --- a/flow-api/pom.xml +++ b/flow-api/pom.xml @@ -26,7 +26,7 @@ 1.0.0-SNAPSHOT 4.0.0 - + flow-api flow-api diff --git a/flow-runtime/pom.xml b/flow-runtime/pom.xml index f9c6577e..c6d6681e 100644 --- a/flow-runtime/pom.xml +++ b/flow-runtime/pom.xml @@ -26,7 +26,7 @@ 1.0.0-SNAPSHOT 4.0.0 - + flow-runtime flow-runtime diff --git a/flow-testing/pom.xml b/flow-testing/pom.xml index 07abef8b..1d2bb74c 100644 --- a/flow-testing/pom.xml +++ b/flow-testing/pom.xml @@ -26,7 +26,7 @@ 1.0.0-SNAPSHOT 4.0.0 - + flow-testing flow-testing diff --git a/fn-spring-cloud-function/pom.xml b/fn-spring-cloud-function/pom.xml index f85d5525..ed84d672 100644 --- a/fn-spring-cloud-function/pom.xml +++ b/fn-spring-cloud-function/pom.xml @@ -26,7 +26,7 @@ 1.0.0-SNAPSHOT 4.0.0 - + fn-spring-cloud-function fn-spring-cloud-function diff --git a/pom.xml b/pom.xml index f7d1846a..158d0e9b 100644 --- a/pom.xml +++ b/pom.xml @@ -54,12 +54,12 @@ - ossrh - https://s01.oss.sonatype.org/service/local/staging/deploy/maven2/ + central + https://central.sonatype.com/api/v1/staging/deploy/maven2 - ossrh - https://s01.oss.sonatype.org/content/repositories/snapshots + central + https://central.sonatype.com/repository/maven-snapshots/ @@ -383,14 +383,15 @@ - org.sonatype.plugins - nexus-staging-maven-plugin - 1.6.7 + org.sonatype.central + central-publishing-maven-plugin + 0.8.0 true - ossrh - https://s01.oss.sonatype.org/ - ${auto.release} + central + true + published + diff --git a/release.version b/release.version index 2be0ce8c..8e8f9d43 100644 --- a/release.version +++ b/release.version @@ -1 +1 @@ -1.0.211 +1.0.213 diff --git a/runtime/pom.xml b/runtime/pom.xml index 850d4d80..70de9733 100644 --- a/runtime/pom.xml +++ b/runtime/pom.xml @@ -26,7 +26,7 @@ 1.0.0-SNAPSHOT 4.0.0 - + runtime runtime diff --git a/testing-core/pom.xml b/testing-core/pom.xml index d88d989d..94d7e9f9 100644 --- a/testing-core/pom.xml +++ b/testing-core/pom.xml @@ -26,7 +26,7 @@ 1.0.0-SNAPSHOT 4.0.0 - + testing-core testing-core diff --git a/testing-junit4/pom.xml b/testing-junit4/pom.xml index 12554a1a..b1089a9c 100644 --- a/testing-junit4/pom.xml +++ b/testing-junit4/pom.xml @@ -26,7 +26,7 @@ 1.0.0-SNAPSHOT 4.0.0 - + testing-junit4 testing-junit4 diff --git a/testing/pom.xml b/testing/pom.xml index 8ee86d46..afa719cc 100644 --- a/testing/pom.xml +++ b/testing/pom.xml @@ -26,7 +26,7 @@ 1.0.0-SNAPSHOT 4.0.0 - + testing testing From a472bbb93d229fc9df563d2cfeff9d6cf04c088c Mon Sep 17 00:00:00 2001 From: CI Date: Mon, 13 Oct 2025 16:41:55 +0000 Subject: [PATCH 298/310] Releasing version 1.0.214 --- release.version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/release.version b/release.version index 8e8f9d43..d83f5998 100644 --- a/release.version +++ b/release.version @@ -1 +1 @@ -1.0.213 +1.0.214 From 96da73c0dc4add2e78f57646ee3fe0c081154c82 Mon Sep 17 00:00:00 2001 From: CI Date: Mon, 27 Oct 2025 10:42:04 +0000 Subject: [PATCH 299/310] Releasing version 1.0.215 --- release.version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/release.version b/release.version index d83f5998..e5365c8e 100644 --- a/release.version +++ b/release.version @@ -1 +1 @@ -1.0.214 +1.0.215 From 062cbd0799a7018889d84953725a5d224667b7f0 Mon Sep 17 00:00:00 2001 From: CI Date: Mon, 10 Nov 2025 14:29:59 +0000 Subject: [PATCH 300/310] Releasing version 1.0.217 --- release.version | 2 +- runtime/src/main/c/CMakeLists.txt | 2 +- runtime/src/main/c/Dockerfile-buildimage | 11 +++++------ 3 files changed, 7 insertions(+), 8 deletions(-) diff --git a/release.version b/release.version index e5365c8e..aae9c383 100644 --- a/release.version +++ b/release.version @@ -1 +1 @@ -1.0.215 +1.0.217 diff --git a/runtime/src/main/c/CMakeLists.txt b/runtime/src/main/c/CMakeLists.txt index c623430c..61d79e3d 100644 --- a/runtime/src/main/c/CMakeLists.txt +++ b/runtime/src/main/c/CMakeLists.txt @@ -1,4 +1,4 @@ -cmake_minimum_required(VERSION 2.8) +cmake_minimum_required(VERSION 3.5) project(fnunixsocket) set(CMAKE_BUILD_TYPE Release) set(JAVA_AWT_LIBRARY NotNeeded) diff --git a/runtime/src/main/c/Dockerfile-buildimage b/runtime/src/main/c/Dockerfile-buildimage index 190e933d..dcfce5dc 100644 --- a/runtime/src/main/c/Dockerfile-buildimage +++ b/runtime/src/main/c/Dockerfile-buildimage @@ -14,12 +14,11 @@ # limitations under the License. # -FROM iad.ocir.io/oraclefunctionsdevelopm/oraclelinux:7.5 - -RUN rm -rf /var/cache/yum/* -RUN yum install -y gcc cmake java-1.8.0-openjdk-devel make -RUN yum install -y gcc-c++ - +FROM container-registry.oracle.com/os/oraclelinux:9-slim +RUN microdnf install -y \ + gcc gcc-c++ cmake make java-1.8.0-openjdk-devel && \ + microdnf clean all \ RUN mkdir /build WORKDIR /build + From ff7b6761f2dd87e0e158f85a5d5d8481e8c8980b Mon Sep 17 00:00:00 2001 From: CI Date: Tue, 25 Nov 2025 10:12:50 +0000 Subject: [PATCH 301/310] Releasing version 1.0.218 --- release.version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/release.version b/release.version index aae9c383..4de9573d 100644 --- a/release.version +++ b/release.version @@ -1 +1 @@ -1.0.217 +1.0.218 From eab48362294fdd5c7bcc8e024f88159b429d3cb7 Mon Sep 17 00:00:00 2001 From: CI Date: Wed, 17 Dec 2025 17:05:13 +0000 Subject: [PATCH 302/310] Releasing version 1.1.2 --- README.md | 4 + examples/README.md | 9 ++ examples/apigateway-event/README.md | 135 ++++++++++++++++++ examples/apigateway-event/func.yaml | 5 + examples/apigateway-event/pom.xml | 100 +++++++++++++ .../fn/examples/EmployeeService.java | 19 +++ .../com/fnproject/fn/examples/Function.java | 34 +++++ .../fn/examples/RequestEmployee.java | 16 +++ .../fn/examples/ResponseEmployee.java | 40 ++++++ .../fnproject/fn/examples/FunctionTest.java | 96 +++++++++++++ examples/connectorhub-logging/README.md | 93 ++++++++++++ examples/connectorhub-logging/func.yaml | 5 + examples/connectorhub-logging/pom.xml | 100 +++++++++++++ .../com/fnproject/fn/examples/Function.java | 21 +++ .../com/fnproject/fn/examples/LogService.java | 19 +++ .../fnproject/fn/examples/FunctionTest.java | 71 +++++++++ examples/connectorhub-monitoring/README.md | 95 ++++++++++++ examples/connectorhub-monitoring/func.yaml | 5 + examples/connectorhub-monitoring/pom.xml | 100 +++++++++++++ .../com/fnproject/fn/examples/Function.java | 21 +++ .../fnproject/fn/examples/MetricService.java | 18 +++ .../fnproject/fn/examples/FunctionTest.java | 60 ++++++++ examples/connectorhub-queue/README.md | 124 ++++++++++++++++ examples/connectorhub-queue/func.yaml | 5 + examples/connectorhub-queue/pom.xml | 100 +++++++++++++ .../com/fnproject/fn/examples/Employee.java | 41 ++++++ .../com/fnproject/fn/examples/Function.java | 20 +++ .../fnproject/fn/examples/QueueService.java | 10 ++ .../fnproject/fn/examples/FunctionTest.java | 42 ++++++ examples/connectorhub-streaming/README.md | 133 +++++++++++++++++ examples/connectorhub-streaming/func.yaml | 5 + examples/connectorhub-streaming/pom.xml | 100 +++++++++++++ .../com/fnproject/fn/examples/Employee.java | 41 ++++++ .../com/fnproject/fn/examples/Function.java | 21 +++ .../fnproject/fn/examples/StreamService.java | 19 +++ .../fnproject/fn/examples/FunctionTest.java | 53 +++++++ examples/notifications/README.md | 116 +++++++++++++++ examples/notifications/func.yaml | 5 + examples/notifications/pom.xml | 112 +++++++++++++++ .../com/fnproject/fn/examples/Employee.java | 41 ++++++ .../com/fnproject/fn/examples/Function.java | 18 +++ .../fn/examples/NotificationService.java | 10 ++ .../fnproject/fn/examples/FunctionTest.java | 36 +++++ examples/pom.xml | 6 + pom.xml | 7 + release.version | 2 +- .../DefaultFunctionInvocationContext.java | 15 ++ .../fn/runtime/DefaultMethodWrapper.java | 4 +- .../FunctionHTTPGatewayContext.java | 10 ++ .../fnproject/fn/testing/FnTestingRule.java | 4 + 50 files changed, 2163 insertions(+), 3 deletions(-) create mode 100644 examples/apigateway-event/README.md create mode 100644 examples/apigateway-event/func.yaml create mode 100644 examples/apigateway-event/pom.xml create mode 100644 examples/apigateway-event/src/main/java/com/fnproject/fn/examples/EmployeeService.java create mode 100644 examples/apigateway-event/src/main/java/com/fnproject/fn/examples/Function.java create mode 100644 examples/apigateway-event/src/main/java/com/fnproject/fn/examples/RequestEmployee.java create mode 100644 examples/apigateway-event/src/main/java/com/fnproject/fn/examples/ResponseEmployee.java create mode 100644 examples/apigateway-event/src/test/java/com/fnproject/fn/examples/FunctionTest.java create mode 100644 examples/connectorhub-logging/README.md create mode 100644 examples/connectorhub-logging/func.yaml create mode 100644 examples/connectorhub-logging/pom.xml create mode 100644 examples/connectorhub-logging/src/main/java/com/fnproject/fn/examples/Function.java create mode 100644 examples/connectorhub-logging/src/main/java/com/fnproject/fn/examples/LogService.java create mode 100644 examples/connectorhub-logging/src/test/java/com/fnproject/fn/examples/FunctionTest.java create mode 100644 examples/connectorhub-monitoring/README.md create mode 100644 examples/connectorhub-monitoring/func.yaml create mode 100644 examples/connectorhub-monitoring/pom.xml create mode 100644 examples/connectorhub-monitoring/src/main/java/com/fnproject/fn/examples/Function.java create mode 100644 examples/connectorhub-monitoring/src/main/java/com/fnproject/fn/examples/MetricService.java create mode 100644 examples/connectorhub-monitoring/src/test/java/com/fnproject/fn/examples/FunctionTest.java create mode 100644 examples/connectorhub-queue/README.md create mode 100644 examples/connectorhub-queue/func.yaml create mode 100644 examples/connectorhub-queue/pom.xml create mode 100644 examples/connectorhub-queue/src/main/java/com/fnproject/fn/examples/Employee.java create mode 100644 examples/connectorhub-queue/src/main/java/com/fnproject/fn/examples/Function.java create mode 100644 examples/connectorhub-queue/src/main/java/com/fnproject/fn/examples/QueueService.java create mode 100644 examples/connectorhub-queue/src/test/java/com/fnproject/fn/examples/FunctionTest.java create mode 100644 examples/connectorhub-streaming/README.md create mode 100644 examples/connectorhub-streaming/func.yaml create mode 100644 examples/connectorhub-streaming/pom.xml create mode 100644 examples/connectorhub-streaming/src/main/java/com/fnproject/fn/examples/Employee.java create mode 100644 examples/connectorhub-streaming/src/main/java/com/fnproject/fn/examples/Function.java create mode 100644 examples/connectorhub-streaming/src/main/java/com/fnproject/fn/examples/StreamService.java create mode 100644 examples/connectorhub-streaming/src/test/java/com/fnproject/fn/examples/FunctionTest.java create mode 100644 examples/notifications/README.md create mode 100644 examples/notifications/func.yaml create mode 100644 examples/notifications/pom.xml create mode 100644 examples/notifications/src/main/java/com/fnproject/fn/examples/Employee.java create mode 100644 examples/notifications/src/main/java/com/fnproject/fn/examples/Function.java create mode 100644 examples/notifications/src/main/java/com/fnproject/fn/examples/NotificationService.java create mode 100644 examples/notifications/src/test/java/com/fnproject/fn/examples/FunctionTest.java create mode 100644 runtime/src/main/java/com/fnproject/fn/runtime/DefaultFunctionInvocationContext.java diff --git a/README.md b/README.md index 029f5628..25d2776b 100644 --- a/README.md +++ b/README.md @@ -19,6 +19,10 @@ New to Fn Project? If you want to learn more about using the Fn Project to power For detailed instructions on using the FDK to build and deploy Java functions to Fn, please see the official FDK developer guide in our docs repo here: https://github.com/fnproject/docs/blob/master/fdks/fdk-java/README.md. +## Integrating with OCI Services + +Use the fn-events library to easily integrate your Function with OCI services; Connector Hub, API Gateway and Notifications. Start with the [README.md](fn-events/README.md) + ## Contributing to the Function Development Kit for Java Please see [CONTRIBUTING.md](CONTRIBUTING.md). diff --git a/examples/README.md b/examples/README.md index 0514760b..620fbee6 100644 --- a/examples/README.md +++ b/examples/README.md @@ -37,3 +37,12 @@ thumbnails for it, then uploads them to an object storage. ## (5) Gradle build This shows how to use Gradle to build functions using the Java FDK. + +## (6) Fn Events +This shows how to use fn-events library for: +- OCI API Gateway Function - [README.md](../examples/apigateway-event/README.md) +- OCI Service Connector Hub: Monitoring - [README.md](../examples/connectorhub-monitoring/README.md) +- OCI Service Connector Hub: Logging - [README.md](../examples/connectorhub-logging/README.md) +- OCI Service Connector Hub: Streaming - [README.md](../examples/connectorhub-streaming/README.md) +- OCI Service Connector Hub: Queue - [connectorhub-queue](../examples/connectorhub-queue) +- OCI Notifications - [README.md](../examples/notifications/README.md) \ No newline at end of file diff --git a/examples/apigateway-event/README.md b/examples/apigateway-event/README.md new file mode 100644 index 00000000..0d3277e2 --- /dev/null +++ b/examples/apigateway-event/README.md @@ -0,0 +1,135 @@ +# Example Fn Java FDK : API Gateway + +This example provides a Function to use as an API Gateway backend. +The function accepts a typed request for easy object handling and returns +http response. + +## Dependencies + +* [fn-events] for APIGatewayFunction classes. +* [fn-events-testing] for APIGatewayFunction testing library. + +## Demonstrated FDK features + +This example showcases how to use the fn-event APIGatewayFunction to +use a Function as the backend. + +## Step by step + +Set the API Gateway and Function +backend [Adding a Function in OCI Functions as an API Gateway Back End](https://docs.oracle.com/en-us/iaas/Content/APIGateway/Tasks/apigatewayusingfunctionsbackend.htm) + +The Function entrypoint extends the `APIGatewayFunction` abstract class. +Note: the [func.yaml](func.yaml) entrypoint remains the class which extends `APIGatewayFunction` +e.g. `cmd: com.fnproject.fn.examples.Function::handler` + + +[Function.java](src/main/java/com/fnproject/fn/examples/Function.java) +```java +import com.fnproject.events.APIGatewayFunction; +import com.fnproject.events.input.APIGatewayRequestEvent; +import com.fnproject.events.output.APIGatewayResponseEvent; +import com.fnproject.fn.api.Headers; +import org.apache.http.HttpStatus; + +public class Function extends APIGatewayFunction { + + @Override + public APIGatewayResponseEvent handler(APIGatewayRequestEvent requestEvent) { + ResponseEmployee employee = new ResponseEmployee(); + Optional id = requestEvent.getQueryParameters().get("id"); + id.ifPresent(s -> employee.setId(Integer.parseInt(s))); + + if (requestEvent.getBody() != null) { + employee.setName(requestEvent.getBody().getName()); + } + + return new APIGatewayResponseEvent.Builder() + .statusCode(HttpStatus.SC_CREATED) + .headers(Headers.emptyHeaders() + .addHeader("X-Custom-Header", "HeaderValue") + .addHeader("X-Custom-Header-2", "HeaderValue2")) + .body(employee) + .build(); + } +} +``` +The APIGatewayRequestEvent.class `requestUrl` is relative to the deployment +path prefix [see API Gateway using HTTP backend](https://docs.oracle.com/en-us/iaas/Content/APIGateway/Tasks/apigatewayusinghttpbackend.htm#usingjson) + + +The class [RequestEmployee.java](src/main/java/com/fnproject/fn/examples/RequestEmployee.java) is the request body type and +[ResponseEmployee.java](src/main/java/com/fnproject/fn/examples/ResponseEmployee.java) is the response body type. +These are passed in position 1 and 2 of abstract class +[Function.java](src/main/java/com/fnproject/fn/examples/Function.java) +`public class Function extends APIGatewayFunction {`. + +To return an error response, throw RuntimeException.class. + +## Test walkthrough + +Unit testing `APIGatewayFunction` is supported with the `APIGatewayTestFeature` and `FnTestingRule`. + +First of all, the class initializes the `FnTestingRule` harness, as explained +in [Testing Functions](../../docs/TestingFunctions.md). + +[FunctionTest.java](src/test/java/com/fnproject/fn/examples/FunctionTest.java) +```java +import static org.junit.Assert.*; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; +import java.io.IOException; +import java.util.Collections; +import java.util.HashMap; +import java.util.List; +import com.fnproject.events.input.APIGatewayRequestEvent; +import com.fnproject.events.output.APIGatewayResponseEvent; +import com.fnproject.events.testing.APIGatewayTestFeature; +import com.fnproject.fn.testing.FnTestingRule; +import org.junit.Rule; +import org.junit.Test; + +public class FunctionTest { + + @Rule + public FnTestingRule fn = FnTestingRule.createDefault(); + + private final APIGatewayTestFeature apiGatewayFeature = APIGatewayTestFeature.createDefault(fn); + + @Test + public void testHttpAttributes() throws IOException { + RequestEmployee requestEmployee = new RequestEmployee(); + requestEmployee.setName("John"); + + APIGatewayRequestEvent event = mock(APIGatewayRequestEvent.class); + + when(event.getBody()).thenReturn(requestEmployee); + when(event.getMethod()).thenReturn("POST"); + when(event.getRequestUrl()).thenReturn("/v2?id=123"); + when(event.getQueryParameters()).thenReturn(new QueryParametersImpl(Collections.singletonMap("id", Collections.singletonList("123")))); + when(event.getHeaders()).thenReturn(Collections.unmodifiableMap(new HashMap>() {{ + put("myHeader", Collections.singletonList("headerValue")); + }})); + + apiGatewayFeature.givenEvent(event) + .enqueue(); + + fn.thenRun(Function.class, "handler"); + + APIGatewayResponseEvent responseEvent = apiGatewayFeature.getResult(ResponseEmployee.class); + + ResponseEmployee responseEventBody = responseEvent.getBody(); + assertEquals(123, responseEventBody.getId()); + assertEquals("John", responseEventBody.getName()); + assertEquals(Integer.valueOf(201), responseEvent.getStatus()); + assertEquals("HeaderValue", responseEvent.getHeaders().get("X-Custom-Header").get(0)); + assertEquals("HeaderValue2", responseEvent.getHeaders().get("X-Custom-Header-2").get(0)); + } +} +``` + +Use `apiGatewayFeature.givenEvent(event).enqueue();` to queue the request event +and invoke the Function with `fn.thenRun(Function.class, "handler");`. + +And get the Function response using +`APIGatewayResponseEvent responseEvent = apiGatewayFeature.getResult(ResponseEmployee.class);` diff --git a/examples/apigateway-event/func.yaml b/examples/apigateway-event/func.yaml new file mode 100644 index 00000000..1f72ed08 --- /dev/null +++ b/examples/apigateway-event/func.yaml @@ -0,0 +1,5 @@ +schema_version: 20180708 +name: apigateway-event +version: 0.0.1 +runtime: java +cmd: com.fnproject.fn.examples.Function::handler diff --git a/examples/apigateway-event/pom.xml b/examples/apigateway-event/pom.xml new file mode 100644 index 00000000..e1b8de57 --- /dev/null +++ b/examples/apigateway-event/pom.xml @@ -0,0 +1,100 @@ + + + + + 4.0.0 + + + UTF-8 + UTF-8 + 1.0.0-SNAPSHOT + 2.16.1 + 4.0.0 + + + com.fnproject.fn.examples + apigateway-event + 1.0.0-SNAPSHOT + + + + com.fnproject.fn + api + ${fdk.version} + + + com.fnproject.fn + fn-events + ${fdk.version} + + + com.fnproject.fn + fn-events-testing + ${fdk.version} + test + + + junit + junit + 4.13.2 + test + + + org.mockito + mockito-core + ${mockito.version} + test + + + com.fnproject.fn + testing-core + ${fdk.version} + test + + + com.fnproject.fn + testing-junit4 + ${fdk.version} + test + + + + + + org.apache.maven.plugins + maven-compiler-plugin + 3.8.0 + + 1.8 + 1.8 + + + + org.apache.maven.plugins + maven-deploy-plugin + 2.8.2 + + true + + + + + diff --git a/examples/apigateway-event/src/main/java/com/fnproject/fn/examples/EmployeeService.java b/examples/apigateway-event/src/main/java/com/fnproject/fn/examples/EmployeeService.java new file mode 100644 index 00000000..8b9357cb --- /dev/null +++ b/examples/apigateway-event/src/main/java/com/fnproject/fn/examples/EmployeeService.java @@ -0,0 +1,19 @@ +package com.fnproject.fn.examples; + +import java.util.Optional; + +public class EmployeeService { + + public ResponseEmployee createEmployee(RequestEmployee requestEmployee, Optional id) { + if (requestEmployee == null) { + throw new IllegalArgumentException("requestEmployee must not be null"); + } + if (!id.isPresent()) { + throw new IllegalArgumentException("id must not be null"); + } + ResponseEmployee employee = new ResponseEmployee(); + employee.setId(Integer.parseInt(id.get())); + employee.setName(requestEmployee.getName()); + return employee; + } +} diff --git a/examples/apigateway-event/src/main/java/com/fnproject/fn/examples/Function.java b/examples/apigateway-event/src/main/java/com/fnproject/fn/examples/Function.java new file mode 100644 index 00000000..bf276d34 --- /dev/null +++ b/examples/apigateway-event/src/main/java/com/fnproject/fn/examples/Function.java @@ -0,0 +1,34 @@ +package com.fnproject.fn.examples; + +import java.util.Optional; +import com.fnproject.events.APIGatewayFunction; +import com.fnproject.events.input.APIGatewayRequestEvent; +import com.fnproject.events.output.APIGatewayResponseEvent; +import com.fnproject.fn.api.Headers; +import org.apache.http.HttpStatus; + + +public class Function extends APIGatewayFunction { + + private final EmployeeService employeeService; + + public Function() { + this.employeeService = new EmployeeService(); + } + + @Override + public APIGatewayResponseEvent handler(APIGatewayRequestEvent requestEvent) { + Optional id = requestEvent.getQueryParameters().get("id"); + RequestEmployee requestEmployee = requestEvent.getBody(); + + ResponseEmployee responseEmployee = employeeService.createEmployee(requestEmployee, id); + + return new APIGatewayResponseEvent.Builder() + .statusCode(HttpStatus.SC_CREATED) + .headers(Headers.emptyHeaders() + .addHeader("X-Custom-Header", "HeaderValue") + .addHeader("X-Custom-Header-2", "HeaderValue2")) + .body(responseEmployee) + .build(); + } +} diff --git a/examples/apigateway-event/src/main/java/com/fnproject/fn/examples/RequestEmployee.java b/examples/apigateway-event/src/main/java/com/fnproject/fn/examples/RequestEmployee.java new file mode 100644 index 00000000..7e1cc74c --- /dev/null +++ b/examples/apigateway-event/src/main/java/com/fnproject/fn/examples/RequestEmployee.java @@ -0,0 +1,16 @@ +package com.fnproject.fn.examples; + +public class RequestEmployee { + private String name; + + public RequestEmployee() {} + + public String getName() { + return this.name; + } + + public void setName(String name) { + this.name = name; + } + +} diff --git a/examples/apigateway-event/src/main/java/com/fnproject/fn/examples/ResponseEmployee.java b/examples/apigateway-event/src/main/java/com/fnproject/fn/examples/ResponseEmployee.java new file mode 100644 index 00000000..9d056c57 --- /dev/null +++ b/examples/apigateway-event/src/main/java/com/fnproject/fn/examples/ResponseEmployee.java @@ -0,0 +1,40 @@ +package com.fnproject.fn.examples; + +import java.util.Objects; + +public class ResponseEmployee { + private Integer id; + private String name; + + public ResponseEmployee() {} + + public Integer getId() { + return this.id; + } + + public void setId(Integer id) { + this.id = id; + } + + public String getName() { + return this.name; + } + + public void setName(String name) { + this.name = name; + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + ResponseEmployee employee = (ResponseEmployee) o; + return id.equals(employee.id) && + Objects.equals(name, employee.name); + } + + @Override + public int hashCode() { + return Objects.hash(id, name); + } +} \ No newline at end of file diff --git a/examples/apigateway-event/src/test/java/com/fnproject/fn/examples/FunctionTest.java b/examples/apigateway-event/src/test/java/com/fnproject/fn/examples/FunctionTest.java new file mode 100644 index 00000000..417ec880 --- /dev/null +++ b/examples/apigateway-event/src/test/java/com/fnproject/fn/examples/FunctionTest.java @@ -0,0 +1,96 @@ +package com.fnproject.fn.examples; + +import static org.junit.Assert.*; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; +import java.io.IOException; +import java.util.Collections; +import com.fnproject.events.input.APIGatewayRequestEvent; +import com.fnproject.events.output.APIGatewayResponseEvent; +import com.fnproject.events.testing.APIGatewayTestFeature; +import com.fnproject.fn.api.Headers; +import com.fnproject.fn.runtime.httpgateway.QueryParametersImpl; +import com.fnproject.fn.testing.FnResult; +import com.fnproject.fn.testing.FnTestingRule; +import org.junit.Rule; +import org.junit.Test; + +public class FunctionTest { + + @Rule + public FnTestingRule fn = FnTestingRule.createDefault(); + + private final APIGatewayTestFeature apiGatewayFeature = APIGatewayTestFeature.createDefault(fn); + + @Test + public void testGetResponseBody() throws IOException { + APIGatewayRequestEvent event = createMinimalRequest(); + + apiGatewayFeature.givenEvent(event) + .enqueue(); + + fn.thenRun(Function.class, "handler"); + + APIGatewayResponseEvent responseEvent = apiGatewayFeature.getResult(ResponseEmployee.class); + + ResponseEmployee responseEventBody = responseEvent.getBody(); + assertEquals(Integer.valueOf(123), responseEventBody.getId()); + assertEquals("John", responseEventBody.getName()); + } + + @Test + public void testGetResponseHeaders() throws IOException { + APIGatewayRequestEvent event = createMinimalRequest(); + + when(event.getHeaders()).thenReturn(Headers.emptyHeaders().addHeader("myHeader", "headerValue")); + + apiGatewayFeature.givenEvent(event) + .enqueue(); + + fn.thenRun(Function.class, "handler"); + + APIGatewayResponseEvent responseEvent = apiGatewayFeature.getResult(ResponseEmployee.class); + assertEquals("HeaderValue", responseEvent.getHeaders().getAllValues("X-Custom-Header").get(0)); + assertEquals("HeaderValue2", responseEvent.getHeaders().get("X-Custom-Header-2").get()); + } + + @Test + public void testGetResponseStatus() throws IOException { + APIGatewayRequestEvent event = createMinimalRequest(); + + apiGatewayFeature.givenEvent(event) + .enqueue(); + + fn.thenRun(Function.class, "handler"); + + APIGatewayResponseEvent responseEvent = apiGatewayFeature.getResult(ResponseEmployee.class); + + assertEquals(Integer.valueOf(201), responseEvent.getStatus()); + } + + @Test + public void testErrorResponse() throws IOException { + APIGatewayRequestEvent event = mock(APIGatewayRequestEvent.class); + + apiGatewayFeature.givenEvent(event) + .enqueue(); + + fn.thenRun(Function.class, "handler"); + + FnResult result = fn.getOnlyResult(); + assertEquals(502, result.getStatus().getCode()); + assertEquals("An error occurred in function: requestEmployee must not be null\n" + + "Caused by: java.lang.IllegalArgumentException: requestEmployee must not be null\n\n", fn.getStdErrAsString()); + assertEquals(1, fn.getLastExitCode()); + } + + private static APIGatewayRequestEvent createMinimalRequest() { + RequestEmployee requestEmployee = new RequestEmployee(); + requestEmployee.setName("John"); + APIGatewayRequestEvent event = mock(APIGatewayRequestEvent.class); + + when(event.getBody()).thenReturn(requestEmployee); + when(event.getQueryParameters()).thenReturn(new QueryParametersImpl(Collections.singletonMap("id", Collections.singletonList("123")))); + return event; + } +} \ No newline at end of file diff --git a/examples/connectorhub-logging/README.md b/examples/connectorhub-logging/README.md new file mode 100644 index 00000000..992474e2 --- /dev/null +++ b/examples/connectorhub-logging/README.md @@ -0,0 +1,93 @@ +# Example Fn Java FDK : Service Connector Hub - Logging + +This example provides a Function to use as a service connector hub target. +The function accepts a typed event containing a batch of source events. + +## Source +[LoggingData.java](../../fn-events/src/main/java/com/fnproject/events/input/sch/LoggingData.java) + +## Dependencies +* [fn-events] for ConnectorHubFunction classes. +* [fn-events-testing] for ConnectorHubFunction testing library. + +## Demonstrated FDK features + +This example showcases how to use the fn-event ConnectorHubFunction to +use a Function as the target for Logging source. + +## Step by step + +Set up the connector hub with Logging source and Function target: +* [Setup default policies](https://docs.oracle.com/en-us/iaas/Content/connector-hub/overview.htm#Authenti__default-policies) +* [create connector hub](https://docs.oracle.com/en-us/iaas/Content/connector-hub/create-service-connector-logging-source.htm) + +The Function entrypoint extends the `ConnectorHubFunction` abstract class. +Note: the [func.yaml](func.yaml) entrypoint remains the class which extends `ConnectorHubFunction` +e.g. `cmd: com.fnproject.fn.examples.Function::handler` + +[Function.java](src/main/java/com/fnproject/fn/examples/Function.java) +```java +package com.fnproject.fn.examples; + +import com.fnproject.events.ConnectorHubFunction; +import com.fnproject.events.input.ConnectorHubBatch; +import com.fnproject.events.input.sch.LoggingData; + +public class Function extends ConnectorHubFunction { + + public LogService logService; + + public Function() { + this.logService = new LogService(); + } + + @Override + public void handler(ConnectorHubBatch batch) { + for (LoggingData log : batch.getBatch()) { + logService.readLog(log); + } + } +} +``` +The [ConnectorHubBatch.java](../../fn-events/src/main/java/com/fnproject/events/input/ConnectorHubBatch.java) +`batch` contains a list of events from Logging as +specified in [Batch Settings](https://docs.oracle.com/en-us/iaas/Content/connector-hub/overview.htm#batch-settings). + +The class [LoggingData.java](../../fn-events/src/main/java/com/fnproject/events/input/sch/LoggingData.java) is +each logging event. + +[Function.java](src/main/java/com/fnproject/fn/examples/Function.java) +`public class Function extends ConnectorHubFunction`. + +To return an error response, throw RuntimeException.class. +Doing so will cause the Function to return a 502 [Retry policy](https://docs.oracle.com/en-us/iaas/Content/connector-hub/overview.htm#deactivate) + +## Test walkthrough + +Unit testing `ConnectorHubFunction` is supported with the `ConnectorHubTestFeature` and `FnTestingRule`. + +First of all, the class initializes the `FnTestingRule` harness, as explained +in [Testing Functions](../../docs/TestingFunctions.md). + +[FunctionTest.java](src/test/java/com/fnproject/fn/examples/FunctionTest.java) +```java +@Rule +public FnTestingRule fn = FnTestingRule.createDefault(); + +private final ConnectorHubTestFeature connectorHubTestFeature = ConnectorHubTestFeature.createDefault(fn); + +@Test +public void testInvokeFunctionWithLoggingData() throws Exception { + + ConnectorHubBatch event = createMinimalRequest(); + connectorHubTestFeature.givenEvent(event).enqueue(); + + fn.thenRun(Function.class, "handler"); + + FnResult result = fn.getOnlyResult(); + assertEquals(200, result.getStatus().getCode()); +} +``` + +Use `connectorHubTestFeature.givenEvent(event).enqueue();` to queue the request event +and invoke the Function with `fn.thenRun(Function.class, "handler");`. diff --git a/examples/connectorhub-logging/func.yaml b/examples/connectorhub-logging/func.yaml new file mode 100644 index 00000000..e5dface3 --- /dev/null +++ b/examples/connectorhub-logging/func.yaml @@ -0,0 +1,5 @@ +schema_version: 20180708 +name: connectorhub-logging +version: 0.0.1 +runtime: java +cmd: com.fnproject.fn.examples.Function::handler diff --git a/examples/connectorhub-logging/pom.xml b/examples/connectorhub-logging/pom.xml new file mode 100644 index 00000000..f768c714 --- /dev/null +++ b/examples/connectorhub-logging/pom.xml @@ -0,0 +1,100 @@ + + + + + 4.0.0 + + + UTF-8 + UTF-8 + 1.0.0-SNAPSHOT + 2.16.1 + 4.0.0 + + + com.fnproject.fn.examples + connectorhub-logging + 1.0.0-SNAPSHOT + + + + com.fnproject.fn + api + ${fdk.version} + + + com.fnproject.fn + fn-events + ${fdk.version} + + + com.fnproject.fn + fn-events-testing + ${fdk.version} + test + + + junit + junit + 4.13.2 + test + + + org.mockito + mockito-core + ${mockito.version} + test + + + com.fnproject.fn + testing-core + ${fdk.version} + test + + + com.fnproject.fn + testing-junit4 + ${fdk.version} + test + + + + + + org.apache.maven.plugins + maven-compiler-plugin + 3.8.0 + + 1.8 + 1.8 + + + + org.apache.maven.plugins + maven-deploy-plugin + 2.8.2 + + true + + + + + diff --git a/examples/connectorhub-logging/src/main/java/com/fnproject/fn/examples/Function.java b/examples/connectorhub-logging/src/main/java/com/fnproject/fn/examples/Function.java new file mode 100644 index 00000000..9aa37965 --- /dev/null +++ b/examples/connectorhub-logging/src/main/java/com/fnproject/fn/examples/Function.java @@ -0,0 +1,21 @@ +package com.fnproject.fn.examples; + +import com.fnproject.events.ConnectorHubFunction; +import com.fnproject.events.input.ConnectorHubBatch; +import com.fnproject.events.input.sch.LoggingData; + +public class Function extends ConnectorHubFunction { + + public LogService logService; + + public Function() { + this.logService = new LogService(); + } + + @Override + public void handler(ConnectorHubBatch batch) { + for (LoggingData log : batch.getBatch()) { + logService.readLog(log); + } + } +} \ No newline at end of file diff --git a/examples/connectorhub-logging/src/main/java/com/fnproject/fn/examples/LogService.java b/examples/connectorhub-logging/src/main/java/com/fnproject/fn/examples/LogService.java new file mode 100644 index 00000000..f0145b2c --- /dev/null +++ b/examples/connectorhub-logging/src/main/java/com/fnproject/fn/examples/LogService.java @@ -0,0 +1,19 @@ +package com.fnproject.fn.examples; + + +import com.fnproject.events.input.sch.LoggingData; + +public class LogService { + + public void readLog(LoggingData loggingData) { + System.out.println(loggingData); + assert loggingData != null; + assert loggingData.getData() != null && !loggingData.getData().isEmpty(); + assert loggingData.getId() != null; + assert loggingData.getOracle() != null && !loggingData.getOracle().isEmpty();; + assert loggingData.getSource() != null; + assert loggingData.getSpecversion() != null; + assert loggingData.getTime() != null; + assert loggingData.getType() != null; + } +} diff --git a/examples/connectorhub-logging/src/test/java/com/fnproject/fn/examples/FunctionTest.java b/examples/connectorhub-logging/src/test/java/com/fnproject/fn/examples/FunctionTest.java new file mode 100644 index 00000000..32ab2414 --- /dev/null +++ b/examples/connectorhub-logging/src/test/java/com/fnproject/fn/examples/FunctionTest.java @@ -0,0 +1,71 @@ +package com.fnproject.fn.examples; + +import static org.junit.Assert.assertEquals; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; +import java.util.Collections; +import java.util.Date; +import java.util.HashMap; +import java.util.Map; +import com.fnproject.events.input.ConnectorHubBatch; +import com.fnproject.events.input.sch.Datapoint; +import com.fnproject.events.input.sch.LoggingData; +import com.fnproject.events.input.sch.MetricData; +import com.fnproject.events.testing.ConnectorHubTestFeature; +import com.fnproject.fn.testing.FnResult; +import com.fnproject.fn.testing.FnTestingRule; +import org.junit.Rule; +import org.junit.Test; + +public class FunctionTest { + + @Rule + public FnTestingRule fn = FnTestingRule.createDefault(); + + private final ConnectorHubTestFeature connectorHubTestFeature = ConnectorHubTestFeature.createDefault(fn); + + @Test + public void testInvokeFunctionWithLoggingData() throws Exception { + + ConnectorHubBatch event = createMinimalRequest(); + connectorHubTestFeature.givenEvent(event).enqueue(); + + fn.thenRun(Function.class, "handler"); + + FnResult result = fn.getOnlyResult(); + assertEquals(200, result.getStatus().getCode()); + } + + private static ConnectorHubBatch createMinimalRequest() { + Map data = new HashMap(); + data.put("applicationId", "ocid1.fnapp.oc1.xyz"); + data.put("containerId", "n/a"); + data.put("functionId", "ocid1.fnfunc.oc1.xyz"); + data.put("message", "Received function invocation request"); + data.put("opcRequestId", "/abc/def"); + data.put("requestId", "/def/abc"); + data.put("src", "STDOUT"); + + Map oracle = new HashMap(); + oracle.put("compartmentid", "ocid1.tenancy.oc1.xyz"); + oracle.put("ingestedtime", "2025-10-23T15:45:19.457Z"); + oracle.put("loggroupid", "ocid1.loggroup.oc1.abc"); + oracle.put("logid", "ocid1.log.oc1.abc"); + oracle.put("tenantid", "ocid1.tenancy.oc1.xyz"); + + LoggingData source = new LoggingData( + "ecb37864-4396-4302-9575-981644949730", + "log-name", + "1.0", + "schedule", + "com.oraclecloud.functions.application.functioninvoke", + data, + oracle, + new Date(1764860467553L) + ); + ConnectorHubBatch event = mock(ConnectorHubBatch.class); + + when(event.getBatch()).thenReturn(Collections.singletonList(source)); + return event; + } +} \ No newline at end of file diff --git a/examples/connectorhub-monitoring/README.md b/examples/connectorhub-monitoring/README.md new file mode 100644 index 00000000..b3790435 --- /dev/null +++ b/examples/connectorhub-monitoring/README.md @@ -0,0 +1,95 @@ +# Example Fn Java FDK : Service Connector Hub - Monitoring + +This example provides a Function to use as a service connector hub target. +The function accepts a typed event containing a batch of source events. + +## Source +[MetricData](https://docs.oracle.com/en-us/iaas/Content/connector-hub/create-service-connector-monitoring-source.htm) + +## Dependencies +* [fn-events] for ConnectorHubFunction classes. +* [fn-events-testing] for ConnectorHubFunction testing library. + +## Demonstrated FDK features + +This example showcases how to use the fn-event ConnectorHubFunction to +use a Function as the target for Monitoring source. + +## Step by step + +Set up the connector hub with Monitoring source and Function target: +* [Setup default policies](https://docs.oracle.com/en-us/iaas/Content/connector-hub/overview.htm#Authenti__default-policies) +* [create connector hub](https://docs.oracle.com/en-us/iaas/Content/connector-hub/create-service-connector-monitoring-source.htm) + +The Function entrypoint extends the `ConnectorHubFunction` abstract class. +Note: the [func.yaml](func.yaml) entrypoint remains the class which extends `ConnectorHubFunction` +e.g. `cmd: com.fnproject.fn.examples.Function::handler` + +[Function.java](src/main/java/com/fnproject/fn/examples/Function.java) +```java +package com.fnproject.fn.examples; + +import com.fnproject.events.ConnectorHubFunction; +import com.fnproject.events.input.ConnectorHubBatch; +import com.fnproject.events.input.sch.MetricData; + +public class Function extends ConnectorHubFunction { + + public MetricService metricService; + + public Function() { + this.metricService = new MetricService(); + } + + @Override + public void handler(ConnectorHubBatch batch) { + for (MetricData metric : batch.getBatch()) { + metricService.readMetric(metric); + } + } +} +``` +The [ConnectorHubBatch.java](../../fn-events/src/main/java/com/fnproject/events/input/ConnectorHubBatch.java) +`batch` contains a list of events from Monitoring as +specified in [Batch Settings](https://docs.oracle.com/en-us/iaas/Content/connector-hub/overview.htm#batch-settings). + +The class [MetricData.java](../../fn-events/src/main/java/com/fnproject/events/input/sch/MetricData.java) is +each Monitoring Event [Monitoring Schema](https://docs.oracle.com/en-us/iaas/Content/connector-hub/create-service-connector-monitoring-source.htm) + +[Function.java](src/main/java/com/fnproject/fn/examples/Function.java) +`public class Function extends ConnectorHubFunction {`. + +To return an error response, throw RuntimeException.class. +Doing so will cause the Function to return a 502 [Retry policy](https://docs.oracle.com/en-us/iaas/Content/connector-hub/overview.htm#deactivate) + +## Test walkthrough + +Unit testing `ConnectorHubFunction` is supported with the `ConnectorHubTestFeature` and `FnTestingRule`. + +First of all, the class initializes the `FnTestingRule` harness, as explained +in [Testing Functions](../../docs/TestingFunctions.md). + +[FunctionTest.java](src/test/java/com/fnproject/fn/examples/FunctionTest.java) +```java + + @Rule + public FnTestingRule fn = FnTestingRule.createDefault(); + + private final ConnectorHubTestFeature connectorHubTestFeature = ConnectorHubTestFeature.createDefault(fn); + + @Test + public void testMetricServiceConsumesEachMetric() throws Exception { + + ConnectorHubBatch event = createMinimalRequest(); + connectorHubTestFeature.givenEvent(event).enqueue(); + + fn.thenRun(Function.class, "handler"); + + FnResult result = fn.getOnlyResult(); + assertEquals(200, result.getStatus().getCode()); + } + +``` + +Use `connectorHubTestFeature.givenEvent(event).enqueue();` to queue the request event +and invoke the Function with `fn.thenRun(Function.class, "handler");`. diff --git a/examples/connectorhub-monitoring/func.yaml b/examples/connectorhub-monitoring/func.yaml new file mode 100644 index 00000000..c7b5de2a --- /dev/null +++ b/examples/connectorhub-monitoring/func.yaml @@ -0,0 +1,5 @@ +schema_version: 20180708 +name: connectorhub-monitoring +version: 0.0.1 +runtime: java +cmd: com.fnproject.fn.examples.Function::handler diff --git a/examples/connectorhub-monitoring/pom.xml b/examples/connectorhub-monitoring/pom.xml new file mode 100644 index 00000000..b955ccfa --- /dev/null +++ b/examples/connectorhub-monitoring/pom.xml @@ -0,0 +1,100 @@ + + + + + 4.0.0 + + + UTF-8 + UTF-8 + 1.0.0-SNAPSHOT + 2.16.1 + 4.0.0 + + + com.fnproject.fn.examples + connectorhub-monitoring + 1.0.0-SNAPSHOT + + + + com.fnproject.fn + api + ${fdk.version} + + + com.fnproject.fn + fn-events + ${fdk.version} + + + com.fnproject.fn + fn-events-testing + ${fdk.version} + test + + + junit + junit + 4.13.2 + test + + + org.mockito + mockito-core + ${mockito.version} + test + + + com.fnproject.fn + testing-core + ${fdk.version} + test + + + com.fnproject.fn + testing-junit4 + ${fdk.version} + test + + + + + + org.apache.maven.plugins + maven-compiler-plugin + 3.8.0 + + 1.8 + 1.8 + + + + org.apache.maven.plugins + maven-deploy-plugin + 2.8.2 + + true + + + + + diff --git a/examples/connectorhub-monitoring/src/main/java/com/fnproject/fn/examples/Function.java b/examples/connectorhub-monitoring/src/main/java/com/fnproject/fn/examples/Function.java new file mode 100644 index 00000000..37e86b4a --- /dev/null +++ b/examples/connectorhub-monitoring/src/main/java/com/fnproject/fn/examples/Function.java @@ -0,0 +1,21 @@ +package com.fnproject.fn.examples; + +import com.fnproject.events.ConnectorHubFunction; +import com.fnproject.events.input.ConnectorHubBatch; +import com.fnproject.events.input.sch.MetricData; + +public class Function extends ConnectorHubFunction { + + public MetricService metricService; + + public Function() { + this.metricService = new MetricService(); + } + + @Override + public void handler(ConnectorHubBatch batch) { + for (MetricData metric : batch.getBatch()) { + metricService.readMetric(metric); + } + } +} \ No newline at end of file diff --git a/examples/connectorhub-monitoring/src/main/java/com/fnproject/fn/examples/MetricService.java b/examples/connectorhub-monitoring/src/main/java/com/fnproject/fn/examples/MetricService.java new file mode 100644 index 00000000..c1750638 --- /dev/null +++ b/examples/connectorhub-monitoring/src/main/java/com/fnproject/fn/examples/MetricService.java @@ -0,0 +1,18 @@ +package com.fnproject.fn.examples; + + +import com.fnproject.events.input.sch.MetricData; + +public class MetricService { + + public void readMetric(MetricData metric) { + System.out.println(metric); + assert metric != null; + assert metric.getDatapoints() != null && !metric.getDatapoints().isEmpty(); + assert metric.getCompartmentId() != null; + assert metric.getDimensions() != null && !metric.getDimensions().isEmpty(); + assert metric.getMetadata() != null && !metric.getMetadata().isEmpty(); + assert metric.getName() != null && !metric.getName().isEmpty(); + assert metric.getNamespace() != null; + } +} diff --git a/examples/connectorhub-monitoring/src/test/java/com/fnproject/fn/examples/FunctionTest.java b/examples/connectorhub-monitoring/src/test/java/com/fnproject/fn/examples/FunctionTest.java new file mode 100644 index 00000000..e056f74c --- /dev/null +++ b/examples/connectorhub-monitoring/src/test/java/com/fnproject/fn/examples/FunctionTest.java @@ -0,0 +1,60 @@ +package com.fnproject.fn.examples; + +import static org.junit.Assert.assertEquals; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; +import java.util.Collections; +import java.util.Date; +import java.util.HashMap; +import java.util.Map; +import com.fnproject.events.input.ConnectorHubBatch; +import com.fnproject.events.input.sch.Datapoint; +import com.fnproject.events.input.sch.MetricData; +import com.fnproject.events.testing.ConnectorHubTestFeature; +import com.fnproject.fn.testing.FnResult; +import com.fnproject.fn.testing.FnTestingRule; +import org.junit.Rule; +import org.junit.Test; + +public class FunctionTest { + + @Rule + public FnTestingRule fn = FnTestingRule.createDefault(); + + private final ConnectorHubTestFeature connectorHubTestFeature = ConnectorHubTestFeature.createDefault(fn); + + @Test + public void testInvokeFunctionWithMetricData() throws Exception { + + ConnectorHubBatch event = createMinimalRequest(); + connectorHubTestFeature.givenEvent(event).enqueue(); + + fn.thenRun(Function.class, "handler"); + + FnResult result = fn.getOnlyResult(); + assertEquals(200, result.getStatus().getCode()); + } + + private static ConnectorHubBatch createMinimalRequest() { + Map dimensions = new HashMap<>(); + dimensions.put("resourceID", "ocid1.bucket.oc1.xyz"); + dimensions.put("resourceDisplayName", "userName"); + Map metadata = new HashMap<>(); + metadata.put("displayName", "PutObject Request Count"); + metadata.put("unit", "count"); + + MetricData source = new MetricData( + "oci_objectstorage", + "unknown", + "ocid1.tenancy.oc1..xyz", + "PutRequests", + dimensions, + metadata, + Collections.singletonList(new Datapoint(new Date(1764860467553L), Double.parseDouble("12.3"), null)) + ); + ConnectorHubBatch event = mock(ConnectorHubBatch.class); + + when(event.getBatch()).thenReturn(Collections.singletonList(source)); + return event; + } +} \ No newline at end of file diff --git a/examples/connectorhub-queue/README.md b/examples/connectorhub-queue/README.md new file mode 100644 index 00000000..215eff2c --- /dev/null +++ b/examples/connectorhub-queue/README.md @@ -0,0 +1,124 @@ +# Example Fn Java FDK : Service Connector Hub - Queue + +This example provides a Function to use as a service connector hub target. +The function accepts a typed event containing a batch of source messages. + +## Source +[LoggingData.java](../../fn-events/src/main/java/com/fnproject/events/input/sch/LoggingData.java) + +## Dependencies +* [fn-events] for ConnectorHubFunction classes. +* [fn-events-testing] for ConnectorHubFunction testing library. + +## Demonstrated FDK features + +This example showcases how to use the fn-event ConnectorHubFunction to +use a Function as the target for Queue source. + +## Step by step + +Set up the connector hub with Logging source and Function target: +* [Setup default policies](https://docs.oracle.com/en-us/iaas/Content/connector-hub/overview.htm#Authenti__default-policies) +* [create connector hub](https://docs.oracle.com/en-us/iaas/Content/connector-hub/create-service-connector-queue-source.htm) + +The Function entrypoint extends the `ConnectorHubFunction` abstract class. +Note: the [func.yaml](func.yaml) entrypoint remains the class which extends `ConnectorHubFunction` +e.g. `cmd: com.fnproject.fn.examples.Function::handler` + +[Function.java](src/main/java/com/fnproject/fn/examples/Function.java) + +```java +package com.fnproject.fn.examples; + +import com.fnproject.events.ConnectorHubFunction; +import com.fnproject.events.input.ConnectorHubBatch; + +public class Function extends ConnectorHubFunction { + + public QueueService queueService; + + public Function() { + this.queueService = new QueueService(); + } + + @Override + public void handler(ConnectorHubBatch batch) { + for (Employee employee : batch.getBatch()) { + queueService.readContent(employee); + } + } +} +``` +The [ConnectorHubBatch.java](../../fn-events/src/main/java/com/fnproject/events/input/ConnectorHubBatch.java) +`batch` contains a list of messages from Queue as +specified in [Batch Settings](https://docs.oracle.com/en-us/iaas/Content/connector-hub/overview.htm#batch-settings). + +The class [Employee.java](src/main/java/com/fnproject/fn/examples/Employee.java) is +a representation of messages received from the Queue. + +Note the messages sent in to the Queue must be a valid String because Connector Hub forwards the message directly to +the Function target. +- wrong: a plain string +- correct: "a plain string" + +[Function.java](src/main/java/com/fnproject/fn/examples/Function.java) +`public class Function extends ConnectorHubFunction`. + +To return an error response, throw RuntimeException.class. +Doing so will cause the Function to return a 502 [Retry policy](https://docs.oracle.com/en-us/iaas/Content/connector-hub/overview.htm#deactivate) + +## Test walkthrough + +Unit testing `ConnectorHubFunction` is supported with the `ConnectorHubTestFeature` and `FnTestingRule`. + +First of all, the class initializes the `FnTestingRule` harness, as explained +in [Testing Functions](../../docs/TestingFunctions.md). + +[FunctionTest.java](src/test/java/com/fnproject/fn/examples/FunctionTest.java) +```java +package com.fnproject.fn.examples; + +import static org.junit.Assert.assertEquals; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; +import java.util.Collections; +import com.fnproject.events.input.ConnectorHubBatch; +import com.fnproject.events.testing.ConnectorHubTestFeature; +import com.fnproject.fn.testing.FnResult; +import com.fnproject.fn.testing.FnTestingRule; +import org.junit.Rule; +import org.junit.Test; + +public class FunctionTest { + + @Rule + public FnTestingRule fn = FnTestingRule.createDefault(); + + private final ConnectorHubTestFeature connectorHubTestFeature = ConnectorHubTestFeature.createDefault(fn); + + @Test + public void testInvokeFunctionWithLoggingData() throws Exception { + + ConnectorHubBatch event = createMinimalRequest(); + connectorHubTestFeature.givenEvent(event).enqueue(); + + fn.thenRun(Function.class, "handler"); + + FnResult result = fn.getOnlyResult(); + assertEquals(200, result.getStatus().getCode()); + } + + private static ConnectorHubBatch createMinimalRequest() { + Employee employee = new Employee(); + employee.setName("foo"); + + ConnectorHubBatch event = mock(ConnectorHubBatch.class); + + when(event.getBatch()).thenReturn(Collections.singletonList(employee)); + return event; + } +} +``` + +Use `connectorHubTestFeature.givenEvent(event).enqueue();` to queue the request event +and invoke the Function with `fn.thenRun(Function.class, "handler");`. diff --git a/examples/connectorhub-queue/func.yaml b/examples/connectorhub-queue/func.yaml new file mode 100644 index 00000000..6cef20c6 --- /dev/null +++ b/examples/connectorhub-queue/func.yaml @@ -0,0 +1,5 @@ +schema_version: 20180708 +name: connectorhub-queue +version: 0.0.1 +runtime: java +cmd: com.fnproject.fn.examples.Function::handler diff --git a/examples/connectorhub-queue/pom.xml b/examples/connectorhub-queue/pom.xml new file mode 100644 index 00000000..7f29999c --- /dev/null +++ b/examples/connectorhub-queue/pom.xml @@ -0,0 +1,100 @@ + + + + + 4.0.0 + + + UTF-8 + UTF-8 + 1.0.0-SNAPSHOT + 2.16.1 + 4.0.0 + + + com.fnproject.fn.examples + connectorhub-queue + 1.0.0-SNAPSHOT + + + + com.fnproject.fn + api + ${fdk.version} + + + com.fnproject.fn + fn-events + ${fdk.version} + + + com.fnproject.fn + fn-events-testing + ${fdk.version} + test + + + junit + junit + 4.13.2 + test + + + org.mockito + mockito-core + ${mockito.version} + test + + + com.fnproject.fn + testing-core + ${fdk.version} + test + + + com.fnproject.fn + testing-junit4 + ${fdk.version} + test + + + + + + org.apache.maven.plugins + maven-compiler-plugin + 3.8.0 + + 1.8 + 1.8 + + + + org.apache.maven.plugins + maven-deploy-plugin + 2.8.2 + + true + + + + + diff --git a/examples/connectorhub-queue/src/main/java/com/fnproject/fn/examples/Employee.java b/examples/connectorhub-queue/src/main/java/com/fnproject/fn/examples/Employee.java new file mode 100644 index 00000000..21079ea8 --- /dev/null +++ b/examples/connectorhub-queue/src/main/java/com/fnproject/fn/examples/Employee.java @@ -0,0 +1,41 @@ +package com.fnproject.fn.examples; + +import java.util.Objects; + +public class Employee { + private String name; + + public Employee() {} + + public String getName() { + return this.name; + } + + public void setName(String name) { + this.name = name; + } + + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } + Employee employee = (Employee) o; + return Objects.equals(name, employee.name); + } + + @Override + public int hashCode() { + return Objects.hashCode(name); + } + + @Override + public String toString() { + return "Employee{" + + "name='" + name + '\'' + + '}'; + } +} diff --git a/examples/connectorhub-queue/src/main/java/com/fnproject/fn/examples/Function.java b/examples/connectorhub-queue/src/main/java/com/fnproject/fn/examples/Function.java new file mode 100644 index 00000000..79423d49 --- /dev/null +++ b/examples/connectorhub-queue/src/main/java/com/fnproject/fn/examples/Function.java @@ -0,0 +1,20 @@ +package com.fnproject.fn.examples; + +import com.fnproject.events.ConnectorHubFunction; +import com.fnproject.events.input.ConnectorHubBatch; + +public class Function extends ConnectorHubFunction { + + public QueueService queueService; + + public Function() { + this.queueService = new QueueService(); + } + + @Override + public void handler(ConnectorHubBatch batch) { + for (Employee employee : batch.getBatch()) { + queueService.readContent(employee); + } + } +} \ No newline at end of file diff --git a/examples/connectorhub-queue/src/main/java/com/fnproject/fn/examples/QueueService.java b/examples/connectorhub-queue/src/main/java/com/fnproject/fn/examples/QueueService.java new file mode 100644 index 00000000..748360aa --- /dev/null +++ b/examples/connectorhub-queue/src/main/java/com/fnproject/fn/examples/QueueService.java @@ -0,0 +1,10 @@ +package com.fnproject.fn.examples; + + +public class QueueService { + + public void readContent(Employee employee) { + System.out.println(employee); + assert employee != null; + } +} diff --git a/examples/connectorhub-queue/src/test/java/com/fnproject/fn/examples/FunctionTest.java b/examples/connectorhub-queue/src/test/java/com/fnproject/fn/examples/FunctionTest.java new file mode 100644 index 00000000..8f0324a5 --- /dev/null +++ b/examples/connectorhub-queue/src/test/java/com/fnproject/fn/examples/FunctionTest.java @@ -0,0 +1,42 @@ +package com.fnproject.fn.examples; + +import static org.junit.Assert.assertEquals; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; +import java.util.Collections; +import com.fnproject.events.input.ConnectorHubBatch; +import com.fnproject.events.testing.ConnectorHubTestFeature; +import com.fnproject.fn.testing.FnResult; +import com.fnproject.fn.testing.FnTestingRule; +import org.junit.Rule; +import org.junit.Test; + +public class FunctionTest { + + @Rule + public FnTestingRule fn = FnTestingRule.createDefault(); + + private final ConnectorHubTestFeature connectorHubTestFeature = ConnectorHubTestFeature.createDefault(fn); + + @Test + public void testInvokeFunctionWithQueueData() throws Exception { + + ConnectorHubBatch event = createMinimalRequest(); + connectorHubTestFeature.givenEvent(event).enqueue(); + + fn.thenRun(Function.class, "handler"); + + FnResult result = fn.getOnlyResult(); + assertEquals(200, result.getStatus().getCode()); + } + + private static ConnectorHubBatch createMinimalRequest() { + Employee employee = new Employee(); + employee.setName("foo"); + + ConnectorHubBatch event = mock(ConnectorHubBatch.class); + + when(event.getBatch()).thenReturn(Collections.singletonList(employee)); + return event; + } +} \ No newline at end of file diff --git a/examples/connectorhub-streaming/README.md b/examples/connectorhub-streaming/README.md new file mode 100644 index 00000000..89361024 --- /dev/null +++ b/examples/connectorhub-streaming/README.md @@ -0,0 +1,133 @@ +# Example Fn Java FDK : Service Connector Hub - Streaming + +This example provides a Function to use as a service connector hub target. +The function accepts a typed event containing a batch of messages. + +## Source +[Streaming](https://docs.oracle.com/en-us/iaas/api/#/en/streaming/20180418/Message) +The value in each streaming event is delivered as base64 encoded. The library automatically decodes it. + +## Dependencies +* [fn-events] for ConnectorHubFunction classes. +* [fn-events-testing] for ConnectorHubFunction testing library. + +## Demonstrated FDK features + +This example showcases how to use the fn-event ConnectorHubFunction to +use a Function as the target for Streaming source. + +## Step by step + +Set up the connector hub with Streaming source and Function target: +* [Setup default policies](https://docs.oracle.com/en-us/iaas/Content/connector-hub/overview.htm#Authenti__default-policies) +* [create connector hub](https://docs.oracle.com/en-us/iaas/Content/connector-hub/create-service-connector-streaming-source.htm) + +The Function entrypoint extends the `ConnectorHubFunction` abstract class. +Note: the [func.yaml](func.yaml) entrypoint remains the class which extends `ConnectorHubFunction` +e.g. `cmd: com.fnproject.fn.examples.Function::handler` + +[Function.java](src/main/java/com/fnproject/fn/examples/Function.java) + +```java +package com.fnproject.fn.examples; + +import com.fnproject.events.ConnectorHubFunction; +import com.fnproject.events.input.ConnectorHubBatch; +import com.fnproject.events.input.sch.StreamingData; + +public class Function extends ConnectorHubFunction> { + + public StreamService streamService; + + public Function() { + this.streamService = new StreamService(); + } + + @Override + public void handler(ConnectorHubBatch> batch) { + for (StreamingData stream : batch.getBatch()) { + streamService.readStream(stream); + } + } +} +``` +The [ConnectorHubBatch.java](../../fn-events/src/main/java/com/fnproject/events/input/ConnectorHubBatch.java) +`batch` contains a list of events from Streaming as +specified in [Batch Settings](https://docs.oracle.com/en-us/iaas/Content/connector-hub/overview.htm#batch-settings). + +The class [StreamingData.java](../../fn-events/src/main/java/com/fnproject/events/input/sch/StreamingData.java) +represents the batch of Streaming Events. + +The [Employee.java](src/main/java/com/fnproject/fn/examples/Employee.java) represents the base64 encoded JSON +from value in each message. Note: Provide a String type if the message value is not JSON format. + +[Function.java](src/main/java/com/fnproject/fn/examples/Function.java) +`public class Function extends ConnectorHubFunction>`. + +To return an error response, throw RuntimeException.class. +Doing so will cause the Function to return a 502 [Retry policy](https://docs.oracle.com/en-us/iaas/Content/connector-hub/overview.htm#deactivate) + +## Test walkthrough + +Unit testing `ConnectorHubFunction` is supported with the `ConnectorHubTestFeature` and `FnTestingRule`. + +First of all, the class initializes the `FnTestingRule` harness, as explained +in [Testing Functions](../../docs/TestingFunctions.md). + +[FunctionTest.java](src/test/java/com/fnproject/fn/examples/FunctionTest.java) +```java +import static org.junit.Assert.assertEquals; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; +import java.util.Collections; +import java.util.Date; +import com.fasterxml.jackson.core.JsonProcessingException; +import com.fnproject.events.input.ConnectorHubBatch; +import com.fnproject.events.input.sch.StreamingData; +import com.fnproject.events.testing.ConnectorHubTestFeature; +import com.fnproject.fn.testing.FnResult; +import com.fnproject.fn.testing.FnTestingRule; +import org.junit.Rule; +import org.junit.Test; + +public class FunctionTest { + + @Rule + public FnTestingRule fn = FnTestingRule.createDefault(); + + private final ConnectorHubTestFeature connectorHubTestFeature = ConnectorHubTestFeature.createDefault(fn); + + @Test + public void testInvokeFunctionWithStreamingData() throws Exception { + + ConnectorHubBatch> event = createMinimalRequest(); + connectorHubTestFeature.givenEvent(event).enqueue(); + + fn.thenRun(Function.class, "handler"); + + FnResult result = fn.getOnlyResult(); + assertEquals(200, result.getStatus().getCode()); + } + + private static ConnectorHubBatch> createMinimalRequest() throws JsonProcessingException { + Employee employee = new Employee(); + employee.setName("foo"); + + StreamingData source = new StreamingData( + "stream-name", + "0", + null, + employee, + "3", + new Date(1764860467553L) + ); + ConnectorHubBatch> event = mock(ConnectorHubBatch.class); + + when(event.getBatch()).thenReturn(Collections.singletonList(source)); + return event; + } +} +``` + +Use `connectorHubTestFeature.givenEvent(event).enqueue();` to queue the request event +and invoke the Function with `fn.thenRun(Function.class, "handler");`. diff --git a/examples/connectorhub-streaming/func.yaml b/examples/connectorhub-streaming/func.yaml new file mode 100644 index 00000000..2b7cd061 --- /dev/null +++ b/examples/connectorhub-streaming/func.yaml @@ -0,0 +1,5 @@ +schema_version: 20180708 +name: connectorhub-streaming +version: 0.0.1 +runtime: java +cmd: com.fnproject.fn.examples.Function::handler diff --git a/examples/connectorhub-streaming/pom.xml b/examples/connectorhub-streaming/pom.xml new file mode 100644 index 00000000..afc256c8 --- /dev/null +++ b/examples/connectorhub-streaming/pom.xml @@ -0,0 +1,100 @@ + + + + + 4.0.0 + + + UTF-8 + UTF-8 + 1.0.0-SNAPSHOT + 2.16.1 + 4.0.0 + + + com.fnproject.fn.examples + connectorhub-streaming + 1.0.0-SNAPSHOT + + + + com.fnproject.fn + api + ${fdk.version} + + + com.fnproject.fn + fn-events + ${fdk.version} + + + com.fnproject.fn + fn-events-testing + ${fdk.version} + test + + + junit + junit + 4.13.2 + test + + + org.mockito + mockito-core + ${mockito.version} + test + + + com.fnproject.fn + testing-core + ${fdk.version} + test + + + com.fnproject.fn + testing-junit4 + ${fdk.version} + test + + + + + + org.apache.maven.plugins + maven-compiler-plugin + 3.8.0 + + 1.8 + 1.8 + + + + org.apache.maven.plugins + maven-deploy-plugin + 2.8.2 + + true + + + + + diff --git a/examples/connectorhub-streaming/src/main/java/com/fnproject/fn/examples/Employee.java b/examples/connectorhub-streaming/src/main/java/com/fnproject/fn/examples/Employee.java new file mode 100644 index 00000000..21079ea8 --- /dev/null +++ b/examples/connectorhub-streaming/src/main/java/com/fnproject/fn/examples/Employee.java @@ -0,0 +1,41 @@ +package com.fnproject.fn.examples; + +import java.util.Objects; + +public class Employee { + private String name; + + public Employee() {} + + public String getName() { + return this.name; + } + + public void setName(String name) { + this.name = name; + } + + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } + Employee employee = (Employee) o; + return Objects.equals(name, employee.name); + } + + @Override + public int hashCode() { + return Objects.hashCode(name); + } + + @Override + public String toString() { + return "Employee{" + + "name='" + name + '\'' + + '}'; + } +} diff --git a/examples/connectorhub-streaming/src/main/java/com/fnproject/fn/examples/Function.java b/examples/connectorhub-streaming/src/main/java/com/fnproject/fn/examples/Function.java new file mode 100644 index 00000000..0b7b8fbd --- /dev/null +++ b/examples/connectorhub-streaming/src/main/java/com/fnproject/fn/examples/Function.java @@ -0,0 +1,21 @@ +package com.fnproject.fn.examples; + +import com.fnproject.events.ConnectorHubFunction; +import com.fnproject.events.input.ConnectorHubBatch; +import com.fnproject.events.input.sch.StreamingData; + +public class Function extends ConnectorHubFunction> { + + public StreamService streamService; + + public Function() { + this.streamService = new StreamService(); + } + + @Override + public void handler(ConnectorHubBatch> batch) { + for (StreamingData stream : batch.getBatch()) { + streamService.readStream(stream); + } + } +} \ No newline at end of file diff --git a/examples/connectorhub-streaming/src/main/java/com/fnproject/fn/examples/StreamService.java b/examples/connectorhub-streaming/src/main/java/com/fnproject/fn/examples/StreamService.java new file mode 100644 index 00000000..c6870ac0 --- /dev/null +++ b/examples/connectorhub-streaming/src/main/java/com/fnproject/fn/examples/StreamService.java @@ -0,0 +1,19 @@ +package com.fnproject.fn.examples; + +import com.fnproject.events.input.sch.StreamingData; + +public class StreamService { + + public void readStream(StreamingData streamingData) { + System.out.println(streamingData); + assert streamingData != null; + assert streamingData.getStream() != null; + assert streamingData.getPartition() != null; + assert streamingData.getValue() != null; + assert streamingData.getOffset() != null; + assert streamingData.getTimestamp() != null; + + Employee employee = streamingData.getValue(); + System.out.println(employee); + } +} diff --git a/examples/connectorhub-streaming/src/test/java/com/fnproject/fn/examples/FunctionTest.java b/examples/connectorhub-streaming/src/test/java/com/fnproject/fn/examples/FunctionTest.java new file mode 100644 index 00000000..bce8a569 --- /dev/null +++ b/examples/connectorhub-streaming/src/test/java/com/fnproject/fn/examples/FunctionTest.java @@ -0,0 +1,53 @@ +package com.fnproject.fn.examples; + +import static org.junit.Assert.assertEquals; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; +import java.util.Collections; +import java.util.Date; +import com.fasterxml.jackson.core.JsonProcessingException; +import com.fnproject.events.input.ConnectorHubBatch; +import com.fnproject.events.input.sch.StreamingData; +import com.fnproject.events.testing.ConnectorHubTestFeature; +import com.fnproject.fn.testing.FnResult; +import com.fnproject.fn.testing.FnTestingRule; +import org.junit.Rule; +import org.junit.Test; + +public class FunctionTest { + + @Rule + public FnTestingRule fn = FnTestingRule.createDefault(); + + private final ConnectorHubTestFeature connectorHubTestFeature = ConnectorHubTestFeature.createDefault(fn); + + @Test + public void testInvokeFunctionWithStreamingData() throws Exception { + + ConnectorHubBatch> event = createMinimalRequest(); + connectorHubTestFeature.givenEvent(event).enqueue(); + + fn.thenRun(Function.class, "handler"); + + FnResult result = fn.getOnlyResult(); + assertEquals(200, result.getStatus().getCode()); + } + + private static ConnectorHubBatch> createMinimalRequest() { + Employee employee = new Employee(); + employee.setName("foo"); + + StreamingData source = new StreamingData<>( + "stream-name", + "0", + null, + employee, + "3", + new Date(1764860467553L) + ); + ConnectorHubBatch> event = mock(ConnectorHubBatch.class); + + when(event.getBatch()).thenReturn(Collections.singletonList(source)); + return event; + } +} \ No newline at end of file diff --git a/examples/notifications/README.md b/examples/notifications/README.md new file mode 100644 index 00000000..2966b991 --- /dev/null +++ b/examples/notifications/README.md @@ -0,0 +1,116 @@ +# Example Fn Java FDK : Notifications + +This example provides a Function to consume a Notification. +The function accepts a typed message event. + +## Source + +* Notifications appends metadata to the headers [Standard header metadata](https://docs.oracle.com/en-us/iaas/Content/Notification/Concepts/notificationoverview.htm#hownw) +* The Notification message body is a user specified Schema or String. +Note: This library currently supports JSON and String types. +* Limits for Notifications [Notification limits](https://docs.oracle.com/en-us/iaas/Content/Notification/Concepts/notificationoverview.htm#limits) + +## Dependencies +* [fn-events](../../fn-events) for NotificationFunction classes. +* [fn-events-testing](../../fn-events-testing) for NotificationFunction testing library. + +## Demonstrated FDK features + +This example showcases how to use the fn-event NotificationFunction to +use a Function to consume messages from a Notification topic. + +## Step by step + +Set up the Notification Topic with Function Subscription: +* [Setup default policies](https://docs.oracle.com/en-us/iaas/Content/Security/Reference/notifications_security.htm#iam-policies__subs) +* [create subscription function](https://docs.oracle.com/en-us/iaas/Content/Notification/Tasks/create-subscription-function.htm) + +The Function entrypoint extends the `NotificationFunction` abstract class. +Note: the [func.yaml](func.yaml) entrypoint remains the class which extends `NotificationFunction` +e.g. `cmd: com.fnproject.fn.examples.Function::handler` + +[Function.java](src/main/java/com/fnproject/fn/examples/Function.java) + +```java +package com.fnproject.fn.examples; + +import com.fnproject.events.NotificationFunction; +import com.fnproject.events.input.NotificationMessage; + +public class Function extends NotificationFunction { + + public NotificationService notificationService; + + public Function() { + this.notificationService = new NotificationService(); + } + + @Override + public void handler(NotificationMessage content) { + notificationService.readNotification(content); + } +} +``` +The [NotificationMessage.java](../../fn-events/src/main/java/com/fnproject/events/input/NotificationMessage.java) +`content` contains the message body. + +The class [Employee.java](src/main/java/com/fnproject/fn/examples/Employee.java) is +the schema for the message content. + +[Function.java](src/main/java/com/fnproject/fn/examples/Function.java) +`public class Function extends NotificationFunction`. + +To return an error response, throw RuntimeException.class. +Doing so will cause the Function to return a 502 [Retry policy](https://docs.oracle.com/en-us/iaas/Content/connector-hub/overview.htm#deactivate) + +## Test walkthrough + +Unit testing `NotificationFunction` is supported with the `NotificationTestFeature` and `FnTestingRule`. + +First of all, the class initializes the `FnTestingRule` harness, as explained +in [Testing Functions](../../docs/TestingFunctions.md). + +[FunctionTest.java](src/test/java/com/fnproject/fn/examples/FunctionTest.java) +```java +package com.fnproject.fn.examples; + +import static org.junit.Assert.assertEquals; +import com.fnproject.events.input.NotificationMessage; +import com.fnproject.events.testing.NotificationTestFeature; +import com.fnproject.fn.api.Headers; +import com.fnproject.fn.testing.FnResult; +import com.fnproject.fn.testing.FnTestingRule; +import org.junit.Rule; +import org.junit.Test; + +public class FunctionTest { + + @Rule + public FnTestingRule fn = FnTestingRule.createDefault(); + + private final NotificationTestFeature connectorHubTestFeature = NotificationTestFeature.createDefault(fn); + + @Test + public void testInvokeFunctionWithLoggingData() throws Exception { + NotificationMessage event = createMinimalRequest(); + connectorHubTestFeature.givenEvent(event).enqueue(); + + fn.thenRun(Function.class, "handler"); + + FnResult result = fn.getOnlyResult(); + assertEquals(200, result.getStatus().getCode()); + } + + private static NotificationMessage createMinimalRequest() { + Employee employee = new Employee(); + employee.setName("foo"); + + return new NotificationMessage<>(employee, Headers.emptyHeaders()); + } +} +``` + +Use `connectorHubTestFeature.givenEvent(event).enqueue();` to queue the request event +and invoke the Function with `fn.thenRun(Function.class, "handler");`. + +To verify the Subscription is working, check [Notification metrics](https://docs.oracle.com/en-us/iaas/Content/Notification/Tasks/view-chart-resource.htm#top) \ No newline at end of file diff --git a/examples/notifications/func.yaml b/examples/notifications/func.yaml new file mode 100644 index 00000000..e065909d --- /dev/null +++ b/examples/notifications/func.yaml @@ -0,0 +1,5 @@ +schema_version: 20180708 +name: notifications +version: 0.0.1 +runtime: java +cmd: com.fnproject.fn.examples.Function::handler diff --git a/examples/notifications/pom.xml b/examples/notifications/pom.xml new file mode 100644 index 00000000..e470aa39 --- /dev/null +++ b/examples/notifications/pom.xml @@ -0,0 +1,112 @@ + + + + + 4.0.0 + + + UTF-8 + UTF-8 + 1.0.0-SNAPSHOT + 2.16.1 + 4.0.0 + + + com.fnproject.fn.examples + notifications + 1.0.0-SNAPSHOT + + + + com.fnproject.fn + api + ${fdk.version} + + + com.fnproject.fn + fn-events + ${fdk.version} + + + com.fnproject.fn + fn-events-testing + ${fdk.version} + test + + + junit + junit + 4.13.2 + test + + + org.mockito + mockito-core + ${mockito.version} + test + + + com.fnproject.fn + testing-core + ${fdk.version} + test + + + com.fnproject.fn + testing-junit4 + ${fdk.version} + test + + + + + faas-release-maven-local + https://artifactory-builds.oci.oraclecorp.com/faas-release-maven-local + + true + + + true + + + + + + + org.apache.maven.plugins + maven-compiler-plugin + 3.8.0 + + 1.8 + 1.8 + + + + org.apache.maven.plugins + maven-deploy-plugin + 2.8.2 + + true + + + + + diff --git a/examples/notifications/src/main/java/com/fnproject/fn/examples/Employee.java b/examples/notifications/src/main/java/com/fnproject/fn/examples/Employee.java new file mode 100644 index 00000000..21079ea8 --- /dev/null +++ b/examples/notifications/src/main/java/com/fnproject/fn/examples/Employee.java @@ -0,0 +1,41 @@ +package com.fnproject.fn.examples; + +import java.util.Objects; + +public class Employee { + private String name; + + public Employee() {} + + public String getName() { + return this.name; + } + + public void setName(String name) { + this.name = name; + } + + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } + Employee employee = (Employee) o; + return Objects.equals(name, employee.name); + } + + @Override + public int hashCode() { + return Objects.hashCode(name); + } + + @Override + public String toString() { + return "Employee{" + + "name='" + name + '\'' + + '}'; + } +} diff --git a/examples/notifications/src/main/java/com/fnproject/fn/examples/Function.java b/examples/notifications/src/main/java/com/fnproject/fn/examples/Function.java new file mode 100644 index 00000000..923c650c --- /dev/null +++ b/examples/notifications/src/main/java/com/fnproject/fn/examples/Function.java @@ -0,0 +1,18 @@ +package com.fnproject.fn.examples; + +import com.fnproject.events.NotificationFunction; +import com.fnproject.events.input.NotificationMessage; + +public class Function extends NotificationFunction { + + public NotificationService notificationService; + + public Function() { + this.notificationService = new NotificationService(); + } + + @Override + public void handler(NotificationMessage content) { + notificationService.readNotification(content); + } +} \ No newline at end of file diff --git a/examples/notifications/src/main/java/com/fnproject/fn/examples/NotificationService.java b/examples/notifications/src/main/java/com/fnproject/fn/examples/NotificationService.java new file mode 100644 index 00000000..3e1ed461 --- /dev/null +++ b/examples/notifications/src/main/java/com/fnproject/fn/examples/NotificationService.java @@ -0,0 +1,10 @@ +package com.fnproject.fn.examples; + +import com.fnproject.events.input.NotificationMessage; + +public class NotificationService { + + public void readNotification(NotificationMessage notification) { + System.out.println(notification); + } +} diff --git a/examples/notifications/src/test/java/com/fnproject/fn/examples/FunctionTest.java b/examples/notifications/src/test/java/com/fnproject/fn/examples/FunctionTest.java new file mode 100644 index 00000000..3afca9e1 --- /dev/null +++ b/examples/notifications/src/test/java/com/fnproject/fn/examples/FunctionTest.java @@ -0,0 +1,36 @@ +package com.fnproject.fn.examples; + +import static org.junit.Assert.assertEquals; +import com.fnproject.events.input.NotificationMessage; +import com.fnproject.events.testing.NotificationTestFeature; +import com.fnproject.fn.api.Headers; +import com.fnproject.fn.testing.FnResult; +import com.fnproject.fn.testing.FnTestingRule; +import org.junit.Rule; +import org.junit.Test; + +public class FunctionTest { + + @Rule + public FnTestingRule fn = FnTestingRule.createDefault(); + + private final NotificationTestFeature connectorHubTestFeature = NotificationTestFeature.createDefault(fn); + + @Test + public void testInvokeFunctionWithLoggingData() throws Exception { + NotificationMessage event = createMinimalRequest(); + connectorHubTestFeature.givenEvent(event).enqueue(); + + fn.thenRun(Function.class, "handler"); + + FnResult result = fn.getOnlyResult(); + assertEquals(200, result.getStatus().getCode()); + } + + private static NotificationMessage createMinimalRequest() { + Employee employee = new Employee(); + employee.setName("foo"); + + return new NotificationMessage<>(employee, Headers.emptyHeaders()); + } +} \ No newline at end of file diff --git a/examples/pom.xml b/examples/pom.xml index c9d9be30..34a63435 100644 --- a/examples/pom.xml +++ b/examples/pom.xml @@ -39,6 +39,12 @@ qr-code --> async-thumbnails + apigateway-event + connectorhub-monitoring + connectorhub-logging + connectorhub-streaming + connectorhub-queue + notifications diff --git a/pom.xml b/pom.xml index 158d0e9b..99f454cf 100644 --- a/pom.xml +++ b/pom.xml @@ -73,6 +73,8 @@ flow-runtime flow-testing fn-spring-cloud-function + fn-events + fn-events-testing examples experimental-native-image-support @@ -117,6 +119,11 @@ flow-runtime ${project.version} + + com.fnproject.fn + fn-events + ${project.version} + com.fnproject.fn runtime diff --git a/release.version b/release.version index 4de9573d..45a1b3f4 100644 --- a/release.version +++ b/release.version @@ -1 +1 @@ -1.0.218 +1.1.2 diff --git a/runtime/src/main/java/com/fnproject/fn/runtime/DefaultFunctionInvocationContext.java b/runtime/src/main/java/com/fnproject/fn/runtime/DefaultFunctionInvocationContext.java new file mode 100644 index 00000000..2ca86f5b --- /dev/null +++ b/runtime/src/main/java/com/fnproject/fn/runtime/DefaultFunctionInvocationContext.java @@ -0,0 +1,15 @@ +package com.fnproject.fn.runtime; + +import java.util.List; +import java.util.Map; +import com.fnproject.fn.api.InputEvent; + +public class DefaultFunctionInvocationContext extends FunctionInvocationContext { + public DefaultFunctionInvocationContext(FunctionRuntimeContext ctx, InputEvent event) { + super(ctx, event); + } + + public Map> getAdditionalResponseHeaders() { + return super.getAdditionalResponseHeaders(); + } +} diff --git a/runtime/src/main/java/com/fnproject/fn/runtime/DefaultMethodWrapper.java b/runtime/src/main/java/com/fnproject/fn/runtime/DefaultMethodWrapper.java index 4a5a7e41..0858ce95 100644 --- a/runtime/src/main/java/com/fnproject/fn/runtime/DefaultMethodWrapper.java +++ b/runtime/src/main/java/com/fnproject/fn/runtime/DefaultMethodWrapper.java @@ -30,12 +30,12 @@ public class DefaultMethodWrapper implements MethodWrapper { private final Class srcClass; private final Method srcMethod; - DefaultMethodWrapper(Class srcClass, Method srcMethod) { + public DefaultMethodWrapper(Class srcClass, Method srcMethod) { this.srcClass = srcClass; this.srcMethod = srcMethod; } - DefaultMethodWrapper(Class srcClass, String srcMethod) { + public DefaultMethodWrapper(Class srcClass, String srcMethod) { this(srcClass, Arrays.stream(srcClass.getMethods()) .filter((m) -> m.getName().equals(srcMethod)) .findFirst() diff --git a/runtime/src/main/java/com/fnproject/fn/runtime/httpgateway/FunctionHTTPGatewayContext.java b/runtime/src/main/java/com/fnproject/fn/runtime/httpgateway/FunctionHTTPGatewayContext.java index e3a259dc..32c22611 100644 --- a/runtime/src/main/java/com/fnproject/fn/runtime/httpgateway/FunctionHTTPGatewayContext.java +++ b/runtime/src/main/java/com/fnproject/fn/runtime/httpgateway/FunctionHTTPGatewayContext.java @@ -102,6 +102,16 @@ public void addResponseHeader(String key, String value) { } + public void addResponseHeader(String key, List values) { + if (values == null || values.isEmpty()) { + setResponseHeader(key, null); + } else { + for (String value : values) { + addResponseHeader(key, value); + } + } + } + @Override public void setResponseHeader(String key, String value, String... vs) { diff --git a/testing-junit4/src/main/java/com/fnproject/fn/testing/FnTestingRule.java b/testing-junit4/src/main/java/com/fnproject/fn/testing/FnTestingRule.java index e8246ef5..55f65fc0 100644 --- a/testing-junit4/src/main/java/com/fnproject/fn/testing/FnTestingRule.java +++ b/testing-junit4/src/main/java/com/fnproject/fn/testing/FnTestingRule.java @@ -167,6 +167,10 @@ public void addFeature(FnTestingRuleFeature f) { this.features.add(f); } + public void addInput(InputEvent input) { + pendingInput.add(input); + } + /** * Create an instance of the testing {@link Rule}, with Flows support * From 6275fbbe73c167c221e8be5ab4b838c68966ea5e Mon Sep 17 00:00:00 2001 From: CI Date: Thu, 18 Dec 2025 10:30:30 +0000 Subject: [PATCH 303/310] Releasing version 1.1.2 --- fn-events-testing/README.md | 22 + fn-events-testing/pom.xml | 87 ++++ .../events/testing/APIGatewayTestFeature.java | 192 +++++++++ .../testing/ConnectorHubTestFeature.java | 115 +++++ .../testing/NotificationTestFeature.java | 116 +++++ .../testing/APIGatewayTestFeatureTest.java | 171 ++++++++ .../com/fnproject/events/testing/Animal.java | 50 +++ .../testing/ConnectorHubTestFeatureTest.java | 236 +++++++++++ .../testing/NotificationTestFeatureTest.java | 58 +++ fn-events/README.md | 37 ++ fn-events/pom.xml | 85 ++++ .../fnproject/events/APIGatewayFunction.java | 18 + .../events/ConnectorHubFunction.java | 16 + .../events/NotificationFunction.java | 16 + .../events/coercion/APIGatewayCoercion.java | 157 +++++++ .../events/coercion/ConnectorHubCoercion.java | 70 +++ .../events/coercion/NotificationCoercion.java | 71 ++++ .../com/fnproject/events/coercion/Util.java | 25 ++ .../jackson/Base64ToTypeDeserializer.java | 116 +++++ .../events/input/APIGatewayRequestEvent.java | 62 +++ .../events/input/ConnectorHubBatch.java | 41 ++ .../events/input/NotificationMessage.java | 40 ++ .../fnproject/events/input/sch/Datapoint.java | 63 +++ .../events/input/sch/LoggingData.java | 106 +++++ .../events/input/sch/MetricData.java | 81 ++++ .../events/input/sch/StreamingData.java | 90 ++++ .../mapper/APIGatewayRequestEventMapper.java | 19 + .../mapper/ApiGatewayRequestMapper.java | 8 + .../output/APIGatewayResponseEvent.java | 52 +++ .../events/APIGatewayFunctionTest.java | 93 ++++ .../events/ConnectorHubFunctionTest.java | 242 +++++++++++ .../events/NotificationFunctionTest.java | 65 +++ .../coercion/APIGatewayCoercionTest.java | 398 ++++++++++++++++++ .../coercion/ConnectorHubCoercionTest.java | 398 ++++++++++++++++++ .../coercion/NotificationCoercionTest.java | 107 +++++ .../jackson/Base64ToTypeDeserializerTest.java | 123 ++++++ .../APIGatewayRequestEventMapperTest.java | 112 +++++ .../output/APIGatewayResponseEventTest.java | 63 +++ .../com/fnproject/events/testfns/Animal.java | 50 +++ .../com/fnproject/events/testfns/Car.java | 24 ++ .../apigatewayfns/APIGatewayTestFunction.java | 16 + .../GrandChildGatewayTestFunction.java | 11 + .../ListAPIGatewayTestFunction.java | 18 + .../StringAPIGatewayTestFunction.java | 16 + .../UncheckedAPIGatewayTestFunction.java | 14 + .../GrandChildMonitorSourceTestFunction.java | 12 + .../LoggingSourceTestFunction.java | 13 + .../MonitorSourceTestFunction.java | 13 + .../QueueSourceObjectTestFunction.java | 13 + .../QueueSourceStringTestFunction.java | 12 + .../StreamingSourceObjectTestFunction.java | 14 + .../StreamingSourceStringTestFunction.java | 14 + .../NotificationObjectTestFunction.java | 13 + .../NotificationStringTestFunction.java | 12 + 54 files changed, 4086 insertions(+) create mode 100644 fn-events-testing/README.md create mode 100644 fn-events-testing/pom.xml create mode 100644 fn-events-testing/src/main/java/com/fnproject/events/testing/APIGatewayTestFeature.java create mode 100644 fn-events-testing/src/main/java/com/fnproject/events/testing/ConnectorHubTestFeature.java create mode 100644 fn-events-testing/src/main/java/com/fnproject/events/testing/NotificationTestFeature.java create mode 100644 fn-events-testing/src/test/java/com/fnproject/events/testing/APIGatewayTestFeatureTest.java create mode 100644 fn-events-testing/src/test/java/com/fnproject/events/testing/Animal.java create mode 100644 fn-events-testing/src/test/java/com/fnproject/events/testing/ConnectorHubTestFeatureTest.java create mode 100644 fn-events-testing/src/test/java/com/fnproject/events/testing/NotificationTestFeatureTest.java create mode 100644 fn-events/README.md create mode 100644 fn-events/pom.xml create mode 100644 fn-events/src/main/java/com/fnproject/events/APIGatewayFunction.java create mode 100644 fn-events/src/main/java/com/fnproject/events/ConnectorHubFunction.java create mode 100644 fn-events/src/main/java/com/fnproject/events/NotificationFunction.java create mode 100644 fn-events/src/main/java/com/fnproject/events/coercion/APIGatewayCoercion.java create mode 100644 fn-events/src/main/java/com/fnproject/events/coercion/ConnectorHubCoercion.java create mode 100644 fn-events/src/main/java/com/fnproject/events/coercion/NotificationCoercion.java create mode 100644 fn-events/src/main/java/com/fnproject/events/coercion/Util.java create mode 100644 fn-events/src/main/java/com/fnproject/events/coercion/jackson/Base64ToTypeDeserializer.java create mode 100644 fn-events/src/main/java/com/fnproject/events/input/APIGatewayRequestEvent.java create mode 100644 fn-events/src/main/java/com/fnproject/events/input/ConnectorHubBatch.java create mode 100644 fn-events/src/main/java/com/fnproject/events/input/NotificationMessage.java create mode 100644 fn-events/src/main/java/com/fnproject/events/input/sch/Datapoint.java create mode 100644 fn-events/src/main/java/com/fnproject/events/input/sch/LoggingData.java create mode 100644 fn-events/src/main/java/com/fnproject/events/input/sch/MetricData.java create mode 100644 fn-events/src/main/java/com/fnproject/events/input/sch/StreamingData.java create mode 100644 fn-events/src/main/java/com/fnproject/events/mapper/APIGatewayRequestEventMapper.java create mode 100644 fn-events/src/main/java/com/fnproject/events/mapper/ApiGatewayRequestMapper.java create mode 100644 fn-events/src/main/java/com/fnproject/events/output/APIGatewayResponseEvent.java create mode 100644 fn-events/src/test/java/com/fnproject/events/APIGatewayFunctionTest.java create mode 100644 fn-events/src/test/java/com/fnproject/events/ConnectorHubFunctionTest.java create mode 100644 fn-events/src/test/java/com/fnproject/events/NotificationFunctionTest.java create mode 100644 fn-events/src/test/java/com/fnproject/events/coercion/APIGatewayCoercionTest.java create mode 100644 fn-events/src/test/java/com/fnproject/events/coercion/ConnectorHubCoercionTest.java create mode 100644 fn-events/src/test/java/com/fnproject/events/coercion/NotificationCoercionTest.java create mode 100644 fn-events/src/test/java/com/fnproject/events/coercion/jackson/Base64ToTypeDeserializerTest.java create mode 100644 fn-events/src/test/java/com/fnproject/events/mapper/APIGatewayRequestEventMapperTest.java create mode 100644 fn-events/src/test/java/com/fnproject/events/output/APIGatewayResponseEventTest.java create mode 100644 fn-events/src/test/java/com/fnproject/events/testfns/Animal.java create mode 100644 fn-events/src/test/java/com/fnproject/events/testfns/Car.java create mode 100644 fn-events/src/test/java/com/fnproject/events/testfns/apigatewayfns/APIGatewayTestFunction.java create mode 100644 fn-events/src/test/java/com/fnproject/events/testfns/apigatewayfns/GrandChildGatewayTestFunction.java create mode 100644 fn-events/src/test/java/com/fnproject/events/testfns/apigatewayfns/ListAPIGatewayTestFunction.java create mode 100644 fn-events/src/test/java/com/fnproject/events/testfns/apigatewayfns/StringAPIGatewayTestFunction.java create mode 100644 fn-events/src/test/java/com/fnproject/events/testfns/apigatewayfns/UncheckedAPIGatewayTestFunction.java create mode 100644 fn-events/src/test/java/com/fnproject/events/testfns/connectorhub/GrandChildMonitorSourceTestFunction.java create mode 100644 fn-events/src/test/java/com/fnproject/events/testfns/connectorhub/LoggingSourceTestFunction.java create mode 100644 fn-events/src/test/java/com/fnproject/events/testfns/connectorhub/MonitorSourceTestFunction.java create mode 100644 fn-events/src/test/java/com/fnproject/events/testfns/connectorhub/QueueSourceObjectTestFunction.java create mode 100644 fn-events/src/test/java/com/fnproject/events/testfns/connectorhub/QueueSourceStringTestFunction.java create mode 100644 fn-events/src/test/java/com/fnproject/events/testfns/connectorhub/StreamingSourceObjectTestFunction.java create mode 100644 fn-events/src/test/java/com/fnproject/events/testfns/connectorhub/StreamingSourceStringTestFunction.java create mode 100644 fn-events/src/test/java/com/fnproject/events/testfns/notification/NotificationObjectTestFunction.java create mode 100644 fn-events/src/test/java/com/fnproject/events/testfns/notification/NotificationStringTestFunction.java diff --git a/fn-events-testing/README.md b/fn-events-testing/README.md new file mode 100644 index 00000000..0bd06d96 --- /dev/null +++ b/fn-events-testing/README.md @@ -0,0 +1,22 @@ +# Testing Fn Events + +You can use `FnEventTesting` to test [README.md](../fn-events/README.md) within your functions. + +Start by importing the `fn-events-testing` library into your function in `test` scope: + +```xml + + com.fnproject.fn + fn-events-testing + ${fdk.version} + test + +``` + +## Usage +- OCI API Gateway Function - [README.md](../examples/apigateway-event/README.md) +- OCI Service Connector Hub: Monitoring - [README.md](../examples/connectorhub-monitoring/README.md) +- OCI Service Connector Hub: Logging - [README.md](../examples/connectorhub-logging/README.md) +- OCI Service Connector Hub: Streaming - [README.md](../examples/connectorhub-streaming/README.md) +- OCI Service Connector Hub: Queue - [connectorhub-queue](../examples/connectorhub-queue) +- OCI Notifications - [README.md](../examples/notifications/README.md) diff --git a/fn-events-testing/pom.xml b/fn-events-testing/pom.xml new file mode 100644 index 00000000..ec638ca7 --- /dev/null +++ b/fn-events-testing/pom.xml @@ -0,0 +1,87 @@ + + + + + + fdk + com.fnproject.fn + 1.0.0-SNAPSHOT + + 4.0.0 + fn-events-testing + fn-events-testing + + + + com.fnproject.fn + api + + + com.fnproject.fn + fn-events + + + com.fnproject.fn + runtime + + + com.fnproject.fn + testing-core + + + com.fnproject.fn + testing-junit4 + + + org.mockito + mockito-core + test + + + org.assertj + assertj-core + test + + + junit + junit + compile + + + + + + + org.apache.maven.plugins + maven-javadoc-plugin + + + attach-javadocs + + jar + + + + + + + + diff --git a/fn-events-testing/src/main/java/com/fnproject/events/testing/APIGatewayTestFeature.java b/fn-events-testing/src/main/java/com/fnproject/events/testing/APIGatewayTestFeature.java new file mode 100644 index 00000000..9e51dd68 --- /dev/null +++ b/fn-events-testing/src/main/java/com/fnproject/events/testing/APIGatewayTestFeature.java @@ -0,0 +1,192 @@ +package com.fnproject.events.testing; + +import java.io.IOException; +import java.io.InputStream; +import java.io.PrintStream; +import java.io.UnsupportedEncodingException; +import java.nio.charset.StandardCharsets; +import java.util.Collections; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.stream.Collectors; +import java.util.stream.Stream; +import java.net.URLEncoder; +import com.fasterxml.jackson.core.JsonProcessingException; +import com.fasterxml.jackson.databind.ObjectMapper; +import com.fnproject.events.input.APIGatewayRequestEvent; +import com.fnproject.events.output.APIGatewayResponseEvent; +import com.fnproject.fn.api.Headers; +import com.fnproject.fn.api.InputEvent; +import com.fnproject.fn.testing.FnEventBuilder; +import com.fnproject.fn.testing.FnEventBuilderJUnit4; +import com.fnproject.fn.testing.FnHttpEventBuilder; +import com.fnproject.fn.testing.FnResult; +import com.fnproject.fn.testing.FnTestingClassLoader; +import com.fnproject.fn.testing.FnTestingRule; +import com.fnproject.fn.testing.FnTestingRuleFeature; + +public class APIGatewayTestFeature implements FnTestingRuleFeature { + private final FnTestingRule rule; + private final ObjectMapper mapper; + + private APIGatewayTestFeature(FnTestingRule rule) { + this(rule, new ObjectMapper()); + } + + private APIGatewayTestFeature(FnTestingRule rule, ObjectMapper mapper) { + this.rule = rule; + this.mapper = mapper; + } + + public static APIGatewayTestFeature createDefault(FnTestingRule rule) { + APIGatewayTestFeature feature = new APIGatewayTestFeature(rule); + rule.addFeature(feature); + return feature; + } + + @Override + public void prepareTest(ClassLoader functionClassLoader, PrintStream stderr, String cls, String method) { + + } + + @Override + public void prepareFunctionClassLoader(FnTestingClassLoader cl) { + + } + + @Override + public void afterTestComplete() { + + } + + public FnEventBuilderJUnit4 givenEvent(APIGatewayRequestEvent event) throws JsonProcessingException { + return new APIGatewayFnEventBuilder(event); + } + + /* + Unwrap output event to APIGatewayResponseEvent type + */ + public APIGatewayResponseEvent getResult(Class tClass) throws IOException { + FnResult result = rule.getOnlyResult(); + APIGatewayResponseEvent.Builder responseBuilder = + new APIGatewayResponseEvent.Builder(); + + if (result.getBodyAsBytes().length != 0) { + T body = mapper.readValue(result.getBodyAsBytes(), tClass); + responseBuilder + .body(body); + } + + Map> myHeaders = new HashMap<>(); + result.getHeaders().asMap().forEach((key, headerValues) -> { + if (key.startsWith("Fn-Http-H-")) { + String httpKey = key.substring("Fn-Http-H-".length()); + if (!httpKey.isEmpty()) { + myHeaders.put(httpKey, headerValues); + } + } + }); + responseBuilder.headers(Headers.emptyHeaders().setHeaders(myHeaders)); + + if (result.getHeaders().get("Fn-Http-Status").isPresent()) { + int statusCode = Integer.parseInt(result.getHeaders().get("Fn-Http-Status").get()); + responseBuilder.statusCode(statusCode); + } + return responseBuilder.build(); + } + + class APIGatewayFnEventBuilder implements FnEventBuilderJUnit4 { + + FnHttpEventBuilder builder = new FnHttpEventBuilder(); + + APIGatewayFnEventBuilder(APIGatewayRequestEvent requestEvent) throws JsonProcessingException { + withBody(mapper.writeValueAsBytes(requestEvent.getBody())); + if (requestEvent.getMethod() != null) { + withHeader("Fn-Http-Method", requestEvent.getMethod()); + } + + if (requestEvent.getHeaders() != null) { + requestEvent.getHeaders().asMap().forEach((key, headerValues) -> { + key = "Fn-Http-H-" + key; + for (String headerValue : headerValues) { + withHeader(key, headerValue); + } + }); + } + + /* + This wraps the test query parameters object into a format the FunctionInvocationContext.class can consume. + */ + String baseUrl = requestEvent.getRequestUrl() != null ? requestEvent.getRequestUrl() : ""; + Map> params = requestEvent.getQueryParameters() != null + ? requestEvent.getQueryParameters().getAll() + : Collections.emptyMap(); + + String query = params.entrySet().stream() + .flatMap(e -> { + String k = urlEncode(e.getKey()); + List vs = e.getValue(); + if (vs == null || vs.isEmpty()) return Stream.of(k + "="); + return vs.stream().map(v -> k + "=" + urlEncode(v)); + }) + .collect(Collectors.joining("&")); + + withHeader("Fn-Http-Request-Url", query.isEmpty() ? baseUrl : baseUrl + "?" + query); + } + + @Override + public FnEventBuilder withHeader(String key, String value) { + builder.withHeader(key, value); + return this; + } + + @Override + public FnEventBuilder withBody(InputStream body) throws IOException { + builder.withBody(body); + return this; + } + + @Override + public FnEventBuilder withBody(byte[] body) { + builder.withBody(body); + return this; + } + + @Override + public FnEventBuilder withBody(String body) { + builder.withBody(body); + return this; + } + + @Override + public FnTestingRule enqueue() { + rule.addInput(builder.buildEvent()); + + return rule; + } + + @Override + public FnTestingRule enqueue(int n) { + if (n <= 0) { + throw new IllegalArgumentException("Invalid count"); + } + for (int i = 0; i < n; i++) { + enqueue(); + } + return rule; + } + + InputEvent build() { + return builder.buildEvent(); + } + } + + private static String urlEncode(String value) { + try { + return URLEncoder.encode(value, StandardCharsets.UTF_8.displayName()); + } catch (UnsupportedEncodingException e) { + throw new RuntimeException(e); + } + } +} diff --git a/fn-events-testing/src/main/java/com/fnproject/events/testing/ConnectorHubTestFeature.java b/fn-events-testing/src/main/java/com/fnproject/events/testing/ConnectorHubTestFeature.java new file mode 100644 index 00000000..93c2a9e4 --- /dev/null +++ b/fn-events-testing/src/main/java/com/fnproject/events/testing/ConnectorHubTestFeature.java @@ -0,0 +1,115 @@ +package com.fnproject.events.testing; + +import java.io.IOException; +import java.io.InputStream; +import java.io.PrintStream; +import com.fasterxml.jackson.core.JsonProcessingException; +import com.fasterxml.jackson.databind.ObjectMapper; +import com.fnproject.events.input.ConnectorHubBatch; +import com.fnproject.fn.api.InputEvent; +import com.fnproject.fn.testing.FnEventBuilder; +import com.fnproject.fn.testing.FnEventBuilderJUnit4; +import com.fnproject.fn.testing.FnHttpEventBuilder; +import com.fnproject.fn.testing.FnTestingClassLoader; +import com.fnproject.fn.testing.FnTestingRule; +import com.fnproject.fn.testing.FnTestingRuleFeature; + +public class ConnectorHubTestFeature implements FnTestingRuleFeature { + private final FnTestingRule rule; + private final ObjectMapper mapper; + + private ConnectorHubTestFeature(FnTestingRule rule) { + this(rule, new ObjectMapper()); + } + + private ConnectorHubTestFeature(FnTestingRule rule, ObjectMapper mapper) { + this.rule = rule; + this.mapper = mapper; + } + + public static ConnectorHubTestFeature createDefault(FnTestingRule rule) { + ConnectorHubTestFeature feature = new ConnectorHubTestFeature(rule); + rule.addFeature(feature); + return feature; + } + + + @Override + public void prepareTest(ClassLoader functionClassLoader, PrintStream stderr, String cls, String method) { + } + + @Override + public void prepareFunctionClassLoader(FnTestingClassLoader cl) { + + } + + @Override + public void afterTestComplete() { + } + + public FnEventBuilderJUnit4 givenEvent(ConnectorHubBatch event) throws JsonProcessingException { + return new ConnectorHubRequestEventBuilder(event); + } + + class ConnectorHubRequestEventBuilder implements FnEventBuilderJUnit4 { + + FnHttpEventBuilder builder = new FnHttpEventBuilder(); + + ConnectorHubRequestEventBuilder(ConnectorHubBatch requestEvent) throws JsonProcessingException { + withBody(mapper.writeValueAsBytes(requestEvent.getBatch())); + if (requestEvent.getHeaders() != null) { + requestEvent.getHeaders().asMap().forEach((key, headerValues) -> { + for (String headerValue : headerValues) { + withHeader(key, headerValue); + } + }); + } + } + + @Override + public FnEventBuilder withHeader(String key, String value) { + builder.withHeader(key, value); + return this; + } + + @Override + public FnEventBuilder withBody(InputStream body) throws IOException { + builder.withBody(body); + return this; + } + + @Override + public FnEventBuilder withBody(byte[] body) { + builder.withBody(body); + return this; + } + + @Override + public FnEventBuilder withBody(String body) { + builder.withBody(body); + return this; + } + + @Override + public FnTestingRule enqueue() { + rule.addInput(builder.buildEvent()); + + return rule; + } + + @Override + public FnTestingRule enqueue(int n) { + if (n <= 0) { + throw new IllegalArgumentException("Invalid count"); + } + for (int i = 0; i < n; i++) { + enqueue(); + } + return rule; + } + + InputEvent build() { + return builder.buildEvent(); + } + } +} diff --git a/fn-events-testing/src/main/java/com/fnproject/events/testing/NotificationTestFeature.java b/fn-events-testing/src/main/java/com/fnproject/events/testing/NotificationTestFeature.java new file mode 100644 index 00000000..9f90af9d --- /dev/null +++ b/fn-events-testing/src/main/java/com/fnproject/events/testing/NotificationTestFeature.java @@ -0,0 +1,116 @@ +package com.fnproject.events.testing; + +import java.io.IOException; +import java.io.InputStream; +import java.io.PrintStream; +import com.fasterxml.jackson.core.JsonProcessingException; +import com.fasterxml.jackson.databind.ObjectMapper; +import com.fnproject.events.input.ConnectorHubBatch; +import com.fnproject.events.input.NotificationMessage; +import com.fnproject.fn.api.InputEvent; +import com.fnproject.fn.testing.FnEventBuilder; +import com.fnproject.fn.testing.FnEventBuilderJUnit4; +import com.fnproject.fn.testing.FnHttpEventBuilder; +import com.fnproject.fn.testing.FnTestingClassLoader; +import com.fnproject.fn.testing.FnTestingRule; +import com.fnproject.fn.testing.FnTestingRuleFeature; + +public class NotificationTestFeature implements FnTestingRuleFeature { + private final FnTestingRule rule; + private final ObjectMapper mapper; + + private NotificationTestFeature(FnTestingRule rule) { + this(rule, new ObjectMapper()); + } + + private NotificationTestFeature(FnTestingRule rule, ObjectMapper mapper) { + this.rule = rule; + this.mapper = mapper; + } + + public static NotificationTestFeature createDefault(FnTestingRule rule) { + NotificationTestFeature feature = new NotificationTestFeature(rule); + rule.addFeature(feature); + return feature; + } + + + @Override + public void prepareTest(ClassLoader functionClassLoader, PrintStream stderr, String cls, String method) { + } + + @Override + public void prepareFunctionClassLoader(FnTestingClassLoader cl) { + + } + + @Override + public void afterTestComplete() { + } + + public FnEventBuilderJUnit4 givenEvent(NotificationMessage event) throws JsonProcessingException { + return new NotificationRequestEventBuilder(event); + } + + class NotificationRequestEventBuilder implements FnEventBuilderJUnit4 { + + FnHttpEventBuilder builder = new FnHttpEventBuilder(); + + NotificationRequestEventBuilder(NotificationMessage requestEvent) throws JsonProcessingException { + withBody(mapper.writeValueAsBytes(requestEvent.getContent())); + if (requestEvent.getHeaders() != null) { + requestEvent.getHeaders().asMap().forEach((key, headerValues) -> { + for (String headerValue : headerValues) { + withHeader(key, headerValue); + } + }); + } + } + + @Override + public FnEventBuilder withHeader(String key, String value) { + builder.withHeader(key, value); + return this; + } + + @Override + public FnEventBuilder withBody(InputStream body) throws IOException { + builder.withBody(body); + return this; + } + + @Override + public FnEventBuilder withBody(byte[] body) { + builder.withBody(body); + return this; + } + + @Override + public FnEventBuilder withBody(String body) { + builder.withBody(body); + return this; + } + + @Override + public FnTestingRule enqueue() { + rule.addInput(builder.buildEvent()); + + return rule; + } + + @Override + public FnTestingRule enqueue(int n) { + if (n <= 0) { + throw new IllegalArgumentException("Invalid count"); + } + for (int i = 0; i < n; i++) { + enqueue(); + } + return rule; + } + + InputEvent build() { + return builder.buildEvent(); + } + } +} diff --git a/fn-events-testing/src/test/java/com/fnproject/events/testing/APIGatewayTestFeatureTest.java b/fn-events-testing/src/test/java/com/fnproject/events/testing/APIGatewayTestFeatureTest.java new file mode 100644 index 00000000..8c7a176a --- /dev/null +++ b/fn-events-testing/src/test/java/com/fnproject/events/testing/APIGatewayTestFeatureTest.java @@ -0,0 +1,171 @@ +package com.fnproject.events.testing; + + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertNull; +import com.fasterxml.jackson.annotation.JsonCreator; +import com.fasterxml.jackson.annotation.JsonProperty; +import com.fnproject.events.input.APIGatewayRequestEvent; +import com.fnproject.events.output.APIGatewayResponseEvent; +import com.fnproject.fn.api.Headers; +import com.fnproject.fn.api.InputEvent; +import com.fnproject.fn.api.httpgateway.HTTPGatewayContext; +import com.fnproject.fn.runtime.httpgateway.QueryParametersImpl; +import com.fnproject.fn.testing.FnEventBuilderJUnit4; +import com.fnproject.fn.testing.FnTestingRule; +import java.io.IOException; +import java.nio.charset.StandardCharsets; +import java.util.ArrayList; +import java.util.Collections; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import org.apache.commons.io.IOUtils; +import org.junit.Rule; +import org.junit.Test; + +public class APIGatewayTestFeatureTest { + + @Rule + public final FnTestingRule fn = FnTestingRule.createDefault(); + + APIGatewayTestFeature feature = APIGatewayTestFeature.createDefault(fn); + + public static class Body { + public final String message; + + @JsonCreator + public Body(@JsonProperty("message") String message) { + this.message = message; + } + } + +/* + A minimal function that echoes input and captures request. +*/ + public String handle(HTTPGatewayContext ctx, InputEvent inputEvent) { + + String body = inputEvent.consumeBody(is -> { + try { + return IOUtils.toString(is, StandardCharsets.UTF_8); + } catch (IOException e) { + throw new RuntimeException("Error reading input as string", e); + } + }); + + ctx.getHeaders().asMap().forEach((key, value1) -> value1.forEach(value -> { + ctx.addResponseHeader(key, value); + })); + + ctx.setStatusCode(200); + + return body; + } + + @Test + public void testRequestStringifyBody() throws Exception { + Body reqBody = new Body("hello"); + APIGatewayRequestEvent req = new APIGatewayRequestEvent(new QueryParametersImpl(), reqBody, "GET", "/v2/employee", Headers.emptyHeaders()); + + APIGatewayTestFeature.APIGatewayFnEventBuilder builder = (APIGatewayTestFeature.APIGatewayFnEventBuilder) feature.givenEvent(req); + InputEvent inputEvent = builder.build(); + + String body = inputEvent.consumeBody(is -> { + try { + return IOUtils.toString(is, StandardCharsets.UTF_8); + } catch (IOException e) { + throw new RuntimeException("Error reading input as string"); + } + }); + assertEquals("{\"message\":\"hello\"}", body); + } + + @Test + public void testRequestUrl() throws Exception { + APIGatewayRequestEvent req = new APIGatewayRequestEvent(new QueryParametersImpl(), null, "GET", "/v2/employee", Headers.emptyHeaders()); + + APIGatewayTestFeature.APIGatewayFnEventBuilder builder = (APIGatewayTestFeature.APIGatewayFnEventBuilder) feature.givenEvent(req); + InputEvent inputEvent = builder.build(); + + assertEquals(req.getRequestUrl(), inputEvent.getHeaders().get("Fn-Http-Request-Url").get()); + } + + @Test + public void testRequestHeaderMethod() throws Exception { + APIGatewayRequestEvent req = new APIGatewayRequestEvent(new QueryParametersImpl(), null, "GET", "/v2/employee", Headers.emptyHeaders()); + + APIGatewayTestFeature.APIGatewayFnEventBuilder builder = (APIGatewayTestFeature.APIGatewayFnEventBuilder) feature.givenEvent(req); + InputEvent inputEvent = builder.build(); + + assertEquals(req.getMethod(), inputEvent.getHeaders().get("Fn-Http-Method").get()); + } + + @Test + public void testRequestQueryParameters() throws Exception { + Map> queryParams = new HashMap<>(); + List paramValues = new ArrayList<>(); + paramValues.add("bar"); + paramValues.add("foo"); + queryParams.put("foo", paramValues); + queryParams.put("spaces", Collections.singletonList("this has spaces")); + + APIGatewayRequestEvent req = new APIGatewayRequestEvent(new QueryParametersImpl(queryParams), null, "GET", "/v2/employee", Headers.emptyHeaders()); + + APIGatewayTestFeature.APIGatewayFnEventBuilder builder = (APIGatewayTestFeature.APIGatewayFnEventBuilder) feature.givenEvent(req); + InputEvent inputEvent = builder.build(); + + assertEquals("/v2/employee?spaces=this+has+spaces&foo=bar&foo=foo", inputEvent.getHeaders().get("Fn-Http-Request-Url").get()); + } + + @Test + public void testReturnObjectResponse() throws Exception { + Body reqBody = new Body("hello"); + APIGatewayRequestEvent req = new APIGatewayRequestEvent(new QueryParametersImpl(), reqBody, "GET", "/v2/employee", Headers.emptyHeaders()); + + FnEventBuilderJUnit4 builder = feature.givenEvent(req); + builder.enqueue(); + + fn.thenRun(APIGatewayTestFeatureTest.class, "handle"); + + APIGatewayResponseEvent resp = feature.getResult(Body.class); + + assertNotNull(resp.getBody()); + assertEquals("hello", resp.getBody().message); + } + + @Test + public void testReturnNullObjectResponse() throws Exception { + APIGatewayRequestEvent req = new APIGatewayRequestEvent(new QueryParametersImpl(), null, "GET", "/v2/employee", Headers.emptyHeaders()); + + FnEventBuilderJUnit4 builder = feature.givenEvent(req); + builder.enqueue(); + + fn.thenRun(APIGatewayTestFeatureTest.class, "handle"); + + APIGatewayResponseEvent resp = feature.getResult(Body.class); + + assertNull(resp.getBody()); + } + + @Test + public void testReturnHeaderResponse() throws Exception { + Headers headers = Headers.emptyHeaders() + .addHeader("Custom", "foo") + .addHeader("Custom", "bar"); + + APIGatewayRequestEvent req = new APIGatewayRequestEvent(new QueryParametersImpl(), null, "GET", "/v2/employee", headers); + + FnEventBuilderJUnit4 builder = feature.givenEvent(req); + builder.enqueue(); + + fn.thenRun(APIGatewayTestFeatureTest.class, "handle"); + + APIGatewayResponseEvent resp = feature.getResult(Body.class); + + assertNotNull(resp.getHeaders()); + assertEquals("foo", resp.getHeaders().getAllValues("Custom").get(0)); + assertEquals("bar", resp.getHeaders().getAllValues("Custom").get(1)); + } + +} \ No newline at end of file diff --git a/fn-events-testing/src/test/java/com/fnproject/events/testing/Animal.java b/fn-events-testing/src/test/java/com/fnproject/events/testing/Animal.java new file mode 100644 index 00000000..4cbe3f2e --- /dev/null +++ b/fn-events-testing/src/test/java/com/fnproject/events/testing/Animal.java @@ -0,0 +1,50 @@ +package com.fnproject.events.testing; + +import java.util.Objects; +import com.fasterxml.jackson.annotation.JsonCreator; +import com.fasterxml.jackson.annotation.JsonProperty; + +public class Animal { + private final String name; + private final int age; + + @JsonCreator + public Animal(@JsonProperty("name") String name, + @JsonProperty("age") int age) { + this.name = name; + this.age = age; + } + + public int getAge() { + return age; + } + + public String getName() { + return name; + } + + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } + Animal animal = (Animal) o; + return age == animal.age && Objects.equals(name, animal.name); + } + + @Override + public int hashCode() { + return Objects.hash(name, age); + } + + @Override + public String toString() { + return "Animal{" + + "name='" + name + '\'' + + ", age=" + age + + '}'; + } +} diff --git a/fn-events-testing/src/test/java/com/fnproject/events/testing/ConnectorHubTestFeatureTest.java b/fn-events-testing/src/test/java/com/fnproject/events/testing/ConnectorHubTestFeatureTest.java new file mode 100644 index 00000000..358d6720 --- /dev/null +++ b/fn-events-testing/src/test/java/com/fnproject/events/testing/ConnectorHubTestFeatureTest.java @@ -0,0 +1,236 @@ +package com.fnproject.events.testing; + +import static org.junit.Assert.assertEquals; +import java.io.IOException; +import java.nio.charset.StandardCharsets; +import java.util.Collections; +import java.util.Date; +import java.util.HashMap; +import java.util.Map; +import com.fnproject.events.input.ConnectorHubBatch; +import com.fnproject.events.input.sch.Datapoint; +import com.fnproject.events.input.sch.LoggingData; +import com.fnproject.events.input.sch.MetricData; +import com.fnproject.events.input.sch.StreamingData; +import com.fnproject.fn.api.Headers; +import com.fnproject.fn.api.InputEvent; +import com.fnproject.fn.testing.FnTestingRule; +import org.apache.commons.io.IOUtils; +import org.junit.Rule; +import org.junit.Test; + +public class ConnectorHubTestFeatureTest { + + @Rule + public final FnTestingRule fn = FnTestingRule.createDefault(); + + ConnectorHubTestFeature feature = ConnectorHubTestFeature.createDefault(fn); + + @Test + public void testMetricDataBody() throws Exception { + ConnectorHubBatch req = new ConnectorHubBatch<>(Collections.singletonList( + new MetricData( + "ns", + null, + "compartment", + "name", + new HashMap<>(), + new HashMap<>(), + Collections.singletonList(new Datapoint( + new Date(1764860467553L), + Double.parseDouble("1.2"), + null) + ) + ) + ), Headers.emptyHeaders()); + + ConnectorHubTestFeature.ConnectorHubRequestEventBuilder builder = (ConnectorHubTestFeature.ConnectorHubRequestEventBuilder) feature.givenEvent(req); + InputEvent inputEvent = builder.build(); + + String body = inputEvent.consumeBody(is -> { + try { + return IOUtils.toString(is, StandardCharsets.UTF_8); + } catch (IOException e) { + throw new RuntimeException("Error reading input as string"); + } + }); + assertEquals( + "[{\"namespace\":\"ns\",\"resourceGroup\":null,\"compartmentId\":\"compartment\",\"name\":\"name\",\"dimensions\":{},\"metadata\":{},\"datapoints\":[{\"timestamp\":1764860467553,\"value\":1.2,\"count\":null}]}]", + body); + } + + @Test + public void testMetricEmptyList() throws Exception { + ConnectorHubBatch req = new ConnectorHubBatch<>(Collections.emptyList(), Headers.emptyHeaders()); + ConnectorHubTestFeature.ConnectorHubRequestEventBuilder builder = (ConnectorHubTestFeature.ConnectorHubRequestEventBuilder) feature.givenEvent(req); + InputEvent inputEvent = builder.build(); + + String body = inputEvent.consumeBody(is -> { + try { + return IOUtils.toString(is, StandardCharsets.UTF_8); + } catch (IOException e) { + throw new RuntimeException("Error reading input as string"); + } + }); + assertEquals("[]", body); + } + + @Test + public void testLoggingDataBody() throws Exception { + Map data = new HashMap(); + data.put("applicationId", "ocid1.fnapp.oc1.xyz"); + data.put("containerId", "n/a"); + data.put("functionId", "ocid1.fnfunc.oc1.xyz"); + data.put("message", "Received function invocation request"); + data.put("opcRequestId", "/abc/def"); + data.put("requestId", "/def/abc"); + data.put("src", "STDOUT"); + + Map oracle = new HashMap(); + oracle.put("compartmentid", "ocid1.tenancy.oc1.xyz"); + oracle.put("ingestedtime", "2025-10-23T15:45:19.457Z"); + oracle.put("loggroupid", "ocid1.loggroup.oc1.abc"); + oracle.put("logid", "ocid1.log.oc1.abc"); + oracle.put("tenantid", "ocid1.tenancy.oc1.xyz"); + + ConnectorHubBatch req = new ConnectorHubBatch<>(Collections.singletonList( + new LoggingData( + "ecb37864-4396-4302-9575-981644949730", + "log-name", + "1.0", + "schedule", + "com.oraclecloud.functions.application.functioninvoke", + data, + oracle, + new Date(1764860467553L) + ) + ), Headers.emptyHeaders()); + + ConnectorHubTestFeature.ConnectorHubRequestEventBuilder builder = (ConnectorHubTestFeature.ConnectorHubRequestEventBuilder) feature.givenEvent(req); + InputEvent inputEvent = builder.build(); + + String body = inputEvent.consumeBody(is -> { + try { + return IOUtils.toString(is, StandardCharsets.UTF_8); + } catch (IOException e) { + throw new RuntimeException("Error reading input as string"); + } + }); + assertEquals( + "[{\"id\":\"ecb37864-4396-4302-9575-981644949730\",\"source\":\"log-name\",\"specversion\":\"1.0\",\"subject\":\"schedule\",\"type\":\"com.oraclecloud.functions.application.functioninvoke\",\"data\":{\"functionId\":\"ocid1.fnfunc.oc1.xyz\",\"opcRequestId\":\"/abc/def\",\"src\":\"STDOUT\",\"requestId\":\"/def/abc\",\"applicationId\":\"ocid1.fnapp.oc1.xyz\",\"containerId\":\"n/a\",\"message\":\"Received function invocation request\"},\"oracle\":{\"compartmentid\":\"ocid1.tenancy.oc1.xyz\",\"ingestedtime\":\"2025-10-23T15:45:19.457Z\",\"loggroupid\":\"ocid1.loggroup.oc1.abc\",\"tenantid\":\"ocid1.tenancy.oc1.xyz\",\"logid\":\"ocid1.log.oc1.abc\"},\"time\":1764860467553}]", + body); + } + + @Test + public void testLoggingDataEmptyList() throws Exception { + ConnectorHubBatch req = new ConnectorHubBatch<>(Collections.emptyList(), Headers.emptyHeaders()); + ConnectorHubTestFeature.ConnectorHubRequestEventBuilder builder = (ConnectorHubTestFeature.ConnectorHubRequestEventBuilder) feature.givenEvent(req); + InputEvent inputEvent = builder.build(); + + String body = inputEvent.consumeBody(is -> { + try { + return IOUtils.toString(is, StandardCharsets.UTF_8); + } catch (IOException e) { + throw new RuntimeException("Error reading input as string"); + } + }); + assertEquals("[]", body); + } + + @Test + public void testStreamingBody() throws Exception { + Animal animal = new Animal("foo", 4); + + StreamingData source = new StreamingData<>( + "stream-name", + "0", + null, + animal, + "3", + new Date(1764860467553L) + ); + + ConnectorHubBatch> req = new ConnectorHubBatch<>(Collections.singletonList( + source + ), Headers.emptyHeaders()); + + ConnectorHubTestFeature.ConnectorHubRequestEventBuilder builder = (ConnectorHubTestFeature.ConnectorHubRequestEventBuilder) feature.givenEvent(req); + InputEvent inputEvent = builder.build(); + + String body = inputEvent.consumeBody(is -> { + try { + return IOUtils.toString(is, StandardCharsets.UTF_8); + } catch (IOException e) { + throw new RuntimeException("Error reading input as string"); + } + }); + assertEquals( + "[{\"stream\":\"stream-name\",\"partition\":\"0\",\"key\":null,\"value\":{\"name\":\"foo\",\"age\":4},\"offset\":\"3\",\"timestamp\":1764860467553}]", + body); + } + + @Test + public void testStreamingStringBody() throws Exception { + StreamingData source = new StreamingData<>( + "stream-name", + "0", + null, + "a plain string", + "3", + new Date(1764860467553L) + ); + + ConnectorHubBatch> req = new ConnectorHubBatch<>(Collections.singletonList( + source + ), Headers.emptyHeaders()); + + ConnectorHubTestFeature.ConnectorHubRequestEventBuilder builder = (ConnectorHubTestFeature.ConnectorHubRequestEventBuilder) feature.givenEvent(req); + InputEvent inputEvent = builder.build(); + + String body = inputEvent.consumeBody(is -> { + try { + return IOUtils.toString(is, StandardCharsets.UTF_8); + } catch (IOException e) { + throw new RuntimeException("Error reading input as string"); + } + }); + assertEquals( + "[{\"stream\":\"stream-name\",\"partition\":\"0\",\"key\":null,\"value\":\"a plain string\",\"offset\":\"3\",\"timestamp\":1764860467553}]", + body); + } + + @Test + public void testStreamingDataEmptyList() throws Exception { + ConnectorHubBatch> req = new ConnectorHubBatch<>(Collections.emptyList(), Headers.emptyHeaders()); + ConnectorHubTestFeature.ConnectorHubRequestEventBuilder builder = (ConnectorHubTestFeature.ConnectorHubRequestEventBuilder) feature.givenEvent(req); + InputEvent inputEvent = builder.build(); + + String body = inputEvent.consumeBody(is -> { + try { + return IOUtils.toString(is, StandardCharsets.UTF_8); + } catch (IOException e) { + throw new RuntimeException("Error reading input as string"); + } + }); + assertEquals("[]", body); + } + + @Test + public void testHeadersEmptyList() throws Exception { + ConnectorHubBatch> req = new ConnectorHubBatch<>(Collections.emptyList(), Headers.emptyHeaders()); + ConnectorHubTestFeature.ConnectorHubRequestEventBuilder builder = (ConnectorHubTestFeature.ConnectorHubRequestEventBuilder) feature.givenEvent(req); + InputEvent inputEvent = builder.build(); + + assertEquals(Headers.emptyHeaders(), inputEvent.getHeaders()); + } + + @Test + public void testHeadersList() throws Exception { + Headers headers = Headers.emptyHeaders().addHeader("foo", "bar"); + ConnectorHubBatch> req = new ConnectorHubBatch<>(Collections.emptyList(), headers); + ConnectorHubTestFeature.ConnectorHubRequestEventBuilder builder = (ConnectorHubTestFeature.ConnectorHubRequestEventBuilder) feature.givenEvent(req); + InputEvent inputEvent = builder.build(); + + assertEquals("bar", inputEvent.getHeaders().get("foo").get()); + } +} \ No newline at end of file diff --git a/fn-events-testing/src/test/java/com/fnproject/events/testing/NotificationTestFeatureTest.java b/fn-events-testing/src/test/java/com/fnproject/events/testing/NotificationTestFeatureTest.java new file mode 100644 index 00000000..569d9dac --- /dev/null +++ b/fn-events-testing/src/test/java/com/fnproject/events/testing/NotificationTestFeatureTest.java @@ -0,0 +1,58 @@ +package com.fnproject.events.testing; + +import static org.junit.Assert.assertEquals; +import java.io.IOException; +import java.nio.charset.StandardCharsets; +import com.fnproject.events.input.NotificationMessage; +import com.fnproject.fn.api.Headers; +import com.fnproject.fn.api.InputEvent; +import com.fnproject.fn.testing.FnTestingRule; +import org.apache.commons.io.IOUtils; +import org.junit.Rule; +import org.junit.Test; + +public class NotificationTestFeatureTest { + + @Rule + public final FnTestingRule fn = FnTestingRule.createDefault(); + + NotificationTestFeature feature = NotificationTestFeature.createDefault(fn); + + @Test + public void testObjectBody() throws Exception { + Animal animal = new Animal("foo", 3); + NotificationMessage req = new NotificationMessage<>(animal, Headers.emptyHeaders()); + NotificationTestFeature.NotificationRequestEventBuilder builder = (NotificationTestFeature.NotificationRequestEventBuilder) feature.givenEvent(req); + InputEvent inputEvent = builder.build(); + + String body = inputEvent.consumeBody(is -> { + try { + return IOUtils.toString(is, StandardCharsets.UTF_8); + } catch (IOException e) { + throw new RuntimeException("Error reading input as string"); + } + }); + assertEquals( + "{\"name\":\"foo\",\"age\":3}", + body); + } + + @Test + public void testHeadersEmptyList() throws Exception { + NotificationMessage req = new NotificationMessage<>("", Headers.emptyHeaders()); + NotificationTestFeature.NotificationRequestEventBuilder builder = (NotificationTestFeature.NotificationRequestEventBuilder) feature.givenEvent(req); + InputEvent inputEvent = builder.build(); + + assertEquals(Headers.emptyHeaders(), inputEvent.getHeaders()); + } + + @Test + public void testHeadersList() throws Exception { + Headers headers = Headers.emptyHeaders().addHeader("foo", "bar"); + NotificationMessage req = new NotificationMessage<>("", headers); + NotificationTestFeature.NotificationRequestEventBuilder builder = (NotificationTestFeature.NotificationRequestEventBuilder) feature.givenEvent(req); + InputEvent inputEvent = builder.build(); + + assertEquals("bar", inputEvent.getHeaders().get("foo").get()); + } +} \ No newline at end of file diff --git a/fn-events/README.md b/fn-events/README.md new file mode 100644 index 00000000..3d343f76 --- /dev/null +++ b/fn-events/README.md @@ -0,0 +1,37 @@ +# Support tools for functions OCI integrations + +This is an optional module that can be added to Functions that resolves some common integrations related to +OCI Services handling oracle functions invocations. + +* OCI API Gateway support + +# Enabling the feature in Function: + +Edit your pom file and add this library as a dependency: + +```xml + + com.fnproject.fn + fn-events + ${fdk.version} + +``` + +Optionally, add the fn-events-testing library: + +```xml + + com.fnproject.fn + fn-events-testing + ${fdk.version} + test + +``` + +## Usage +- OCI API Gateway Function - [README.md](../examples/apigateway-event/README.md) +- OCI Service Connector Hub: Monitoring - [README.md](../examples/connectorhub-monitoring/README.md) +- OCI Service Connector Hub: Logging - [README.md](../examples/connectorhub-logging/README.md) +- OCI Service Connector Hub: Streaming - [README.md](../examples/connectorhub-streaming/README.md) +- OCI Service Connector Hub: Queue - [connectorhub-queue](../examples/connectorhub-queue) +- OCI Notifications - [README.md](../examples/notifications/README.md) diff --git a/fn-events/pom.xml b/fn-events/pom.xml new file mode 100644 index 00000000..6cd6eae2 --- /dev/null +++ b/fn-events/pom.xml @@ -0,0 +1,85 @@ + + + + + + fdk + com.fnproject.fn + 1.0.0-SNAPSHOT + + 4.0.0 + fn-events + fn-events + + + + com.fnproject.fn + api + + + com.fnproject.fn + runtime + + + com.fnproject.fn + testing-core + test + + + com.fnproject.fn + testing-junit4 + test + + + org.mockito + mockito-core + test + + + org.assertj + assertj-core + test + + + junit + junit + test + + + + + + + org.apache.maven.plugins + maven-javadoc-plugin + + + attach-javadocs + + jar + + + + + + + + diff --git a/fn-events/src/main/java/com/fnproject/events/APIGatewayFunction.java b/fn-events/src/main/java/com/fnproject/events/APIGatewayFunction.java new file mode 100644 index 00000000..92e870dd --- /dev/null +++ b/fn-events/src/main/java/com/fnproject/events/APIGatewayFunction.java @@ -0,0 +1,18 @@ +package com.fnproject.events; + +import com.fnproject.events.coercion.APIGatewayCoercion; +import com.fnproject.events.input.APIGatewayRequestEvent; +import com.fnproject.events.output.APIGatewayResponseEvent; +import com.fnproject.fn.api.FnConfiguration; +import com.fnproject.fn.api.RuntimeContext; + +public abstract class APIGatewayFunction { + + @FnConfiguration + public void configure(RuntimeContext ctx){ + ctx.addInputCoercion(APIGatewayCoercion.instance()); + ctx.addOutputCoercion(APIGatewayCoercion.instance()); + } + + public abstract APIGatewayResponseEvent handler(APIGatewayRequestEvent requestEvent); +} diff --git a/fn-events/src/main/java/com/fnproject/events/ConnectorHubFunction.java b/fn-events/src/main/java/com/fnproject/events/ConnectorHubFunction.java new file mode 100644 index 00000000..dedb4966 --- /dev/null +++ b/fn-events/src/main/java/com/fnproject/events/ConnectorHubFunction.java @@ -0,0 +1,16 @@ +package com.fnproject.events; + +import com.fnproject.events.coercion.ConnectorHubCoercion; +import com.fnproject.events.input.ConnectorHubBatch; +import com.fnproject.fn.api.FnConfiguration; +import com.fnproject.fn.api.RuntimeContext; + +public abstract class ConnectorHubFunction { + + @FnConfiguration + public void configure(RuntimeContext ctx){ + ctx.addInputCoercion(ConnectorHubCoercion.instance()); + } + + public abstract void handler(ConnectorHubBatch connectorHubBatch); +} diff --git a/fn-events/src/main/java/com/fnproject/events/NotificationFunction.java b/fn-events/src/main/java/com/fnproject/events/NotificationFunction.java new file mode 100644 index 00000000..b5c9fb01 --- /dev/null +++ b/fn-events/src/main/java/com/fnproject/events/NotificationFunction.java @@ -0,0 +1,16 @@ +package com.fnproject.events; + +import com.fnproject.events.coercion.NotificationCoercion; +import com.fnproject.events.input.NotificationMessage; +import com.fnproject.fn.api.FnConfiguration; +import com.fnproject.fn.api.RuntimeContext; + +public abstract class NotificationFunction { + + @FnConfiguration + public void configure(RuntimeContext ctx){ + ctx.addInputCoercion(NotificationCoercion.instance()); + } + + public abstract void handler(NotificationMessage notification); +} diff --git a/fn-events/src/main/java/com/fnproject/events/coercion/APIGatewayCoercion.java b/fn-events/src/main/java/com/fnproject/events/coercion/APIGatewayCoercion.java new file mode 100644 index 00000000..f42d8f9e --- /dev/null +++ b/fn-events/src/main/java/com/fnproject/events/coercion/APIGatewayCoercion.java @@ -0,0 +1,157 @@ +package com.fnproject.events.coercion; + +import static com.fnproject.events.coercion.Util.hasEventFnInHierarchy; +import static com.fnproject.events.coercion.Util.readBodyAsString; +import static com.fnproject.fn.api.OutputEvent.CONTENT_TYPE_HEADER; +import java.io.IOException; +import java.lang.reflect.ParameterizedType; +import java.lang.reflect.Type; +import java.util.List; +import java.util.Optional; +import com.fasterxml.jackson.core.JsonProcessingException; +import com.fasterxml.jackson.databind.JavaType; +import com.fasterxml.jackson.databind.ObjectMapper; +import com.fasterxml.jackson.databind.type.TypeFactory; +import com.fnproject.events.APIGatewayFunction; +import com.fnproject.events.input.APIGatewayRequestEvent; +import com.fnproject.events.mapper.APIGatewayRequestEventMapper; +import com.fnproject.events.mapper.ApiGatewayRequestMapper; +import com.fnproject.events.output.APIGatewayResponseEvent; +import com.fnproject.fn.api.InputCoercion; +import com.fnproject.fn.api.InputEvent; +import com.fnproject.fn.api.InvocationContext; +import com.fnproject.fn.api.MethodWrapper; +import com.fnproject.fn.api.OutputCoercion; +import com.fnproject.fn.api.OutputEvent; +import com.fnproject.fn.runtime.httpgateway.FunctionHTTPGatewayContext; + + +public class APIGatewayCoercion implements InputCoercion, OutputCoercion { + + private static final APIGatewayCoercion instance = new APIGatewayCoercion(); + static final String OM_KEY = APIGatewayCoercion.class.getCanonicalName() + ".om"; + private final ApiGatewayRequestMapper requestMapper; + + public APIGatewayCoercion(ApiGatewayRequestMapper requestMapper) { + this.requestMapper = requestMapper; + } + + private APIGatewayCoercion() { + requestMapper = new APIGatewayRequestEventMapper(); + } + + public static APIGatewayCoercion instance() { + return instance; + } + + private static ObjectMapper objectMapper(InvocationContext ctx) { + Optional omo = ctx.getRuntimeContext().getAttribute(OM_KEY, ObjectMapper.class); + if (!omo.isPresent()) { + ObjectMapper om = new ObjectMapper(); + + ctx.getRuntimeContext().setAttribute(OM_KEY, om); + return om; + } else { + return omo.get(); + } + } + + @Override + public Optional tryCoerceParam(InvocationContext currentContext, int param, InputEvent input, MethodWrapper method) { + if (hasEventFnInHierarchy(method.getTargetClass().getSuperclass(), APIGatewayFunction.class)) { + FunctionHTTPGatewayContext functionHTTPGatewayContext = new FunctionHTTPGatewayContext(currentContext); + + Type type = method.getTargetMethod().getGenericParameterTypes()[param]; + JavaType javaType = objectMapper(currentContext).constructType(type); + List requestGenerics = javaType.getBindings().getTypeParameters(); + + Object body; + + if (!requestGenerics.isEmpty()) { + JavaType requestGeneric = requestGenerics.get(0); + if (requestGeneric.hasRawClass(String.class)) { + body = readBodyAsString(input); + } else { + ObjectMapper mapper = objectMapper(currentContext); + body = input.consumeBody(is -> { + try { + return mapper.readValue(is, requestGeneric); + } catch (IOException e) { + throw coercionFailed(requestGeneric, e); + } + }); + } + } else { + body = readBodyAsString(input); + } + APIGatewayRequestEvent requestEvent = requestMapper.toApiGatewayRequestEvent(functionHTTPGatewayContext, body); + return Optional.of(requestEvent); + } else { + return Optional.empty(); + } + } + + @Override + public Optional wrapFunctionResult(InvocationContext currentContext, MethodWrapper method, Object value) { + if (!hasEventFnInHierarchy(method.getTargetClass().getSuperclass(), APIGatewayFunction.class) || value == null) { + return Optional.empty(); + } + + FunctionHTTPGatewayContext ctx = new FunctionHTTPGatewayContext(currentContext); + APIGatewayResponseEvent responseEvent = (APIGatewayResponseEvent) value; + + String contentType = null; + + if (responseEvent.getHeaders() != null) { + for (String key : responseEvent.getHeaders().asMap().keySet()) { + ctx.addResponseHeader(key, responseEvent.getHeaders().getAllValues(key)); + } + + Optional userSetContentType = responseEvent.getHeaders().get(CONTENT_TYPE_HEADER); + if (userSetContentType.isPresent()) { + contentType = userSetContentType.get(); + } + } + + if (responseEvent.getStatus() != null) { + ctx.setStatusCode(responseEvent.getStatus()); + } + + Optional body = Optional.ofNullable(responseEvent.getBody()); + + Type gs = method.getTargetClass().getGenericSuperclass(); + if (gs instanceof ParameterizedType) { + Type responseGeneric = ((ParameterizedType) gs).getActualTypeArguments()[1]; // response type param + JavaType responseType = TypeFactory + .defaultInstance() + .constructType(responseGeneric); + + if (responseType.hasRawClass(String.class)) { + if (contentType == null) { + contentType = "text/plain"; + } + return Optional.of(OutputEvent.fromBytes(((String) body.orElse("")).getBytes(), OutputEvent.Status.Success, contentType)); + } + if (contentType == null) { + contentType = "application/json"; + } + + try { + return Optional.of(OutputEvent.fromBytes(objectMapper(currentContext).writeValueAsBytes(body.orElse("")), OutputEvent.Status.Success, contentType)); + } catch (JsonProcessingException e) { + throw new RuntimeException("Failed to render response to JSON", e); + } + } else { + if (contentType == null) { + contentType = "text/plain"; + } + return Optional.of(OutputEvent.fromBytes(((String) body.orElse("")).getBytes(), OutputEvent.Status.Success, contentType)); + } + + } + + private static RuntimeException coercionFailed(Type paramType, Throwable cause) { + return new RuntimeException("Failed to coerce event to user function parameter type " + paramType, cause); + } + +} \ No newline at end of file diff --git a/fn-events/src/main/java/com/fnproject/events/coercion/ConnectorHubCoercion.java b/fn-events/src/main/java/com/fnproject/events/coercion/ConnectorHubCoercion.java new file mode 100644 index 00000000..7581786f --- /dev/null +++ b/fn-events/src/main/java/com/fnproject/events/coercion/ConnectorHubCoercion.java @@ -0,0 +1,70 @@ +package com.fnproject.events.coercion; + +import static com.fnproject.events.coercion.Util.hasEventFnInHierarchy; +import java.io.IOException; +import java.lang.reflect.Type; +import java.util.List; +import java.util.Optional; +import com.fasterxml.jackson.databind.JavaType; +import com.fasterxml.jackson.databind.ObjectMapper; +import com.fnproject.events.ConnectorHubFunction; +import com.fnproject.events.input.ConnectorHubBatch; +import com.fnproject.fn.api.InputCoercion; +import com.fnproject.fn.api.InputEvent; +import com.fnproject.fn.api.InvocationContext; +import com.fnproject.fn.api.MethodWrapper; + + +public class ConnectorHubCoercion implements InputCoercion> { + + private static final ConnectorHubCoercion instance = new ConnectorHubCoercion(); + static final String OM_KEY = ConnectorHubCoercion.class.getCanonicalName() + ".om"; + + public static ConnectorHubCoercion instance() { + return instance; + } + + private static ObjectMapper objectMapper(InvocationContext ctx) { + Optional omo = ctx.getRuntimeContext().getAttribute(OM_KEY, ObjectMapper.class); + if (!omo.isPresent()) { + ObjectMapper om = new ObjectMapper(); + + ctx.getRuntimeContext().setAttribute(OM_KEY, om); + return om; + } else { + return omo.get(); + } + } + + @Override + public Optional> tryCoerceParam(InvocationContext currentContext, int param, InputEvent input, MethodWrapper method) { + if (hasEventFnInHierarchy(method.getTargetClass().getSuperclass(), ConnectorHubFunction.class)) { + Type type = method.getTargetMethod().getGenericParameterTypes()[param]; + JavaType javaType = objectMapper(currentContext).constructType(type); + List requestGenerics = javaType.getBindings().getTypeParameters(); + + ObjectMapper mapper = objectMapper(currentContext); + + JavaType elementType = requestGenerics.get(0); + JavaType listType = mapper.getTypeFactory() + .constructCollectionType(List.class, elementType); + + List batchedItems = input.consumeBody(is -> { + try { + return mapper.readValue(is, listType); + } catch (IOException e) { + throw coercionFailed(listType, e); + } + }); + + return Optional.of(new ConnectorHubBatch(batchedItems, currentContext.getRequestHeaders())); + } else { + return Optional.empty(); + } + } + + private static RuntimeException coercionFailed(Type paramType, Throwable cause) { + return new RuntimeException("Failed to coerce event to user function parameter type " + paramType, cause); + } + +} \ No newline at end of file diff --git a/fn-events/src/main/java/com/fnproject/events/coercion/NotificationCoercion.java b/fn-events/src/main/java/com/fnproject/events/coercion/NotificationCoercion.java new file mode 100644 index 00000000..dbe01092 --- /dev/null +++ b/fn-events/src/main/java/com/fnproject/events/coercion/NotificationCoercion.java @@ -0,0 +1,71 @@ +package com.fnproject.events.coercion; + +import static com.fnproject.events.coercion.Util.hasEventFnInHierarchy; +import static com.fnproject.events.coercion.Util.readBodyAsString; +import java.io.IOException; +import java.lang.reflect.Type; +import java.util.List; +import java.util.Optional; +import com.fasterxml.jackson.databind.JavaType; +import com.fasterxml.jackson.databind.ObjectMapper; +import com.fnproject.events.NotificationFunction; +import com.fnproject.events.input.NotificationMessage; +import com.fnproject.fn.api.InputCoercion; +import com.fnproject.fn.api.InputEvent; +import com.fnproject.fn.api.InvocationContext; +import com.fnproject.fn.api.MethodWrapper; + + +public class NotificationCoercion implements InputCoercion> { + + private static final NotificationCoercion instance = new NotificationCoercion(); + static final String OM_KEY = NotificationCoercion.class.getCanonicalName() + ".om"; + + public static NotificationCoercion instance() { + return instance; + } + + private static ObjectMapper objectMapper(InvocationContext ctx) { + Optional omo = ctx.getRuntimeContext().getAttribute(OM_KEY, ObjectMapper.class); + if (!omo.isPresent()) { + ObjectMapper om = new ObjectMapper(); + + ctx.getRuntimeContext().setAttribute(OM_KEY, om); + return om; + } else { + return omo.get(); + } + } + + @Override + public Optional> tryCoerceParam(InvocationContext currentContext, int param, InputEvent input, MethodWrapper method) { + if (hasEventFnInHierarchy(method.getTargetClass().getSuperclass(), NotificationFunction.class)) { + Type type = method.getTargetMethod().getGenericParameterTypes()[param]; + JavaType javaType = objectMapper(currentContext).constructType(type); + List requestGenerics = javaType.getBindings().getTypeParameters(); + + JavaType elementType = requestGenerics.get(0); + if (elementType.hasRawClass(String.class)) { + return Optional.of(new NotificationMessage(readBodyAsString(input), currentContext.getRequestHeaders())); + } + + ObjectMapper mapper = objectMapper(currentContext); + Object messageContent = input.consumeBody(is -> { + try { + return mapper.readValue(is, elementType); + } catch (IOException e) { + throw coercionFailed(elementType, e); + } + }); + + return Optional.of(new NotificationMessage<>(messageContent, currentContext.getRequestHeaders())); + } else { + return Optional.empty(); + } + } + + private static RuntimeException coercionFailed(Type paramType, Throwable cause) { + return new RuntimeException("Failed to coerce event to user function parameter type " + paramType, cause); + } + +} \ No newline at end of file diff --git a/fn-events/src/main/java/com/fnproject/events/coercion/Util.java b/fn-events/src/main/java/com/fnproject/events/coercion/Util.java new file mode 100644 index 00000000..e9c36f08 --- /dev/null +++ b/fn-events/src/main/java/com/fnproject/events/coercion/Util.java @@ -0,0 +1,25 @@ +package com.fnproject.events.coercion; + +import java.io.IOException; +import java.nio.charset.StandardCharsets; +import com.fnproject.fn.api.InputEvent; +import org.apache.commons.io.IOUtils; + +public class Util { + public static boolean hasEventFnInHierarchy(Class targetClass, Class eventClass) { + for (Class c = targetClass; c != null; c = c.getSuperclass()) { + if (c == eventClass) return true; + } + return false; + } + + static String readBodyAsString(InputEvent input) { + return input.consumeBody(is -> { + try { + return IOUtils.toString(is, StandardCharsets.UTF_8); + } catch (IOException e) { + throw new RuntimeException("Error reading input as string", e); + } + }); + } +} diff --git a/fn-events/src/main/java/com/fnproject/events/coercion/jackson/Base64ToTypeDeserializer.java b/fn-events/src/main/java/com/fnproject/events/coercion/jackson/Base64ToTypeDeserializer.java new file mode 100644 index 00000000..26b91a5c --- /dev/null +++ b/fn-events/src/main/java/com/fnproject/events/coercion/jackson/Base64ToTypeDeserializer.java @@ -0,0 +1,116 @@ +package com.fnproject.events.coercion.jackson; + + +import com.fasterxml.jackson.core.JsonParser; +import com.fasterxml.jackson.core.JsonToken; +import com.fasterxml.jackson.core.ObjectCodec; +import com.fasterxml.jackson.databind.BeanProperty; +import com.fasterxml.jackson.databind.DeserializationContext; +import com.fasterxml.jackson.databind.JavaType; +import com.fasterxml.jackson.databind.JsonDeserializer; +import com.fasterxml.jackson.databind.ObjectMapper; +import com.fasterxml.jackson.databind.deser.ContextualDeserializer; +import com.fasterxml.jackson.databind.jsontype.TypeDeserializer; + +import java.io.IOException; +import java.nio.charset.StandardCharsets; +import java.util.Base64; + +public class Base64ToTypeDeserializer extends JsonDeserializer implements ContextualDeserializer { + private final JavaType targetType; + + public Base64ToTypeDeserializer() { + this(null); + } + + private Base64ToTypeDeserializer(JavaType targetType) { + this.targetType = targetType; + } + + @Override + public Object deserialize(JsonParser p, DeserializationContext ctxt) throws IOException { + final JavaType t = (targetType != null) ? targetType : ctxt.constructType(Object.class); + final ObjectCodec codec = p.getCodec(); + final ObjectMapper mapper = (codec instanceof ObjectMapper) ? (ObjectMapper) codec : new ObjectMapper(); + + JsonToken tok = p.currentToken(); + if (tok == JsonToken.VALUE_NULL) { + return null; + } + + // If we didn't receive a string, just let Jackson handle it normally (it might already be JSON) + if (tok != JsonToken.VALUE_STRING) { + return codec.readValue(p, t); + } + + // We have a string; attempt base64 decode first + String v = p.getValueAsString(); + if (v == null) { + return null; + } + + try { + byte[] bytes = Base64.getDecoder().decode(v); + + // If T is String, return textual content of decoded bytes + if (t.isTypeOrSubTypeOf(String.class)) { + return new String(bytes, StandardCharsets.UTF_8); + } + + // Otherwise, treat decoded bytes as JSON and map to target type T + try (JsonParser jp = mapper.getFactory().createParser(bytes)) { + return mapper.readValue(jp, t); + } + } catch (IllegalArgumentException notBase64) { + // Not valid base64; fallback behavior + + // If T is String, return the raw string as-is + if (t.isTypeOrSubTypeOf(String.class)) { + return v; + } + + // Try to interpret the string itself as JSON for T + // (common case: string contains JSON payload but wasn't base64-encoded) + try { + return mapper.readValue(v, t); + } catch (IOException cannotParseAsJson) { + // Final fallback: wrap as JSON string and let Jackson coerce if possible (e.g., to primitive/wrapper) + // If not compatible, throw a Jackson-standard exception + try { + return mapper.readValue(mapper.writeValueAsBytes(v), t); + } catch (IOException e) { + return ctxt.reportInputMismatch( + t, + "Cannot coerce non-base64 string value into %s: %s", + t.toString(), e.getMessage() + ); + } + } + } + } + + @Override + public JsonDeserializer createContextual(DeserializationContext ctxt, BeanProperty property) { + JavaType t = (property != null) ? property.getType() : ctxt.getContextualType(); + if (t == null || t.hasRawClass(Object.class)) { + // On constructor params this often mirrors property.getType(); if still Object, + // try the context’s parent (the bean being created) via getContextualType() + JavaType enclosing = ctxt.getContextualType(); + if (enclosing != null && enclosing.containedTypeCount() > 0) { + t = enclosing.containedType(0); // StreamingData -> T + } + if (t == null || t.hasRawClass(Object.class)) { + t = ctxt.constructType(Object.class); + } + } + + return new Base64ToTypeDeserializer(t); + + } + + @Override + public Object deserializeWithType(JsonParser p, DeserializationContext ctxt, TypeDeserializer typeDeserializer) throws IOException { + return deserialize(p, ctxt); + } + +} \ No newline at end of file diff --git a/fn-events/src/main/java/com/fnproject/events/input/APIGatewayRequestEvent.java b/fn-events/src/main/java/com/fnproject/events/input/APIGatewayRequestEvent.java new file mode 100644 index 00000000..ebfb4ad3 --- /dev/null +++ b/fn-events/src/main/java/com/fnproject/events/input/APIGatewayRequestEvent.java @@ -0,0 +1,62 @@ +package com.fnproject.events.input; + +import java.util.Objects; +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fnproject.fn.api.Headers; +import com.fnproject.fn.api.QueryParameters; + +@JsonIgnoreProperties(ignoreUnknown = true) +public class APIGatewayRequestEvent { + + private final QueryParameters queryParameters; + private final T body; + private final String method; + private final String requestUrl; + private final Headers headers; + + public APIGatewayRequestEvent(QueryParameters queryParameters, T body, String method, String requestUrl, Headers headers) { + this.queryParameters = queryParameters; + this.body = body; + this.method = method; + this.requestUrl = requestUrl; + this.headers = headers; + } + + public T getBody() { + return body; + } + + public QueryParameters getQueryParameters() { + return queryParameters; + } + + public String getMethod() { + return method; + } + + public Headers getHeaders() { + return headers; + } + + public String getRequestUrl() { + return requestUrl; + } + + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } + APIGatewayRequestEvent that = (APIGatewayRequestEvent) o; + return Objects.equals(queryParameters, that.queryParameters) && Objects.equals(body, that.body) && Objects.equals(method, that.method) && + Objects.equals(requestUrl, that.requestUrl) && Objects.equals(headers, that.headers); + } + + @Override + public int hashCode() { + return Objects.hash(queryParameters, body, method, requestUrl, headers); + } +} \ No newline at end of file diff --git a/fn-events/src/main/java/com/fnproject/events/input/ConnectorHubBatch.java b/fn-events/src/main/java/com/fnproject/events/input/ConnectorHubBatch.java new file mode 100644 index 00000000..e677bbd9 --- /dev/null +++ b/fn-events/src/main/java/com/fnproject/events/input/ConnectorHubBatch.java @@ -0,0 +1,41 @@ +package com.fnproject.events.input; + +import java.util.List; +import java.util.Objects; +import com.fnproject.fn.api.Headers; + +public class ConnectorHubBatch { + private final Headers headers; + private final List batch; + + public ConnectorHubBatch(List batch, Headers headers) { + this.batch = batch; + this.headers = headers; + } + + public List getBatch() { + return batch; + } + + public Headers getHeaders() { + return headers; + } + + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } + ConnectorHubBatch that = (ConnectorHubBatch) o; + return Objects.equals(headers, that.headers) && Objects.equals(batch, that.batch); + } + + @Override + public int hashCode() { + return Objects.hash(headers, batch); + } + +} diff --git a/fn-events/src/main/java/com/fnproject/events/input/NotificationMessage.java b/fn-events/src/main/java/com/fnproject/events/input/NotificationMessage.java new file mode 100644 index 00000000..b0f7272b --- /dev/null +++ b/fn-events/src/main/java/com/fnproject/events/input/NotificationMessage.java @@ -0,0 +1,40 @@ +package com.fnproject.events.input; + +import java.util.Objects; +import com.fnproject.fn.api.Headers; + +public class NotificationMessage { + private final T content; + private final Headers headers; + + public NotificationMessage(T content, Headers headers) { + this.content = content; + this.headers = headers; + } + + public T getContent() { + return content; + } + + public Headers getHeaders() { + return headers; + } + + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } + NotificationMessage message = (NotificationMessage) o; + return Objects.equals(content, message.content) && Objects.equals(headers, message.headers); + } + + @Override + public int hashCode() { + return Objects.hash(content, headers); + } + +} diff --git a/fn-events/src/main/java/com/fnproject/events/input/sch/Datapoint.java b/fn-events/src/main/java/com/fnproject/events/input/sch/Datapoint.java new file mode 100644 index 00000000..704e02ec --- /dev/null +++ b/fn-events/src/main/java/com/fnproject/events/input/sch/Datapoint.java @@ -0,0 +1,63 @@ +package com.fnproject.events.input.sch; + +import java.util.Date; +import java.util.Objects; +import com.fasterxml.jackson.annotation.JsonCreator; +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonProperty; + +@JsonIgnoreProperties(ignoreUnknown = true) +public final class Datapoint { + private final Date timestamp; + private final Double value; + private final Integer count; + + @JsonCreator + public Datapoint( + @JsonProperty("timestamp") Date timestamp, + @JsonProperty("value") Double value, + @JsonProperty("count") Integer count) { + this.timestamp = timestamp; + this.value = value; + this.count = count; + } + + public Date getTimestamp() { + return timestamp; + } + + public Double getValue() { + return value; + } + + public Integer getCount() { + return count; + } + + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } + Datapoint datapoint = (Datapoint) o; + return Objects.equals(timestamp, datapoint.timestamp) && Objects.equals(value, datapoint.value) && Objects.equals(count, datapoint.count); + } + + @Override + public int hashCode() { + return Objects.hash(timestamp, value, count); + } + + @Override + public String toString() { + return "Datapoint{" + + "timestamp=" + timestamp + + ", value=" + value + + ", count=" + count + + '}'; + } + +} \ No newline at end of file diff --git a/fn-events/src/main/java/com/fnproject/events/input/sch/LoggingData.java b/fn-events/src/main/java/com/fnproject/events/input/sch/LoggingData.java new file mode 100644 index 00000000..b8db16af --- /dev/null +++ b/fn-events/src/main/java/com/fnproject/events/input/sch/LoggingData.java @@ -0,0 +1,106 @@ +package com.fnproject.events.input.sch; + +import java.util.Date; +import java.util.Map; +import java.util.Objects; +import com.fasterxml.jackson.annotation.JsonCreator; +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonProperty; + +@JsonIgnoreProperties(ignoreUnknown = true) +public class LoggingData { + private final String id; + private final String source; + private final String specversion; + private final String subject; + private final String type; + private final Map data; + private final Map oracle; + private final Date time; + + @JsonCreator + public LoggingData( + @JsonProperty("id") String id, + @JsonProperty("source") String source, + @JsonProperty("specversion") String specversion, + @JsonProperty("subject") String subject, + @JsonProperty("type") String type, + @JsonProperty("data") Map data, + @JsonProperty("oracle") Map oracle, + @JsonProperty("time") Date time) { + + this.id = id; + this.source = source; + this.specversion = specversion; + this.subject = subject; + this.type = type; + this.data = data; + this.oracle = oracle; + this.time = time; + } + + public String getId() { + return id; + } + + public String getSource() { + return source; + } + + public String getSpecversion() { + return specversion; + } + + public String getSubject() { + return subject; + } + + public Map getData() { + return data; + } + + public Map getOracle() { + return oracle; + } + + public Date getTime() { + return time; + } + + public String getType() { + return type; + } + + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } + LoggingData that = (LoggingData) o; + return Objects.equals(id, that.id) && Objects.equals(source, that.source) && Objects.equals(specversion, that.specversion) && + Objects.equals(subject, that.subject) && Objects.equals(type, that.type) && Objects.equals(data, that.data) && + Objects.equals(oracle, that.oracle) && Objects.equals(time, that.time); + } + + @Override + public int hashCode() { + return Objects.hash(id, source, specversion, subject, type, data, oracle, time); + } + + @Override + public String toString() { + return "LoggingData{" + + "id='" + id + '\'' + + ", source='" + source + '\'' + + ", specversion='" + specversion + '\'' + + ", subject='" + subject + '\'' + + ", type='" + type + '\'' + + ", data=" + data + + ", oracle=" + oracle + + ", time=" + time + + '}'; + } +} \ No newline at end of file diff --git a/fn-events/src/main/java/com/fnproject/events/input/sch/MetricData.java b/fn-events/src/main/java/com/fnproject/events/input/sch/MetricData.java new file mode 100644 index 00000000..d427ecab --- /dev/null +++ b/fn-events/src/main/java/com/fnproject/events/input/sch/MetricData.java @@ -0,0 +1,81 @@ +package com.fnproject.events.input.sch; + +import com.fasterxml.jackson.annotation.JsonCreator; +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonProperty; + +import java.util.List; +import java.util.Map; + +@JsonIgnoreProperties(ignoreUnknown = true) +public class MetricData { + private final String namespace; + private final String resourceGroup; + private final String compartmentId; + private final String name; + private final Map dimensions; + private final Map metadata; + private final List datapoints; + + @JsonCreator + public MetricData( + @JsonProperty("namespace") String namespace, + @JsonProperty("resourceGroup") String resourceGroup, + @JsonProperty("compartmentId") String compartmentId, + @JsonProperty("name") String name, + @JsonProperty("dimensions") Map dimensions, + @JsonProperty("metadata") Map metadata, + @JsonProperty("datapoints") List datapoints) { + + this.namespace = namespace; + this.resourceGroup = resourceGroup; + this.compartmentId = compartmentId; + this.name = name; + this.dimensions = dimensions; + this.metadata = metadata; + this.datapoints = datapoints; + } + + public String getNamespace() { + return namespace; + } + + public String getResourceGroup() { + return resourceGroup; + } + + public String getCompartmentId() { + return compartmentId; + } + + public String getName() { + return name; + } + + public Map getDimensions() { + return dimensions; + } + + public Map getMetadata() { + return metadata; + } + + public List getDatapoints() { + return datapoints; + } + + + @Override + public String toString() { + return "MetricData{" + + "namespace='" + namespace + '\'' + + ", resourceGroup='" + resourceGroup + '\'' + + ", compartmentId='" + compartmentId + '\'' + + ", name='" + name + '\'' + + ", dimensions=" + dimensions + + ", metadata=" + metadata + + ", datapoints=" + datapoints + + '}'; + } + +} \ No newline at end of file diff --git a/fn-events/src/main/java/com/fnproject/events/input/sch/StreamingData.java b/fn-events/src/main/java/com/fnproject/events/input/sch/StreamingData.java new file mode 100644 index 00000000..b93ee640 --- /dev/null +++ b/fn-events/src/main/java/com/fnproject/events/input/sch/StreamingData.java @@ -0,0 +1,90 @@ +package com.fnproject.events.input.sch; + +import java.util.Date; +import java.util.Objects; + +import com.fasterxml.jackson.annotation.JsonCreator; +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonProperty; +import com.fasterxml.jackson.databind.annotation.JsonDeserialize; +import com.fnproject.events.coercion.jackson.Base64ToTypeDeserializer; + +@JsonIgnoreProperties(ignoreUnknown = true) +public class StreamingData { + private final String stream; + private final String partition; + private final String key; + private final T value; + private final String offset; + private final Date timestamp; + + @JsonCreator + public StreamingData( + @JsonProperty("stream") String stream, + @JsonProperty("partition") String partition, + @JsonProperty("key") String key, + @JsonDeserialize(using = Base64ToTypeDeserializer.class) @JsonProperty("value") T value, + @JsonProperty("offset") String offset, + @JsonProperty("time") Date timestamp) { + this.stream = stream; + this.partition = partition; + this.key = key; + this.value = value; + this.offset = offset; + this.timestamp = timestamp; + } + + public String getStream() { + return stream; + } + + public String getPartition() { + return partition; + } + + public String getKey() { + return key; + } + + public T getValue() { + return value; + } + + public Date getTimestamp() { + return timestamp; + } + + public String getOffset() { + return offset; + } + + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } + StreamingData that = (StreamingData) o; + return Objects.equals(stream, that.stream) && Objects.equals(partition, that.partition) && Objects.equals(key, that.key) && + Objects.equals(value, that.value) && Objects.equals(offset, that.offset) && Objects.equals(timestamp, that.timestamp); + } + + @Override + public int hashCode() { + return Objects.hash(stream, partition, key, value, offset, timestamp); + } + + @Override + public String toString() { + return "StreamingData{" + + "stream='" + stream + '\'' + + ", partition='" + partition + '\'' + + ", key='" + key + '\'' + + ", value=" + value + + ", offset='" + offset + '\'' + + ", timestamp=" + timestamp + + '}'; + } +} \ No newline at end of file diff --git a/fn-events/src/main/java/com/fnproject/events/mapper/APIGatewayRequestEventMapper.java b/fn-events/src/main/java/com/fnproject/events/mapper/APIGatewayRequestEventMapper.java new file mode 100644 index 00000000..d7fb4f41 --- /dev/null +++ b/fn-events/src/main/java/com/fnproject/events/mapper/APIGatewayRequestEventMapper.java @@ -0,0 +1,19 @@ +package com.fnproject.events.mapper; + +import com.fnproject.events.input.APIGatewayRequestEvent; +import com.fnproject.fn.api.Headers; +import com.fnproject.fn.api.QueryParameters; +import com.fnproject.fn.api.httpgateway.HTTPGatewayContext; +import com.fnproject.fn.runtime.httpgateway.QueryParametersImpl; + +public class APIGatewayRequestEventMapper implements ApiGatewayRequestMapper { + + public APIGatewayRequestEvent toApiGatewayRequestEvent(HTTPGatewayContext context, T body) { + QueryParameters queryParameters = + context.getQueryParameters() != null ? context.getQueryParameters() : new QueryParametersImpl(); + Headers headers = + context.getHeaders() != null ? context.getHeaders() : Headers.emptyHeaders(); + + return new APIGatewayRequestEvent<>(queryParameters, body, context.getMethod(), context.getRequestURL(), headers); + } +} diff --git a/fn-events/src/main/java/com/fnproject/events/mapper/ApiGatewayRequestMapper.java b/fn-events/src/main/java/com/fnproject/events/mapper/ApiGatewayRequestMapper.java new file mode 100644 index 00000000..bb529d09 --- /dev/null +++ b/fn-events/src/main/java/com/fnproject/events/mapper/ApiGatewayRequestMapper.java @@ -0,0 +1,8 @@ +package com.fnproject.events.mapper; + +import com.fnproject.events.input.APIGatewayRequestEvent; +import com.fnproject.fn.api.httpgateway.HTTPGatewayContext; + +public interface ApiGatewayRequestMapper { + APIGatewayRequestEvent toApiGatewayRequestEvent(HTTPGatewayContext context, T body); +} diff --git a/fn-events/src/main/java/com/fnproject/events/output/APIGatewayResponseEvent.java b/fn-events/src/main/java/com/fnproject/events/output/APIGatewayResponseEvent.java new file mode 100644 index 00000000..f32a75f4 --- /dev/null +++ b/fn-events/src/main/java/com/fnproject/events/output/APIGatewayResponseEvent.java @@ -0,0 +1,52 @@ +package com.fnproject.events.output; + +import com.fnproject.fn.api.Headers; + +public class APIGatewayResponseEvent { + private final T body; + private final Integer statusCode; + private final Headers headers; + + private APIGatewayResponseEvent(T body, Integer statusCode, Headers headers) { + this.headers = headers; + this.body = body; + this.statusCode = statusCode; + } + + public static class Builder { + private T body; + private Integer statusCode; + private Headers headers; + + public Builder body(T body) { + this.body = body; + return this; + } + + public Builder statusCode(int statusCode) { + this.statusCode = statusCode; + return this; + } + + public Builder headers(Headers headers) { + this.headers = headers; + return this; + } + + public APIGatewayResponseEvent build() { + return new APIGatewayResponseEvent<>(this.body, this.statusCode, this.headers); + } + } + + public Integer getStatus() { + return statusCode; + } + + public Headers getHeaders() { + return headers; + } + + public T getBody() { + return body; + } +} \ No newline at end of file diff --git a/fn-events/src/test/java/com/fnproject/events/APIGatewayFunctionTest.java b/fn-events/src/test/java/com/fnproject/events/APIGatewayFunctionTest.java new file mode 100644 index 00000000..89f817f6 --- /dev/null +++ b/fn-events/src/test/java/com/fnproject/events/APIGatewayFunctionTest.java @@ -0,0 +1,93 @@ +package com.fnproject.events; + +import static org.junit.Assert.assertEquals; +import com.fnproject.events.testfns.apigatewayfns.APIGatewayTestFunction; +import com.fnproject.events.testfns.apigatewayfns.ListAPIGatewayTestFunction; +import com.fnproject.events.testfns.apigatewayfns.StringAPIGatewayTestFunction; +import com.fnproject.events.testfns.apigatewayfns.UncheckedAPIGatewayTestFunction; +import com.fnproject.fn.testing.FnTestingRule; +import org.junit.Rule; +import org.junit.Test; + +public class APIGatewayFunctionTest { + + @Rule + public final FnTestingRule fnRule = FnTestingRule.createDefault(); + + @Test + public void testStringHandler() { + fnRule + .givenEvent() + .withHeader("Fn-Http-H-Custom-Header", "headerValue") + .withHeader("Fn-Http-Method", "POST") + .withHeader("Fn-Http-Request-Url", "/v1?param1=value%20with%20spaces") + .withBody("plain string body") + .enqueue(); + + fnRule.thenRun(StringAPIGatewayTestFunction.class, "handler"); + + assertEquals("test response", fnRule.getOnlyResult().getBodyAsString()); + assertEquals("200", fnRule.getOnlyResult().getHeaders().get("Fn-Http-Status").get()); + assertEquals("headerValue", fnRule.getOnlyResult().getHeaders().get("Fn-Http-H-Custom-Header").get()); + } + + @Test + public void testObjectHandler() { + fnRule + .givenEvent() + .withHeader("Fn-Http-H-Custom-Header", "headerValue") + .withHeader("Fn-Http-Method", "POST") + .withHeader("Fn-Http-Request-Url", "/v1?param1=value%20with%20spaces") + .withBody("{\"name\":\"chicken\",\"age\":2}") + .enqueue(); + + fnRule.thenRun(APIGatewayTestFunction.class, "handler"); + + assertEquals("{\"brand\":\"ford\",\"wheels\":4}", fnRule.getOnlyResult().getBodyAsString()); + } + + @Test + public void testNullObjectPropertyHandler() { + fnRule + .givenEvent() + .withHeader("Fn-Http-H-Custom-Header", "headerValue") + .withHeader("Fn-Http-Method", "POST") + .withHeader("Fn-Http-Request-Url", "/v1?param1=value%20with%20spaces") + .withBody("{\"age\":2}") + .enqueue(); + + fnRule.thenRun(APIGatewayTestFunction.class, "handler"); + + assertEquals("{\"brand\":\"ford\",\"wheels\":4}", fnRule.getOnlyResult().getBodyAsString()); + } + + @Test + public void testListObjectHandler() { + fnRule + .givenEvent() + .withHeader("Fn-Http-H-Custom-Header", "headerValue") + .withHeader("Fn-Http-Method", "POST") + .withHeader("Fn-Http-Request-Url", "/v1?param1=value%20with%20spaces") + .withBody("[{\"name\":\"chicken\",\"age\":2}]") + .enqueue(); + + fnRule.thenRun(ListAPIGatewayTestFunction.class, "handler"); + + assertEquals("[{\"brand\":\"ford\",\"wheels\":4}]", fnRule.getOnlyResult().getBodyAsString()); + } + + @Test + public void testUncheckedHandler() { + fnRule + .givenEvent() + .withHeader("Fn-Http-H-Custom-Header", "headerValue") + .withHeader("Fn-Http-Method", "POST") + .withHeader("Fn-Http-Request-Url", "/v1?param1=value%20with%20spaces") + .withBody("plain string body") + .enqueue(); + + fnRule.thenRun(UncheckedAPIGatewayTestFunction.class, "handler"); + + assertEquals("test response", fnRule.getOnlyResult().getBodyAsString()); + } +} \ No newline at end of file diff --git a/fn-events/src/test/java/com/fnproject/events/ConnectorHubFunctionTest.java b/fn-events/src/test/java/com/fnproject/events/ConnectorHubFunctionTest.java new file mode 100644 index 00000000..7e6d97c2 --- /dev/null +++ b/fn-events/src/test/java/com/fnproject/events/ConnectorHubFunctionTest.java @@ -0,0 +1,242 @@ +package com.fnproject.events; + +import static org.junit.Assert.assertEquals; +import java.util.Base64; +import com.fasterxml.jackson.core.JsonProcessingException; +import com.fasterxml.jackson.databind.ObjectMapper; +import com.fnproject.events.testfns.Animal; +import com.fnproject.events.testfns.connectorhub.LoggingSourceTestFunction; +import com.fnproject.events.testfns.connectorhub.MonitorSourceTestFunction; +import com.fnproject.events.testfns.connectorhub.QueueSourceObjectTestFunction; +import com.fnproject.events.testfns.connectorhub.QueueSourceStringTestFunction; +import com.fnproject.events.testfns.connectorhub.StreamingSourceObjectTestFunction; +import com.fnproject.events.testfns.connectorhub.StreamingSourceStringTestFunction; +import com.fnproject.fn.testing.FnTestingRule; +import org.junit.Rule; +import org.junit.Test; + +public class ConnectorHubFunctionTest { + + @Rule + public final FnTestingRule fnRule = FnTestingRule.createDefault(); + + @Test + public void testMonitorSourceTestFunction() { + fnRule + .givenEvent() + .withBody("[\n" + + " {\n" + + " \"namespace\":\"oci_computeagent\",\n" + + " \"compartmentId\":\"ocid1.tenancy.oc1..exampleuniqueID\",\n" + + " \"name\":\"DiskBytesRead\",\n" + + " \"dimensions\":{\n" + + " \"resourceId\":\"ocid1.instance.region1.phx.exampleuniqueID\"\n" + + " },\n" + + " \"metadata\":{\n" + + " \"unit\":\"bytes\"\n" + + " },\n" + + " \"datapoints\":[\n" + + " {\n" + + " \"timestamp\":\"1761318377414\",\n" + + " \"value\":10.4\n" + + " },\n" + + " {\n" + + " \"timestamp\":\"1761318377414\",\n" + + " \"value\":11.3\n" + + " }\n" + + " ]\n" + + " }\n" + + "]") + .enqueue(); + + fnRule.thenRun(MonitorSourceTestFunction.class, "handler"); + + int exitCode = fnRule.getLastExitCode(); + assertEquals(0, exitCode); + } + + @Test + public void testEmptyMonitorSourceTestFunction() { + fnRule + .givenEvent() + .withBody("[]") + .enqueue(); + + fnRule.thenRun(MonitorSourceTestFunction.class, "handler"); + + int exitCode = fnRule.getLastExitCode(); + assertEquals(0, exitCode); + } + + @Test + public void testLoggingSourceTestFunction() { + fnRule + .givenEvent() + .withBody("[\n" + + " {\n" + + " \"data\": {\n" + + " \"applicationId\": \"ocid1.fnapp.oc1.abc\",\n" + + " \"containerId\": \"n/a\",\n" + + " \"functionId\": \"ocid1.fnfunc.oc1.abc\",\n" + + " \"message\": \"Received function invocation request\",\n" + + " \"opcRequestId\": \"/abc/def\",\n" + + " \"requestId\": \"/def/abc\",\n" + + " \"src\": \"stdout\"\n" + + " },\n" + + " \"id\": \"abc-zyx\",\n" + + " \"oracle\": {\n" + + " \"compartmentid\": \"ocid1.tenancy.oc1..xyz\",\n" + + " \"ingestedtime\": \"2025-10-23T15:45:19.457Z\",\n" + + " \"loggroupid\": \"ocid1.loggroup.oc1.abc\",\n" + + " \"logid\": \"ocid1.log.oc1.def\",\n" + + " \"tenantid\": \"ocid1.tenancy.oc1..xyz\"\n" + + " },\n" + + " \"source\": \"your-log\",\n" + + " \"specversion\": \"1.0\",\n" + + " \"subject\": \"schedule\",\n" + + " \"time\": \"2025-10-23T15:45:17.239Z\",\n" + + " \"type\": \"com.oraclecloud.functions.application.functioninvoke\"\n" + + " }\n" + + "]") + .enqueue(); + + fnRule.thenRun(LoggingSourceTestFunction.class, "handler"); + + int exitCode = fnRule.getLastExitCode(); + assertEquals(0, exitCode); + } + + @Test + public void testEmptyLoggingSourceTestFunction() { + fnRule + .givenEvent() + .withBody("[]") + .enqueue(); + + fnRule.thenRun(LoggingSourceTestFunction.class, "handler"); + + int exitCode = fnRule.getLastExitCode(); + assertEquals(0, exitCode); + } + + @Test + public void testStreamingSourceStringTestFunction() { + fnRule + .givenEvent() + .withBody("[" + + "{\"stream\":\"stream-name\"," + + "\"partition\":\"0\"," + + "\"key\":null," + + "\"value\":\"U2VudCBhIHBsYWluIG1lc3NhZ2U=\"," + + "\"offset\":3," + + "\"timestamp\":1761223385480" + + "}" + + "]") + .enqueue(); + + fnRule.thenRun(StreamingSourceStringTestFunction.class, "handler"); + + int exitCode = fnRule.getLastExitCode(); + assertEquals(0, exitCode); + } + + @Test + public void testEmptyStreamingSourceStringTestFunction() { + fnRule + .givenEvent() + .withBody("[]") + .enqueue(); + + fnRule.thenRun(StreamingSourceStringTestFunction.class, "handler"); + + int exitCode = fnRule.getLastExitCode(); + assertEquals(0, exitCode); + } + + @Test + public void testStreamingSourceObjectTestFunction() throws JsonProcessingException { + Animal animal = new Animal("foo", 4); + String encodedAnimal = Base64.getEncoder().encodeToString(new ObjectMapper().writeValueAsBytes(animal)); + fnRule + .givenEvent() + .withBody("[" + + "{\"stream\":\"stream-name\"," + + "\"partition\":\"0\"," + + "\"key\":null," + + "\"value\":\"" + encodedAnimal + "\"," + + "\"offset\":3," + + "\"timestamp\":1761223385480" + + "}" + + "]") + .enqueue(); + + fnRule.thenRun(StreamingSourceObjectTestFunction.class, "handler"); + + int exitCode = fnRule.getLastExitCode(); + assertEquals(0, exitCode); + } + + @Test + public void testQueueSourceStringTestFunction() { + fnRule + .givenEvent() + .withBody("[\"a plain string, end\", \"another string\"]") + .enqueue(); + + fnRule.thenRun(QueueSourceStringTestFunction.class, "handler"); + + int exitCode = fnRule.getLastExitCode(); + assertEquals(0, exitCode); + } + + @Test + public void testInvalidQueueSourceStringTestFunction() { + fnRule + .givenEvent() + .withBody("[a plain string, end, another string]") + .enqueue(); + + fnRule.thenRun(QueueSourceStringTestFunction.class, "handler"); + + int exitCode = fnRule.getLastExitCode(); + assertEquals(2, exitCode); + } + + @Test + public void testQueueSourceEmptyTestFunction() { + fnRule + .givenEvent() + .withBody("[]") + .enqueue(); + + fnRule.thenRun(QueueSourceStringTestFunction.class, "handler"); + + int exitCode = fnRule.getLastExitCode(); + assertEquals(0, exitCode); + } + + @Test + public void testQueueSourceObjectTestFunction() { + fnRule + .givenEvent() + .withBody("[{\"name\":\"foo\",\"age\":3}]") + .enqueue(); + + fnRule.thenRun(QueueSourceObjectTestFunction.class, "handler"); + + int exitCode = fnRule.getLastExitCode(); + assertEquals(0, exitCode); + } + + @Test + public void testSourceWithoutBodyThrows() { + fnRule + .givenEvent() + .enqueue(); + + fnRule.thenRun(QueueSourceStringTestFunction.class, "handler"); + + int exitCode = fnRule.getLastExitCode(); + assertEquals(2, exitCode); + } +} \ No newline at end of file diff --git a/fn-events/src/test/java/com/fnproject/events/NotificationFunctionTest.java b/fn-events/src/test/java/com/fnproject/events/NotificationFunctionTest.java new file mode 100644 index 00000000..6628c2c2 --- /dev/null +++ b/fn-events/src/test/java/com/fnproject/events/NotificationFunctionTest.java @@ -0,0 +1,65 @@ +package com.fnproject.events; + +import static org.junit.Assert.assertEquals; +import com.fnproject.events.testfns.notification.NotificationObjectTestFunction; +import com.fnproject.events.testfns.notification.NotificationStringTestFunction; +import com.fnproject.fn.testing.FnTestingRule; +import org.junit.Rule; +import org.junit.Test; + +public class NotificationFunctionTest { + + @Rule + public final FnTestingRule fnRule = FnTestingRule.createDefault(); + + @Test + public void testNotificationTestFunction() { + fnRule + .givenEvent() + .withBody("{\"name\":\"foo\",\"age\":3}") + .enqueue(); + + fnRule.thenRun(NotificationObjectTestFunction.class, "handler"); + + int exitCode = fnRule.getLastExitCode(); + assertEquals(0, exitCode); + } + + @Test + public void testNotificationStringTestFunction() { + fnRule + .givenEvent() + .withBody("test string") + .enqueue(); + + fnRule.thenRun(NotificationStringTestFunction.class, "handler"); + + int exitCode = fnRule.getLastExitCode(); + assertEquals(0, exitCode); + } + + @Test + public void testBlankNotificationStringTestFunction() { + fnRule + .givenEvent() + .withBody("") + .enqueue(); + + fnRule.thenRun(NotificationStringTestFunction.class, "handler"); + + int exitCode = fnRule.getLastExitCode(); + assertEquals(0, exitCode); + } + + @Test + public void testBlankNotificationWithoutBodyTestFunction() { + fnRule + .givenEvent() + .enqueue(); + + fnRule.thenRun(NotificationStringTestFunction.class, "handler"); + + int exitCode = fnRule.getLastExitCode(); + assertEquals(0, exitCode); + } +} \ No newline at end of file diff --git a/fn-events/src/test/java/com/fnproject/events/coercion/APIGatewayCoercionTest.java b/fn-events/src/test/java/com/fnproject/events/coercion/APIGatewayCoercionTest.java new file mode 100644 index 00000000..0d92df1a --- /dev/null +++ b/fn-events/src/test/java/com/fnproject/events/coercion/APIGatewayCoercionTest.java @@ -0,0 +1,398 @@ +package com.fnproject.events.coercion; + +import static com.fnproject.events.coercion.APIGatewayCoercion.OM_KEY; +import static org.junit.Assert.*; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.nio.charset.StandardCharsets; +import java.time.Instant; +import java.util.Collections; +import java.util.HashMap; +import java.util.List; +import java.util.Optional; +import com.fasterxml.jackson.databind.ObjectMapper; +import com.fnproject.events.input.APIGatewayRequestEvent; +import com.fnproject.events.output.APIGatewayResponseEvent; +import com.fnproject.events.testfns.Car; +import com.fnproject.events.testfns.apigatewayfns.APIGatewayTestFunction; +import com.fnproject.events.testfns.Animal; +import com.fnproject.events.testfns.apigatewayfns.GrandChildGatewayTestFunction; +import com.fnproject.events.testfns.apigatewayfns.ListAPIGatewayTestFunction; +import com.fnproject.events.testfns.apigatewayfns.StringAPIGatewayTestFunction; +import com.fnproject.events.testfns.apigatewayfns.UncheckedAPIGatewayTestFunction; +import com.fnproject.fn.api.Headers; +import com.fnproject.fn.api.InputEvent; +import com.fnproject.fn.api.InvocationContext; +import com.fnproject.fn.api.MethodWrapper; +import com.fnproject.fn.api.OutputEvent; +import com.fnproject.fn.api.RuntimeContext; +import com.fnproject.fn.runtime.DefaultFunctionInvocationContext; +import com.fnproject.fn.runtime.DefaultMethodWrapper; +import com.fnproject.fn.runtime.FunctionRuntimeContext; +import com.fnproject.fn.runtime.ReadOnceInputEvent; +import org.junit.Before; +import org.junit.Test; + + +public class APIGatewayCoercionTest { + private APIGatewayCoercion coercion; + private InvocationContext requestinvocationContext; + private DefaultFunctionInvocationContext responseInvocationContext; + + @Before + public void setUp() { + coercion = APIGatewayCoercion.instance(); + requestinvocationContext = mock(InvocationContext.class); + RuntimeContext runtimeContext = mock(RuntimeContext.class); + ObjectMapper mapper = new ObjectMapper(); + + when(runtimeContext.getAttribute(OM_KEY, ObjectMapper.class)).thenReturn(Optional.of(mapper)); + when(requestinvocationContext.getRuntimeContext()).thenReturn(runtimeContext); + } + + @Test + public void testReturnEmptyWhenNotAPIGatewayClass() { + MethodWrapper method = new DefaultMethodWrapper(APIGatewayCoercionTest.class, "testMethod"); + + Headers headers = Headers.emptyHeaders(); + + when(requestinvocationContext.getRequestHeaders()).thenReturn(headers); + ByteArrayInputStream is = new ByteArrayInputStream("".getBytes(StandardCharsets.UTF_8)); + InputEvent inputEvent = new ReadOnceInputEvent(is, Headers.emptyHeaders(), "call", Instant.now()); + Optional requestEvent = coercion.tryCoerceParam(requestinvocationContext, 0, inputEvent, method); + + assertFalse(requestEvent.isPresent()); + } + + @Test + public void testRequestHeaders() { + MethodWrapper method = new DefaultMethodWrapper(StringAPIGatewayTestFunction.class, "handler"); + + Headers h = Headers.emptyHeaders() + .setHeader("H1", "h1val") + .setHeader("Fn-Http-H-", "ignored") + .setHeader("Fn-Http-H-A", "b") + .setHeader("Fn-Http-H-mv", "c", "d"); + + APIGatewayRequestEvent requestEvent = coerceRequest(method, h, ""); + + assertEquals("b", (requestEvent.getHeaders().get("A")).get()); + assertEquals("c", (requestEvent.getHeaders().getAllValues("Mv")).get(0)); + assertEquals("d", (requestEvent.getHeaders().getAllValues("Mv")).get(1)); + assertFalse(requestEvent.getHeaders().get("H1").isPresent()); + } + + @Test + public void testRequestUrl() { + MethodWrapper method = new DefaultMethodWrapper(StringAPIGatewayTestFunction.class, "handler"); + + Headers h = Headers.emptyHeaders() + .setHeader("Fn-Http-Request-Url", "/v2/employee/123?param1=value%20with%20spaces"); + + APIGatewayRequestEvent requestEvent = coerceRequest(method, h, ""); + + assertEquals("/v2/employee/123?param1=value%20with%20spaces", requestEvent.getRequestUrl()); + } + + @Test + public void testRequestMethod() { + MethodWrapper method = new DefaultMethodWrapper(StringAPIGatewayTestFunction.class, "handler"); + + Headers h = Headers.emptyHeaders() + .setHeader("Fn-Http-Method", "PATCH"); + + APIGatewayRequestEvent requestEvent = coerceRequest(method, h, ""); + + assertEquals("PATCH", requestEvent.getMethod()); + } + + @Test + public void testQueryParameters() { + MethodWrapper method = new DefaultMethodWrapper(StringAPIGatewayTestFunction.class, "handler"); + + Headers h = Headers.emptyHeaders() + .setHeader("Fn-Http-Request-Url", "/v2/employee/123?param1=value%20with%20spaces&repeat=2&repeat=3"); + + APIGatewayRequestEvent requestEvent = coerceRequest(method, h, ""); + + assertEquals("value with spaces", requestEvent.getQueryParameters().get("param1").get()); + } + + @Test + public void testQueryRepeatedParameters() { + MethodWrapper method = new DefaultMethodWrapper(StringAPIGatewayTestFunction.class, "handler"); + + Headers h = Headers.emptyHeaders() + .setHeader("Fn-Http-Request-Url", "/v2/employee/123?param1=value%20with%20spaces&repeat=2&repeat=3"); + + APIGatewayRequestEvent requestEvent = coerceRequest(method, h, ""); + + assertEquals("2", (requestEvent.getQueryParameters().getValues("repeat")).get(0)); + assertEquals("3", (requestEvent.getQueryParameters().getValues("repeat")).get(1)); + } + + @Test + public void testRequestStringBody() { + MethodWrapper method = new DefaultMethodWrapper(StringAPIGatewayTestFunction.class, "handler"); + APIGatewayRequestEvent requestEvent = coerceRequest(method, "simple string"); + + assertEquals("simple string", requestEvent.getBody()); + } + + @Test + public void testListObjectRequestBody() { + MethodWrapper method = new DefaultMethodWrapper(ListAPIGatewayTestFunction.class, "handler"); + APIGatewayRequestEvent requestEvent = coerceRequest(method, "[{\"name\":\"Spot\",\"age\":6}]"); + + assertEquals("Spot", ((List) requestEvent.getBody()).get(0).getName()); + assertEquals(6, ((List) requestEvent.getBody()).get(0).getAge()); + } + + @Test + public void testSingleObjectRequestBody() { + MethodWrapper method = new DefaultMethodWrapper(APIGatewayTestFunction.class, "handler"); + APIGatewayRequestEvent requestEvent = coerceRequest(method, "{\"name\":\"Spot\",\"age\":6}"); + + assertEquals("Spot", ((Animal) requestEvent.getBody()).getName()); + assertEquals(6, ((Animal) requestEvent.getBody()).getAge()); + } + + @Test + public void testUncheckedHandler() { + MethodWrapper method = new DefaultMethodWrapper(UncheckedAPIGatewayTestFunction.class, "handler"); + Headers h = Headers.emptyHeaders().setHeader("H1", "h1val"); + + APIGatewayRequestEvent requestEvent = coerceRequest(method, h, "{\"name\":\"Spot\",\"age\":6}"); + + assertEquals("{\"name\":\"Spot\",\"age\":6}", requestEvent.getBody()); + } + + @Test + public void testFailureToParseIsUserFriendlyError() { + MethodWrapper method = new DefaultMethodWrapper(APIGatewayTestFunction.class, "handler"); + RuntimeException exception = assertThrows(RuntimeException.class, () -> coerceRequest(method, "INVALID JSON")); + + assertEquals("Failed to coerce event to user function parameter type [simple type, class com.fnproject.events.testfns.Animal]", exception.getMessage()); + assertTrue(exception.getCause().getMessage().startsWith("Unrecognized token 'INVALID':")); + } + + @Test + public void testCoerceForGrandChild() { + MethodWrapper method = new DefaultMethodWrapper(GrandChildGatewayTestFunction.class, "handler"); + APIGatewayRequestEvent requestEvent = coerceRequest(method, "simple string"); + + assertEquals("simple string", requestEvent.getBody()); + } + + @Test + public void testReturnEmptyResponseWhenNotAPIGatewayClass() { + MethodWrapper method = new DefaultMethodWrapper(APIGatewayCoercionTest.class, "testMethod"); + + APIGatewayResponseEvent responseEvent = new APIGatewayResponseEvent.Builder().build(); + Optional outputEvent = coercion.wrapFunctionResult(responseInvocationContext, method, responseEvent); + + assertFalse(outputEvent.isPresent()); + } + + @Test + public void testResponseHeaders() { + Headers headers = Headers.emptyHeaders() + .addHeader("custom-header", "customValue") + .setHeaders(Collections.singletonMap("custom-header-2", Collections.singletonList("customValue2"))); + APIGatewayResponseEvent responseEvent = new APIGatewayResponseEvent.Builder() + .headers(headers) + .build(); + + DefaultMethodWrapper method = new DefaultMethodWrapper(APIGatewayTestFunction.class, "handler"); + Optional outputEvent = wrap(responseEvent, method); + + assertTrue(outputEvent.isPresent()); + assertEquals("customValue", + responseInvocationContext.getAdditionalResponseHeaders().get("Fn-Http-H-Custom-Header").get(0)); + assertEquals("customValue2", + responseInvocationContext.getAdditionalResponseHeaders().get("Fn-Http-H-Custom-Header-2").get(0)); + } + + @Test + public void testResponseRepeatHeaders() { + Headers headers = Headers.emptyHeaders() + .addHeader("repeat", "1") + .addHeader("repeat", "2"); + APIGatewayResponseEvent responseEvent = new APIGatewayResponseEvent.Builder() + .headers(headers) + .build(); + + DefaultMethodWrapper method = new DefaultMethodWrapper(APIGatewayTestFunction.class, "handler"); + Optional outputEvent = wrap(responseEvent, method); + + assertTrue(outputEvent.isPresent()); + assertEquals("2", + responseInvocationContext.getAdditionalResponseHeaders().get("Fn-Http-H-Repeat").get(1)); + assertEquals("1", + responseInvocationContext.getAdditionalResponseHeaders().get("Fn-Http-H-Repeat").get(0)); + } + + @Test + public void testResponseContentTypeDefaultString() { + APIGatewayResponseEvent responseEvent = new APIGatewayResponseEvent.Builder() + .build(); + + DefaultMethodWrapper method = new DefaultMethodWrapper(StringAPIGatewayTestFunction.class, "handler"); + Optional outputEvent = wrap(responseEvent, method); + + assertTrue(outputEvent.isPresent()); + assertEquals("text/plain", outputEvent.get().getContentType().get()); + } + + @Test + public void testResponseContentTypeDefault() { + APIGatewayResponseEvent responseEvent = new APIGatewayResponseEvent.Builder() + .build(); + + DefaultMethodWrapper method = new DefaultMethodWrapper(APIGatewayTestFunction.class, "handler"); + Optional outputEvent = wrap(responseEvent, method); + + assertTrue(outputEvent.isPresent()); + assertEquals("application/json", outputEvent.get().getContentType().get()); + } + + @Test + public void testResponseCustomContentType() { + Headers headers = Headers.emptyHeaders() + .addHeader("content-type", "application/octet-stream"); + APIGatewayResponseEvent responseEvent = new APIGatewayResponseEvent.Builder() + .headers(headers) + .build(); + + DefaultMethodWrapper method = new DefaultMethodWrapper(APIGatewayTestFunction.class, "handler"); + Optional outputEvent = wrap(responseEvent, method); + + assertTrue(outputEvent.isPresent()); + assertEquals("application/octet-stream", outputEvent.get().getContentType().get()); + } + + @Test + public void testResponseStatus() { + APIGatewayResponseEvent responseEvent = new APIGatewayResponseEvent.Builder() + .statusCode(200) + .build(); + + DefaultMethodWrapper method = new DefaultMethodWrapper(APIGatewayTestFunction.class, "handler"); + Optional outputEvent = wrap(responseEvent, method); + + assertTrue(outputEvent.isPresent()); + assertEquals("200", responseInvocationContext.getAdditionalResponseHeaders().get("Fn-Http-Status").get(0)); + } + + @Test + public void testResponseStringBody() throws IOException { + APIGatewayResponseEvent responseEvent = new APIGatewayResponseEvent.Builder() + .body("string body") + .build(); + + DefaultMethodWrapper method = new DefaultMethodWrapper(StringAPIGatewayTestFunction.class, "handler"); + Optional outputEvent = wrap(responseEvent, method); + + assertTrue(outputEvent.isPresent()); + String actual = writeToString(outputEvent.get()); + assertEquals("string body", actual); + } + + @Test + public void testResponseObjectBody() throws IOException { + Car car = new Car("ford", 4); + APIGatewayResponseEvent responseEvent = new APIGatewayResponseEvent.Builder() + .body(car) + .build(); + + DefaultMethodWrapper method = new DefaultMethodWrapper(APIGatewayTestFunction.class, "handler"); + Optional outputEvent = wrap(responseEvent, method); + + assertTrue(outputEvent.isPresent()); + String actual = writeToString(outputEvent.get()); + assertEquals("{\"brand\":\"ford\",\"wheels\":4}", actual); + } + + @Test + public void testResponseListBody() throws IOException { + Car car = new Car("ford", 4); + APIGatewayResponseEvent> responseEvent = new APIGatewayResponseEvent.Builder>() + .body(Collections.singletonList(car)) + .build(); + + DefaultMethodWrapper method = new DefaultMethodWrapper(APIGatewayTestFunction.class, "handler"); + Optional outputEvent = wrap(responseEvent, method); + + assertTrue(outputEvent.isPresent()); + String actual = writeToString(outputEvent.get()); + assertEquals("[{\"brand\":\"ford\",\"wheels\":4}]", actual); + } + + @Test + public void testResponseStringNullBody() { + APIGatewayResponseEvent responseEvent = new APIGatewayResponseEvent.Builder() + .build(); + + DefaultMethodWrapper method = new DefaultMethodWrapper(StringAPIGatewayTestFunction.class, "handler"); + Optional outputEvent = wrap(responseEvent, method); + + assertTrue(outputEvent.isPresent()); + assertEquals("text/plain", outputEvent.get().getContentType().get()); + } + + @Test + public void testResponseUncheckedBody() { + APIGatewayResponseEvent responseEvent = new APIGatewayResponseEvent.Builder() + .build(); + + DefaultMethodWrapper method = new DefaultMethodWrapper(UncheckedAPIGatewayTestFunction.class, "handler"); + Optional outputEvent = wrap(responseEvent, method); + + assertTrue(outputEvent.isPresent()); + assertEquals("text/plain", outputEvent.get().getContentType().get()); + } + + @Test + public void testNullResponse() { + DefaultMethodWrapper method = new DefaultMethodWrapper(UncheckedAPIGatewayTestFunction.class, "handler"); + Optional outputEvent = wrap(null, method); + + assertFalse(outputEvent.isPresent()); + } + + private Optional wrap(APIGatewayResponseEvent responseEvent, MethodWrapper method) { + Headers requestHeaders = Headers.emptyHeaders(); + InputEvent inputEvent = mock(InputEvent.class); + when(inputEvent.getHeaders()).thenReturn(requestHeaders); + + FunctionRuntimeContext frc = new FunctionRuntimeContext(method, new HashMap<>()); + + responseInvocationContext = new DefaultFunctionInvocationContext(frc, inputEvent); + return coercion.wrapFunctionResult(responseInvocationContext, method, responseEvent); + } + + private static String writeToString(OutputEvent oe) throws IOException { + ByteArrayOutputStream baos = new ByteArrayOutputStream(); + oe.writeToOutput(baos); + return baos.toString("UTF-8"); + } + + private APIGatewayRequestEvent coerceRequest(MethodWrapper method, Headers headers, String body) { + when(requestinvocationContext.getRequestHeaders()).thenReturn(headers); + ByteArrayInputStream is = new ByteArrayInputStream(body.getBytes(StandardCharsets.UTF_8)); + InputEvent inputEvent = new ReadOnceInputEvent(is, Headers.emptyHeaders(), "call", Instant.now()); + return coercion.tryCoerceParam(requestinvocationContext, 0, inputEvent, method).orElseThrow(RuntimeException::new); + } + + private APIGatewayRequestEvent coerceRequest(MethodWrapper method, String body) { + return coerceRequest(method, Headers.emptyHeaders(), body); + } + + public String testMethod(List ss) { + // This method isn't actually called, it only exists to have its parameter types examined by the JacksonCoercion + return ss.get(0).getName(); + } +} \ No newline at end of file diff --git a/fn-events/src/test/java/com/fnproject/events/coercion/ConnectorHubCoercionTest.java b/fn-events/src/test/java/com/fnproject/events/coercion/ConnectorHubCoercionTest.java new file mode 100644 index 00000000..19b61a74 --- /dev/null +++ b/fn-events/src/test/java/com/fnproject/events/coercion/ConnectorHubCoercionTest.java @@ -0,0 +1,398 @@ +package com.fnproject.events.coercion; + +import static com.fnproject.events.coercion.APIGatewayCoercion.OM_KEY; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertNull; +import static org.junit.Assert.assertThrows; +import static org.junit.Assert.assertTrue; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; +import java.io.ByteArrayInputStream; +import java.nio.charset.StandardCharsets; +import java.time.Instant; +import java.util.Base64; +import java.util.Collections; +import java.util.Date; +import java.util.Optional; +import com.fasterxml.jackson.core.JsonProcessingException; +import com.fasterxml.jackson.databind.ObjectMapper; +import com.fnproject.events.input.ConnectorHubBatch; +import com.fnproject.events.input.sch.LoggingData; +import com.fnproject.events.input.sch.MetricData; +import com.fnproject.events.input.sch.StreamingData; +import com.fnproject.events.testfns.Animal; +import com.fnproject.events.testfns.connectorhub.GrandChildMonitorSourceTestFunction; +import com.fnproject.events.testfns.connectorhub.LoggingSourceTestFunction; +import com.fnproject.events.testfns.connectorhub.MonitorSourceTestFunction; +import com.fnproject.events.testfns.connectorhub.QueueSourceObjectTestFunction; +import com.fnproject.events.testfns.connectorhub.QueueSourceStringTestFunction; +import com.fnproject.events.testfns.connectorhub.StreamingSourceObjectTestFunction; +import com.fnproject.events.testfns.connectorhub.StreamingSourceStringTestFunction; +import com.fnproject.fn.api.Headers; +import com.fnproject.fn.api.InputEvent; +import com.fnproject.fn.api.InvocationContext; +import com.fnproject.fn.api.MethodWrapper; +import com.fnproject.fn.api.RuntimeContext; +import com.fnproject.fn.runtime.DefaultMethodWrapper; +import com.fnproject.fn.runtime.ReadOnceInputEvent; +import org.junit.Before; +import org.junit.Test; + +public class ConnectorHubCoercionTest { + private ConnectorHubCoercion coercion; + private InvocationContext requestinvocationContext; + + @Before + public void setUp() { + coercion = ConnectorHubCoercion.instance(); + requestinvocationContext = mock(InvocationContext.class); + RuntimeContext runtimeContext = mock(RuntimeContext.class); + ObjectMapper mapper = new ObjectMapper(); + + when(runtimeContext.getAttribute(OM_KEY, ObjectMapper.class)).thenReturn(Optional.of(mapper)); + when(requestinvocationContext.getRuntimeContext()).thenReturn(runtimeContext); + } + + @Test + public void testReturnEmptyWhenNotConnectorHubEventClass() { + MethodWrapper method = new DefaultMethodWrapper(APIGatewayCoercionTest.class, "testMethod"); + + Headers headers = Headers.emptyHeaders(); + + when(requestinvocationContext.getRequestHeaders()).thenReturn(headers); + ByteArrayInputStream is = new ByteArrayInputStream("".getBytes(StandardCharsets.UTF_8)); + InputEvent inputEvent = new ReadOnceInputEvent(is, Headers.emptyHeaders(), "call", Instant.now()); + Optional> batch = coercion.tryCoerceParam(requestinvocationContext, 0, inputEvent, method); + + assertFalse(batch.isPresent()); + } + + @Test + public void testMonitoringSourceInput() { + MethodWrapper method = new DefaultMethodWrapper(MonitorSourceTestFunction.class, "handler"); + + ConnectorHubBatch event = coerceRequest(method, "[\n" + + " {\n" + + " \"namespace\": \"oci_objectstorage\",\n" + + " \"resourceGroup\": \"nullable\",\n" + + " \"compartmentId\": \"ocid1.tenancy.oc1..xyz\",\n" + + " \"name\": \"PutRequests\",\n" + + " \"dimensions\": {\n" + + " \"resourceID\": \"ocid1.bucket.oc1.uk-london-1.xyz\",\n" + + " \"resourceDisplayName\": \"foo\"\n" + + " },\n" + + " \"metadata\": {\n" + + " \"displayName\": \"PutObject Request Count\",\n" + + " \"unit\": \"count\"\n" + + " },\n" + + " \"datapoints\": [\n" + + " {\n" + + " \"timestamp\": 1761318377414,\n" + + " \"value\": 1.0,\n" + + " \"count\": 1\n" + + " }\n" + + " ]\n" + + " }," + + " {\n" + + " \"namespace\": \"oci_objectstorage\",\n" + + " \"resourceGroup\": null,\n" + + " \"compartmentId\": \"ocid1.tenancy.oc1..abc\",\n" + + " \"name\": \"PutRequests\",\n" + + " \"dimensions\": {\n" + + " \"resourceID\": \"ocid1.bucket.oc1.uk-london-1.abc\",\n" + + " \"resourceDisplayName\": \"bar\"\n" + + " },\n" + + " \"metadata\": {\n" + + " \"displayName\": \"PutObject Request Count\",\n" + + " \"unit\": \"count\"\n" + + " },\n" + + " \"datapoints\": [\n" + + " {\n" + + " \"timestamp\": 1761318377414,\n" + + " \"value\": 1.0,\n" + + " \"count\": 1\n" + + " },\n" + + " {\n" + + " \"timestamp\": 1761318377614,\n" + + " \"value\": 2.0,\n" + + " \"count\": 1\n" + + " }\n" + + " ]\n" + + " }" + + "]"); + + assertFalse(event.getBatch().isEmpty()); + assertEquals(2, event.getBatch().size()); + MetricData monitoringSource = event.getBatch().get(0); + assertEquals("PutRequests", monitoringSource.getName()); + assertEquals("nullable", monitoringSource.getResourceGroup()); + assertEquals("ocid1.tenancy.oc1..xyz", monitoringSource.getCompartmentId()); + assertEquals("oci_objectstorage", monitoringSource.getNamespace()); + assertEquals("ocid1.bucket.oc1.uk-london-1.xyz", monitoringSource.getDimensions().get("resourceID")); + assertEquals("foo", monitoringSource.getDimensions().get("resourceDisplayName")); + assertEquals("PutObject Request Count", monitoringSource.getMetadata().get("displayName")); + assertEquals("count", monitoringSource.getMetadata().get("unit")); + assertEquals(Integer.valueOf(1), monitoringSource.getDatapoints().get(0).getCount()); + assertEquals(Double.parseDouble("1.0"), monitoringSource.getDatapoints().get(0).getValue(), 0); + assertEquals(Date.from(Instant.ofEpochMilli(Long.parseLong("1761318377414"))), monitoringSource.getDatapoints().get(0).getTimestamp()); + } + + @Test + public void testMonitoringSourceInputNoCount() { + MethodWrapper method = new DefaultMethodWrapper(MonitorSourceTestFunction.class, "handler"); + + ConnectorHubBatch event = coerceRequest(method, "[\n" + + " {\n" + + " \"namespace\":\"oci_computeagent\",\n" + + " \"compartmentId\":\"ocid1.tenancy.oc1..exampleuniqueID\",\n" + + " \"name\":\"DiskBytesRead\",\n" + + " \"dimensions\":{\n" + + " \"resourceId\":\"ocid1.instance.region1.phx.exampleuniqueID\"\n" + + " },\n" + + " \"metadata\":{\n" + + " \"unit\":\"bytes\"\n" + + " },\n" + + " \"datapoints\":[\n" + + " {\n" + + " \"timestamp\":\"1761318377414\",\n" + + " \"value\":10.4\n" + + " },\n" + + " {\n" + + " \"timestamp\":\"1761318377414\",\n" + + " \"value\":11.3\n" + + " }\n" + + " ]\n" + + " }\n" + + "]"); + + assertFalse(event.getBatch().isEmpty()); + assertEquals(1, event.getBatch().size()); + MetricData monitoringSource = event.getBatch().get(0); + assertEquals("DiskBytesRead", monitoringSource.getName()); + assertEquals("ocid1.tenancy.oc1..exampleuniqueID", monitoringSource.getCompartmentId()); + assertEquals("oci_computeagent", monitoringSource.getNamespace()); + assertNull(monitoringSource.getDimensions().get("resourceID")); + assertNull(monitoringSource.getDimensions().get("resourceDisplayName")); + assertNull(monitoringSource.getMetadata().get("displayName")); + assertEquals("bytes", monitoringSource.getMetadata().get("unit")); + assertEquals(Double.parseDouble("10.4"), monitoringSource.getDatapoints().get(0).getValue(), 0); + assertEquals(Date.from(Instant.ofEpochMilli(Long.parseLong("1761318377414"))), monitoringSource.getDatapoints().get(0).getTimestamp()); + } + + @Test + public void testMonitoringSourceInputEmpty() { + MethodWrapper method = new DefaultMethodWrapper(MonitorSourceTestFunction.class, "handler"); + + ConnectorHubBatch event = coerceRequest(method, "[]"); + + assertTrue(event.getBatch().isEmpty()); + } + + @Test + public void testGrandChildIsCoercedInputEmpty() { + MethodWrapper method = new DefaultMethodWrapper(GrandChildMonitorSourceTestFunction.class, "handler"); + + ConnectorHubBatch event = coerceRequest(method, "[]"); + + assertTrue(event.getBatch().isEmpty()); + } + + @Test + public void testFailureToParseIsUserFriendlyError() { + MethodWrapper method = new DefaultMethodWrapper(MonitorSourceTestFunction.class, "handler"); + RuntimeException exception = assertThrows(RuntimeException.class, () -> coerceRequest(method, "INVALID JSON")); + + assertEquals( + "Failed to coerce event to user function parameter type [collection type; class java.util.List, contains [simple type, class com.fnproject.events.input.sch.MetricData]]", + exception.getMessage()); + assertTrue(exception.getCause().getMessage().startsWith("Unrecognized token 'INVALID':")); + } + + @Test + public void testLoggingSourceInput() { + MethodWrapper method = new DefaultMethodWrapper(LoggingSourceTestFunction.class, "handler"); + + ConnectorHubBatch event = coerceRequest(method, "[\n" + + " {\n" + + " \"data\": {\n" + + " \"applicationId\": \"ocid1.fnapp.oc1.abc\",\n" + + " \"containerId\": \"n/a\",\n" + + " \"functionId\": \"ocid1.fnfunc.oc1.abc\",\n" + + " \"message\": \"Received function invocation request\",\n" + + " \"opcRequestId\": \"/abc/def\",\n" + + " \"requestId\": \"/def/abc\",\n" + + " \"src\": \"stdout\"\n" + + " },\n" + + " \"id\": \"abc-zyx\",\n" + + " \"oracle\": {\n" + + " \"compartmentid\": \"ocid1.tenancy.oc1..xyz\",\n" + + " \"ingestedtime\": \"2025-10-23T15:45:19.457Z\",\n" + + " \"loggroupid\": \"ocid1.loggroup.oc1.abc\",\n" + + " \"logid\": \"ocid1.log.oc1.def\",\n" + + " \"tenantid\": \"ocid1.tenancy.oc1..xyz\"\n" + + " },\n" + + " \"source\": \"your-log\",\n" + + " \"specversion\": \"1.0\",\n" + + " \"subject\": \"schedule\",\n" + + " \"time\": \"2025-10-24T15:06:17.000Z\",\n" + + " \"type\": \"com.oraclecloud.functions.application.functioninvoke\"\n" + + " },\n" + + " {\n" + + " \"data\": {\n" + + " \"applicationId\": \"ocid1.fnapp.oc1.def\",\n" + + " \"containerId\": \"n/a\",\n" + + " \"functionId\": \"ocid1.fnfunc.oc1.def\",\n" + + " \"message\": \"Received function invocation request\",\n" + + " \"opcRequestId\": \"/def/xyz\",\n" + + " \"requestId\": \"/foo/bar\",\n" + + " \"src\": \"stdout\"\n" + + " },\n" + + " \"id\": \"foo-zyx\",\n" + + " \"oracle\": {\n" + + " \"compartmentid\": \"ocid1.tenancy.oc1..xyz\",\n" + + " \"ingestedtime\": \"2025-11-23T15:45:19.457Z\",\n" + + " \"loggroupid\": \"ocid1.loggroup.oc1.def\",\n" + + " \"logid\": \"ocid1.log.oc1.xyz\",\n" + + " \"tenantid\": \"ocid1.tenancy.oc1..xyz\"\n" + + " },\n" + + " \"source\": \"your-log\",\n" + + " \"specversion\": \"1.0\",\n" + + " \"subject\": \"schedule\",\n" + + " \"time\": \"2025-11-23T15:45:17.239Z\",\n" + + " \"type\": \"com.oraclecloud.functions.application.functioninvoke\"\n" + + " }\n" + + "]"); + + assertFalse(event.getBatch().isEmpty()); + assertEquals(2, event.getBatch().size()); + LoggingData loggingData = event.getBatch().get(0); + assertEquals("your-log", loggingData.getSource()); + assertEquals("abc-zyx", loggingData.getId()); + assertEquals("schedule", loggingData.getSubject()); + assertEquals("1.0", loggingData.getSpecversion()); + assertEquals("ocid1.fnapp.oc1.abc", loggingData.getData().get("applicationId")); + assertEquals("n/a", loggingData.getData().get("containerId")); + assertEquals("ocid1.fnfunc.oc1.abc", loggingData.getData().get("functionId")); + assertEquals("Received function invocation request", loggingData.getData().get("message")); + assertEquals("/abc/def", loggingData.getData().get("opcRequestId")); + assertEquals("/def/abc", loggingData.getData().get("requestId")); + assertEquals("stdout", loggingData.getData().get("src")); + assertEquals("ocid1.tenancy.oc1..xyz", loggingData.getOracle().get("compartmentid")); + assertEquals("2025-10-23T15:45:19.457Z", loggingData.getOracle().get("ingestedtime")); + assertEquals("ocid1.loggroup.oc1.abc", loggingData.getOracle().get("loggroupid")); + assertEquals("ocid1.log.oc1.def", loggingData.getOracle().get("logid")); + assertEquals("ocid1.tenancy.oc1..xyz", loggingData.getOracle().get("tenantid")); + assertEquals(Date.from(Instant.ofEpochMilli(Long.parseLong("1761318377000"))), loggingData.getTime()); + assertEquals("com.oraclecloud.functions.application.functioninvoke", loggingData.getType()); + } + + @Test + public void testStreamingSourceInput() { + MethodWrapper method = new DefaultMethodWrapper(StreamingSourceStringTestFunction.class, "handler"); + + ConnectorHubBatch> event = coerceRequest(method, "[" + + "{\"stream\":\"stream-name\"," + + "\"partition\":\"0\"," + + "\"key\":null," + + "\"value\":\"U2VudCBhIHBsYWluIG1lc3NhZ2U=\"," + + "\"offset\":3," + + "\"timestamp\":1761223385480" + + "}," + + "{\"stream\":\"stream-name\"," + + "\"partition\":\"0\"," + + "\"key\":null," + + "\"value\":\"U2VudCBhIHBsYWluIG1lc3NhZ2U=\"," + + "\"offset\":3," + + "\"timestamp\":1761223385480" + + "}" + + "]"); + + assertFalse(event.getBatch().isEmpty()); + assertEquals(2, event.getBatch().size()); + StreamingData streamingData = event.getBatch().get(0); + assertEquals("stream-name", streamingData.getStream()); + assertNull(streamingData.getKey()); + assertEquals("3", streamingData.getOffset()); + assertEquals("0", streamingData.getPartition()); + assertEquals(Date.from(Instant.ofEpochMilli(Long.parseLong("1761223385480"))), streamingData.getTimestamp()); + assertEquals("Sent a plain message", streamingData.getValue()); + } + + @Test + public void testStreamingSourceInputObject() throws JsonProcessingException { + MethodWrapper method = new DefaultMethodWrapper(StreamingSourceObjectTestFunction.class, "handler"); + Animal animal = new Animal("cat", 2); + + ConnectorHubBatch> event = coerceRequest(method, "[" + + "{\"stream\":\"stream-name\"," + + "\"partition\":\"0\"," + + "\"key\":null," + + "\"value\":\"" + Base64.getEncoder().encodeToString(new ObjectMapper().writeValueAsBytes(animal)) + "\"," + + "\"offset\":3," + + "\"timestamp\":1761223385480" + + "}" + + "]"); + + assertFalse(event.getBatch().isEmpty()); + assertEquals(1, event.getBatch().size()); + StreamingData streamingData = event.getBatch().get(0); + assertEquals("stream-name", streamingData.getStream()); + assertNull(streamingData.getKey()); + assertEquals("3", streamingData.getOffset()); + assertEquals("0", streamingData.getPartition()); + assertEquals(animal.getAge(), streamingData.getValue().getAge()); + assertEquals(Date.from(Instant.ofEpochMilli(Long.parseLong("1761223385480"))), streamingData.getTimestamp()); + } + + @Test + public void testQueueSourceInputInvalidMessage() { + MethodWrapper method = new DefaultMethodWrapper(QueueSourceStringTestFunction.class, "handler"); + assertThrows(RuntimeException.class, () -> coerceRequest(method, "[a plain string]")); + } + + @Test + public void testQueueSourceInputString() { + MethodWrapper method = new DefaultMethodWrapper(QueueSourceStringTestFunction.class, "handler"); + ConnectorHubBatch event = coerceRequest(method, "[\"a plain , comma string 1\",\"a plain , comma string 2\",\"a plain , comma string 3\"]"); + + assertFalse(event.getBatch().isEmpty()); + assertEquals(3, event.getBatch().size()); + assertEquals("a plain , comma string 1", event.getBatch().get(0)); + } + + @Test + public void testQueueSourceInputObject() { + Animal animal = new Animal("cat", 2); + MethodWrapper method = new DefaultMethodWrapper(QueueSourceObjectTestFunction.class, "handler"); + ConnectorHubBatch event = coerceRequest(method, "[{\"name\": \"cat\",\"age\":2}]"); + + assertFalse(event.getBatch().isEmpty()); + assertEquals(1, event.getBatch().size()); + assertEquals(animal, event.getBatch().get(0)); + } + + @Test + public void testHeaders() { + MethodWrapper method = new DefaultMethodWrapper(QueueSourceObjectTestFunction.class, "handler"); + when(requestinvocationContext.getRequestHeaders()).thenReturn(Headers.emptyHeaders().addHeader("foo", "bar")); + ConnectorHubBatch event = coerceRequest(method, "[{\"name\": \"cat\",\"age\":2}]"); + + assertEquals("bar", event.getHeaders().get("foo").get()); + } + + @Test + public void testEmptyHeaders() { + MethodWrapper method = new DefaultMethodWrapper(QueueSourceObjectTestFunction.class, "handler"); + when(requestinvocationContext.getRequestHeaders()).thenReturn(Headers.emptyHeaders()); + ConnectorHubBatch event = coerceRequest(method, "[{\"name\": \"cat\",\"age\":2}]"); + + assertEquals(0, event.getHeaders().asMap().size()); + } + + private ConnectorHubBatch coerceRequest(MethodWrapper method, String body) { + ByteArrayInputStream is = new ByteArrayInputStream(body.getBytes(StandardCharsets.UTF_8)); + InputEvent inputEvent = new ReadOnceInputEvent(is, Headers.emptyHeaders(), "call", Instant.now()); + return coercion.tryCoerceParam(requestinvocationContext, 0, inputEvent, method).orElseThrow(RuntimeException::new); + } +} \ No newline at end of file diff --git a/fn-events/src/test/java/com/fnproject/events/coercion/NotificationCoercionTest.java b/fn-events/src/test/java/com/fnproject/events/coercion/NotificationCoercionTest.java new file mode 100644 index 00000000..9b362e9b --- /dev/null +++ b/fn-events/src/test/java/com/fnproject/events/coercion/NotificationCoercionTest.java @@ -0,0 +1,107 @@ +package com.fnproject.events.coercion; + +import static com.fnproject.events.coercion.APIGatewayCoercion.OM_KEY; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; +import java.io.ByteArrayInputStream; +import java.nio.charset.StandardCharsets; +import java.time.Instant; +import java.util.Optional; +import com.fasterxml.jackson.databind.ObjectMapper; +import com.fnproject.events.input.NotificationMessage; +import com.fnproject.events.testfns.Animal; +import com.fnproject.events.testfns.notification.NotificationObjectTestFunction; +import com.fnproject.events.testfns.notification.NotificationStringTestFunction; +import com.fnproject.fn.api.Headers; +import com.fnproject.fn.api.InputEvent; +import com.fnproject.fn.api.InvocationContext; +import com.fnproject.fn.api.MethodWrapper; +import com.fnproject.fn.api.RuntimeContext; +import com.fnproject.fn.runtime.DefaultMethodWrapper; +import com.fnproject.fn.runtime.ReadOnceInputEvent; +import org.junit.Before; +import org.junit.Test; + + +public class NotificationCoercionTest { + private NotificationCoercion coercion; + private InvocationContext requestinvocationContext; + + @Before + public void setUp() { + coercion = NotificationCoercion.instance(); + requestinvocationContext = mock(InvocationContext.class); + RuntimeContext runtimeContext = mock(RuntimeContext.class); + ObjectMapper mapper = new ObjectMapper(); + + when(runtimeContext.getAttribute(OM_KEY, ObjectMapper.class)).thenReturn(Optional.of(mapper)); + when(requestinvocationContext.getRuntimeContext()).thenReturn(runtimeContext); + } + + @Test + public void testReturnEmptyWhenNotNotificationClass() { + MethodWrapper method = new DefaultMethodWrapper(APIGatewayCoercionTest.class, "testMethod"); + + Headers headers = Headers.emptyHeaders(); + + when(requestinvocationContext.getRequestHeaders()).thenReturn(headers); + ByteArrayInputStream is = new ByteArrayInputStream("".getBytes(StandardCharsets.UTF_8)); + InputEvent inputEvent = new ReadOnceInputEvent(is, Headers.emptyHeaders(), "call", Instant.now()); + Optional batch = coercion.tryCoerceParam(requestinvocationContext, 0, inputEvent, method); + + assertFalse(batch.isPresent()); + } + + @Test + public void testNotificationObjectInput() { + MethodWrapper method = new DefaultMethodWrapper(NotificationObjectTestFunction.class, "handler"); + + NotificationMessage event = coerceRequest(method, "{\"name\":\"foo\",\"age\":3}"); + + assertEquals(3, event.getContent().getAge()); + assertEquals("foo", event.getContent().getName()); + } + + @Test + public void testNotificationStringInput() { + MethodWrapper method = new DefaultMethodWrapper(NotificationStringTestFunction.class, "handler"); + NotificationMessage event = coerceRequest(method, "a plain string"); + + assertEquals("a plain string", event.getContent()); + } + + @Test + public void testNotificationStringInputEmpty() { + MethodWrapper method = new DefaultMethodWrapper(NotificationStringTestFunction.class, "handler"); + + NotificationMessage event = coerceRequest(method, ""); + + assertEquals("", event.getContent()); + } + + @Test + public void testHeaders() { + MethodWrapper method = new DefaultMethodWrapper(NotificationObjectTestFunction.class, "handler"); + when(requestinvocationContext.getRequestHeaders()).thenReturn(Headers.emptyHeaders().addHeader("foo", "bar")); + NotificationMessage event = coerceRequest(method, "{\"name\": \"cat\",\"age\":2}"); + + assertEquals("bar", event.getHeaders().get("foo").get()); + } + + @Test + public void testEmptyHeaders() { + MethodWrapper method = new DefaultMethodWrapper(NotificationObjectTestFunction.class, "handler"); + when(requestinvocationContext.getRequestHeaders()).thenReturn(Headers.emptyHeaders()); + NotificationMessage event = coerceRequest(method, "{\"name\": \"cat\",\"age\":2}"); + + assertEquals(0, event.getHeaders().asMap().size()); + } + + private NotificationMessage coerceRequest(MethodWrapper method, String body) { + ByteArrayInputStream is = new ByteArrayInputStream(body.getBytes(StandardCharsets.UTF_8)); + InputEvent inputEvent = new ReadOnceInputEvent(is, Headers.emptyHeaders(), "call", Instant.now()); + return coercion.tryCoerceParam(requestinvocationContext, 0, inputEvent, method).orElseThrow(RuntimeException::new); + } +} \ No newline at end of file diff --git a/fn-events/src/test/java/com/fnproject/events/coercion/jackson/Base64ToTypeDeserializerTest.java b/fn-events/src/test/java/com/fnproject/events/coercion/jackson/Base64ToTypeDeserializerTest.java new file mode 100644 index 00000000..269b89fd --- /dev/null +++ b/fn-events/src/test/java/com/fnproject/events/coercion/jackson/Base64ToTypeDeserializerTest.java @@ -0,0 +1,123 @@ +package com.fnproject.events.coercion.jackson; + +import static org.hamcrest.CoreMatchers.instanceOf; +import static org.hamcrest.MatcherAssert.assertThat; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNull; +import static org.junit.Assert.assertThrows; +import com.fasterxml.jackson.core.type.TypeReference; +import com.fasterxml.jackson.databind.ObjectMapper; +import com.fasterxml.jackson.databind.exc.MismatchedInputException; +import com.fnproject.events.input.sch.StreamingData; +import com.fnproject.events.testfns.Animal; +import org.junit.Test; + +import java.nio.charset.StandardCharsets; +import java.util.Base64; +import java.util.List; + +public class Base64ToTypeDeserializerTest { + private final ObjectMapper mapper = new ObjectMapper(); + + // Helpers + private static String b64(String s) { + return Base64.getEncoder().encodeToString(s.getBytes(StandardCharsets.UTF_8)); + } + + private static String animalJson(String name, int age) { + return "{\"name\":\"" + name + "\",\"age\":" + age + "}"; + } + + @Test + public void testDecodeBase64JsonIntoPojo() throws Exception { + String valueB64 = b64(animalJson("Felix", 2)); + String json = "{ \"stream\":\"s\", \"partition\":\"p\", \"key\":\"k\", \"value\":\"" + valueB64 + "\", \"offset\":\"o\" }"; + + StreamingData sd = mapper.readValue(json, new TypeReference>() { + }); + assertThat(sd.getValue(), instanceOf(Animal.class)); + assertEquals("Felix", sd.getValue().getName()); + assertEquals(2, sd.getValue().getAge()); + } + + @Test + public void testDecodeBase64TextIntoString() throws Exception { + String valueB64 = b64("hello world"); + String json = "{ \"stream\":\"s\", \"partition\":\"p\", \"key\":\"k\", \"value\":\"" + valueB64 + "\", \"offset\":\"o\" }"; + + StreamingData sd = mapper.readValue(json, new TypeReference>() { + }); + assertEquals("hello world", sd.getValue()); + } + + @Test + public void testPassThroughNonBase64StringForStringTarget() throws Exception { + String json = "{ \"stream\":\"s\", \"partition\":\"p\", \"key\":\"k\", \"value\":\"not-base64$\", \"offset\":\"o\" }"; + + StreamingData sd = mapper.readValue(json, new TypeReference>() { + }); + assertEquals("not-base64$", sd.getValue()); + } + + @Test + public void testInterpretPlainJsonStringWhenNotBase64() throws Exception { + // value is a string that contains JSON; not base64 + String inner = animalJson("Buddy", 1); + String json = "{ \"stream\":\"s\", \"partition\":\"p\", \"key\":\"k\", \"value\":\"" + inner.replace("\"", "\\\"") + "\", \"offset\":\"o\" }"; + + StreamingData sd = mapper.readValue(json, new TypeReference>() { + }); + assertThat(sd.getValue(), instanceOf(Animal.class)); + assertEquals("Buddy", sd.getValue().getName()); + assertEquals(1, sd.getValue().getAge()); + } + + @Test + public void testNonStringValueDelegatesNormally() throws Exception { + // The value is already a JSON object (not a string). The deserializer should delegate to normal binding. + String json = "{ \"stream\":\"s\", \"partition\":\"p\", \"key\":\"k\", \"value\": " + animalJson("Milo", 3) + ", \"offset\":\"o\" }"; + + StreamingData sd = mapper.readValue(json, new TypeReference>() { + }); + assertThat(sd.getValue(), instanceOf(Animal.class)); + assertEquals("Milo", sd.getValue().getName()); + assertEquals(3, sd.getValue().getAge()); + } + + @Test + public void testNullValueReturnsNull() throws Exception { + String json = "{ \"stream\":\"s\", \"partition\":\"p\", \"key\":\"k\", \"value\": null, \"offset\":\"o\" }"; + + StreamingData sd = mapper.readValue(json, new TypeReference>() { + }); + assertNull(sd.getValue()); + } + + @Test + public void testResolveTypeFromEnclosingGenericInCollection() throws Exception { + String v1 = b64(animalJson("Felix", 1)); + String v2 = b64(animalJson("Buddy", 2)); + String json = "[ " + + "{ \"stream\":\"s\", \"partition\":\"p\", \"key\":\"k1\", \"value\":\"" + v1 + "\", \"offset\":\"o1\" }," + + "{ \"stream\":\"s\", \"partition\":\"p\", \"key\":\"k2\", \"value\":\"" + v2 + "\", \"offset\":\"o2\" }" + + "]"; + + List> list = mapper.readValue( + json, new TypeReference>>() { + }); + assertEquals(2, list.size()); + assertThat(list.get(0).getValue(), instanceOf(Animal.class)); + assertEquals("Felix", list.get(0).getValue().getName()); + assertThat(list.get(1).getValue(), instanceOf(Animal.class)); + assertEquals("Buddy", list.get(1).getValue().getName()); + } + + @Test + public void testInvalidNonJsonForNonStringTargetYieldsMismatch() { + // Not base64; not JSON; not coercible to Animal -> should surface a MismatchedInputException + String json = "{ \"stream\":\"s\", \"partition\":\"p\", \"key\":\"k\", \"value\":\"not-json-or-base64\", \"offset\":\"o\" }"; + + assertThrows(MismatchedInputException.class, () -> mapper.readValue(json, new TypeReference>() {})); + } + +} \ No newline at end of file diff --git a/fn-events/src/test/java/com/fnproject/events/mapper/APIGatewayRequestEventMapperTest.java b/fn-events/src/test/java/com/fnproject/events/mapper/APIGatewayRequestEventMapperTest.java new file mode 100644 index 00000000..534dc3ac --- /dev/null +++ b/fn-events/src/test/java/com/fnproject/events/mapper/APIGatewayRequestEventMapperTest.java @@ -0,0 +1,112 @@ +package com.fnproject.events.mapper; + +import static org.junit.Assert.*; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import com.fnproject.events.input.APIGatewayRequestEvent; +import com.fnproject.events.testfns.Animal; +import com.fnproject.fn.api.Headers; +import com.fnproject.fn.api.QueryParameters; +import com.fnproject.fn.api.httpgateway.HTTPGatewayContext; +import com.fnproject.fn.runtime.httpgateway.QueryParametersImpl; +import org.junit.Before; +import org.junit.Test; + +public class APIGatewayRequestEventMapperTest { + + private APIGatewayRequestEventMapper mapper; + + @Before + public void setUp() { + mapper = new APIGatewayRequestEventMapper(); + } + + @Test + public void testQueryParameter() { + Map> params = new HashMap<>(); + List paramValues = new ArrayList<>(); + paramValues.add("value"); + paramValues.add("value2"); + params.put("keyTest", paramValues); + QueryParametersImpl qp = new QueryParametersImpl(params); + + HTTPGatewayContext httpGatewayContextMock = mock(HTTPGatewayContext.class); + when(httpGatewayContextMock.getQueryParameters()).thenReturn(qp); + + APIGatewayRequestEvent event = mapper.toApiGatewayRequestEvent(httpGatewayContextMock, ""); + QueryParameters queryParameters = event.getQueryParameters(); + + assertEquals("value", queryParameters.getValues("keyTest").get(0)); + assertEquals("value2", queryParameters.getValues("keyTest").get(1)); + } + + @Test + public void testGetBody() { + String payload = "value"; + + HTTPGatewayContext httpGatewayContextMock = mock(HTTPGatewayContext.class); + APIGatewayRequestEvent event = mapper.toApiGatewayRequestEvent(httpGatewayContextMock, payload); + String body = event.getBody(); + + assertEquals("value", body); + } + + @Test + public void testGetBodyObject() { + Animal request = new Animal("value", 1); + HTTPGatewayContext httpGatewayContextMock = mock(HTTPGatewayContext.class); + APIGatewayRequestEvent event = mapper.toApiGatewayRequestEvent(httpGatewayContextMock, request); + Animal body = event.getBody(); + + assertEquals(request, body); + } + + @Test + public void testGetNullBodyObject() { + HTTPGatewayContext httpGatewayContextMock = mock(HTTPGatewayContext.class); + APIGatewayRequestEvent event = mapper.toApiGatewayRequestEvent(httpGatewayContextMock, null); + Animal body = event.getBody(); + + assertNull(body); + } + + @Test + public void testGetMethod() { + HTTPGatewayContext httpGatewayContextMock = mock(HTTPGatewayContext.class); + when(httpGatewayContextMock.getMethod()).thenReturn("GET"); + APIGatewayRequestEvent event = mapper.toApiGatewayRequestEvent(httpGatewayContextMock, ""); + String method = event.getMethod(); + + assertEquals("GET", method); + } + + @Test + public void testGetHeaders() { + HTTPGatewayContext httpGatewayContextMock = mock(HTTPGatewayContext.class); + + Headers headers = Headers.emptyHeaders().addHeader("key1", "value1"); + when(httpGatewayContextMock.getHeaders()).thenReturn(headers); + + APIGatewayRequestEvent event = mapper.toApiGatewayRequestEvent(httpGatewayContextMock, ""); + Headers eventHeaders = event.getHeaders(); + + assertEquals("value1", eventHeaders.get("key1").get()); + } + + @Test + public void testGetRepeatedHeaders() { + HTTPGatewayContext httpGatewayContextMock = mock(HTTPGatewayContext.class); + Headers headers = Headers.emptyHeaders().addHeader("repeat", "1", "2"); + when(httpGatewayContextMock.getHeaders()).thenReturn(headers); + + APIGatewayRequestEvent event = mapper.toApiGatewayRequestEvent(httpGatewayContextMock, ""); + Headers eventHeaders = event.getHeaders(); + + assertEquals("1", eventHeaders.getAllValues("repeat").get(0)); + assertEquals("2", eventHeaders.getAllValues("repeat").get(1)); + } +} \ No newline at end of file diff --git a/fn-events/src/test/java/com/fnproject/events/output/APIGatewayResponseEventTest.java b/fn-events/src/test/java/com/fnproject/events/output/APIGatewayResponseEventTest.java new file mode 100644 index 00000000..f2b83ca8 --- /dev/null +++ b/fn-events/src/test/java/com/fnproject/events/output/APIGatewayResponseEventTest.java @@ -0,0 +1,63 @@ +package com.fnproject.events.output; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNull; +import java.util.Collections; +import java.util.List; +import com.fnproject.events.testfns.Animal; +import com.fnproject.fn.api.Headers; +import org.junit.Test; + +public class APIGatewayResponseEventTest { + + @Test + public void testGetBody() { + String body = "body"; + APIGatewayResponseEvent event = new APIGatewayResponseEvent.Builder().body(body).build(); + assertEquals("body", event.getBody()); + } + + @Test + public void testGetBodyAsObject() { + Animal response = new Animal("body", 1); + APIGatewayResponseEvent event = new APIGatewayResponseEvent.Builder().body(response).build(); + assertEquals(response, event.getBody()); + } + + @Test + public void testGetBodyAsList() { + Animal response = new Animal("body", 1); + List list = Collections.singletonList(response); + APIGatewayResponseEvent> event = new APIGatewayResponseEvent.Builder>().body(list).build(); + assertEquals(list, event.getBody()); + } + + @Test + public void testGetNullBody() { + APIGatewayResponseEvent> event = new APIGatewayResponseEvent.Builder>().body(null).build(); + assertNull(event.getBody()); + } + + @Test + public void testGetStatus() { + APIGatewayResponseEvent event = new APIGatewayResponseEvent.Builder().statusCode(201).build(); + assertEquals(Integer.valueOf(201), event.getStatus()); + } + + @Test + public void testGetHeaders() { + Headers headers = Headers.emptyHeaders().addHeader("foo","bar"); + APIGatewayResponseEvent event = new APIGatewayResponseEvent.Builder().headers(headers).build(); + assertEquals(headers, event.getHeaders()); + } + + @Test + public void testGetRepeatedHeaders() { + Headers headers = Headers.emptyHeaders().addHeader("repeated", "foo").addHeader("repeated", "bar"); + APIGatewayResponseEvent event = new APIGatewayResponseEvent.Builder() + .headers(headers) + .build(); + assertEquals("foo", event.getHeaders().getAllValues("repeated").get(0)); + assertEquals("bar", event.getHeaders().getAllValues("repeated").get(1)); + } +} \ No newline at end of file diff --git a/fn-events/src/test/java/com/fnproject/events/testfns/Animal.java b/fn-events/src/test/java/com/fnproject/events/testfns/Animal.java new file mode 100644 index 00000000..0a82911c --- /dev/null +++ b/fn-events/src/test/java/com/fnproject/events/testfns/Animal.java @@ -0,0 +1,50 @@ +package com.fnproject.events.testfns; + +import java.util.Objects; +import com.fasterxml.jackson.annotation.JsonCreator; +import com.fasterxml.jackson.annotation.JsonProperty; + +public class Animal { + private final String name; + private final int age; + + @JsonCreator + public Animal(@JsonProperty("name") String name, + @JsonProperty("age") int age) { + this.name = name; + this.age = age; + } + + public int getAge() { + return age; + } + + public String getName() { + return name; + } + + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } + Animal animal = (Animal) o; + return age == animal.age && Objects.equals(name, animal.name); + } + + @Override + public int hashCode() { + return Objects.hash(name, age); + } + + @Override + public String toString() { + return "Animal{" + + "name='" + name + '\'' + + ", age=" + age + + '}'; + } +} diff --git a/fn-events/src/test/java/com/fnproject/events/testfns/Car.java b/fn-events/src/test/java/com/fnproject/events/testfns/Car.java new file mode 100644 index 00000000..7ff1efe4 --- /dev/null +++ b/fn-events/src/test/java/com/fnproject/events/testfns/Car.java @@ -0,0 +1,24 @@ +package com.fnproject.events.testfns; + +import com.fasterxml.jackson.annotation.JsonCreator; +import com.fasterxml.jackson.annotation.JsonProperty; + +public class Car { + private final String brand; + private final int wheels; + + @JsonCreator + public Car(@JsonProperty("brand") String brand, + @JsonProperty("wheels") int wheels) { + this.brand = brand; + this.wheels = wheels; + } + + public int getWheels() { + return wheels; + } + + public String getBrand() { + return brand; + } +} diff --git a/fn-events/src/test/java/com/fnproject/events/testfns/apigatewayfns/APIGatewayTestFunction.java b/fn-events/src/test/java/com/fnproject/events/testfns/apigatewayfns/APIGatewayTestFunction.java new file mode 100644 index 00000000..64c8edb3 --- /dev/null +++ b/fn-events/src/test/java/com/fnproject/events/testfns/apigatewayfns/APIGatewayTestFunction.java @@ -0,0 +1,16 @@ +package com.fnproject.events.testfns.apigatewayfns; + +import com.fnproject.events.APIGatewayFunction; +import com.fnproject.events.input.APIGatewayRequestEvent; +import com.fnproject.events.output.APIGatewayResponseEvent; +import com.fnproject.events.testfns.Animal; +import com.fnproject.events.testfns.Car; + +public class APIGatewayTestFunction extends APIGatewayFunction { + @Override + public APIGatewayResponseEvent handler(APIGatewayRequestEvent requestEvent) { + return new APIGatewayResponseEvent.Builder() + .body(new Car("ford", 4)) + .build(); + } +} diff --git a/fn-events/src/test/java/com/fnproject/events/testfns/apigatewayfns/GrandChildGatewayTestFunction.java b/fn-events/src/test/java/com/fnproject/events/testfns/apigatewayfns/GrandChildGatewayTestFunction.java new file mode 100644 index 00000000..3364fd32 --- /dev/null +++ b/fn-events/src/test/java/com/fnproject/events/testfns/apigatewayfns/GrandChildGatewayTestFunction.java @@ -0,0 +1,11 @@ +package com.fnproject.events.testfns.apigatewayfns; + +import com.fnproject.events.input.APIGatewayRequestEvent; +import com.fnproject.events.output.APIGatewayResponseEvent; + +public class GrandChildGatewayTestFunction extends StringAPIGatewayTestFunction { + @Override + public APIGatewayResponseEvent handler(APIGatewayRequestEvent requestEvent) { + return super.handler(requestEvent); + } +} diff --git a/fn-events/src/test/java/com/fnproject/events/testfns/apigatewayfns/ListAPIGatewayTestFunction.java b/fn-events/src/test/java/com/fnproject/events/testfns/apigatewayfns/ListAPIGatewayTestFunction.java new file mode 100644 index 00000000..b1b5d0d2 --- /dev/null +++ b/fn-events/src/test/java/com/fnproject/events/testfns/apigatewayfns/ListAPIGatewayTestFunction.java @@ -0,0 +1,18 @@ +package com.fnproject.events.testfns.apigatewayfns; + +import java.util.Collections; +import java.util.List; +import com.fnproject.events.APIGatewayFunction; +import com.fnproject.events.input.APIGatewayRequestEvent; +import com.fnproject.events.output.APIGatewayResponseEvent; +import com.fnproject.events.testfns.Animal; +import com.fnproject.events.testfns.Car; + +public class ListAPIGatewayTestFunction extends APIGatewayFunction, List> { + @Override + public APIGatewayResponseEvent> handler(APIGatewayRequestEvent> requestEvent) { + return new APIGatewayResponseEvent.Builder>() + .body(Collections.singletonList(new Car("ford", 4))) + .build(); + } +} \ No newline at end of file diff --git a/fn-events/src/test/java/com/fnproject/events/testfns/apigatewayfns/StringAPIGatewayTestFunction.java b/fn-events/src/test/java/com/fnproject/events/testfns/apigatewayfns/StringAPIGatewayTestFunction.java new file mode 100644 index 00000000..96c35f58 --- /dev/null +++ b/fn-events/src/test/java/com/fnproject/events/testfns/apigatewayfns/StringAPIGatewayTestFunction.java @@ -0,0 +1,16 @@ +package com.fnproject.events.testfns.apigatewayfns; + +import com.fnproject.events.APIGatewayFunction; +import com.fnproject.events.input.APIGatewayRequestEvent; +import com.fnproject.events.output.APIGatewayResponseEvent; + +public class StringAPIGatewayTestFunction extends APIGatewayFunction { + @Override + public APIGatewayResponseEvent handler(APIGatewayRequestEvent requestEvent) { + return new APIGatewayResponseEvent.Builder() + .body("test response") + .statusCode(200) + .headers(requestEvent.getHeaders()) + .build(); + } +} diff --git a/fn-events/src/test/java/com/fnproject/events/testfns/apigatewayfns/UncheckedAPIGatewayTestFunction.java b/fn-events/src/test/java/com/fnproject/events/testfns/apigatewayfns/UncheckedAPIGatewayTestFunction.java new file mode 100644 index 00000000..7d2912b6 --- /dev/null +++ b/fn-events/src/test/java/com/fnproject/events/testfns/apigatewayfns/UncheckedAPIGatewayTestFunction.java @@ -0,0 +1,14 @@ +package com.fnproject.events.testfns.apigatewayfns; + +import com.fnproject.events.APIGatewayFunction; +import com.fnproject.events.input.APIGatewayRequestEvent; +import com.fnproject.events.output.APIGatewayResponseEvent; + +public class UncheckedAPIGatewayTestFunction extends APIGatewayFunction { + @Override + public APIGatewayResponseEvent handler(APIGatewayRequestEvent requestEvent) { + return new APIGatewayResponseEvent.Builder() + .body("test response") + .build(); + } +} diff --git a/fn-events/src/test/java/com/fnproject/events/testfns/connectorhub/GrandChildMonitorSourceTestFunction.java b/fn-events/src/test/java/com/fnproject/events/testfns/connectorhub/GrandChildMonitorSourceTestFunction.java new file mode 100644 index 00000000..224d8182 --- /dev/null +++ b/fn-events/src/test/java/com/fnproject/events/testfns/connectorhub/GrandChildMonitorSourceTestFunction.java @@ -0,0 +1,12 @@ +package com.fnproject.events.testfns.connectorhub; + +import com.fnproject.events.input.ConnectorHubBatch; +import com.fnproject.events.input.sch.MetricData; + +public class GrandChildMonitorSourceTestFunction extends MonitorSourceTestFunction { + + @Override + public void handler(ConnectorHubBatch batch) { + super.handler(batch); + } +} diff --git a/fn-events/src/test/java/com/fnproject/events/testfns/connectorhub/LoggingSourceTestFunction.java b/fn-events/src/test/java/com/fnproject/events/testfns/connectorhub/LoggingSourceTestFunction.java new file mode 100644 index 00000000..de8ffb84 --- /dev/null +++ b/fn-events/src/test/java/com/fnproject/events/testfns/connectorhub/LoggingSourceTestFunction.java @@ -0,0 +1,13 @@ +package com.fnproject.events.testfns.connectorhub; + +import com.fnproject.events.ConnectorHubFunction; +import com.fnproject.events.input.ConnectorHubBatch; +import com.fnproject.events.input.sch.LoggingData; + +public class LoggingSourceTestFunction extends ConnectorHubFunction { + + @Override + public void handler(ConnectorHubBatch batch) { + + } +} diff --git a/fn-events/src/test/java/com/fnproject/events/testfns/connectorhub/MonitorSourceTestFunction.java b/fn-events/src/test/java/com/fnproject/events/testfns/connectorhub/MonitorSourceTestFunction.java new file mode 100644 index 00000000..5629204e --- /dev/null +++ b/fn-events/src/test/java/com/fnproject/events/testfns/connectorhub/MonitorSourceTestFunction.java @@ -0,0 +1,13 @@ +package com.fnproject.events.testfns.connectorhub; + +import com.fnproject.events.ConnectorHubFunction; +import com.fnproject.events.input.ConnectorHubBatch; +import com.fnproject.events.input.sch.MetricData; + +public class MonitorSourceTestFunction extends ConnectorHubFunction { + + @Override + public void handler(ConnectorHubBatch batch) { + + } +} diff --git a/fn-events/src/test/java/com/fnproject/events/testfns/connectorhub/QueueSourceObjectTestFunction.java b/fn-events/src/test/java/com/fnproject/events/testfns/connectorhub/QueueSourceObjectTestFunction.java new file mode 100644 index 00000000..99b43583 --- /dev/null +++ b/fn-events/src/test/java/com/fnproject/events/testfns/connectorhub/QueueSourceObjectTestFunction.java @@ -0,0 +1,13 @@ +package com.fnproject.events.testfns.connectorhub; + +import com.fnproject.events.ConnectorHubFunction; +import com.fnproject.events.input.ConnectorHubBatch; +import com.fnproject.events.testfns.Animal; + +public class QueueSourceObjectTestFunction extends ConnectorHubFunction { + + @Override + public void handler(ConnectorHubBatch batch) { + + } +} diff --git a/fn-events/src/test/java/com/fnproject/events/testfns/connectorhub/QueueSourceStringTestFunction.java b/fn-events/src/test/java/com/fnproject/events/testfns/connectorhub/QueueSourceStringTestFunction.java new file mode 100644 index 00000000..e3d82f00 --- /dev/null +++ b/fn-events/src/test/java/com/fnproject/events/testfns/connectorhub/QueueSourceStringTestFunction.java @@ -0,0 +1,12 @@ +package com.fnproject.events.testfns.connectorhub; + +import com.fnproject.events.ConnectorHubFunction; +import com.fnproject.events.input.ConnectorHubBatch; + +public class QueueSourceStringTestFunction extends ConnectorHubFunction { + + @Override + public void handler(ConnectorHubBatch batch) { + + } +} diff --git a/fn-events/src/test/java/com/fnproject/events/testfns/connectorhub/StreamingSourceObjectTestFunction.java b/fn-events/src/test/java/com/fnproject/events/testfns/connectorhub/StreamingSourceObjectTestFunction.java new file mode 100644 index 00000000..c1527d7f --- /dev/null +++ b/fn-events/src/test/java/com/fnproject/events/testfns/connectorhub/StreamingSourceObjectTestFunction.java @@ -0,0 +1,14 @@ +package com.fnproject.events.testfns.connectorhub; + +import com.fnproject.events.ConnectorHubFunction; +import com.fnproject.events.input.ConnectorHubBatch; +import com.fnproject.events.input.sch.StreamingData; +import com.fnproject.events.testfns.Animal; + +public class StreamingSourceObjectTestFunction extends ConnectorHubFunction> { + + @Override + public void handler(ConnectorHubBatch> batch) { + + } +} diff --git a/fn-events/src/test/java/com/fnproject/events/testfns/connectorhub/StreamingSourceStringTestFunction.java b/fn-events/src/test/java/com/fnproject/events/testfns/connectorhub/StreamingSourceStringTestFunction.java new file mode 100644 index 00000000..dfe2bdd1 --- /dev/null +++ b/fn-events/src/test/java/com/fnproject/events/testfns/connectorhub/StreamingSourceStringTestFunction.java @@ -0,0 +1,14 @@ +package com.fnproject.events.testfns.connectorhub; + +import com.fnproject.events.ConnectorHubFunction; +import com.fnproject.events.input.ConnectorHubBatch; +import com.fnproject.events.input.sch.StreamingData; +import com.fnproject.events.testfns.Animal; + +public class StreamingSourceStringTestFunction extends ConnectorHubFunction> { + + @Override + public void handler(ConnectorHubBatch> batch) { + + } +} diff --git a/fn-events/src/test/java/com/fnproject/events/testfns/notification/NotificationObjectTestFunction.java b/fn-events/src/test/java/com/fnproject/events/testfns/notification/NotificationObjectTestFunction.java new file mode 100644 index 00000000..54c0f873 --- /dev/null +++ b/fn-events/src/test/java/com/fnproject/events/testfns/notification/NotificationObjectTestFunction.java @@ -0,0 +1,13 @@ +package com.fnproject.events.testfns.notification; + +import com.fnproject.events.NotificationFunction; +import com.fnproject.events.input.NotificationMessage; +import com.fnproject.events.testfns.Animal; + +public class NotificationObjectTestFunction extends NotificationFunction { + + @Override + public void handler(NotificationMessage batch) { + + } +} diff --git a/fn-events/src/test/java/com/fnproject/events/testfns/notification/NotificationStringTestFunction.java b/fn-events/src/test/java/com/fnproject/events/testfns/notification/NotificationStringTestFunction.java new file mode 100644 index 00000000..18a94eb9 --- /dev/null +++ b/fn-events/src/test/java/com/fnproject/events/testfns/notification/NotificationStringTestFunction.java @@ -0,0 +1,12 @@ +package com.fnproject.events.testfns.notification; + +import com.fnproject.events.NotificationFunction; +import com.fnproject.events.input.NotificationMessage; + +public class NotificationStringTestFunction extends NotificationFunction { + + @Override + public void handler(NotificationMessage batch) { + + } +} From 084f5c12cc17737bdde244fbf753006995d74c42 Mon Sep 17 00:00:00 2001 From: CI Date: Mon, 5 Jan 2026 19:58:38 +0000 Subject: [PATCH 304/310] Releasing version 1.1.3 --- release.version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/release.version b/release.version index 45a1b3f4..781dcb07 100644 --- a/release.version +++ b/release.version @@ -1 +1 @@ -1.1.2 +1.1.3 From 6e0ca35a7d65250168c2f26fca761fea517c5edd Mon Sep 17 00:00:00 2001 From: CI Date: Fri, 23 Jan 2026 06:23:55 +0000 Subject: [PATCH 305/310] Releasing version 1.1.4 --- release.version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/release.version b/release.version index 781dcb07..65087b4f 100644 --- a/release.version +++ b/release.version @@ -1 +1 @@ -1.1.3 +1.1.4 From fcd94f34e4af5e9d6eeab978e56afcfc1c8caaa0 Mon Sep 17 00:00:00 2001 From: CI Date: Wed, 4 Feb 2026 15:48:20 +0000 Subject: [PATCH 306/310] Releasing version 1.1.5 --- release.version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/release.version b/release.version index 65087b4f..e25d8d9f 100644 --- a/release.version +++ b/release.version @@ -1 +1 @@ -1.1.4 +1.1.5 From e03dde482b5d3561b73be436348e2d99d7307434 Mon Sep 17 00:00:00 2001 From: CI Date: Thu, 26 Feb 2026 10:48:54 +0000 Subject: [PATCH 307/310] Releasing version 1.1.7 --- release.version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/release.version b/release.version index e25d8d9f..2bf1ca5f 100644 --- a/release.version +++ b/release.version @@ -1 +1 @@ -1.1.5 +1.1.7 From 0802078dd4277a86dbb8682e3ca934fb1a8cae60 Mon Sep 17 00:00:00 2001 From: CI Date: Wed, 1 Apr 2026 06:11:04 +0000 Subject: [PATCH 308/310] Releasing version 1.1.11 --- .gitignore | 2 +- pom.xml | 2 +- release.version | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/.gitignore b/.gitignore index e33dd4d3..cb830517 100644 --- a/.gitignore +++ b/.gitignore @@ -17,4 +17,4 @@ examples/gradle-build/build **/*.project **/*.settings .oca/ - +.csis \ No newline at end of file diff --git a/pom.xml b/pom.xml index 99f454cf..283110c0 100644 --- a/pom.xml +++ b/pom.xml @@ -86,7 +86,7 @@ 3.21.0 2.14.0 4.4.14 - 2.16.1 + 2.21.2 0.8.1 9.4.12.v20180830 4.13.2 diff --git a/release.version b/release.version index 2bf1ca5f..9ee1f786 100644 --- a/release.version +++ b/release.version @@ -1 +1 @@ -1.1.7 +1.1.11 From f1518a0dd5f419270871b3dc8a0564e03225e3ca Mon Sep 17 00:00:00 2001 From: CI Date: Thu, 7 May 2026 11:13:50 +0000 Subject: [PATCH 309/310] Releasing version 1.1.12 --- release.version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/release.version b/release.version index 9ee1f786..ccad953a 100644 --- a/release.version +++ b/release.version @@ -1 +1 @@ -1.1.11 +1.1.12 From 5fa72720e66725a714de26efbcccb55b988e323d Mon Sep 17 00:00:00 2001 From: CI Date: Tue, 9 Jun 2026 05:45:41 +0000 Subject: [PATCH 310/310] Releasing version 1.1.14 --- release.version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/release.version b/release.version index ccad953a..e9bc1499 100644 --- a/release.version +++ b/release.version @@ -1 +1 @@ -1.1.12 +1.1.14