hub/internal/handlers/apikey/handlers_test.go

398 lines
9.9 KiB
Go

package apikey
import (
"bytes"
"context"
"encoding/json"
"io/ioutil"
"net/http"
"net/http/httptest"
"os"
"strings"
"testing"
"github.com/artifacthub/hub/internal/apikey"
"github.com/artifacthub/hub/internal/handlers/helpers"
"github.com/artifacthub/hub/internal/hub"
"github.com/artifacthub/hub/internal/tests"
"github.com/go-chi/chi"
"github.com/rs/zerolog"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/mock"
)
const apiKeyID = "00000000-0000-0000-0000-000000000001"
func TestMain(m *testing.M) {
zerolog.SetGlobalLevel(zerolog.Disabled)
os.Exit(m.Run())
}
func TestAdd(t *testing.T) {
akJSON := `{"name": "apikey1"}`
ak := &hub.APIKey{}
_ = json.Unmarshal([]byte(akJSON), &ak)
t.Run("invalid input", func(t *testing.T) {
testCases := []struct {
description string
akJSON string
err error
}{
{
"no api key provided",
"",
nil,
},
{
"invalid json",
"-",
nil,
},
{
"missing name",
`{}`,
hub.ErrInvalidInput,
},
}
for _, tc := range testCases {
tc := tc
t.Run(tc.description, func(t *testing.T) {
t.Parallel()
w := httptest.NewRecorder()
r, _ := http.NewRequest("POST", "/", strings.NewReader(tc.akJSON))
r = r.WithContext(context.WithValue(r.Context(), hub.UserIDKey, "userID"))
hw := newHandlersWrapper()
if tc.err != nil {
hw.am.On("Add", r.Context(), mock.Anything).Return(nil, tc.err)
}
hw.h.Add(w, r)
resp := w.Result()
defer resp.Body.Close()
assert.Equal(t, http.StatusBadRequest, resp.StatusCode)
hw.am.AssertExpectations(t)
})
}
})
t.Run("error adding api key", func(t *testing.T) {
t.Parallel()
w := httptest.NewRecorder()
r, _ := http.NewRequest("POST", "/", strings.NewReader(akJSON))
r = r.WithContext(context.WithValue(r.Context(), hub.UserIDKey, "userID"))
hw := newHandlersWrapper()
hw.am.On("Add", r.Context(), ak).Return(nil, tests.ErrFakeDB)
hw.h.Add(w, r)
resp := w.Result()
defer resp.Body.Close()
assert.Equal(t, http.StatusInternalServerError, resp.StatusCode)
hw.am.AssertExpectations(t)
})
t.Run("api key added successfully", func(t *testing.T) {
t.Parallel()
w := httptest.NewRecorder()
r, _ := http.NewRequest("POST", "/", strings.NewReader(akJSON))
r = r.WithContext(context.WithValue(r.Context(), hub.UserIDKey, "userID"))
hw := newHandlersWrapper()
akOUT := &hub.APIKey{
APIKeyID: "apiKeyID",
Secret: "secret",
}
hw.am.On("Add", r.Context(), ak).Return(akOUT, nil)
hw.h.Add(w, r)
resp := w.Result()
defer resp.Body.Close()
h := resp.Header
data, _ := ioutil.ReadAll(resp.Body)
assert.Equal(t, http.StatusCreated, resp.StatusCode)
assert.Equal(t, "application/json", h.Get("Content-Type"))
assert.Equal(t, helpers.BuildCacheControlHeader(0), h.Get("Cache-Control"))
outputAKJSON, _ := json.Marshal(akOUT)
assert.Equal(t, outputAKJSON, data)
hw.am.AssertExpectations(t)
})
}
func TestDelete(t *testing.T) {
rctx := &chi.Context{
URLParams: chi.RouteParams{
Keys: []string{"apiKeyID"},
Values: []string{apiKeyID},
},
}
t.Run("error deleting api key", func(t *testing.T) {
testCases := []struct {
err error
expectedStatusCode int
}{
{
hub.ErrInvalidInput,
http.StatusBadRequest,
},
{
tests.ErrFakeDB,
http.StatusInternalServerError,
},
}
for _, tc := range testCases {
tc := tc
t.Run(tc.err.Error(), func(t *testing.T) {
t.Parallel()
w := httptest.NewRecorder()
r, _ := http.NewRequest("DELETE", "/", nil)
r = r.WithContext(context.WithValue(r.Context(), hub.UserIDKey, "userID"))
r = r.WithContext(context.WithValue(r.Context(), chi.RouteCtxKey, rctx))
hw := newHandlersWrapper()
hw.am.On("Delete", r.Context(), apiKeyID).Return(tc.err)
hw.h.Delete(w, r)
resp := w.Result()
defer resp.Body.Close()
assert.Equal(t, tc.expectedStatusCode, resp.StatusCode)
hw.am.AssertExpectations(t)
})
}
})
t.Run("delete api key succeeded", func(t *testing.T) {
t.Parallel()
w := httptest.NewRecorder()
r, _ := http.NewRequest("DELETE", "/", nil)
r = r.WithContext(context.WithValue(r.Context(), hub.UserIDKey, "userID"))
r = r.WithContext(context.WithValue(r.Context(), chi.RouteCtxKey, rctx))
hw := newHandlersWrapper()
hw.am.On("Delete", r.Context(), apiKeyID).Return(nil)
hw.h.Delete(w, r)
resp := w.Result()
defer resp.Body.Close()
assert.Equal(t, http.StatusNoContent, resp.StatusCode)
hw.am.AssertExpectations(t)
})
}
func TestGet(t *testing.T) {
rctx := &chi.Context{
URLParams: chi.RouteParams{
Keys: []string{"apiKeyID"},
Values: []string{apiKeyID},
},
}
t.Run("error getting api key", func(t *testing.T) {
testCases := []struct {
err error
expectedStatusCode int
}{
{
hub.ErrInvalidInput,
http.StatusBadRequest,
},
{
tests.ErrFakeDB,
http.StatusInternalServerError,
},
}
for _, tc := range testCases {
tc := tc
t.Run(tc.err.Error(), func(t *testing.T) {
t.Parallel()
w := httptest.NewRecorder()
r, _ := http.NewRequest("GET", "/", nil)
r = r.WithContext(context.WithValue(r.Context(), hub.UserIDKey, "userID"))
r = r.WithContext(context.WithValue(r.Context(), chi.RouteCtxKey, rctx))
hw := newHandlersWrapper()
hw.am.On("GetJSON", r.Context(), apiKeyID).Return(nil, tc.err)
hw.h.Get(w, r)
resp := w.Result()
defer resp.Body.Close()
assert.Equal(t, tc.expectedStatusCode, resp.StatusCode)
hw.am.AssertExpectations(t)
})
}
})
t.Run("api key get succeeded", func(t *testing.T) {
t.Parallel()
w := httptest.NewRecorder()
r, _ := http.NewRequest("GET", "/", nil)
r = r.WithContext(context.WithValue(r.Context(), hub.UserIDKey, "userID"))
r = r.WithContext(context.WithValue(r.Context(), chi.RouteCtxKey, rctx))
hw := newHandlersWrapper()
hw.am.On("GetJSON", r.Context(), apiKeyID).Return([]byte("dataJSON"), nil)
hw.h.Get(w, r)
resp := w.Result()
defer resp.Body.Close()
h := resp.Header
data, _ := ioutil.ReadAll(resp.Body)
assert.Equal(t, http.StatusOK, resp.StatusCode)
assert.Equal(t, "application/json", h.Get("Content-Type"))
assert.Equal(t, helpers.BuildCacheControlHeader(0), h.Get("Cache-Control"))
assert.Equal(t, []byte("dataJSON"), data)
hw.am.AssertExpectations(t)
})
}
func TestGetOwnedByUser(t *testing.T) {
t.Run("error getting api keys owned by user", func(t *testing.T) {
t.Parallel()
w := httptest.NewRecorder()
r, _ := http.NewRequest("GET", "/", nil)
r = r.WithContext(context.WithValue(r.Context(), hub.UserIDKey, "userID"))
hw := newHandlersWrapper()
hw.am.On("GetOwnedByUserJSON", r.Context()).Return(nil, tests.ErrFakeDB)
hw.h.GetOwnedByUser(w, r)
resp := w.Result()
defer resp.Body.Close()
assert.Equal(t, http.StatusInternalServerError, resp.StatusCode)
hw.am.AssertExpectations(t)
})
t.Run("get api keys owned by user succeeded", func(t *testing.T) {
t.Parallel()
w := httptest.NewRecorder()
r, _ := http.NewRequest("GET", "/", nil)
r = r.WithContext(context.WithValue(r.Context(), hub.UserIDKey, "userID"))
hw := newHandlersWrapper()
hw.am.On("GetOwnedByUserJSON", r.Context()).Return([]byte("dataJSON"), nil)
hw.h.GetOwnedByUser(w, r)
resp := w.Result()
defer resp.Body.Close()
h := resp.Header
data, _ := ioutil.ReadAll(resp.Body)
assert.Equal(t, http.StatusOK, resp.StatusCode)
assert.Equal(t, "application/json", h.Get("Content-Type"))
assert.Equal(t, helpers.BuildCacheControlHeader(0), h.Get("Cache-Control"))
assert.Equal(t, []byte("dataJSON"), data)
hw.am.AssertExpectations(t)
})
}
func TestUpdate(t *testing.T) {
t.Run("invalid input", func(t *testing.T) {
testCases := []struct {
description string
akJSON string
err error
}{
{
"no api key provided",
"",
nil,
},
{
"invalid json",
"-",
nil,
},
{
"missing name",
`{}`,
hub.ErrInvalidInput,
},
}
for _, tc := range testCases {
tc := tc
t.Run(tc.description, func(t *testing.T) {
t.Parallel()
w := httptest.NewRecorder()
r, _ := http.NewRequest("PUT", "/", strings.NewReader(tc.akJSON))
r = r.WithContext(context.WithValue(r.Context(), hub.UserIDKey, "userID"))
hw := newHandlersWrapper()
if tc.err != nil {
hw.am.On("Update", r.Context(), mock.Anything).Return(tc.err)
}
hw.h.Update(w, r)
resp := w.Result()
defer resp.Body.Close()
assert.Equal(t, http.StatusBadRequest, resp.StatusCode)
hw.am.AssertExpectations(t)
})
}
})
t.Run("valid api key provided", func(t *testing.T) {
ak := &hub.APIKey{
APIKeyID: apiKeyID,
Name: "apikey1",
}
akJSON, _ := json.Marshal(ak)
testCases := []struct {
description string
err error
expectedStatusCode int
}{
{
"api key update succeeded",
nil,
http.StatusNoContent,
},
{
"error updating api key (db error)",
tests.ErrFakeDB,
http.StatusInternalServerError,
},
}
for _, tc := range testCases {
tc := tc
t.Run(tc.description, func(t *testing.T) {
t.Parallel()
w := httptest.NewRecorder()
r, _ := http.NewRequest("PUT", "/", bytes.NewReader(akJSON))
r = r.WithContext(context.WithValue(r.Context(), hub.UserIDKey, "userID"))
rctx := &chi.Context{
URLParams: chi.RouteParams{
Keys: []string{"apiKeyID"},
Values: []string{apiKeyID},
},
}
r = r.WithContext(context.WithValue(r.Context(), chi.RouteCtxKey, rctx))
hw := newHandlersWrapper()
hw.am.On("Update", r.Context(), ak).Return(tc.err)
hw.h.Update(w, r)
resp := w.Result()
defer resp.Body.Close()
assert.Equal(t, tc.expectedStatusCode, resp.StatusCode)
hw.am.AssertExpectations(t)
})
}
})
}
type handlersWrapper struct {
am *apikey.ManagerMock
h *Handlers
}
func newHandlersWrapper() *handlersWrapper {
am := &apikey.ManagerMock{}
return &handlersWrapper{
am: am,
h: NewHandlers(am),
}
}