mirror of
https://github.com/fnproject/fn.git
synced 2022-10-28 21:29:17 +03:00
Full stack tests
This commit is contained in:
committed by
Reed Allman
parent
c85571f51d
commit
adf61c77be
@@ -51,6 +51,16 @@ test_job:
|
|||||||
script:
|
script:
|
||||||
- DOCKER_LOCATION=container_ip ./test.sh
|
- DOCKER_LOCATION=container_ip ./test.sh
|
||||||
|
|
||||||
|
#integration_tests:
|
||||||
|
# stage: test
|
||||||
|
# script:
|
||||||
|
# - go build -o functions-alpine
|
||||||
|
# - docker build -t funcy/functions:latest .
|
||||||
|
# - make docker-test-run-with-bolt
|
||||||
|
# - make docker-test-run-with-mysql
|
||||||
|
# - make docker-test-run-with-postgres
|
||||||
|
# - make docker-test-run-with-redis
|
||||||
|
|
||||||
deploy_job:
|
deploy_job:
|
||||||
only:
|
only:
|
||||||
- tags
|
- tags
|
||||||
|
|||||||
12
Makefile
12
Makefile
@@ -37,6 +37,18 @@ docker-build:
|
|||||||
docker-run: docker-build
|
docker-run: docker-build
|
||||||
docker run --rm --privileged -it -e NO_PROXY -e HTTP_PROXY -e LOG_LEVEL=debug -e "DB_URL=bolt:///app/data/bolt.db" -v ${CURDIR}/data:/app/data -p 8080:8080 funcy/functions
|
docker run --rm --privileged -it -e NO_PROXY -e HTTP_PROXY -e LOG_LEVEL=debug -e "DB_URL=bolt:///app/data/bolt.db" -v ${CURDIR}/data:/app/data -p 8080:8080 funcy/functions
|
||||||
|
|
||||||
|
docker-test-run-with-bolt:
|
||||||
|
./api_test.sh bolt
|
||||||
|
|
||||||
|
docker-test-run-with-mysql:
|
||||||
|
./api_test.sh mysql
|
||||||
|
|
||||||
|
docker-test-run-with-postgres:
|
||||||
|
./api_test.sh postgres
|
||||||
|
|
||||||
|
docker-test-run-with-redis:
|
||||||
|
./api_test.sh redis
|
||||||
|
|
||||||
docker-test:
|
docker-test:
|
||||||
docker run -ti --privileged --rm -e LOG_LEVEL=debug \
|
docker run -ti --privileged --rm -e LOG_LEVEL=debug \
|
||||||
-v /var/run/docker.sock:/var/run/docker.sock \
|
-v /var/run/docker.sock:/var/run/docker.sock \
|
||||||
|
|||||||
52
api_test.sh
Executable file
52
api_test.sh
Executable file
@@ -0,0 +1,52 @@
|
|||||||
|
set -ex
|
||||||
|
|
||||||
|
|
||||||
|
case "$1" in
|
||||||
|
|
||||||
|
"bolt" )
|
||||||
|
docker rm -fv func-server || echo No prev func-server container
|
||||||
|
|
||||||
|
docker run --name func-server --privileged -v /var/run/docker.sock:/var/run/docker.sock -d -e NO_PROXY -e HTTP_PROXY -e DOCKER_HOST=${DOCKER_HOST} -e LOG_LEVEL=debug -p 8080:8080 funcy/functions
|
||||||
|
sleep 1
|
||||||
|
;;
|
||||||
|
|
||||||
|
"mysql" )
|
||||||
|
docker rm -fv func-mysql-test || echo No prev mysql test db container
|
||||||
|
docker rm -fv func-server || echo No prev func-server container
|
||||||
|
|
||||||
|
docker run --name func-mysql-test -p 3307:3306 -e MYSQL_DATABASE=funcs -e MYSQL_ROOT_PASSWORD=root -d mysql
|
||||||
|
sleep 8
|
||||||
|
export MYSQL_HOST="$(docker inspect -f '{{.NetworkSettings.IPAddress}}' func-mysql-test)"
|
||||||
|
export MYSQL_PORT=3306
|
||||||
|
docker run --name func-server --privileged -d -e NO_PROXY -e HTTP_PROXY -e DOCKER_HOST=${DOCKER_HOST} -e LOG_LEVEL=debug -e "DB_URL=mysql://root:root@tcp(${MYSQL_HOST}:${MYSQL_PORT})/funcs" -p 8080:8080 -v /var/run/docker.sock:/var/run/docker.sock funcy/functions
|
||||||
|
|
||||||
|
;;
|
||||||
|
|
||||||
|
"postgres" )
|
||||||
|
docker rm -fv func-postgres-test || echo No prev test db container
|
||||||
|
docker rm -fv func-server || echo No prev func-server container
|
||||||
|
|
||||||
|
docker run --name func-postgres-test -p -e "POSTGRES_DB=funcs" 5432:5432 -d postgres
|
||||||
|
sleep 8
|
||||||
|
export POSTGRES_HOST="$(docker inspect -f '{{.NetworkSettings.IPAddress}}' func-postgres-test)"
|
||||||
|
export POSTGRES_PORT=5432
|
||||||
|
docker run --name func-server --privileged -d -e NO_PROXY -e HTTP_PROXY -e DOCKER_HOST=${DOCKER_HOST} -e LOG_LEVEL=debug -e "DB_URL=postgres://postgres@${POSTGRES_HOST}:${POSTGRES_PORT}/funcs?sslmode=disable" -p 8080:8080 -v /var/run/docker.sock:/var/run/docker.sock funcy/functions
|
||||||
|
|
||||||
|
;;
|
||||||
|
|
||||||
|
"redis" )
|
||||||
|
docker rm -fv func-redis-test|| echo No prev redis test db container
|
||||||
|
docker rm -fv func-server || echo No prev func-server container
|
||||||
|
|
||||||
|
docker run --name func-redis-test -p 6379:6379 -d redis
|
||||||
|
sleep 8
|
||||||
|
export REDIS_HOST="$(docker inspect -f '{{.NetworkSettings.IPAddress}}' func-redis-test)"
|
||||||
|
export REDIS_PORT=6379
|
||||||
|
docker run --name func-server --privileged -d -e NO_PROXY -e HTTP_PROXY -e DOCKER_HOST=${DOCKER_HOST} -e LOG_LEVEL=debug -e "DB_URL=redis://${REDIS_HOST}:${REDIS_PORT}/" -p 8080:8080 -v /var/run/docker.sock:/var/run/docker.sock funcy/functions
|
||||||
|
|
||||||
|
;;
|
||||||
|
|
||||||
|
|
||||||
|
esac
|
||||||
|
|
||||||
|
cd fn/tests && API_URL="http://$(docker inspect -f '{{.NetworkSettings.IPAddress}}' func-server):8080" go test -v ./...; cd ../../
|
||||||
@@ -13,7 +13,10 @@ dep:
|
|||||||
dep ensure
|
dep ensure
|
||||||
|
|
||||||
test:
|
test:
|
||||||
go test $(go list ./... | grep -v /vendor/)
|
go test $(go list ./... | grep -v /vendor/ | grep -v /tests)
|
||||||
|
|
||||||
|
test-integration:
|
||||||
|
cd tests/ && go test -v ./...; cd ..
|
||||||
|
|
||||||
release:
|
release:
|
||||||
GOOS=linux go build -o fn_linux
|
GOOS=linux go build -o fn_linux
|
||||||
|
|||||||
@@ -8,6 +8,7 @@ import (
|
|||||||
|
|
||||||
"context"
|
"context"
|
||||||
fnclient "github.com/funcy/functions_go/client"
|
fnclient "github.com/funcy/functions_go/client"
|
||||||
|
client "gitlab-odx.oracle.com/odx/functions/fn/client"
|
||||||
apiapps "github.com/funcy/functions_go/client/apps"
|
apiapps "github.com/funcy/functions_go/client/apps"
|
||||||
"github.com/funcy/functions_go/models"
|
"github.com/funcy/functions_go/models"
|
||||||
"github.com/jmoiron/jsonq"
|
"github.com/jmoiron/jsonq"
|
||||||
@@ -20,7 +21,7 @@ type appsCmd struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func apps() cli.Command {
|
func apps() cli.Command {
|
||||||
a := appsCmd{client: apiClient()}
|
a := appsCmd{client: client.APIClient()}
|
||||||
|
|
||||||
return cli.Command{
|
return cli.Command{
|
||||||
Name: "apps",
|
Name: "apps",
|
||||||
|
|||||||
@@ -5,6 +5,7 @@ import (
|
|||||||
"fmt"
|
"fmt"
|
||||||
|
|
||||||
fnclient "github.com/funcy/functions_go/client"
|
fnclient "github.com/funcy/functions_go/client"
|
||||||
|
client "gitlab-odx.oracle.com/odx/functions/fn/client"
|
||||||
apicall "github.com/funcy/functions_go/client/call"
|
apicall "github.com/funcy/functions_go/client/call"
|
||||||
"github.com/funcy/functions_go/models"
|
"github.com/funcy/functions_go/models"
|
||||||
"github.com/urfave/cli"
|
"github.com/urfave/cli"
|
||||||
@@ -15,7 +16,7 @@ type callsCmd struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func calls() cli.Command {
|
func calls() cli.Command {
|
||||||
c := callsCmd{client: apiClient()}
|
c := callsCmd{client: client.APIClient()}
|
||||||
|
|
||||||
return cli.Command{
|
return cli.Command{
|
||||||
Name: "calls",
|
Name: "calls",
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
package main
|
package client
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"os"
|
"os"
|
||||||
@@ -11,7 +11,7 @@ import (
|
|||||||
"github.com/go-openapi/strfmt"
|
"github.com/go-openapi/strfmt"
|
||||||
)
|
)
|
||||||
|
|
||||||
func host() string {
|
func Host() string {
|
||||||
apiURL := os.Getenv("API_URL")
|
apiURL := os.Getenv("API_URL")
|
||||||
if apiURL == "" {
|
if apiURL == "" {
|
||||||
apiURL = "http://localhost:8080"
|
apiURL = "http://localhost:8080"
|
||||||
@@ -21,12 +21,12 @@ func host() string {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
log.Fatalln("Couldn't parse API URL:", err)
|
log.Fatalln("Couldn't parse API URL:", err)
|
||||||
}
|
}
|
||||||
|
log.Println("trace: Host:", u.Host)
|
||||||
return u.Host
|
return u.Host
|
||||||
}
|
}
|
||||||
|
|
||||||
func apiClient() *fnclient.Functions {
|
func APIClient() *fnclient.Functions {
|
||||||
transport := httptransport.New(host(), "/v1", []string{"http"})
|
transport := httptransport.New(Host(), "/v1", []string{"http"})
|
||||||
if os.Getenv("FN_TOKEN") != "" {
|
if os.Getenv("FN_TOKEN") != "" {
|
||||||
transport.DefaultAuthentication = httptransport.BearerToken(os.Getenv("FN_TOKEN"))
|
transport.DefaultAuthentication = httptransport.BearerToken(os.Getenv("FN_TOKEN"))
|
||||||
}
|
}
|
||||||
53
fn/client/call_fn.go
Normal file
53
fn/client/call_fn.go
Normal file
@@ -0,0 +1,53 @@
|
|||||||
|
package client
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"io"
|
||||||
|
"net/http"
|
||||||
|
"os"
|
||||||
|
"strings"
|
||||||
|
)
|
||||||
|
|
||||||
|
func EnvAsHeader(req *http.Request, selectedEnv []string) {
|
||||||
|
detectedEnv := os.Environ()
|
||||||
|
if len(selectedEnv) > 0 {
|
||||||
|
detectedEnv = selectedEnv
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, e := range detectedEnv {
|
||||||
|
kv := strings.Split(e, "=")
|
||||||
|
name := kv[0]
|
||||||
|
req.Header.Set(name, os.Getenv(name))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
func CallFN(u string, content io.Reader, output io.Writer, method string, env []string) error {
|
||||||
|
if method == "" {
|
||||||
|
if content == nil {
|
||||||
|
method = "GET"
|
||||||
|
} else {
|
||||||
|
method = "POST"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
req, err := http.NewRequest(method, u, content)
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("error running route: %s", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
req.Header.Set("Content-Type", "application/json")
|
||||||
|
|
||||||
|
if len(env) > 0 {
|
||||||
|
EnvAsHeader(req, env)
|
||||||
|
}
|
||||||
|
|
||||||
|
resp, err := http.DefaultClient.Do(req)
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("error running route: %s", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
io.Copy(output, resp.Body)
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
@@ -11,6 +11,7 @@ import (
|
|||||||
"time"
|
"time"
|
||||||
|
|
||||||
functions "github.com/funcy/functions_go"
|
functions "github.com/funcy/functions_go"
|
||||||
|
client "gitlab-odx.oracle.com/odx/functions/fn/client"
|
||||||
"github.com/funcy/functions_go/models"
|
"github.com/funcy/functions_go/models"
|
||||||
"github.com/urfave/cli"
|
"github.com/urfave/cli"
|
||||||
)
|
)
|
||||||
@@ -150,7 +151,7 @@ func (p *deploycmd) route(c *cli.Context, ff *funcfile) error {
|
|||||||
return fmt.Errorf("error setting endpoint: %v", err)
|
return fmt.Errorf("error setting endpoint: %v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
routesCmd := routesCmd{client: apiClient()}
|
routesCmd := routesCmd{client: client.APIClient()}
|
||||||
rt := &models.Route{}
|
rt := &models.Route{}
|
||||||
if err := routeWithFuncFile(c, ff, rt); err != nil {
|
if err := routeWithFuncFile(c, ff, rt); err != nil {
|
||||||
return fmt.Errorf("error getting route with funcfile: %s", err)
|
return fmt.Errorf("error getting route with funcfile: %s", err)
|
||||||
|
|||||||
55
fn/routes.go
55
fn/routes.go
@@ -5,8 +5,6 @@ import (
|
|||||||
"encoding/json"
|
"encoding/json"
|
||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
"io"
|
|
||||||
"net/http"
|
|
||||||
"net/url"
|
"net/url"
|
||||||
"os"
|
"os"
|
||||||
"path"
|
"path"
|
||||||
@@ -14,6 +12,8 @@ import (
|
|||||||
"text/tabwriter"
|
"text/tabwriter"
|
||||||
|
|
||||||
fnclient "github.com/funcy/functions_go/client"
|
fnclient "github.com/funcy/functions_go/client"
|
||||||
|
client "gitlab-odx.oracle.com/odx/functions/fn/client"
|
||||||
|
utils "gitlab-odx.oracle.com/odx/functions/fn/utils"
|
||||||
apiroutes "github.com/funcy/functions_go/client/routes"
|
apiroutes "github.com/funcy/functions_go/client/routes"
|
||||||
fnmodels "github.com/funcy/functions_go/models"
|
fnmodels "github.com/funcy/functions_go/models"
|
||||||
"github.com/jmoiron/jsonq"
|
"github.com/jmoiron/jsonq"
|
||||||
@@ -57,7 +57,7 @@ var routeFlags = []cli.Flag{
|
|||||||
|
|
||||||
func routes() cli.Command {
|
func routes() cli.Command {
|
||||||
|
|
||||||
r := routesCmd{client: apiClient()}
|
r := routesCmd{client: client.APIClient()}
|
||||||
|
|
||||||
return cli.Command{
|
return cli.Command{
|
||||||
Name: "routes",
|
Name: "routes",
|
||||||
@@ -132,7 +132,7 @@ func routes() cli.Command {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func call() cli.Command {
|
func call() cli.Command {
|
||||||
r := routesCmd{client: apiClient()}
|
r := routesCmd{client: client.APIClient()}
|
||||||
|
|
||||||
return cli.Command{
|
return cli.Command{
|
||||||
Name: "call",
|
Name: "call",
|
||||||
@@ -191,55 +191,12 @@ func (a *routesCmd) call(c *cli.Context) error {
|
|||||||
|
|
||||||
u := url.URL{
|
u := url.URL{
|
||||||
Scheme: "http",
|
Scheme: "http",
|
||||||
Host: host(),
|
Host: client.Host(),
|
||||||
}
|
}
|
||||||
u.Path = path.Join(u.Path, "r", appName, route)
|
u.Path = path.Join(u.Path, "r", appName, route)
|
||||||
content := stdin()
|
content := stdin()
|
||||||
|
|
||||||
return callfn(u.String(), content, os.Stdout, c.String("method"), c.StringSlice("e"))
|
return client.CallFN(u.String(), content, os.Stdout, c.String("method"), c.StringSlice("e"))
|
||||||
}
|
|
||||||
|
|
||||||
func callfn(u string, content io.Reader, output io.Writer, method string, env []string) error {
|
|
||||||
if method == "" {
|
|
||||||
if content == nil {
|
|
||||||
method = "GET"
|
|
||||||
} else {
|
|
||||||
method = "POST"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
req, err := http.NewRequest(method, u, content)
|
|
||||||
if err != nil {
|
|
||||||
return fmt.Errorf("error running route: %s", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
req.Header.Set("Content-Type", "application/json")
|
|
||||||
|
|
||||||
if len(env) > 0 {
|
|
||||||
envAsHeader(req, env)
|
|
||||||
}
|
|
||||||
|
|
||||||
resp, err := http.DefaultClient.Do(req)
|
|
||||||
if err != nil {
|
|
||||||
return fmt.Errorf("error running route: %s", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
io.Copy(output, resp.Body)
|
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func envAsHeader(req *http.Request, selectedEnv []string) {
|
|
||||||
detectedEnv := os.Environ()
|
|
||||||
if len(selectedEnv) > 0 {
|
|
||||||
detectedEnv = selectedEnv
|
|
||||||
}
|
|
||||||
|
|
||||||
for _, e := range detectedEnv {
|
|
||||||
kv := strings.Split(e, "=")
|
|
||||||
name := kv[0]
|
|
||||||
req.Header.Set(name, os.Getenv(name))
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func routeWithFlags(c *cli.Context, rt *fnmodels.Route) {
|
func routeWithFlags(c *cli.Context, rt *fnmodels.Route) {
|
||||||
|
|||||||
@@ -4,6 +4,7 @@ import (
|
|||||||
"net/http"
|
"net/http"
|
||||||
"os"
|
"os"
|
||||||
"testing"
|
"testing"
|
||||||
|
"gitlab-odx.oracle.com/odx/functions/fn/utils"
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestEnvAsHeader(t *testing.T) {
|
func TestEnvAsHeader(t *testing.T) {
|
||||||
@@ -17,7 +18,7 @@ func TestEnvAsHeader(t *testing.T) {
|
|||||||
}
|
}
|
||||||
for _, selectedEnv := range cases {
|
for _, selectedEnv := range cases {
|
||||||
req, _ := http.NewRequest("GET", "http://www.example.com", nil)
|
req, _ := http.NewRequest("GET", "http://www.example.com", nil)
|
||||||
envAsHeader(req, selectedEnv)
|
utils.EnvAsHeader(req, selectedEnv)
|
||||||
if found := req.Header.Get("k"); found != expectedValue {
|
if found := req.Header.Get("k"); found != expectedValue {
|
||||||
t.Errorf("not found expected header: %v", found)
|
t.Errorf("not found expected header: %v", found)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -11,6 +11,7 @@ import (
|
|||||||
"strings"
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
"gitlab-odx.oracle.com/odx/functions/fn/client"
|
||||||
functions "github.com/funcy/functions_go"
|
functions "github.com/funcy/functions_go"
|
||||||
"github.com/urfave/cli"
|
"github.com/urfave/cli"
|
||||||
)
|
)
|
||||||
@@ -173,7 +174,7 @@ func runremotetest(target string, in, expectedOut, expectedErr *string, env map[
|
|||||||
os.Setenv(k, v)
|
os.Setenv(k, v)
|
||||||
restrictedEnv = append(restrictedEnv, k)
|
restrictedEnv = append(restrictedEnv, k)
|
||||||
}
|
}
|
||||||
if err := callfn(target, stdin, &stdout, "", restrictedEnv); err != nil {
|
if err := client.CallFN(target, stdin, &stdout, "", restrictedEnv); err != nil {
|
||||||
return fmt.Errorf("%v\nstdout:%s\n", err, stdout.String())
|
return fmt.Errorf("%v\nstdout:%s\n", err, stdout.String())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
19
fn/tests/README.md
Normal file
19
fn/tests/README.md
Normal file
@@ -0,0 +1,19 @@
|
|||||||
|
Oracle Functions integration API tests
|
||||||
|
======================================
|
||||||
|
|
||||||
|
|
||||||
|
Test dependencies
|
||||||
|
-----------------
|
||||||
|
|
||||||
|
```bash
|
||||||
|
DOCKER_HOST - for building images
|
||||||
|
API_URL - Oracle Functions API endpoint
|
||||||
|
```
|
||||||
|
|
||||||
|
How to run tests?
|
||||||
|
-----------------
|
||||||
|
|
||||||
|
```bash
|
||||||
|
export API_URL=http://localhost:8080
|
||||||
|
go test -v ./...
|
||||||
|
```
|
||||||
117
fn/tests/apps_test.go
Normal file
117
fn/tests/apps_test.go
Normal file
@@ -0,0 +1,117 @@
|
|||||||
|
package tests
|
||||||
|
|
||||||
|
import (
|
||||||
|
"testing"
|
||||||
|
"time"
|
||||||
|
"strings"
|
||||||
|
"reflect"
|
||||||
|
|
||||||
|
"github.com/funcy/functions_go/client/apps"
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
func TestApps(t *testing.T) {
|
||||||
|
s := SetupDefaultSuite()
|
||||||
|
|
||||||
|
t.Run("no-apps-found-test", func(t *testing.T) {
|
||||||
|
cfg := &apps.GetAppsParams{
|
||||||
|
Context: s.Context,
|
||||||
|
}
|
||||||
|
cfg.WithTimeout(time.Second * 60)
|
||||||
|
appsPayload, err := s.Client.Apps.GetApps(cfg)
|
||||||
|
CheckAppResponseError(t, err)
|
||||||
|
// on this step we should not have any apps so far
|
||||||
|
actualApps := appsPayload.Payload.Apps
|
||||||
|
if len(actualApps) != 0 {
|
||||||
|
t.Fatalf("Expected to see no apps, but found %v apps.", len(actualApps))
|
||||||
|
}
|
||||||
|
t.Logf("Test `%v` passed", t.Name())
|
||||||
|
})
|
||||||
|
|
||||||
|
t.Run("app-not-found-test", func(t *testing.T) {
|
||||||
|
cfg := &apps.GetAppsAppParams{
|
||||||
|
App: "missing-app",
|
||||||
|
Context: s.Context,
|
||||||
|
}
|
||||||
|
cfg.WithTimeout(time.Second * 60)
|
||||||
|
_, err := s.Client.Apps.GetAppsApp(cfg)
|
||||||
|
CheckAppResponseError(t, err)
|
||||||
|
t.Logf("Test `%v` passed", t.Name())
|
||||||
|
})
|
||||||
|
|
||||||
|
t.Run("create-app-no-config-test", func(t *testing.T) {
|
||||||
|
CreateApp(t, s.Context, s.Client, s.AppName, map[string]string{})
|
||||||
|
t.Logf("Test `%v` passed.", t.Name())
|
||||||
|
})
|
||||||
|
|
||||||
|
t.Run("delete-app-no-config", func(t *testing.T) {
|
||||||
|
DeleteApp(t, s.Context, s.Client, s.AppName)
|
||||||
|
t.Logf("Test `%v` passed", t.Name())
|
||||||
|
})
|
||||||
|
|
||||||
|
t.Run("create-app-with-config-test", func(t *testing.T) {
|
||||||
|
CreateApp(t, s.Context, s.Client, s.AppName, map[string]string{"A": "a"})
|
||||||
|
t.Logf("Test `%v` passed.", t.Name())
|
||||||
|
})
|
||||||
|
|
||||||
|
t.Run("inspect-app-with-config-test", func(t *testing.T) {
|
||||||
|
cfg := &apps.GetAppsAppParams{
|
||||||
|
Context: s.Context,
|
||||||
|
App: s.AppName,
|
||||||
|
}
|
||||||
|
appPayload, err := s.Client.Apps.GetAppsApp(cfg)
|
||||||
|
CheckAppResponseError(t, err)
|
||||||
|
appBody := appPayload.Payload.App
|
||||||
|
val, ok := appBody.Config["A"]
|
||||||
|
if !ok {
|
||||||
|
t.Fatal("Error during app config inspect: config map misses required entity `A` with value `a`.")
|
||||||
|
}
|
||||||
|
if !strings.Contains("a", val) {
|
||||||
|
t.Fatalf("App config value is different. Expected: `a`. Actual %v", val)
|
||||||
|
}
|
||||||
|
DeleteApp(t, s.Context, s.Client, s.AppName)
|
||||||
|
t.Logf("Test `%v` passed.", t.Name())
|
||||||
|
})
|
||||||
|
|
||||||
|
t.Run("patch-override-app-config", func(t *testing.T){
|
||||||
|
config := map[string]string{
|
||||||
|
"A": "b",
|
||||||
|
}
|
||||||
|
appPayload := UpdateApp(t, s.Context, s.Client, s.AppName, config)
|
||||||
|
val, ok := appPayload.Payload.App.Config["A"]
|
||||||
|
if !ok {
|
||||||
|
t.Fatal("Error during app config inspect: config map misses required entity `A` with value `a`.")
|
||||||
|
}
|
||||||
|
if !strings.Contains("b", val) {
|
||||||
|
t.Fatalf("App config value is different. Expected: `b`. Actual %v", val)
|
||||||
|
}
|
||||||
|
DeleteApp(t, s.Context, s.Client, s.AppName)
|
||||||
|
t.Logf("Test `%v` passed.", t.Name())
|
||||||
|
})
|
||||||
|
|
||||||
|
t.Run("patch-add-app-config", func(t *testing.T) {
|
||||||
|
config := map[string]string{
|
||||||
|
"B": "b",
|
||||||
|
}
|
||||||
|
appPayload := UpdateApp(t, s.Context, s.Client, s.AppName, config)
|
||||||
|
val, ok := appPayload.Payload.App.Config["B"]
|
||||||
|
if !ok {
|
||||||
|
t.Fatal("Error during app config inspect: config map misses required entity `B` with value `b`.")
|
||||||
|
}
|
||||||
|
if !strings.Contains("b", val) {
|
||||||
|
t.Fatalf("App config value is different. Expected: `b`. Actual %v", val)
|
||||||
|
}
|
||||||
|
DeleteApp(t, s.Context, s.Client, s.AppName)
|
||||||
|
t.Logf("Test `%v` passed.", t.Name())
|
||||||
|
})
|
||||||
|
|
||||||
|
t.Run("crete-app-duplicate", func(t *testing.T) {
|
||||||
|
CreateApp(t, s.Context, s.Client, s.AppName, map[string]string{})
|
||||||
|
_, err := CreateAppNoAssert(s.Context, s.Client, s.AppName, map[string]string{})
|
||||||
|
if reflect.TypeOf(err) != reflect.TypeOf(apps.NewPostAppsConflict()) {
|
||||||
|
CheckAppResponseError(t, err)
|
||||||
|
}
|
||||||
|
DeleteApp(t, s.Context, s.Client, s.AppName)
|
||||||
|
t.Logf("Test `%v` passed.", t.Name())
|
||||||
|
})
|
||||||
|
}
|
||||||
107
fn/tests/calls_test.go
Normal file
107
fn/tests/calls_test.go
Normal file
@@ -0,0 +1,107 @@
|
|||||||
|
package tests
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bytes"
|
||||||
|
"testing"
|
||||||
|
"time"
|
||||||
|
"net/url"
|
||||||
|
"path"
|
||||||
|
|
||||||
|
"gitlab-odx.oracle.com/odx/functions/fn/client"
|
||||||
|
"github.com/funcy/functions_go/client/call"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestCalls(t *testing.T) {
|
||||||
|
s := SetupDefaultSuite()
|
||||||
|
|
||||||
|
t.Run("list-calls-for-missing-app", func(t *testing.T) {
|
||||||
|
cfg := &call.GetAppsAppCallsRouteParams{
|
||||||
|
App: s.AppName,
|
||||||
|
Route: s.RoutePath,
|
||||||
|
Context: s.Context,
|
||||||
|
}
|
||||||
|
_, err := s.Client.Call.GetAppsAppCallsRoute(cfg)
|
||||||
|
if err == nil {
|
||||||
|
t.Fatalf("Must fail with missing app error, but got %s", err)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
CreateApp(t, s.Context, s.Client, s.AppName, map[string]string{})
|
||||||
|
|
||||||
|
u := url.URL{
|
||||||
|
Scheme: "http",
|
||||||
|
Host: client.Host(),
|
||||||
|
}
|
||||||
|
u.Path = path.Join(u.Path, "r", s.AppName, s.RoutePath)
|
||||||
|
|
||||||
|
t.Run("list-calls-for-missing-route", func(t *testing.T) {
|
||||||
|
cfg := &call.GetAppsAppCallsRouteParams{
|
||||||
|
App: s.AppName,
|
||||||
|
Route: s.RoutePath,
|
||||||
|
Context: s.Context,
|
||||||
|
}
|
||||||
|
_, err := s.Client.Call.GetAppsAppCallsRoute(cfg)
|
||||||
|
if err == nil {
|
||||||
|
t.Fatalf("Must fail with missing route error, but got %s", err)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
CreateRoute(t, s.Context, s.Client, s.AppName, s.RoutePath, s.Image, s.RouteType,
|
||||||
|
s.RouteConfig, s.RouteHeaders)
|
||||||
|
|
||||||
|
t.Run("get-dummy-call", func(t *testing.T) {
|
||||||
|
cfg := &call.GetCallsCallParams{
|
||||||
|
Call: "dummy",
|
||||||
|
Context: s.Context,
|
||||||
|
}
|
||||||
|
cfg.WithTimeout(time.Second * 60)
|
||||||
|
_, err := s.Client.Call.GetCallsCall(cfg)
|
||||||
|
if err == nil {
|
||||||
|
t.Fatal("Must fail because `dummy` call does not exist.")
|
||||||
|
}
|
||||||
|
t.Logf("Test `%v` passed.", t.Name())
|
||||||
|
})
|
||||||
|
|
||||||
|
t.Run("get-real-call", func(t *testing.T) {
|
||||||
|
|
||||||
|
callID := CallAsync(t, u, &bytes.Buffer{})
|
||||||
|
time.Sleep(time.Second * 2)
|
||||||
|
cfg := &call.GetCallsCallParams{
|
||||||
|
Call: callID,
|
||||||
|
Context: s.Context,
|
||||||
|
}
|
||||||
|
cfg.WithTimeout(time.Second * 60)
|
||||||
|
_, err := s.Client.Call.GetCallsCall(cfg)
|
||||||
|
if err != nil {
|
||||||
|
switch err.(type) {
|
||||||
|
case *call.GetCallsCallNotFound:
|
||||||
|
msg := err.(*call.GetCallsCallNotFound).Payload.Error.Message
|
||||||
|
t.Fatalf("Unexpected error occurred: %v.", msg)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
t.Logf("Test `%v` passed.", t.Name())
|
||||||
|
})
|
||||||
|
|
||||||
|
t.Run("list-calls", func(t *testing.T) {
|
||||||
|
cfg := &call.GetAppsAppCallsRouteParams{
|
||||||
|
App: s.AppName,
|
||||||
|
Route: s.RoutePath,
|
||||||
|
Context: s.Context,
|
||||||
|
}
|
||||||
|
calls, err := s.Client.Call.GetAppsAppCallsRoute(cfg)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("Unexpected error: %s", err)
|
||||||
|
}
|
||||||
|
if len(calls.Payload.Calls) == 0 {
|
||||||
|
t.Fatalf("Must fail. There should be at least one call to `%v` route.", s.RoutePath)
|
||||||
|
}
|
||||||
|
for _, c := range calls.Payload.Calls {
|
||||||
|
if c.Path != s.RoutePath {
|
||||||
|
t.Fatalf("Call path mismatch.\n\tExpected: %v\n\tActual: %v", c.Path, s.RoutePath)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
DeleteRoute(t, s.Context, s.Client, s.AppName, s.RoutePath)
|
||||||
|
DeleteApp(t, s.Context, s.Client, s.AppName)
|
||||||
|
}
|
||||||
303
fn/tests/exec_test.go
Normal file
303
fn/tests/exec_test.go
Normal file
@@ -0,0 +1,303 @@
|
|||||||
|
package tests
|
||||||
|
|
||||||
|
import (
|
||||||
|
"io"
|
||||||
|
"encoding/json"
|
||||||
|
"bytes"
|
||||||
|
"testing"
|
||||||
|
"time"
|
||||||
|
"net/url"
|
||||||
|
"path"
|
||||||
|
"strings"
|
||||||
|
|
||||||
|
"gitlab-odx.oracle.com/odx/functions/fn/client"
|
||||||
|
"github.com/funcy/functions_go/client/call"
|
||||||
|
"github.com/funcy/functions_go/client/operations"
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
type ErrMsg struct {
|
||||||
|
Message string `json:"message"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type TimeoutBody struct{
|
||||||
|
Error ErrMsg `json:"error"`
|
||||||
|
CallID string `json:"request_id"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func CallAsync(t *testing.T, u url.URL, content io.Reader) string {
|
||||||
|
output := &bytes.Buffer{}
|
||||||
|
err := client.CallFN(u.String(), content, output, "POST", []string{})
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("Got unexpected error: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
expectedOutput := "call_id"
|
||||||
|
if !strings.Contains(output.String(), expectedOutput) {
|
||||||
|
t.Fatalf("Assertion error.\n\tExpected: %v\n\tActual: %v", expectedOutput, output.String())
|
||||||
|
}
|
||||||
|
|
||||||
|
type CallID struct {
|
||||||
|
CallID string `json:"call_id"`
|
||||||
|
}
|
||||||
|
|
||||||
|
callID := &CallID{}
|
||||||
|
json.NewDecoder(output).Decode(callID)
|
||||||
|
|
||||||
|
if callID.CallID == "" {
|
||||||
|
t.Fatalf("`call_id` not suppose to be empty string")
|
||||||
|
}
|
||||||
|
t.Logf("Async execution call ID: %v", callID.CallID)
|
||||||
|
return callID.CallID
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
func TestRouteExecutions(t *testing.T) {
|
||||||
|
s := SetupDefaultSuite()
|
||||||
|
newRouteType := "async"
|
||||||
|
|
||||||
|
CreateApp(t, s.Context, s.Client, s.AppName, map[string]string{})
|
||||||
|
CreateRoute(t, s.Context, s.Client, s.AppName, s.RoutePath, s.Image, "sync",
|
||||||
|
s.RouteConfig, s.RouteHeaders)
|
||||||
|
|
||||||
|
u := url.URL{
|
||||||
|
Scheme: "http",
|
||||||
|
Host: client.Host(),
|
||||||
|
}
|
||||||
|
u.Path = path.Join(u.Path, "r", s.AppName, s.RoutePath)
|
||||||
|
|
||||||
|
t.Run("run-sync-funcy/hello-no-input", func(t *testing.T) {
|
||||||
|
content := &bytes.Buffer{}
|
||||||
|
output := &bytes.Buffer{}
|
||||||
|
err := client.CallFN(u.String(), content, output, "POST", []string{})
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("Got unexpected error: %v", err)
|
||||||
|
}
|
||||||
|
expectedOutput := "Hello World!\n"
|
||||||
|
if !strings.Contains(expectedOutput, output.String()) {
|
||||||
|
t.Fatalf("Assertion error.\n\tExpected: %v\n\tActual: %v", expectedOutput, output.String())
|
||||||
|
}
|
||||||
|
t.Logf("Test `%v` passed.", t.Name())
|
||||||
|
})
|
||||||
|
|
||||||
|
t.Run("run-sync-funcy/hello-with-input", func(t *testing.T) {
|
||||||
|
content := &bytes.Buffer{}
|
||||||
|
json.NewEncoder(content).Encode(struct {
|
||||||
|
Name string
|
||||||
|
}{Name: "John"})
|
||||||
|
output := &bytes.Buffer{}
|
||||||
|
err := client.CallFN(u.String(), content, output, "POST", []string{})
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("Got unexpected error: %v", err)
|
||||||
|
}
|
||||||
|
expectedOutput := "Hello John!\n"
|
||||||
|
if !strings.Contains(expectedOutput, output.String()) {
|
||||||
|
t.Fatalf("Assertion error.\n\tExpected: %v\n\tActual: %v", expectedOutput, output.String())
|
||||||
|
}
|
||||||
|
t.Logf("Test `%v` passed.", t.Name())
|
||||||
|
})
|
||||||
|
|
||||||
|
_, err := UpdateRoute(
|
||||||
|
t, s.Context, s.Client,
|
||||||
|
s.AppName, s.RoutePath,
|
||||||
|
s.Image, newRouteType, s.Format,
|
||||||
|
s.Memory, s.RouteConfig, s.RouteHeaders, "")
|
||||||
|
|
||||||
|
CheckRouteResponseError(t, err)
|
||||||
|
|
||||||
|
t.Run("run-async-funcy/hello", func(t *testing.T) {
|
||||||
|
CallAsync(t, u, &bytes.Buffer{})
|
||||||
|
t.Logf("Test `%v` passed.", t.Name())
|
||||||
|
})
|
||||||
|
|
||||||
|
t.Run("run-async-funcy/hello-with-status-check", func(t *testing.T) {
|
||||||
|
callID := CallAsync(t, u, &bytes.Buffer{})
|
||||||
|
time.Sleep(time.Second * 2)
|
||||||
|
cfg := &call.GetCallsCallParams{
|
||||||
|
Call: callID,
|
||||||
|
Context: s.Context,
|
||||||
|
}
|
||||||
|
cfg.WithTimeout(time.Second * 60)
|
||||||
|
callResponse, err := s.Client.Call.GetCallsCall(cfg)
|
||||||
|
if err != nil {
|
||||||
|
switch err.(type) {
|
||||||
|
case *call.GetCallsCallNotFound:
|
||||||
|
msg := err.(*call.GetCallsCallNotFound).Payload.Error.Message
|
||||||
|
t.Fatalf("Unexpected error occurred: %v.", msg)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
callObject := callResponse.Payload.Call
|
||||||
|
|
||||||
|
if callObject.AppName != s.AppName {
|
||||||
|
t.Fatalf("Call object app name mismatch.\n\tExpected: %v\n\tActual:%v", s.AppName, callObject.AppName)
|
||||||
|
}
|
||||||
|
if callObject.ID != callID {
|
||||||
|
t.Fatalf("Call object ID mismatch.\n\tExpected: %v\n\tActual:%v", callID, callObject.ID)
|
||||||
|
}
|
||||||
|
if callObject.Path != s.RoutePath {
|
||||||
|
t.Fatalf("Call object route path mismatch.\n\tExpected: %v\n\tActual:%v", s.RoutePath, callObject.Path)
|
||||||
|
}
|
||||||
|
if callObject.Status != "success" {
|
||||||
|
t.Fatalf("Call object status mismatch.\n\tExpected: %v\n\tActual:%v", "success", callObject.Status)
|
||||||
|
}
|
||||||
|
|
||||||
|
})
|
||||||
|
|
||||||
|
DeleteRoute(t, s.Context, s.Client, s.AppName, s.RoutePath)
|
||||||
|
|
||||||
|
|
||||||
|
routePath := "/timeout"
|
||||||
|
image := "funcy/timeout:0.0.1"
|
||||||
|
routeType := "sync"
|
||||||
|
CreateRoute(t, s.Context, s.Client, s.AppName, routePath, image, routeType,
|
||||||
|
s.RouteConfig, s.RouteHeaders)
|
||||||
|
|
||||||
|
t.Run("exec-timeout-test", func(t *testing.T) {
|
||||||
|
|
||||||
|
u := url.URL{
|
||||||
|
Scheme: "http",
|
||||||
|
Host: client.Host(),
|
||||||
|
}
|
||||||
|
u.Path = path.Join(u.Path, "r", s.AppName, routePath)
|
||||||
|
|
||||||
|
content := &bytes.Buffer{}
|
||||||
|
json.NewEncoder(content).Encode(struct {
|
||||||
|
Seconds int64 `json:"seconds"`
|
||||||
|
}{Seconds: 31})
|
||||||
|
output := &bytes.Buffer{}
|
||||||
|
|
||||||
|
client.CallFN(u.String(), content, output, "POST", []string{})
|
||||||
|
|
||||||
|
if !strings.Contains(output.String(), "Timed out") {
|
||||||
|
t.Fatalf("Must fail because of timeout, but got error message: %v", output.String())
|
||||||
|
}
|
||||||
|
tB := &TimeoutBody{}
|
||||||
|
|
||||||
|
json.NewDecoder(output).Decode(tB)
|
||||||
|
|
||||||
|
cfg := &call.GetCallsCallParams{
|
||||||
|
Call: tB.CallID,
|
||||||
|
Context: s.Context,
|
||||||
|
}
|
||||||
|
cfg.WithTimeout(time.Second * 60)
|
||||||
|
callObj, err := s.Client.Call.GetCallsCall(cfg)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("Unexpected error: %s", err)
|
||||||
|
}
|
||||||
|
if !strings.Contains("timeout", callObj.Payload.Call.Status) {
|
||||||
|
t.Fatalf("Call status mismatch.\n\tExpected: %v\n\tActual: %v",
|
||||||
|
"output", "callObj.Payload.Call.Status")
|
||||||
|
}
|
||||||
|
|
||||||
|
t.Logf("Test `%v` passed.", t.Name())
|
||||||
|
})
|
||||||
|
DeleteRoute(t, s.Context, s.Client, s.AppName, routePath)
|
||||||
|
|
||||||
|
routePath = "/multi-log"
|
||||||
|
image = "funcy/multi-log:0.0.1"
|
||||||
|
routeType = "async"
|
||||||
|
CreateRoute(t, s.Context, s.Client, s.AppName, routePath, image, routeType,
|
||||||
|
s.RouteConfig, s.RouteHeaders)
|
||||||
|
|
||||||
|
t.Run("exec-multi-log-test", func(t *testing.T) {
|
||||||
|
u := url.URL{
|
||||||
|
Scheme: "http",
|
||||||
|
Host: client.Host(),
|
||||||
|
}
|
||||||
|
u.Path = path.Join(u.Path, "r", s.AppName, routePath)
|
||||||
|
|
||||||
|
callID := CallAsync(t, u, &bytes.Buffer{})
|
||||||
|
time.Sleep(5 * time.Second)
|
||||||
|
|
||||||
|
cfg := &operations.GetCallsCallLogParams{
|
||||||
|
Call: callID,
|
||||||
|
Context: s.Context,
|
||||||
|
}
|
||||||
|
|
||||||
|
logObj, err := s.Client.Operations.GetCallsCallLog(cfg)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("Unexpected error: %s", err)
|
||||||
|
}
|
||||||
|
if logObj.Payload.Log.Log == "" {
|
||||||
|
t.Fatalf("Log entry must not be empty!")
|
||||||
|
}
|
||||||
|
if !strings.Contains(logObj.Payload.Log.Log, "First line") {
|
||||||
|
t.Fatalf("Log entry must contain `First line` " +
|
||||||
|
"string, but got: %v", logObj.Payload.Log.Log)
|
||||||
|
}
|
||||||
|
if !strings.Contains(logObj.Payload.Log.Log, "Second line") {
|
||||||
|
t.Fatalf("Log entry must contain `Second line` " +
|
||||||
|
"string, but got: %v", logObj.Payload.Log.Log)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
DeleteRoute(t, s.Context, s.Client, s.AppName, routePath)
|
||||||
|
|
||||||
|
routePath = "/log"
|
||||||
|
image = "funcy/log:0.0.1"
|
||||||
|
routeType = "async"
|
||||||
|
CreateRoute(t, s.Context, s.Client, s.AppName, routePath, image, routeType,
|
||||||
|
s.RouteConfig, s.RouteHeaders)
|
||||||
|
|
||||||
|
t.Run("exec-log-test", func(t *testing.T) {
|
||||||
|
u := url.URL{
|
||||||
|
Scheme: "http",
|
||||||
|
Host: client.Host(),
|
||||||
|
}
|
||||||
|
u.Path = path.Join(u.Path, "r", s.AppName, routePath)
|
||||||
|
content := &bytes.Buffer{}
|
||||||
|
json.NewEncoder(content).Encode(struct {
|
||||||
|
Size int
|
||||||
|
}{Size: 20})
|
||||||
|
|
||||||
|
callID := CallAsync(t, u, content)
|
||||||
|
time.Sleep(5 * time.Second)
|
||||||
|
|
||||||
|
cfg := &operations.GetCallsCallLogParams{
|
||||||
|
Call: callID,
|
||||||
|
Context: s.Context,
|
||||||
|
}
|
||||||
|
|
||||||
|
_, err := s.Client.Operations.GetCallsCallLog(cfg)
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("Unexpected error: %s", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
})
|
||||||
|
|
||||||
|
t.Run("exec-oversized-log-test", func(t *testing.T) {
|
||||||
|
t.Skip("Skipped until fix for https://gitlab-odx.oracle.com/odx/functions/issues/86.")
|
||||||
|
size := 1 * 1024 * 1024 * 1024
|
||||||
|
u := url.URL{
|
||||||
|
Scheme: "http",
|
||||||
|
Host: client.Host(),
|
||||||
|
}
|
||||||
|
u.Path = path.Join(u.Path, "r", s.AppName, routePath)
|
||||||
|
content := &bytes.Buffer{}
|
||||||
|
json.NewEncoder(content).Encode(struct {
|
||||||
|
Size int
|
||||||
|
}{Size: size}) //exceeding log by 1 symbol
|
||||||
|
|
||||||
|
callID := CallAsync(t, u, content)
|
||||||
|
time.Sleep(5 * time.Second)
|
||||||
|
|
||||||
|
cfg := &operations.GetCallsCallLogParams{
|
||||||
|
Call: callID,
|
||||||
|
Context: s.Context,
|
||||||
|
}
|
||||||
|
|
||||||
|
logObj, err := s.Client.Operations.GetCallsCallLog(cfg)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("Unexpected error: %s", err)
|
||||||
|
}
|
||||||
|
if len(logObj.Payload.Log.Log) >= size {
|
||||||
|
t.Fatalf("Log entry suppose to be truncated up to expected size %v, got %v",
|
||||||
|
size / 1024, len(logObj.Payload.Log.Log))
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
DeleteRoute(t, s.Context, s.Client, s.AppName, routePath)
|
||||||
|
|
||||||
|
DeleteApp(t, s.Context, s.Client, s.AppName)
|
||||||
|
}
|
||||||
8
fn/tests/fn/log/Dockerfile
Normal file
8
fn/tests/fn/log/Dockerfile
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
FROM funcy/go:dev as build-stage
|
||||||
|
WORKDIR /function
|
||||||
|
ADD . /src
|
||||||
|
RUN cd /src && go build -o func
|
||||||
|
FROM funcy/go
|
||||||
|
WORKDIR /function
|
||||||
|
COPY --from=build-stage /src/func /function/
|
||||||
|
ENTRYPOINT ["./func"]
|
||||||
5
fn/tests/fn/log/func.yaml
Normal file
5
fn/tests/fn/log/func.yaml
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
name: funcy/log
|
||||||
|
version: 0.0.1
|
||||||
|
runtime: go
|
||||||
|
entrypoint: ./func
|
||||||
|
path: /log
|
||||||
29
fn/tests/fn/log/main.go
Normal file
29
fn/tests/fn/log/main.go
Normal file
@@ -0,0 +1,29 @@
|
|||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"encoding/json"
|
||||||
|
"os"
|
||||||
|
"math/rand"
|
||||||
|
)
|
||||||
|
|
||||||
|
const lBytes = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"
|
||||||
|
|
||||||
|
type OutputSize struct {
|
||||||
|
Size int `json:"size"`
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
func RandStringBytes(n int) string {
|
||||||
|
b := make([]byte, n)
|
||||||
|
for i := range b {
|
||||||
|
b[i] = lBytes[rand.Intn(len(lBytes))]
|
||||||
|
}
|
||||||
|
return string(b)
|
||||||
|
}
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
out := &OutputSize{}
|
||||||
|
json.NewDecoder(os.Stdin).Decode(out)
|
||||||
|
fmt.Fprintln(os.Stderr, RandStringBytes(out.Size))
|
||||||
|
}
|
||||||
3
fn/tests/fn/log/sample.payload.json
Normal file
3
fn/tests/fn/log/sample.payload.json
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
{
|
||||||
|
"size": 1048576
|
||||||
|
}
|
||||||
8
fn/tests/fn/multi-log/Dockerfile
Normal file
8
fn/tests/fn/multi-log/Dockerfile
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
FROM funcy/go:dev as build-stage
|
||||||
|
WORKDIR /function
|
||||||
|
ADD . /src
|
||||||
|
RUN cd /src && go build -o func
|
||||||
|
FROM funcy/go
|
||||||
|
WORKDIR /function
|
||||||
|
COPY --from=build-stage /src/func /function/
|
||||||
|
ENTRYPOINT ["./func"]
|
||||||
5
fn/tests/fn/multi-log/func.yaml
Normal file
5
fn/tests/fn/multi-log/func.yaml
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
name: funcy/multi-log
|
||||||
|
version: 0.0.1
|
||||||
|
runtime: go
|
||||||
|
entrypoint: ./func
|
||||||
|
path: /multi-log
|
||||||
15
fn/tests/fn/multi-log/main.go
Normal file
15
fn/tests/fn/multi-log/main.go
Normal file
@@ -0,0 +1,15 @@
|
|||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"os"
|
||||||
|
"time"
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
fmt.Fprintln(os.Stderr, "First line")
|
||||||
|
fmt.Fprintln(os.Stdout, "Ok")
|
||||||
|
time.Sleep(3 * time.Second)
|
||||||
|
fmt.Fprintln(os.Stderr, "Second line")
|
||||||
|
}
|
||||||
8
fn/tests/fn/timeout/Dockerfile
Normal file
8
fn/tests/fn/timeout/Dockerfile
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
FROM funcy/go:dev as build-stage
|
||||||
|
WORKDIR /function
|
||||||
|
ADD . /src
|
||||||
|
RUN cd /src && go build -o func
|
||||||
|
FROM funcy/go
|
||||||
|
WORKDIR /function
|
||||||
|
COPY --from=build-stage /src/func /function/
|
||||||
|
ENTRYPOINT ["./func"]
|
||||||
5
fn/tests/fn/timeout/func.yaml
Normal file
5
fn/tests/fn/timeout/func.yaml
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
name: funcy/timeout
|
||||||
|
version: 0.0.1
|
||||||
|
runtime: go
|
||||||
|
entrypoint: ./func
|
||||||
|
path: /timeouter
|
||||||
9
fn/tests/fn/timeout/main.go
Normal file
9
fn/tests/fn/timeout/main.go
Normal file
@@ -0,0 +1,9 @@
|
|||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"time"
|
||||||
|
)
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
time.Sleep(32 * time.Second)
|
||||||
|
}
|
||||||
83
fn/tests/routes_test.go
Normal file
83
fn/tests/routes_test.go
Normal file
@@ -0,0 +1,83 @@
|
|||||||
|
package tests
|
||||||
|
|
||||||
|
import (
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"github.com/funcy/functions_go/models"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestRoutes(t *testing.T) {
|
||||||
|
s := SetupDefaultSuite()
|
||||||
|
|
||||||
|
newRouteType := "sync"
|
||||||
|
newRoutePath := "/new-hello"
|
||||||
|
|
||||||
|
CreateApp(t, s.Context, s.Client, s.AppName, map[string]string{})
|
||||||
|
|
||||||
|
t.Run("create-route", func(t *testing.T) {
|
||||||
|
CreateRoute(t, s.Context, s.Client, s.AppName, s.RoutePath, s.Image, s.RouteType,
|
||||||
|
s.RouteConfig, s.RouteHeaders)
|
||||||
|
t.Logf("Test `%v` passed.", t.Name())
|
||||||
|
})
|
||||||
|
|
||||||
|
t.Run("list-and-find-route", func(t *testing.T) {
|
||||||
|
if !assertContainsRoute(ListRoutes(t, s.Context, s.Client, s.AppName), s.RoutePath) {
|
||||||
|
t.Fatalf("Unable to find corresponding route `%v` in list", s.RoutePath)
|
||||||
|
}
|
||||||
|
t.Logf("Test `%v` passed.", t.Name())
|
||||||
|
})
|
||||||
|
|
||||||
|
t.Run("can-get-corresponding-route", func(t *testing.T) {
|
||||||
|
rObjects := []*models.Route{GetRoute(t, s.Context, s.Client, s.AppName, s.RoutePath), }
|
||||||
|
if !assertContainsRoute(rObjects, s.RoutePath) {
|
||||||
|
t.Fatalf("Unable to find corresponding route `%v` in list", s.RoutePath)
|
||||||
|
}
|
||||||
|
t.Logf("Test `%v` passed.", t.Name())
|
||||||
|
})
|
||||||
|
|
||||||
|
t.Run("can-update-route-info", func(t *testing.T) {
|
||||||
|
routeResp, err := UpdateRoute(
|
||||||
|
t, s.Context, s.Client,
|
||||||
|
s.AppName, s.RoutePath,
|
||||||
|
s.Image, newRouteType, s.Format,
|
||||||
|
s.Memory, s.RouteConfig, s.RouteHeaders, "")
|
||||||
|
|
||||||
|
CheckRouteResponseError(t, err)
|
||||||
|
assertRouteFields(t, routeResp.Payload.Route, s.RoutePath, s.Image, newRouteType)
|
||||||
|
|
||||||
|
t.Logf("Test `%v` passed.", t.Name())
|
||||||
|
})
|
||||||
|
|
||||||
|
t.Run("fail-to-update-route-path", func(t *testing.T) {
|
||||||
|
_, err := UpdateRoute(
|
||||||
|
t, s.Context, s.Client,
|
||||||
|
s.AppName, s.RoutePath,
|
||||||
|
s.Image, s.RouteType, s.Format,
|
||||||
|
s.Memory, s.RouteConfig, s.RouteHeaders, newRoutePath)
|
||||||
|
if err == nil {
|
||||||
|
t.Fatalf("Route path suppose to be immutable, but it's not.")
|
||||||
|
}
|
||||||
|
t.Logf("Test `%v` passed.", t.Name())
|
||||||
|
})
|
||||||
|
|
||||||
|
t.Run("create-route-duplicate", func(t *testing.T) {
|
||||||
|
_, err := createRoute(s.Context, s.Client, s.AppName, s.Image, s.RoutePath, newRouteType, s.RouteConfig, s.RouteHeaders)
|
||||||
|
if err == nil {
|
||||||
|
t.Fatalf("Route duplicate error should appear, but it didn't")
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
t.Run("can-delete-route", func(t *testing.T) {
|
||||||
|
DeleteRoute(t, s.Context, s.Client, s.AppName, s.RoutePath)
|
||||||
|
t.Logf("Test `%v` passed.", t.Name())
|
||||||
|
})
|
||||||
|
|
||||||
|
t.Run("fail-to-delete-missing-route", func(t *testing.T) {
|
||||||
|
_, err := deleteRoute(s.Context, s.Client, s.AppName, "dummy-route")
|
||||||
|
if err == nil {
|
||||||
|
t.Fatal("Delete from missing route must fail.")
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
DeleteApp(t, s.Context, s.Client, s.AppName)
|
||||||
|
}
|
||||||
388
fn/tests/utils.go
Normal file
388
fn/tests/utils.go
Normal file
@@ -0,0 +1,388 @@
|
|||||||
|
package tests
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"strings"
|
||||||
|
"time"
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
fn "github.com/funcy/functions_go/client"
|
||||||
|
"github.com/funcy/functions_go/models"
|
||||||
|
"github.com/funcy/functions_go/client/apps"
|
||||||
|
"gitlab-odx.oracle.com/odx/functions/fn/client"
|
||||||
|
"github.com/funcy/functions_go/client/routes"
|
||||||
|
)
|
||||||
|
|
||||||
|
type SuiteSetup struct {
|
||||||
|
Context context.Context
|
||||||
|
Client *fn.Functions
|
||||||
|
AppName string
|
||||||
|
RoutePath string
|
||||||
|
Image string
|
||||||
|
RouteType string
|
||||||
|
Format string
|
||||||
|
Memory int64
|
||||||
|
RouteConfig map[string]string
|
||||||
|
RouteHeaders map[string][]string
|
||||||
|
}
|
||||||
|
|
||||||
|
func SetupDefaultSuite() *SuiteSetup {
|
||||||
|
return &SuiteSetup{
|
||||||
|
Context: context.Background(),
|
||||||
|
Client: client.APIClient(),
|
||||||
|
AppName: "test-app",
|
||||||
|
RoutePath: "/hello",
|
||||||
|
Image: "funcy/hello",
|
||||||
|
Format: "default",
|
||||||
|
RouteType: "async",
|
||||||
|
RouteConfig: map[string]string{},
|
||||||
|
RouteHeaders: map[string][]string{},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
func CheckAppResponseError(t *testing.T, err error) {
|
||||||
|
if err != nil {
|
||||||
|
switch err.(type) {
|
||||||
|
|
||||||
|
case *apps.DeleteAppsAppDefault:
|
||||||
|
msg := err.(*apps.DeleteAppsAppDefault).Payload.Error.Message
|
||||||
|
code := err.(*apps.DeleteAppsAppDefault).Code()
|
||||||
|
t.Fatalf("Unexpected error occurred: %v. Status code: %v", msg, code)
|
||||||
|
return
|
||||||
|
|
||||||
|
case *apps.PostAppsDefault:
|
||||||
|
msg := err.(*apps.PostAppsDefault).Payload.Error.Message
|
||||||
|
code := err.(*apps.DeleteAppsAppDefault).Code()
|
||||||
|
t.Fatalf("Unexpected error occurred: %v. Status code: %v", msg, code)
|
||||||
|
return
|
||||||
|
|
||||||
|
case *apps.GetAppsAppNotFound:
|
||||||
|
msg := err.(*apps.GetAppsAppNotFound).Payload.Error.Message
|
||||||
|
if !strings.Contains("App not found", msg) {
|
||||||
|
t.Fatalf("Unexpected error occurred: %v", msg)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
return
|
||||||
|
|
||||||
|
case *apps.GetAppsAppDefault:
|
||||||
|
msg := err.(*apps.GetAppsAppDefault).Payload.Error.Message
|
||||||
|
code := err.(*apps.GetAppsAppDefault).Code()
|
||||||
|
t.Fatalf("Unexpected error occurred: %v. Status code: %v", msg, code)
|
||||||
|
return
|
||||||
|
|
||||||
|
case *apps.PatchAppsAppDefault:
|
||||||
|
msg := err.(*apps.PatchAppsAppDefault).Payload.Error.Message
|
||||||
|
code := err.(*apps.PatchAppsAppDefault).Code()
|
||||||
|
t.Fatalf("Unexpected error occurred: %v. Status code: %v", msg, code)
|
||||||
|
return
|
||||||
|
|
||||||
|
case *apps.PatchAppsAppNotFound:
|
||||||
|
msg := err.(*apps.PatchAppsAppNotFound).Payload.Error.Message
|
||||||
|
t.Fatalf("Unexpected error occurred: %v.", msg)
|
||||||
|
return
|
||||||
|
|
||||||
|
case *apps.PatchAppsAppBadRequest:
|
||||||
|
msg := err.(*apps.PatchAppsAppBadRequest).Payload.Error.Message
|
||||||
|
t.Fatalf("Unexpected error occurred: %v.", msg)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
t.Fatalf("Unable to determine type of error: %s", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
func CreateAppNoAssert(ctx context.Context, fnclient *fn.Functions, appName string, config map[string]string) (*apps.PostAppsOK, error){
|
||||||
|
cfg := &apps.PostAppsParams{
|
||||||
|
Body: &models.AppWrapper{
|
||||||
|
App: &models.App{
|
||||||
|
Config: config,
|
||||||
|
Name: appName,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
Context: ctx,
|
||||||
|
}
|
||||||
|
cfg.WithTimeout(time.Second * 60)
|
||||||
|
return fnclient.Apps.PostApps(cfg)
|
||||||
|
}
|
||||||
|
|
||||||
|
func CreateApp(t *testing.T, ctx context.Context, fnclient *fn.Functions, appName string, config map[string]string) {
|
||||||
|
appPayload, err := CreateAppNoAssert(ctx, fnclient, appName, config)
|
||||||
|
CheckAppResponseError(t, err)
|
||||||
|
if !strings.Contains(appName, appPayload.Payload.App.Name) {
|
||||||
|
t.Fatalf("App name mismatch.\nExpected: %v\nActual: %v",
|
||||||
|
appName, appPayload.Payload.App.Name)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func UpdateApp(t *testing.T, ctx context.Context, fnclient *fn.Functions ,appName string, config map[string]string) *apps.PatchAppsAppOK {
|
||||||
|
CreateApp(t, ctx, fnclient, appName, map[string]string{"A": "a"})
|
||||||
|
cfg := &apps.PatchAppsAppParams{
|
||||||
|
App: appName,
|
||||||
|
Body: &models.AppWrapper{
|
||||||
|
App: &models.App{
|
||||||
|
Config: config,
|
||||||
|
Name: "",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
Context: ctx,
|
||||||
|
}
|
||||||
|
appPayload, err := fnclient.Apps.PatchAppsApp(cfg)
|
||||||
|
CheckAppResponseError(t, err)
|
||||||
|
return appPayload
|
||||||
|
}
|
||||||
|
|
||||||
|
func DeleteApp(t *testing.T, ctx context.Context, fnclient *fn.Functions, appName string) {
|
||||||
|
cfg := &apps.DeleteAppsAppParams{
|
||||||
|
App: appName,
|
||||||
|
Context: ctx,
|
||||||
|
}
|
||||||
|
cfg.WithTimeout(time.Second * 60)
|
||||||
|
_, err := fnclient.Apps.DeleteAppsApp(cfg)
|
||||||
|
CheckAppResponseError(t, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
func CheckRouteResponseError(t *testing.T, err error) {
|
||||||
|
if err != nil {
|
||||||
|
switch err.(type) {
|
||||||
|
|
||||||
|
case *routes.PostAppsAppRoutesDefault:
|
||||||
|
msg := err.(*routes.PostAppsAppRoutesDefault).Payload.Error.Message
|
||||||
|
code := err.(*routes.PostAppsAppRoutesDefault).Code()
|
||||||
|
t.Fatalf("Unexpected error occurred: %v. Status code: %v", msg, code)
|
||||||
|
return
|
||||||
|
|
||||||
|
case *routes.PostAppsAppRoutesBadRequest:
|
||||||
|
msg := err.(*routes.PostAppsAppRoutesBadRequest).Payload.Error.Message
|
||||||
|
t.Fatalf("Unexpected error occurred: %v.", msg)
|
||||||
|
return
|
||||||
|
|
||||||
|
case *routes.PostAppsAppRoutesConflict:
|
||||||
|
msg := err.(*routes.PostAppsAppRoutesConflict).Payload.Error.Message
|
||||||
|
t.Fatalf("Unexpected error occurred: %v.", msg)
|
||||||
|
return
|
||||||
|
|
||||||
|
case *routes.GetAppsAppRoutesRouteNotFound:
|
||||||
|
msg := err.(*routes.GetAppsAppRoutesRouteNotFound).Payload.Error.Message
|
||||||
|
t.Fatalf("Unexpected error occurred: %v.", msg)
|
||||||
|
return
|
||||||
|
|
||||||
|
case *routes.GetAppsAppRoutesRouteDefault:
|
||||||
|
msg := err.(*routes.GetAppsAppRoutesRouteDefault).Payload.Error.Message
|
||||||
|
code := err.(*routes.GetAppsAppRoutesRouteDefault).Code()
|
||||||
|
t.Fatalf("Unexpected error occurred: %v. Status code: %v", msg, code)
|
||||||
|
return
|
||||||
|
|
||||||
|
case *routes.DeleteAppsAppRoutesRouteNotFound:
|
||||||
|
msg := err.(*routes.DeleteAppsAppRoutesRouteNotFound).Payload.Error.Message
|
||||||
|
t.Fatalf("Unexpected error occurred: %v.", msg)
|
||||||
|
return
|
||||||
|
|
||||||
|
case *routes.DeleteAppsAppRoutesRouteDefault:
|
||||||
|
msg := err.(*routes.DeleteAppsAppRoutesRouteDefault).Payload.Error.Message
|
||||||
|
code := err.(*routes.DeleteAppsAppRoutesRouteDefault).Code()
|
||||||
|
t.Fatalf("Unexpected error occurred: %v. Status code: %v", msg, code)
|
||||||
|
return
|
||||||
|
case *routes.GetAppsAppRoutesNotFound:
|
||||||
|
msg := err.(*routes.GetAppsAppRoutesNotFound).Payload.Error.Message
|
||||||
|
t.Fatalf("Unexpected error occurred: %v.", msg)
|
||||||
|
return
|
||||||
|
|
||||||
|
case *routes.GetAppsAppRoutesDefault:
|
||||||
|
msg := err.(*routes.GetAppsAppRoutesDefault).Payload.Error.Message
|
||||||
|
code := err.(*routes.GetAppsAppRoutesDefault).Code()
|
||||||
|
t.Fatalf("Unexpected error occurred: %v. Status code: %v", msg, code)
|
||||||
|
return
|
||||||
|
|
||||||
|
case *routes.PatchAppsAppRoutesRouteBadRequest:
|
||||||
|
msg := err.(*routes.PatchAppsAppRoutesRouteBadRequest).Payload.Error.Message
|
||||||
|
t.Fatalf("Unexpected error occurred: %v.", msg)
|
||||||
|
return
|
||||||
|
|
||||||
|
case *routes.PatchAppsAppRoutesRouteNotFound:
|
||||||
|
msg := err.(*routes.PatchAppsAppRoutesRouteNotFound).Payload.Error.Message
|
||||||
|
t.Fatalf("Unexpected error occurred: %v.", msg)
|
||||||
|
return
|
||||||
|
|
||||||
|
case *routes.PatchAppsAppRoutesRouteDefault:
|
||||||
|
msg := err.(*routes.PatchAppsAppRoutesRouteDefault).Payload.Error.Message
|
||||||
|
code := err.(*routes.PatchAppsAppRoutesRouteDefault).Code()
|
||||||
|
t.Fatalf("Unexpected error occurred: %v. Status code: %v", msg, code)
|
||||||
|
return
|
||||||
|
|
||||||
|
}
|
||||||
|
t.Fatalf("Unable to determine type of error: %s", err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func logRoute(t *testing.T, routeObject *models.Route) {
|
||||||
|
t.Logf("Route path: %v", routeObject.Path)
|
||||||
|
t.Logf("Route image: %v", routeObject.Image)
|
||||||
|
t.Logf("Route type: %v", routeObject.Type)
|
||||||
|
t.Logf("Route timeout: %vs", *routeObject.Timeout)
|
||||||
|
t.Logf("Route idle timeout: %vs", *routeObject.IDLETimeout)
|
||||||
|
}
|
||||||
|
|
||||||
|
func assertRouteFields(t *testing.T, routeObject *models.Route, path, image, routeType string) {
|
||||||
|
|
||||||
|
logRoute(t, routeObject)
|
||||||
|
rPath := routeObject.Path
|
||||||
|
rImage := routeObject.Image
|
||||||
|
rType := routeObject.Type
|
||||||
|
rTimeout := *routeObject.Timeout
|
||||||
|
rIdleTimeout := *routeObject.IDLETimeout
|
||||||
|
if rPath != path {
|
||||||
|
t.Fatalf("Route path mismatch. Expected: %v. Actual: %v", path, rPath)
|
||||||
|
}
|
||||||
|
if rImage != image {
|
||||||
|
t.Fatalf("Route image mismatch. Expected: %v. Actual: %v", image, rImage)
|
||||||
|
}
|
||||||
|
if rType != routeType {
|
||||||
|
t.Fatalf("Route type mismatch. Expected: %v. Actual: %v", routeType, rType)
|
||||||
|
}
|
||||||
|
if rTimeout == 0 {
|
||||||
|
t.Fatal("Route timeout should have default value of 30 seconds, but got 0 seconds")
|
||||||
|
}
|
||||||
|
if rIdleTimeout == 0 {
|
||||||
|
t.Fatal("Route idle timeout should have default value of 30 seconds, but got 0 seconds")
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
func createRoute(ctx context.Context, fnclient *fn.Functions, appName, image, routePath, routeType string, routeConfig map[string]string, headers map[string][]string) (*routes.PostAppsAppRoutesOK, error) {
|
||||||
|
cfg := &routes.PostAppsAppRoutesParams{
|
||||||
|
App: appName,
|
||||||
|
Body: &models.RouteWrapper{
|
||||||
|
Route: &models.Route{
|
||||||
|
Config: routeConfig,
|
||||||
|
Headers: headers,
|
||||||
|
Image: image,
|
||||||
|
Path: routePath,
|
||||||
|
Type: routeType,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
Context: ctx,
|
||||||
|
}
|
||||||
|
cfg.WithTimeout(time.Second * 60)
|
||||||
|
return fnclient.Routes.PostAppsAppRoutes(cfg)
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
func CreateRoute(t *testing.T, ctx context.Context, fnclient *fn.Functions, appName, routePath, image, routeType string, routeConfig map[string]string, headers map[string][]string) {
|
||||||
|
routeResponse, err := createRoute(ctx, fnclient, appName, image, routePath, routeType, routeConfig, headers)
|
||||||
|
CheckRouteResponseError(t, err)
|
||||||
|
|
||||||
|
assertRouteFields(t, routeResponse.Payload.Route, routePath, image, routeType)
|
||||||
|
}
|
||||||
|
|
||||||
|
func deleteRoute(ctx context.Context, fnclient *fn.Functions, appName, routePath string) (*routes.DeleteAppsAppRoutesRouteOK, error){
|
||||||
|
cfg := &routes.DeleteAppsAppRoutesRouteParams{
|
||||||
|
App: appName,
|
||||||
|
Route: routePath,
|
||||||
|
Context: ctx,
|
||||||
|
}
|
||||||
|
cfg.WithTimeout(time.Second * 60)
|
||||||
|
return fnclient.Routes.DeleteAppsAppRoutesRoute(cfg)
|
||||||
|
}
|
||||||
|
|
||||||
|
func DeleteRoute(t *testing.T, ctx context.Context, fnclient *fn.Functions, appName, routePath string) {
|
||||||
|
_, err := deleteRoute(ctx, fnclient, appName, routePath)
|
||||||
|
CheckRouteResponseError(t, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
func ListRoutes(t *testing.T, ctx context.Context, fnclient *fn.Functions, appName string) []*models.Route {
|
||||||
|
cfg := &routes.GetAppsAppRoutesParams{
|
||||||
|
App: appName,
|
||||||
|
Context: ctx,
|
||||||
|
}
|
||||||
|
cfg.WithTimeout(time.Second * 60)
|
||||||
|
routesResponse, err := fnclient.Routes.GetAppsAppRoutes(cfg)
|
||||||
|
CheckRouteResponseError(t, err)
|
||||||
|
return routesResponse.Payload.Routes
|
||||||
|
}
|
||||||
|
|
||||||
|
func GetRoute(t *testing.T, ctx context.Context, fnclient *fn.Functions, appName, routePath string) *models.Route{
|
||||||
|
cfg := &routes.GetAppsAppRoutesRouteParams{
|
||||||
|
App: appName,
|
||||||
|
Route: routePath,
|
||||||
|
Context: ctx,
|
||||||
|
}
|
||||||
|
cfg.WithTimeout(time.Second * 60)
|
||||||
|
routeResponse, err := fnclient.Routes.GetAppsAppRoutesRoute(cfg)
|
||||||
|
CheckRouteResponseError(t, err)
|
||||||
|
return routeResponse.Payload.Route
|
||||||
|
}
|
||||||
|
|
||||||
|
func UpdateRoute(t *testing.T, ctx context.Context, fnclient *fn.Functions, appName, routePath, image, routeType, format string, memory int64, routeConfig map[string]string, headers map[string][]string, newRoutePath string) (*routes.PatchAppsAppRoutesRouteOK, error){
|
||||||
|
|
||||||
|
routeObject := GetRoute(t, ctx, fnclient, appName, routePath)
|
||||||
|
if routeObject.Config == nil {
|
||||||
|
routeObject.Config = map[string]string{}
|
||||||
|
}
|
||||||
|
|
||||||
|
if routeObject.Headers == nil {
|
||||||
|
routeObject.Headers = map[string][]string{}
|
||||||
|
}
|
||||||
|
logRoute(t, routeObject)
|
||||||
|
|
||||||
|
routeObject.Path = ""
|
||||||
|
if newRoutePath != "" {
|
||||||
|
routeObject.Path = newRoutePath
|
||||||
|
}
|
||||||
|
|
||||||
|
if routeConfig != nil {
|
||||||
|
for k, v := range routeConfig {
|
||||||
|
if string(k[0]) == "-" {
|
||||||
|
delete(routeObject.Config, string(k[1:]))
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
routeObject.Config[k] = v
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if headers != nil {
|
||||||
|
for k, v := range headers {
|
||||||
|
if string(k[0]) == "-" {
|
||||||
|
delete(routeObject.Headers, k)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
routeObject.Headers[k] = v
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if image != "" {
|
||||||
|
routeObject.Image = image
|
||||||
|
}
|
||||||
|
if format != "" {
|
||||||
|
routeObject.Format = format
|
||||||
|
}
|
||||||
|
if routeType != "" {
|
||||||
|
routeObject.Type = routeType
|
||||||
|
}
|
||||||
|
if memory > 0 {
|
||||||
|
routeObject.Memory = memory
|
||||||
|
}
|
||||||
|
|
||||||
|
cfg := &routes.PatchAppsAppRoutesRouteParams{
|
||||||
|
App: appName,
|
||||||
|
Context: ctx,
|
||||||
|
Body: &models.RouteWrapper{
|
||||||
|
Route: routeObject,
|
||||||
|
},
|
||||||
|
Route: routePath,
|
||||||
|
}
|
||||||
|
cfg.WithTimeout(time.Second * 60)
|
||||||
|
|
||||||
|
t.Log("Calling update")
|
||||||
|
|
||||||
|
return fnclient.Routes.PatchAppsAppRoutesRoute(cfg)
|
||||||
|
}
|
||||||
|
|
||||||
|
func assertContainsRoute(routeModels []*models.Route, expectedRoute string) bool {
|
||||||
|
for _, r := range routeModels {
|
||||||
|
if r.Path == expectedRoute {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user