Files
fn-serverless/api/server/apps_test.go
C Cirello 3b16b7f1d8 functions: application updates no longer accept name in the body (#391)
* functions: application updates no longer accept name in the body

AppUpdate was initially conceived as an upsert endpoint for apps.
It turns out that it created an inconsistency regarding updates:
updates with names divergent with URL would not actually change
application's name.

This commit atempts to address the issue by returning an HTTP
error when trying to update an application name. In swagger.yml,
application names are already `readOnly:true`. Thus there is no
change from expected behavior.

Fixes #380

* functions: use specific error value for name change
2016-12-07 19:54:21 +01:00

256 lines
6.6 KiB
Go

package server
import (
"bytes"
"log"
"net/http"
"strings"
"testing"
"github.com/Sirupsen/logrus"
"github.com/gin-gonic/gin"
"github.com/iron-io/functions/api/datastore"
"github.com/iron-io/functions/api/models"
"github.com/iron-io/functions/api/mqs"
"github.com/iron-io/functions/api/runner/task"
)
func setLogBuffer() *bytes.Buffer {
var buf bytes.Buffer
buf.WriteByte('\n')
logrus.SetOutput(&buf)
gin.DefaultErrorWriter = &buf
gin.DefaultWriter = &buf
log.SetOutput(&buf)
return &buf
}
func mockTasksConduit() chan task.Request {
tasks := make(chan task.Request)
go func() {
for range tasks {
}
}()
return tasks
}
func TestAppCreate(t *testing.T) {
buf := setLogBuffer()
tasks := mockTasksConduit()
defer close(tasks)
for i, test := range []struct {
mock *datastore.Mock
path string
body string
expectedCode int
expectedError error
}{
// errors
{&datastore.Mock{}, "/v1/apps", ``, http.StatusBadRequest, models.ErrInvalidJSON},
{&datastore.Mock{}, "/v1/apps", `{}`, http.StatusBadRequest, models.ErrAppsMissingNew},
{&datastore.Mock{}, "/v1/apps", `{ "name": "Test" }`, http.StatusBadRequest, models.ErrAppsMissingNew},
{&datastore.Mock{}, "/v1/apps", `{ "app": { "name": "" } }`, http.StatusInternalServerError, models.ErrAppsValidationMissingName},
{&datastore.Mock{}, "/v1/apps", `{ "app": { "name": "1234567890123456789012345678901" } }`, http.StatusInternalServerError, models.ErrAppsValidationTooLongName},
{&datastore.Mock{}, "/v1/apps", `{ "app": { "name": "&&%@!#$#@$" } }`, http.StatusInternalServerError, models.ErrAppsValidationInvalidName},
{&datastore.Mock{}, "/v1/apps", `{ "app": { "name": "&&%@!#$#@$" } }`, http.StatusInternalServerError, models.ErrAppsValidationInvalidName},
// success
{&datastore.Mock{}, "/v1/apps", `{ "app": { "name": "teste" } }`, http.StatusCreated, nil},
} {
rnr, cancel := testRunner(t)
router := testRouter(test.mock, &mqs.Mock{}, rnr, tasks)
body := bytes.NewBuffer([]byte(test.body))
_, rec := routerRequest(t, router, "POST", test.path, body)
if rec.Code != test.expectedCode {
t.Log(buf.String())
t.Errorf("Test %d: Expected status code to be %d but was %d",
i, test.expectedCode, rec.Code)
}
if test.expectedError != nil {
resp := getErrorResponse(t, rec)
if !strings.Contains(resp.Error.Message, test.expectedError.Error()) {
t.Log(buf.String())
t.Errorf("Test %d: Expected error message to have `%s`",
i, test.expectedError.Error())
}
}
cancel()
}
}
func TestAppDelete(t *testing.T) {
buf := setLogBuffer()
tasks := mockTasksConduit()
defer close(tasks)
for i, test := range []struct {
ds models.Datastore
path string
body string
expectedCode int
expectedError error
}{
{&datastore.Mock{}, "/v1/apps", "", http.StatusNotFound, nil},
{&datastore.Mock{
Apps: []*models.App{{
Name: "myapp",
}},
}, "/v1/apps/myapp", "", http.StatusOK, nil},
} {
rnr, cancel := testRunner(t)
router := testRouter(test.ds, &mqs.Mock{}, rnr, tasks)
_, rec := routerRequest(t, router, "DELETE", test.path, nil)
if rec.Code != test.expectedCode {
t.Log(buf.String())
t.Errorf("Test %d: Expected status code to be %d but was %d",
i, test.expectedCode, rec.Code)
}
if test.expectedError != nil {
resp := getErrorResponse(t, rec)
if !strings.Contains(resp.Error.Message, test.expectedError.Error()) {
t.Log(buf.String())
t.Errorf("Test %d: Expected error message to have `%s`",
i, test.expectedError.Error())
}
}
cancel()
}
}
func TestAppList(t *testing.T) {
buf := setLogBuffer()
tasks := mockTasksConduit()
defer close(tasks)
rnr, cancel := testRunner(t)
defer cancel()
router := testRouter(&datastore.Mock{}, &mqs.Mock{}, rnr, tasks)
for i, test := range []struct {
path string
body string
expectedCode int
expectedError error
}{
{"/v1/apps", "", http.StatusOK, nil},
} {
_, rec := routerRequest(t, router, "GET", test.path, nil)
if rec.Code != test.expectedCode {
t.Log(buf.String())
t.Errorf("Test %d: Expected status code to be %d but was %d",
i, test.expectedCode, rec.Code)
}
if test.expectedError != nil {
resp := getErrorResponse(t, rec)
if !strings.Contains(resp.Error.Message, test.expectedError.Error()) {
t.Log(buf.String())
t.Errorf("Test %d: Expected error message to have `%s`",
i, test.expectedError.Error())
}
}
}
}
func TestAppGet(t *testing.T) {
buf := setLogBuffer()
tasks := mockTasksConduit()
defer close(tasks)
rnr, cancel := testRunner(t)
defer cancel()
router := testRouter(&datastore.Mock{}, &mqs.Mock{}, rnr, tasks)
for i, test := range []struct {
path string
body string
expectedCode int
expectedError error
}{
{"/v1/apps/myapp", "", http.StatusNotFound, nil},
} {
_, rec := routerRequest(t, router, "GET", test.path, nil)
if rec.Code != test.expectedCode {
t.Log(buf.String())
t.Errorf("Test %d: Expected status code to be %d but was %d",
i, test.expectedCode, rec.Code)
}
if test.expectedError != nil {
resp := getErrorResponse(t, rec)
if !strings.Contains(resp.Error.Message, test.expectedError.Error()) {
t.Log(buf.String())
t.Errorf("Test %d: Expected error message to have `%s`",
i, test.expectedError.Error())
}
}
}
}
func TestAppUpdate(t *testing.T) {
buf := setLogBuffer()
tasks := mockTasksConduit()
defer close(tasks)
for i, test := range []struct {
mock *datastore.Mock
path string
body string
expectedCode int
expectedError error
}{
// errors
{&datastore.Mock{}, "/v1/apps/myapp", ``, http.StatusBadRequest, models.ErrInvalidJSON},
// success
{&datastore.Mock{
Apps: []*models.App{{
Name: "myapp",
}},
}, "/v1/apps/myapp", `{ "app": { "config": { "test": "1" } } }`, http.StatusOK, nil},
// Addresses #380
{&datastore.Mock{
Apps: []*models.App{{
Name: "myapp",
}},
}, "/v1/apps/myapp", `{ "app": { "name": "othername" } }`, http.StatusForbidden, nil},
} {
rnr, cancel := testRunner(t)
router := testRouter(test.mock, &mqs.Mock{}, rnr, tasks)
body := bytes.NewBuffer([]byte(test.body))
_, rec := routerRequest(t, router, "PUT", test.path, body)
if rec.Code != test.expectedCode {
t.Log(buf.String())
t.Errorf("Test %d: Expected status code to be %d but was %d",
i, test.expectedCode, rec.Code)
}
if test.expectedError != nil {
resp := getErrorResponse(t, rec)
if !strings.Contains(resp.Error.Message, test.expectedError.Error()) {
t.Log(buf.String())
t.Errorf("Test %d: Expected error message to have `%s`",
i, test.expectedError.Error())
}
}
cancel()
}
}