mirror of https://github.com/artifacthub/hub.git
966 lines
24 KiB
Go
966 lines
24 KiB
Go
package org
|
|
|
|
import (
|
|
"context"
|
|
"encoding/json"
|
|
"fmt"
|
|
"io"
|
|
"net/http"
|
|
"net/http/httptest"
|
|
"os"
|
|
"strings"
|
|
"testing"
|
|
|
|
"github.com/artifacthub/hub/internal/authz"
|
|
"github.com/artifacthub/hub/internal/handlers/helpers"
|
|
"github.com/artifacthub/hub/internal/hub"
|
|
"github.com/artifacthub/hub/internal/org"
|
|
"github.com/artifacthub/hub/internal/tests"
|
|
"github.com/go-chi/chi/v5"
|
|
"github.com/rs/zerolog"
|
|
"github.com/spf13/viper"
|
|
"github.com/stretchr/testify/assert"
|
|
"github.com/stretchr/testify/mock"
|
|
)
|
|
|
|
func TestMain(m *testing.M) {
|
|
zerolog.SetGlobalLevel(zerolog.Disabled)
|
|
os.Exit(m.Run())
|
|
}
|
|
|
|
func TestAdd(t *testing.T) {
|
|
t.Run("invalid organization provided", func(t *testing.T) {
|
|
testCases := []struct {
|
|
description string
|
|
orgJSON string
|
|
omErr error
|
|
}{
|
|
{
|
|
"no organization provided",
|
|
"",
|
|
nil,
|
|
},
|
|
{
|
|
"invalid json",
|
|
"-",
|
|
nil,
|
|
},
|
|
{
|
|
"missing name",
|
|
`{"display_name": "Display Name"}`,
|
|
hub.ErrInvalidInput,
|
|
},
|
|
{
|
|
"invalid name",
|
|
`{"name": "_org"}`,
|
|
hub.ErrInvalidInput,
|
|
},
|
|
}
|
|
for _, tc := range testCases {
|
|
t.Run(tc.description, func(t *testing.T) {
|
|
t.Parallel()
|
|
w := httptest.NewRecorder()
|
|
r, _ := http.NewRequest("POST", "/", strings.NewReader(tc.orgJSON))
|
|
r = r.WithContext(context.WithValue(r.Context(), hub.UserIDKey, "userID"))
|
|
|
|
hw := newHandlersWrapper()
|
|
if tc.omErr != nil {
|
|
hw.om.On("Add", r.Context(), mock.Anything).Return(tc.omErr)
|
|
}
|
|
hw.h.Add(w, r)
|
|
resp := w.Result()
|
|
defer resp.Body.Close()
|
|
|
|
assert.Equal(t, http.StatusBadRequest, resp.StatusCode)
|
|
hw.om.AssertExpectations(t)
|
|
})
|
|
}
|
|
})
|
|
|
|
t.Run("valid organization provided", func(t *testing.T) {
|
|
orgJSON := `
|
|
{
|
|
"name": "org1",
|
|
"display_name": "Organization 1",
|
|
"description": "description"
|
|
}
|
|
`
|
|
o := &hub.Organization{}
|
|
_ = json.Unmarshal([]byte(orgJSON), &o)
|
|
|
|
testCases := []struct {
|
|
description string
|
|
err error
|
|
expectedStatusCode int
|
|
}{
|
|
{
|
|
"add organization succeeded",
|
|
nil,
|
|
http.StatusCreated,
|
|
},
|
|
{
|
|
"error adding organization",
|
|
tests.ErrFakeDB,
|
|
http.StatusInternalServerError,
|
|
},
|
|
}
|
|
for _, tc := range testCases {
|
|
t.Run(tc.description, func(t *testing.T) {
|
|
t.Parallel()
|
|
w := httptest.NewRecorder()
|
|
r, _ := http.NewRequest("POST", "/", strings.NewReader(orgJSON))
|
|
r = r.WithContext(context.WithValue(r.Context(), hub.UserIDKey, "userID"))
|
|
|
|
hw := newHandlersWrapper()
|
|
hw.om.On("Add", r.Context(), o).Return(tc.err)
|
|
hw.h.Add(w, r)
|
|
resp := w.Result()
|
|
defer resp.Body.Close()
|
|
|
|
assert.Equal(t, tc.expectedStatusCode, resp.StatusCode)
|
|
hw.om.AssertExpectations(t)
|
|
})
|
|
}
|
|
})
|
|
}
|
|
|
|
func TestAddMember(t *testing.T) {
|
|
testCases := []struct {
|
|
omErr error
|
|
expectedStatusCode int
|
|
}{
|
|
{
|
|
nil,
|
|
http.StatusCreated,
|
|
},
|
|
{
|
|
hub.ErrInvalidInput,
|
|
http.StatusBadRequest,
|
|
},
|
|
{
|
|
hub.ErrInsufficientPrivilege,
|
|
http.StatusForbidden,
|
|
},
|
|
{
|
|
tests.ErrFakeDB,
|
|
http.StatusInternalServerError,
|
|
},
|
|
}
|
|
for _, tc := range testCases {
|
|
var desc string
|
|
if tc.omErr != nil {
|
|
desc = tc.omErr.Error()
|
|
}
|
|
t.Run(desc, func(t *testing.T) {
|
|
t.Parallel()
|
|
w := httptest.NewRecorder()
|
|
r, _ := http.NewRequest("POST", "/", nil)
|
|
r = r.WithContext(context.WithValue(r.Context(), hub.UserIDKey, "userID"))
|
|
rctx := &chi.Context{
|
|
URLParams: chi.RouteParams{
|
|
Keys: []string{"orgName", "userAlias"},
|
|
Values: []string{"org1", "userAlias"},
|
|
},
|
|
}
|
|
r = r.WithContext(context.WithValue(r.Context(), chi.RouteCtxKey, rctx))
|
|
|
|
hw := newHandlersWrapper()
|
|
hw.om.On("AddMember", r.Context(), "org1", "userAlias").Return(tc.omErr)
|
|
hw.h.AddMember(w, r)
|
|
resp := w.Result()
|
|
defer resp.Body.Close()
|
|
|
|
assert.Equal(t, tc.expectedStatusCode, resp.StatusCode)
|
|
hw.om.AssertExpectations(t)
|
|
})
|
|
}
|
|
}
|
|
|
|
func TestCheckAvailability(t *testing.T) {
|
|
t.Run("invalid input", func(t *testing.T) {
|
|
t.Parallel()
|
|
w := httptest.NewRecorder()
|
|
r, _ := http.NewRequest("HEAD", "/?v=value", nil)
|
|
rctx := &chi.Context{
|
|
URLParams: chi.RouteParams{
|
|
Keys: []string{"resourceKind"},
|
|
Values: []string{"invalid"},
|
|
},
|
|
}
|
|
r = r.WithContext(context.WithValue(r.Context(), chi.RouteCtxKey, rctx))
|
|
|
|
hw := newHandlersWrapper()
|
|
hw.om.On("CheckAvailability", r.Context(), "invalid", "value").
|
|
Return(false, hub.ErrInvalidInput)
|
|
hw.h.CheckAvailability(w, r)
|
|
resp := w.Result()
|
|
defer resp.Body.Close()
|
|
h := resp.Header
|
|
|
|
assert.Equal(t, http.StatusBadRequest, resp.StatusCode)
|
|
assert.Equal(t, helpers.BuildCacheControlHeader(0), h.Get("Cache-Control"))
|
|
hw.om.AssertExpectations(t)
|
|
})
|
|
|
|
t.Run("valid input", func(t *testing.T) {
|
|
t.Run("check availability succeeded", func(t *testing.T) {
|
|
testCases := []struct {
|
|
resourceKind string
|
|
available bool
|
|
}{
|
|
{
|
|
"organizationName",
|
|
true,
|
|
},
|
|
}
|
|
for _, tc := range testCases {
|
|
t.Run(fmt.Sprintf("resource kind: %s", tc.resourceKind), func(t *testing.T) {
|
|
t.Parallel()
|
|
w := httptest.NewRecorder()
|
|
r, _ := http.NewRequest("HEAD", "/?v=value", nil)
|
|
rctx := &chi.Context{
|
|
URLParams: chi.RouteParams{
|
|
Keys: []string{"resourceKind"},
|
|
Values: []string{tc.resourceKind},
|
|
},
|
|
}
|
|
r = r.WithContext(context.WithValue(r.Context(), chi.RouteCtxKey, rctx))
|
|
|
|
hw := newHandlersWrapper()
|
|
hw.om.On("CheckAvailability", r.Context(), tc.resourceKind, "value").Return(tc.available, nil)
|
|
hw.h.CheckAvailability(w, r)
|
|
resp := w.Result()
|
|
defer resp.Body.Close()
|
|
h := resp.Header
|
|
|
|
if tc.available {
|
|
assert.Equal(t, http.StatusNotFound, resp.StatusCode)
|
|
} else {
|
|
assert.Equal(t, http.StatusNoContent, resp.StatusCode)
|
|
}
|
|
assert.Equal(t, helpers.BuildCacheControlHeader(0), h.Get("Cache-Control"))
|
|
hw.om.AssertExpectations(t)
|
|
})
|
|
}
|
|
})
|
|
|
|
t.Run("check availability failed", func(t *testing.T) {
|
|
t.Parallel()
|
|
w := httptest.NewRecorder()
|
|
r, _ := http.NewRequest("HEAD", "/?v=value", nil)
|
|
rctx := &chi.Context{
|
|
URLParams: chi.RouteParams{
|
|
Keys: []string{"resourceKind"},
|
|
Values: []string{"organizationName"},
|
|
},
|
|
}
|
|
r = r.WithContext(context.WithValue(r.Context(), chi.RouteCtxKey, rctx))
|
|
|
|
hw := newHandlersWrapper()
|
|
hw.om.On("CheckAvailability", r.Context(), "organizationName", "value").
|
|
Return(false, tests.ErrFakeDB)
|
|
hw.h.CheckAvailability(w, r)
|
|
resp := w.Result()
|
|
defer resp.Body.Close()
|
|
|
|
assert.Equal(t, http.StatusInternalServerError, resp.StatusCode)
|
|
hw.om.AssertExpectations(t)
|
|
})
|
|
})
|
|
}
|
|
|
|
func TestConfirmMembership(t *testing.T) {
|
|
testCases := []struct {
|
|
omErr error
|
|
expectedStatusCode int
|
|
}{
|
|
{
|
|
nil,
|
|
http.StatusNoContent,
|
|
},
|
|
{
|
|
hub.ErrInvalidInput,
|
|
http.StatusBadRequest,
|
|
},
|
|
{
|
|
tests.ErrFakeDB,
|
|
http.StatusInternalServerError,
|
|
},
|
|
}
|
|
for _, tc := range testCases {
|
|
var desc string
|
|
if tc.omErr != nil {
|
|
desc = tc.omErr.Error()
|
|
}
|
|
t.Run(desc, func(t *testing.T) {
|
|
t.Parallel()
|
|
w := httptest.NewRecorder()
|
|
r, _ := http.NewRequest("PUT", "/", nil)
|
|
r = r.WithContext(context.WithValue(r.Context(), hub.UserIDKey, "userID"))
|
|
rctx := &chi.Context{
|
|
URLParams: chi.RouteParams{
|
|
Keys: []string{"orgName"},
|
|
Values: []string{"org1"},
|
|
},
|
|
}
|
|
r = r.WithContext(context.WithValue(r.Context(), chi.RouteCtxKey, rctx))
|
|
|
|
hw := newHandlersWrapper()
|
|
hw.om.On("ConfirmMembership", r.Context(), "org1").Return(tc.omErr)
|
|
hw.h.ConfirmMembership(w, r)
|
|
resp := w.Result()
|
|
defer resp.Body.Close()
|
|
|
|
assert.Equal(t, tc.expectedStatusCode, resp.StatusCode)
|
|
hw.om.AssertExpectations(t)
|
|
})
|
|
}
|
|
}
|
|
|
|
func TestDelete(t *testing.T) {
|
|
testCases := []struct {
|
|
omErr error
|
|
expectedStatusCode int
|
|
}{
|
|
{
|
|
nil,
|
|
http.StatusNoContent,
|
|
},
|
|
{
|
|
hub.ErrInvalidInput,
|
|
http.StatusBadRequest,
|
|
},
|
|
{
|
|
hub.ErrInsufficientPrivilege,
|
|
http.StatusForbidden,
|
|
},
|
|
{
|
|
tests.ErrFakeDB,
|
|
http.StatusInternalServerError,
|
|
},
|
|
}
|
|
for _, tc := range testCases {
|
|
var desc string
|
|
if tc.omErr != nil {
|
|
desc = tc.omErr.Error()
|
|
}
|
|
t.Run(desc, func(t *testing.T) {
|
|
t.Parallel()
|
|
w := httptest.NewRecorder()
|
|
r, _ := http.NewRequest("DELETE", "/", nil)
|
|
r = r.WithContext(context.WithValue(r.Context(), hub.UserIDKey, "userID"))
|
|
rctx := &chi.Context{
|
|
URLParams: chi.RouteParams{
|
|
Keys: []string{"orgName"},
|
|
Values: []string{"org1"},
|
|
},
|
|
}
|
|
r = r.WithContext(context.WithValue(r.Context(), chi.RouteCtxKey, rctx))
|
|
|
|
hw := newHandlersWrapper()
|
|
hw.om.On("Delete", r.Context(), "org1").Return(tc.omErr)
|
|
hw.h.Delete(w, r)
|
|
resp := w.Result()
|
|
defer resp.Body.Close()
|
|
|
|
assert.Equal(t, tc.expectedStatusCode, resp.StatusCode)
|
|
hw.om.AssertExpectations(t)
|
|
})
|
|
}
|
|
}
|
|
|
|
func TestDeleteMember(t *testing.T) {
|
|
testCases := []struct {
|
|
omErr error
|
|
expectedStatusCode int
|
|
}{
|
|
{
|
|
nil,
|
|
http.StatusNoContent,
|
|
},
|
|
{
|
|
hub.ErrInvalidInput,
|
|
http.StatusBadRequest,
|
|
},
|
|
{
|
|
hub.ErrInsufficientPrivilege,
|
|
http.StatusForbidden,
|
|
},
|
|
{
|
|
tests.ErrFakeDB,
|
|
http.StatusInternalServerError,
|
|
},
|
|
}
|
|
for _, tc := range testCases {
|
|
var desc string
|
|
if tc.omErr != nil {
|
|
desc = tc.omErr.Error()
|
|
}
|
|
t.Run(desc, func(t *testing.T) {
|
|
t.Parallel()
|
|
w := httptest.NewRecorder()
|
|
r, _ := http.NewRequest("DELETE", "/", nil)
|
|
r = r.WithContext(context.WithValue(r.Context(), hub.UserIDKey, "userID"))
|
|
rctx := &chi.Context{
|
|
URLParams: chi.RouteParams{
|
|
Keys: []string{"orgName", "userAlias"},
|
|
Values: []string{"org1", "userAlias"},
|
|
},
|
|
}
|
|
r = r.WithContext(context.WithValue(r.Context(), chi.RouteCtxKey, rctx))
|
|
|
|
hw := newHandlersWrapper()
|
|
hw.om.On("DeleteMember", r.Context(), "org1", "userAlias").Return(tc.omErr)
|
|
hw.h.DeleteMember(w, r)
|
|
resp := w.Result()
|
|
defer resp.Body.Close()
|
|
|
|
assert.Equal(t, tc.expectedStatusCode, resp.StatusCode)
|
|
hw.om.AssertExpectations(t)
|
|
})
|
|
}
|
|
}
|
|
|
|
func TestGet(t *testing.T) {
|
|
rctx := &chi.Context{
|
|
URLParams: chi.RouteParams{
|
|
Keys: []string{"orgName"},
|
|
Values: []string{"org1"},
|
|
},
|
|
}
|
|
|
|
t.Run("error getting organization", func(t *testing.T) {
|
|
testCases := []struct {
|
|
omErr error
|
|
expectedStatusCode int
|
|
}{
|
|
{
|
|
hub.ErrInvalidInput,
|
|
http.StatusBadRequest,
|
|
},
|
|
{
|
|
tests.ErrFakeDB,
|
|
http.StatusInternalServerError,
|
|
},
|
|
}
|
|
for _, tc := range testCases {
|
|
t.Run(tc.omErr.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.om.On("GetJSON", r.Context(), "org1").Return(nil, tc.omErr)
|
|
hw.h.Get(w, r)
|
|
resp := w.Result()
|
|
defer resp.Body.Close()
|
|
|
|
assert.Equal(t, tc.expectedStatusCode, resp.StatusCode)
|
|
hw.om.AssertExpectations(t)
|
|
})
|
|
}
|
|
})
|
|
|
|
t.Run("get organization 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.om.On("GetJSON", r.Context(), "org1").Return([]byte("dataJSON"), nil)
|
|
hw.h.Get(w, r)
|
|
resp := w.Result()
|
|
defer resp.Body.Close()
|
|
h := resp.Header
|
|
data, _ := io.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.om.AssertExpectations(t)
|
|
})
|
|
}
|
|
|
|
func TestGetAuthorizationPolicy(t *testing.T) {
|
|
rctx := &chi.Context{
|
|
URLParams: chi.RouteParams{
|
|
Keys: []string{"orgName"},
|
|
Values: []string{"org1"},
|
|
},
|
|
}
|
|
|
|
t.Run("error getting authorization policy", func(t *testing.T) {
|
|
testCases := []struct {
|
|
omErr error
|
|
expectedStatusCode int
|
|
}{
|
|
{
|
|
hub.ErrInvalidInput,
|
|
http.StatusBadRequest,
|
|
},
|
|
{
|
|
tests.ErrFakeDB,
|
|
http.StatusInternalServerError,
|
|
},
|
|
}
|
|
for _, tc := range testCases {
|
|
t.Run(tc.omErr.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.om.On("GetAuthorizationPolicyJSON", r.Context(), "org1").Return(nil, tc.omErr)
|
|
hw.h.GetAuthorizationPolicy(w, r)
|
|
resp := w.Result()
|
|
defer resp.Body.Close()
|
|
|
|
assert.Equal(t, tc.expectedStatusCode, resp.StatusCode)
|
|
hw.om.AssertExpectations(t)
|
|
})
|
|
}
|
|
})
|
|
|
|
t.Run("get authorization policy 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.om.On("GetAuthorizationPolicyJSON", r.Context(), "org1").Return([]byte("dataJSON"), nil)
|
|
hw.h.GetAuthorizationPolicy(w, r)
|
|
resp := w.Result()
|
|
defer resp.Body.Close()
|
|
h := resp.Header
|
|
data, _ := io.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.om.AssertExpectations(t)
|
|
})
|
|
}
|
|
|
|
func TestGetByUser(t *testing.T) {
|
|
t.Run("get user organizations succeeded", func(t *testing.T) {
|
|
t.Parallel()
|
|
w := httptest.NewRecorder()
|
|
r, _ := http.NewRequest("GET", "/?limit=10&offset=1", nil)
|
|
r = r.WithContext(context.WithValue(r.Context(), hub.UserIDKey, "userID"))
|
|
|
|
hw := newHandlersWrapper()
|
|
hw.om.On("GetByUserJSON", r.Context(), &hub.Pagination{
|
|
Limit: 10,
|
|
Offset: 1,
|
|
}).Return(&hub.JSONQueryResult{
|
|
Data: []byte("dataJSON"),
|
|
TotalCount: 1,
|
|
}, nil)
|
|
hw.h.GetByUser(w, r)
|
|
resp := w.Result()
|
|
defer resp.Body.Close()
|
|
h := resp.Header
|
|
data, _ := io.ReadAll(resp.Body)
|
|
|
|
assert.Equal(t, http.StatusOK, resp.StatusCode)
|
|
assert.Equal(t, h.Get(helpers.PaginationTotalCount), "1")
|
|
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.om.AssertExpectations(t)
|
|
})
|
|
|
|
t.Run("error getting user organizations", func(t *testing.T) {
|
|
t.Parallel()
|
|
w := httptest.NewRecorder()
|
|
r, _ := http.NewRequest("GET", "/?limit=10&offset=1", nil)
|
|
r = r.WithContext(context.WithValue(r.Context(), hub.UserIDKey, "userID"))
|
|
|
|
hw := newHandlersWrapper()
|
|
hw.om.On("GetByUserJSON", r.Context(), &hub.Pagination{
|
|
Limit: 10,
|
|
Offset: 1,
|
|
}).Return(nil, tests.ErrFakeDB)
|
|
hw.h.GetByUser(w, r)
|
|
resp := w.Result()
|
|
defer resp.Body.Close()
|
|
|
|
assert.Equal(t, http.StatusInternalServerError, resp.StatusCode)
|
|
hw.om.AssertExpectations(t)
|
|
})
|
|
}
|
|
|
|
func TestGetMembers(t *testing.T) {
|
|
rctx := &chi.Context{
|
|
URLParams: chi.RouteParams{
|
|
Keys: []string{"orgName"},
|
|
Values: []string{"org1"},
|
|
},
|
|
}
|
|
|
|
t.Run("error getting organization members", func(t *testing.T) {
|
|
testCases := []struct {
|
|
omErr error
|
|
expectedStatusCode int
|
|
}{
|
|
{
|
|
hub.ErrInvalidInput,
|
|
http.StatusBadRequest,
|
|
},
|
|
{
|
|
tests.ErrFakeDB,
|
|
http.StatusInternalServerError,
|
|
},
|
|
}
|
|
for _, tc := range testCases {
|
|
t.Run(tc.omErr.Error(), func(t *testing.T) {
|
|
t.Parallel()
|
|
w := httptest.NewRecorder()
|
|
r, _ := http.NewRequest("GET", "/?limit=10&offset=1", nil)
|
|
r = r.WithContext(context.WithValue(r.Context(), hub.UserIDKey, "userID"))
|
|
r = r.WithContext(context.WithValue(r.Context(), chi.RouteCtxKey, rctx))
|
|
|
|
hw := newHandlersWrapper()
|
|
hw.om.On("GetMembersJSON", r.Context(), "org1", &hub.Pagination{
|
|
Limit: 10,
|
|
Offset: 1,
|
|
}).Return(nil, tc.omErr)
|
|
hw.h.GetMembers(w, r)
|
|
resp := w.Result()
|
|
defer resp.Body.Close()
|
|
|
|
assert.Equal(t, tc.expectedStatusCode, resp.StatusCode)
|
|
hw.om.AssertExpectations(t)
|
|
})
|
|
}
|
|
})
|
|
|
|
t.Run("get organization members succeeded", func(t *testing.T) {
|
|
t.Parallel()
|
|
w := httptest.NewRecorder()
|
|
r, _ := http.NewRequest("GET", "/?limit=10&offset=1", nil)
|
|
r = r.WithContext(context.WithValue(r.Context(), hub.UserIDKey, "userID"))
|
|
r = r.WithContext(context.WithValue(r.Context(), chi.RouteCtxKey, rctx))
|
|
|
|
hw := newHandlersWrapper()
|
|
hw.om.On("GetMembersJSON", r.Context(), "org1", &hub.Pagination{
|
|
Limit: 10,
|
|
Offset: 1,
|
|
}).Return(&hub.JSONQueryResult{
|
|
Data: []byte("dataJSON"),
|
|
TotalCount: 1,
|
|
}, nil)
|
|
hw.h.GetMembers(w, r)
|
|
resp := w.Result()
|
|
defer resp.Body.Close()
|
|
h := resp.Header
|
|
data, _ := io.ReadAll(resp.Body)
|
|
|
|
assert.Equal(t, http.StatusOK, resp.StatusCode)
|
|
assert.Equal(t, h.Get(helpers.PaginationTotalCount), "1")
|
|
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.om.AssertExpectations(t)
|
|
})
|
|
}
|
|
|
|
func TestUpdate(t *testing.T) {
|
|
rctx := &chi.Context{
|
|
URLParams: chi.RouteParams{
|
|
Keys: []string{"orgName"},
|
|
Values: []string{"org1"},
|
|
},
|
|
}
|
|
|
|
t.Run("invalid organization provided", func(t *testing.T) {
|
|
testCases := []struct {
|
|
description string
|
|
orgJSON string
|
|
omErr error
|
|
}{
|
|
{
|
|
"no organization provided",
|
|
"",
|
|
nil,
|
|
},
|
|
{
|
|
"invalid json",
|
|
"-",
|
|
nil,
|
|
},
|
|
{
|
|
"invalid logo image id",
|
|
`{"name": "org1", "logo_image_id": "invalid"}`,
|
|
hub.ErrInvalidInput,
|
|
},
|
|
}
|
|
for _, tc := range testCases {
|
|
t.Run(tc.description, func(t *testing.T) {
|
|
t.Parallel()
|
|
w := httptest.NewRecorder()
|
|
r, _ := http.NewRequest("PUT", "/", strings.NewReader(tc.orgJSON))
|
|
r = r.WithContext(context.WithValue(r.Context(), hub.UserIDKey, "userID"))
|
|
r = r.WithContext(context.WithValue(r.Context(), chi.RouteCtxKey, rctx))
|
|
|
|
hw := newHandlersWrapper()
|
|
if tc.omErr != nil {
|
|
hw.om.On("Update", r.Context(), "org1", mock.Anything).Return(tc.omErr)
|
|
}
|
|
hw.h.Update(w, r)
|
|
resp := w.Result()
|
|
defer resp.Body.Close()
|
|
|
|
assert.Equal(t, http.StatusBadRequest, resp.StatusCode)
|
|
hw.om.AssertExpectations(t)
|
|
})
|
|
}
|
|
})
|
|
|
|
t.Run("valid organization provided", func(t *testing.T) {
|
|
orgJSON := `
|
|
{
|
|
"name": "org1",
|
|
"display_name": "Organization 1 updated",
|
|
"description": "description updated"
|
|
}
|
|
`
|
|
o := &hub.Organization{}
|
|
_ = json.Unmarshal([]byte(orgJSON), &o)
|
|
|
|
testCases := []struct {
|
|
description string
|
|
err error
|
|
expectedStatusCode int
|
|
}{
|
|
{
|
|
"organization update succeeded",
|
|
nil,
|
|
http.StatusNoContent,
|
|
},
|
|
{
|
|
"error updating organization (insufficiente privilege)",
|
|
hub.ErrInsufficientPrivilege,
|
|
http.StatusForbidden,
|
|
},
|
|
{
|
|
"error updating organization (db error)",
|
|
tests.ErrFakeDB,
|
|
http.StatusInternalServerError,
|
|
},
|
|
}
|
|
for _, tc := range testCases {
|
|
t.Run(tc.description, func(t *testing.T) {
|
|
t.Parallel()
|
|
w := httptest.NewRecorder()
|
|
r, _ := http.NewRequest("PUT", "/", strings.NewReader(orgJSON))
|
|
r = r.WithContext(context.WithValue(r.Context(), hub.UserIDKey, "userID"))
|
|
r = r.WithContext(context.WithValue(r.Context(), chi.RouteCtxKey, rctx))
|
|
|
|
hw := newHandlersWrapper()
|
|
hw.om.On("Update", r.Context(), "org1", o).Return(tc.err)
|
|
hw.h.Update(w, r)
|
|
resp := w.Result()
|
|
defer resp.Body.Close()
|
|
|
|
assert.Equal(t, tc.expectedStatusCode, resp.StatusCode)
|
|
hw.om.AssertExpectations(t)
|
|
})
|
|
}
|
|
})
|
|
}
|
|
|
|
func TestUpdateAuthorizationPolicy(t *testing.T) {
|
|
rctx := &chi.Context{
|
|
URLParams: chi.RouteParams{
|
|
Keys: []string{"orgName"},
|
|
Values: []string{"org1"},
|
|
},
|
|
}
|
|
|
|
t.Run("invalid authorization policy provided", func(t *testing.T) {
|
|
testCases := []struct {
|
|
description string
|
|
policyJSON string
|
|
omErr error
|
|
}{
|
|
{
|
|
"no authorization policy provided",
|
|
"",
|
|
nil,
|
|
},
|
|
{
|
|
"invalid json",
|
|
"-",
|
|
nil,
|
|
},
|
|
{
|
|
"invalid policy data",
|
|
`{"policy_data": "invalid"}`,
|
|
hub.ErrInvalidInput,
|
|
},
|
|
}
|
|
for _, tc := range testCases {
|
|
t.Run(tc.description, func(t *testing.T) {
|
|
t.Parallel()
|
|
w := httptest.NewRecorder()
|
|
r, _ := http.NewRequest("PUT", "/", strings.NewReader(tc.policyJSON))
|
|
r = r.WithContext(context.WithValue(r.Context(), hub.UserIDKey, "userID"))
|
|
r = r.WithContext(context.WithValue(r.Context(), chi.RouteCtxKey, rctx))
|
|
|
|
hw := newHandlersWrapper()
|
|
if tc.omErr != nil {
|
|
hw.om.On("UpdateAuthorizationPolicy", r.Context(), "org1", mock.Anything).Return(tc.omErr)
|
|
}
|
|
hw.h.UpdateAuthorizationPolicy(w, r)
|
|
resp := w.Result()
|
|
defer resp.Body.Close()
|
|
|
|
assert.Equal(t, http.StatusBadRequest, resp.StatusCode)
|
|
hw.om.AssertExpectations(t)
|
|
})
|
|
}
|
|
})
|
|
|
|
t.Run("valid authorization policy provided", func(t *testing.T) {
|
|
policyJSON := `
|
|
{
|
|
"authorization_enabled": true,
|
|
"predefined_policy": "rbac.v1",
|
|
"custom_policy": "",
|
|
"policy_data": "{\"k\": \"v\"}"
|
|
}
|
|
`
|
|
policy := &hub.AuthorizationPolicy{}
|
|
_ = json.Unmarshal([]byte(policyJSON), &policy)
|
|
|
|
testCases := []struct {
|
|
description string
|
|
err error
|
|
expectedStatusCode int
|
|
}{
|
|
{
|
|
"authorization policy update succeeded",
|
|
nil,
|
|
http.StatusNoContent,
|
|
},
|
|
{
|
|
"error updating organization policy (insufficiente privilege)",
|
|
hub.ErrInsufficientPrivilege,
|
|
http.StatusForbidden,
|
|
},
|
|
{
|
|
"error updating organization policy (db error)",
|
|
tests.ErrFakeDB,
|
|
http.StatusInternalServerError,
|
|
},
|
|
}
|
|
for _, tc := range testCases {
|
|
t.Run(tc.description, func(t *testing.T) {
|
|
t.Parallel()
|
|
w := httptest.NewRecorder()
|
|
r, _ := http.NewRequest("PUT", "/", strings.NewReader(policyJSON))
|
|
r = r.WithContext(context.WithValue(r.Context(), hub.UserIDKey, "userID"))
|
|
rctx := &chi.Context{
|
|
URLParams: chi.RouteParams{
|
|
Keys: []string{"orgName"},
|
|
Values: []string{"org1"},
|
|
},
|
|
}
|
|
r = r.WithContext(context.WithValue(r.Context(), chi.RouteCtxKey, rctx))
|
|
|
|
hw := newHandlersWrapper()
|
|
hw.om.On("UpdateAuthorizationPolicy", r.Context(), "org1", policy).Return(tc.err)
|
|
hw.h.UpdateAuthorizationPolicy(w, r)
|
|
resp := w.Result()
|
|
defer resp.Body.Close()
|
|
|
|
assert.Equal(t, tc.expectedStatusCode, resp.StatusCode)
|
|
hw.om.AssertExpectations(t)
|
|
})
|
|
}
|
|
})
|
|
}
|
|
|
|
func TestGetUserAllowedActions(t *testing.T) {
|
|
rctx := &chi.Context{
|
|
URLParams: chi.RouteParams{
|
|
Keys: []string{"orgName"},
|
|
Values: []string{"org1"},
|
|
},
|
|
}
|
|
|
|
t.Run("get allowed actions failed", 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.az.On("GetAllowedActions", r.Context(), "userID", "org1").Return(nil, tests.ErrFake)
|
|
hw.h.GetUserAllowedActions(w, r)
|
|
resp := w.Result()
|
|
defer resp.Body.Close()
|
|
|
|
assert.Equal(t, http.StatusInternalServerError, resp.StatusCode)
|
|
hw.om.AssertExpectations(t)
|
|
})
|
|
|
|
t.Run("get allowed actions 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.az.On("GetAllowedActions", r.Context(), "userID", "org1").Return([]hub.Action{
|
|
hub.AddOrganizationMember,
|
|
hub.DeleteOrganizationMember,
|
|
}, nil)
|
|
hw.h.GetUserAllowedActions(w, r)
|
|
resp := w.Result()
|
|
defer resp.Body.Close()
|
|
h := resp.Header
|
|
data, _ := io.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(`["addOrganizationMember","deleteOrganizationMember"]`), data)
|
|
hw.om.AssertExpectations(t)
|
|
})
|
|
}
|
|
|
|
type handlersWrapper struct {
|
|
cfg *viper.Viper
|
|
om *org.ManagerMock
|
|
az *authz.AuthorizerMock
|
|
h *Handlers
|
|
}
|
|
|
|
func newHandlersWrapper() *handlersWrapper {
|
|
cfg := viper.New()
|
|
cfg.Set("server.baseURL", "baseURL")
|
|
om := &org.ManagerMock{}
|
|
az := &authz.AuthorizerMock{}
|
|
|
|
return &handlersWrapper{
|
|
cfg: cfg,
|
|
om: om,
|
|
az: az,
|
|
h: NewHandlers(om, az, cfg),
|
|
}
|
|
}
|