From 46b3ab8af7afc075ea6ee3047b20df0edfb1d8c8 Mon Sep 17 00:00:00 2001 From: Sanket Sudake Date: Tue, 9 Jun 2026 09:24:23 +0530 Subject: [PATCH 1/2] Move examples to fission/examples; vendor minimal CI fixtures Runnable examples now live canonically in the fission/examples repo. This removes the duplicated examples/ directory from every environment. To keep the environment test suites self-contained, the minimal function code each test needs is vendored under that environment's test dir as tests/fixtures/ (or test/fixtures/), and the test scripts are repointed: - binary, python, python-fastapi, rust, jvm, tensorflow-serving - jvm: adjusted the install-fission-java-core.sh mount depth for the new fixture path README "ready-to-run examples" links now point at github.com/fission/examples. Updated CLAUDE.md and the release-process note accordingly. Co-Authored-By: Claude Opus 4.8 (1M context) --- .claude/resources/release-process.md | 2 +- CLAUDE.md | 5 +- binary/examples/README.md | 80 ----------- binary/examples/headers.sh | 3 - binary/examples/hello.go | 12 -- binary/examples/hello.sh | 3 - binary/examples/module-example/test.sh | 15 -- binary/{examples => test/fixtures}/echo.sh | 0 binary/test/local_test.sh | 2 +- dotnet/README.md | 2 +- dotnet/examples/arguments.cs | 11 -- dotnet/examples/helloworld.cs | 9 -- dotnet/examples/requestbody.cs | 24 ---- dotnet/examples/requestheaders.cs | 17 --- dotnet20/README.md | 2 +- dotnet20/examples/arguments.cs | 11 -- dotnet20/examples/echo.cs | 10 -- dotnet20/examples/helloworld.cs | 9 -- dotnet20/examples/requestbody.cs | 24 ---- dotnet20/examples/requestheaders.cs | 17 --- .../AsyncFunctionExample.csproj | 14 -- .../AsyncFunctionExample/MyFunction.cs | 17 --- dotnet8/examples/HelloWorld/HelloWorld.csproj | 11 -- dotnet8/examples/HelloWorld/MyFunction.cs | 9 -- .../HttpTriggerExample.csproj | 11 -- .../examples/HttpTriggerExample/MyFunction.cs | 14 -- .../Controllers/ApiController.cs | 129 ----------------- .../MultiFileExample/Models/DataModels.cs | 43 ------ .../examples/MultiFileExample/Models/User.cs | 23 --- .../MultiFileExample/Models/Weather.cs | 34 ----- .../MultiFileExample/MultiFileExample.csproj | 19 --- .../examples/MultiFileExample/MyFunction.cs | 23 --- dotnet8/examples/MultiFileExample/README.md | 116 ---------------- .../Services/DataProcessor.cs | 81 ----------- .../MultiFileExample/Services/UserService.cs | 65 --------- .../Services/WeatherService.cs | 64 --------- go/README.md | 2 +- go/examples/README.md | 23 --- go/examples/hello.go | 11 -- go/examples/module-example/README.md | 29 ---- go/examples/module-example/go.mod | 5 - go/examples/module-example/go.sum | 23 --- go/examples/module-example/main.go | 17 --- go/examples/specs/env.yaml | 12 -- .../specs/fission-deployment-config.yaml | 6 - go/examples/specs/function-hello.yaml | 39 ------ jvm-jersey/README.md | 2 +- jvm-jersey/examples/java/pom.xml | 76 ---------- jvm-jersey/examples/java/specs/env-java.yaml | 17 --- .../java/specs/fission-deployment-config.yaml | 7 - .../examples/java/specs/function-hello.yaml | 27 ---- .../java/specs/package-hellojava.yaml | 26 ---- .../src/main/java/io/fission/HelloWorld.java | 25 ---- .../test/java/io/fission/HelloWorldTest.java | 25 ---- jvm/README.md | 2 +- jvm/examples/java/.gitignore | 4 - jvm/examples/java/README.md | 60 -------- jvm/examples/java/build.sh | 5 - jvm/examples/java/specs/README | 42 ------ .../tests/fixtures}/java/.gitignore | 0 .../tests/fixtures}/java/README.md | 0 .../tests/fixtures}/java/build.sh | 0 jvm/{examples => tests/fixtures}/java/pom.xml | 0 .../tests/fixtures}/java/specs/README | 0 .../fixtures}/java/specs/env-java.yaml | 0 .../java/specs/fission-deployment-config.yaml | 0 .../fixtures}/java/specs/function-hello.yaml | 0 .../java/specs/package-hellojava.yaml | 0 .../src/main/java/io/fission/HelloWorld.java | 0 .../test/java/io/fission/HelloWorldTest.java | 0 jvm/tests/test_java_env.sh | 4 +- nodejs/README.md | 2 +- nodejs/examples/README.md | 131 ------------------ nodejs/examples/README_V1.md | 105 -------------- nodejs/examples/broadcast.js | 9 -- nodejs/examples/echo.js | 6 - nodejs/examples/hello-callback.js | 4 - nodejs/examples/hello-esm.js | 14 -- nodejs/examples/hello.js | 7 - nodejs/examples/index.html | 98 ------------- nodejs/examples/index.js | 1 - nodejs/examples/kubeEventsSlack.js | 64 --------- nodejs/examples/multi-entry-esm.js | 40 ------ nodejs/examples/multi-entry.js | 13 -- nodejs/examples/package.json | 29 ---- nodejs/examples/weather-esm.js | 82 ----------- nodejs/examples/weather.js | 37 ----- perl/examples/hello.pm | 36 ----- php7/README.md | 2 +- php7/examples/hello.php | 3 - php7/examples/hellopsr.php | 12 -- php7/examples/multifile/README.md | 69 --------- php7/examples/multifile/composer.json | 14 -- .../multifile/handlers/FileReader.php | 16 --- php7/examples/multifile/handlers/message.txt | 1 - php7/examples/stock.php | 47 ------- python-fastapi/examples/README.md | 27 ---- python-fastapi/examples/guestbook/add.py | 20 --- python-fastapi/examples/guestbook/build.sh | 2 - python-fastapi/examples/guestbook/deploy.sh | 24 ---- python-fastapi/examples/guestbook/get.py | 29 ---- python-fastapi/examples/guestbook/redis.yaml | 45 ------ .../examples/guestbook/requirements.txt | 3 - python-fastapi/examples/multifile/README.md | 62 --------- python-fastapi/examples/multifile/__init__.py | 0 python-fastapi/examples/multifile/main.py | 11 -- python-fastapi/examples/multifile/message.txt | 1 - python-fastapi/examples/multifile/readfile.py | 3 - python-fastapi/examples/requestdata.py | 6 - python-fastapi/examples/sourcepkg/__init__.py | 0 python-fastapi/examples/sourcepkg/build.sh | 2 - .../examples/sourcepkg/requirements.txt | 1 - python-fastapi/examples/sourcepkg/user.py | 18 --- python-fastapi/examples/statuscode.py | 4 - .../{examples => tests/fixtures}/hello.py | 0 python-fastapi/tests/local_test.sh | 2 +- .../tests/test_python_fastapi_env.sh | 2 +- python/examples/README.md | 29 ---- python/examples/guestbook/add.py | 18 --- python/examples/guestbook/deploy.sh | 18 --- python/examples/guestbook/get.py | 28 ---- python/examples/guestbook/redis.yaml | 45 ------ python/examples/multifile/README.md | 62 --------- python/examples/multifile/__init__.py | 0 python/examples/multifile/main.py | 11 -- python/examples/multifile/message.txt | 1 - python/examples/multifile/readfile.py | 3 - python/examples/requestdata.py | 7 - python/examples/sourcepkg/__init__.py | 0 python/examples/sourcepkg/build.sh | 2 - python/examples/sourcepkg/requirements.txt | 1 - python/examples/sourcepkg/user.py | 11 -- python/examples/statuscode.py | 4 - python/{examples => tests/fixtures}/hello.py | 0 .../fixtures}/websocket/main.py | 0 python/tests/local_test.sh | 2 +- python/tests/test_python_env.sh | 2 +- python/tests/websocket_test.sh | 2 +- ruby/README.md | 2 +- ruby/examples/README.md | 115 --------------- ruby/examples/events_to_slack.rb | 33 ----- ruby/examples/hello.rb | 4 - ruby/examples/parse/Gemfile | 7 - ruby/examples/parse/Gemfile.lock | 42 ------ ruby/examples/parse/parse.rb | 13 -- ruby/examples/request_data.rb | 20 --- rust/README.md | 5 +- rust/examples/README.md | 25 ---- rust/examples/hello.rs | 7 - .../fixtures}/project-example/Cargo.lock | 0 .../fixtures}/project-example/Cargo.toml | 0 .../fixtures}/project-example/src/main.rs | 0 rust/test/local_test.sh | 4 +- tensorflow-serving/examples/README.md | 24 ---- .../half_plus_two/00000123/saved_model.pb | Bin .../variables/variables.data-00000-of-00001 | Bin .../00000123/variables/variables.index | Bin .../tests/test_tensorflow_serving_env.sh | 2 +- 158 files changed, 27 insertions(+), 3046 deletions(-) delete mode 100644 binary/examples/README.md delete mode 100644 binary/examples/headers.sh delete mode 100644 binary/examples/hello.go delete mode 100755 binary/examples/hello.sh delete mode 100755 binary/examples/module-example/test.sh rename binary/{examples => test/fixtures}/echo.sh (100%) delete mode 100644 dotnet/examples/arguments.cs delete mode 100644 dotnet/examples/helloworld.cs delete mode 100644 dotnet/examples/requestbody.cs delete mode 100644 dotnet/examples/requestheaders.cs delete mode 100644 dotnet20/examples/arguments.cs delete mode 100644 dotnet20/examples/echo.cs delete mode 100644 dotnet20/examples/helloworld.cs delete mode 100644 dotnet20/examples/requestbody.cs delete mode 100644 dotnet20/examples/requestheaders.cs delete mode 100644 dotnet8/examples/AsyncFunctionExample/AsyncFunctionExample.csproj delete mode 100644 dotnet8/examples/AsyncFunctionExample/MyFunction.cs delete mode 100644 dotnet8/examples/HelloWorld/HelloWorld.csproj delete mode 100644 dotnet8/examples/HelloWorld/MyFunction.cs delete mode 100644 dotnet8/examples/HttpTriggerExample/HttpTriggerExample.csproj delete mode 100644 dotnet8/examples/HttpTriggerExample/MyFunction.cs delete mode 100644 dotnet8/examples/MultiFileExample/Controllers/ApiController.cs delete mode 100644 dotnet8/examples/MultiFileExample/Models/DataModels.cs delete mode 100644 dotnet8/examples/MultiFileExample/Models/User.cs delete mode 100644 dotnet8/examples/MultiFileExample/Models/Weather.cs delete mode 100644 dotnet8/examples/MultiFileExample/MultiFileExample.csproj delete mode 100644 dotnet8/examples/MultiFileExample/MyFunction.cs delete mode 100644 dotnet8/examples/MultiFileExample/README.md delete mode 100644 dotnet8/examples/MultiFileExample/Services/DataProcessor.cs delete mode 100644 dotnet8/examples/MultiFileExample/Services/UserService.cs delete mode 100644 dotnet8/examples/MultiFileExample/Services/WeatherService.cs delete mode 100644 go/examples/README.md delete mode 100644 go/examples/hello.go delete mode 100644 go/examples/module-example/README.md delete mode 100644 go/examples/module-example/go.mod delete mode 100644 go/examples/module-example/go.sum delete mode 100644 go/examples/module-example/main.go delete mode 100644 go/examples/specs/env.yaml delete mode 100644 go/examples/specs/fission-deployment-config.yaml delete mode 100644 go/examples/specs/function-hello.yaml delete mode 100644 jvm-jersey/examples/java/pom.xml delete mode 100644 jvm-jersey/examples/java/specs/env-java.yaml delete mode 100644 jvm-jersey/examples/java/specs/fission-deployment-config.yaml delete mode 100644 jvm-jersey/examples/java/specs/function-hello.yaml delete mode 100644 jvm-jersey/examples/java/specs/package-hellojava.yaml delete mode 100644 jvm-jersey/examples/java/src/main/java/io/fission/HelloWorld.java delete mode 100644 jvm-jersey/examples/java/src/test/java/io/fission/HelloWorldTest.java delete mode 100644 jvm/examples/java/.gitignore delete mode 100644 jvm/examples/java/README.md delete mode 100755 jvm/examples/java/build.sh delete mode 100644 jvm/examples/java/specs/README rename {jvm-jersey/examples => jvm/tests/fixtures}/java/.gitignore (100%) rename {jvm-jersey/examples => jvm/tests/fixtures}/java/README.md (100%) rename {jvm-jersey/examples => jvm/tests/fixtures}/java/build.sh (100%) rename jvm/{examples => tests/fixtures}/java/pom.xml (100%) rename {jvm-jersey/examples => jvm/tests/fixtures}/java/specs/README (100%) rename jvm/{examples => tests/fixtures}/java/specs/env-java.yaml (100%) rename jvm/{examples => tests/fixtures}/java/specs/fission-deployment-config.yaml (100%) rename jvm/{examples => tests/fixtures}/java/specs/function-hello.yaml (100%) rename jvm/{examples => tests/fixtures}/java/specs/package-hellojava.yaml (100%) rename jvm/{examples => tests/fixtures}/java/src/main/java/io/fission/HelloWorld.java (100%) rename jvm/{examples => tests/fixtures}/java/src/test/java/io/fission/HelloWorldTest.java (100%) delete mode 100644 nodejs/examples/README.md delete mode 100644 nodejs/examples/README_V1.md delete mode 100644 nodejs/examples/broadcast.js delete mode 100644 nodejs/examples/echo.js delete mode 100644 nodejs/examples/hello-callback.js delete mode 100644 nodejs/examples/hello-esm.js delete mode 100644 nodejs/examples/hello.js delete mode 100644 nodejs/examples/index.html delete mode 100644 nodejs/examples/index.js delete mode 100644 nodejs/examples/kubeEventsSlack.js delete mode 100644 nodejs/examples/multi-entry-esm.js delete mode 100644 nodejs/examples/multi-entry.js delete mode 100644 nodejs/examples/package.json delete mode 100644 nodejs/examples/weather-esm.js delete mode 100644 nodejs/examples/weather.js delete mode 100644 perl/examples/hello.pm delete mode 100644 php7/examples/hello.php delete mode 100644 php7/examples/hellopsr.php delete mode 100644 php7/examples/multifile/README.md delete mode 100644 php7/examples/multifile/composer.json delete mode 100644 php7/examples/multifile/handlers/FileReader.php delete mode 100644 php7/examples/multifile/handlers/message.txt delete mode 100644 php7/examples/stock.php delete mode 100644 python-fastapi/examples/README.md delete mode 100644 python-fastapi/examples/guestbook/add.py delete mode 100755 python-fastapi/examples/guestbook/build.sh delete mode 100755 python-fastapi/examples/guestbook/deploy.sh delete mode 100644 python-fastapi/examples/guestbook/get.py delete mode 100644 python-fastapi/examples/guestbook/redis.yaml delete mode 100644 python-fastapi/examples/guestbook/requirements.txt delete mode 100644 python-fastapi/examples/multifile/README.md delete mode 100644 python-fastapi/examples/multifile/__init__.py delete mode 100644 python-fastapi/examples/multifile/main.py delete mode 100644 python-fastapi/examples/multifile/message.txt delete mode 100644 python-fastapi/examples/multifile/readfile.py delete mode 100644 python-fastapi/examples/requestdata.py delete mode 100644 python-fastapi/examples/sourcepkg/__init__.py delete mode 100755 python-fastapi/examples/sourcepkg/build.sh delete mode 100644 python-fastapi/examples/sourcepkg/requirements.txt delete mode 100644 python-fastapi/examples/sourcepkg/user.py delete mode 100644 python-fastapi/examples/statuscode.py rename python-fastapi/{examples => tests/fixtures}/hello.py (100%) delete mode 100644 python/examples/README.md delete mode 100644 python/examples/guestbook/add.py delete mode 100755 python/examples/guestbook/deploy.sh delete mode 100644 python/examples/guestbook/get.py delete mode 100644 python/examples/guestbook/redis.yaml delete mode 100644 python/examples/multifile/README.md delete mode 100644 python/examples/multifile/__init__.py delete mode 100644 python/examples/multifile/main.py delete mode 100644 python/examples/multifile/message.txt delete mode 100644 python/examples/multifile/readfile.py delete mode 100644 python/examples/requestdata.py delete mode 100644 python/examples/sourcepkg/__init__.py delete mode 100755 python/examples/sourcepkg/build.sh delete mode 100644 python/examples/sourcepkg/requirements.txt delete mode 100644 python/examples/sourcepkg/user.py delete mode 100644 python/examples/statuscode.py rename python/{examples => tests/fixtures}/hello.py (100%) rename python/{examples => tests/fixtures}/websocket/main.py (100%) delete mode 100644 ruby/examples/README.md delete mode 100644 ruby/examples/events_to_slack.rb delete mode 100644 ruby/examples/hello.rb delete mode 100644 ruby/examples/parse/Gemfile delete mode 100644 ruby/examples/parse/Gemfile.lock delete mode 100644 ruby/examples/parse/parse.rb delete mode 100644 ruby/examples/request_data.rb delete mode 100644 rust/examples/README.md delete mode 100644 rust/examples/hello.rs rename rust/{examples => test/fixtures}/project-example/Cargo.lock (100%) rename rust/{examples => test/fixtures}/project-example/Cargo.toml (100%) rename rust/{examples => test/fixtures}/project-example/src/main.rs (100%) delete mode 100644 tensorflow-serving/examples/README.md rename tensorflow-serving/{examples => tests/fixtures}/half_plus_two/00000123/saved_model.pb (100%) rename tensorflow-serving/{examples => tests/fixtures}/half_plus_two/00000123/variables/variables.data-00000-of-00001 (100%) rename tensorflow-serving/{examples => tests/fixtures}/half_plus_two/00000123/variables/variables.index (100%) diff --git a/.claude/resources/release-process.md b/.claude/resources/release-process.md index 8b5ec52c..a8a41d3e 100644 --- a/.claude/resources/release-process.md +++ b/.claude/resources/release-process.md @@ -8,7 +8,7 @@ 3. On merge to master, `.github/workflows/release.yaml` (path filter `**/envconfig.json**`) runs `hack/release_check.py`, which emits a matrix of every `image:version` not yet on ghcr.io; the workflow's `docker-buildx-push` job then runs `TAG= make -img` (and `-img` in `builder/`) plus a `latest` push for each matrix entry. Image content changes without an envconfig bump never release — if a merged change should reach the published image (e.g. a lockfile refresh), follow up with a version-bump PR. -Conversely, examples/ and docs changes don't need a bump (they're not in the image). +Conversely, test fixtures and docs changes don't need a bump (they're not in the image). ## release_check.py semantics diff --git a/CLAUDE.md b/CLAUDE.md index e127799f..9d4db928 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -7,7 +7,10 @@ This file provides guidance to Claude Code (claude.ai/code) when working with co Language runtime environments for [Fission](https://fission.io) (Kubernetes serverless framework). Each top-level directory (`go/`, `python/`, `nodejs/`, `jvm/`, `binary/`, `dotnet8/`, etc.) is one self-contained environment that produces Docker images published to `ghcr.io/fission`. -Every environment follows the same layout: `server.*` (the runtime HTTP server), `Dockerfile` + `Makefile` (runtime image), optional `builder/` (builder image with `build.sh`), `envconfig.json` (metadata; the `version` field drives releases), `examples/`, and `tests/` or `test/`. +Every environment follows the same layout: `server.*` (the runtime HTTP server), `Dockerfile` + `Makefile` (runtime image), optional `builder/` (builder image with `build.sh`), `envconfig.json` (metadata; the `version` field drives releases), and `tests/` or `test/`. + +Runnable examples live in the [fission/examples](https://github.com/fission/examples) repo, not here. +Each `tests/` (or `test/`) dir keeps a small `fixtures/` directory with the minimal function code its CI needs. ## Quick commands diff --git a/binary/examples/README.md b/binary/examples/README.md deleted file mode 100644 index 8acfa187..00000000 --- a/binary/examples/README.md +++ /dev/null @@ -1,80 +0,0 @@ -# Binary Environment Examples - -The `binary` runtime is a go server that uses a subprocess to invoke executables or execute shell scripts. - -For more info read the [environment README](../README.md). - -## Requirements - -First, set up your fission deployment with the binary environment. - -```bash -fission env create --name binary-env --image fission/binary-env -``` - -## Example Usage - -### hello.sh -`hello.sh` is an very basic shell script that returns `"Hello, World!"`. - -```bash -# Upload the function to fission -fission function create --name hello --env binary-env --code hello.sh - -# Map /hello to the hello function -fission route create --method GET --url /hello --function hello - -# Run the function -curl http://$FISSION_ROUTER/hello -``` - -This should return a HTTP response with the body `Hello World!` - -### echo.sh -`echo.sh` shows the the use of STDIN to read the request body, echoing the input back in the response. - -```bash -# Upload the function to fission -fission function create --name echo --env binary-env --code echo.sh - -# Map /hello to the hello function -fission route create --method POST --url /echo --function echo - -# Run the function -curl -XPOST -d 'Echoooooo!' http://$FISSION_ROUTER/echo -``` -This should return a HTTP response with the body `... Echoooooo!`. - - -### headers.sh -`headers.sh` shows the access to the environment variables that hold the HTTP headers, returning the set HTTP headers. - -```bash -# Upload the function to fission -fission function create --name headers --env binary-env --code headers.sh - -# Map /hello to the hello function -fission route create --url /headers --function headers - -# Run the function -curl -H 'X-FOO: BAR' http://$FISSION_ROUTER/headers -``` -This should return a HTTP response with the body `... Echoooooo!`. - -### hello..go -This example shows the differences between using shell scripts and binaries. `hello.go` returns `Hello World!` + the -environment variables it received from the server. - -```bash -# Build the function targeted at the right architecture -GOOS=linux GOARCH=386 go build -o hello-go-func hello.go - -# Upload the function to fission -fission function create --name hello-go --env binary-env --code hello-go-func - -# Map /hello to the hello function -fission route create --url /hello-go --function hello-go - -# Run the function -curl -H 'X-GO: AWESOME!' http://$FISSION_ROUTER/hello-go -``` \ No newline at end of file diff --git a/binary/examples/headers.sh b/binary/examples/headers.sh deleted file mode 100644 index b0790b21..00000000 --- a/binary/examples/headers.sh +++ /dev/null @@ -1,3 +0,0 @@ -#!/bin/sh - -env | grep "^HTTP_" \ No newline at end of file diff --git a/binary/examples/hello.go b/binary/examples/hello.go deleted file mode 100644 index 60bd1a0a..00000000 --- a/binary/examples/hello.go +++ /dev/null @@ -1,12 +0,0 @@ -package main - -import ( - "fmt" - "os" -) - -// See README.md in the examples/binary directory for instructions -func main() { - fmt.Println("Hello World!") - fmt.Printf("Environment: %v", os.Environ()) -} diff --git a/binary/examples/hello.sh b/binary/examples/hello.sh deleted file mode 100755 index 4544d792..00000000 --- a/binary/examples/hello.sh +++ /dev/null @@ -1,3 +0,0 @@ -#!/bin/bash - -echo "Hello World!" \ No newline at end of file diff --git a/binary/examples/module-example/test.sh b/binary/examples/module-example/test.sh deleted file mode 100755 index 1ca57d11..00000000 --- a/binary/examples/module-example/test.sh +++ /dev/null @@ -1,15 +0,0 @@ -#!/bin/sh - -num1=0 -num2=1 - -i=0 -while [ "$i" -le 10 ] -do - echo "$num1 " - sum=$((num1+num2)) - num1=$num2 - num2=$sum - i=$(( i + 1 )) -done -echo "Modules are awesome!" \ No newline at end of file diff --git a/binary/examples/echo.sh b/binary/test/fixtures/echo.sh similarity index 100% rename from binary/examples/echo.sh rename to binary/test/fixtures/echo.sh diff --git a/binary/test/local_test.sh b/binary/test/local_test.sh index 898ad160..0a5e37cd 100755 --- a/binary/test/local_test.sh +++ b/binary/test/local_test.sh @@ -30,7 +30,7 @@ echo "--Healthz" curl -i -f -X GET "$SERVER"/healthz echo "-- Specializing" -curl -i -f -XPOST "$SERVER"/v2/specialize -H 'Content-Type: application/json' -d '{"filepath": "./examples/echo.sh"}' +curl -i -f -XPOST "$SERVER"/v2/specialize -H 'Content-Type: application/json' -d '{"filepath": "./test/fixtures/echo.sh"}' echo "-- Running" curl -i -f -XPOST "$SERVER" -d 'Echoooooo!' diff --git a/dotnet/README.md b/dotnet/README.md index 8991474f..94bf6d78 100644 --- a/dotnet/README.md +++ b/dotnet/README.md @@ -32,7 +32,7 @@ public class FissionFunction { ``` Please see examples below, or if you are looking for ready-to-run examples, see -the [DotNet examples directory](../../examples/dotnet). +the [DotNet examples directory](https://github.com/fission/examples/tree/main/dotnet). ## Rebuilding and pushing the image diff --git a/dotnet/examples/arguments.cs b/dotnet/examples/arguments.cs deleted file mode 100644 index c3e2a48e..00000000 --- a/dotnet/examples/arguments.cs +++ /dev/null @@ -1,11 +0,0 @@ -using System; -using Fission.DotNetCore.Api; - -public class FissionFunction -{ - public string Execute(FissionContext context){ - var x = Convert.ToInt32(context.Arguments["x"]); - var y = Convert.ToInt32(context.Arguments["y"]); - return (x+y).ToString(); - } -} diff --git a/dotnet/examples/helloworld.cs b/dotnet/examples/helloworld.cs deleted file mode 100644 index cae5a7e9..00000000 --- a/dotnet/examples/helloworld.cs +++ /dev/null @@ -1,9 +0,0 @@ -using Fission.DotNetCore.Api; - -public class FissionFunction -{ - public string Execute(FissionContext context) - { - return "Hello World!"; - } -} diff --git a/dotnet/examples/requestbody.cs b/dotnet/examples/requestbody.cs deleted file mode 100644 index c4be5f44..00000000 --- a/dotnet/examples/requestbody.cs +++ /dev/null @@ -1,24 +0,0 @@ -using System.IO; -using System.Runtime.Serialization.Json; -using Fission.DotNetCore.Api; - -public class FissionFunction -{ - public string Execute(FissionContext context) - { - var person = Person.Deserialize(context.Request.Body); - return $"Hello, my name is {person.Name} and I am {person.Age} years old."; - } -} - -public class Person -{ - public string Name { get; set; } - public int Age { get; set; } - - public static Person Deserialize(Stream json) - { - var serializer = new DataContractJsonSerializer(typeof(Person)); - return (Person)serializer.ReadObject(json); - } -} diff --git a/dotnet/examples/requestheaders.cs b/dotnet/examples/requestheaders.cs deleted file mode 100644 index 8e44f2f7..00000000 --- a/dotnet/examples/requestheaders.cs +++ /dev/null @@ -1,17 +0,0 @@ -using System; -using Fission.DotNetCore.Api; - -public class FissionFunction -{ - public string Execute(FissionContext context){ - var buffer = new System.Text.StringBuilder(); - foreach(var header in context.Request.Headers){ - buffer.AppendLine(header.Key); - foreach(var item in header.Value){ - buffer.AppendLine($"\t{item}"); - } - } - buffer.AppendLine($"Url: {context.Request.Url}, method: {context.Request.Method}"); - return buffer.ToString(); - } -} diff --git a/dotnet20/README.md b/dotnet20/README.md index 9163ec7a..59e85947 100644 --- a/dotnet20/README.md +++ b/dotnet20/README.md @@ -32,7 +32,7 @@ public class FissionFunction { ``` Please see examples below, or if you are looking for ready-to-run examples, see -the [DotNet20 examples directory](../../examples/dotnet20). +the [DotNet20 examples directory](https://github.com/fission/examples/tree/main/dotnet). ## Rebuilding and pushing the image diff --git a/dotnet20/examples/arguments.cs b/dotnet20/examples/arguments.cs deleted file mode 100644 index c3e2a48e..00000000 --- a/dotnet20/examples/arguments.cs +++ /dev/null @@ -1,11 +0,0 @@ -using System; -using Fission.DotNetCore.Api; - -public class FissionFunction -{ - public string Execute(FissionContext context){ - var x = Convert.ToInt32(context.Arguments["x"]); - var y = Convert.ToInt32(context.Arguments["y"]); - return (x+y).ToString(); - } -} diff --git a/dotnet20/examples/echo.cs b/dotnet20/examples/echo.cs deleted file mode 100644 index 9e399583..00000000 --- a/dotnet20/examples/echo.cs +++ /dev/null @@ -1,10 +0,0 @@ -using System; -using Fission.DotNetCore.Api; - -public class FissionFunction -{ - public string Execute(FissionContext context){ - context.Logger.WriteInfo("executing.. {0}", context.Arguments["text"]); - return (string)context.Arguments["text"]; - } -} \ No newline at end of file diff --git a/dotnet20/examples/helloworld.cs b/dotnet20/examples/helloworld.cs deleted file mode 100644 index cae5a7e9..00000000 --- a/dotnet20/examples/helloworld.cs +++ /dev/null @@ -1,9 +0,0 @@ -using Fission.DotNetCore.Api; - -public class FissionFunction -{ - public string Execute(FissionContext context) - { - return "Hello World!"; - } -} diff --git a/dotnet20/examples/requestbody.cs b/dotnet20/examples/requestbody.cs deleted file mode 100644 index c4be5f44..00000000 --- a/dotnet20/examples/requestbody.cs +++ /dev/null @@ -1,24 +0,0 @@ -using System.IO; -using System.Runtime.Serialization.Json; -using Fission.DotNetCore.Api; - -public class FissionFunction -{ - public string Execute(FissionContext context) - { - var person = Person.Deserialize(context.Request.Body); - return $"Hello, my name is {person.Name} and I am {person.Age} years old."; - } -} - -public class Person -{ - public string Name { get; set; } - public int Age { get; set; } - - public static Person Deserialize(Stream json) - { - var serializer = new DataContractJsonSerializer(typeof(Person)); - return (Person)serializer.ReadObject(json); - } -} diff --git a/dotnet20/examples/requestheaders.cs b/dotnet20/examples/requestheaders.cs deleted file mode 100644 index 8e44f2f7..00000000 --- a/dotnet20/examples/requestheaders.cs +++ /dev/null @@ -1,17 +0,0 @@ -using System; -using Fission.DotNetCore.Api; - -public class FissionFunction -{ - public string Execute(FissionContext context){ - var buffer = new System.Text.StringBuilder(); - foreach(var header in context.Request.Headers){ - buffer.AppendLine(header.Key); - foreach(var item in header.Value){ - buffer.AppendLine($"\t{item}"); - } - } - buffer.AppendLine($"Url: {context.Request.Url}, method: {context.Request.Method}"); - return buffer.ToString(); - } -} diff --git a/dotnet8/examples/AsyncFunctionExample/AsyncFunctionExample.csproj b/dotnet8/examples/AsyncFunctionExample/AsyncFunctionExample.csproj deleted file mode 100644 index 8f23c4c9..00000000 --- a/dotnet8/examples/AsyncFunctionExample/AsyncFunctionExample.csproj +++ /dev/null @@ -1,14 +0,0 @@ - - - - Library - net8.0 - - - - - ./Fission.DotNet.Common.dll - - - - diff --git a/dotnet8/examples/AsyncFunctionExample/MyFunction.cs b/dotnet8/examples/AsyncFunctionExample/MyFunction.cs deleted file mode 100644 index be5603fb..00000000 --- a/dotnet8/examples/AsyncFunctionExample/MyFunction.cs +++ /dev/null @@ -1,17 +0,0 @@ -using Fission.DotNet.Common; -using System.Threading.Tasks; - -public class MyFunction -{ - public object Execute(FissionContext context) - { - // Call the async method and wait for it to complete - return ExecuteAsync(context).GetAwaiter().GetResult(); - } - - public async Task ExecuteAsync(FissionContext context) - { - await Task.Delay(1000); // Simulate an asynchronous operation - return "Hello from async function!"; - } -} diff --git a/dotnet8/examples/HelloWorld/HelloWorld.csproj b/dotnet8/examples/HelloWorld/HelloWorld.csproj deleted file mode 100644 index 36a12871..00000000 --- a/dotnet8/examples/HelloWorld/HelloWorld.csproj +++ /dev/null @@ -1,11 +0,0 @@ - - - Library - net8.0 - - - - ./Fission.DotNet.Common.dll - - - diff --git a/dotnet8/examples/HelloWorld/MyFunction.cs b/dotnet8/examples/HelloWorld/MyFunction.cs deleted file mode 100644 index 3b387273..00000000 --- a/dotnet8/examples/HelloWorld/MyFunction.cs +++ /dev/null @@ -1,9 +0,0 @@ -using Fission.DotNet.Common; - -public class MyFunction -{ - public object Execute(FissionContext context) - { - return "Hello World!x"; - } -} diff --git a/dotnet8/examples/HttpTriggerExample/HttpTriggerExample.csproj b/dotnet8/examples/HttpTriggerExample/HttpTriggerExample.csproj deleted file mode 100644 index 8b490311..00000000 --- a/dotnet8/examples/HttpTriggerExample/HttpTriggerExample.csproj +++ /dev/null @@ -1,11 +0,0 @@ - - - Library - net8.0 - - - - ./Fission.DotNet.Common.dll - - - diff --git a/dotnet8/examples/HttpTriggerExample/MyFunction.cs b/dotnet8/examples/HttpTriggerExample/MyFunction.cs deleted file mode 100644 index 9f40bcd0..00000000 --- a/dotnet8/examples/HttpTriggerExample/MyFunction.cs +++ /dev/null @@ -1,14 +0,0 @@ -using Fission.DotNet.Common; - -public class MyFunction -{ - public object Execute(FissionContext context) - { - var httpContext = context as FissionHttpContext; - if (httpContext != null) - { - return $"Hello from HTTP trigger! Method: {httpContext.Method}, URL: {httpContext.Url}"; - } - return "Hello from non-HTTP trigger!"; - } -} diff --git a/dotnet8/examples/MultiFileExample/Controllers/ApiController.cs b/dotnet8/examples/MultiFileExample/Controllers/ApiController.cs deleted file mode 100644 index 579d94f0..00000000 --- a/dotnet8/examples/MultiFileExample/Controllers/ApiController.cs +++ /dev/null @@ -1,129 +0,0 @@ -using System; -using System.Threading.Tasks; -using MultiFileExample.Services; -using MultiFileExample.Models; -using Fission.DotNet.Common; - -namespace MultiFileExample.Controllers -{ - public class ApiController - { - private readonly WeatherService _weatherService; - private readonly UserService _userService; - private readonly DataProcessor _dataProcessor; - - public ApiController() - { - // In production, use dependency injection - _weatherService = new WeatherService(); - _userService = new UserService(); - _dataProcessor = new DataProcessor(); - } - - public async Task RouteRequest(FissionContext context) - { - var path = ExtractPath(context); - var method = ExtractMethod(context); - - // Route to appropriate handler based on path - return path.ToLower() switch - { - "" or "multifile" => GetApiInfo(), - "weather" => await _weatherService.GetWeatherAsync(), - "weather/forecast" => await _weatherService.GetForecastAsync(), - "users" => _userService.GetAllUsers(), - "users/active" => _userService.GetActiveUsers(), - "process" => _dataProcessor.ProcessData(new DataRequest { Input = "test-data" }), - "health" => GetHealthStatus(), - _ => GetNotFoundResponse(path) - }; - } - - private string ExtractPath(FissionContext context) - { - // Try to get path from HTTP context - if (context is FissionHttpContext httpContext) - { - return httpContext.Url?.TrimStart('/') ?? ""; - } - - // Fallback to subpath argument for testing - if (context?.Arguments?.ContainsKey("subpath") == true) - { - return context.Arguments["subpath"]?.ToString() ?? ""; - } - - return ""; - } - - private string ExtractMethod(FissionContext context) - { - if (context is FissionHttpContext httpContext) - { - return httpContext.Method?.ToUpper() ?? "GET"; - } - return "GET"; - } - - private object GetApiInfo() - { - return new - { - name = "Multi-File Example API", - description = "MVC-pattern Fission function with controller-based routing", - version = "2.0.0", - architecture = new - { - pattern = "MVC", - entryPoint = "MyFunction.cs", - controller = "ApiController.cs", - services = new[] { "WeatherService.cs", "UserService.cs", "DataProcessor.cs" }, - models = new[] { "User.cs", "Weather.cs", "DataModels.cs" } - }, - endpoints = GetAvailableEndpoints() - }; - } - - private object GetHealthStatus() - { - return new - { - status = "healthy", - service = "MultiFileExample", - version = "2.0.0", - timestamp = DateTime.UtcNow, - components = new - { - weatherService = "operational", - userService = "operational", - dataProcessor = "operational" - } - }; - } - - private object GetNotFoundResponse(string path) - { - return new - { - error = "Endpoint not found", - path = path, - statusCode = 404, - availableEndpoints = GetAvailableEndpoints() - }; - } - - private string[] GetAvailableEndpoints() - { - return new[] - { - "/ - API information", - "/weather - Current weather", - "/weather/forecast - 5-day forecast", - "/users - List all users", - "/users/active - List active users", - "/process - Data processing demo", - "/health - Health check" - }; - } - } -} \ No newline at end of file diff --git a/dotnet8/examples/MultiFileExample/Models/DataModels.cs b/dotnet8/examples/MultiFileExample/Models/DataModels.cs deleted file mode 100644 index 464dc61b..00000000 --- a/dotnet8/examples/MultiFileExample/Models/DataModels.cs +++ /dev/null @@ -1,43 +0,0 @@ -using System; - -namespace MultiFileExample.Models -{ - public class DataRequest - { - public string Input { get; set; } - public string Format { get; set; } - public bool Validate { get; set; } - } - - public class ProcessedData - { - public string Original { get; set; } - public string Uppercase { get; set; } - public string Lowercase { get; set; } - public string Reversed { get; set; } - public int Length { get; set; } - public int WordCount { get; set; } - public string Hash { get; set; } - public string Base64Encoded { get; set; } - } - - public class ProcessingStats - { - public int CharacterCount { get; set; } - public int AlphaCount { get; set; } - public int DigitCount { get; set; } - public int SpaceCount { get; set; } - public int SpecialCharCount { get; set; } - } - - public class DataResponse - { - public bool Success { get; set; } - public string Error { get; set; } - public ProcessedData ProcessedData { get; set; } - public ProcessingStats Statistics { get; set; } - public DateTime ProcessedAt { get; set; } - public string ProcessingTime { get; set; } - public string Source { get; set; } - } -} \ No newline at end of file diff --git a/dotnet8/examples/MultiFileExample/Models/User.cs b/dotnet8/examples/MultiFileExample/Models/User.cs deleted file mode 100644 index e3e9123a..00000000 --- a/dotnet8/examples/MultiFileExample/Models/User.cs +++ /dev/null @@ -1,23 +0,0 @@ -using System; -using System.Collections.Generic; - -namespace MultiFileExample.Models -{ - public class User - { - public int Id { get; set; } - public string Name { get; set; } - public string Email { get; set; } - public bool IsActive { get; set; } - public DateTime CreatedAt { get; set; } - } - - public class UserListResponse - { - public List Users { get; set; } - public int Total { get; set; } - public string FilteredBy { get; set; } - public DateTime Timestamp { get; set; } - public string Source { get; set; } - } -} \ No newline at end of file diff --git a/dotnet8/examples/MultiFileExample/Models/Weather.cs b/dotnet8/examples/MultiFileExample/Models/Weather.cs deleted file mode 100644 index 3fd7c486..00000000 --- a/dotnet8/examples/MultiFileExample/Models/Weather.cs +++ /dev/null @@ -1,34 +0,0 @@ -using System; -using System.Collections.Generic; - -namespace MultiFileExample.Models -{ - public class WeatherResponse - { - public string City { get; set; } - public int Temperature { get; set; } - public string Condition { get; set; } - public int Humidity { get; set; } - public int WindSpeed { get; set; } - public DateTime Timestamp { get; set; } - public string Source { get; set; } - } - - public class DailyForecast - { - public DateTime Date { get; set; } - public int High { get; set; } - public int Low { get; set; } - public string Condition { get; set; } - public int ChanceOfRain { get; set; } - } - - public class ForecastResponse - { - public string City { get; set; } - public int Days { get; set; } - public List Forecasts { get; set; } - public DateTime GeneratedAt { get; set; } - public string Source { get; set; } - } -} \ No newline at end of file diff --git a/dotnet8/examples/MultiFileExample/MultiFileExample.csproj b/dotnet8/examples/MultiFileExample/MultiFileExample.csproj deleted file mode 100644 index 796cb33c..00000000 --- a/dotnet8/examples/MultiFileExample/MultiFileExample.csproj +++ /dev/null @@ -1,19 +0,0 @@ - - - Library - net8.0 - MultiFileExample - MultiFileExample - true - - - - - ./Fission.DotNet.Common.dll - - - - - - - \ No newline at end of file diff --git a/dotnet8/examples/MultiFileExample/MyFunction.cs b/dotnet8/examples/MultiFileExample/MyFunction.cs deleted file mode 100644 index ce325ca2..00000000 --- a/dotnet8/examples/MultiFileExample/MyFunction.cs +++ /dev/null @@ -1,23 +0,0 @@ -using Fission.DotNet.Common; -using System.Threading.Tasks; -using MultiFileExample.Controllers; - -namespace MultiFileExample -{ - - public class MyFunction - { - private readonly ApiController _controller; - - public MyFunction() - { - _controller = new ApiController(); - } - - public async Task Execute(FissionContext context) - { - // Delegate all routing and business logic to the controller - return await _controller.RouteRequest(context); - } - } -} \ No newline at end of file diff --git a/dotnet8/examples/MultiFileExample/README.md b/dotnet8/examples/MultiFileExample/README.md deleted file mode 100644 index a04206b8..00000000 --- a/dotnet8/examples/MultiFileExample/README.md +++ /dev/null @@ -1,116 +0,0 @@ -# Multi-File Example for Fission .NET 8 - -This example demonstrates how to organize a Fission function across multiple files using proper .NET project structure with services, models, and separation of concerns. - -## Project Structure - -``` -MultiFileExample/ -├── MyFunction.cs # Thin Fission entry point (delegates to controller) -├── MultiFileExample.csproj # Project file -├── Controllers/ # MVC Controllers -│ └── ApiController.cs # Main controller handling routing and orchestration -├── Services/ # Business logic layer -│ ├── WeatherService.cs # Weather-related operations -│ ├── UserService.cs # User management -│ └── DataProcessor.cs # Data processing utilities -└── Models/ # Data models - ├── User.cs # User models - ├── Weather.cs # Weather models - └── DataModels.cs # Data processing models -``` - - -## Deploy to Fission - -```bash -# Create environment (if not already created) -fission env create --name dotnet8 \ - --image fission/dotnet8-env \ - --builder fission/dotnet8-builder \ - --poolsize 1 - -# Create package with all source files -cd /dotnet8/examples/MultiFileExample -fission pkg create --name multifile-pkg \ - --env dotnet8 \ - --src . \ - --buildcmd "/usr/local/bin/build" - -# Wait for build to complete -fission pkg list - -# Create function -fission fn create --name multifile-fn \ - --pkg multifile-pkg \ - --env dotnet8 \ - --entrypoint "MultiFileExample.MyFunction" - -# Create HTTP route -fission route create --name multifile-route \ - --function multifile-fn \ - --url "/multifile/*" \ - --method GET POST - -# Test the function -fission fn test --name multifile-fn -``` - -## Available Endpoints - -```bash -# Port forward to access locally -kubectl port-forward -n fission service/router 8080:80 & - -# API Information -curl http://localhost:8080/fission-function/multifile-fn/ - -# Weather Service endpoints -curl http://localhost:8080/fission-function/multifile-fn/weather -curl http://localhost:8080/fission-function/multifile-fn/weather/forecast - -# User Service endpoints -curl http://localhost:8080/fission-function/multifile-fn/users -curl http://localhost:8080/fission-function/multifile-fn/users/active - -# Data Processing endpoint -curl http://localhost:8080/fission-function/multifile-fn/process - -# Health check -curl http://localhost:8080/fission-function/multifile-fn/health -``` - -## How It Works - -1. **Entry Point**: `MyFunction.cs` implements the Fission function interface (thin wrapper) -2. **Controller**: `ApiController.cs` handles all routing and orchestration -3. **Dependency Injection**: Services are instantiated in the controller's constructor -4. **Routing**: Controller routes requests to appropriate services based on path -5. **Services**: Each service encapsulates related business logic -6. **Models**: Shared data structures used across services - - -## Adding New Features - -To add a new service: - -1. Create a new service file in `Services/` directory -2. Create models in `Models/` directory -3. Add routing in `MyFunction.cs` -4. Rebuild and redeploy the package - -Example: -```csharp -// Services/OrderService.cs -namespace MultiFileExample.Services -{ - public class OrderService - { - public object GetOrders() { /* ... */ } - } -} - -// In MyFunction.cs -private readonly OrderService _orderService = new OrderService(); -// Add to switch: "orders" => _orderService.GetOrders() -``` \ No newline at end of file diff --git a/dotnet8/examples/MultiFileExample/Services/DataProcessor.cs b/dotnet8/examples/MultiFileExample/Services/DataProcessor.cs deleted file mode 100644 index fbadc8c8..00000000 --- a/dotnet8/examples/MultiFileExample/Services/DataProcessor.cs +++ /dev/null @@ -1,81 +0,0 @@ -using System; -using System.Linq; -using System.Text; -using MultiFileExample.Models; - -namespace MultiFileExample.Services -{ - public class DataProcessor - { - public DataResponse ProcessData(DataRequest request) - { - if (request == null || string.IsNullOrEmpty(request.Input)) - { - return new DataResponse - { - Success = false, - Error = "Input data is required", - ProcessedAt = DateTime.UtcNow - }; - } - - // Simulate various data processing operations - var processed = new ProcessedData - { - Original = request.Input, - Uppercase = request.Input.ToUpper(), - Lowercase = request.Input.ToLower(), - Reversed = new string(request.Input.Reverse().ToArray()), - Length = request.Input.Length, - WordCount = request.Input.Split(' ', StringSplitOptions.RemoveEmptyEntries).Length, - Hash = ComputeSimpleHash(request.Input), - Base64Encoded = Convert.ToBase64String(Encoding.UTF8.GetBytes(request.Input)) - }; - - // Calculate some statistics - var stats = new ProcessingStats - { - CharacterCount = request.Input.Length, - AlphaCount = request.Input.Count(char.IsLetter), - DigitCount = request.Input.Count(char.IsDigit), - SpaceCount = request.Input.Count(char.IsWhiteSpace), - SpecialCharCount = request.Input.Count(c => !char.IsLetterOrDigit(c) && !char.IsWhiteSpace(c)) - }; - - return new DataResponse - { - Success = true, - ProcessedData = processed, - Statistics = stats, - ProcessedAt = DateTime.UtcNow, - ProcessingTime = "< 1ms", - Source = "DataProcessor.cs" - }; - } - - private string ComputeSimpleHash(string input) - { - // Simple hash for demonstration - int hash = 0; - foreach (char c in input) - { - hash = ((hash << 5) - hash) + c; - } - return Math.Abs(hash).ToString("X8"); - } - - public object AnalyzeData(string data) - { - if (string.IsNullOrEmpty(data)) - return new { error = "No data provided" }; - - return new - { - analysis = "Complete", - dataPoints = data.Length, - checksum = ComputeSimpleHash(data), - timestamp = DateTime.UtcNow - }; - } - } -} \ No newline at end of file diff --git a/dotnet8/examples/MultiFileExample/Services/UserService.cs b/dotnet8/examples/MultiFileExample/Services/UserService.cs deleted file mode 100644 index 255396b5..00000000 --- a/dotnet8/examples/MultiFileExample/Services/UserService.cs +++ /dev/null @@ -1,65 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using MultiFileExample.Models; - -namespace MultiFileExample.Services -{ - public class UserService - { - private readonly List _users; - - public UserService() - { - // Initialize with sample data - _users = new List - { - new User { Id = 1, Name = "Alice Johnson", Email = "alice@example.com", IsActive = true, CreatedAt = DateTime.UtcNow.AddDays(-30) }, - new User { Id = 2, Name = "Bob Smith", Email = "bob@example.com", IsActive = true, CreatedAt = DateTime.UtcNow.AddDays(-25) }, - new User { Id = 3, Name = "Charlie Brown", Email = "charlie@example.com", IsActive = false, CreatedAt = DateTime.UtcNow.AddDays(-20) }, - new User { Id = 4, Name = "Diana Prince", Email = "diana@example.com", IsActive = true, CreatedAt = DateTime.UtcNow.AddDays(-15) }, - new User { Id = 5, Name = "Edward Norton", Email = "edward@example.com", IsActive = false, CreatedAt = DateTime.UtcNow.AddDays(-10) } - }; - } - - public UserListResponse GetAllUsers() - { - return new UserListResponse - { - Users = _users, - Total = _users.Count, - Timestamp = DateTime.UtcNow, - Source = "UserService.cs" - }; - } - - public UserListResponse GetActiveUsers() - { - var activeUsers = _users.Where(u => u.IsActive).ToList(); - - return new UserListResponse - { - Users = activeUsers, - Total = activeUsers.Count, - FilteredBy = "IsActive = true", - Timestamp = DateTime.UtcNow, - Source = "UserService.cs" - }; - } - - public User GetUserById(int id) - { - return _users.FirstOrDefault(u => u.Id == id); - } - - public bool AddUser(User user) - { - if (user == null || _users.Any(u => u.Id == user.Id)) - return false; - - user.CreatedAt = DateTime.UtcNow; - _users.Add(user); - return true; - } - } -} \ No newline at end of file diff --git a/dotnet8/examples/MultiFileExample/Services/WeatherService.cs b/dotnet8/examples/MultiFileExample/Services/WeatherService.cs deleted file mode 100644 index efc350c5..00000000 --- a/dotnet8/examples/MultiFileExample/Services/WeatherService.cs +++ /dev/null @@ -1,64 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Threading.Tasks; -using MultiFileExample.Models; - -namespace MultiFileExample.Services -{ - public class WeatherService - { - private readonly Random _random = new Random(); - private readonly string[] _conditions = { "Sunny", "Cloudy", "Rainy", "Stormy", "Snowy", "Foggy", "Clear" }; - private readonly string[] _cities = { "New York", "London", "Tokyo", "Paris", "Sydney", "Toronto", "Berlin" }; - - public async Task GetWeatherAsync() - { - // Simulate async operation - await Task.Delay(10); - - var city = _cities[_random.Next(_cities.Length)]; - - return new WeatherResponse - { - City = city, - Temperature = _random.Next(-10, 35), - Condition = _conditions[_random.Next(_conditions.Length)], - Humidity = _random.Next(30, 95), - WindSpeed = _random.Next(0, 50), - Timestamp = DateTime.UtcNow, - Source = "WeatherService.cs" - }; - } - - public async Task GetForecastAsync() - { - // Simulate async operation - await Task.Delay(10); - - var city = _cities[_random.Next(_cities.Length)]; - var forecasts = new List(); - - for (int i = 0; i < 5; i++) - { - forecasts.Add(new DailyForecast - { - Date = DateTime.UtcNow.AddDays(i), - High = _random.Next(10, 35), - Low = _random.Next(-5, 15), - Condition = _conditions[_random.Next(_conditions.Length)], - ChanceOfRain = _random.Next(0, 100) - }); - } - - return new ForecastResponse - { - City = city, - Days = 5, - Forecasts = forecasts, - GeneratedAt = DateTime.UtcNow, - Source = "WeatherService.cs" - }; - } - } -} \ No newline at end of file diff --git a/go/README.md b/go/README.md index 50ce6b26..d165dde3 100644 --- a/go/README.md +++ b/go/README.md @@ -4,7 +4,7 @@ This is the Go environment for Fission. It's a Docker image containing a Go runtime, along with a dynamic loader. -Looking for ready-to-run examples? See the [Go examples directory](../../examples/go). +Looking for ready-to-run examples? See the [Go examples directory](https://github.com/fission/examples/tree/main/go). ## Build this image diff --git a/go/examples/README.md b/go/examples/README.md deleted file mode 100644 index adcd3a51..00000000 --- a/go/examples/README.md +++ /dev/null @@ -1,23 +0,0 @@ -# Hello World in Go on Fission - -`hello.go` contains a very simple fission function that says "Hello, World!". - -## Deploying this function on your cluster - -```bash - -# Create the Fission Go environment and function, and wait for the -# function to build. (Take a look at the YAML files in the specs -# directory for details about how the environment and function are -# specified.) - -$ fission spec apply --wait -1 environment created -1 package created -1 function created - -# Now, run the function with the "fission function test" command: - -$ fission function test --name hello-go -Hello, World! -``` diff --git a/go/examples/hello.go b/go/examples/hello.go deleted file mode 100644 index 88c004fe..00000000 --- a/go/examples/hello.go +++ /dev/null @@ -1,11 +0,0 @@ -package main - -import ( - "net/http" -) - -// Handler is the entry point for this fission function -func Handler(w http.ResponseWriter, r *http.Request) { - msg := "Hello, world!\n" - w.Write([]byte(msg)) -} diff --git a/go/examples/module-example/README.md b/go/examples/module-example/README.md deleted file mode 100644 index 9671a3ef..00000000 --- a/go/examples/module-example/README.md +++ /dev/null @@ -1,29 +0,0 @@ -# Go module usage - -1. Initialize your project - - ```console - go mod init - ``` - -2. Add dependencies - See [modules daily-workflow](https://github.com/golang/go/wiki/Modules#daily-workflow) - -3. Verify - - ```console - go mod tidy - go mod verify - ``` - -4. Archive and create package as usual - - ```console - $ zip -r go.zip . - adding: go.mod (deflated 26%) - adding: go.sum (deflated 1%) - adding: README.md (deflated 37%) - adding: main.go (deflated 30%) - - $ fission pkg create --env go --src go.zip - ``` diff --git a/go/examples/module-example/go.mod b/go/examples/module-example/go.mod deleted file mode 100644 index 8fd9f683..00000000 --- a/go/examples/module-example/go.mod +++ /dev/null @@ -1,5 +0,0 @@ -module github.com/fission/environments/go/examples/module-example - -go 1.25 - -require golang.org/x/example v0.0.0-20210811190340-787a929d5a0d diff --git a/go/examples/module-example/go.sum b/go/examples/module-example/go.sum deleted file mode 100644 index e5eaf196..00000000 --- a/go/examples/module-example/go.sum +++ /dev/null @@ -1,23 +0,0 @@ -github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= -golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= -golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= -golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= -golang.org/x/example v0.0.0-20210811190340-787a929d5a0d h1:VYLNvPLNayyBk9XOnsTk5jh7vZarEfiJe7/S15vri2g= -golang.org/x/example v0.0.0-20210811190340-787a929d5a0d/go.mod h1:+yakPl5KR9J+ysfUNADYwEU5qeqjUO473wDktD4xMYw= -golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= -golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= -golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= -golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= -golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= -golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= -golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= -golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= -golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= -golang.org/x/tools v0.0.0-20210112183307-1e6ecd4bf1b0/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= -golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= -golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= -golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= diff --git a/go/examples/module-example/main.go b/go/examples/module-example/main.go deleted file mode 100644 index feadefa6..00000000 --- a/go/examples/module-example/main.go +++ /dev/null @@ -1,17 +0,0 @@ -package main - -import ( - "log" - "net/http" - - "golang.org/x/example/stringutil" -) - -// Handler is the entry point for this fission function -func Handler(w http.ResponseWriter, r *http.Request) { - msg := stringutil.Reverse(stringutil.Reverse("Vendor Example Test")) - _, err := w.Write([]byte(msg)) - if err != nil { - log.Printf("Error writing response: %v", err) - } -} diff --git a/go/examples/specs/env.yaml b/go/examples/specs/env.yaml deleted file mode 100644 index 513bf645..00000000 --- a/go/examples/specs/env.yaml +++ /dev/null @@ -1,12 +0,0 @@ -apiVersion: fission.io/v1 -kind: Environment -metadata: - name: go - namespace: default -spec: - version: 2 - builder: - command: build - image: fission/go-builder-1.26:1.34.0 - runtime: - image: fission/go-env-1.26:1.34.0 diff --git a/go/examples/specs/fission-deployment-config.yaml b/go/examples/specs/fission-deployment-config.yaml deleted file mode 100644 index 0967a979..00000000 --- a/go/examples/specs/fission-deployment-config.yaml +++ /dev/null @@ -1,6 +0,0 @@ -# This file is generated by the 'fission spec init' command. -# See the README in this directory for background and usage information. -# Do not edit the UID below: that will break 'fission spec apply' -kind: DeploymentConfig -name: hello-go -uid: a8cdb63c-9be8-4a59-9427-89051afecd7b diff --git a/go/examples/specs/function-hello.yaml b/go/examples/specs/function-hello.yaml deleted file mode 100644 index f53e92dd..00000000 --- a/go/examples/specs/function-hello.yaml +++ /dev/null @@ -1,39 +0,0 @@ -kind: ArchiveUploadSpec -name: hello-go -include: -- hello.go - ---- -apiVersion: fission.io/v1 -kind: Package -metadata: - creationTimestamp: null - name: hello-go-pkg - namespace: default -spec: - environment: - name: go - namespace: default - source: - type: url - url: archive://hello-go -status: - buildstatus: pending - ---- -apiVersion: fission.io/v1 -kind: Function -metadata: - creationTimestamp: null - name: hello-go - namespace: default -spec: - environment: - name: go - namespace: default - functionTimeout: 60 - package: - functionName: Handler - packageref: - name: hello-go-pkg - namespace: default diff --git a/jvm-jersey/README.md b/jvm-jersey/README.md index 2a6278d9..fb353b2a 100644 --- a/jvm-jersey/README.md +++ b/jvm-jersey/README.md @@ -8,7 +8,7 @@ pom.xml file. Unlike the other [JVM environment](../jvm) which is based on the Spring framework, this environment uses Jersey. -Looking for ready-to-run examples? See the [JVM examples directory](../../examples/jvm-jersey). +Looking for ready-to-run examples? See the [Java examples](https://github.com/fission/examples/tree/main/java). ## Customizing this image diff --git a/jvm-jersey/examples/java/pom.xml b/jvm-jersey/examples/java/pom.xml deleted file mode 100644 index bfbb6865..00000000 --- a/jvm-jersey/examples/java/pom.xml +++ /dev/null @@ -1,76 +0,0 @@ - - - 4.0.0 - io.fission - jersey-hello-world - 0.0.1 - jar - - hello-world - http://maven.apache.org - - - UTF-8 - 25 - 25 - - - - - io.fission - fission-jvm-jersey - 0.0.1 - provided - - - javax.ws.rs - javax.ws.rs-api - 2.0 - provided - - - org.glassfish.jersey.containers - jersey-container-servlet-core - 2.0 - test - - - junit - junit - 4.13.1 - test - - - - - - - maven-assembly-plugin - - - jar-with-dependencies - - - - - make-assembly - package - - single - - - - - - org.apache.maven.plugins - maven-surefire-plugin - 2.22.1 - - false - - - - - - diff --git a/jvm-jersey/examples/java/specs/env-java.yaml b/jvm-jersey/examples/java/specs/env-java.yaml deleted file mode 100644 index 78b2db7b..00000000 --- a/jvm-jersey/examples/java/specs/env-java.yaml +++ /dev/null @@ -1,17 +0,0 @@ -apiVersion: fission.io/v1 -kind: Environment -metadata: - creationTimestamp: null - name: java-jersey - namespace: default -spec: - builder: - command: build - image: fission/jvm-jersey-builder - imagepullsecret: "" - keeparchive: true - poolsize: 3 - resources: {} - runtime: - image: fission/jvm-jersey-env - version: 2 diff --git a/jvm-jersey/examples/java/specs/fission-deployment-config.yaml b/jvm-jersey/examples/java/specs/fission-deployment-config.yaml deleted file mode 100644 index 24e5e094..00000000 --- a/jvm-jersey/examples/java/specs/fission-deployment-config.yaml +++ /dev/null @@ -1,7 +0,0 @@ -# This file is generated by the 'fission spec init' command. -# See the README in this directory for background and usage information. -# Do not edit the UID below: that will break 'fission spec apply' -apiVersion: fission.io/v1 -kind: DeploymentConfig -name: java-jersey -uid: 908a303a-bf23-4bae-a22c-b1db9a1f71a9 diff --git a/jvm-jersey/examples/java/specs/function-hello.yaml b/jvm-jersey/examples/java/specs/function-hello.yaml deleted file mode 100644 index 9dd85f65..00000000 --- a/jvm-jersey/examples/java/specs/function-hello.yaml +++ /dev/null @@ -1,27 +0,0 @@ -apiVersion: fission.io/v1 -kind: Function -metadata: - creationTimestamp: null - name: hello - namespace: default -spec: - InvokeStrategy: - ExecutionStrategy: - ExecutorType: poolmgr - MaxScale: 0 - MinScale: 0 - SpecializationTimeout: 120 - TargetCPUPercent: 0 - StrategyType: execution - configmaps: null - environment: - name: java-jersey - namespace: default - functionTimeout: 60 - package: - functionName: io.fission.HelloWorld - packageref: - name: hellojava - namespace: default - resources: {} - secrets: null diff --git a/jvm-jersey/examples/java/specs/package-hellojava.yaml b/jvm-jersey/examples/java/specs/package-hellojava.yaml deleted file mode 100644 index f606e112..00000000 --- a/jvm-jersey/examples/java/specs/package-hellojava.yaml +++ /dev/null @@ -1,26 +0,0 @@ -include: -- src -- pom.xml -kind: ArchiveUploadSpec -name: src-URlE - ---- -apiVersion: fission.io/v1 -kind: Package -metadata: - creationTimestamp: null - name: hellojavajersey - namespace: default -spec: - deployment: - checksum: {} - environment: - name: java-jersey - namespace: default - source: - checksum: {} - type: url - url: archive://src-URlE -status: - buildstatus: pending - lastUpdateTimestamp: "2020-01-29T09:43:56Z" diff --git a/jvm-jersey/examples/java/src/main/java/io/fission/HelloWorld.java b/jvm-jersey/examples/java/src/main/java/io/fission/HelloWorld.java deleted file mode 100644 index 29039300..00000000 --- a/jvm-jersey/examples/java/src/main/java/io/fission/HelloWorld.java +++ /dev/null @@ -1,25 +0,0 @@ -package io.fission; - -import javax.ws.rs.core.Response; -import javax.ws.rs.container.ContainerRequestContext; -import io.fission.Function; -import java.io.BufferedReader; -import java.util.stream.Collectors; -import java.io.InputStreamReader; - -public class HelloWorld implements Function { - - public static final String RETURN_STRING = "Hello World!"; - - @Override - public Response call(ContainerRequestContext request, Context arg1) { - if(request.getMethod().equals("GET")) { - return Response.ok(RETURN_STRING).build(); - } - else { - String body = new BufferedReader(new InputStreamReader(request.getEntityStream())).lines() - .parallel().collect(Collectors.joining("\n")); - return Response.ok("Echo: " + body).build(); - } - } -} diff --git a/jvm-jersey/examples/java/src/test/java/io/fission/HelloWorldTest.java b/jvm-jersey/examples/java/src/test/java/io/fission/HelloWorldTest.java deleted file mode 100644 index 907946d8..00000000 --- a/jvm-jersey/examples/java/src/test/java/io/fission/HelloWorldTest.java +++ /dev/null @@ -1,25 +0,0 @@ -package io.fission; - -import java.net.URI; -import java.net.URISyntaxException; -import org.glassfish.jersey.server.ContainerRequest; -import javax.ws.rs.core.Response; -import org.junit.Assert; -import org.junit.Test; - - -public class HelloWorldTest { - - @Test - public void testResponse() { - HelloWorld hw = new HelloWorld(); - ContainerRequest request = null; - try { - request = new ContainerRequest(new URI("http://example.com/"),new URI("/hello"),"GET",null,null); - } catch (URISyntaxException e) { - e.printStackTrace(); - } - Response response = hw.call(request, null); - Assert.assertTrue(response.getEntity().toString().equals(HelloWorld.RETURN_STRING)); - } -} diff --git a/jvm/README.md b/jvm/README.md index c69a7ae5..3acedb92 100644 --- a/jvm/README.md +++ b/jvm/README.md @@ -6,7 +6,7 @@ It's a Docker image containing a OpenJDK22 runtime by [Eclipse Temurin](https:// dynamic loader. A few dependencies are included in the pom.xml file. -Looking for ready-to-run examples? See the [JVM examples directory](../../examples/jvm). +Looking for ready-to-run examples? See the [Java examples](https://github.com/fission/examples/tree/main/java). ## Customizing this image diff --git a/jvm/examples/java/.gitignore b/jvm/examples/java/.gitignore deleted file mode 100644 index 4c3f8757..00000000 --- a/jvm/examples/java/.gitignore +++ /dev/null @@ -1,4 +0,0 @@ -.project -.settings -.classpath -target/ diff --git a/jvm/examples/java/README.md b/jvm/examples/java/README.md deleted file mode 100644 index 1c9bf76e..00000000 --- a/jvm/examples/java/README.md +++ /dev/null @@ -1,60 +0,0 @@ -# Hello World in JVM/Java on Fission - -The `io.fission.HelloWorld.java` class is a very simple fission function that implements `io.fission.Function` and says "Hello, World!" . - -## Building and deploying using Fission - -Fission's builder can be used to create the binary artifact from source code. Create an environment with builder image and then create a package. - -``` -$ zip -r java-src-pkg.zip * -$ fission env create --name java --image fission/jvm-env --version 2 --keeparchive --builder fission/jvm-builder -$ fission package create --sourcearchive java-src-pkg.zip --env java -java-src-pkg-zip-tvd0 -$ fission package info --name java-src-pkg-zip-tvd0 -Name: java-src-pkg-zip-tvd0 -Environment: java -Status: succeeded -Build Logs: -[INFO] Scanning for projects... -[INFO] -[INFO] -----------------------< io.fission:hello-world >----------------------- -[INFO] Building hello-world 1.0-SNAPSHOT -[INFO] --------------------------------[ jar ]--------------------------------- -``` - -Once package's status is `succeeded` then that package can be used to create and execute a function. - -``` -$ fission fn create --name hello --pkg java-src-pkg-zip-tvd0 --env java --entrypoint io.fission.HelloWorld -$ fission fn test --name hello -Hello World! -``` - -## Building locally and deploying with Fission - -You can build the jar file in one of the two ways below based on your setup: - -- You can use docker without the need to install JDK and Maven to build the jar file from source code: - -```bash -$ bash -x ./build.sh - -``` -- If you have JDK and Maven installed, you can directly build the JAR file using command: - -``` -$ mvn clean package -``` - -Both of above steps will generate a target subdirectory which has the archive `target/hello-world-1.0-SNAPSHOT-jar-with-dependencies.jar` which will be used for creating function. - -- The archive created above will be used as a deploy package when creating the function. - -``` -$ fission env create --name jvm --image fission/jvm-env --version 2 --keeparchive=true -$ fission fn create --name hello --deploy target/hello-world-1.0-SNAPSHOT-jar-with-dependencies.jar --env jvm --entrypoint io.fission.HelloWorld -$ fission route create --function hello --url /hellop --method GET -$ fission fn test --name hello -Hello World! -``` diff --git a/jvm/examples/java/build.sh b/jvm/examples/java/build.sh deleted file mode 100755 index abac4200..00000000 --- a/jvm/examples/java/build.sh +++ /dev/null @@ -1,5 +0,0 @@ -#!/bin/sh -# This script allows you to build the jar without needing Maven & JDK installed locally. -# You need docker, as it uses a Docker image to build source code -set -eou pipefail -docker run -it --rm -v "$(pwd)":/usr/src/mymaven -w /usr/src/mymaven maven:3.5-jdk-8 mvn clean package diff --git a/jvm/examples/java/specs/README b/jvm/examples/java/specs/README deleted file mode 100644 index 1db3f9a5..00000000 --- a/jvm/examples/java/specs/README +++ /dev/null @@ -1,42 +0,0 @@ - -Fission Specs -============= - -This is a set of specifications for a Fission app. This includes functions, -environments, and triggers; we collectively call these things "resources". - -How to use these specs ----------------------- - -These specs are handled with the 'fission spec' command. See 'fission spec --help'. - -'fission spec apply' will "apply" all resources specified in this directory to your -cluster. That means it checks what resources exist on your cluster, what resources are -specified in the specs directory, and reconciles the difference by creating, updating or -deleting resources on the cluster. - -'fission spec apply' will also package up your source code (or compiled binaries) and -upload the archives to the cluster if needed. It uses 'ArchiveUploadSpec' resources in -this directory to figure out which files to archive. - -You can use 'fission spec apply --watch' to watch for file changes and continuously keep -the cluster updated. - -You can add YAMLs to this directory by writing them manually, but it's easier to generate -them. Use 'fission function create --spec' to generate a function spec, -'fission environment create --spec' to generate an environment spec, and so on. - -You can edit any of the files in this directory, except 'fission-deployment-config.yaml', -which contains a UID that you should never change. To apply your changes simply use -'fission spec apply'. - -fission-deployment-config.yaml ------------------------------- - -fission-deployment-config.yaml contains a UID. This UID is what fission uses to correlate -resources on the cluster to resources in this directory. - -All resources created by 'fission spec apply' are annotated with this UID. Resources on -the cluster that are _not_ annotated with this UID are never modified or deleted by -fission. - diff --git a/jvm-jersey/examples/java/.gitignore b/jvm/tests/fixtures/java/.gitignore similarity index 100% rename from jvm-jersey/examples/java/.gitignore rename to jvm/tests/fixtures/java/.gitignore diff --git a/jvm-jersey/examples/java/README.md b/jvm/tests/fixtures/java/README.md similarity index 100% rename from jvm-jersey/examples/java/README.md rename to jvm/tests/fixtures/java/README.md diff --git a/jvm-jersey/examples/java/build.sh b/jvm/tests/fixtures/java/build.sh similarity index 100% rename from jvm-jersey/examples/java/build.sh rename to jvm/tests/fixtures/java/build.sh diff --git a/jvm/examples/java/pom.xml b/jvm/tests/fixtures/java/pom.xml similarity index 100% rename from jvm/examples/java/pom.xml rename to jvm/tests/fixtures/java/pom.xml diff --git a/jvm-jersey/examples/java/specs/README b/jvm/tests/fixtures/java/specs/README similarity index 100% rename from jvm-jersey/examples/java/specs/README rename to jvm/tests/fixtures/java/specs/README diff --git a/jvm/examples/java/specs/env-java.yaml b/jvm/tests/fixtures/java/specs/env-java.yaml similarity index 100% rename from jvm/examples/java/specs/env-java.yaml rename to jvm/tests/fixtures/java/specs/env-java.yaml diff --git a/jvm/examples/java/specs/fission-deployment-config.yaml b/jvm/tests/fixtures/java/specs/fission-deployment-config.yaml similarity index 100% rename from jvm/examples/java/specs/fission-deployment-config.yaml rename to jvm/tests/fixtures/java/specs/fission-deployment-config.yaml diff --git a/jvm/examples/java/specs/function-hello.yaml b/jvm/tests/fixtures/java/specs/function-hello.yaml similarity index 100% rename from jvm/examples/java/specs/function-hello.yaml rename to jvm/tests/fixtures/java/specs/function-hello.yaml diff --git a/jvm/examples/java/specs/package-hellojava.yaml b/jvm/tests/fixtures/java/specs/package-hellojava.yaml similarity index 100% rename from jvm/examples/java/specs/package-hellojava.yaml rename to jvm/tests/fixtures/java/specs/package-hellojava.yaml diff --git a/jvm/examples/java/src/main/java/io/fission/HelloWorld.java b/jvm/tests/fixtures/java/src/main/java/io/fission/HelloWorld.java similarity index 100% rename from jvm/examples/java/src/main/java/io/fission/HelloWorld.java rename to jvm/tests/fixtures/java/src/main/java/io/fission/HelloWorld.java diff --git a/jvm/examples/java/src/test/java/io/fission/HelloWorldTest.java b/jvm/tests/fixtures/java/src/test/java/io/fission/HelloWorldTest.java similarity index 100% rename from jvm/examples/java/src/test/java/io/fission/HelloWorldTest.java rename to jvm/tests/fixtures/java/src/test/java/io/fission/HelloWorldTest.java diff --git a/jvm/tests/test_java_env.sh b/jvm/tests/test_java_env.sh index 4a504b6e..76bfa9fb 100755 --- a/jvm/tests/test_java_env.sh +++ b/jvm/tests/test_java_env.sh @@ -25,7 +25,7 @@ else log "TEST_NOCLEANUP is set; not cleaning up test artifacts afterwards." fi -cd jvm/examples/java +cd jvm/tests/fixtures/java log "Creating the jar from application" #Using Docker to build Jar so that maven & other Java dependencies are not needed on CI server @@ -33,7 +33,7 @@ log "Creating the jar from application" #first because it is not resolvable from any remote repository. docker run --rm \ -v "$(pwd)":/usr/src/mymaven \ - -v "$(pwd)/../../install-fission-java-core.sh":/usr/local/bin/install-fission-java-core \ + -v "$(pwd)/../../../install-fission-java-core.sh":/usr/local/bin/install-fission-java-core \ -w /usr/src/mymaven \ maven:3.9.16-eclipse-temurin-25-alpine \ sh -c "install-fission-java-core && mvn clean package -q" diff --git a/nodejs/README.md b/nodejs/README.md index b965e546..0d6c5029 100644 --- a/nodejs/README.md +++ b/nodejs/README.md @@ -6,7 +6,7 @@ It's a Docker image containing a NodeJS runtime, along with a dynamic loader. A few common dependencies are included in the package.json file. -Looking for ready-to-run examples? See the [NodeJS examples directory](./examples/). +Looking for ready-to-run examples? See the [NodeJS examples directory](https://github.com/fission/examples/tree/main/nodejs). ## Customizing this image diff --git a/nodejs/examples/README.md b/nodejs/examples/README.md deleted file mode 100644 index 31298bfc..00000000 --- a/nodejs/examples/README.md +++ /dev/null @@ -1,131 +0,0 @@ -# Fission Node.js Examples - -This is V2 example, check [here](README_V1.md) for V1. - -This directory contains several examples to get you started using Node.js with Fission. - -Before running any of these functions, make sure you have created a `nodejs` Fission environment: - -```bash -# Create an environment with default nodejs images -$ fission env create --name nodeenv --image fission/node-env:latest --builder fission/node-builder:latest -# Create zip file from our example -$ zip -jr nodejs.zip nodejs/ -# Create a package with the zip file -$ fission pkg create --sourcearchive nodejs.zip --env nodeenv -``` - -## Function signature - -Every Node.js function has the same basic form: - -```javascript -module.exports = async function(context) { - return { - status: 200, - body: 'Your body here', - headers: { - 'Foo': 'Bar' - } - } -} -``` -## hello.js - -This is a basic "Hello, World!" example. It simply returns a status of `200` and text body. - -### Usage -Since it is an `async` function, you can `await` `Promise`s, as demonstrated in the `weather.js` function. - -```bash -# Create a function -$ fission fn create --name hello --pkg [pkgname] --entrypoint "hello" - -# Test the function -$ fission fn test --name hello -``` - -## index.js - -This file does nothing but for demonstrating `require` feature. - -### Usage -```bash -# Create a function, you can skip `--entrypoint` as node will look for `index.js` by default -$ fission fn create --name index --pkg [pkgname] - -# Test the function -$ fission fn test --name index -``` - -## multi-entry.js - -This is a multiple exports example. There are two exports: entry1 and entry2 - -### Usage -```bash -# Create a function for entry1 -$ fission fn create --name entry1 --pkg [pkgname] --entrypoint "multi-entry.entry1" - -# Test the function -$ fission fn test --name entry1 - -# Create a function for entry2 -$ fission fn create --name entry2 --pkg [pkgname] --entrypoint "multi-entry.entry2" - -# Test the function -$ fission fn test --name entry2 -``` - -## hello-callback.js - -This is a basic "Hello, World!" example implemented with the legacy callback implementation. If you declare your function with two arguments (`context`, `callback`), a callback taking three arguments (`status`, `body`, `headers`) is provided. - -⚠️️ Callback support is only provided for backwards compatibility! We recommend that you use `async` functions instead. - -### Usage - -```bash -# Create a function -$ fission fn create --name hello-callback --pkg [pkgname] --entrypoint "hello-callback" - -# Map GET /hello-callback to your new function -$ fission route create --method GET --url /hello-callback --function hello-callback - -# Run the function. -$ curl http://$FISSION_ROUTER/hello-callback -Hello, world! -``` - -## kubeEventsSlack.js - -This example watches Kubernetes events and sends them to a Slack channel. To use this, create an incoming webhook for your Slack channel, and replace the `slackWebhookPath` in the example code. - -### Usage - -```bash -# Upload your function code to fission -$ fission fn create --name kubeEventsSlack --pkg [pkgname] --entrypoint "hello-callback" - -# Watch all services in the default namespace: -$ fission watch create --function kubeEventsSlack --type service --ns default -``` - -## weather.js - -In this example, the Yahoo Weather API is used to current weather at a given location. - -### Usage - -```bash -# Upload your function code to fission -$ fission function create --name weather --pkg [pkgname] --entrypoint "weather" - -# Map GET /stock to your new function -$ fission route create --method POST --url /weather --function weather - -# Run the function. -$ curl -H "Content-Type: application/json" -X POST -d '{"location":"Sieteiglesias, Spain"}' http://$FISSION_ROUTER/weather - -{"text":"It is 2 celsius degrees in Sieteiglesias, Spain and Mostly Clear"} -``` diff --git a/nodejs/examples/README_V1.md b/nodejs/examples/README_V1.md deleted file mode 100644 index d70da2e3..00000000 --- a/nodejs/examples/README_V1.md +++ /dev/null @@ -1,105 +0,0 @@ -# Fission Node.js Examples - -This directory contains several examples to get you started using Node.js with Fission. - -## Environment - -Before running any of these functions, make sure you have created a `nodejs` Fission environment: - -``` -$ fission env create --name nodejs --image fission/node-env -``` - -Note: The default `fission/node-env` image is based on Alpine, which is much smaller than the main Debian Node image (65MB vs 680MB) while still being suitable for most use cases. -If you need to use the full Debian image use the `fission/node-env-debian` image instead. -See the [official Node docker hub repo](https://hub.docker.com/_/node/) for considerations -relating to this choice. - -## Function signature - -Every Node.js function has the same basic form: - -```javascript -module.exports = async function(context) { - return { - status: 200, - body: 'Your body here', - headers: { - 'Foo': 'Bar' - } - } -} -``` - -Since it is an `async` function, you can `await` `Promise`s, as demonstrated in the `weather.js` function. - -## hello.js - -This is a basic "Hello, World!" example. It simply returns a status of `200` and text body. - -### Usage - -```bash -# Upload your function code to fission -$ fission function create --name hello --env nodejs --code hello.js - -# Map GET /hello to your new function -$ fission route create --method GET --url /hello --function hello - -# Run the function. -$ curl http://$FISSION_ROUTER/hello -Hello, world! -``` - -## hello-callback.js - -This is a basic "Hello, World!" example implemented with the legacy callback implementation. If you declare your function with two arguments (`context`, `callback`), a callback taking three arguments (`status`, `body`, `headers`) is provided. - -⚠️️ Callback support is only provided for backwards compatibility! We recommend that you use `async` functions instead. - -### Usage - -```bash -# Upload your function code to fission -$ fission function create --name hello-callback --env nodejs --code hello-callback.js - -# Map GET /hello-callback to your new function -$ fission route create --method GET --url /hello-callback --function hello-callback - -# Run the function. -$ curl http://$FISSION_ROUTER/hello-callback -Hello, world! -``` - -## kubeEventsSlack.js - -This example watches Kubernetes events and sends them to a Slack channel. To use this, create an incoming webhook for your Slack channel, and replace the `slackWebhookPath` in the example code. - -### Usage - -```bash -# Upload your function code to fission -$ fission fn create --name kubeEventsSlack --env nodejs --code kubeEventsSlack.js - -# Watch all services in the default namespace: -$ fission watch create --function kubeEventsSlack --type service --ns default -``` - -## weather.js - -In this example, the Yahoo Weather API is used to current weather at a given location. - -### Usage - -```bash -# Upload your function code to fission -$ fission function create --name weather --env nodejs --code weather.js - -# Map GET /stock to your new function -$ fission route create --method POST --url /weather --function weather - -# Run the function. -$ curl -H "Content-Type: application/json" -X POST -d '{"location":"Sieteiglesias, Spain"}' http://$FISSION_ROUTER/weather - -{"text":"It is 2 celsius degrees in Sieteiglesias, Spain and Mostly Clear"} -``` diff --git a/nodejs/examples/broadcast.js b/nodejs/examples/broadcast.js deleted file mode 100644 index f1caf412..00000000 --- a/nodejs/examples/broadcast.js +++ /dev/null @@ -1,9 +0,0 @@ -module.exports = async function(ws, clients) { - - ws.on('message', function incoming(data) { - clients.forEach(function each(client) { - client.send(data); - }); - }); - }); -} diff --git a/nodejs/examples/echo.js b/nodejs/examples/echo.js deleted file mode 100644 index 5ab3fa6c..00000000 --- a/nodejs/examples/echo.js +++ /dev/null @@ -1,6 +0,0 @@ -module.exports = async function(ws, clients) { - - ws.on('message', message => { - ws.send(message) - }); -} diff --git a/nodejs/examples/hello-callback.js b/nodejs/examples/hello-callback.js deleted file mode 100644 index 8d521777..00000000 --- a/nodejs/examples/hello-callback.js +++ /dev/null @@ -1,4 +0,0 @@ - -module.exports = (context, callback) => { - callback(200, "Hello, world callback!\n"); -} diff --git a/nodejs/examples/hello-esm.js b/nodejs/examples/hello-esm.js deleted file mode 100644 index e33c7097..00000000 --- a/nodejs/examples/hello-esm.js +++ /dev/null @@ -1,14 +0,0 @@ -export default async (context) => { - return { - status: 200, - body: JSON.stringify({ - message: "Hello from Node.js 22 Pure ESM! 🚀", - nodeVersion: process.version, - moduleType: "ESM", - timestamp: new Date().toISOString() - }, null, 2), - headers: { - "Content-Type": "application/json" - } - }; -}; \ No newline at end of file diff --git a/nodejs/examples/hello.js b/nodejs/examples/hello.js deleted file mode 100644 index c7346744..00000000 --- a/nodejs/examples/hello.js +++ /dev/null @@ -1,7 +0,0 @@ - -module.exports = async (context) => { - return { - status: 200, - body: "hello, world!\n" - }; -} diff --git a/nodejs/examples/index.html b/nodejs/examples/index.html deleted file mode 100644 index 78a6875c..00000000 --- a/nodejs/examples/index.html +++ /dev/null @@ -1,98 +0,0 @@ - - - -Chat Example - - - - -
-
- - -
- - diff --git a/nodejs/examples/index.js b/nodejs/examples/index.js deleted file mode 100644 index d2baebe6..00000000 --- a/nodejs/examples/index.js +++ /dev/null @@ -1 +0,0 @@ -module.exports = require('./hello'); diff --git a/nodejs/examples/kubeEventsSlack.js b/nodejs/examples/kubeEventsSlack.js deleted file mode 100644 index ed2e34d7..00000000 --- a/nodejs/examples/kubeEventsSlack.js +++ /dev/null @@ -1,64 +0,0 @@ -'use strict'; - -// -// Watch kubernetes events and send them to a slack channel. This -// uses Slack's incoming webhooks. To use this, create an incoming -// webhook for your slack channel through Slack's UI, and populate the -// relative path below. -// -// Create the function in fission: -// -// fission fn create --name kubeEventsSlack --env nodejs --code kubeEventsSlack.js -// -// Then, watch all services in the default namespace: -// -// fission watch create --function kubeEventsSlack --type service --ns default -// - -let https = require('https'); - -const slackWebhookPath = "YOUR RELATIVE PATH HERE"; // Something like "/services/XXX/YYY/zZz123" - -const upcaseFirst = (s) => { - return s.charAt(0).toUpperCase() + s.slice(1).toLowerCase(); -} - -const sendSlackMessage = async (msg) => { - const postData = `{"text": "${msg}"}`; - const options = { - hostname: "hooks.slack.com", - path: slackWebhookPath, - method: "POST", - headers: { - "Content-Type": "application/json" - } - }; - - return new Promise(function (resolve, reject) { - const req = https.request(options, function (res) { - console.log(`slack request status = ${res.statusCode}`); - return resolve(); - }); - req.send(postData); - }); -} - -module.exports = async (context) => { - const body = context.request.body; - const version = body.metadata.resourceVersion; - const eventType = context.request.get('X-Kubernetes-Event-Type'); - const objType = context.request.get('X-Kubernetes-Object-Type'); - - const msg = `${upcaseFirst(eventType)} ${objType} ${body.metadata.name}`; - console.log(msg, version); - - if (eventType == 'DELETED' || eventType == 'ADDED') { - console.log("sending event to slack") - await sendSlackMessage(msg); - } - - return { - status: 200, - body: "" - } -} \ No newline at end of file diff --git a/nodejs/examples/multi-entry-esm.js b/nodejs/examples/multi-entry-esm.js deleted file mode 100644 index daa7493b..00000000 --- a/nodejs/examples/multi-entry-esm.js +++ /dev/null @@ -1,40 +0,0 @@ -export const entry1 = async (context) => { - const { request } = context; - const name = request.query?.name || 'World'; - - return { - status: 200, - body: JSON.stringify({ - message: `Hello from Entry Point 1, ${name}! 🚀`, - entryPoint: 'entry1', - nodeVersion: process.version, - timestamp: new Date().toISOString(), - features: ['Named Exports', 'ESM Modules', 'Multiple Endpoints'] - }, null, 2), - headers: { - 'Content-Type': 'application/json', - 'X-Entry-Point': 'entry1' - } - }; -}; - -export const entry2 = async (context) => { - const { request } = context; - const data = request.body || {}; - - return { - status: 200, - body: JSON.stringify({ - message: `Greetings from Entry Point 2! 🎯`, - entryPoint: 'entry2', - nodeVersion: process.version, - timestamp: new Date().toISOString(), - receivedData: data, - capabilities: ['Data Processing', 'JSON Handling', 'Modern ESM'] - }, null, 2), - headers: { - 'Content-Type': 'application/json', - 'X-Entry-Point': 'entry2' - } - }; -}; \ No newline at end of file diff --git a/nodejs/examples/multi-entry.js b/nodejs/examples/multi-entry.js deleted file mode 100644 index 8c633d45..00000000 --- a/nodejs/examples/multi-entry.js +++ /dev/null @@ -1,13 +0,0 @@ -module.exports.entry1 = async (context) => { - return { - status: 200, - body: "Hello, entry 1!\n" - }; -} - -module.exports.entry2 = async (context) => { - return { - status: 200, - body: "Hello, entry 2!\n" - }; -} diff --git a/nodejs/examples/package.json b/nodejs/examples/package.json deleted file mode 100644 index 09fee482..00000000 --- a/nodejs/examples/package.json +++ /dev/null @@ -1,29 +0,0 @@ -{ - "name": "fission-nodejs-example", - "version": "0.1.0", - "author": "Soam Vasani", - "contributors": [ - { - "name": "Soam Vasani", - "email": "soamvasani+1@gmail.com" - }, - { - "name": "Gary Yeap", - "email": "contact@garyyeap.com" - } - ], - "description": "Nodejs example for Fission framework", - "engines": { - "node": ">=7.6.0" - }, - "dependencies": { - "body-parser": "*", - "co": "~4.6.0", - "express": "*", - "minimist": "*", - "morgan": "*", - "mz": "~2.7.0", - "node-fetch": "^2.6.1", - "underscore": ">=1.8.3" - } -} diff --git a/nodejs/examples/weather-esm.js b/nodejs/examples/weather-esm.js deleted file mode 100644 index 816b7ef5..00000000 --- a/nodejs/examples/weather-esm.js +++ /dev/null @@ -1,82 +0,0 @@ -// Weather API example for Node.js 22 ESM -// Uses Node.js 22's built-in fetch API (no external dependencies needed!) - -export default async (context) => { - const { request } = context; - // Support both body and query parameters - const location = request.body?.location || request.query?.location; - - if (!location) { - return { - status: 400, - body: JSON.stringify({ - error: 'Location is required', - usage: { - post: 'POST with {"location": "City, Country"}', - get: 'GET with ?location=City,Country', - example: '{"location": "San Francisco, CA"}' - } - }), - headers: { - 'Content-Type': 'application/json' - } - }; - } - - try { - // Note: This example uses mock weather data - // In production, replace with a real weather API like OpenWeatherMap - const mockWeatherData = { - location, - temperature: Math.floor(Math.random() * 30) + 5, // 5-35°C - condition: ['Sunny', 'Cloudy', 'Rainy', 'Partly Cloudy', 'Thunderstorms'][Math.floor(Math.random() * 5)], - humidity: Math.floor(Math.random() * 40) + 30, // 30-70% - windSpeed: Math.floor(Math.random() * 20) + 5, // 5-25 km/h - uvIndex: Math.floor(Math.random() * 11), // 0-10 - visibility: Math.floor(Math.random() * 15) + 5, // 5-20 km - timestamp: new Date().toISOString(), - coordinates: { - lat: (Math.random() * 180 - 90).toFixed(4), - lon: (Math.random() * 360 - 180).toFixed(4) - } - }; - - // Simulate weather severity - const severity = mockWeatherData.condition === 'Thunderstorms' ? 'high' : - mockWeatherData.condition === 'Rainy' ? 'medium' : 'low'; - - return { - status: 200, - body: JSON.stringify({ - success: true, - data: { - ...mockWeatherData, - severity, - recommendation: severity === 'high' ? 'Stay indoors' : - severity === 'medium' ? 'Bring an umbrella' : 'Great weather for outdoor activities' - }, - message: `Current weather in ${location}: ${mockWeatherData.temperature}°C and ${mockWeatherData.condition}`, - nodeVersion: process.version, - builtInFetch: 'Node.js 22 native fetch API ready for real weather services!', - requestMethod: request.method || 'GET' - }, null, 2), - headers: { - 'Content-Type': 'application/json', - 'X-Weather-Source': 'mock-data', - 'X-Node-Version': process.version - } - }; - } catch (error) { - return { - status: 500, - body: JSON.stringify({ - error: 'Failed to fetch weather data', - details: error.message, - nodeVersion: process.version - }), - headers: { - 'Content-Type': 'application/json' - } - }; - } -}; \ No newline at end of file diff --git a/nodejs/examples/weather.js b/nodejs/examples/weather.js deleted file mode 100644 index 4b26f1f8..00000000 --- a/nodejs/examples/weather.js +++ /dev/null @@ -1,37 +0,0 @@ -'use strict'; - -const fetch = require('node-fetch'); - -module.exports = async (context) => { - const location = ctx.request.body.location; - - if (!location) { - return { - status: 400, - body: { - text: 'You must provide a location.' - } - }; - } - - try { - const locationSearch = await fetch(`https://www.metaweather.com/api/location/search/?query=${encodeURIComponent(location)}`).then(res => JSON.parse(res)); - const weatherResponse = await fetch(`https://www.metaweather.com/api/location/(${locationSearch[0].woeid}/`).then(res => JSON.parse(res)); - const weather = weatherResponse.consolidatedWeather[0] - return { - status: 200, - body: { - text: `It is ${weather.the_temp} celsius degrees in ${location} and ${weather.weather_state_name}` - }, - headers: { - 'Content-Type': 'application/json' - } - }; - } catch (e) { - console.error(e); - return { - status: 500, - body: e - }; - } -} \ No newline at end of file diff --git a/perl/examples/hello.pm b/perl/examples/hello.pm deleted file mode 100644 index 680a4f64..00000000 --- a/perl/examples/hello.pm +++ /dev/null @@ -1,36 +0,0 @@ -=pod - -You return a CODEREF from the package that will be called as your function. - -The code in the server is something like this (simplified): - - my $sub = require('hello.pm'); - $sub->(request); - -As you can see, you get the L object as first argument -to your function. You can use it to retrieve params given to your function or -anything else Dancer2 offers. You can also use Dancer2 and use its DSL. - -=cut - -use utf8; -use strict; -use warnings; - -# Get more helper functions (status and send_as below) -use Dancer2; - -return sub { - my ($request) = @_; - - my ($name) = $request->query_parameters->{'name'} // 'world'; - - # set status code by name - status 'i_m_a_teapot'; - - # send message as JSON - send_as JSON => { - msg => "Hello, $name", - auth => $request->header('Authorization'), # read request header - }; -}; diff --git a/php7/README.md b/php7/README.md index 400a3533..c6045fbe 100644 --- a/php7/README.md +++ b/php7/README.md @@ -22,7 +22,7 @@ A few common extensions are included : - xmlrpc - zip -Looking for ready-to-run examples? See the [PHP examples directory](../../examples/php). +Looking for ready-to-run examples? See the [PHP examples directory](https://github.com/fission/examples/tree/main/php7). ## Customizing this image diff --git a/php7/examples/hello.php b/php7/examples/hello.php deleted file mode 100644 index 340116ab..00000000 --- a/php7/examples/hello.php +++ /dev/null @@ -1,3 +0,0 @@ -warning("Hello logger"); \ No newline at end of file diff --git a/php7/examples/hellopsr.php b/php7/examples/hellopsr.php deleted file mode 100644 index 31c9bdb4..00000000 --- a/php7/examples/hellopsr.php +++ /dev/null @@ -1,12 +0,0 @@ -getBody()->write("Hello from handler PHP"); - $logger->warning("Hello logger"); -} \ No newline at end of file diff --git a/php7/examples/multifile/README.md b/php7/examples/multifile/README.md deleted file mode 100644 index f5f80422..00000000 --- a/php7/examples/multifile/README.md +++ /dev/null @@ -1,69 +0,0 @@ -This is an example of creating a deployment package with multiple -files including external libraries via composer. - -### Create an environment - -``` -fission env create --name php --image fission/php-env:latest --builder fission/php-builder:latest --version 2 -``` - -### Create a zip file with all your files - -``` -zip -r multifile.zip . -i *.php *.txt composer.json -``` - -### Create a package -``` -fission package create --sourcearchive multifile.zip --env php -``` -This command will print the created package. We will use it in the next step. - - -### Create a function - -Since there are multiple files, you have to specify an _entrypoint_ to -for the function. Its format is `::`. In our -example, that's `handlers/FileReader.php::execute`, to run function `execute` in `handlers/FileReader.php`. - -``` -fission function create --name multifile --env php --pkg --entrypoint "handlers/FileReader.php::execute" -``` - -### Test it - -``` -fission function test --name multifile -``` - -You should see the "Hello, world" message. - - -## Updating the function - -### Edit a file - -``` -echo "I said hellooooo!" > message.txt -``` - -### Update the deployment package - -``` -zip -r multifile.zip . -i *.php *.txt composer.json -``` - -### Update the package - -``` -fission package update --name --sourcearchive multifile.zip --env php -``` - -### Test it - -``` -fission function test --name multifile -``` - -You should now see your new, edited message. - diff --git a/php7/examples/multifile/composer.json b/php7/examples/multifile/composer.json deleted file mode 100644 index 24b5ba72..00000000 --- a/php7/examples/multifile/composer.json +++ /dev/null @@ -1,14 +0,0 @@ -{ - "name": "example/php7", - "description": "Example for php7 environment", - "require": { - "psr/log": "^1.1", - "psr/http-message": "^1.0" - }, - "authors": [ - { - "name": "Alberto Lopez", - "email": "alberto.lopez.benito@gmail.com" - } - ] -} diff --git a/php7/examples/multifile/handlers/FileReader.php b/php7/examples/multifile/handlers/FileReader.php deleted file mode 100644 index a5fc028f..00000000 --- a/php7/examples/multifile/handlers/FileReader.php +++ /dev/null @@ -1,16 +0,0 @@ -getBody()->write(file_get_contents(__DIR__ . '/message.txt')); - $logger->debug('File read: example.txt'); -} diff --git a/php7/examples/multifile/handlers/message.txt b/php7/examples/multifile/handlers/message.txt deleted file mode 100644 index 91fb05b9..00000000 --- a/php7/examples/multifile/handlers/message.txt +++ /dev/null @@ -1 +0,0 @@ -I said hellooooo! diff --git a/php7/examples/stock.php b/php7/examples/stock.php deleted file mode 100644 index ede840f5..00000000 --- a/php7/examples/stock.php +++ /dev/null @@ -1,47 +0,0 @@ -withStatus(500); - $response->getBody()->write($message); - return $response; -} - -function handler($context){ - /** @var ResponseInterface $response */ - $response = $context["response"]; - /** @var ServerRequestInterface $request */ - $request = $context["request"]; - /** @var LoggerInterface $logger */ - $logger = $context["logger"]; - - $logger->debug("Request : ",$request->getParsedBody()); - if($request->getMethod() != "POST") - return sendError($response,"You must use POST method"); - - $body = $request->getParsedBody(); - if(!isset($body["currency"])) - return sendError($response,"'currency' is not present in the POST request"); - - $allowedCurrency = ["ltc","btc"]; - if(!in_array($body["currency"],$allowedCurrency)) - return sendError($response,"'currency' is non allowed. Use one of them : ".implode(",",$allowedCurrency)); - - $curl = curl_init(); - curl_setopt_array($curl, array( - CURLOPT_RETURNTRANSFER => 1, - CURLOPT_URL => 'https://api.cryptonator.com/api/ticker/'.$body["currency"].'-usd' - )); - $result = curl_exec($curl); - curl_close($curl); - - $result = json_decode($result,true); - if($result){ - $logger->debug("Response API",$result); - $response->getBody()->write(json_encode(array("text"=>sprintf("%s-USB = %02f",$body["currency"],$result["ticker"]["price"])))); - }else - return sendError($response,"Cryptonator API not available"); - -} diff --git a/python-fastapi/examples/README.md b/python-fastapi/examples/README.md deleted file mode 100644 index 8141cec0..00000000 --- a/python-fastapi/examples/README.md +++ /dev/null @@ -1,27 +0,0 @@ -# Python Examples - -This directory contains a Python examples to show different the features of the Fission Python environment: -- `hello.py` is a simple Pythonic _hello world_ function. -- `sourcepkg/` is an example of how to use the Fission Python Build environment to resolve (pip) dependencies - before deploying the function. -- `multifile/` shows how to create Fission Python functions with multiple source files. -- `requestdata.py` shows how you can access the HTTP request fields, such as the body, headers and query. -- `statuscode.py` is an example of how you can change the response status code. -- `guestbook/` is a more realistic demonstration of using Python and Fission to create a serverless guestbook. - -## Getting Started - -Create a Fission Python environment with the default Python runtime image (this does not include the build environment): -``` -fission environment create --name python --image ghcr.io/fission/python-fastapi-env -``` - -Use the `hello.py` to create a Fission Python function: -``` -fission function create --name hello-py --env python --code hello.py -``` - -Test the function: -``` -fission function test --name hello-py -``` diff --git a/python-fastapi/examples/guestbook/add.py b/python-fastapi/examples/guestbook/add.py deleted file mode 100644 index 03420d8a..00000000 --- a/python-fastapi/examples/guestbook/add.py +++ /dev/null @@ -1,20 +0,0 @@ -# -# Handles POST /guestbook -- adds item to guestbook -# - -from fastapi import Request, Response -from fastapi.responses import RedirectResponse -import redis - -# Connect to redis. -redisConnection = redis.StrictRedis(host='redis.guestbook', port=6379, db=0) - -async def main(request: Request): - # Read the item from POST params, add it to redis, and redirect - # back to the list - form = await request.form() - book = form.get('text') - if book is None: - return Response(status_code=400) - redisConnection.rpush('guestbook', book) - return RedirectResponse('/guestbook', status_code=303) diff --git a/python-fastapi/examples/guestbook/build.sh b/python-fastapi/examples/guestbook/build.sh deleted file mode 100755 index c9e6acd5..00000000 --- a/python-fastapi/examples/guestbook/build.sh +++ /dev/null @@ -1,2 +0,0 @@ -#!/bin/sh -pip3 install -r ${SRC_PKG}/requirements.txt -t ${SRC_PKG} && cp -r ${SRC_PKG} ${DEPLOY_PKG} diff --git a/python-fastapi/examples/guestbook/deploy.sh b/python-fastapi/examples/guestbook/deploy.sh deleted file mode 100755 index 01649e6c..00000000 --- a/python-fastapi/examples/guestbook/deploy.sh +++ /dev/null @@ -1,24 +0,0 @@ -#!/bin/sh - -set -e - -kubectl apply -f redis.yaml - -if [ -z "$FISSION_URL" ] -then - echo "Need $FISSION_URL set to a fission controller address" - exit 1 -fi - -# Create python env if it doesn't exist -fission env get --name python || fission env create --name python --image python-fastapi-env --builder python-fastapi-builder - -# Create zip file -zip -jr guestbook.zip ../guestbook - -# Create packages -fission package create --name guestbook --sourcearchive guestbook.zip --env python --buildcmd "./build.sh" - -# Register functions and routes with fission -fission function create --name guestbook-get --env python --pkg guestbook --entrypoint "get.main" --url /guestbook --method GET -fission function create --name guestbook-add --env python --pkg guestbook --entrypoint "add.main" --url /guestbook --method POST diff --git a/python-fastapi/examples/guestbook/get.py b/python-fastapi/examples/guestbook/get.py deleted file mode 100644 index db21357c..00000000 --- a/python-fastapi/examples/guestbook/get.py +++ /dev/null @@ -1,29 +0,0 @@ -# -# Handles GET /guestbook -- returns a list of items in the guestbook -# with a form to add more. -# - -from fastapi import Request, Response -from markupsafe import escape -import redis - -# Connect to redis. This is run only when this file is loaded; as -# long as the pod is alive, the connection is reused. -redisConnection = redis.StrictRedis(host='redis.guestbook', port=6379, db=0) - -def main(request: Request): - messages = redisConnection.lrange('guestbook', 0, -1) - - items = [("
  • %s
  • " % escape(m.decode('utf-8'))) for m in messages] - ul = "
      %s
    " % "\n".join(items) - return Response(""" - -

    Guestbook

    -
    - - -
    -
    - %s - - """ % ul) diff --git a/python-fastapi/examples/guestbook/redis.yaml b/python-fastapi/examples/guestbook/redis.yaml deleted file mode 100644 index 4269b0b5..00000000 --- a/python-fastapi/examples/guestbook/redis.yaml +++ /dev/null @@ -1,45 +0,0 @@ -apiVersion: v1 -kind: Namespace -metadata: - name: guestbook - labels: - name: guestbook - ---- -apiVersion: apps/v1 -kind: Deployment -metadata: - labels: - run: redis - name: redis - namespace: guestbook -spec: - replicas: 1 - selector: - matchLabels: - run: redis - template: - metadata: - labels: - run: redis - spec: - containers: - - image: redis - name: redis - ---- -apiVersion: v1 -kind: Service -metadata: - labels: - run: redis - name: redis - namespace: guestbook -spec: - selector: - run: redis - type: ClusterIP - ports: - - port: 6379 - protocol: TCP - targetPort: 6379 diff --git a/python-fastapi/examples/guestbook/requirements.txt b/python-fastapi/examples/guestbook/requirements.txt deleted file mode 100644 index 92f838b6..00000000 --- a/python-fastapi/examples/guestbook/requirements.txt +++ /dev/null @@ -1,3 +0,0 @@ -redis==3.5.3 -MarkupSafe==2.1.4 -python-multipart==0.0.27 diff --git a/python-fastapi/examples/multifile/README.md b/python-fastapi/examples/multifile/README.md deleted file mode 100644 index e7c1daba..00000000 --- a/python-fastapi/examples/multifile/README.md +++ /dev/null @@ -1,62 +0,0 @@ -This is an example of creating a deployment package with multiple -files including some static data in text file. - -### Create an environment - -``` -fission env create --name python --image ghcr.io/fission/python-fastapi-env --version 3 -``` - -### Create a zip file with all your files - -``` -zip -jr multifile.zip *.py *.txt -``` - -### Create a function - -Since there are multiple files, you have to specify an _entrypoint_ to -for the function. Its format is `.`. In our -example, that's `main.main`, to run function `main` in `main.py`. - -``` -fission function create --name multifile --env python --code multifile.zip --entrypoint main.main -``` - -### Test it - -``` -fission function test --name multifile -``` - -You should see the "Hello, world" message. - - -## Updating the function - -### Edit a file - -``` -echo "I said hellooooo!" > message.txt -``` - -### Update the deployment package - -``` -zip -jr multifile.zip *.py *.txt -``` - -### Update the function - -``` -fission function update --name multifile --code multifile.zip -``` - -### Test it - -``` -fission function test --name multifile -``` - -You should now see your new, edited message. - diff --git a/python-fastapi/examples/multifile/__init__.py b/python-fastapi/examples/multifile/__init__.py deleted file mode 100644 index e69de29b..00000000 diff --git a/python-fastapi/examples/multifile/main.py b/python-fastapi/examples/multifile/main.py deleted file mode 100644 index 6ce7c4b0..00000000 --- a/python-fastapi/examples/multifile/main.py +++ /dev/null @@ -1,11 +0,0 @@ -from fastapi import logger, Request, Response -import sys -import readfile -import os - -def main(request: Request): - logger.logger.info("Hi") - - current_dir = os.path.dirname(__file__) - - return Response(readfile.readFile(os.path.join(current_dir, "message.txt"))) diff --git a/python-fastapi/examples/multifile/message.txt b/python-fastapi/examples/multifile/message.txt deleted file mode 100644 index af5626b4..00000000 --- a/python-fastapi/examples/multifile/message.txt +++ /dev/null @@ -1 +0,0 @@ -Hello, world! diff --git a/python-fastapi/examples/multifile/readfile.py b/python-fastapi/examples/multifile/readfile.py deleted file mode 100644 index 02e892bf..00000000 --- a/python-fastapi/examples/multifile/readfile.py +++ /dev/null @@ -1,3 +0,0 @@ -def readFile(name): - with open(name) as f: - return f.read() diff --git a/python-fastapi/examples/requestdata.py b/python-fastapi/examples/requestdata.py deleted file mode 100644 index 20b6186f..00000000 --- a/python-fastapi/examples/requestdata.py +++ /dev/null @@ -1,6 +0,0 @@ -from fastapi import logger, Request, Response - -async def main(request: Request): - logger.logger.info("Received request") - msg = "---HEADERS---\n%s\n--BODY--\n%s\n-----\n" % (request.headers, str(await request.body(), encoding='utf-8')) - return Response(msg) diff --git a/python-fastapi/examples/sourcepkg/__init__.py b/python-fastapi/examples/sourcepkg/__init__.py deleted file mode 100644 index e69de29b..00000000 diff --git a/python-fastapi/examples/sourcepkg/build.sh b/python-fastapi/examples/sourcepkg/build.sh deleted file mode 100755 index c9e6acd5..00000000 --- a/python-fastapi/examples/sourcepkg/build.sh +++ /dev/null @@ -1,2 +0,0 @@ -#!/bin/sh -pip3 install -r ${SRC_PKG}/requirements.txt -t ${SRC_PKG} && cp -r ${SRC_PKG} ${DEPLOY_PKG} diff --git a/python-fastapi/examples/sourcepkg/requirements.txt b/python-fastapi/examples/sourcepkg/requirements.txt deleted file mode 100644 index c3726e8b..00000000 --- a/python-fastapi/examples/sourcepkg/requirements.txt +++ /dev/null @@ -1 +0,0 @@ -pyyaml diff --git a/python-fastapi/examples/sourcepkg/user.py b/python-fastapi/examples/sourcepkg/user.py deleted file mode 100644 index ebc33bcc..00000000 --- a/python-fastapi/examples/sourcepkg/user.py +++ /dev/null @@ -1,18 +0,0 @@ -from yaml import load, dump -from fastapi import Request, Response - -try: - from yaml import CLoader as Loader, CDumper as Dumper -except ImportError: - from yaml import Loader, Dumper - -document = """ - a: 1 - b: - c: 3 - d: 4 -""" - - -def main(request: Request): - return Response(dump(load(document, Loader=Loader), default_flow_style=None, Dumper=Dumper)) diff --git a/python-fastapi/examples/statuscode.py b/python-fastapi/examples/statuscode.py deleted file mode 100644 index 4ec0cb52..00000000 --- a/python-fastapi/examples/statuscode.py +++ /dev/null @@ -1,4 +0,0 @@ -from fastapi import Request, Response - -def main(request: Request): - return Response("Not Found", 404) diff --git a/python-fastapi/examples/hello.py b/python-fastapi/tests/fixtures/hello.py similarity index 100% rename from python-fastapi/examples/hello.py rename to python-fastapi/tests/fixtures/hello.py diff --git a/python-fastapi/tests/local_test.sh b/python-fastapi/tests/local_test.sh index 40e9746c..0e6b7c3c 100755 --- a/python-fastapi/tests/local_test.sh +++ b/python-fastapi/tests/local_test.sh @@ -32,7 +32,7 @@ echo "--Healthz" curl -f -X GET http://localhost:$RUNTIME_PORT/healthz echo "-- Specializing" -curl -f -XPOST http://localhost:$RUNTIME_PORT/v2/specialize -H 'Content-Type: application/json' -d '{"filepath": "./examples/hello.py", "functionName": "main"}' +curl -f -XPOST http://localhost:$RUNTIME_PORT/v2/specialize -H 'Content-Type: application/json' -d '{"filepath": "./tests/fixtures/hello.py", "functionName": "main"}' echo "-- Running user function" echo "-- GET request" diff --git a/python-fastapi/tests/test_python_fastapi_env.sh b/python-fastapi/tests/test_python_fastapi_env.sh index ba29773f..ab2d5041 100755 --- a/python-fastapi/tests/test_python_fastapi_env.sh +++ b/python-fastapi/tests/test_python_fastapi_env.sh @@ -57,7 +57,7 @@ timeout 60s bash -c "waitBuild $pkg" log "===== 1. test env with v1 api =====" -fission fn create --name $fn1 --env $env_v1api --code $ROOT/python-fastapi/examples/hello.py +fission fn create --name $fn1 --env $env_v1api --code $ROOT/python-fastapi/tests/fixtures/hello.py fission route create --name $fn1 --function $fn1 --url /$fn1 --method GET sleep 3 # Waiting for router to catch up timeout 60 bash -c "test_fn $fn1 'Hello, world!'" diff --git a/python/examples/README.md b/python/examples/README.md deleted file mode 100644 index 17522d9e..00000000 --- a/python/examples/README.md +++ /dev/null @@ -1,29 +0,0 @@ -# Python Examples - -This directory contains a Python examples to show different the features of the Fission Python environment: -- `hello.py` is a simple Pythonic _hello world_ function. -- `requestdata.py` shows how you can access the HTTP request fields, such as the body, headers and query. -- `statuscode.py` is an example of how you can change the response status code. -- `multifile/` shows how to create Fission Python functions with multiple source files. -- `guestbook/` is a more realistic demonstration of using Python and Fission to create a serverless guestbook. -- `sourcepkg/` is an example of how to use the Fission Python Build environment to resolve (pip) dependencies - before deploying the function. - -## Getting Started - -Create a Fission Python environment with the default Python runtime image (this does not include the build environment): -``` -fission environment create --name python --image fission/python-env -``` - -Use the `hello.py` to create a Fission Python function: -``` -fission function create --name hello-py --env python --code hello.py -``` - -Test the function: -``` -fission function test --name hello-py -``` - -For a full guide see the [official documentation on Python with Fission](https://docs.fission.io/languages/python/). diff --git a/python/examples/guestbook/add.py b/python/examples/guestbook/add.py deleted file mode 100644 index f7a747ae..00000000 --- a/python/examples/guestbook/add.py +++ /dev/null @@ -1,18 +0,0 @@ -# -# Handles POST /guestbook -- adds item to guestbook -# - -from flask import request, redirect -import redis - -# Connect to redis. -redisConnection = redis.StrictRedis(host='redis.guestbook', port=6379, db=0) - -def main(): - # Read the item from POST params, add it to redis, and redirect - # back to the list - item = request.form['text'] - redisConnection.rpush('guestbook', item) - r = redirect('/guestbook', code=303) - r.autocorrect_location_header = False - return r diff --git a/python/examples/guestbook/deploy.sh b/python/examples/guestbook/deploy.sh deleted file mode 100755 index 815c0115..00000000 --- a/python/examples/guestbook/deploy.sh +++ /dev/null @@ -1,18 +0,0 @@ -#!/bin/sh - -set -e - -kubectl create -f redis.yaml - -if [ -z "$FISSION_URL" ] -then - echo "Need $FISSION_URL set to a fission controller address" - exit 1 -fi - -# Create python env if it doesn't exist -fission env get --name python || fission env create --name python --image fission/python-env - -# Register functions and routes with fission -fission function create --name guestbook-get --env python --code get.py --url /guestbook --method GET -fission function create --name guestbook-add --env python --code add.py --url /guestbook --method POST diff --git a/python/examples/guestbook/get.py b/python/examples/guestbook/get.py deleted file mode 100644 index a95016b4..00000000 --- a/python/examples/guestbook/get.py +++ /dev/null @@ -1,28 +0,0 @@ -# -# Handles GET /guestbook -- returns a list of items in the guestbook -# with a form to add more. -# - -from flask import current_app, escape -import redis - -# Connect to redis. This is run only when this file is loaded; as -# long as the pod is alive, the connection is reused. -redisConnection = redis.StrictRedis(host='redis.guestbook', port=6379, db=0) - -def main(): - messages = redisConnection.lrange('guestbook', 0, -1) - - items = [("
  • %s
  • " % escape(m.decode('utf-8'))) for m in messages] - ul = "
      %s
    " % "\n".join(items) - return """ - -

    Guestbook

    -
    - - -
    -
    - %s - - """ % ul diff --git a/python/examples/guestbook/redis.yaml b/python/examples/guestbook/redis.yaml deleted file mode 100644 index 4269b0b5..00000000 --- a/python/examples/guestbook/redis.yaml +++ /dev/null @@ -1,45 +0,0 @@ -apiVersion: v1 -kind: Namespace -metadata: - name: guestbook - labels: - name: guestbook - ---- -apiVersion: apps/v1 -kind: Deployment -metadata: - labels: - run: redis - name: redis - namespace: guestbook -spec: - replicas: 1 - selector: - matchLabels: - run: redis - template: - metadata: - labels: - run: redis - spec: - containers: - - image: redis - name: redis - ---- -apiVersion: v1 -kind: Service -metadata: - labels: - run: redis - name: redis - namespace: guestbook -spec: - selector: - run: redis - type: ClusterIP - ports: - - port: 6379 - protocol: TCP - targetPort: 6379 diff --git a/python/examples/multifile/README.md b/python/examples/multifile/README.md deleted file mode 100644 index f822b5fc..00000000 --- a/python/examples/multifile/README.md +++ /dev/null @@ -1,62 +0,0 @@ -This is an example of creating a deployment package with multiple -files including some static data in text file. - -### Create an environment - -``` -fission env create --name python --image fission/python-env:0.4.0rc --version 2 -``` - -### Create a zip file with all your files - -``` -zip -jr multifile.zip *.py *.txt -``` - -### Create a function - -Since there are multiple files, you have to specify an _entrypoint_ to -for the function. Its format is `.`. In our -example, that's `main.main`, to run function `main` in `main.py`. - -``` -fission function create --name multifile --env python --code multifile.zip --entrypoint main.main -``` - -### Test it - -``` -fission function test --name multifile -``` - -You should see the "Hello, world" message. - - -## Updating the function - -### Edit a file - -``` -echo "I said hellooooo!" > message.txt -``` - -### Update the deployment package - -``` -zip -jr multifile.zip *.py *.txt -``` - -### Update the function - -``` -fission function update --name multifile --code multifile.zip -``` - -### Test it - -``` -fission function test --name multifile -``` - -You should now see your new, edited message. - diff --git a/python/examples/multifile/__init__.py b/python/examples/multifile/__init__.py deleted file mode 100644 index e69de29b..00000000 diff --git a/python/examples/multifile/main.py b/python/examples/multifile/main.py deleted file mode 100644 index bffcf997..00000000 --- a/python/examples/multifile/main.py +++ /dev/null @@ -1,11 +0,0 @@ -from flask import current_app -import sys -import readfile -import os - -def main(): - current_app.logger.info("Hi") - - current_dir = os.path.dirname(__file__) - - return readfile.readFile(os.path.join(current_dir, "message.txt")) diff --git a/python/examples/multifile/message.txt b/python/examples/multifile/message.txt deleted file mode 100644 index af5626b4..00000000 --- a/python/examples/multifile/message.txt +++ /dev/null @@ -1 +0,0 @@ -Hello, world! diff --git a/python/examples/multifile/readfile.py b/python/examples/multifile/readfile.py deleted file mode 100644 index 02e892bf..00000000 --- a/python/examples/multifile/readfile.py +++ /dev/null @@ -1,3 +0,0 @@ -def readFile(name): - with open(name) as f: - return f.read() diff --git a/python/examples/requestdata.py b/python/examples/requestdata.py deleted file mode 100644 index 93f725a5..00000000 --- a/python/examples/requestdata.py +++ /dev/null @@ -1,7 +0,0 @@ -from flask import request -from flask import current_app - -def main(): - current_app.logger.info("Received request") - msg = "---HEADERS---\n%s\n--BODY--\n%s\n-----\n" % (request.headers, request.get_data()) - return msg diff --git a/python/examples/sourcepkg/__init__.py b/python/examples/sourcepkg/__init__.py deleted file mode 100644 index e69de29b..00000000 diff --git a/python/examples/sourcepkg/build.sh b/python/examples/sourcepkg/build.sh deleted file mode 100755 index e9215130..00000000 --- a/python/examples/sourcepkg/build.sh +++ /dev/null @@ -1,2 +0,0 @@ -#!/bin/sh -pip3 install -r ${SRC_PKG}/requirements.txt -t ${SRC_PKG} && cp -r ${SRC_PKG} ${DEPLOY_PKG} \ No newline at end of file diff --git a/python/examples/sourcepkg/requirements.txt b/python/examples/sourcepkg/requirements.txt deleted file mode 100644 index c3726e8b..00000000 --- a/python/examples/sourcepkg/requirements.txt +++ /dev/null @@ -1 +0,0 @@ -pyyaml diff --git a/python/examples/sourcepkg/user.py b/python/examples/sourcepkg/user.py deleted file mode 100644 index aef11272..00000000 --- a/python/examples/sourcepkg/user.py +++ /dev/null @@ -1,11 +0,0 @@ -import yaml - -document = """ - a: 1 - b: - c: 3 - d: 4 -""" - -def main(): - return yaml.dump(yaml.load(document), default_flow_style=None) diff --git a/python/examples/statuscode.py b/python/examples/statuscode.py deleted file mode 100644 index 7d747157..00000000 --- a/python/examples/statuscode.py +++ /dev/null @@ -1,4 +0,0 @@ -def main(): - # You can return any http status code you like, simply place a comma after - # your return statement, and typing in the status code. - return "Not Found\n", 404 diff --git a/python/examples/hello.py b/python/tests/fixtures/hello.py similarity index 100% rename from python/examples/hello.py rename to python/tests/fixtures/hello.py diff --git a/python/examples/websocket/main.py b/python/tests/fixtures/websocket/main.py similarity index 100% rename from python/examples/websocket/main.py rename to python/tests/fixtures/websocket/main.py diff --git a/python/tests/local_test.sh b/python/tests/local_test.sh index 40e9746c..0e6b7c3c 100755 --- a/python/tests/local_test.sh +++ b/python/tests/local_test.sh @@ -32,7 +32,7 @@ echo "--Healthz" curl -f -X GET http://localhost:$RUNTIME_PORT/healthz echo "-- Specializing" -curl -f -XPOST http://localhost:$RUNTIME_PORT/v2/specialize -H 'Content-Type: application/json' -d '{"filepath": "./examples/hello.py", "functionName": "main"}' +curl -f -XPOST http://localhost:$RUNTIME_PORT/v2/specialize -H 'Content-Type: application/json' -d '{"filepath": "./tests/fixtures/hello.py", "functionName": "main"}' echo "-- Running user function" echo "-- GET request" diff --git a/python/tests/test_python_env.sh b/python/tests/test_python_env.sh index 2287b9bb..021f9c57 100755 --- a/python/tests/test_python_env.sh +++ b/python/tests/test_python_env.sh @@ -57,7 +57,7 @@ timeout 60s bash -c "waitBuild $pkg" log "===== 1. test env with v1 api =====" -fission fn create --name $fn1 --env $env_v1api --code $ROOT/python/examples/hello.py +fission fn create --name $fn1 --env $env_v1api --code $ROOT/python/tests/fixtures/hello.py fission route create --name $fn1 --function $fn1 --url /$fn1 --method GET sleep 3 # Waiting for router to catch up timeout 60 bash -c "test_fn $fn1 'Hello, world!'" diff --git a/python/tests/websocket_test.sh b/python/tests/websocket_test.sh index 6037fffd..862ead51 100755 --- a/python/tests/websocket_test.sh +++ b/python/tests/websocket_test.sh @@ -39,7 +39,7 @@ echo "--Healthz" curl -f -X GET http://localhost:$RUNTIME_PORT/healthz echo "-- Specializing" -curl -f -XPOST http://localhost:$RUNTIME_PORT/v2/specialize -H 'Content-Type: application/json' -d '{"filepath": "./examples/websocket/main.py", "functionName": "main"}' +curl -f -XPOST http://localhost:$RUNTIME_PORT/v2/specialize -H 'Content-Type: application/json' -d '{"filepath": "./tests/fixtures/websocket/main.py", "functionName": "main"}' echo "-- Websocket ready to connect ws://localhost:$RUNTIME_PORT/." read -p "Press enter to continue" diff --git a/ruby/README.md b/ruby/README.md index 9a605bae..d11f1d37 100644 --- a/ruby/README.md +++ b/ruby/README.md @@ -17,7 +17,7 @@ The `Fission::Request` object is a subclass of `Rack::Request` and provides access to parameters and headers. See `fission/request.rb` for the public api. -Looking for ready-to-run examples? See the [Ruby examples directory](../../examples/ruby). +Looking for ready-to-run examples? See the [Ruby examples directory](https://github.com/fission/examples/tree/main/ruby). ## Customizing this image diff --git a/ruby/examples/README.md b/ruby/examples/README.md deleted file mode 100644 index 741b9a04..00000000 --- a/ruby/examples/README.md +++ /dev/null @@ -1,115 +0,0 @@ -# Ruby examples - -This directory contains several examples to get you started using Ruby -with Fission. - -Before running any of these functions, make sure you have created a -`ruby` Fission environment: - -``` -$ fission env create --name ruby --image USER/ruby-env -``` - -## Method signature - -A standard Ruby function has the basic form: - -```ruby -def handler(context) - return [200, {}, []] -end -``` - -If the fission context is not required, the function can be simplified: - -```ruby -def handler - [200, {}, ["Hello, world!\n"]] -end -``` - -If a simple text response is to be returned, with a status of 200, this -can be further simplified. - -```ruby -def handler - "Hello, world!\n" -end -``` - -## Hello example (`hello.rb`) - -This example is the simplest possible Ruby function, as described above. - -To run the example: - -``` -$ fission function create --name hello --env ruby --code examples/ruby/hello.rb - -$ fission route create --method GET --url /hello --function hello - -$ curl http://$FISSION_ROUTER/hello - Hello, world! -``` - -## Request data example (`request_data.rb`) - -This example shows basic use of the `Fission::Context` and -`Fission::Request` objects. - -To run the example: - -``` -$ fission function create --name request --env ruby --code examples/ruby/request_data.rb - -$ fission route create --method GET --url /request/{id} --function request - -$ curl http://$FISSION_ROUTER/request/123?key=abc - ---ENV--- - GATEWAY_INTERFACE=CGI/1.1 - PATH_INFO=/ - QUERY_STRING=key=abc - REMOTE_ADDR=172.17.0.8 - REMOTE_HOST=172.17.0.8 - REQUEST_METHOD=GET - REQUEST_URI=http://192.168.64.200:31314/?key=abc - SCRIPT_NAME= - SERVER_NAME=192.168.64.200 - SERVER_PORT=31314 - SERVER_PROTOCOL=HTTP/1.1 - SERVER_SOFTWARE=WEBrick/1.3.1 (Ruby/2.4.1/2017-03-22) - HTTP_HOST=192.168.64.200:31314 - HTTP_USER_AGENT=curl/7.52.1 - HTTP_ACCEPT=*/* - HTTP_X_FISSION_PARAMS_ID=123 - HTTP_X_FORWARDED_FOR=172.17.0.1 - HTTP_ACCEPT_ENCODING=gzip - rack.version=1=3 - ... - HTTP_VERSION=HTTP/1.1 - REQUEST_PATH=/ - - ---HEADERS--- - Accept: */* - Accept-Encoding: gzip - Host: 192.168.64.200:31314 - User-Agent: curl/7.52.1 - Version: HTTP/1.1 - X-Fission-Params-Id: 123 - X-Forwarded-For: 172.17.0.1 - - ---PARAMS--- - key=abc - id=123 - - --BODY-- - -``` - -## V2 Specification Example (with builder support) - -``` -$ fission function create --name parse --env ruby --src "parse/*" --entrypoint handler -$ fission fn test --name parse --body 'This is my message' - This is my message -``` diff --git a/ruby/examples/events_to_slack.rb b/ruby/examples/events_to_slack.rb deleted file mode 100644 index 861ab50c..00000000 --- a/ruby/examples/events_to_slack.rb +++ /dev/null @@ -1,33 +0,0 @@ -# frozen_string_literal: true -require 'net/http' -require 'uri' -require 'json' - -SLACK_BASE_URL = 'https://hooks.slack.com/' -SLACK_WEBHOOK_PATH = 'YOUR RELATIVE PATH HERE' # Something like "/services/XXX/YYY/zZz123" - -def send_slack_message(message) - uri = URI.join(SLACK_BASE_URL, SLACK_WEBHOOK_PATH) - data = "{'channel': '#hackdays-serverless', 'username': 'fissionbot', 'text': \"#{message}\", 'icon_emoji': ':fission:'}" - res = Net::HTTP.post_form(uri, payload: data) - res.success? -end - -def handler(context) - request = context.request - - event_type = request.headers['X-Kubernetes-Event-Type'] - object_type = request.headers['X-Kubernetes-Object-Type'] - - object = JSON.parse(request.body.read) - object_name = object.dig('metadata', 'name') - object_namespace = object.dig('metadata', 'namespace') - - message = "#{event_type} #{object_type} #{object_namespace}/#{object_name}" - - if send_slack_message(message) - "Slack message sent - #{message}" - else - Rack::Response.new(["Failed to send Slack message - #{message}"], 500).finish - end -end diff --git a/ruby/examples/hello.rb b/ruby/examples/hello.rb deleted file mode 100644 index 75e4c88a..00000000 --- a/ruby/examples/hello.rb +++ /dev/null @@ -1,4 +0,0 @@ -# frozen_string_literal: true -def handler - "Hello, world!\n" -end diff --git a/ruby/examples/parse/Gemfile b/ruby/examples/parse/Gemfile deleted file mode 100644 index 0d758433..00000000 --- a/ruby/examples/parse/Gemfile +++ /dev/null @@ -1,7 +0,0 @@ -# frozen_string_literal: true - -source "https://rubygems.org" - -git_source(:github) {|repo_name| "https://github.com/#{repo_name}" } - -gem "nokogiri", ">= 1.12.5" \ No newline at end of file diff --git a/ruby/examples/parse/Gemfile.lock b/ruby/examples/parse/Gemfile.lock deleted file mode 100644 index 74888fdd..00000000 --- a/ruby/examples/parse/Gemfile.lock +++ /dev/null @@ -1,42 +0,0 @@ -GEM - remote: https://rubygems.org/ - specs: - mini_portile2 (2.8.9) - nokogiri (1.19.3) - mini_portile2 (~> 2.8.2) - racc (~> 1.4) - nokogiri (1.19.3-aarch64-linux-gnu) - racc (~> 1.4) - nokogiri (1.19.3-aarch64-linux-musl) - racc (~> 1.4) - nokogiri (1.19.3-arm-linux-gnu) - racc (~> 1.4) - nokogiri (1.19.3-arm-linux-musl) - racc (~> 1.4) - nokogiri (1.19.3-arm64-darwin) - racc (~> 1.4) - nokogiri (1.19.3-x86_64-darwin) - racc (~> 1.4) - nokogiri (1.19.3-x86_64-linux-gnu) - racc (~> 1.4) - nokogiri (1.19.3-x86_64-linux-musl) - racc (~> 1.4) - racc (1.8.1) - -PLATFORMS - aarch64-linux-gnu - aarch64-linux-musl - arm-linux-gnu - arm-linux-musl - arm64-darwin - ruby - x86_64-darwin - x86_64-linux - x86_64-linux-gnu - x86_64-linux-musl - -DEPENDENCIES - nokogiri (>= 1.12.5) - -BUNDLED WITH - 2.6.9 diff --git a/ruby/examples/parse/parse.rb b/ruby/examples/parse/parse.rb deleted file mode 100644 index 8f999b85..00000000 --- a/ruby/examples/parse/parse.rb +++ /dev/null @@ -1,13 +0,0 @@ -# frozen_string_literal: true - -require 'nokogiri' - -def handler(context) - context.logger.info("Received request") - - doc = Nokogiri::XML(context.request.body.read) - ele = doc.at_xpath('//message') - msg = ele.nil? ? 'No Message' : ele.content - - Rack::Response.new([msg, "\n"]).finish -end \ No newline at end of file diff --git a/ruby/examples/request_data.rb b/ruby/examples/request_data.rb deleted file mode 100644 index e05cc10a..00000000 --- a/ruby/examples/request_data.rb +++ /dev/null @@ -1,20 +0,0 @@ -# frozen_string_literal: true -def handler(context) - context.logger.info("Received request") - - msg = <<~MSG - ---ENV--- - #{context.request.env.map { |h| h.join('=') }.join("\n") } - - ---HEADERS--- - #{context.request.headers.map { |h| h.join(': ') }.join("\n") } - - ---PARAMS--- - #{context.request.params.map { |h| h.join('=') }.join("\n") } - - --BODY-- - #{context.request.body.read} - MSG - - Rack::Response.new([msg]).finish -end diff --git a/rust/README.md b/rust/README.md index 474e63a9..4149f290 100644 --- a/rust/README.md +++ b/rust/README.md @@ -43,10 +43,11 @@ For anything more, use a Cargo project. Provide a source archive containing a Cargo binary crate (a `Cargo.toml` at the archive root). The only contract: the binary must serve HTTP on `127.0.0.1:$FISSION_RUNTIME_PORT`. -Any framework works — axum, actix-web, rocket, warp — see [examples/project-example](examples/project-example). +Any framework works — axum, actix-web, rocket, warp — see [rust/project-example in fission/examples](https://github.com/fission/examples/tree/main/rust/project-example). ```sh -cd examples/project-example && zip -r /tmp/project.zip Cargo.toml src +# from a clone of https://github.com/fission/examples +cd rust/project-example && zip -r /tmp/project.zip Cargo.toml src fission package create --name echo --src /tmp/project.zip --env rust ``` diff --git a/rust/examples/README.md b/rust/examples/README.md deleted file mode 100644 index e5a76663..00000000 --- a/rust/examples/README.md +++ /dev/null @@ -1,25 +0,0 @@ -# Rust function examples - -## hello.rs — single-file mode - -A function is one `.rs` file with a `pub async fn handler` using any axum handler signature. - -```sh -fission env create --name rust --image ghcr.io/fission/rust-env --builder ghcr.io/fission/rust-builder -fission package create --name hello --src hello.rs --env rust -fission fn create --name hello --env rust --pkg hello -fission fn test --name hello -``` - -## project-example — Cargo project mode - -A full Cargo binary crate; the binary serves HTTP on `127.0.0.1:$FISSION_RUNTIME_PORT`. -This example uses plain axum to echo the request body as JSON, demonstrating that any framework satisfying the port contract works. - -```sh -cd project-example && zip -r /tmp/project.zip Cargo.toml src -fission package create --name echo --src /tmp/project.zip --env rust -fission fn create --name echo --env rust --pkg echo -fission route create --name echo --function echo --url /echo --method POST -curl -X POST "http://$FISSION_ROUTER/echo" -d '{"lang":"rust"}' -``` diff --git a/rust/examples/hello.rs b/rust/examples/hello.rs deleted file mode 100644 index fa64f4a7..00000000 --- a/rust/examples/hello.rs +++ /dev/null @@ -1,7 +0,0 @@ -// Single-file Fission Rust function: define `pub async fn handler`, -// using any axum handler signature (extractors, Json, ...). -use fission_rust::IntoResponse; - -pub async fn handler() -> impl IntoResponse { - "Hello, World!\n" -} diff --git a/rust/examples/project-example/Cargo.lock b/rust/test/fixtures/project-example/Cargo.lock similarity index 100% rename from rust/examples/project-example/Cargo.lock rename to rust/test/fixtures/project-example/Cargo.lock diff --git a/rust/examples/project-example/Cargo.toml b/rust/test/fixtures/project-example/Cargo.toml similarity index 100% rename from rust/examples/project-example/Cargo.toml rename to rust/test/fixtures/project-example/Cargo.toml diff --git a/rust/examples/project-example/src/main.rs b/rust/test/fixtures/project-example/src/main.rs similarity index 100% rename from rust/examples/project-example/src/main.rs rename to rust/test/fixtures/project-example/src/main.rs diff --git a/rust/test/local_test.sh b/rust/test/local_test.sh index f2203a33..8d06d088 100755 --- a/rust/test/local_test.sh +++ b/rust/test/local_test.sh @@ -28,7 +28,7 @@ kill_processes cd "$DIR" cargo build --release -p supervisor -p fission-function -(cd examples/project-example && cargo build --release) +(cd test/fixtures/project-example && cargo build --release) wait_for_server() { for _ in $(seq 1 50); do @@ -41,7 +41,7 @@ wait_for_server() { echo "-- Phase 1: project-mode binary (echo)" mkdir -p "$TMPPATH/deploy-echo" -cp examples/project-example/target/release/echo-example "$TMPPATH/deploy-echo/handler" +cp test/fixtures/project-example/target/release/echo-example "$TMPPATH/deploy-echo/handler" ./target/release/supervisor & wait_for_server diff --git a/tensorflow-serving/examples/README.md b/tensorflow-serving/examples/README.md deleted file mode 100644 index f4c2e7de..00000000 --- a/tensorflow-serving/examples/README.md +++ /dev/null @@ -1,24 +0,0 @@ -# Tensorflow Serving Environment Example - -## Create Environment - -```bash -$ fission env create --name tensorflow --image fission/tensorflow-serving-env --version 2 -``` - -## Create Package - -```bash -$ zip -r half_plus_two.zip ./half_plus_two -$ fission pkg create --env tensorflow --deploy half_plus_two.zip -``` - -## Create Function - -Here, the `--entrypoint` represents the name of the top directory contains the trained model and what kind of API the model supports. -Currently, three API are supported: `predict`, `classify`, `regress`. `predict` API will be used if no API kind was given. - -```bash -$ fission fn create --name t1 --pkg --env tensorflow --entrypoint "half_plus_two:predict" -$ fission fn test --name t1 --body '{"instances": [1.0, 2.0, 0.0]}' --method POST -``` diff --git a/tensorflow-serving/examples/half_plus_two/00000123/saved_model.pb b/tensorflow-serving/tests/fixtures/half_plus_two/00000123/saved_model.pb similarity index 100% rename from tensorflow-serving/examples/half_plus_two/00000123/saved_model.pb rename to tensorflow-serving/tests/fixtures/half_plus_two/00000123/saved_model.pb diff --git a/tensorflow-serving/examples/half_plus_two/00000123/variables/variables.data-00000-of-00001 b/tensorflow-serving/tests/fixtures/half_plus_two/00000123/variables/variables.data-00000-of-00001 similarity index 100% rename from tensorflow-serving/examples/half_plus_two/00000123/variables/variables.data-00000-of-00001 rename to tensorflow-serving/tests/fixtures/half_plus_two/00000123/variables/variables.data-00000-of-00001 diff --git a/tensorflow-serving/examples/half_plus_two/00000123/variables/variables.index b/tensorflow-serving/tests/fixtures/half_plus_two/00000123/variables/variables.index similarity index 100% rename from tensorflow-serving/examples/half_plus_two/00000123/variables/variables.index rename to tensorflow-serving/tests/fixtures/half_plus_two/00000123/variables/variables.index diff --git a/tensorflow-serving/tests/test_tensorflow_serving_env.sh b/tensorflow-serving/tests/test_tensorflow_serving_env.sh index a225fbc5..e45d5ccc 100755 --- a/tensorflow-serving/tests/test_tensorflow_serving_env.sh +++ b/tensorflow-serving/tests/test_tensorflow_serving_env.sh @@ -26,7 +26,7 @@ env=ts-$TEST_ID fn_poolmgr=hello-ts-poolmgr-$TEST_ID fn_nd=hello-ts-nd-$TEST_ID -cd $ROOT/examples/tensorflow-serving +cd "$(dirname $0)/fixtures" log "Creating environment for Tensorflow Serving" fission env create --name $env --image $TS_RUNTIME_IMAGE --version 2 --period 5 From c2c21fc9f5440fca407cd53a7b61353a85c6233a Mon Sep 17 00:00:00 2001 From: Sanket Sudake Date: Tue, 9 Jun 2026 10:09:11 +0530 Subject: [PATCH 2/2] Fix CI: repoint e2e tests and catalog links after examples removal The first pass missed the e2e suites (test_go_env.sh, test_rust_env.sh, test_binary_env.sh, test_dotnet8_env.sh) because they `cd $ROOT//examples` without a trailing slash. They now build from vendored fixtures: - go/tests/fixtures (hello.go + module-example) - rust/tests/fixtures (hello.rs + project-example) - binary/test/fixtures (hello.sh + module-example, alongside echo.sh) - dotnet8/tests/fixtures (HelloWorld + MultiFileExample) Also repoint the `examples` URL in every envconfig.json to fission/examples (fixing two pre-existing copy-paste bugs: python-fastapi pointed at python, php7 pointed at perl) and regenerate environments.json. Co-Authored-By: Claude Opus 4.8 (1M context) --- binary/envconfig.json | 2 +- binary/test/fixtures/hello.sh | 3 + binary/test/fixtures/module-example/test.sh | 15 + binary/test/test_binary_env.sh | 2 +- dotnet/envconfig.json | 2 +- dotnet20/envconfig.json | 2 +- dotnet8/envconfig.json | 2 +- .../fixtures/HelloWorld/HelloWorld.csproj | 11 + .../tests/fixtures/HelloWorld/MyFunction.cs | 9 + .../Controllers/ApiController.cs | 129 +++++ .../MultiFileExample/Models/DataModels.cs | 43 ++ .../fixtures/MultiFileExample/Models/User.cs | 23 + .../MultiFileExample/Models/Weather.cs | 34 ++ .../MultiFileExample/MultiFileExample.csproj | 19 + .../fixtures/MultiFileExample/MyFunction.cs | 23 + .../tests/fixtures/MultiFileExample/README.md | 116 ++++ .../Services/DataProcessor.cs | 81 +++ .../MultiFileExample/Services/UserService.cs | 65 +++ .../Services/WeatherService.cs | 64 +++ dotnet8/tests/test_dotnet8_env.sh | 2 +- environments.json | 36 +- go/envconfig.json | 4 +- go/tests/fixtures/hello.go | 11 + go/tests/fixtures/module-example/go.mod | 5 + go/tests/fixtures/module-example/go.sum | 23 + go/tests/fixtures/module-example/main.go | 17 + go/tests/test_go_env.sh | 2 +- jvm-jersey/envconfig.json | 2 +- jvm/envconfig.json | 2 +- nodejs/envconfig.json | 6 +- perl/envconfig.json | 2 +- php7/envconfig.json | 2 +- python-fastapi/envconfig.json | 2 +- python/envconfig.json | 2 +- ruby/envconfig.json | 2 +- rust/envconfig.json | 2 +- rust/tests/fixtures/hello.rs | 7 + .../tests/fixtures/project-example/Cargo.lock | 497 ++++++++++++++++++ .../tests/fixtures/project-example/Cargo.toml | 19 + .../fixtures/project-example/src/main.rs | 23 + rust/tests/test_rust_env.sh | 2 +- tensorflow-serving/envconfig.json | 2 +- 42 files changed, 1277 insertions(+), 40 deletions(-) create mode 100755 binary/test/fixtures/hello.sh create mode 100755 binary/test/fixtures/module-example/test.sh create mode 100644 dotnet8/tests/fixtures/HelloWorld/HelloWorld.csproj create mode 100644 dotnet8/tests/fixtures/HelloWorld/MyFunction.cs create mode 100644 dotnet8/tests/fixtures/MultiFileExample/Controllers/ApiController.cs create mode 100644 dotnet8/tests/fixtures/MultiFileExample/Models/DataModels.cs create mode 100644 dotnet8/tests/fixtures/MultiFileExample/Models/User.cs create mode 100644 dotnet8/tests/fixtures/MultiFileExample/Models/Weather.cs create mode 100644 dotnet8/tests/fixtures/MultiFileExample/MultiFileExample.csproj create mode 100644 dotnet8/tests/fixtures/MultiFileExample/MyFunction.cs create mode 100644 dotnet8/tests/fixtures/MultiFileExample/README.md create mode 100644 dotnet8/tests/fixtures/MultiFileExample/Services/DataProcessor.cs create mode 100644 dotnet8/tests/fixtures/MultiFileExample/Services/UserService.cs create mode 100644 dotnet8/tests/fixtures/MultiFileExample/Services/WeatherService.cs create mode 100644 go/tests/fixtures/hello.go create mode 100644 go/tests/fixtures/module-example/go.mod create mode 100644 go/tests/fixtures/module-example/go.sum create mode 100644 go/tests/fixtures/module-example/main.go create mode 100644 rust/tests/fixtures/hello.rs create mode 100644 rust/tests/fixtures/project-example/Cargo.lock create mode 100644 rust/tests/fixtures/project-example/Cargo.toml create mode 100644 rust/tests/fixtures/project-example/src/main.rs diff --git a/binary/envconfig.json b/binary/envconfig.json index 77098908..50b48e8a 100644 --- a/binary/envconfig.json +++ b/binary/envconfig.json @@ -1,7 +1,7 @@ [ { "builder": "binary-builder", - "examples": "https://github.com/fission/environments/tree/master/binary/examples", + "examples": "https://github.com/fission/examples/tree/main/miscellaneous/binary", "icon": "./logo/full_colored_dark.svg", "image": "binary-env", "keywords": [], diff --git a/binary/test/fixtures/hello.sh b/binary/test/fixtures/hello.sh new file mode 100755 index 00000000..4544d792 --- /dev/null +++ b/binary/test/fixtures/hello.sh @@ -0,0 +1,3 @@ +#!/bin/bash + +echo "Hello World!" \ No newline at end of file diff --git a/binary/test/fixtures/module-example/test.sh b/binary/test/fixtures/module-example/test.sh new file mode 100755 index 00000000..1ca57d11 --- /dev/null +++ b/binary/test/fixtures/module-example/test.sh @@ -0,0 +1,15 @@ +#!/bin/sh + +num1=0 +num2=1 + +i=0 +while [ "$i" -le 10 ] +do + echo "$num1 " + sum=$((num1+num2)) + num1=$num2 + num2=$sum + i=$(( i + 1 )) +done +echo "Modules are awesome!" \ No newline at end of file diff --git a/binary/test/test_binary_env.sh b/binary/test/test_binary_env.sh index d9d88848..0ff38528 100755 --- a/binary/test/test_binary_env.sh +++ b/binary/test/test_binary_env.sh @@ -24,7 +24,7 @@ fi env=binary-$TEST_ID -cd $ROOT/binary/examples +cd $ROOT/binary/test/fixtures export BINARY_BUILDER_IMAGE=binary-builder export BINARY_RUNTIME_IMAGE=binary-env diff --git a/dotnet/envconfig.json b/dotnet/envconfig.json index c6f806b4..1a03e83f 100644 --- a/dotnet/envconfig.json +++ b/dotnet/envconfig.json @@ -1,6 +1,6 @@ [ { - "examples": "https://github.com/fission/environments/tree/master/dotnet/examples", + "examples": "https://github.com/fission/examples/tree/main/dotnet", "icon": "./logo/dotnet-logo.svg", "image": "dotnet-env", "keywords": [], diff --git a/dotnet20/envconfig.json b/dotnet20/envconfig.json index 2b63350c..732dcc3f 100644 --- a/dotnet20/envconfig.json +++ b/dotnet20/envconfig.json @@ -1,7 +1,7 @@ [ { "builder": "dotnet20-builder", - "examples": "https://github.com/fission/environments/tree/master/dotnet20/examples", + "examples": "https://github.com/fission/examples/tree/main/dotnet", "icon": "./logo/logo_NETcore.svg", "image": "dotnet20-env", "keywords": [], diff --git a/dotnet8/envconfig.json b/dotnet8/envconfig.json index 405ed70c..b236df24 100644 --- a/dotnet8/envconfig.json +++ b/dotnet8/envconfig.json @@ -1,7 +1,7 @@ [ { "builder": "dotnet8-builder", - "examples": "https://github.com/fission/environments/tree/master/dotnet8/examples", + "examples": "https://github.com/fission/examples/tree/main/dotnet8", "icon": "./logo/logo_NETcore.svg", "image": "dotnet8-env", "keywords": [], diff --git a/dotnet8/tests/fixtures/HelloWorld/HelloWorld.csproj b/dotnet8/tests/fixtures/HelloWorld/HelloWorld.csproj new file mode 100644 index 00000000..36a12871 --- /dev/null +++ b/dotnet8/tests/fixtures/HelloWorld/HelloWorld.csproj @@ -0,0 +1,11 @@ + + + Library + net8.0 + + + + ./Fission.DotNet.Common.dll + + + diff --git a/dotnet8/tests/fixtures/HelloWorld/MyFunction.cs b/dotnet8/tests/fixtures/HelloWorld/MyFunction.cs new file mode 100644 index 00000000..3b387273 --- /dev/null +++ b/dotnet8/tests/fixtures/HelloWorld/MyFunction.cs @@ -0,0 +1,9 @@ +using Fission.DotNet.Common; + +public class MyFunction +{ + public object Execute(FissionContext context) + { + return "Hello World!x"; + } +} diff --git a/dotnet8/tests/fixtures/MultiFileExample/Controllers/ApiController.cs b/dotnet8/tests/fixtures/MultiFileExample/Controllers/ApiController.cs new file mode 100644 index 00000000..579d94f0 --- /dev/null +++ b/dotnet8/tests/fixtures/MultiFileExample/Controllers/ApiController.cs @@ -0,0 +1,129 @@ +using System; +using System.Threading.Tasks; +using MultiFileExample.Services; +using MultiFileExample.Models; +using Fission.DotNet.Common; + +namespace MultiFileExample.Controllers +{ + public class ApiController + { + private readonly WeatherService _weatherService; + private readonly UserService _userService; + private readonly DataProcessor _dataProcessor; + + public ApiController() + { + // In production, use dependency injection + _weatherService = new WeatherService(); + _userService = new UserService(); + _dataProcessor = new DataProcessor(); + } + + public async Task RouteRequest(FissionContext context) + { + var path = ExtractPath(context); + var method = ExtractMethod(context); + + // Route to appropriate handler based on path + return path.ToLower() switch + { + "" or "multifile" => GetApiInfo(), + "weather" => await _weatherService.GetWeatherAsync(), + "weather/forecast" => await _weatherService.GetForecastAsync(), + "users" => _userService.GetAllUsers(), + "users/active" => _userService.GetActiveUsers(), + "process" => _dataProcessor.ProcessData(new DataRequest { Input = "test-data" }), + "health" => GetHealthStatus(), + _ => GetNotFoundResponse(path) + }; + } + + private string ExtractPath(FissionContext context) + { + // Try to get path from HTTP context + if (context is FissionHttpContext httpContext) + { + return httpContext.Url?.TrimStart('/') ?? ""; + } + + // Fallback to subpath argument for testing + if (context?.Arguments?.ContainsKey("subpath") == true) + { + return context.Arguments["subpath"]?.ToString() ?? ""; + } + + return ""; + } + + private string ExtractMethod(FissionContext context) + { + if (context is FissionHttpContext httpContext) + { + return httpContext.Method?.ToUpper() ?? "GET"; + } + return "GET"; + } + + private object GetApiInfo() + { + return new + { + name = "Multi-File Example API", + description = "MVC-pattern Fission function with controller-based routing", + version = "2.0.0", + architecture = new + { + pattern = "MVC", + entryPoint = "MyFunction.cs", + controller = "ApiController.cs", + services = new[] { "WeatherService.cs", "UserService.cs", "DataProcessor.cs" }, + models = new[] { "User.cs", "Weather.cs", "DataModels.cs" } + }, + endpoints = GetAvailableEndpoints() + }; + } + + private object GetHealthStatus() + { + return new + { + status = "healthy", + service = "MultiFileExample", + version = "2.0.0", + timestamp = DateTime.UtcNow, + components = new + { + weatherService = "operational", + userService = "operational", + dataProcessor = "operational" + } + }; + } + + private object GetNotFoundResponse(string path) + { + return new + { + error = "Endpoint not found", + path = path, + statusCode = 404, + availableEndpoints = GetAvailableEndpoints() + }; + } + + private string[] GetAvailableEndpoints() + { + return new[] + { + "/ - API information", + "/weather - Current weather", + "/weather/forecast - 5-day forecast", + "/users - List all users", + "/users/active - List active users", + "/process - Data processing demo", + "/health - Health check" + }; + } + } +} \ No newline at end of file diff --git a/dotnet8/tests/fixtures/MultiFileExample/Models/DataModels.cs b/dotnet8/tests/fixtures/MultiFileExample/Models/DataModels.cs new file mode 100644 index 00000000..464dc61b --- /dev/null +++ b/dotnet8/tests/fixtures/MultiFileExample/Models/DataModels.cs @@ -0,0 +1,43 @@ +using System; + +namespace MultiFileExample.Models +{ + public class DataRequest + { + public string Input { get; set; } + public string Format { get; set; } + public bool Validate { get; set; } + } + + public class ProcessedData + { + public string Original { get; set; } + public string Uppercase { get; set; } + public string Lowercase { get; set; } + public string Reversed { get; set; } + public int Length { get; set; } + public int WordCount { get; set; } + public string Hash { get; set; } + public string Base64Encoded { get; set; } + } + + public class ProcessingStats + { + public int CharacterCount { get; set; } + public int AlphaCount { get; set; } + public int DigitCount { get; set; } + public int SpaceCount { get; set; } + public int SpecialCharCount { get; set; } + } + + public class DataResponse + { + public bool Success { get; set; } + public string Error { get; set; } + public ProcessedData ProcessedData { get; set; } + public ProcessingStats Statistics { get; set; } + public DateTime ProcessedAt { get; set; } + public string ProcessingTime { get; set; } + public string Source { get; set; } + } +} \ No newline at end of file diff --git a/dotnet8/tests/fixtures/MultiFileExample/Models/User.cs b/dotnet8/tests/fixtures/MultiFileExample/Models/User.cs new file mode 100644 index 00000000..e3e9123a --- /dev/null +++ b/dotnet8/tests/fixtures/MultiFileExample/Models/User.cs @@ -0,0 +1,23 @@ +using System; +using System.Collections.Generic; + +namespace MultiFileExample.Models +{ + public class User + { + public int Id { get; set; } + public string Name { get; set; } + public string Email { get; set; } + public bool IsActive { get; set; } + public DateTime CreatedAt { get; set; } + } + + public class UserListResponse + { + public List Users { get; set; } + public int Total { get; set; } + public string FilteredBy { get; set; } + public DateTime Timestamp { get; set; } + public string Source { get; set; } + } +} \ No newline at end of file diff --git a/dotnet8/tests/fixtures/MultiFileExample/Models/Weather.cs b/dotnet8/tests/fixtures/MultiFileExample/Models/Weather.cs new file mode 100644 index 00000000..3fd7c486 --- /dev/null +++ b/dotnet8/tests/fixtures/MultiFileExample/Models/Weather.cs @@ -0,0 +1,34 @@ +using System; +using System.Collections.Generic; + +namespace MultiFileExample.Models +{ + public class WeatherResponse + { + public string City { get; set; } + public int Temperature { get; set; } + public string Condition { get; set; } + public int Humidity { get; set; } + public int WindSpeed { get; set; } + public DateTime Timestamp { get; set; } + public string Source { get; set; } + } + + public class DailyForecast + { + public DateTime Date { get; set; } + public int High { get; set; } + public int Low { get; set; } + public string Condition { get; set; } + public int ChanceOfRain { get; set; } + } + + public class ForecastResponse + { + public string City { get; set; } + public int Days { get; set; } + public List Forecasts { get; set; } + public DateTime GeneratedAt { get; set; } + public string Source { get; set; } + } +} \ No newline at end of file diff --git a/dotnet8/tests/fixtures/MultiFileExample/MultiFileExample.csproj b/dotnet8/tests/fixtures/MultiFileExample/MultiFileExample.csproj new file mode 100644 index 00000000..796cb33c --- /dev/null +++ b/dotnet8/tests/fixtures/MultiFileExample/MultiFileExample.csproj @@ -0,0 +1,19 @@ + + + Library + net8.0 + MultiFileExample + MultiFileExample + true + + + + + ./Fission.DotNet.Common.dll + + + + + + + \ No newline at end of file diff --git a/dotnet8/tests/fixtures/MultiFileExample/MyFunction.cs b/dotnet8/tests/fixtures/MultiFileExample/MyFunction.cs new file mode 100644 index 00000000..ce325ca2 --- /dev/null +++ b/dotnet8/tests/fixtures/MultiFileExample/MyFunction.cs @@ -0,0 +1,23 @@ +using Fission.DotNet.Common; +using System.Threading.Tasks; +using MultiFileExample.Controllers; + +namespace MultiFileExample +{ + + public class MyFunction + { + private readonly ApiController _controller; + + public MyFunction() + { + _controller = new ApiController(); + } + + public async Task Execute(FissionContext context) + { + // Delegate all routing and business logic to the controller + return await _controller.RouteRequest(context); + } + } +} \ No newline at end of file diff --git a/dotnet8/tests/fixtures/MultiFileExample/README.md b/dotnet8/tests/fixtures/MultiFileExample/README.md new file mode 100644 index 00000000..a04206b8 --- /dev/null +++ b/dotnet8/tests/fixtures/MultiFileExample/README.md @@ -0,0 +1,116 @@ +# Multi-File Example for Fission .NET 8 + +This example demonstrates how to organize a Fission function across multiple files using proper .NET project structure with services, models, and separation of concerns. + +## Project Structure + +``` +MultiFileExample/ +├── MyFunction.cs # Thin Fission entry point (delegates to controller) +├── MultiFileExample.csproj # Project file +├── Controllers/ # MVC Controllers +│ └── ApiController.cs # Main controller handling routing and orchestration +├── Services/ # Business logic layer +│ ├── WeatherService.cs # Weather-related operations +│ ├── UserService.cs # User management +│ └── DataProcessor.cs # Data processing utilities +└── Models/ # Data models + ├── User.cs # User models + ├── Weather.cs # Weather models + └── DataModels.cs # Data processing models +``` + + +## Deploy to Fission + +```bash +# Create environment (if not already created) +fission env create --name dotnet8 \ + --image fission/dotnet8-env \ + --builder fission/dotnet8-builder \ + --poolsize 1 + +# Create package with all source files +cd /dotnet8/examples/MultiFileExample +fission pkg create --name multifile-pkg \ + --env dotnet8 \ + --src . \ + --buildcmd "/usr/local/bin/build" + +# Wait for build to complete +fission pkg list + +# Create function +fission fn create --name multifile-fn \ + --pkg multifile-pkg \ + --env dotnet8 \ + --entrypoint "MultiFileExample.MyFunction" + +# Create HTTP route +fission route create --name multifile-route \ + --function multifile-fn \ + --url "/multifile/*" \ + --method GET POST + +# Test the function +fission fn test --name multifile-fn +``` + +## Available Endpoints + +```bash +# Port forward to access locally +kubectl port-forward -n fission service/router 8080:80 & + +# API Information +curl http://localhost:8080/fission-function/multifile-fn/ + +# Weather Service endpoints +curl http://localhost:8080/fission-function/multifile-fn/weather +curl http://localhost:8080/fission-function/multifile-fn/weather/forecast + +# User Service endpoints +curl http://localhost:8080/fission-function/multifile-fn/users +curl http://localhost:8080/fission-function/multifile-fn/users/active + +# Data Processing endpoint +curl http://localhost:8080/fission-function/multifile-fn/process + +# Health check +curl http://localhost:8080/fission-function/multifile-fn/health +``` + +## How It Works + +1. **Entry Point**: `MyFunction.cs` implements the Fission function interface (thin wrapper) +2. **Controller**: `ApiController.cs` handles all routing and orchestration +3. **Dependency Injection**: Services are instantiated in the controller's constructor +4. **Routing**: Controller routes requests to appropriate services based on path +5. **Services**: Each service encapsulates related business logic +6. **Models**: Shared data structures used across services + + +## Adding New Features + +To add a new service: + +1. Create a new service file in `Services/` directory +2. Create models in `Models/` directory +3. Add routing in `MyFunction.cs` +4. Rebuild and redeploy the package + +Example: +```csharp +// Services/OrderService.cs +namespace MultiFileExample.Services +{ + public class OrderService + { + public object GetOrders() { /* ... */ } + } +} + +// In MyFunction.cs +private readonly OrderService _orderService = new OrderService(); +// Add to switch: "orders" => _orderService.GetOrders() +``` \ No newline at end of file diff --git a/dotnet8/tests/fixtures/MultiFileExample/Services/DataProcessor.cs b/dotnet8/tests/fixtures/MultiFileExample/Services/DataProcessor.cs new file mode 100644 index 00000000..fbadc8c8 --- /dev/null +++ b/dotnet8/tests/fixtures/MultiFileExample/Services/DataProcessor.cs @@ -0,0 +1,81 @@ +using System; +using System.Linq; +using System.Text; +using MultiFileExample.Models; + +namespace MultiFileExample.Services +{ + public class DataProcessor + { + public DataResponse ProcessData(DataRequest request) + { + if (request == null || string.IsNullOrEmpty(request.Input)) + { + return new DataResponse + { + Success = false, + Error = "Input data is required", + ProcessedAt = DateTime.UtcNow + }; + } + + // Simulate various data processing operations + var processed = new ProcessedData + { + Original = request.Input, + Uppercase = request.Input.ToUpper(), + Lowercase = request.Input.ToLower(), + Reversed = new string(request.Input.Reverse().ToArray()), + Length = request.Input.Length, + WordCount = request.Input.Split(' ', StringSplitOptions.RemoveEmptyEntries).Length, + Hash = ComputeSimpleHash(request.Input), + Base64Encoded = Convert.ToBase64String(Encoding.UTF8.GetBytes(request.Input)) + }; + + // Calculate some statistics + var stats = new ProcessingStats + { + CharacterCount = request.Input.Length, + AlphaCount = request.Input.Count(char.IsLetter), + DigitCount = request.Input.Count(char.IsDigit), + SpaceCount = request.Input.Count(char.IsWhiteSpace), + SpecialCharCount = request.Input.Count(c => !char.IsLetterOrDigit(c) && !char.IsWhiteSpace(c)) + }; + + return new DataResponse + { + Success = true, + ProcessedData = processed, + Statistics = stats, + ProcessedAt = DateTime.UtcNow, + ProcessingTime = "< 1ms", + Source = "DataProcessor.cs" + }; + } + + private string ComputeSimpleHash(string input) + { + // Simple hash for demonstration + int hash = 0; + foreach (char c in input) + { + hash = ((hash << 5) - hash) + c; + } + return Math.Abs(hash).ToString("X8"); + } + + public object AnalyzeData(string data) + { + if (string.IsNullOrEmpty(data)) + return new { error = "No data provided" }; + + return new + { + analysis = "Complete", + dataPoints = data.Length, + checksum = ComputeSimpleHash(data), + timestamp = DateTime.UtcNow + }; + } + } +} \ No newline at end of file diff --git a/dotnet8/tests/fixtures/MultiFileExample/Services/UserService.cs b/dotnet8/tests/fixtures/MultiFileExample/Services/UserService.cs new file mode 100644 index 00000000..255396b5 --- /dev/null +++ b/dotnet8/tests/fixtures/MultiFileExample/Services/UserService.cs @@ -0,0 +1,65 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using MultiFileExample.Models; + +namespace MultiFileExample.Services +{ + public class UserService + { + private readonly List _users; + + public UserService() + { + // Initialize with sample data + _users = new List + { + new User { Id = 1, Name = "Alice Johnson", Email = "alice@example.com", IsActive = true, CreatedAt = DateTime.UtcNow.AddDays(-30) }, + new User { Id = 2, Name = "Bob Smith", Email = "bob@example.com", IsActive = true, CreatedAt = DateTime.UtcNow.AddDays(-25) }, + new User { Id = 3, Name = "Charlie Brown", Email = "charlie@example.com", IsActive = false, CreatedAt = DateTime.UtcNow.AddDays(-20) }, + new User { Id = 4, Name = "Diana Prince", Email = "diana@example.com", IsActive = true, CreatedAt = DateTime.UtcNow.AddDays(-15) }, + new User { Id = 5, Name = "Edward Norton", Email = "edward@example.com", IsActive = false, CreatedAt = DateTime.UtcNow.AddDays(-10) } + }; + } + + public UserListResponse GetAllUsers() + { + return new UserListResponse + { + Users = _users, + Total = _users.Count, + Timestamp = DateTime.UtcNow, + Source = "UserService.cs" + }; + } + + public UserListResponse GetActiveUsers() + { + var activeUsers = _users.Where(u => u.IsActive).ToList(); + + return new UserListResponse + { + Users = activeUsers, + Total = activeUsers.Count, + FilteredBy = "IsActive = true", + Timestamp = DateTime.UtcNow, + Source = "UserService.cs" + }; + } + + public User GetUserById(int id) + { + return _users.FirstOrDefault(u => u.Id == id); + } + + public bool AddUser(User user) + { + if (user == null || _users.Any(u => u.Id == user.Id)) + return false; + + user.CreatedAt = DateTime.UtcNow; + _users.Add(user); + return true; + } + } +} \ No newline at end of file diff --git a/dotnet8/tests/fixtures/MultiFileExample/Services/WeatherService.cs b/dotnet8/tests/fixtures/MultiFileExample/Services/WeatherService.cs new file mode 100644 index 00000000..efc350c5 --- /dev/null +++ b/dotnet8/tests/fixtures/MultiFileExample/Services/WeatherService.cs @@ -0,0 +1,64 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Threading.Tasks; +using MultiFileExample.Models; + +namespace MultiFileExample.Services +{ + public class WeatherService + { + private readonly Random _random = new Random(); + private readonly string[] _conditions = { "Sunny", "Cloudy", "Rainy", "Stormy", "Snowy", "Foggy", "Clear" }; + private readonly string[] _cities = { "New York", "London", "Tokyo", "Paris", "Sydney", "Toronto", "Berlin" }; + + public async Task GetWeatherAsync() + { + // Simulate async operation + await Task.Delay(10); + + var city = _cities[_random.Next(_cities.Length)]; + + return new WeatherResponse + { + City = city, + Temperature = _random.Next(-10, 35), + Condition = _conditions[_random.Next(_conditions.Length)], + Humidity = _random.Next(30, 95), + WindSpeed = _random.Next(0, 50), + Timestamp = DateTime.UtcNow, + Source = "WeatherService.cs" + }; + } + + public async Task GetForecastAsync() + { + // Simulate async operation + await Task.Delay(10); + + var city = _cities[_random.Next(_cities.Length)]; + var forecasts = new List(); + + for (int i = 0; i < 5; i++) + { + forecasts.Add(new DailyForecast + { + Date = DateTime.UtcNow.AddDays(i), + High = _random.Next(10, 35), + Low = _random.Next(-5, 15), + Condition = _conditions[_random.Next(_conditions.Length)], + ChanceOfRain = _random.Next(0, 100) + }); + } + + return new ForecastResponse + { + City = city, + Days = 5, + Forecasts = forecasts, + GeneratedAt = DateTime.UtcNow, + Source = "WeatherService.cs" + }; + } + } +} \ No newline at end of file diff --git a/dotnet8/tests/test_dotnet8_env.sh b/dotnet8/tests/test_dotnet8_env.sh index f5de0532..7854978c 100755 --- a/dotnet8/tests/test_dotnet8_env.sh +++ b/dotnet8/tests/test_dotnet8_env.sh @@ -26,7 +26,7 @@ env=dotnet8-$TEST_ID fn_poolmgr=hello-dotnet8-pm-$TEST_ID fn_nd=hello-dotnet8-nd-$TEST_ID -cd $ROOT/dotnet8/examples +cd $ROOT/dotnet8/tests/fixtures DOTNET8_BUILDER_IMAGE=${DOTNET8_BUILDER_IMAGE:-davidchase03/dotnet8-builder:v21.1} DOTNET8_RUNTIME_IMAGE=${DOTNET8_RUNTIME_IMAGE:-davidchase03/dotnet8-env:v21.0} diff --git a/environments.json b/environments.json index f73a520a..f94c9f8f 100644 --- a/environments.json +++ b/environments.json @@ -1,7 +1,7 @@ [ [ { - "examples": "https://github.com/fission/environments/tree/master/nodejs/examples", + "examples": "https://github.com/fission/examples/tree/main/nodejs", "icon": "./logo/nodejs-new-pantone-black.svg", "image": "node-env-debian", "keywords": [], @@ -25,7 +25,7 @@ }, { "builder": "node-builder-22", - "examples": "https://github.com/fission/environments/tree/master/nodejs/examples", + "examples": "https://github.com/fission/examples/tree/main/nodejs", "icon": "./logo/nodejs-new-pantone-black.svg", "image": "node-env-22", "keywords": [], @@ -49,7 +49,7 @@ }, { "builder": "node-builder", - "examples": "https://github.com/fission/environments/tree/master/nodejs/examples", + "examples": "https://github.com/fission/examples/tree/main/nodejs", "icon": "./logo/nodejs-new-pantone-black.svg", "image": "node-env", "keywords": [], @@ -76,7 +76,7 @@ [ { "builder": "go-builder", - "examples": "https://github.com/fission/environments/tree/master/go/examples", + "examples": "https://github.com/fission/examples/tree/main/go", "icon": "./logo/go-logo-blue.svg", "image": "go-env", "kind": "environment", @@ -99,7 +99,7 @@ }, { "builder": "go-builder-1.26", - "examples": "https://github.com/fission/environments/tree/master/go/examples", + "examples": "https://github.com/fission/examples/tree/main/go", "icon": "./logo/go-logo-blue.svg", "image": "go-env-1.26", "kind": "environment", @@ -125,7 +125,7 @@ [ { "builder": "python-fastapi-builder", - "examples": "https://github.com/fission/environments/tree/master/python/examples", + "examples": "https://github.com/fission/examples/tree/main/python-fastapi", "icon": "./logo/Python-logo-notext.png", "image": "python-fastapi-env", "keywords": [], @@ -152,7 +152,7 @@ [ { "builder": "python-builder", - "examples": "https://github.com/fission/environments/tree/master/python/examples", + "examples": "https://github.com/fission/examples/tree/main/python", "icon": "./logo/Python-logo-notext.png", "image": "python-env", "keywords": [], @@ -178,7 +178,7 @@ , [ { - "examples": "https://github.com/fission/environments/tree/master/perl/examples", + "examples": "https://github.com/fission/examples/tree/main/perl", "icon": "./logo/perl-programming-language.svg", "image": "perl-env", "keywords": [], @@ -209,7 +209,7 @@ [ { "builder": "rust-builder", - "examples": "https://github.com/fission/environments/tree/master/rust/examples", + "examples": "https://github.com/fission/examples/tree/main/rust", "icon": "./logo/rust-logo.svg", "image": "rust-env", "keywords": [ @@ -236,7 +236,7 @@ [ { "builder": "jvm-builder", - "examples": "https://github.com/fission/environments/tree/master/jvm/examples", + "examples": "https://github.com/fission/examples/tree/main/java", "icon": "./logo/Java-Logo.png", "image": "jvm-env", "keywords": [], @@ -267,7 +267,7 @@ [ { "builder": "php-builder", - "examples": "https://github.com/fission/environments/tree/master/perl/examples", + "examples": "https://github.com/fission/examples/tree/main/php7", "icon": "./logo/new-php-logo.svg", "image": "php-env", "keywords": [], @@ -297,7 +297,7 @@ , [ { - "examples": "https://github.com/fission/environments/tree/master/dotnet/examples", + "examples": "https://github.com/fission/examples/tree/main/dotnet", "icon": "./logo/dotnet-logo.svg", "image": "dotnet-env", "keywords": [], @@ -328,7 +328,7 @@ [ { "builder": "jvm-jersey-builder-25", - "examples": "https://github.com/fission/environments/tree/master/jvm-jersey/examples", + "examples": "https://github.com/fission/examples/tree/main/java", "icon": "./logo/Java-Logo.png", "image": "jvm-jersey-env-25", "keywords": [], @@ -359,7 +359,7 @@ [ { "builder": "binary-builder", - "examples": "https://github.com/fission/environments/tree/master/binary/examples", + "examples": "https://github.com/fission/examples/tree/main/miscellaneous/binary", "icon": "./logo/full_colored_dark.svg", "image": "binary-env", "keywords": [], @@ -385,7 +385,7 @@ , [ { - "examples": "https://github.com/fission/environments/tree/master/tensorflow-serving/examples", + "examples": "https://github.com/fission/examples/tree/main/miscellaneous/tensorflow-serving", "icon": "./logo/Tensorflow_logo.svg", "image": "tensorflow-serving-env", "keywords": [], @@ -416,7 +416,7 @@ [ { "builder": "dotnet20-builder", - "examples": "https://github.com/fission/environments/tree/master/dotnet20/examples", + "examples": "https://github.com/fission/examples/tree/main/dotnet", "icon": "./logo/logo_NETcore.svg", "image": "dotnet20-env", "keywords": [], @@ -447,7 +447,7 @@ [ { "builder": "dotnet8-builder", - "examples": "https://github.com/fission/environments/tree/master/dotnet8/examples", + "examples": "https://github.com/fission/examples/tree/main/dotnet8", "icon": "./logo/logo_NETcore.svg", "image": "dotnet8-env", "keywords": [], @@ -470,7 +470,7 @@ [ { "builder": "ruby-builder", - "examples": "https://github.com/fission/environments/tree/master/ruby/examples", + "examples": "https://github.com/fission/examples/tree/main/ruby", "icon": "./logo/Ruby_logo.svg", "image": "ruby-env", "keywords": [], diff --git a/go/envconfig.json b/go/envconfig.json index 7d2d58f4..44b693e5 100644 --- a/go/envconfig.json +++ b/go/envconfig.json @@ -1,7 +1,7 @@ [ { "builder": "go-builder", - "examples": "https://github.com/fission/environments/tree/master/go/examples", + "examples": "https://github.com/fission/examples/tree/main/go", "icon": "./logo/go-logo-blue.svg", "image": "go-env", "kind": "environment", @@ -24,7 +24,7 @@ }, { "builder": "go-builder-1.26", - "examples": "https://github.com/fission/environments/tree/master/go/examples", + "examples": "https://github.com/fission/examples/tree/main/go", "icon": "./logo/go-logo-blue.svg", "image": "go-env-1.26", "kind": "environment", diff --git a/go/tests/fixtures/hello.go b/go/tests/fixtures/hello.go new file mode 100644 index 00000000..88c004fe --- /dev/null +++ b/go/tests/fixtures/hello.go @@ -0,0 +1,11 @@ +package main + +import ( + "net/http" +) + +// Handler is the entry point for this fission function +func Handler(w http.ResponseWriter, r *http.Request) { + msg := "Hello, world!\n" + w.Write([]byte(msg)) +} diff --git a/go/tests/fixtures/module-example/go.mod b/go/tests/fixtures/module-example/go.mod new file mode 100644 index 00000000..8fd9f683 --- /dev/null +++ b/go/tests/fixtures/module-example/go.mod @@ -0,0 +1,5 @@ +module github.com/fission/environments/go/examples/module-example + +go 1.25 + +require golang.org/x/example v0.0.0-20210811190340-787a929d5a0d diff --git a/go/tests/fixtures/module-example/go.sum b/go/tests/fixtures/module-example/go.sum new file mode 100644 index 00000000..e5eaf196 --- /dev/null +++ b/go/tests/fixtures/module-example/go.sum @@ -0,0 +1,23 @@ +github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= +golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= +golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= +golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= +golang.org/x/example v0.0.0-20210811190340-787a929d5a0d h1:VYLNvPLNayyBk9XOnsTk5jh7vZarEfiJe7/S15vri2g= +golang.org/x/example v0.0.0-20210811190340-787a929d5a0d/go.mod h1:+yakPl5KR9J+ysfUNADYwEU5qeqjUO473wDktD4xMYw= +golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= +golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= +golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= +golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= +golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= +golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20210112183307-1e6ecd4bf1b0/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= +golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= diff --git a/go/tests/fixtures/module-example/main.go b/go/tests/fixtures/module-example/main.go new file mode 100644 index 00000000..feadefa6 --- /dev/null +++ b/go/tests/fixtures/module-example/main.go @@ -0,0 +1,17 @@ +package main + +import ( + "log" + "net/http" + + "golang.org/x/example/stringutil" +) + +// Handler is the entry point for this fission function +func Handler(w http.ResponseWriter, r *http.Request) { + msg := stringutil.Reverse(stringutil.Reverse("Vendor Example Test")) + _, err := w.Write([]byte(msg)) + if err != nil { + log.Printf("Error writing response: %v", err) + } +} diff --git a/go/tests/test_go_env.sh b/go/tests/test_go_env.sh index a509c6c8..b3ab34b3 100755 --- a/go/tests/test_go_env.sh +++ b/go/tests/test_go_env.sh @@ -26,7 +26,7 @@ env=go-$TEST_ID fn_poolmgr=hello-go-poolmgr-$TEST_ID fn_nd=hello-go-nd-$TEST_ID -cd $ROOT/go/examples +cd $ROOT/go/tests/fixtures export GO_BUILDER_IMAGE=go-builder export GO_RUNTIME_IMAGE=go-env diff --git a/jvm-jersey/envconfig.json b/jvm-jersey/envconfig.json index 122c8998..159ab16d 100644 --- a/jvm-jersey/envconfig.json +++ b/jvm-jersey/envconfig.json @@ -1,7 +1,7 @@ [ { "builder": "jvm-jersey-builder-25", - "examples": "https://github.com/fission/environments/tree/master/jvm-jersey/examples", + "examples": "https://github.com/fission/examples/tree/main/java", "icon": "./logo/Java-Logo.png", "image": "jvm-jersey-env-25", "keywords": [], diff --git a/jvm/envconfig.json b/jvm/envconfig.json index a2546091..d66cf0b8 100644 --- a/jvm/envconfig.json +++ b/jvm/envconfig.json @@ -1,7 +1,7 @@ [ { "builder": "jvm-builder", - "examples": "https://github.com/fission/environments/tree/master/jvm/examples", + "examples": "https://github.com/fission/examples/tree/main/java", "icon": "./logo/Java-Logo.png", "image": "jvm-env", "keywords": [], diff --git a/nodejs/envconfig.json b/nodejs/envconfig.json index 06b97674..14692f8d 100644 --- a/nodejs/envconfig.json +++ b/nodejs/envconfig.json @@ -1,6 +1,6 @@ [ { - "examples": "https://github.com/fission/environments/tree/master/nodejs/examples", + "examples": "https://github.com/fission/examples/tree/main/nodejs", "icon": "./logo/nodejs-new-pantone-black.svg", "image": "node-env-debian", "keywords": [], @@ -24,7 +24,7 @@ }, { "builder": "node-builder-22", - "examples": "https://github.com/fission/environments/tree/master/nodejs/examples", + "examples": "https://github.com/fission/examples/tree/main/nodejs", "icon": "./logo/nodejs-new-pantone-black.svg", "image": "node-env-22", "keywords": [], @@ -48,7 +48,7 @@ }, { "builder": "node-builder", - "examples": "https://github.com/fission/environments/tree/master/nodejs/examples", + "examples": "https://github.com/fission/examples/tree/main/nodejs", "icon": "./logo/nodejs-new-pantone-black.svg", "image": "node-env", "keywords": [], diff --git a/perl/envconfig.json b/perl/envconfig.json index 4a77ffae..a99d43ee 100644 --- a/perl/envconfig.json +++ b/perl/envconfig.json @@ -1,6 +1,6 @@ [ { - "examples": "https://github.com/fission/environments/tree/master/perl/examples", + "examples": "https://github.com/fission/examples/tree/main/perl", "icon": "./logo/perl-programming-language.svg", "image": "perl-env", "keywords": [], diff --git a/php7/envconfig.json b/php7/envconfig.json index 11669c8d..2d05f86c 100644 --- a/php7/envconfig.json +++ b/php7/envconfig.json @@ -1,7 +1,7 @@ [ { "builder": "php-builder", - "examples": "https://github.com/fission/environments/tree/master/perl/examples", + "examples": "https://github.com/fission/examples/tree/main/php7", "icon": "./logo/new-php-logo.svg", "image": "php-env", "keywords": [], diff --git a/python-fastapi/envconfig.json b/python-fastapi/envconfig.json index 6cd28918..012ea8b8 100644 --- a/python-fastapi/envconfig.json +++ b/python-fastapi/envconfig.json @@ -1,7 +1,7 @@ [ { "builder": "python-fastapi-builder", - "examples": "https://github.com/fission/environments/tree/master/python/examples", + "examples": "https://github.com/fission/examples/tree/main/python-fastapi", "icon": "./logo/Python-logo-notext.png", "image": "python-fastapi-env", "keywords": [], diff --git a/python/envconfig.json b/python/envconfig.json index 04dbf1e5..dfeba2e4 100644 --- a/python/envconfig.json +++ b/python/envconfig.json @@ -1,7 +1,7 @@ [ { "builder": "python-builder", - "examples": "https://github.com/fission/environments/tree/master/python/examples", + "examples": "https://github.com/fission/examples/tree/main/python", "icon": "./logo/Python-logo-notext.png", "image": "python-env", "keywords": [], diff --git a/ruby/envconfig.json b/ruby/envconfig.json index a8bb2341..c2bd5629 100644 --- a/ruby/envconfig.json +++ b/ruby/envconfig.json @@ -1,7 +1,7 @@ [ { "builder": "ruby-builder", - "examples": "https://github.com/fission/environments/tree/master/ruby/examples", + "examples": "https://github.com/fission/examples/tree/main/ruby", "icon": "./logo/Ruby_logo.svg", "image": "ruby-env", "keywords": [], diff --git a/rust/envconfig.json b/rust/envconfig.json index c67b4dee..6d7b32f0 100644 --- a/rust/envconfig.json +++ b/rust/envconfig.json @@ -1,7 +1,7 @@ [ { "builder": "rust-builder", - "examples": "https://github.com/fission/environments/tree/master/rust/examples", + "examples": "https://github.com/fission/examples/tree/main/rust", "icon": "./logo/rust-logo.svg", "image": "rust-env", "keywords": [ diff --git a/rust/tests/fixtures/hello.rs b/rust/tests/fixtures/hello.rs new file mode 100644 index 00000000..fa64f4a7 --- /dev/null +++ b/rust/tests/fixtures/hello.rs @@ -0,0 +1,7 @@ +// Single-file Fission Rust function: define `pub async fn handler`, +// using any axum handler signature (extractors, Json, ...). +use fission_rust::IntoResponse; + +pub async fn handler() -> impl IntoResponse { + "Hello, World!\n" +} diff --git a/rust/tests/fixtures/project-example/Cargo.lock b/rust/tests/fixtures/project-example/Cargo.lock new file mode 100644 index 00000000..a4b9083b --- /dev/null +++ b/rust/tests/fixtures/project-example/Cargo.lock @@ -0,0 +1,497 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 4 + +[[package]] +name = "atomic-waker" +version = "1.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1505bd5d3d116872e7271a6d4e16d81d0c8570876c8de68093a09ac269d8aac0" + +[[package]] +name = "axum" +version = "0.8.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "31b698c5f9a010f6573133b09e0de5408834d0c82f8d7475a89fc1867a71cd90" +dependencies = [ + "axum-core", + "bytes", + "form_urlencoded", + "futures-util", + "http", + "http-body", + "http-body-util", + "hyper", + "hyper-util", + "itoa", + "matchit", + "memchr", + "mime", + "percent-encoding", + "pin-project-lite", + "serde_core", + "serde_json", + "serde_path_to_error", + "serde_urlencoded", + "sync_wrapper", + "tokio", + "tower", + "tower-layer", + "tower-service", + "tracing", +] + +[[package]] +name = "axum-core" +version = "0.5.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "08c78f31d7b1291f7ee735c1c6780ccde7785daae9a9206026862dab7d8792d1" +dependencies = [ + "bytes", + "futures-core", + "http", + "http-body", + "http-body-util", + "mime", + "pin-project-lite", + "sync_wrapper", + "tower-layer", + "tower-service", + "tracing", +] + +[[package]] +name = "bytes" +version = "1.11.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1e748733b7cbc798e1434b6ac524f0c1ff2ab456fe201501e6497c8417a4fc33" + +[[package]] +name = "echo-example" +version = "0.1.0" +dependencies = [ + "axum", + "serde_json", + "tokio", +] + +[[package]] +name = "form_urlencoded" +version = "1.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cb4cb245038516f5f85277875cdaa4f7d2c9a0fa0468de06ed190163b1581fcf" +dependencies = [ + "percent-encoding", +] + +[[package]] +name = "futures-channel" +version = "0.3.32" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "07bbe89c50d7a535e539b8c17bc0b49bdb77747034daa8087407d655f3f7cc1d" +dependencies = [ + "futures-core", +] + +[[package]] +name = "futures-core" +version = "0.3.32" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7e3450815272ef58cec6d564423f6e755e25379b217b0bc688e295ba24df6b1d" + +[[package]] +name = "futures-task" +version = "0.3.32" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "037711b3d59c33004d3856fbdc83b99d4ff37a24768fa1be9ce3538a1cde4393" + +[[package]] +name = "futures-util" +version = "0.3.32" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "389ca41296e6190b48053de0321d02a77f32f8a5d2461dd38762c0593805c6d6" +dependencies = [ + "futures-core", + "futures-task", + "pin-project-lite", + "slab", +] + +[[package]] +name = "http" +version = "1.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8be7462df143984c4598a256ef469b251d7d7f9e271135073e78fc535414f3d0" +dependencies = [ + "bytes", + "itoa", +] + +[[package]] +name = "http-body" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1efedce1fb8e6913f23e0c92de8e62cd5b772a67e7b3946df930a62566c93184" +dependencies = [ + "bytes", + "http", +] + +[[package]] +name = "http-body-util" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b021d93e26becf5dc7e1b75b1bed1fd93124b374ceb73f43d4d4eafec896a64a" +dependencies = [ + "bytes", + "futures-core", + "http", + "http-body", + "pin-project-lite", +] + +[[package]] +name = "httparse" +version = "1.10.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6dbf3de79e51f3d586ab4cb9d5c3e2c14aa28ed23d180cf89b4df0454a69cc87" + +[[package]] +name = "httpdate" +version = "1.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "df3b46402a9d5adb4c86a0cf463f42e19994e3ee891101b1841f30a545cb49a9" + +[[package]] +name = "hyper" +version = "1.10.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "55281c53a1894c864990125767da440a4e630446785086f52523b20033b74498" +dependencies = [ + "atomic-waker", + "bytes", + "futures-channel", + "futures-core", + "http", + "http-body", + "httparse", + "httpdate", + "itoa", + "pin-project-lite", + "smallvec", + "tokio", +] + +[[package]] +name = "hyper-util" +version = "0.1.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "96547c2556ec9d12fb1578c4eaf448b04993e7fb79cbaad930a656880a6bdfa0" +dependencies = [ + "bytes", + "http", + "http-body", + "hyper", + "pin-project-lite", + "tokio", + "tower-service", +] + +[[package]] +name = "itoa" +version = "1.0.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f42a60cbdf9a97f5d2305f08a87dc4e09308d1276d28c869c684d7777685682" + +[[package]] +name = "libc" +version = "0.2.186" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "68ab91017fe16c622486840e4c83c9a37afeff978bd239b5293d61ece587de66" + +[[package]] +name = "log" +version = "0.4.32" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "953f07c43838f8e6f9758cab68bf5bed85465e7587ebe0b823f1bcd81978ad3a" + +[[package]] +name = "matchit" +version = "0.8.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "47e1ffaa40ddd1f3ed91f717a33c8c0ee23fff369e3aa8772b9605cc1d22f4c3" + +[[package]] +name = "memchr" +version = "2.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6b947ae49db0d222b1dbc6b113ce7248a3fc3a6ca21b696717bfc000ba4484d8" + +[[package]] +name = "mime" +version = "0.3.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6877bb514081ee2a7ff5ef9de3281f14a4dd4bceac4c09388074a6b5df8a139a" + +[[package]] +name = "mio" +version = "1.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "02bd0af71c67b473010cbbc60715ee815645a4dc942899111f494b4b737d6fda" +dependencies = [ + "libc", + "wasi", + "windows-sys", +] + +[[package]] +name = "once_cell" +version = "1.21.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9f7c3e4beb33f85d45ae3e3a1792185706c8e16d043238c593331cc7cd313b50" + +[[package]] +name = "percent-encoding" +version = "2.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9b4f627cb1b25917193a259e49bdad08f671f8d9708acfd5fe0a8c1455d87220" + +[[package]] +name = "pin-project-lite" +version = "0.2.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a89322df9ebe1c1578d689c92318e070967d1042b512afbe49518723f4e6d5cd" + +[[package]] +name = "proc-macro2" +version = "1.0.106" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8fd00f0bb2e90d81d1044c2b32617f68fcb9fa3bb7640c23e9c748e53fb30934" +dependencies = [ + "unicode-ident", +] + +[[package]] +name = "quote" +version = "1.0.45" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "41f2619966050689382d2b44f664f4bc593e129785a36d6ee376ddf37259b924" +dependencies = [ + "proc-macro2", +] + +[[package]] +name = "ryu" +version = "1.0.23" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9774ba4a74de5f7b1c1451ed6cd5285a32eddb5cccb8cc655a4e50009e06477f" + +[[package]] +name = "serde" +version = "1.0.228" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9a8e94ea7f378bd32cbbd37198a4a91436180c5bb472411e48b5ec2e2124ae9e" +dependencies = [ + "serde_core", +] + +[[package]] +name = "serde_core" +version = "1.0.228" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "41d385c7d4ca58e59fc732af25c3983b67ac852c1a25000afe1175de458b67ad" +dependencies = [ + "serde_derive", +] + +[[package]] +name = "serde_derive" +version = "1.0.228" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d540f220d3187173da220f885ab66608367b6574e925011a9353e4badda91d79" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "serde_json" +version = "1.0.150" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e8014e44b4736ed0538adeecded0fce2a272f22dc9578a7eb6b2d9993c74cfb9" +dependencies = [ + "itoa", + "memchr", + "serde", + "serde_core", + "zmij", +] + +[[package]] +name = "serde_path_to_error" +version = "0.1.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "10a9ff822e371bb5403e391ecd83e182e0e77ba7f6fe0160b795797109d1b457" +dependencies = [ + "itoa", + "serde", + "serde_core", +] + +[[package]] +name = "serde_urlencoded" +version = "0.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d3491c14715ca2294c4d6a88f15e84739788c1d030eed8c110436aafdaa2f3fd" +dependencies = [ + "form_urlencoded", + "itoa", + "ryu", + "serde", +] + +[[package]] +name = "slab" +version = "0.4.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0c790de23124f9ab44544d7ac05d60440adc586479ce501c1d6d7da3cd8c9cf5" + +[[package]] +name = "smallvec" +version = "1.15.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "67b1b7a3b5fe4f1376887184045fcf45c69e92af734b7aaddc05fb777b6fbd03" + +[[package]] +name = "socket2" +version = "0.6.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "52d1cfed4120b4d927bf7c0f86d2087a4a7d6027c906d9f9d525a80573b9be51" +dependencies = [ + "libc", + "windows-sys", +] + +[[package]] +name = "syn" +version = "2.0.117" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e665b8803e7b1d2a727f4023456bbbbe74da67099c585258af0ad9c5013b9b99" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + +[[package]] +name = "sync_wrapper" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0bf256ce5efdfa370213c1dabab5935a12e49f2c58d15e9eac2870d3b4f27263" + +[[package]] +name = "tokio" +version = "1.52.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8fc7f01b389ac15039e4dc9531aa973a135d7a4135281b12d7c1bc79fd57fffe" +dependencies = [ + "libc", + "mio", + "pin-project-lite", + "socket2", + "tokio-macros", + "windows-sys", +] + +[[package]] +name = "tokio-macros" +version = "2.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "385a6cb71ab9ab790c5fe8d67f1645e6c450a7ce006a33de03daa956cf70a496" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "tower" +version = "0.5.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ebe5ef63511595f1344e2d5cfa636d973292adc0eec1f0ad45fae9f0851ab1d4" +dependencies = [ + "futures-core", + "futures-util", + "pin-project-lite", + "sync_wrapper", + "tokio", + "tower-layer", + "tower-service", + "tracing", +] + +[[package]] +name = "tower-layer" +version = "0.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "121c2a6cda46980bb0fcd1647ffaf6cd3fc79a013de288782836f6df9c48780e" + +[[package]] +name = "tower-service" +version = "0.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8df9b6e13f2d32c91b9bd719c00d1958837bc7dec474d94952798cc8e69eeec3" + +[[package]] +name = "tracing" +version = "0.1.44" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "63e71662fa4b2a2c3a26f570f037eb95bb1f85397f3cd8076caed2f026a6d100" +dependencies = [ + "log", + "pin-project-lite", + "tracing-core", +] + +[[package]] +name = "tracing-core" +version = "0.1.36" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "db97caf9d906fbde555dd62fa95ddba9eecfd14cb388e4f491a66d74cd5fb79a" +dependencies = [ + "once_cell", +] + +[[package]] +name = "unicode-ident" +version = "1.0.24" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e6e4313cd5fcd3dad5cafa179702e2b244f760991f45397d14d4ebf38247da75" + +[[package]] +name = "wasi" +version = "0.11.1+wasi-snapshot-preview1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ccf3ec651a847eb01de73ccad15eb7d99f80485de043efb2f370cd654f4ea44b" + +[[package]] +name = "windows-link" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f0805222e57f7521d6a62e36fa9163bc891acd422f971defe97d64e70d0a4fe5" + +[[package]] +name = "windows-sys" +version = "0.61.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ae137229bcbd6cdf0f7b80a31df61766145077ddf49416a728b02cb3921ff3fc" +dependencies = [ + "windows-link", +] + +[[package]] +name = "zmij" +version = "1.0.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b8848ee67ecc8aedbaf3e4122217aff892639231befc6a1b58d29fff4c2cabaa" diff --git a/rust/tests/fixtures/project-example/Cargo.toml b/rust/tests/fixtures/project-example/Cargo.toml new file mode 100644 index 00000000..d2f646c5 --- /dev/null +++ b/rust/tests/fixtures/project-example/Cargo.toml @@ -0,0 +1,19 @@ +# A Fission Rust function as a full Cargo project. The only contract: +# the binary must serve HTTP on 127.0.0.1:$FISSION_RUNTIME_PORT, so any +# framework works (axum shown here; actix-web, rocket, warp all fine). +[package] +name = "echo-example" +version = "0.1.0" +edition = "2024" + +# Standalone crate, not part of the environment workspace. +[workspace] + +[dependencies] +axum = "0.8" +tokio = { version = "1", features = ["rt-multi-thread", "net", "macros"] } +serde_json = "1" + +[profile.release] +lto = "thin" +strip = true diff --git a/rust/tests/fixtures/project-example/src/main.rs b/rust/tests/fixtures/project-example/src/main.rs new file mode 100644 index 00000000..70b8a6cb --- /dev/null +++ b/rust/tests/fixtures/project-example/src/main.rs @@ -0,0 +1,23 @@ +use axum::{Json, Router, body::Bytes, response::IntoResponse}; +use serde_json::{Value, json}; + +async fn echo(body: Bytes) -> impl IntoResponse { + // Echo JSON bodies as JSON, anything else as a string. + let value: Value = serde_json::from_slice(&body) + .unwrap_or_else(|_| Value::String(String::from_utf8_lossy(&body).into_owned())); + Json(json!({ "echo": value })) +} + +#[tokio::main] +async fn main() { + let port: u16 = std::env::var("FISSION_RUNTIME_PORT") + .ok() + .and_then(|p| p.parse().ok()) + .unwrap_or(8889); + let listener = tokio::net::TcpListener::bind(("127.0.0.1", port)) + .await + .expect("bind function port"); + axum::serve(listener, Router::new().fallback(echo)) + .await + .expect("server error"); +} diff --git a/rust/tests/test_rust_env.sh b/rust/tests/test_rust_env.sh index d28f1622..191535f3 100755 --- a/rust/tests/test_rust_env.sh +++ b/rust/tests/test_rust_env.sh @@ -27,7 +27,7 @@ fn_poolmgr=hello-rust-poolmgr-$TEST_ID fn_nd=hello-rust-nd-$TEST_ID fn_echo=echo-rust-$TEST_ID -cd $ROOT/rust/examples +cd $ROOT/rust/tests/fixtures export RUST_BUILDER_IMAGE=rust-builder export RUST_RUNTIME_IMAGE=rust-env diff --git a/tensorflow-serving/envconfig.json b/tensorflow-serving/envconfig.json index 98ab2316..57cc870a 100644 --- a/tensorflow-serving/envconfig.json +++ b/tensorflow-serving/envconfig.json @@ -1,6 +1,6 @@ [ { - "examples": "https://github.com/fission/environments/tree/master/tensorflow-serving/examples", + "examples": "https://github.com/fission/examples/tree/main/miscellaneous/tensorflow-serving", "icon": "./logo/Tensorflow_logo.svg", "image": "tensorflow-serving-env", "keywords": [],