From b319fa6b314d6d44a143e34b8fe8d04dad634c7c Mon Sep 17 00:00:00 2001 From: Pedro Nasser Date: Fri, 29 Jul 2016 19:35:38 -0300 Subject: [PATCH] initial router tests: apps --- api/server/datastore/mock.go | 37 ++++ .../{apps_destroy.go => apps_delete.go} | 2 +- api/server/router/apps_test.go | 176 ++++++++++++++++++ api/server/router/apps_update.go | 20 ++ api/server/router/helpers.go | 53 ++++++ api/server/router/router.go | 4 +- .../{routes_destroy.go => routes_delete.go} | 2 +- api/server/router/routes_test.go | 1 + api/server/router/runner.go | 5 + api/server/router/runner_test.go | 1 + 10 files changed, 297 insertions(+), 4 deletions(-) create mode 100644 api/server/datastore/mock.go rename api/server/router/{apps_destroy.go => apps_delete.go} (92%) create mode 100644 api/server/router/apps_test.go create mode 100644 api/server/router/helpers.go rename api/server/router/{routes_destroy.go => routes_delete.go} (92%) create mode 100644 api/server/router/routes_test.go create mode 100644 api/server/router/runner_test.go diff --git a/api/server/datastore/mock.go b/api/server/datastore/mock.go new file mode 100644 index 000000000..588fa5d33 --- /dev/null +++ b/api/server/datastore/mock.go @@ -0,0 +1,37 @@ +package datastore + +import "github.com/iron-io/functions/api/models" + +type Mock struct{} + +func (m *Mock) GetApp(app string) (*models.App, error) { + return nil, nil +} + +func (m *Mock) GetApps(appFilter *models.AppFilter) ([]*models.App, error) { + return nil, nil +} + +func (m *Mock) StoreApp(app *models.App) (*models.App, error) { + return nil, nil +} + +func (m *Mock) RemoveApp(app string) error { + return nil +} + +func (m *Mock) GetRoute(app, route string) (*models.Route, error) { + return nil, nil +} + +func (m *Mock) GetRoutes(routeFilter *models.RouteFilter) ([]*models.Route, error) { + return nil, nil +} + +func (m *Mock) StoreRoute(route *models.Route) (*models.Route, error) { + return nil, nil +} + +func (m *Mock) RemoveRoute(app, route string) error { + return nil +} diff --git a/api/server/router/apps_destroy.go b/api/server/router/apps_delete.go similarity index 92% rename from api/server/router/apps_destroy.go rename to api/server/router/apps_delete.go index 454cb5b64..9d9c14fa8 100644 --- a/api/server/router/apps_destroy.go +++ b/api/server/router/apps_delete.go @@ -8,7 +8,7 @@ import ( "github.com/iron-io/functions/api/models" ) -func handleAppDestroy(c *gin.Context) { +func handleAppDelete(c *gin.Context) { store := c.MustGet("store").(models.Datastore) log := c.MustGet("log").(logrus.FieldLogger) diff --git a/api/server/router/apps_test.go b/api/server/router/apps_test.go new file mode 100644 index 000000000..f7c7f4aca --- /dev/null +++ b/api/server/router/apps_test.go @@ -0,0 +1,176 @@ +package router + +import ( + "bytes" + "net/http" + "strings" + "testing" + + "github.com/iron-io/functions/api/models" +) + +func TestAppCreate(t *testing.T) { + router := testRouter() + + for i, test := range []struct { + path string + body string + expectedCode int + expectedError error + }{ + // errors + {"/v1/apps", ``, http.StatusBadRequest, models.ErrInvalidJSON}, + {"/v1/apps", `{}`, http.StatusBadRequest, models.ErrAppsMissingNew}, + {"/v1/apps", `{ "name": "Test" }`, http.StatusBadRequest, models.ErrAppsMissingNew}, + {"/v1/apps", `{ "app": { "name": "" } }`, http.StatusInternalServerError, models.ErrAppsValidationMissingName}, + {"/v1/apps", `{ "app": { "name": "1234567890123456789012345678901" } }`, http.StatusInternalServerError, models.ErrAppsValidationTooLongName}, + {"/v1/apps", `{ "app": { "name": "&&%@!#$#@$" } }`, http.StatusInternalServerError, models.ErrAppsValidationInvalidName}, + {"/v1/apps", `{ "app": { "name": "&&%@!#$#@$" } }`, http.StatusInternalServerError, models.ErrAppsValidationInvalidName}, + + // success + {"/v1/apps", `{ "app": { "name": "teste" } }`, http.StatusOK, nil}, + } { + body := bytes.NewBuffer([]byte(test.body)) + _, rec := routerRequest(t, router, "POST", test.path, body) + + if rec.Code != test.expectedCode { + 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.Errorf("Test %d: Expected error message to have `%s`", + i, test.expectedError.Error()) + } + } + } +} + +func TestAppDelete(t *testing.T) { + router := testRouter() + + for i, test := range []struct { + path string + body string + expectedCode int + expectedError error + }{ + {"/v1/apps", "", http.StatusNotFound, nil}, + {"/v1/apps/myapp", "", http.StatusOK, nil}, + } { + _, rec := routerRequest(t, router, "DELETE", test.path, nil) + + if rec.Code != test.expectedCode { + 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.Errorf("Test %d: Expected error message to have `%s`", + i, test.expectedError.Error()) + } + } + } +} + +func TestAppList(t *testing.T) { + router := testRouter() + + 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.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.Errorf("Test %d: Expected error message to have `%s`", + i, test.expectedError.Error()) + } + } + } +} + +func TestAppGet(t *testing.T) { + router := testRouter() + + 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.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.Errorf("Test %d: Expected error message to have `%s`", + i, test.expectedError.Error()) + } + } + } +} + +func TestAppUpdate(t *testing.T) { + router := testRouter() + + for i, test := range []struct { + path string + body string + expectedCode int + expectedError error + }{ + // errors + {"/v1/apps/myapp", ``, http.StatusBadRequest, models.ErrInvalidJSON}, + {"/v1/apps/myapp", `{ "name": "" }`, http.StatusInternalServerError, models.ErrAppsValidationMissingName}, + {"/v1/apps/myapp", `{ "name": "1234567890123456789012345678901" }`, http.StatusInternalServerError, models.ErrAppsValidationTooLongName}, + {"/v1/apps/myapp", `{ "name": "&&%@!#$#@$" }`, http.StatusInternalServerError, models.ErrAppsValidationInvalidName}, + {"/v1/apps/myapp", `{ "name": "&&%@!#$#@$" }`, http.StatusInternalServerError, models.ErrAppsValidationInvalidName}, + + // success + {"/v1/apps/myapp", `{ "name": "teste" }`, http.StatusOK, nil}, + } { + body := bytes.NewBuffer([]byte(test.body)) + _, rec := routerRequest(t, router, "PUT", test.path, body) + + if rec.Code != test.expectedCode { + 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.Errorf("Test %d: Expected error message to have `%s`", + i, test.expectedError.Error()) + } + } + } +} diff --git a/api/server/router/apps_update.go b/api/server/router/apps_update.go index f00f331ce..90beedf03 100644 --- a/api/server/router/apps_update.go +++ b/api/server/router/apps_update.go @@ -21,5 +21,25 @@ func handleAppUpdate(c *gin.Context) { return } + if app == nil { + log.Debug(models.ErrAppsMissingNew) + c.JSON(http.StatusBadRequest, simpleError(models.ErrAppsMissingNew)) + return + } + + if err := app.Validate(); err != nil { + log.Error(err) + c.JSON(http.StatusInternalServerError, simpleError(err)) + return + } + + // app, err := store.StoreApp(wapp.App) + // if err != nil { + // log.WithError(err).Debug(models.ErrAppsCreate) + // c.JSON(http.StatusInternalServerError, simpleError(models.ErrAppsCreate)) + // return + // } + + // Nothing to update right now in apps c.JSON(http.StatusOK, simpleError(models.ErrAppsNothingToUpdate)) } diff --git a/api/server/router/helpers.go b/api/server/router/helpers.go new file mode 100644 index 000000000..56b6c241d --- /dev/null +++ b/api/server/router/helpers.go @@ -0,0 +1,53 @@ +package router + +import ( + "encoding/json" + "io" + "io/ioutil" + "net/http" + "net/http/httptest" + "testing" + + "github.com/Sirupsen/logrus" + "github.com/gin-gonic/gin" + "github.com/iron-io/functions/api/models" + "github.com/iron-io/functions/api/server/datastore" +) + +func testRouter() *gin.Engine { + r := gin.Default() + r.Use(func(c *gin.Context) { + c.Set("store", &datastore.Mock{}) + c.Set("log", logrus.WithFields(logrus.Fields{})) + c.Next() + }) + Start(r) + return r +} + +func routerRequest(t *testing.T, router *gin.Engine, method, path string, body io.Reader) (*http.Request, *httptest.ResponseRecorder) { + req, err := http.NewRequest(method, "http://localhost:8080"+path, body) + if err != nil { + t.Fatalf("Test: Could not create %s request to %s: %v", method, path, err) + } + + rec := httptest.NewRecorder() + router.ServeHTTP(rec, req) + + return req, rec +} + +func getErrorResponse(t *testing.T, rec *httptest.ResponseRecorder) models.Error { + respBody, err := ioutil.ReadAll(rec.Body) + if err != nil { + t.Error("Test: Expected not empty response body") + } + + var errResp models.Error + err = json.Unmarshal(respBody, &errResp) + if err != nil { + t.Error("Test: Expected response body to be a valid models.Error object") + } + + return errResp +} diff --git a/api/server/router/router.go b/api/server/router/router.go index 8178be917..712d5e450 100644 --- a/api/server/router/router.go +++ b/api/server/router/router.go @@ -16,7 +16,7 @@ func Start(engine *gin.Engine) { v1.GET("/apps/:app", handleAppGet) v1.PUT("/apps/:app", handleAppUpdate) - v1.DELETE("/apps/:app", handleAppDestroy) + v1.DELETE("/apps/:app", handleAppDelete) apps := v1.Group("/apps/:app") { @@ -24,7 +24,7 @@ func Start(engine *gin.Engine) { apps.POST("/routes", handleRouteCreate) apps.GET("/routes/:route", handleRouteGet) apps.POST("/routes/:route", handleRouteUpdate) - apps.DELETE("/routes/:route", handleRouteDestroy) + apps.DELETE("/routes/:route", handleRouteDelete) } } diff --git a/api/server/router/routes_destroy.go b/api/server/router/routes_delete.go similarity index 92% rename from api/server/router/routes_destroy.go rename to api/server/router/routes_delete.go index d61fde6f4..6f2f35b8b 100644 --- a/api/server/router/routes_destroy.go +++ b/api/server/router/routes_delete.go @@ -8,7 +8,7 @@ import ( "github.com/iron-io/functions/api/models" ) -func handleRouteDestroy(c *gin.Context) { +func handleRouteDelete(c *gin.Context) { store := c.MustGet("store").(models.Datastore) log := c.MustGet("log").(logrus.FieldLogger) diff --git a/api/server/router/routes_test.go b/api/server/router/routes_test.go new file mode 100644 index 000000000..461fcf442 --- /dev/null +++ b/api/server/router/routes_test.go @@ -0,0 +1 @@ +package router \ No newline at end of file diff --git a/api/server/router/runner.go b/api/server/router/runner.go index 7fef10a70..85c391f96 100644 --- a/api/server/router/runner.go +++ b/api/server/router/runner.go @@ -13,6 +13,11 @@ import ( ) func handleRunner(c *gin.Context) { + if strings.HasPrefix(c.Request.URL.Path, "/v1") { + c.Status(http.StatusNotFound) + return + } + log := c.MustGet("log").(logrus.FieldLogger) store := c.MustGet("store").(models.Datastore) config := c.MustGet("config").(*models.Config) diff --git a/api/server/router/runner_test.go b/api/server/router/runner_test.go new file mode 100644 index 000000000..7ef135b39 --- /dev/null +++ b/api/server/router/runner_test.go @@ -0,0 +1 @@ +package router