mirror of
https://github.com/fnproject/fn.git
synced 2022-10-28 21:29:17 +03:00
more strict configuration of routes
* idle_timeout max of 1h * timeout max of 120s for sync, 1h for async * max memory of 8GB * do full route validation before call invocation * ensure that idle_timeout >= timeout we are now doing validation of updating route inside of the database transaction, which is what we should have been doing all along really. we need this behavior to ensure that the idle timeout is longer than the timeout, among other benefits (like not updating the most recent version of the existing struct and overwriting previous updates, yay). since we have this, we can get rid of the weird skipZero behavior on validate too and validate the real deal holyfield. validating the route before making the call is handy so that we don't do weird things like run a func that wants to use 300GB of RAM and run for 3 weeks. closes #192 closes #344 closes #162
This commit is contained in:
@@ -32,7 +32,10 @@ jobs:
|
|||||||
- run: docker version
|
- run: docker version
|
||||||
# login here for tests
|
# login here for tests
|
||||||
- run: docker login -u $DOCKER_USER -p $DOCKER_PASS
|
- run: docker login -u $DOCKER_USER -p $DOCKER_PASS
|
||||||
- run: ./test.sh
|
- run: make docker-build
|
||||||
|
- run: make install
|
||||||
|
- run: make test
|
||||||
|
# TODO these should be inside test.sh file ?
|
||||||
- run: ./api_test.sh mysql 4
|
- run: ./api_test.sh mysql 4
|
||||||
- run: ./api_test.sh postgres 4
|
- run: ./api_test.sh postgres 4
|
||||||
- run: ./api_test.sh sqlite 4
|
- run: ./api_test.sh sqlite 4
|
||||||
|
|||||||
3
Makefile
3
Makefile
@@ -10,6 +10,9 @@ dep-up:
|
|||||||
build:
|
build:
|
||||||
go build -o functions
|
go build -o functions
|
||||||
|
|
||||||
|
install:
|
||||||
|
go install
|
||||||
|
|
||||||
test:
|
test:
|
||||||
./test.sh
|
./test.sh
|
||||||
|
|
||||||
|
|||||||
@@ -146,6 +146,13 @@ func FromRequest(appName, path string, req *http.Request) CallOpt {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// this ensures that there is an image, path, timeouts, memory, etc are valid.
|
||||||
|
// NOTE: this means assign any changes above into route's fields
|
||||||
|
err = route.Validate()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
c.Call = &models.Call{
|
c.Call = &models.Call{
|
||||||
ID: id,
|
ID: id,
|
||||||
AppName: appName,
|
AppName: appName,
|
||||||
@@ -166,14 +173,6 @@ func FromRequest(appName, path string, req *http.Request) CallOpt {
|
|||||||
Method: req.Method,
|
Method: req.Method,
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO if these made it to here we have a problemo. error instead?
|
|
||||||
if c.Timeout <= 0 {
|
|
||||||
c.Timeout = models.DefaultRouteTimeout
|
|
||||||
}
|
|
||||||
if c.IdleTimeout <= 0 {
|
|
||||||
c.IdleTimeout = models.DefaultIdleTimeout
|
|
||||||
}
|
|
||||||
|
|
||||||
c.req = req
|
c.req = req
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -449,7 +449,7 @@ func Test(t *testing.T, dsf func() models.Datastore) {
|
|||||||
updated, err := ds.UpdateRoute(ctx, &models.Route{
|
updated, err := ds.UpdateRoute(ctx, &models.Route{
|
||||||
AppName: testRoute.AppName,
|
AppName: testRoute.AppName,
|
||||||
Path: testRoute.Path,
|
Path: testRoute.Path,
|
||||||
Timeout: 100,
|
Timeout: 2,
|
||||||
Config: map[string]string{
|
Config: map[string]string{
|
||||||
"FIRST": "1",
|
"FIRST": "1",
|
||||||
"SECOND": "2",
|
"SECOND": "2",
|
||||||
@@ -472,8 +472,10 @@ func Test(t *testing.T, dsf func() models.Datastore) {
|
|||||||
Image: "fnproject/hello",
|
Image: "fnproject/hello",
|
||||||
Type: "sync",
|
Type: "sync",
|
||||||
Format: "http",
|
Format: "http",
|
||||||
|
IdleTimeout: testRoute.IdleTimeout,
|
||||||
|
Memory: testRoute.Memory,
|
||||||
// updated
|
// updated
|
||||||
Timeout: 100,
|
Timeout: 2,
|
||||||
Config: map[string]string{
|
Config: map[string]string{
|
||||||
"FIRST": "1",
|
"FIRST": "1",
|
||||||
"SECOND": "2",
|
"SECOND": "2",
|
||||||
@@ -515,7 +517,9 @@ func Test(t *testing.T, dsf func() models.Datastore) {
|
|||||||
Image: "fnproject/hello",
|
Image: "fnproject/hello",
|
||||||
Type: "sync",
|
Type: "sync",
|
||||||
Format: "http",
|
Format: "http",
|
||||||
Timeout: 100,
|
Timeout: 2,
|
||||||
|
Memory: testRoute.Memory,
|
||||||
|
IdleTimeout: testRoute.IdleTimeout,
|
||||||
// updated
|
// updated
|
||||||
Config: map[string]string{
|
Config: map[string]string{
|
||||||
"FIRST": "first",
|
"FIRST": "first",
|
||||||
@@ -687,4 +691,7 @@ var testRoute = &models.Route{
|
|||||||
Image: "fnproject/hello",
|
Image: "fnproject/hello",
|
||||||
Type: "sync",
|
Type: "sync",
|
||||||
Format: "http",
|
Format: "http",
|
||||||
|
Timeout: models.DefaultTimeout,
|
||||||
|
IdleTimeout: models.DefaultIdleTimeout,
|
||||||
|
Memory: models.DefaultMemory,
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -144,8 +144,14 @@ func (m *mock) UpdateRoute(ctx context.Context, route *models.Route) (*models.Ro
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
r.Update(route)
|
clone := r.Clone()
|
||||||
return r.Clone(), nil
|
clone.Update(route)
|
||||||
|
err = clone.Validate()
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
r.Update(route) // only if validate works (pointer)
|
||||||
|
return clone, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (m *mock) RemoveRoute(ctx context.Context, appName, routePath string) error {
|
func (m *mock) RemoveRoute(ctx context.Context, appName, routePath string) error {
|
||||||
|
|||||||
@@ -335,6 +335,10 @@ func (ds *sqlStore) UpdateRoute(ctx context.Context, newroute *models.Route) (*m
|
|||||||
}
|
}
|
||||||
|
|
||||||
route.Update(newroute)
|
route.Update(newroute)
|
||||||
|
err = route.Validate()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
query = tx.Rebind(`UPDATE routes SET
|
query = tx.Rebind(`UPDATE routes SET
|
||||||
image = :image,
|
image = :image,
|
||||||
|
|||||||
@@ -7,14 +7,14 @@ type App struct {
|
|||||||
|
|
||||||
func (a *App) Validate() error {
|
func (a *App) Validate() error {
|
||||||
if a.Name == "" {
|
if a.Name == "" {
|
||||||
return ErrAppsValidationMissingName
|
return ErrAppsMissingName
|
||||||
}
|
}
|
||||||
if len(a.Name) > maxAppName {
|
if len(a.Name) > maxAppName {
|
||||||
return ErrAppsValidationTooLongName
|
return ErrAppsTooLongName
|
||||||
}
|
}
|
||||||
for _, c := range a.Name {
|
for _, c := range a.Name {
|
||||||
if (c < '0' || '9' < c) && (c < 'A' || 'Z' > c) && (c < 'a' || 'z' < c) && c != '_' && c != '-' {
|
if (c < '0' || '9' < c) && (c < 'A' || 'Z' > c) && (c < 'a' || 'z' < c) && c != '_' && c != '-' {
|
||||||
return ErrAppsValidationInvalidName
|
return ErrAppsInvalidName
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
|
|||||||
@@ -20,15 +20,15 @@ var (
|
|||||||
code: http.StatusGatewayTimeout,
|
code: http.StatusGatewayTimeout,
|
||||||
error: errors.New("Timed out"),
|
error: errors.New("Timed out"),
|
||||||
}
|
}
|
||||||
ErrAppsValidationMissingName = err{
|
ErrAppsMissingName = err{
|
||||||
code: http.StatusBadRequest,
|
code: http.StatusBadRequest,
|
||||||
error: errors.New("Missing app name"),
|
error: errors.New("Missing app name"),
|
||||||
}
|
}
|
||||||
ErrAppsValidationTooLongName = err{
|
ErrAppsTooLongName = err{
|
||||||
code: http.StatusBadRequest,
|
code: http.StatusBadRequest,
|
||||||
error: fmt.Errorf("App name must be %v characters or less", maxAppName),
|
error: fmt.Errorf("App name must be %v characters or less", maxAppName),
|
||||||
}
|
}
|
||||||
ErrAppsValidationInvalidName = err{
|
ErrAppsInvalidName = err{
|
||||||
code: http.StatusBadRequest,
|
code: http.StatusBadRequest,
|
||||||
error: errors.New("Invalid app name"),
|
error: errors.New("Invalid app name"),
|
||||||
}
|
}
|
||||||
@@ -42,7 +42,7 @@ var (
|
|||||||
}
|
}
|
||||||
ErrAppsNameImmutable = err{
|
ErrAppsNameImmutable = err{
|
||||||
code: http.StatusConflict,
|
code: http.StatusConflict,
|
||||||
error: errors.New("Could not update app - name is immutable"),
|
error: errors.New("Could not update - name is immutable"),
|
||||||
}
|
}
|
||||||
ErrAppsNotFound = err{
|
ErrAppsNotFound = err{
|
||||||
code: http.StatusNotFound,
|
code: http.StatusNotFound,
|
||||||
@@ -94,41 +94,41 @@ var (
|
|||||||
}
|
}
|
||||||
ErrRoutesPathImmutable = err{
|
ErrRoutesPathImmutable = err{
|
||||||
code: http.StatusConflict,
|
code: http.StatusConflict,
|
||||||
error: errors.New("Could not update route - path is immutable"),
|
error: errors.New("Could not update - path is immutable"),
|
||||||
}
|
}
|
||||||
ErrFoundDynamicURL = err{
|
ErrFoundDynamicURL = err{
|
||||||
code: http.StatusBadRequest,
|
code: http.StatusBadRequest,
|
||||||
error: errors.New("Dynamic URL is not allowed"),
|
error: errors.New("Dynamic URL is not allowed"),
|
||||||
}
|
}
|
||||||
ErrInvalidPath = err{
|
ErrRoutesInvalidPath = err{
|
||||||
code: http.StatusBadRequest,
|
code: http.StatusBadRequest,
|
||||||
error: errors.New("Invalid Path format"),
|
error: errors.New("Invalid route path format"),
|
||||||
}
|
}
|
||||||
ErrInvalidType = err{
|
ErrRoutesInvalidType = err{
|
||||||
code: http.StatusBadRequest,
|
code: http.StatusBadRequest,
|
||||||
error: errors.New("Invalid route Type"),
|
error: errors.New("Invalid route Type"),
|
||||||
}
|
}
|
||||||
ErrInvalidFormat = err{
|
ErrRoutesInvalidFormat = err{
|
||||||
code: http.StatusBadRequest,
|
code: http.StatusBadRequest,
|
||||||
error: errors.New("Invalid route Format"),
|
error: errors.New("Invalid route Format"),
|
||||||
}
|
}
|
||||||
ErrMissingAppName = err{
|
ErrRoutesMissingAppName = err{
|
||||||
code: http.StatusBadRequest,
|
code: http.StatusBadRequest,
|
||||||
error: errors.New("Missing route AppName"),
|
error: errors.New("Missing route AppName"),
|
||||||
}
|
}
|
||||||
ErrMissingImage = err{
|
ErrRoutesMissingImage = err{
|
||||||
code: http.StatusBadRequest,
|
code: http.StatusBadRequest,
|
||||||
error: errors.New("Missing route Image"),
|
error: errors.New("Missing route Image"),
|
||||||
}
|
}
|
||||||
ErrMissingName = err{
|
ErrRoutesMissingName = err{
|
||||||
code: http.StatusBadRequest,
|
code: http.StatusBadRequest,
|
||||||
error: errors.New("Missing route Name"),
|
error: errors.New("Missing route Name"),
|
||||||
}
|
}
|
||||||
ErrMissingPath = err{
|
ErrRoutesMissingPath = err{
|
||||||
code: http.StatusBadRequest,
|
code: http.StatusBadRequest,
|
||||||
error: errors.New("Missing route Path"),
|
error: errors.New("Missing route Path"),
|
||||||
}
|
}
|
||||||
ErrMissingType = err{
|
ErrRoutesMissingType = err{
|
||||||
code: http.StatusBadRequest,
|
code: http.StatusBadRequest,
|
||||||
error: errors.New("Missing route Type"),
|
error: errors.New("Missing route Type"),
|
||||||
}
|
}
|
||||||
@@ -144,13 +144,21 @@ var (
|
|||||||
code: http.StatusBadRequest,
|
code: http.StatusBadRequest,
|
||||||
error: errors.New("from_time is not an epoch time"),
|
error: errors.New("from_time is not an epoch time"),
|
||||||
}
|
}
|
||||||
ErrNegativeTimeout = err{
|
ErrRoutesInvalidTimeout = err{
|
||||||
code: http.StatusBadRequest,
|
code: http.StatusBadRequest,
|
||||||
error: errors.New("Negative timeout"),
|
error: fmt.Errorf("timeout value is too large or small. 0 < timeout < max. async max: %d sync max: %d", MaxAsyncTimeout, MaxSyncTimeout),
|
||||||
}
|
}
|
||||||
ErrNegativeIdleTimeout = err{
|
ErrRoutesInvalidIdleTimeout = err{
|
||||||
code: http.StatusBadRequest,
|
code: http.StatusBadRequest,
|
||||||
error: errors.New("Negative idle timeout"),
|
error: fmt.Errorf("idle_timeout value is too large or small. 0 < timeout < %d", MaxIdleTimeout),
|
||||||
|
}
|
||||||
|
ErrRoutesInvalidMemory = err{
|
||||||
|
code: http.StatusBadRequest,
|
||||||
|
error: fmt.Errorf("memory value is invalid. 0 < memory < %d", MaxMemory),
|
||||||
|
}
|
||||||
|
ErrRoutesTimeoutLongerThanIdle = err{
|
||||||
|
code: http.StatusBadRequest,
|
||||||
|
error: errors.New("timeout must be less than idle_timeout"),
|
||||||
}
|
}
|
||||||
ErrCallNotFound = err{
|
ErrCallNotFound = err{
|
||||||
code: http.StatusNotFound,
|
code: http.StatusNotFound,
|
||||||
|
|||||||
@@ -8,8 +8,14 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
DefaultRouteTimeout = 30 // seconds
|
DefaultTimeout = 30 // seconds
|
||||||
DefaultIdleTimeout = 30 // seconds
|
DefaultIdleTimeout = 30 // seconds
|
||||||
|
DefaultMemory = 128 // MB
|
||||||
|
|
||||||
|
MaxSyncTimeout = 120 // 2 minutes
|
||||||
|
MaxAsyncTimeout = 3600 // 1 hour
|
||||||
|
MaxIdleTimeout = MaxAsyncTimeout
|
||||||
|
MaxMemory = 1024 * 8 // 8GB TODO should probably be a var of machine max?
|
||||||
)
|
)
|
||||||
|
|
||||||
type Routes []*Route
|
type Routes []*Route
|
||||||
@@ -30,7 +36,7 @@ type Route struct {
|
|||||||
// SetDefaults sets zeroed field to defaults.
|
// SetDefaults sets zeroed field to defaults.
|
||||||
func (r *Route) SetDefaults() {
|
func (r *Route) SetDefaults() {
|
||||||
if r.Memory == 0 {
|
if r.Memory == 0 {
|
||||||
r.Memory = 128
|
r.Memory = DefaultMemory
|
||||||
}
|
}
|
||||||
|
|
||||||
if r.Type == TypeNone {
|
if r.Type == TypeNone {
|
||||||
@@ -50,7 +56,7 @@ func (r *Route) SetDefaults() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if r.Timeout == 0 {
|
if r.Timeout == 0 {
|
||||||
r.Timeout = DefaultRouteTimeout
|
r.Timeout = DefaultTimeout
|
||||||
}
|
}
|
||||||
|
|
||||||
if r.IdleTimeout == 0 {
|
if r.IdleTimeout == 0 {
|
||||||
@@ -58,24 +64,15 @@ func (r *Route) SetDefaults() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Validate validates field values, skipping zeroed fields if skipZero is true.
|
// Validate validates all field values, returning the first error, if any.
|
||||||
// it returns the first error, if any.
|
func (r *Route) Validate() error {
|
||||||
func (r *Route) Validate(skipZero bool) error {
|
|
||||||
if !skipZero {
|
|
||||||
if r.AppName == "" {
|
if r.AppName == "" {
|
||||||
return ErrMissingAppName
|
return ErrRoutesMissingAppName
|
||||||
}
|
}
|
||||||
|
|
||||||
if r.Path == "" {
|
if r.Path == "" {
|
||||||
return ErrMissingPath
|
return ErrRoutesMissingPath
|
||||||
}
|
} else {
|
||||||
|
|
||||||
if r.Image == "" {
|
|
||||||
return ErrMissingImage
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if !skipZero || r.Path != "" {
|
|
||||||
u, err := url.Parse(r.Path)
|
u, err := url.Parse(r.Path)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return ErrPathMalformed
|
return ErrPathMalformed
|
||||||
@@ -86,28 +83,38 @@ func (r *Route) Validate(skipZero bool) error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if !path.IsAbs(u.Path) {
|
if !path.IsAbs(u.Path) {
|
||||||
return ErrInvalidPath
|
return ErrRoutesInvalidPath
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if !skipZero || r.Type != "" {
|
if r.Image == "" {
|
||||||
|
return ErrRoutesMissingImage
|
||||||
|
}
|
||||||
|
|
||||||
if r.Type != TypeAsync && r.Type != TypeSync {
|
if r.Type != TypeAsync && r.Type != TypeSync {
|
||||||
return ErrInvalidType
|
return ErrRoutesInvalidType
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if !skipZero || r.Format != "" {
|
|
||||||
if r.Format != FormatDefault && r.Format != FormatHTTP {
|
if r.Format != FormatDefault && r.Format != FormatHTTP {
|
||||||
return ErrInvalidFormat
|
return ErrRoutesInvalidFormat
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if r.Timeout < 0 {
|
if r.Timeout <= 0 ||
|
||||||
return ErrNegativeTimeout
|
(r.Type == TypeSync && r.Timeout > MaxSyncTimeout) ||
|
||||||
|
(r.Type == TypeAsync && r.Timeout > MaxAsyncTimeout) {
|
||||||
|
return ErrRoutesInvalidTimeout
|
||||||
}
|
}
|
||||||
|
|
||||||
if r.IdleTimeout < 0 {
|
if r.IdleTimeout <= 0 || r.IdleTimeout > MaxIdleTimeout {
|
||||||
return ErrNegativeIdleTimeout
|
return ErrRoutesInvalidIdleTimeout
|
||||||
|
}
|
||||||
|
|
||||||
|
if r.Timeout > r.IdleTimeout {
|
||||||
|
return ErrRoutesTimeoutLongerThanIdle
|
||||||
|
}
|
||||||
|
|
||||||
|
if r.Memory < 1 || r.Memory > MaxMemory {
|
||||||
|
return ErrRoutesInvalidMemory
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
|
|||||||
@@ -4,15 +4,9 @@ type RouteWrapper struct {
|
|||||||
Route *Route `json:"route"`
|
Route *Route `json:"route"`
|
||||||
}
|
}
|
||||||
|
|
||||||
func (m *RouteWrapper) Validate(skipZero bool) error { return m.validateRoute(skipZero) }
|
func (m *RouteWrapper) Validate() error {
|
||||||
|
|
||||||
func (m *RouteWrapper) validateRoute(skipZero bool) error {
|
|
||||||
|
|
||||||
if m.Route != nil {
|
if m.Route != nil {
|
||||||
if err := m.Route.Validate(skipZero); err != nil {
|
return m.Route.Validate()
|
||||||
return err
|
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -41,10 +41,10 @@ func TestAppCreate(t *testing.T) {
|
|||||||
{datastore.NewMock(), logs.NewMock(), "/v1/apps", ``, http.StatusBadRequest, models.ErrInvalidJSON},
|
{datastore.NewMock(), logs.NewMock(), "/v1/apps", ``, http.StatusBadRequest, models.ErrInvalidJSON},
|
||||||
{datastore.NewMock(), logs.NewMock(), "/v1/apps", `{}`, http.StatusBadRequest, models.ErrAppsMissingNew},
|
{datastore.NewMock(), logs.NewMock(), "/v1/apps", `{}`, http.StatusBadRequest, models.ErrAppsMissingNew},
|
||||||
{datastore.NewMock(), logs.NewMock(), "/v1/apps", `{ "name": "Test" }`, http.StatusBadRequest, models.ErrAppsMissingNew},
|
{datastore.NewMock(), logs.NewMock(), "/v1/apps", `{ "name": "Test" }`, http.StatusBadRequest, models.ErrAppsMissingNew},
|
||||||
{datastore.NewMock(), logs.NewMock(), "/v1/apps", `{ "app": { "name": "" } }`, http.StatusBadRequest, models.ErrAppsValidationMissingName},
|
{datastore.NewMock(), logs.NewMock(), "/v1/apps", `{ "app": { "name": "" } }`, http.StatusBadRequest, models.ErrAppsMissingName},
|
||||||
{datastore.NewMock(), logs.NewMock(), "/v1/apps", `{ "app": { "name": "1234567890123456789012345678901" } }`, http.StatusBadRequest, models.ErrAppsValidationTooLongName},
|
{datastore.NewMock(), logs.NewMock(), "/v1/apps", `{ "app": { "name": "1234567890123456789012345678901" } }`, http.StatusBadRequest, models.ErrAppsTooLongName},
|
||||||
{datastore.NewMock(), logs.NewMock(), "/v1/apps", `{ "app": { "name": "&&%@!#$#@$" } }`, http.StatusBadRequest, models.ErrAppsValidationInvalidName},
|
{datastore.NewMock(), logs.NewMock(), "/v1/apps", `{ "app": { "name": "&&%@!#$#@$" } }`, http.StatusBadRequest, models.ErrAppsInvalidName},
|
||||||
{datastore.NewMock(), logs.NewMock(), "/v1/apps", `{ "app": { "name": "&&%@!#$#@$" } }`, http.StatusBadRequest, models.ErrAppsValidationInvalidName},
|
{datastore.NewMock(), logs.NewMock(), "/v1/apps", `{ "app": { "name": "&&%@!#$#@$" } }`, http.StatusBadRequest, models.ErrAppsInvalidName},
|
||||||
|
|
||||||
// success
|
// success
|
||||||
{datastore.NewMock(), logs.NewMock(), "/v1/apps", `{ "app": { "name": "teste" } }`, http.StatusOK, nil},
|
{datastore.NewMock(), logs.NewMock(), "/v1/apps", `{ "app": { "name": "teste" } }`, http.StatusOK, nil},
|
||||||
|
|||||||
@@ -57,7 +57,7 @@ func TestCallGet(t *testing.T) {
|
|||||||
expectedCode int
|
expectedCode int
|
||||||
expectedError error
|
expectedError error
|
||||||
}{
|
}{
|
||||||
{"/v1/apps//calls/" + call.ID, "", http.StatusBadRequest, models.ErrMissingAppName},
|
{"/v1/apps//calls/" + call.ID, "", http.StatusBadRequest, models.ErrAppsMissingName},
|
||||||
{"/v1/apps/nodawg/calls/" + call.ID, "", http.StatusNotFound, models.ErrCallNotFound}, // TODO a little weird
|
{"/v1/apps/nodawg/calls/" + call.ID, "", http.StatusNotFound, models.ErrCallNotFound}, // TODO a little weird
|
||||||
{"/v1/apps/myapp/calls/" + call.ID[:3], "", http.StatusNotFound, models.ErrCallNotFound},
|
{"/v1/apps/myapp/calls/" + call.ID[:3], "", http.StatusNotFound, models.ErrCallNotFound},
|
||||||
{"/v1/apps/myapp/calls/" + call.ID, "", http.StatusOK, nil},
|
{"/v1/apps/myapp/calls/" + call.ID, "", http.StatusOK, nil},
|
||||||
@@ -140,7 +140,7 @@ func TestCallList(t *testing.T) {
|
|||||||
expectedLen int
|
expectedLen int
|
||||||
nextCursor string
|
nextCursor string
|
||||||
}{
|
}{
|
||||||
{"/v1/apps//calls", "", http.StatusBadRequest, models.ErrMissingAppName, 0, ""},
|
{"/v1/apps//calls", "", http.StatusBadRequest, models.ErrAppsMissingName, 0, ""},
|
||||||
{"/v1/apps/nodawg/calls", "", http.StatusNotFound, models.ErrAppsNotFound, 0, ""},
|
{"/v1/apps/nodawg/calls", "", http.StatusNotFound, models.ErrAppsNotFound, 0, ""},
|
||||||
{"/v1/apps/myapp/calls", "", http.StatusOK, nil, 3, ""},
|
{"/v1/apps/myapp/calls", "", http.StatusOK, nil, 3, ""},
|
||||||
{"/v1/apps/myapp/calls?per_page=1", "", http.StatusOK, nil, 1, c3.ID},
|
{"/v1/apps/myapp/calls?per_page=1", "", http.StatusOK, nil, 1, c3.ID},
|
||||||
|
|||||||
@@ -49,7 +49,8 @@ func (s *Server) handleRoutesPostPutPatch(c *gin.Context) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (s *Server) submitRoute(ctx context.Context, wroute *models.RouteWrapper) error {
|
func (s *Server) submitRoute(ctx context.Context, wroute *models.RouteWrapper) error {
|
||||||
err := s.setDefaultsAndValidate(wroute)
|
wroute.Route.SetDefaults()
|
||||||
|
err := wroute.Route.Validate()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@@ -62,10 +63,6 @@ func (s *Server) submitRoute(ctx context.Context, wroute *models.RouteWrapper) e
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (s *Server) changeRoute(ctx context.Context, wroute *models.RouteWrapper) error {
|
func (s *Server) changeRoute(ctx context.Context, wroute *models.RouteWrapper) error {
|
||||||
err := wroute.Validate(true)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
r, err := s.Datastore.UpdateRoute(ctx, wroute.Route)
|
r, err := s.Datastore.UpdateRoute(ctx, wroute.Route)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
@@ -163,13 +160,8 @@ func bindRoute(c *gin.Context, method string, wroute *models.RouteWrapper) error
|
|||||||
}
|
}
|
||||||
if method == http.MethodPost {
|
if method == http.MethodPost {
|
||||||
if wroute.Route.Path == "" {
|
if wroute.Route.Path == "" {
|
||||||
return models.ErrMissingPath
|
return models.ErrRoutesMissingPath
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *Server) setDefaultsAndValidate(wroute *models.RouteWrapper) error {
|
|
||||||
wroute.Route.SetDefaults()
|
|
||||||
return wroute.Validate(false)
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -61,11 +61,11 @@ func TestRouteCreate(t *testing.T) {
|
|||||||
{datastore.NewMock(), logs.NewMock(), http.MethodPost, "/v1/apps/a/routes", ``, http.StatusBadRequest, models.ErrInvalidJSON},
|
{datastore.NewMock(), logs.NewMock(), http.MethodPost, "/v1/apps/a/routes", ``, http.StatusBadRequest, models.ErrInvalidJSON},
|
||||||
{datastore.NewMock(), logs.NewMock(), http.MethodPost, "/v1/apps/a/routes", `{ "type": "sync" }`, http.StatusBadRequest, models.ErrRoutesMissingNew},
|
{datastore.NewMock(), logs.NewMock(), http.MethodPost, "/v1/apps/a/routes", `{ "type": "sync" }`, http.StatusBadRequest, models.ErrRoutesMissingNew},
|
||||||
{datastore.NewMock(), logs.NewMock(), http.MethodPost, "/v1/apps/a/routes", `{ "path": "/myroute", "type": "sync" }`, http.StatusBadRequest, models.ErrRoutesMissingNew},
|
{datastore.NewMock(), logs.NewMock(), http.MethodPost, "/v1/apps/a/routes", `{ "path": "/myroute", "type": "sync" }`, http.StatusBadRequest, models.ErrRoutesMissingNew},
|
||||||
{datastore.NewMock(), logs.NewMock(), http.MethodPost, "/v1/apps/a/routes", `{ "route": { } }`, http.StatusBadRequest, models.ErrMissingPath},
|
{datastore.NewMock(), logs.NewMock(), http.MethodPost, "/v1/apps/a/routes", `{ "route": { } }`, http.StatusBadRequest, models.ErrRoutesMissingPath},
|
||||||
{datastore.NewMock(), logs.NewMock(), http.MethodPost, "/v1/apps/a/routes", `{ "route": { "path": "/myroute", "type": "sync" } }`, http.StatusBadRequest, models.ErrMissingImage},
|
{datastore.NewMock(), logs.NewMock(), http.MethodPost, "/v1/apps/a/routes", `{ "route": { "path": "/myroute", "type": "sync" } }`, http.StatusBadRequest, models.ErrRoutesMissingImage},
|
||||||
{datastore.NewMock(), logs.NewMock(), http.MethodPost, "/v1/apps/a/routes", `{ "route": { "image": "fnproject/hello", "type": "sync" } }`, http.StatusBadRequest, models.ErrMissingPath},
|
{datastore.NewMock(), logs.NewMock(), http.MethodPost, "/v1/apps/a/routes", `{ "route": { "image": "fnproject/hello", "type": "sync" } }`, http.StatusBadRequest, models.ErrRoutesMissingPath},
|
||||||
{datastore.NewMock(), logs.NewMock(), http.MethodPost, "/v1/apps/a/routes", `{ "route": { "image": "fnproject/hello", "path": "myroute", "type": "sync" } }`, http.StatusBadRequest, models.ErrInvalidPath},
|
{datastore.NewMock(), logs.NewMock(), http.MethodPost, "/v1/apps/a/routes", `{ "route": { "image": "fnproject/hello", "path": "myroute", "type": "sync" } }`, http.StatusBadRequest, models.ErrRoutesInvalidPath},
|
||||||
{datastore.NewMock(), logs.NewMock(), http.MethodPost, "/v1/apps/$/routes", `{ "route": { "image": "fnproject/hello", "path": "/myroute", "type": "sync" } }`, http.StatusBadRequest, models.ErrAppsValidationInvalidName},
|
{datastore.NewMock(), logs.NewMock(), http.MethodPost, "/v1/apps/$/routes", `{ "route": { "image": "fnproject/hello", "path": "/myroute", "type": "sync" } }`, http.StatusBadRequest, models.ErrAppsInvalidName},
|
||||||
{datastore.NewMockInit(nil,
|
{datastore.NewMockInit(nil,
|
||||||
[]*models.Route{
|
[]*models.Route{
|
||||||
{
|
{
|
||||||
@@ -89,13 +89,13 @@ func TestRoutePut(t *testing.T) {
|
|||||||
// errors (NOTE: this route doesn't exist yet)
|
// errors (NOTE: this route doesn't exist yet)
|
||||||
{datastore.NewMock(), logs.NewMock(), http.MethodPut, "/v1/apps/a/routes/myroute", `{ }`, http.StatusBadRequest, models.ErrRoutesMissingNew},
|
{datastore.NewMock(), logs.NewMock(), http.MethodPut, "/v1/apps/a/routes/myroute", `{ }`, http.StatusBadRequest, models.ErrRoutesMissingNew},
|
||||||
{datastore.NewMock(), logs.NewMock(), http.MethodPut, "/v1/apps/a/routes/myroute", `{ "path": "/myroute", "type": "sync" }`, http.StatusBadRequest, models.ErrRoutesMissingNew},
|
{datastore.NewMock(), logs.NewMock(), http.MethodPut, "/v1/apps/a/routes/myroute", `{ "path": "/myroute", "type": "sync" }`, http.StatusBadRequest, models.ErrRoutesMissingNew},
|
||||||
{datastore.NewMock(), logs.NewMock(), http.MethodPut, "/v1/apps/a/routes/myroute", `{ "route": { "type": "sync" } }`, http.StatusBadRequest, models.ErrMissingImage},
|
{datastore.NewMock(), logs.NewMock(), http.MethodPut, "/v1/apps/a/routes/myroute", `{ "route": { "type": "sync" } }`, http.StatusBadRequest, models.ErrRoutesMissingImage},
|
||||||
{datastore.NewMock(), logs.NewMock(), http.MethodPut, "/v1/apps/a/routes/myroute", `{ "route": { "path": "/myroute", "type": "sync" } }`, http.StatusBadRequest, models.ErrMissingImage},
|
{datastore.NewMock(), logs.NewMock(), http.MethodPut, "/v1/apps/a/routes/myroute", `{ "route": { "path": "/myroute", "type": "sync" } }`, http.StatusBadRequest, models.ErrRoutesMissingImage},
|
||||||
{datastore.NewMock(), logs.NewMock(), http.MethodPut, "/v1/apps/a/routes/myroute", `{ "route": { "image": "fnproject/hello", "path": "myroute", "type": "sync" } }`, http.StatusConflict, models.ErrRoutesPathImmutable},
|
{datastore.NewMock(), logs.NewMock(), http.MethodPut, "/v1/apps/a/routes/myroute", `{ "route": { "image": "fnproject/hello", "path": "myroute", "type": "sync" } }`, http.StatusConflict, models.ErrRoutesPathImmutable},
|
||||||
{datastore.NewMock(), logs.NewMock(), http.MethodPut, "/v1/apps/a/routes/myroute", `{ "route": { "image": "fnproject/hello", "path": "diffRoute", "type": "sync" } }`, http.StatusConflict, models.ErrRoutesPathImmutable},
|
{datastore.NewMock(), logs.NewMock(), http.MethodPut, "/v1/apps/a/routes/myroute", `{ "route": { "image": "fnproject/hello", "path": "diffRoute", "type": "sync" } }`, http.StatusConflict, models.ErrRoutesPathImmutable},
|
||||||
{datastore.NewMock(), logs.NewMock(), http.MethodPut, "/v1/apps/$/routes/myroute", `{ "route": { "image": "fnproject/hello", "path": "/myroute", "type": "sync" } }`, http.StatusBadRequest, models.ErrAppsValidationInvalidName},
|
{datastore.NewMock(), logs.NewMock(), http.MethodPut, "/v1/apps/$/routes/myroute", `{ "route": { "image": "fnproject/hello", "path": "/myroute", "type": "sync" } }`, http.StatusBadRequest, models.ErrAppsInvalidName},
|
||||||
{datastore.NewMock(), logs.NewMock(), http.MethodPut, "/v1/apps/a/routes/myroute", `{ "route": { "image": "fnproject/hello", "path": "/myroute", "type": "invalid-type" } }`, http.StatusBadRequest, models.ErrInvalidType},
|
{datastore.NewMock(), logs.NewMock(), http.MethodPut, "/v1/apps/a/routes/myroute", `{ "route": { "image": "fnproject/hello", "path": "/myroute", "type": "invalid-type" } }`, http.StatusBadRequest, models.ErrRoutesInvalidType},
|
||||||
{datastore.NewMock(), logs.NewMock(), http.MethodPut, "/v1/apps/a/routes/myroute", `{ "route": { "image": "fnproject/hello", "path": "/myroute", "format": "invalid-format", "type": "sync" } }`, http.StatusBadRequest, models.ErrInvalidFormat},
|
{datastore.NewMock(), logs.NewMock(), http.MethodPut, "/v1/apps/a/routes/myroute", `{ "route": { "image": "fnproject/hello", "path": "/myroute", "format": "invalid-format", "type": "sync" } }`, http.StatusBadRequest, models.ErrRoutesInvalidFormat},
|
||||||
|
|
||||||
// success
|
// success
|
||||||
{datastore.NewMock(), logs.NewMock(), http.MethodPut, "/v1/apps/a/routes/myroute", `{ "route": { "image": "fnproject/hello", "path": "/myroute", "type": "sync" } }`, http.StatusOK, nil},
|
{datastore.NewMock(), logs.NewMock(), http.MethodPut, "/v1/apps/a/routes/myroute", `{ "route": { "image": "fnproject/hello", "path": "/myroute", "type": "sync" } }`, http.StatusOK, nil},
|
||||||
@@ -189,7 +189,7 @@ func TestRouteList(t *testing.T) {
|
|||||||
expectedLen int
|
expectedLen int
|
||||||
nextCursor string
|
nextCursor string
|
||||||
}{
|
}{
|
||||||
{"/v1/apps//routes", "", http.StatusBadRequest, models.ErrMissingAppName, 0, ""},
|
{"/v1/apps//routes", "", http.StatusBadRequest, models.ErrAppsMissingName, 0, ""},
|
||||||
{"/v1/apps/a/routes", "", http.StatusNotFound, models.ErrAppsNotFound, 0, ""},
|
{"/v1/apps/a/routes", "", http.StatusNotFound, models.ErrAppsNotFound, 0, ""},
|
||||||
{"/v1/apps/myapp/routes", "", http.StatusOK, nil, 3, ""},
|
{"/v1/apps/myapp/routes", "", http.StatusOK, nil, 3, ""},
|
||||||
{"/v1/apps/myapp/routes?per_page=1", "", http.StatusOK, nil, 1, r1b},
|
{"/v1/apps/myapp/routes?per_page=1", "", http.StatusOK, nil, 1, r1b},
|
||||||
@@ -274,33 +274,30 @@ func TestRouteGet(t *testing.T) {
|
|||||||
|
|
||||||
func TestRouteUpdate(t *testing.T) {
|
func TestRouteUpdate(t *testing.T) {
|
||||||
buf := setLogBuffer()
|
buf := setLogBuffer()
|
||||||
|
ds := datastore.NewMockInit(nil, nil, nil)
|
||||||
|
|
||||||
for i, test := range []routeTestCase{
|
for i, test := range []routeTestCase{
|
||||||
// errors
|
|
||||||
{datastore.NewMock(), logs.NewMock(), http.MethodPatch, "/v1/apps/a/routes/myroute/do", ``, http.StatusBadRequest, models.ErrInvalidJSON},
|
|
||||||
{datastore.NewMock(), logs.NewMock(), http.MethodPatch, "/v1/apps/a/routes/myroute/do", `{}`, http.StatusBadRequest, models.ErrRoutesMissingNew},
|
|
||||||
{datastore.NewMock(), logs.NewMock(), http.MethodPatch, "/v1/apps/a/routes/myroute/do", `{ "route": { "type": "invalid-type" } }`, http.StatusBadRequest, models.ErrInvalidType},
|
|
||||||
{datastore.NewMock(), logs.NewMock(), http.MethodPatch, "/v1/apps/a/routes/myroute/do", `{ "route": { "format": "invalid-format" } }`, http.StatusBadRequest, models.ErrInvalidFormat},
|
|
||||||
|
|
||||||
// success
|
// success
|
||||||
{datastore.NewMockInit(nil,
|
{ds, logs.NewMock(), http.MethodPut, "/v1/apps/a/routes/myroute/do", `{ "route": { "image": "fnproject/yodawg" } }`, http.StatusOK, nil},
|
||||||
[]*models.Route{
|
{ds, logs.NewMock(), http.MethodPatch, "/v1/apps/a/routes/myroute/do", `{ "route": { "image": "fnproject/hello" } }`, http.StatusOK, nil},
|
||||||
{
|
|
||||||
AppName: "a",
|
// errors (after success, so route exists)
|
||||||
Path: "/myroute/do",
|
{ds, logs.NewMock(), http.MethodPatch, "/v1/apps/a/routes/myroute/do", ``, http.StatusBadRequest, models.ErrInvalidJSON},
|
||||||
},
|
{ds, logs.NewMock(), http.MethodPatch, "/v1/apps/a/routes/myroute/do", `{}`, http.StatusBadRequest, models.ErrRoutesMissingNew},
|
||||||
}, nil,
|
{ds, logs.NewMock(), http.MethodPatch, "/v1/apps/a/routes/myroute/do", `{ "route": { "type": "invalid-type" } }`, http.StatusBadRequest, models.ErrRoutesInvalidType},
|
||||||
), logs.NewMock(), http.MethodPatch, "/v1/apps/a/routes/myroute/do", `{ "route": { "image": "fnproject/hello" } }`, http.StatusOK, nil},
|
{ds, logs.NewMock(), http.MethodPatch, "/v1/apps/a/routes/myroute/do", `{ "route": { "format": "invalid-format" } }`, http.StatusBadRequest, models.ErrRoutesInvalidFormat},
|
||||||
|
{ds, logs.NewMock(), http.MethodPatch, "/v1/apps/a/routes/myroute/do", `{ "route": { "timeout": 121 } }`, http.StatusBadRequest, models.ErrRoutesInvalidTimeout},
|
||||||
|
{ds, logs.NewMock(), http.MethodPatch, "/v1/apps/a/routes/myroute/do", `{ "route": { "type": "async", "timeout": 3601 } }`, http.StatusBadRequest, models.ErrRoutesInvalidTimeout},
|
||||||
|
{ds, logs.NewMock(), http.MethodPatch, "/v1/apps/a/routes/myroute/do", `{ "route": { "type": "async", "timeout": 121, "idle_timeout": 240 } }`, http.StatusOK, nil}, // should work if async
|
||||||
|
{ds, logs.NewMock(), http.MethodPatch, "/v1/apps/a/routes/myroute/do", `{ "route": { "idle_timeout": 3601 } }`, http.StatusBadRequest, models.ErrRoutesInvalidIdleTimeout},
|
||||||
|
{ds, logs.NewMock(), http.MethodPatch, "/v1/apps/a/routes/myroute/do", `{ "route": { "timeout": 241 } }`, http.StatusBadRequest, models.ErrRoutesTimeoutLongerThanIdle},
|
||||||
|
{ds, logs.NewMock(), http.MethodPatch, "/v1/apps/a/routes/myroute/do", `{ "route": { "memory": 100000000000000 } }`, http.StatusBadRequest, models.ErrRoutesInvalidMemory},
|
||||||
|
// TODO this should be correct, waiting for patch to come in
|
||||||
|
//{ds, logs.NewMock(), http.MethodPatch, "/v1/apps/b/routes/myroute/dont", `{ "route": {} }`, http.StatusNotFound, models.ErrAppsNotFound},
|
||||||
|
{ds, logs.NewMock(), http.MethodPatch, "/v1/apps/a/routes/myroute/dont", `{ "route": {} }`, http.StatusNotFound, models.ErrRoutesNotFound},
|
||||||
|
|
||||||
// Addresses #381
|
// Addresses #381
|
||||||
{datastore.NewMockInit(nil,
|
{ds, logs.NewMock(), http.MethodPatch, "/v1/apps/a/routes/myroute/do", `{ "route": { "path": "/otherpath" } }`, http.StatusConflict, models.ErrRoutesPathImmutable},
|
||||||
[]*models.Route{
|
|
||||||
{
|
|
||||||
AppName: "a",
|
|
||||||
Path: "/myroute/do",
|
|
||||||
},
|
|
||||||
}, nil,
|
|
||||||
), logs.NewMock(), http.MethodPatch, "/v1/apps/a/routes/myroute/do", `{ "route": { "path": "/otherpath" } }`, http.StatusConflict, models.ErrRoutesPathImmutable},
|
|
||||||
} {
|
} {
|
||||||
test.run(t, i, buf)
|
test.run(t, i, buf)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -39,9 +39,9 @@ func TestRouteRunnerAsyncExecution(t *testing.T) {
|
|||||||
{Name: "myapp", Config: map[string]string{"app": "true"}},
|
{Name: "myapp", Config: map[string]string{"app": "true"}},
|
||||||
},
|
},
|
||||||
[]*models.Route{
|
[]*models.Route{
|
||||||
{Type: "async", Path: "/myroute", AppName: "myapp", Image: "fnproject/hello", Config: map[string]string{"test": "true"}},
|
{Type: "async", Path: "/myroute", AppName: "myapp", Image: "fnproject/hello", Config: map[string]string{"test": "true"}, Memory: 128, Timeout: 30, IdleTimeout: 30},
|
||||||
{Type: "async", Path: "/myerror", AppName: "myapp", Image: "fnproject/error", Config: map[string]string{"test": "true"}},
|
{Type: "async", Path: "/myerror", AppName: "myapp", Image: "fnproject/error", Config: map[string]string{"test": "true"}, Memory: 128, Timeout: 30, IdleTimeout: 30},
|
||||||
{Type: "async", Path: "/myroute/:param", AppName: "myapp", Image: "fnproject/hello", Config: map[string]string{"test": "true"}},
|
{Type: "async", Path: "/myroute/:param", AppName: "myapp", Image: "fnproject/hello", Config: map[string]string{"test": "true"}, Memory: 128, Timeout: 30, IdleTimeout: 30},
|
||||||
}, nil,
|
}, nil,
|
||||||
)
|
)
|
||||||
mq := &mqs.Mock{}
|
mq := &mqs.Mock{}
|
||||||
|
|||||||
@@ -4,6 +4,7 @@ import (
|
|||||||
"bytes"
|
"bytes"
|
||||||
"context"
|
"context"
|
||||||
"errors"
|
"errors"
|
||||||
|
"io/ioutil"
|
||||||
"net/http"
|
"net/http"
|
||||||
"strings"
|
"strings"
|
||||||
"testing"
|
"testing"
|
||||||
@@ -128,11 +129,11 @@ func TestRouteRunnerExecution(t *testing.T) {
|
|||||||
{Name: "myapp", Config: models.Config{}},
|
{Name: "myapp", Config: models.Config{}},
|
||||||
},
|
},
|
||||||
[]*models.Route{
|
[]*models.Route{
|
||||||
{Path: "/", AppName: "myapp", Image: "fnproject/hello", Headers: map[string][]string{"X-Function": {"Test"}}},
|
{Path: "/", AppName: "myapp", Image: "fnproject/hello", Type: "sync", Memory: 128, Timeout: 30, IdleTimeout: 30, Headers: map[string][]string{"X-Function": {"Test"}}},
|
||||||
{Path: "/myroute", AppName: "myapp", Image: "fnproject/hello", Headers: map[string][]string{"X-Function": {"Test"}}},
|
{Path: "/myroute", AppName: "myapp", Image: "fnproject/hello", Type: "sync", Memory: 128, Timeout: 30, IdleTimeout: 30, Headers: map[string][]string{"X-Function": {"Test"}}},
|
||||||
{Path: "/myerror", AppName: "myapp", Image: "fnproject/error", Headers: map[string][]string{"X-Function": {"Test"}}},
|
{Path: "/myerror", AppName: "myapp", Image: "fnproject/error", Type: "sync", Memory: 128, Timeout: 30, IdleTimeout: 30, Headers: map[string][]string{"X-Function": {"Test"}}},
|
||||||
{Path: "/mydne", AppName: "myapp", Image: "fnproject/imagethatdoesnotexist"},
|
{Path: "/mydne", AppName: "myapp", Image: "fnproject/imagethatdoesnotexist", Type: "sync", Memory: 128, Timeout: 30, IdleTimeout: 30},
|
||||||
{Path: "/mydnehot", AppName: "myapp", Image: "fnproject/imagethatdoesnotexist", Format: "http"},
|
{Path: "/mydnehot", AppName: "myapp", Image: "fnproject/imagethatdoesnotexist", Type: "sync", Format: "http", Memory: 128, Timeout: 30, IdleTimeout: 30},
|
||||||
}, nil,
|
}, nil,
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -165,8 +166,9 @@ func TestRouteRunnerExecution(t *testing.T) {
|
|||||||
|
|
||||||
if rec.Code != test.expectedCode {
|
if rec.Code != test.expectedCode {
|
||||||
t.Log(buf.String())
|
t.Log(buf.String())
|
||||||
t.Errorf("Test %d: Expected status code to be %d but was %d",
|
bod, _ := ioutil.ReadAll(rec.Body)
|
||||||
i, test.expectedCode, rec.Code)
|
t.Errorf("Test %d: Expected status code to be %d but was %d. body: %s",
|
||||||
|
i, test.expectedCode, rec.Code, string(bod))
|
||||||
}
|
}
|
||||||
|
|
||||||
if test.expectedHeaders == nil {
|
if test.expectedHeaders == nil {
|
||||||
@@ -200,7 +202,7 @@ func TestFailedEnqueue(t *testing.T) {
|
|||||||
{Name: "myapp", Config: models.Config{}},
|
{Name: "myapp", Config: models.Config{}},
|
||||||
},
|
},
|
||||||
[]*models.Route{
|
[]*models.Route{
|
||||||
{Path: "/dummy", AppName: "myapp", Image: "dummy/dummy", Type: "async"},
|
{Path: "/dummy", AppName: "myapp", Image: "dummy/dummy", Type: "async", Memory: 128, Timeout: 30, IdleTimeout: 30},
|
||||||
}, nil,
|
}, nil,
|
||||||
)
|
)
|
||||||
err := errors.New("Unable to push task to queue")
|
err := errors.New("Unable to push task to queue")
|
||||||
|
|||||||
@@ -215,7 +215,7 @@ func loggerWrap(c *gin.Context) {
|
|||||||
func appWrap(c *gin.Context) {
|
func appWrap(c *gin.Context) {
|
||||||
appName := c.GetString(api.AppName)
|
appName := c.GetString(api.AppName)
|
||||||
if appName == "" {
|
if appName == "" {
|
||||||
handleErrorResponse(c, models.ErrMissingAppName)
|
handleErrorResponse(c, models.ErrAppsMissingName)
|
||||||
c.Abort()
|
c.Abort()
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|||||||
3
test.sh
3
test.sh
@@ -2,9 +2,6 @@
|
|||||||
|
|
||||||
set -ex
|
set -ex
|
||||||
|
|
||||||
make build
|
|
||||||
make docker-build
|
|
||||||
|
|
||||||
docker rm -fv func-postgres-test || echo No prev test db container
|
docker rm -fv func-postgres-test || echo No prev test db container
|
||||||
docker run --name func-postgres-test -p 15432:5432 -d postgres
|
docker run --name func-postgres-test -p 15432:5432 -d postgres
|
||||||
docker rm -fv func-mysql-test || echo No prev mysql test db container
|
docker rm -fv func-mysql-test || echo No prev mysql test db container
|
||||||
|
|||||||
Reference in New Issue
Block a user