Improving API tests

This commit is contained in:
Denis Makogon
2017-07-25 10:29:20 -07:00
committed by James Jeffrey
parent e0569192ee
commit 5b41fe2dc7
10 changed files with 686 additions and 565 deletions

View File

@@ -39,9 +39,7 @@ test_job:
integration_tests: integration_tests:
stage: test stage: test
script: script:
- go build -o functions-alpine - DOCKER_LOCATION=container_ip make docker-test-run-with-sqlite3
- docker build -t funcy/functions:latest .
- make docker-test-run-with-sqlite3
deploy_job: deploy_job:
only: only:

View File

@@ -41,13 +41,13 @@ docker-run: docker-build
docker run --rm --privileged -it -e NO_PROXY -e HTTP_PROXY -e LOG_LEVEL=debug -e "DB_URL=sqlite3:///app/data/fn.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=sqlite3:///app/data/fn.db" -v ${CURDIR}/data:/app/data -p 8080:8080 funcy/functions
docker-test-run-with-sqlite3: docker-test-run-with-sqlite3:
./api_test.sh sqlite3 ./api_test.sh sqlite3 4
docker-test-run-with-mysql: docker-test-run-with-mysql:
./api_test.sh mysql ./api_test.sh mysql 4
docker-test-run-with-postgres: docker-test-run-with-postgres:
./api_test.sh postgres ./api_test.sh postgres 4
docker-test: docker-test:
docker run -ti --privileged --rm -e LOG_LEVEL=debug \ docker run -ti --privileged --rm -e LOG_LEVEL=debug \

View File

@@ -1,61 +1,52 @@
set -ex set -ex
function host {
case ${DOCKER_LOCATION:-localhost} in
localhost)
echo "localhost"
;;
docker_ip)
if [[ ! -z ${DOCKER_HOST} ]]
then
DOCKER_IP=`echo ${DOCKER_HOST} | awk -F/ '{print $3}'| awk -F: '{print $1}'`
fi
echo ${DOCKER_IP}
;;
container_ip)
echo "$(docker inspect -f '{{.NetworkSettings.IPAddress}}' ${1})"
;;
esac
}
case "$1" in case "$1" in
"sqlite3" ) "sqlite3" )
# docker rm -fv func-server || echo No prev func-server container rm -fr /tmp/fn_integration_tests.db
# touch /tmp/fn_integration_tests.db
# 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 DB_URL="sqlite3:///tmp/fn_integration_tests.db"
# sleep 10
# docker logs func-server
# docker inspect -f '{{.NetworkSettings.IPAddress}}' func-server
;; ;;
"mysql" ) "mysql" )
docker rm -fv func-mysql-test || echo No prev mysql test db container DB_CONTAINER="func-mysql-test"
docker rm -fv func-server || echo No prev func-server container docker rm -fv ${DB_CONTAINER} || echo No prev mysql test db container
docker run --name ${DB_CONTAINER} -p 3306:3306 -e MYSQL_DATABASE=funcs -e MYSQL_ROOT_PASSWORD=root -d mysql
docker run --name func-mysql-test -p 3306:3306 -e MYSQL_DATABASE=funcs -e MYSQL_ROOT_PASSWORD=root -d mysql sleep 15
sleep 30 MYSQL_HOST=`host ${DB_CONTAINER}`
docker logs func-mysql-test MYSQL_PORT=3306
export MYSQL_HOST="$(docker inspect -f '{{.NetworkSettings.IPAddress}}' func-mysql-test)" DB_URL="mysql://root:root@tcp(${MYSQL_HOST}:${MYSQL_PORT})/funcs"
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
docker logs func-server
docker inspect -f '{{.NetworkSettings.IPAddress}}' func-mysql-test
docker inspect -f '{{.NetworkSettings.IPAddress}}' func-server
;; ;;
"postgres" ) "postgres" )
docker rm -fv func-postgres-test || echo No prev test db container DB_CONTAINER="func-postgres-test"
docker rm -fv func-server || echo No prev func-server container docker rm -fv ${DB_CONTAINER} || echo No prev test db container
docker run --name ${DB_CONTAINER} -e "POSTGRES_DB=funcs" -e "POSTGRES_PASSWORD=root" -p 5432:5432 -d postgres
docker run --name func-postgres-test -e "POSTGRES_DB=funcs" -e "POSTGRES_PASSWORD=root" -p 5432:5432 -d postgres sleep 15
sleep 30 POSTGRES_HOST=`host ${DB_CONTAINER}`
docker logs func-postgres-test POSTGRES_PORT=5432
export POSTGRES_HOST="$(docker inspect -f '{{.NetworkSettings.IPAddress}}' func-postgres-test)" DB_URL="postgres://postgres:root@${POSTGRES_HOST}:${POSTGRES_PORT}/funcs?sslmode=disable"
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:root@${POSTGRES_HOST}:${POSTGRES_PORT}/funcs?sslmode=disable" -p 8080:8080 -v /var/run/docker.sock:/var/run/docker.sock funcy/functions
docker logs func-server
docker inspect -f '{{.NetworkSettings.IPAddress}}' func-postgres-test
docker inspect -f '{{.NetworkSettings.IPAddress}}' func-server
;; ;;
esac esac
case ${DOCKER_LOCATION:-localhost} in cd test/fn-api-tests && API_URL="http://localhost:8080" DB_URL=${DB_URL} go test -v -parallel ${2:-1} ./...; cd ../../
localhost)
cd test/fn-api-tests && API_URL="http://localhost:8080" go test -v ./...; cd ../../
;;
docker_ip)
if [[ ! -z ${DOCKER_HOST} ]]
then
DOCKER_IP=`echo ${DOCKER_HOST} | awk -F/ '{print $3}'| awk -F: '{print $1}'`
fi
cd test/fn-api-tests && API_URL="http://${DOCKER_IP:-localhost}:8080" go test -v ./...; cd ../../
;;
container_ip)
cd test/fn-api-tests && API_URL="http://"$(docker inspect -f '{{.NetworkSettings.IPAddress}}' func-server)":8080" go test -v ./...; cd ../../
;;
esac

View File

@@ -0,0 +1,100 @@
package tests
import (
"context"
"strings"
"testing"
"time"
"github.com/funcy/functions_go/client"
"github.com/funcy/functions_go/client/apps"
"github.com/funcy/functions_go/models"
)
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.Errorf("Unexpected error occurred: %v. Status code: %v", msg, code)
case *apps.PostAppsDefault:
msg := err.(*apps.PostAppsDefault).Payload.Error.Message
code := err.(*apps.PostAppsDefault).Code()
t.Errorf("Unexpected error occurred: %v. Status code: %v", msg, code)
case *apps.GetAppsAppNotFound:
msg := err.(*apps.GetAppsAppNotFound).Payload.Error.Message
if !strings.Contains("App not found", msg) {
t.Errorf("Unexpected error occurred: %v", msg)
}
case *apps.GetAppsAppDefault:
msg := err.(*apps.GetAppsAppDefault).Payload.Error.Message
code := err.(*apps.GetAppsAppDefault).Code()
t.Errorf("Unexpected error occurred: %v. Status code: %v", msg, code)
case *apps.PatchAppsAppDefault:
msg := err.(*apps.PatchAppsAppDefault).Payload.Error.Message
code := err.(*apps.PatchAppsAppDefault).Code()
t.Errorf("Unexpected error occurred: %v. Status code: %v", msg, code)
case *apps.PatchAppsAppNotFound:
msg := err.(*apps.PatchAppsAppNotFound).Payload.Error.Message
t.Errorf("Unexpected error occurred: %v.", msg)
case *apps.PatchAppsAppBadRequest:
msg := err.(*apps.PatchAppsAppBadRequest).Payload.Error.Message
t.Errorf("Unexpected error occurred: %v.", msg)
default:
t.Errorf("Unable to determine type of error: %s", err)
}
}
}
func CreateAppNoAssert(ctx context.Context, fnclient *client.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 *client.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.Errorf("App name mismatch.\nExpected: %v\nActual: %v",
appName, appPayload.Payload.App.Name)
}
}
func UpdateApp(t *testing.T, ctx context.Context, fnclient *client.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 *client.Functions, appName string) {
cfg := &apps.DeleteAppsAppParams{
App: appName,
Context: ctx,
}
cfg.WithTimeout(time.Second * 60)
_, err := fnclient.Apps.DeleteAppsApp(cfg)
CheckAppResponseError(t, err)
}

View File

@@ -10,24 +10,10 @@ import (
) )
func TestApps(t *testing.T) { 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) { t.Run("app-not-found-test", func(t *testing.T) {
t.Parallel()
s := SetupDefaultSuite()
cfg := &apps.GetAppsAppParams{ cfg := &apps.GetAppsAppParams{
App: "missing-app", App: "missing-app",
Context: s.Context, Context: s.Context,
@@ -35,25 +21,26 @@ func TestApps(t *testing.T) {
cfg.WithTimeout(time.Second * 60) cfg.WithTimeout(time.Second * 60)
_, err := s.Client.Apps.GetAppsApp(cfg) _, err := s.Client.Apps.GetAppsApp(cfg)
CheckAppResponseError(t, err) CheckAppResponseError(t, err)
t.Logf("Test `%v` passed", t.Name())
}) })
t.Run("create-app-no-config-test", func(t *testing.T) { t.Run("create-app-and-delete-no-config-test", func(t *testing.T) {
t.Parallel()
s := SetupDefaultSuite()
CreateApp(t, s.Context, s.Client, s.AppName, map[string]string{}) 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) 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) { t.Run("create-app-with-config-test", func(t *testing.T) {
t.Parallel()
s := SetupDefaultSuite()
CreateApp(t, s.Context, s.Client, s.AppName, map[string]string{"A": "a"}) CreateApp(t, s.Context, s.Client, s.AppName, map[string]string{"A": "a"})
t.Logf("Test `%v` passed.", t.Name()) DeleteApp(t, s.Context, s.Client, s.AppName)
}) })
t.Run("inspect-app-with-config-test", func(t *testing.T) { t.Run("inspect-app-with-config-test", func(t *testing.T) {
t.Parallel()
s := SetupDefaultSuite()
CreateApp(t, s.Context, s.Client, s.AppName, map[string]string{"A": "a"})
cfg := &apps.GetAppsAppParams{ cfg := &apps.GetAppsAppParams{
Context: s.Context, Context: s.Context,
App: s.AppName, App: s.AppName,
@@ -63,54 +50,56 @@ func TestApps(t *testing.T) {
appBody := appPayload.Payload.App appBody := appPayload.Payload.App
val, ok := appBody.Config["A"] val, ok := appBody.Config["A"]
if !ok { if !ok {
t.Fatal("Error during app config inspect: config map misses required entity `A` with value `a`.") t.Error("Error during app config inspect: config map misses required entity `A` with value `a`.")
} }
if !strings.Contains("a", val) { if !strings.Contains("a", val) {
t.Fatalf("App config value is different. Expected: `a`. Actual %v", val) t.Errorf("App config value is different. Expected: `a`. Actual %v", val)
} }
DeleteApp(t, s.Context, s.Client, s.AppName) 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) { t.Run("patch-override-app-config", func(t *testing.T) {
t.Parallel()
s := SetupDefaultSuite()
config := map[string]string{ config := map[string]string{
"A": "b", "A": "b",
} }
appPayload := UpdateApp(t, s.Context, s.Client, s.AppName, config) appPayload := UpdateApp(t, s.Context, s.Client, s.AppName, config)
val, ok := appPayload.Payload.App.Config["A"] val, ok := appPayload.Payload.App.Config["A"]
if !ok { if !ok {
t.Fatal("Error during app config inspect: config map misses required entity `A` with value `a`.") t.Error("Error during app config inspect: config map misses required entity `A` with value `a`.")
} }
if !strings.Contains("b", val) { if !strings.Contains("b", val) {
t.Fatalf("App config value is different. Expected: `b`. Actual %v", val) t.Errorf("App config value is different. Expected: `b`. Actual %v", val)
} }
DeleteApp(t, s.Context, s.Client, s.AppName) 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) { t.Run("patch-add-app-config", func(t *testing.T) {
t.Parallel()
s := SetupDefaultSuite()
config := map[string]string{ config := map[string]string{
"B": "b", "B": "b",
} }
appPayload := UpdateApp(t, s.Context, s.Client, s.AppName, config) appPayload := UpdateApp(t, s.Context, s.Client, s.AppName, config)
val, ok := appPayload.Payload.App.Config["B"] val, ok := appPayload.Payload.App.Config["B"]
if !ok { if !ok {
t.Fatal("Error during app config inspect: config map misses required entity `B` with value `b`.") t.Error("Error during app config inspect: config map misses required entity `B` with value `b`.")
} }
if !strings.Contains("b", val) { if !strings.Contains("b", val) {
t.Fatalf("App config value is different. Expected: `b`. Actual %v", val) t.Errorf("App config value is different. Expected: `b`. Actual %v", val)
} }
DeleteApp(t, s.Context, s.Client, s.AppName) DeleteApp(t, s.Context, s.Client, s.AppName)
t.Logf("Test `%v` passed.", t.Name())
}) })
t.Run("crete-app-duplicate", func(t *testing.T) { t.Run("crete-app-duplicate", func(t *testing.T) {
t.Parallel()
s := SetupDefaultSuite()
CreateApp(t, s.Context, s.Client, s.AppName, map[string]string{}) CreateApp(t, s.Context, s.Client, s.AppName, map[string]string{})
_, err := CreateAppNoAssert(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()) { if reflect.TypeOf(err) != reflect.TypeOf(apps.NewPostAppsConflict()) {
CheckAppResponseError(t, err) CheckAppResponseError(t, err)
} }
DeleteApp(t, s.Context, s.Client, s.AppName) DeleteApp(t, s.Context, s.Client, s.AppName)
t.Logf("Test `%v` passed.", t.Name())
}) })
} }

View File

@@ -11,9 +11,10 @@ import (
) )
func TestCalls(t *testing.T) { func TestCalls(t *testing.T) {
s := SetupDefaultSuite()
t.Run("list-calls-for-missing-app", func(t *testing.T) { t.Run("list-calls-for-missing-app", func(t *testing.T) {
t.Parallel()
s := SetupDefaultSuite()
cfg := &call.GetAppsAppCallsRouteParams{ cfg := &call.GetAppsAppCallsRouteParams{
App: s.AppName, App: s.AppName,
Route: s.RoutePath, Route: s.RoutePath,
@@ -21,19 +22,15 @@ func TestCalls(t *testing.T) {
} }
_, err := s.Client.Call.GetAppsAppCallsRoute(cfg) _, err := s.Client.Call.GetAppsAppCallsRoute(cfg)
if err == nil { if err == nil {
t.Fatalf("Must fail with missing app error, but got %s", err) t.Errorf("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: Host(),
}
u.Path = path.Join(u.Path, "r", s.AppName, s.RoutePath)
t.Run("list-calls-for-missing-route", func(t *testing.T) { t.Run("list-calls-for-missing-route", func(t *testing.T) {
t.Parallel()
s := SetupDefaultSuite()
CreateApp(t, s.Context, s.Client, s.AppName, map[string]string{})
cfg := &call.GetAppsAppCallsRouteParams{ cfg := &call.GetAppsAppCallsRouteParams{
App: s.AppName, App: s.AppName,
Route: s.RoutePath, Route: s.RoutePath,
@@ -41,14 +38,19 @@ func TestCalls(t *testing.T) {
} }
_, err := s.Client.Call.GetAppsAppCallsRoute(cfg) _, err := s.Client.Call.GetAppsAppCallsRoute(cfg)
if err == nil { if err == nil {
t.Fatalf("Must fail with missing route error, but got %s", err) t.Errorf("Must fail with missing route error, but got %s", err)
} }
DeleteApp(t, s.Context, s.Client, s.AppName)
}) })
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) { t.Run("get-dummy-call", func(t *testing.T) {
t.Parallel()
s := SetupDefaultSuite()
CreateApp(t, s.Context, s.Client, s.AppName, map[string]string{})
CreateRoute(t, s.Context, s.Client, s.AppName, s.RoutePath, s.Image, s.RouteType,
s.RouteConfig, s.RouteHeaders)
cfg := &call.GetCallsCallParams{ cfg := &call.GetCallsCallParams{
Call: "dummy", Call: "dummy",
Context: s.Context, Context: s.Context,
@@ -56,12 +58,25 @@ func TestCalls(t *testing.T) {
cfg.WithTimeout(time.Second * 60) cfg.WithTimeout(time.Second * 60)
_, err := s.Client.Call.GetCallsCall(cfg) _, err := s.Client.Call.GetCallsCall(cfg)
if err == nil { if err == nil {
t.Fatal("Must fail because `dummy` call does not exist.") t.Error("Must fail because `dummy` call does not exist.")
} }
t.Logf("Test `%v` passed.", t.Name())
DeleteRoute(t, s.Context, s.Client, s.AppName, s.RoutePath)
DeleteApp(t, s.Context, s.Client, s.AppName)
}) })
t.Run("get-real-call", func(t *testing.T) { t.Run("get-real-call", func(t *testing.T) {
t.Parallel()
s := SetupDefaultSuite()
CreateApp(t, s.Context, s.Client, s.AppName, map[string]string{})
CreateRoute(t, s.Context, s.Client, s.AppName, s.RoutePath, s.Image, s.RouteType,
s.RouteConfig, s.RouteHeaders)
u := url.URL{
Scheme: "http",
Host: Host(),
}
u.Path = path.Join(u.Path, "r", s.AppName, s.RoutePath)
callID := CallAsync(t, u, &bytes.Buffer{}) callID := CallAsync(t, u, &bytes.Buffer{})
time.Sleep(time.Second * 5) time.Sleep(time.Second * 5)
@@ -75,13 +90,29 @@ func TestCalls(t *testing.T) {
switch err.(type) { switch err.(type) {
case *call.GetCallsCallNotFound: case *call.GetCallsCallNotFound:
msg := err.(*call.GetCallsCallNotFound).Payload.Error.Message msg := err.(*call.GetCallsCallNotFound).Payload.Error.Message
t.Fatalf("Unexpected error occurred: %v.", msg) t.Errorf("Unexpected error occurred: %v.", msg)
} }
} }
t.Logf("Test `%v` passed.", t.Name()) DeleteRoute(t, s.Context, s.Client, s.AppName, s.RoutePath)
DeleteApp(t, s.Context, s.Client, s.AppName)
}) })
t.Run("list-calls", func(t *testing.T) { t.Run("list-calls", func(t *testing.T) {
t.Parallel()
s := SetupDefaultSuite()
CreateApp(t, s.Context, s.Client, s.AppName, map[string]string{})
CreateRoute(t, s.Context, s.Client, s.AppName, s.RoutePath, s.Image, s.RouteType,
s.RouteConfig, s.RouteHeaders)
u := url.URL{
Scheme: "http",
Host: Host(),
}
u.Path = path.Join(u.Path, "r", s.AppName, s.RoutePath)
CallAsync(t, u, &bytes.Buffer{})
time.Sleep(time.Second * 8)
cfg := &call.GetAppsAppCallsRouteParams{ cfg := &call.GetAppsAppCallsRouteParams{
App: s.AppName, App: s.AppName,
Route: s.RoutePath, Route: s.RoutePath,
@@ -89,18 +120,18 @@ func TestCalls(t *testing.T) {
} }
calls, err := s.Client.Call.GetAppsAppCallsRoute(cfg) calls, err := s.Client.Call.GetAppsAppCallsRoute(cfg)
if err != nil { if err != nil {
t.Fatalf("Unexpected error: %s", err) t.Errorf("Unexpected error: %s", err)
} }
if len(calls.Payload.Calls) == 0 { if len(calls.Payload.Calls) == 0 {
t.Fatalf("Must fail. There should be at least one call to `%v` route.", s.RoutePath) t.Errorf("Must fail. There should be at least one call to `%v` route.", s.RoutePath)
} }
for _, c := range calls.Payload.Calls { for _, c := range calls.Payload.Calls {
if c.Path != s.RoutePath { if c.Path != s.RoutePath {
t.Fatalf("Call path mismatch.\n\tExpected: %v\n\tActual: %v", c.Path, s.RoutePath) t.Errorf("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)
}) })
DeleteRoute(t, s.Context, s.Client, s.AppName, s.RoutePath)
DeleteApp(t, s.Context, s.Client, s.AppName)
} }

View File

@@ -27,12 +27,12 @@ func CallAsync(t *testing.T, u url.URL, content io.Reader) string {
output := &bytes.Buffer{} output := &bytes.Buffer{}
err := CallFN(u.String(), content, output, "POST", []string{}) err := CallFN(u.String(), content, output, "POST", []string{})
if err != nil { if err != nil {
t.Fatalf("Got unexpected error: %v", err) t.Errorf("Got unexpected error: %v", err)
} }
expectedOutput := "call_id" expectedOutput := "call_id"
if !strings.Contains(output.String(), expectedOutput) { if !strings.Contains(output.String(), expectedOutput) {
t.Fatalf("Assertion error.\n\tExpected: %v\n\tActual: %v", expectedOutput, output.String()) t.Errorf("Assertion error.\n\tExpected: %v\n\tActual: %v", expectedOutput, output.String())
} }
type CallID struct { type CallID struct {
@@ -43,42 +43,55 @@ func CallAsync(t *testing.T, u url.URL, content io.Reader) string {
json.NewDecoder(output).Decode(callID) json.NewDecoder(output).Decode(callID)
if callID.CallID == "" { if callID.CallID == "" {
t.Fatalf("`call_id` not suppose to be empty string") t.Errorf("`call_id` not suppose to be empty string")
} }
t.Logf("Async execution call ID: %v", callID.CallID) t.Logf("Async execution call ID: %v", callID.CallID)
return callID.CallID return callID.CallID
} }
func TestRouteExecutions(t *testing.T) { func TestRouteExecutions(t *testing.T) {
s := SetupDefaultSuite()
newRouteType := "async" 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: Host(),
}
u.Path = path.Join(u.Path, "r", s.AppName, s.RoutePath)
t.Run("run-sync-funcy/hello-no-input", func(t *testing.T) { t.Run("run-sync-funcy/hello-no-input", func(t *testing.T) {
t.Parallel()
s := SetupDefaultSuite()
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: Host(),
}
u.Path = path.Join(u.Path, "r", s.AppName, s.RoutePath)
content := &bytes.Buffer{} content := &bytes.Buffer{}
output := &bytes.Buffer{} output := &bytes.Buffer{}
err := CallFN(u.String(), content, output, "POST", []string{}) err := CallFN(u.String(), content, output, "POST", []string{})
if err != nil { if err != nil {
t.Fatalf("Got unexpected error: %v", err) t.Errorf("Got unexpected error: %v", err)
} }
expectedOutput := "Hello World!\n" expectedOutput := "Hello World!\n"
if !strings.Contains(expectedOutput, output.String()) { if !strings.Contains(expectedOutput, output.String()) {
t.Fatalf("Assertion error.\n\tExpected: %v\n\tActual: %v", expectedOutput, output.String()) t.Errorf("Assertion error.\n\tExpected: %v\n\tActual: %v", expectedOutput, output.String())
} }
t.Logf("Test `%v` passed.", t.Name()) DeleteRoute(t, s.Context, s.Client, s.AppName, s.RoutePath)
DeleteApp(t, s.Context, s.Client, s.AppName)
}) })
t.Run("run-sync-funcy/hello-with-input", func(t *testing.T) { t.Run("run-sync-funcy/hello-with-input", func(t *testing.T) {
t.Parallel()
s := SetupDefaultSuite()
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: Host(),
}
u.Path = path.Join(u.Path, "r", s.AppName, s.RoutePath)
content := &bytes.Buffer{} content := &bytes.Buffer{}
json.NewEncoder(content).Encode(struct { json.NewEncoder(content).Encode(struct {
Name string Name string
@@ -86,29 +99,64 @@ func TestRouteExecutions(t *testing.T) {
output := &bytes.Buffer{} output := &bytes.Buffer{}
err := CallFN(u.String(), content, output, "POST", []string{}) err := CallFN(u.String(), content, output, "POST", []string{})
if err != nil { if err != nil {
t.Fatalf("Got unexpected error: %v", err) t.Errorf("Got unexpected error: %v", err)
} }
expectedOutput := "Hello John!\n" expectedOutput := "Hello John!\n"
if !strings.Contains(expectedOutput, output.String()) { if !strings.Contains(expectedOutput, output.String()) {
t.Fatalf("Assertion error.\n\tExpected: %v\n\tActual: %v", expectedOutput, output.String()) t.Errorf("Assertion error.\n\tExpected: %v\n\tActual: %v", expectedOutput, output.String())
} }
t.Logf("Test `%v` passed.", t.Name()) DeleteRoute(t, s.Context, s.Client, s.AppName, s.RoutePath)
DeleteApp(t, s.Context, s.Client, s.AppName)
}) })
_, 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) { t.Run("run-async-funcy/hello", func(t *testing.T) {
t.Parallel()
s := SetupDefaultSuite()
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: Host(),
}
u.Path = path.Join(u.Path, "r", s.AppName, s.RoutePath)
_, 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)
CallAsync(t, u, &bytes.Buffer{}) CallAsync(t, u, &bytes.Buffer{})
t.Logf("Test `%v` passed.", t.Name()) DeleteRoute(t, s.Context, s.Client, s.AppName, s.RoutePath)
DeleteApp(t, s.Context, s.Client, s.AppName)
}) })
t.Run("run-async-funcy/hello-with-status-check", func(t *testing.T) { t.Run("run-async-funcy/hello-with-status-check", func(t *testing.T) {
t.Parallel()
s := SetupDefaultSuite()
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: Host(),
}
u.Path = path.Join(u.Path, "r", s.AppName, s.RoutePath)
_, 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)
callID := CallAsync(t, u, &bytes.Buffer{}) callID := CallAsync(t, u, &bytes.Buffer{})
time.Sleep(time.Second * 10) time.Sleep(time.Second * 10)
cfg := &call.GetCallsCallParams{ cfg := &call.GetCallsCallParams{
@@ -121,35 +169,39 @@ func TestRouteExecutions(t *testing.T) {
switch err.(type) { switch err.(type) {
case *call.GetCallsCallNotFound: case *call.GetCallsCallNotFound:
msg := err.(*call.GetCallsCallNotFound).Payload.Error.Message msg := err.(*call.GetCallsCallNotFound).Payload.Error.Message
t.Fatalf("Unexpected error occurred: %v.", msg) t.Errorf("Unexpected error occurred: %v.", msg)
} }
} }
callObject := callResponse.Payload.Call callObject := callResponse.Payload.Call
if callObject.AppName != s.AppName { if callObject.AppName != s.AppName {
t.Fatalf("Call object app name mismatch.\n\tExpected: %v\n\tActual:%v", s.AppName, callObject.AppName) t.Errorf("Call object app name mismatch.\n\tExpected: %v\n\tActual:%v", s.AppName, callObject.AppName)
} }
if callObject.ID != callID { if callObject.ID != callID {
t.Fatalf("Call object ID mismatch.\n\tExpected: %v\n\tActual:%v", callID, callObject.ID) t.Errorf("Call object ID mismatch.\n\tExpected: %v\n\tActual:%v", callID, callObject.ID)
} }
if callObject.Path != s.RoutePath { if callObject.Path != s.RoutePath {
t.Fatalf("Call object route path mismatch.\n\tExpected: %v\n\tActual:%v", s.RoutePath, callObject.Path) t.Errorf("Call object route path mismatch.\n\tExpected: %v\n\tActual:%v", s.RoutePath, callObject.Path)
} }
if callObject.Status != "success" { if callObject.Status != "success" {
t.Fatalf("Call object status mismatch.\n\tExpected: %v\n\tActual:%v", "success", callObject.Status) t.Errorf("Call object status mismatch.\n\tExpected: %v\n\tActual:%v", "success", callObject.Status)
} }
DeleteRoute(t, s.Context, s.Client, s.AppName, s.RoutePath)
DeleteApp(t, s.Context, s.Client, s.AppName)
}) })
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) { t.Run("exec-timeout-test", func(t *testing.T) {
t.Parallel()
s := SetupDefaultSuite()
routePath := "/" + RandStringBytes(10)
image := "funcy/timeout:0.0.1"
routeType := "sync"
CreateApp(t, s.Context, s.Client, s.AppName, map[string]string{})
CreateRoute(t, s.Context, s.Client, s.AppName, routePath, image, routeType,
s.RouteConfig, s.RouteHeaders)
u := url.URL{ u := url.URL{
Scheme: "http", Scheme: "http",
@@ -166,7 +218,7 @@ func TestRouteExecutions(t *testing.T) {
CallFN(u.String(), content, output, "POST", []string{}) CallFN(u.String(), content, output, "POST", []string{})
if !strings.Contains(output.String(), "Timed out") { if !strings.Contains(output.String(), "Timed out") {
t.Fatalf("Must fail because of timeout, but got error message: %v", output.String()) t.Errorf("Must fail because of timeout, but got error message: %v", output.String())
} }
tB := &TimeoutBody{} tB := &TimeoutBody{}
@@ -179,24 +231,28 @@ func TestRouteExecutions(t *testing.T) {
cfg.WithTimeout(time.Second * 60) cfg.WithTimeout(time.Second * 60)
callObj, err := s.Client.Call.GetCallsCall(cfg) callObj, err := s.Client.Call.GetCallsCall(cfg)
if err != nil { if err != nil {
t.Fatalf("Unexpected error: %s", err) t.Errorf("Unexpected error: %s", err)
} }
if !strings.Contains("timeout", callObj.Payload.Call.Status) { if !strings.Contains("timeout", callObj.Payload.Call.Status) {
t.Fatalf("Call status mismatch.\n\tExpected: %v\n\tActual: %v", t.Errorf("Call status mismatch.\n\tExpected: %v\n\tActual: %v",
"output", "callObj.Payload.Call.Status") "output", "callObj.Payload.Call.Status")
} }
t.Logf("Test `%v` passed.", t.Name()) DeleteRoute(t, s.Context, s.Client, s.AppName, routePath)
DeleteApp(t, s.Context, s.Client, s.AppName)
}) })
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) { t.Run("exec-multi-log-test", func(t *testing.T) {
t.Parallel()
s := SetupDefaultSuite()
routePath := "/multi-log"
image := "funcy/multi-log:0.0.1"
routeType := "async"
CreateApp(t, s.Context, s.Client, s.AppName, map[string]string{})
CreateRoute(t, s.Context, s.Client, s.AppName, routePath, image, routeType,
s.RouteConfig, s.RouteHeaders)
u := url.URL{ u := url.URL{
Scheme: "http", Scheme: "http",
Host: Host(), Host: Host(),
@@ -213,30 +269,34 @@ func TestRouteExecutions(t *testing.T) {
logObj, err := s.Client.Operations.GetCallsCallLog(cfg) logObj, err := s.Client.Operations.GetCallsCallLog(cfg)
if err != nil { if err != nil {
t.Fatalf("Unexpected error: %s", err) t.Errorf("Unexpected error: %s", err)
} }
if logObj.Payload.Log.Log == "" { if logObj.Payload.Log.Log == "" {
t.Fatalf("Log entry must not be empty!") t.Errorf("Log entry must not be empty!")
} }
if !strings.Contains(logObj.Payload.Log.Log, "First line") { if !strings.Contains(logObj.Payload.Log.Log, "First line") {
t.Fatalf("Log entry must contain `First line` "+ t.Errorf("Log entry must contain `First line` "+
"string, but got: %v", logObj.Payload.Log.Log) "string, but got: %v", logObj.Payload.Log.Log)
} }
if !strings.Contains(logObj.Payload.Log.Log, "Second line") { if !strings.Contains(logObj.Payload.Log.Log, "Second line") {
t.Fatalf("Log entry must contain `Second line` "+ t.Errorf("Log entry must contain `Second line` "+
"string, but got: %v", logObj.Payload.Log.Log) "string, but got: %v", logObj.Payload.Log.Log)
} }
DeleteRoute(t, s.Context, s.Client, s.AppName, routePath)
DeleteApp(t, s.Context, s.Client, s.AppName)
}) })
DeleteRoute(t, s.Context, s.Client, s.AppName, routePath)
routePath = "/os.environ"
image = "denismakogon/os.environ"
routeType = "sync"
CreateRoute(t, s.Context, s.Client, s.AppName, routePath, image, routeType,
s.RouteConfig, s.RouteHeaders)
t.Run("verify-headers-separator", func(t *testing.T) { t.Run("verify-headers-separator", func(t *testing.T) {
t.Parallel()
s := SetupDefaultSuite()
CreateApp(t, s.Context, s.Client, s.AppName, map[string]string{})
routePath := "/os.environ"
image := "denismakogon/os.environ"
routeType := "sync"
CreateRoute(t, s.Context, s.Client, s.AppName, routePath, image, routeType,
s.RouteConfig, s.RouteHeaders)
u := url.URL{ u := url.URL{
Scheme: "http", Scheme: "http",
Host: Host(), Host: Host(),
@@ -254,17 +314,21 @@ func TestRouteExecutions(t *testing.T) {
t.Errorf("HEADER_ACCEPT='application/xml, application/json; q=0.2' "+ t.Errorf("HEADER_ACCEPT='application/xml, application/json; q=0.2' "+
"should be in output, have:\n%", res) "should be in output, have:\n%", res)
} }
DeleteRoute(t, s.Context, s.Client, s.AppName, routePath)
DeleteApp(t, s.Context, s.Client, s.AppName)
}) })
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) { t.Run("exec-log-test", func(t *testing.T) {
t.Parallel()
s := SetupDefaultSuite()
routePath := "/log"
image := "funcy/log:0.0.1"
routeType := "async"
CreateApp(t, s.Context, s.Client, s.AppName, map[string]string{})
CreateRoute(t, s.Context, s.Client, s.AppName, routePath, image, routeType,
s.RouteConfig, s.RouteHeaders)
u := url.URL{ u := url.URL{
Scheme: "http", Scheme: "http",
Host: Host(), Host: Host(),
@@ -286,13 +350,26 @@ func TestRouteExecutions(t *testing.T) {
_, err := s.Client.Operations.GetCallsCallLog(cfg) _, err := s.Client.Operations.GetCallsCallLog(cfg)
if err != nil { if err != nil {
t.Fatalf("Unexpected error: %s", err) t.Errorf("Unexpected error: %s", err)
} }
DeleteRoute(t, s.Context, s.Client, s.AppName, routePath)
DeleteApp(t, s.Context, s.Client, s.AppName)
}) })
t.Run("exec-oversized-log-test", func(t *testing.T) { t.Run("exec-oversized-log-test", func(t *testing.T) {
t.Parallel()
t.Skip("Skipped until fix for https://gitlab-odx.oracle.com/odx/functions/issues/86.") t.Skip("Skipped until fix for https://gitlab-odx.oracle.com/odx/functions/issues/86.")
s := SetupDefaultSuite()
routePath := "/log"
image := "funcy/log:0.0.1"
routeType := "async"
CreateApp(t, s.Context, s.Client, s.AppName, map[string]string{})
CreateRoute(t, s.Context, s.Client, s.AppName, routePath, image, routeType,
s.RouteConfig, s.RouteHeaders)
size := 1 * 1024 * 1024 * 1024 size := 1 * 1024 * 1024 * 1024
u := url.URL{ u := url.URL{
Scheme: "http", Scheme: "http",
@@ -314,15 +391,14 @@ func TestRouteExecutions(t *testing.T) {
logObj, err := s.Client.Operations.GetCallsCallLog(cfg) logObj, err := s.Client.Operations.GetCallsCallLog(cfg)
if err != nil { if err != nil {
t.Fatalf("Unexpected error: %s", err) t.Errorf("Unexpected error: %s", err)
} }
if len(logObj.Payload.Log.Log) >= size { if len(logObj.Payload.Log.Log) >= size {
t.Fatalf("Log entry suppose to be truncated up to expected size %v, got %v", t.Errorf("Log entry suppose to be truncated up to expected size %v, got %v",
size/1024, len(logObj.Payload.Log.Log)) size/1024, len(logObj.Payload.Log.Log))
} }
DeleteRoute(t, s.Context, s.Client, s.AppName, routePath)
DeleteApp(t, s.Context, s.Client, s.AppName)
}) })
DeleteRoute(t, s.Context, s.Client, s.AppName, routePath)
DeleteApp(t, s.Context, s.Client, s.AppName)
} }

View File

@@ -0,0 +1,220 @@
package tests
import (
"context"
"testing"
"time"
"github.com/funcy/functions_go/client"
"github.com/funcy/functions_go/client/routes"
"github.com/funcy/functions_go/models"
)
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.Errorf("Unexpected error occurred: %v. Status code: %v", msg, code)
case *routes.PostAppsAppRoutesBadRequest:
msg := err.(*routes.PostAppsAppRoutesBadRequest).Payload.Error.Message
t.Errorf("Unexpected error occurred: %v.", msg)
case *routes.PostAppsAppRoutesConflict:
msg := err.(*routes.PostAppsAppRoutesConflict).Payload.Error.Message
t.Errorf("Unexpected error occurred: %v.", msg)
case *routes.GetAppsAppRoutesRouteNotFound:
msg := err.(*routes.GetAppsAppRoutesRouteNotFound).Payload.Error.Message
t.Errorf("Unexpected error occurred: %v.", msg)
case *routes.GetAppsAppRoutesRouteDefault:
msg := err.(*routes.GetAppsAppRoutesRouteDefault).Payload.Error.Message
code := err.(*routes.GetAppsAppRoutesRouteDefault).Code()
t.Errorf("Unexpected error occurred: %v. Status code: %v", msg, code)
case *routes.DeleteAppsAppRoutesRouteNotFound:
msg := err.(*routes.DeleteAppsAppRoutesRouteNotFound).Payload.Error.Message
t.Errorf("Unexpected error occurred: %v.", msg)
case *routes.DeleteAppsAppRoutesRouteDefault:
msg := err.(*routes.DeleteAppsAppRoutesRouteDefault).Payload.Error.Message
code := err.(*routes.DeleteAppsAppRoutesRouteDefault).Code()
t.Errorf("Unexpected error occurred: %v. Status code: %v", msg, code)
case *routes.GetAppsAppRoutesNotFound:
msg := err.(*routes.GetAppsAppRoutesNotFound).Payload.Error.Message
t.Errorf("Unexpected error occurred: %v.", msg)
case *routes.GetAppsAppRoutesDefault:
msg := err.(*routes.GetAppsAppRoutesDefault).Payload.Error.Message
code := err.(*routes.GetAppsAppRoutesDefault).Code()
t.Errorf("Unexpected error occurred: %v. Status code: %v", msg, code)
case *routes.PatchAppsAppRoutesRouteBadRequest:
msg := err.(*routes.PatchAppsAppRoutesRouteBadRequest).Payload.Error.Message
t.Errorf("Unexpected error occurred: %v.", msg)
case *routes.PatchAppsAppRoutesRouteNotFound:
msg := err.(*routes.PatchAppsAppRoutesRouteNotFound).Payload.Error.Message
t.Errorf("Unexpected error occurred: %v.", msg)
case *routes.PatchAppsAppRoutesRouteDefault:
msg := err.(*routes.PatchAppsAppRoutesRouteDefault).Payload.Error.Message
code := err.(*routes.PatchAppsAppRoutesRouteDefault).Code()
t.Errorf("Unexpected error occurred: %v. Status code: %v", msg, code)
default:
t.Errorf("Unable to determine type of error: %s", err)
}
}
}
func assertRouteFields(t *testing.T, routeObject *models.Route, path, image, routeType string) {
rPath := routeObject.Path
rImage := routeObject.Image
rType := routeObject.Type
rTimeout := *routeObject.Timeout
rIdleTimeout := *routeObject.IDLETimeout
if rPath != path {
t.Errorf("Route path mismatch. Expected: %v. Actual: %v", path, rPath)
}
if rImage != image {
t.Errorf("Route image mismatch. Expected: %v. Actual: %v", image, rImage)
}
if rType != routeType {
t.Errorf("Route type mismatch. Expected: %v. Actual: %v", routeType, rType)
}
if rTimeout == 0 {
t.Error("Route timeout should have default value of 30 seconds, but got 0 seconds")
}
if rIdleTimeout == 0 {
t.Error("Route idle timeout should have default value of 30 seconds, but got 0 seconds")
}
}
func createRoute(ctx context.Context, fnclient *client.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 *client.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 *client.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 *client.Functions, appName, routePath string) {
_, err := deleteRoute(ctx, fnclient, appName, routePath)
CheckRouteResponseError(t, err)
}
func ListRoutes(t *testing.T, ctx context.Context, fnclient *client.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 *client.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 *client.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{}
}
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)
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
}

View File

@@ -1,41 +1,63 @@
package tests package tests
//
import ( import (
"testing" "testing"
"github.com/funcy/functions_go/models" "github.com/funcy/functions_go/models"
"gitlab-odx.oracle.com/odx/functions/api/id"
) )
func TestRoutes(t *testing.T) { func TestRoutes(t *testing.T) {
s := SetupDefaultSuite()
newRouteType := "sync" newRouteType := "sync"
newRoutePath := "/new-hello" newRoutePath := id.New().String()
CreateApp(t, s.Context, s.Client, s.AppName, map[string]string{})
t.Run("create-route", func(t *testing.T) { t.Run("create-route", func(t *testing.T) {
t.Parallel()
s := SetupDefaultSuite()
CreateApp(t, s.Context, s.Client, s.AppName, map[string]string{})
CreateRoute(t, s.Context, s.Client, s.AppName, s.RoutePath, s.Image, s.RouteType, CreateRoute(t, s.Context, s.Client, s.AppName, s.RoutePath, s.Image, s.RouteType,
s.RouteConfig, s.RouteHeaders) s.RouteConfig, s.RouteHeaders)
t.Logf("Test `%v` passed.", t.Name()) DeleteRoute(t, s.Context, s.Client, s.AppName, s.RoutePath)
DeleteApp(t, s.Context, s.Client, s.AppName)
}) })
t.Run("list-and-find-route", func(t *testing.T) { t.Run("list-and-find-route", func(t *testing.T) {
t.Parallel()
s := SetupDefaultSuite()
CreateApp(t, s.Context, s.Client, s.AppName, map[string]string{})
CreateRoute(t, s.Context, s.Client, s.AppName, s.RoutePath, s.Image, s.RouteType,
s.RouteConfig, s.RouteHeaders)
if !assertContainsRoute(ListRoutes(t, s.Context, s.Client, s.AppName), s.RoutePath) { 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.Errorf("Unable to find corresponding route `%v` in list", s.RoutePath)
} }
t.Logf("Test `%v` passed.", t.Name()) DeleteRoute(t, s.Context, s.Client, s.AppName, s.RoutePath)
DeleteApp(t, s.Context, s.Client, s.AppName)
}) })
t.Run("can-get-corresponding-route", func(t *testing.T) { t.Run("can-get-corresponding-route", func(t *testing.T) {
t.Parallel()
s := SetupDefaultSuite()
CreateApp(t, s.Context, s.Client, s.AppName, map[string]string{})
CreateRoute(t, s.Context, s.Client, s.AppName, s.RoutePath, s.Image, s.RouteType,
s.RouteConfig, s.RouteHeaders)
rObjects := []*models.Route{GetRoute(t, s.Context, s.Client, s.AppName, s.RoutePath)} rObjects := []*models.Route{GetRoute(t, s.Context, s.Client, s.AppName, s.RoutePath)}
if !assertContainsRoute(rObjects, s.RoutePath) { if !assertContainsRoute(rObjects, s.RoutePath) {
t.Fatalf("Unable to find corresponding route `%v` in list", s.RoutePath) t.Errorf("Unable to find corresponding route `%v` in list", s.RoutePath)
} }
t.Logf("Test `%v` passed.", t.Name())
DeleteRoute(t, s.Context, s.Client, s.AppName, s.RoutePath)
DeleteApp(t, s.Context, s.Client, s.AppName)
}) })
t.Run("can-update-route-info", func(t *testing.T) { t.Run("can-update-route-info", func(t *testing.T) {
t.Parallel()
s := SetupDefaultSuite()
CreateApp(t, s.Context, s.Client, s.AppName, map[string]string{})
CreateRoute(t, s.Context, s.Client, s.AppName, s.RoutePath, s.Image, s.RouteType,
s.RouteConfig, s.RouteHeaders)
routeResp, err := UpdateRoute( routeResp, err := UpdateRoute(
t, s.Context, s.Client, t, s.Context, s.Client,
s.AppName, s.RoutePath, s.AppName, s.RoutePath,
@@ -45,39 +67,66 @@ func TestRoutes(t *testing.T) {
CheckRouteResponseError(t, err) CheckRouteResponseError(t, err)
assertRouteFields(t, routeResp.Payload.Route, s.RoutePath, s.Image, newRouteType) assertRouteFields(t, routeResp.Payload.Route, s.RoutePath, s.Image, newRouteType)
t.Logf("Test `%v` passed.", t.Name()) DeleteRoute(t, s.Context, s.Client, s.AppName, s.RoutePath)
DeleteApp(t, s.Context, s.Client, s.AppName)
}) })
t.Run("fail-to-update-route-path", func(t *testing.T) { t.Run("fail-to-update-route-path", func(t *testing.T) {
t.Parallel()
s := SetupDefaultSuite()
CreateApp(t, s.Context, s.Client, s.AppName, map[string]string{})
CreateRoute(t, s.Context, s.Client, s.AppName, s.RoutePath, s.Image, s.RouteType,
s.RouteConfig, s.RouteHeaders)
_, err := UpdateRoute( _, err := UpdateRoute(
t, s.Context, s.Client, t, s.Context, s.Client,
s.AppName, s.RoutePath, s.AppName, s.RoutePath,
s.Image, s.RouteType, s.Format, s.Image, s.RouteType, s.Format,
s.Memory, s.RouteConfig, s.RouteHeaders, newRoutePath) s.Memory, s.RouteConfig, s.RouteHeaders, newRoutePath)
if err == nil { if err == nil {
t.Fatalf("Route path suppose to be immutable, but it's not.") t.Errorf("Route path suppose to be immutable, but it's not.")
} }
t.Logf("Test `%v` passed.", t.Name())
DeleteRoute(t, s.Context, s.Client, s.AppName, s.RoutePath)
DeleteApp(t, s.Context, s.Client, s.AppName)
}) })
t.Run("create-route-duplicate", func(t *testing.T) { t.Run("create-route-duplicate", func(t *testing.T) {
t.Parallel()
s := SetupDefaultSuite()
CreateApp(t, s.Context, s.Client, s.AppName, map[string]string{})
CreateRoute(t, s.Context, s.Client, s.AppName, s.RoutePath, s.Image, s.RouteType,
s.RouteConfig, s.RouteHeaders)
_, err := createRoute(s.Context, s.Client, s.AppName, s.Image, s.RoutePath, newRouteType, s.RouteConfig, s.RouteHeaders) _, err := createRoute(s.Context, s.Client, s.AppName, s.Image, s.RoutePath, newRouteType, s.RouteConfig, s.RouteHeaders)
if err == nil { if err == nil {
t.Fatalf("Route duplicate error should appear, but it didn't") t.Errorf("Route duplicate error should appear, but it didn't")
} }
DeleteRoute(t, s.Context, s.Client, s.AppName, s.RoutePath)
DeleteApp(t, s.Context, s.Client, s.AppName)
}) })
t.Run("can-delete-route", func(t *testing.T) { t.Run("can-delete-route", func(t *testing.T) {
t.Parallel()
s := SetupDefaultSuite()
CreateApp(t, s.Context, s.Client, s.AppName, map[string]string{})
CreateRoute(t, s.Context, s.Client, s.AppName, s.RoutePath, s.Image, s.RouteType,
s.RouteConfig, s.RouteHeaders)
DeleteRoute(t, s.Context, s.Client, s.AppName, s.RoutePath) DeleteRoute(t, s.Context, s.Client, s.AppName, s.RoutePath)
t.Logf("Test `%v` passed.", t.Name()) DeleteApp(t, s.Context, s.Client, s.AppName)
}) })
t.Run("fail-to-delete-missing-route", func(t *testing.T) { t.Run("fail-to-delete-missing-route", func(t *testing.T) {
t.Parallel()
s := SetupDefaultSuite()
CreateApp(t, s.Context, s.Client, s.AppName, map[string]string{})
_, err := deleteRoute(s.Context, s.Client, s.AppName, "dummy-route") _, err := deleteRoute(s.Context, s.Client, s.AppName, "dummy-route")
if err == nil { if err == nil {
t.Fatal("Delete from missing route must fail.") t.Error("Delete from missing route must fail.")
} }
DeleteApp(t, s.Context, s.Client, s.AppName)
}) })
DeleteApp(t, s.Context, s.Client, s.AppName)
} }

View File

@@ -4,7 +4,6 @@ import (
"context" "context"
"strings" "strings"
"sync" "sync"
"testing"
"time" "time"
"gitlab-odx.oracle.com/odx/functions/api/server" "gitlab-odx.oracle.com/odx/functions/api/server"
@@ -12,19 +11,19 @@ import (
"fmt" "fmt"
"io" "io"
"log" "log"
"math/rand"
"net/http" "net/http"
"net/url" "net/url"
"os" "os"
"github.com/funcy/functions_go/client" "github.com/funcy/functions_go/client"
"github.com/funcy/functions_go/client/apps"
"github.com/funcy/functions_go/client/routes"
"github.com/funcy/functions_go/models"
httptransport "github.com/go-openapi/runtime/client" httptransport "github.com/go-openapi/runtime/client"
"github.com/go-openapi/strfmt" "github.com/go-openapi/strfmt"
"github.com/spf13/viper" "github.com/spf13/viper"
) )
const lBytes = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"
func Host() string { func Host() string {
apiURL := os.Getenv("API_URL") apiURL := os.Getenv("API_URL")
if apiURL == "" { if apiURL == "" {
@@ -45,18 +44,16 @@ func APIClient() *client.Functions {
} }
// create the API client, with the transport // create the API client, with the transport
client := client.New(transport, strfmt.Default) return client.New(transport, strfmt.Default)
return client
} }
var ( var (
getServer sync.Once getServer sync.Once
cancel2 context.CancelFunc
s *server.Server
) )
func getServerWithCancel() (*server.Server, context.CancelFunc) { func getServerWithCancel() (*server.Server, context.CancelFunc) {
var cancel2 context.CancelFunc
var s *server.Server
getServer.Do(func() { getServer.Do(func() {
ctx, cancel := context.WithCancel(context.Background()) ctx, cancel := context.WithCancel(context.Background())
@@ -64,11 +61,15 @@ func getServerWithCancel() (*server.Server, context.CancelFunc) {
viper.Set(server.EnvAPIURL, "http://localhost:8080") viper.Set(server.EnvAPIURL, "http://localhost:8080")
viper.Set(server.EnvLogLevel, "fatal") viper.Set(server.EnvLogLevel, "fatal")
timeString := time.Now().Format("2006_01_02_15_04_05") timeString := time.Now().Format("2006_01_02_15_04_05")
db_url := os.Getenv("DB_URL")
tmpDir := os.TempDir() tmpDir := os.TempDir()
tmpMq := fmt.Sprintf("%s/fn_integration_test_%s_worker_mq.db", tmpDir, timeString) tmpMq := fmt.Sprintf("%s/fn_integration_test_%s_worker_mq.db", tmpDir, timeString)
tmpDB := fmt.Sprintf("%s/fn_integration_test_%s_fn.db", tmpDir, timeString) tmpDb := fmt.Sprintf("%s/fn_integration_test_%s_fn.db", tmpDir, timeString)
viper.Set(server.EnvMQURL, fmt.Sprintf("bolt://%s", tmpMq)) viper.Set(server.EnvMQURL, fmt.Sprintf("bolt://%s", tmpMq))
viper.Set(server.EnvDBURL, fmt.Sprintf("sqlite3://%s", tmpDB)) if db_url == "" {
db_url = fmt.Sprintf("sqlite3://%s", tmpDb)
}
viper.Set(server.EnvDBURL, db_url)
s = server.NewFromEnv(ctx) s = server.NewFromEnv(ctx)
@@ -79,6 +80,7 @@ func getServerWithCancel() (*server.Server, context.CancelFunc) {
panic("Failed to start server.") panic("Failed to start server.")
} }
}) })
log.Println(server.EnvAPIURL)
_, err := http.Get(viper.GetString(server.EnvAPIURL) + "/version") _, err := http.Get(viper.GetString(server.EnvAPIURL) + "/version")
for err != nil { for err != nil {
_, err = http.Get(viper.GetString(server.EnvAPIURL) + "/version") _, err = http.Get(viper.GetString(server.EnvAPIURL) + "/version")
@@ -87,7 +89,7 @@ func getServerWithCancel() (*server.Server, context.CancelFunc) {
cancel2 = context.CancelFunc(func() { cancel2 = context.CancelFunc(func() {
cancel() cancel()
os.Remove(tmpMq) os.Remove(tmpMq)
os.Remove(tmpDB) os.Remove(tmpDb)
}) })
}) })
return s, cancel2 return s, cancel2
@@ -107,12 +109,20 @@ type SuiteSetup struct {
Cancel context.CancelFunc Cancel context.CancelFunc
} }
func RandStringBytes(n int) string {
b := make([]byte, n)
for i := range b {
b[i] = lBytes[rand.Intn(len(lBytes))]
}
return strings.ToLower(string(b))
}
func SetupDefaultSuite() *SuiteSetup { func SetupDefaultSuite() *SuiteSetup {
ss := &SuiteSetup{ ss := &SuiteSetup{
Context: context.Background(), Context: context.Background(),
Client: APIClient(), Client: APIClient(),
AppName: "test-app", AppName: RandStringBytes(10),
RoutePath: "/hello", RoutePath: "/" + RandStringBytes(10),
Image: "funcy/hello", Image: "funcy/hello",
Format: "default", Format: "default",
RouteType: "async", RouteType: "async",
@@ -137,353 +147,10 @@ func SetupDefaultSuite() *SuiteSetup {
} }
} }
} }
return ss return ss
} }
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.PostAppsDefault).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 *client.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 *client.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 *client.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 *client.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 *client.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 *client.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 *client.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 *client.Functions, appName, routePath string) {
_, err := deleteRoute(ctx, fnclient, appName, routePath)
CheckRouteResponseError(t, err)
}
func ListRoutes(t *testing.T, ctx context.Context, fnclient *client.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 *client.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 *client.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
}
func EnvAsHeader(req *http.Request, selectedEnv []string) { func EnvAsHeader(req *http.Request, selectedEnv []string) {
detectedEnv := os.Environ() detectedEnv := os.Environ()
if len(selectedEnv) > 0 { if len(selectedEnv) > 0 {