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  }