github.com/iron-io/functions@v0.0.0-20180820112432-d59d7d1c40b2/api/server/server_test.go (about) 1 // +build server 2 3 package server 4 5 import ( 6 "bytes" 7 "context" 8 "encoding/json" 9 "io" 10 "io/ioutil" 11 "net/http" 12 "net/http/httptest" 13 "os" 14 "testing" 15 16 "github.com/gin-gonic/gin" 17 "github.com/iron-io/functions/api/datastore" 18 "github.com/iron-io/functions/api/models" 19 "github.com/iron-io/functions/api/mqs" 20 "github.com/iron-io/functions/api/runner" 21 "github.com/iron-io/functions/api/runner/task" 22 "github.com/iron-io/functions/api/server/internal/routecache" 23 ) 24 25 var tmpBolt = "/tmp/bolt_fn_server.db" 26 27 type Suite []struct { 28 name string 29 method string 30 path string 31 body string 32 expectedCode int 33 expectedCacheSize int 34 } 35 36 var testSuite = Suite{ 37 {"create my app", "POST", "/v1/apps", `{ "app": { "name": "myapp" } }`, http.StatusOK, 0}, 38 {"list apps", "GET", "/v1/apps", ``, http.StatusOK, 0}, 39 {"get app", "GET", "/v1/apps/myapp", ``, http.StatusOK, 0}, 40 {"add myroute", "POST", "/v1/apps/myapp/routes", `{ "route": { "name": "myroute", "path": "/myroute", "image": "iron/hello" } }`, http.StatusOK, 1}, 41 {"add myroute2", "POST", "/v1/apps/myapp/routes", `{ "route": { "name": "myroute2", "path": "/myroute2", "image": "iron/error" } }`, http.StatusOK, 2}, 42 {"get myroute", "GET", "/v1/apps/myapp/routes/myroute", ``, http.StatusOK, 2}, 43 {"get myroute2", "GET", "/v1/apps/myapp/routes/myroute2", ``, http.StatusOK, 2}, 44 {"get all routes", "GET", "/v1/apps/myapp/routes", ``, http.StatusOK, 2}, 45 {"execute myroute", "POST", "/r/myapp/myroute", `{ "name": "Teste" }`, http.StatusOK, 2}, 46 {"execute myroute2", "POST", "/r/myapp/myroute2", `{ "name": "Teste" }`, http.StatusInternalServerError, 2}, 47 {"delete myroute", "DELETE", "/v1/apps/myapp/routes/myroute", ``, http.StatusOK, 1}, 48 {"delete app (fail)", "DELETE", "/v1/apps/myapp", ``, http.StatusBadRequest, 1}, 49 {"delete myroute2", "DELETE", "/v1/apps/myapp/routes/myroute2", ``, http.StatusOK, 0}, 50 {"delete app (success)", "DELETE", "/v1/apps/myapp", ``, http.StatusOK, 0}, 51 {"get deleted app", "GET", "/v1/apps/myapp", ``, http.StatusNotFound, 0}, 52 {"get deleteds route on deleted app", "GET", "/v1/apps/myapp/routes/myroute", ``, http.StatusNotFound, 0}, 53 } 54 55 func testServer(ds models.Datastore, mq models.MessageQueue, rnr *runner.Runner, tasks chan task.Request) *Server { 56 ctx := context.Background() 57 58 s := &Server{ 59 Runner: rnr, 60 Router: gin.New(), 61 Datastore: ds, 62 MQ: mq, 63 tasks: tasks, 64 Enqueue: DefaultEnqueue, 65 hotroutes: routecache.New(2), 66 } 67 68 r := s.Router 69 r.Use(gin.Logger()) 70 71 s.Router.Use(prepareMiddleware(ctx)) 72 s.bindHandlers(ctx) 73 s.setupMiddlewares() 74 75 return s 76 } 77 78 func routerRequest(t *testing.T, router *gin.Engine, method, path string, body io.Reader) (*http.Request, *httptest.ResponseRecorder) { 79 req, err := http.NewRequest(method, "http://127.0.0.1:8080"+path, body) 80 if err != nil { 81 t.Fatalf("Test: Could not create %s request to %s: %v", method, path, err) 82 } 83 84 rec := httptest.NewRecorder() 85 router.ServeHTTP(rec, req) 86 87 return req, rec 88 } 89 90 func newRouterRequest(t *testing.T, method, path string, body io.Reader) (*http.Request, *httptest.ResponseRecorder) { 91 req, err := http.NewRequest(method, "http://127.0.0.1:8080"+path, body) 92 if err != nil { 93 t.Fatalf("Test: Could not create %s request to %s: %v", method, path, err) 94 } 95 96 rec := httptest.NewRecorder() 97 98 return req, rec 99 } 100 101 func getErrorResponse(t *testing.T, rec *httptest.ResponseRecorder) models.Error { 102 respBody, err := ioutil.ReadAll(rec.Body) 103 if err != nil { 104 t.Error("Test: Expected not empty response body") 105 } 106 107 var errResp models.Error 108 err = json.Unmarshal(respBody, &errResp) 109 if err != nil { 110 t.Error("Test: Expected response body to be a valid models.Error object") 111 } 112 113 return errResp 114 } 115 116 func prepareBolt(t *testing.T) models.Datastore { 117 ds, err := datastore.New("bolt://" + tmpBolt) 118 if err != nil { 119 t.Fatal("Error when creating datastore: %s", err) 120 } 121 return ds 122 } 123 124 func TestFullStackWithNoAuth(t *testing.T) { 125 testFullStack(t, setJwtAuth, testSuite) 126 teardown() 127 } 128 129 func teardown() { 130 os.Remove(tmpBolt) 131 } 132 133 func testFullStack(t *testing.T, authFn func(*http.Request), suite Suite) { 134 buf := setLogBuffer() 135 ds := prepareBolt(t) 136 137 tasks := make(chan task.Request) 138 ctx, cancel := context.WithCancel(context.Background()) 139 defer cancel() 140 141 rnr, rnrcancel := testRunner(t) 142 defer rnrcancel() 143 144 go runner.StartWorkers(ctx, rnr, tasks) 145 146 srv := testServer(ds, &mqs.Mock{}, rnr, tasks) 147 srv.hotroutes = routecache.New(2) 148 149 for _, test := range suite { 150 _, rec := routerRequestWithAuth(t, srv.Router, test.method, test.path, bytes.NewBuffer([]byte(test.body)), authFn) 151 152 if rec.Code != test.expectedCode { 153 t.Log(buf.String()) 154 t.Errorf("Test \"%s\": Expected status code to be %d but was %d", 155 test.name, test.expectedCode, rec.Code) 156 } 157 if srv.hotroutes.Len() != test.expectedCacheSize { 158 t.Log(buf.String()) 159 t.Errorf("Test \"%s\": Expected cache size to be %d but was %d", 160 test.name, test.expectedCacheSize, srv.hotroutes.Len()) 161 } 162 } 163 }