func TestRouter(t *testing.T) { tests := []struct { path string expectedRoute string }{ { // 0 "/", "/", }, { // 1 "/users", "/users", }, { // 2 "/users/meta", "/users/meta", }, { // 3 "/users/abc123", "/users/:id", }, { // 4 "/users/abc123/meta", "/users/:id/meta", }, { // 5 "/users/abc123/comments", "/users/:id/comments", }, { // 6 "/users/abc123/relationships/comments", "/users/:id/relationships/comments", }, { // 7 "/users/abc123/relationships/comments/meta", "/users/:id/relationships/comments/meta", }, { // 8 "/users/abc123/relationships/comments/def456", "/users/:id/relationships/comments/:id", }, } for i, test := range tests { path := strings.Split(test.path, "/")[1:] route := deduceRoute(path) tchek.AreEqual(t, i, test.expectedRoute, route) } }
func TestBuildSelfLink(t *testing.T) { tests := []struct { resource interface{} expectedString string }{ { // 0 user{ID: "1"}, "http://example.com/users/1", }, { // 1 &book{ID: "abc-123"}, "http://example.com/books/abc-123", }, { // 2 user{ID: ""}, "", }, { // 3 time.Now(), "", }, { // 4 "", "", }, } for i, test := range tests { link := buildSelfLink(reflect.ValueOf(test.resource)) tchek.AreEqual(t, i, test.expectedString, link) } }
func TestBasicRequests(t *testing.T) { testApp := NewApp() testApp.UseFunc(Recoverer) testApp.UseFunc(URLParser) testApp.RegisterModel(user{}) testApp.RegisterModel(comment{}) testApp.Get("/users", func(ctx context.Context, w ResponseWriter) context.Context { w.Write([]byte("users")) return ctx }, GatePublic) testApp.Get("/users/:id", func(ctx context.Context, w ResponseWriter) context.Context { r := GetRequest(ctx) w.Write([]byte("user " + r.ResID)) return ctx }, GatePublic) testApp.Get("/users/:id/relationships/comments", func(ctx context.Context, w ResponseWriter) context.Context { r := GetRequest(ctx) w.Write([]byte("user " + r.ResID + " " + r.ResRel + " " + r.ResRelName)) return ctx }, GatePublic) testApp.Get("/users/:id/comments", func(ctx context.Context, w ResponseWriter) context.Context { r := GetRequest(ctx) w.Write([]byte("user " + r.ResID + " " + r.ResRel + " " + r.ResRelName)) return ctx }, GatePublic) testApp.Get("/comments", func(ctx context.Context, w ResponseWriter) context.Context { w.Write([]byte("comments")) return ctx }, GatePublic) server := httptest.NewServer(testApp) tests := []struct { url string expectedStatusCode int expectedBody string }{ { // 0 url: "/users", expectedStatusCode: http.StatusOK, expectedBody: "users", }, { // 1 url: "/users/abc123", expectedStatusCode: http.StatusOK, expectedBody: "user abc123", }, { // 2 url: "/users/abc123/relationships/comments", expectedStatusCode: http.StatusOK, expectedBody: "user abc123 self comments", }, { // 3 url: "/users/abc123/comments", expectedStatusCode: http.StatusOK, expectedBody: "user abc123 related comments", }, } for i, test := range tests { res := tchek.MakeRequest(server, "GET", test.url, "") fmt.Printf("\n") var body []byte body, err := ioutil.ReadAll(res.Body) tchek.UnintendedError(err) tchek.AreEqual(t, i, test.expectedStatusCode, res.StatusCode) tchek.AreEqual(t, i, test.expectedBody, string(body)) } }
func TestMarshalAndUnmarshal(t *testing.T) { tests := []struct { source interface{} destination interface{} params int marshalErrorExpected bool unmarshalErrorExpected bool }{ { // 0 nil, nil, 0, true, false, }, { // 1 users["1"], &user{}, 0, false, false, }, { // 2 []*user{users["1"], users["2"]}, &[]*user{}, 0, false, false, }, { // 3 []user{*users["1"], *users["2"]}, &[]*user{}, 0, false, false, }, { // 4 []*user{}, &[]user{}, 0, false, false, }, { // 5 []*user{users["1"], users["2"], users["3"]}, &user{}, 0, false, true, }, } options := []Options{ Options{ Extra: Extra{ JSONAPI: map[string]interface{}{ "version": "1.0", }, }, }, Options{ Extra: Extra{ Meta: map[string]interface{}{ "meta1": "value", "meta2": 38, }, JSONAPI: map[string]interface{}{ "version": "1.0", }, }, IncludeRelationshipIdentifiers: map[string]bool{ "books": false, }, }, } for n, test := range tests { payload, err := Marshal(test.source, options[0]) tchek.ErrorExpected(t, n, test.marshalErrorExpected, err) if !test.marshalErrorExpected { if printTests { log.Printf("Payload from test %d:\n", n) var out bytes.Buffer json.Indent(&out, payload, "", "\t") out.WriteTo(os.Stdout) fmt.Printf("\n") } err = Unmarshal(payload, test.destination) tchek.ErrorExpected(t, n, test.unmarshalErrorExpected, err) srcVal := reflect.ValueOf(test.destination).Elem() dstType := reflect.ValueOf(test.destination).Type().Elem() if dstType.Kind() == reflect.Slice { dstVal := reflect.ValueOf(test.destination).Elem() tchek.AreEqual(t, n, srcVal.Len(), dstVal.Len()) for i := 0; i < dstVal.Len(); i++ { tchek.AreShallowEqual(t, n, !test.unmarshalErrorExpected, srcVal.Index(i).Interface(), dstVal.Index(i).Interface()) } } else { tchek.AreShallowEqual(t, n, !test.unmarshalErrorExpected, test.source, test.destination) } } } }
func TestJWTParser(t *testing.T) { testApp := NewApp() testApp.UseFunc(Recoverer) testApp.UseFunc(URLParser) testApp.UseFunc(JWTParser) testApp.Get("/jwt", func(ctx context.Context, w ResponseWriter) context.Context { r := ctx.Value(key("id")).(string) for _, s := range ctx.Value(key("groups")).([]string) { r += s } w.Write([]byte(r)) return ctx }, GatePublic) server := httptest.NewServer(testApp) tests := []struct { id string groups []string expectation string }{ { // 0 id: "abc123", groups: []string{"admin", "developer", "founder"}, expectation: "abc123admindeveloperfounder", }, { // 1 id: "abc123", groups: []string{}, expectation: "abc123", }, { // 2 id: "", groups: []string{"public"}, expectation: "public", }, { // 3 id: "", groups: []string{}, expectation: "", }, } for i, test := range tests { token, err := cybele.GenerateJWT(map[string]interface{}{ "id": test.id, "groups": test.groups, }) tchek.UnintendedError(err) res := tchek.MakeRequest(server, "GET", "/jwt", token) fmt.Printf("\n") var body []byte body, err = ioutil.ReadAll(res.Body) tchek.UnintendedError(err) tchek.AreEqual(t, i, test.expectation, string(body)) } }
func TestURLParser(t *testing.T) { testApp := NewApp() testApp.UseFunc(URLParser) testApp.UseFunc(func(ctx context.Context, w ResponseWriter, next CtxHandlerFunc) context.Context { normURL := GetRequest(ctx).NormalizedURL w.Write([]byte(fmt.Sprintf("%v", normURL))) next(ctx, w) return ctx }) server := httptest.NewServer(testApp) tests := []struct { url string expectedStatusCode int expectedBody string }{ { // 0 url: "/", expectedStatusCode: http.StatusBadRequest, expectedBody: "", }, { // 1 url: "/type/1/relationships/rel", expectedStatusCode: http.StatusOK, expectedBody: "/type/1/relationships/rel", }, { // 2 url: "/type/1/relationships/rel/", expectedStatusCode: http.StatusOK, expectedBody: "/type/1/relationships/rel", }, { // 3 url: "/this/is/an/invalid/request", expectedStatusCode: http.StatusBadRequest, expectedBody: "", }, { // 4 url: "/request//invalid", expectedStatusCode: http.StatusBadRequest, expectedBody: "", }, { // 5 url: "/groups/1/users?fields[user]=id,name,age", expectedStatusCode: http.StatusOK, expectedBody: "/groups/1/users?fields[user]=age,id,name", }, { // 6 url: "/boards?filters[lang]=fr", expectedStatusCode: http.StatusOK, expectedBody: "/boards?filters[lang]=fr", }, { // 7 url: "/users?sort=xp,age", expectedStatusCode: http.StatusOK, expectedBody: "/users?sort=xp,age", }, { // 8 url: "/users?page[size]=10&page[number]=1", expectedStatusCode: http.StatusOK, expectedBody: "/users?page[number]=1&page[size]=10", }, { // 9 url: "/users?fields[user]=id,name&filters[group]=15&sort=age,-xp,name&page[size]=10&page[number]=3", expectedStatusCode: http.StatusOK, expectedBody: "/users?fields[user]=id,name&filters[group]=15&page[number]=3&page[size]=10&sort=age,-xp,name", }, } for i, test := range tests { res := tchek.MakeRequest(server, "GET", test.url, "") fmt.Printf("\n") var body []byte body, err := ioutil.ReadAll(res.Body) tchek.UnintendedError(err) tchek.AreEqual(t, i, test.expectedStatusCode, res.StatusCode) tchek.AreEqual(t, i, test.expectedBody, string(body)) } }
func TestAuthorizer(t *testing.T) { testApp := NewApp() testApp.UseFunc(Recoverer) testApp.UseFunc(URLParser) testApp.UseFunc(JWTParser) testApp.UseFunc(Authorizer) testApp.Get("/users", func(ctx context.Context, w ResponseWriter) context.Context { return ctx }, GateAdmin) testApp.Get("/comments", func(ctx context.Context, w ResponseWriter) context.Context { return ctx }, GatePublic) testApp.Post("/comments", func(ctx context.Context, w ResponseWriter) context.Context { return ctx }, GateNotBannedUser) server := httptest.NewServer(testApp) tests := []struct { method string url string id string groups []string expectedStatusCode int }{ { // 0 method: "GET", url: "/comments", id: "", groups: []string{}, expectedStatusCode: http.StatusOK, }, { // 1 method: "GET", url: "/comments", id: "abc123", groups: []string{"banned"}, expectedStatusCode: http.StatusOK, }, { // 2 method: "POST", url: "/comments", id: "abc123", groups: []string{"banned"}, expectedStatusCode: http.StatusForbidden, }, { // 4 method: "GET", url: "/users", id: "abc123", groups: []string{"admin"}, expectedStatusCode: http.StatusOK, }, } for i, test := range tests { var err error token := "" if test.id != "" { token, err = cybele.GenerateJWT(map[string]interface{}{ "id": test.id, "groups": test.groups, }) tchek.UnintendedError(err) } res := tchek.MakeRequest(server, test.method, test.url, token) fmt.Printf("\n") tchek.AreEqual(t, i, test.expectedStatusCode, res.StatusCode) } }