mirror of https://github.com/artifacthub/hub.git
702 lines
19 KiB
Go
702 lines
19 KiB
Go
package repo
|
|
|
|
import (
|
|
"context"
|
|
"encoding/json"
|
|
"fmt"
|
|
"io"
|
|
"net/http"
|
|
"net/http/httptest"
|
|
"net/url"
|
|
"os"
|
|
"strings"
|
|
"testing"
|
|
"time"
|
|
|
|
"github.com/artifacthub/hub/internal/handlers/helpers"
|
|
"github.com/artifacthub/hub/internal/hub"
|
|
"github.com/artifacthub/hub/internal/repo"
|
|
"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) {
|
|
rctx := &chi.Context{
|
|
URLParams: chi.RouteParams{
|
|
Keys: []string{"orgName"},
|
|
Values: []string{"org1"},
|
|
},
|
|
}
|
|
|
|
t.Run("invalid input", func(t *testing.T) {
|
|
testCases := []struct {
|
|
description string
|
|
repoJSON string
|
|
rmErr error
|
|
}{
|
|
{
|
|
"no repository provided",
|
|
"",
|
|
nil,
|
|
},
|
|
{
|
|
"invalid json",
|
|
"-",
|
|
nil,
|
|
},
|
|
{
|
|
"missing name",
|
|
`{"url": "https://repo1.url"}`,
|
|
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.repoJSON))
|
|
r = r.WithContext(context.WithValue(r.Context(), hub.UserIDKey, "userID"))
|
|
r = r.WithContext(context.WithValue(r.Context(), chi.RouteCtxKey, rctx))
|
|
|
|
hw := newHandlersWrapper()
|
|
if tc.rmErr != nil {
|
|
hw.rm.On("Add", r.Context(), "org1", mock.Anything).Return(tc.rmErr)
|
|
}
|
|
hw.h.Add(w, r)
|
|
resp := w.Result()
|
|
defer resp.Body.Close()
|
|
|
|
assert.Equal(t, http.StatusBadRequest, resp.StatusCode)
|
|
hw.rm.AssertExpectations(t)
|
|
})
|
|
}
|
|
})
|
|
|
|
t.Run("valid repository provided", func(t *testing.T) {
|
|
repoJSON := `
|
|
{
|
|
"name": "repo1",
|
|
"display_name": "Repository 1",
|
|
"url": "https://repo1.url"
|
|
}
|
|
`
|
|
repo := &hub.Repository{}
|
|
_ = json.Unmarshal([]byte(repoJSON), &repo)
|
|
|
|
testCases := []struct {
|
|
description string
|
|
err error
|
|
expectedStatusCode int
|
|
}{
|
|
{
|
|
"add repository succeeded",
|
|
nil,
|
|
http.StatusCreated,
|
|
},
|
|
{
|
|
"error adding repository (insufficient privilege)",
|
|
hub.ErrInsufficientPrivilege,
|
|
http.StatusForbidden,
|
|
},
|
|
{
|
|
"error adding repository (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("POST", "/", strings.NewReader(repoJSON))
|
|
r = r.WithContext(context.WithValue(r.Context(), hub.UserIDKey, "userID"))
|
|
r = r.WithContext(context.WithValue(r.Context(), chi.RouteCtxKey, rctx))
|
|
|
|
hw := newHandlersWrapper()
|
|
hw.rm.On("Add", r.Context(), "org1", repo).Return(tc.err)
|
|
hw.h.Add(w, r)
|
|
resp := w.Result()
|
|
defer resp.Body.Close()
|
|
|
|
assert.Equal(t, tc.expectedStatusCode, resp.StatusCode)
|
|
hw.rm.AssertExpectations(t)
|
|
})
|
|
}
|
|
})
|
|
}
|
|
|
|
func TestBadge(t *testing.T) {
|
|
t.Run("badge info returned successfully", func(t *testing.T) {
|
|
t.Parallel()
|
|
w := httptest.NewRecorder()
|
|
r, _ := http.NewRequest("GET", "/", nil)
|
|
rctx := &chi.Context{
|
|
URLParams: chi.RouteParams{
|
|
Keys: []string{"repoName"},
|
|
Values: []string{"artifact-hub"},
|
|
},
|
|
}
|
|
r = r.WithContext(context.WithValue(r.Context(), chi.RouteCtxKey, rctx))
|
|
|
|
hw := newHandlersWrapper()
|
|
hw.h.Badge(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(helpers.DefaultAPICacheMaxAge), h.Get("Cache-Control"))
|
|
assert.Equal(t, []byte(`{"color":"2D4857","label":"Artifact Hub","labelColor":"417598","logoSvg":"\u003csvg xmlns=\"http://www.w3.org/2000/svg\" width=\"14\" height=\"14\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"#ffffff\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\" class=\"feather feather-hexagon\"\u003e\u003cpath d=\"M21 16V8a2 2 0 0 0-1-1.73l-7-4a2 2 0 0 0-2 0l-7 4A2 2 0 0 0 3 8v8a2 2 0 0 0 1 1.73l7 4a2 2 0 0 0 2 0l7-4A2 2 0 0 0 21 16z\"\u003e\u003c/path\u003e\u003c/svg\u003e","logoWidth":18,"message":"artifact-hub","schemaVersion":1,"style":"flat"}`), data)
|
|
hw.rm.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.rm.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.rm.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
|
|
}{
|
|
{
|
|
"repositoryName",
|
|
true,
|
|
},
|
|
{
|
|
"repositoryURL",
|
|
false,
|
|
},
|
|
}
|
|
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.rm.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.rm.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{"repositoryName"},
|
|
},
|
|
}
|
|
r = r.WithContext(context.WithValue(r.Context(), chi.RouteCtxKey, rctx))
|
|
|
|
hw := newHandlersWrapper()
|
|
hw.rm.On("CheckAvailability", r.Context(), "repositoryName", "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.rm.AssertExpectations(t)
|
|
})
|
|
})
|
|
}
|
|
|
|
func TestClaimOwnership(t *testing.T) {
|
|
t.Run("invalid input - missing repo name", func(t *testing.T) {
|
|
t.Parallel()
|
|
w := httptest.NewRecorder()
|
|
r, _ := http.NewRequest("PUT", "/", nil)
|
|
r = r.WithContext(context.WithValue(r.Context(), hub.UserIDKey, "userID"))
|
|
|
|
hw := newHandlersWrapper()
|
|
hw.rm.On("ClaimOwnership", r.Context(), "", "").Return(hub.ErrInvalidInput)
|
|
hw.h.ClaimOwnership(w, r)
|
|
resp := w.Result()
|
|
defer resp.Body.Close()
|
|
|
|
assert.Equal(t, http.StatusBadRequest, resp.StatusCode)
|
|
hw.rm.AssertExpectations(t)
|
|
})
|
|
|
|
t.Run("valid input", func(t *testing.T) {
|
|
testCases := []struct {
|
|
description string
|
|
err error
|
|
expectedStatusCode int
|
|
}{
|
|
{
|
|
"repository ownership claim succeeded",
|
|
nil,
|
|
http.StatusNoContent,
|
|
},
|
|
{
|
|
"error claiming repository ownership (insufficient privilege)",
|
|
hub.ErrInsufficientPrivilege,
|
|
http.StatusForbidden,
|
|
},
|
|
{
|
|
"error claiming repository ownership (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", "/?org=org1", nil)
|
|
r = r.WithContext(context.WithValue(r.Context(), hub.UserIDKey, "userID"))
|
|
rctx := &chi.Context{
|
|
URLParams: chi.RouteParams{
|
|
Keys: []string{"repoName"},
|
|
Values: []string{"repo1"},
|
|
},
|
|
}
|
|
r = r.WithContext(context.WithValue(r.Context(), chi.RouteCtxKey, rctx))
|
|
|
|
hw := newHandlersWrapper()
|
|
hw.rm.On("ClaimOwnership", r.Context(), "repo1", "org1").Return(tc.err)
|
|
hw.h.ClaimOwnership(w, r)
|
|
resp := w.Result()
|
|
defer resp.Body.Close()
|
|
|
|
assert.Equal(t, tc.expectedStatusCode, resp.StatusCode)
|
|
hw.rm.AssertExpectations(t)
|
|
})
|
|
}
|
|
})
|
|
}
|
|
|
|
func TestDelete(t *testing.T) {
|
|
rctx := &chi.Context{
|
|
URLParams: chi.RouteParams{
|
|
Keys: []string{"repoName"},
|
|
Values: []string{"repo1"},
|
|
},
|
|
}
|
|
|
|
t.Run("delete repository 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.rm.On("Delete", r.Context(), "repo1").Return(nil)
|
|
hw.h.Delete(w, r)
|
|
resp := w.Result()
|
|
defer resp.Body.Close()
|
|
|
|
assert.Equal(t, http.StatusNoContent, resp.StatusCode)
|
|
hw.rm.AssertExpectations(t)
|
|
})
|
|
|
|
t.Run("error deleting repository", func(t *testing.T) {
|
|
testCases := []struct {
|
|
rmErr error
|
|
expectedStatusCode int
|
|
}{
|
|
{
|
|
hub.ErrInvalidInput,
|
|
http.StatusBadRequest,
|
|
},
|
|
{
|
|
hub.ErrInsufficientPrivilege,
|
|
http.StatusForbidden,
|
|
},
|
|
{
|
|
tests.ErrFakeDB,
|
|
http.StatusInternalServerError,
|
|
},
|
|
}
|
|
for _, tc := range testCases {
|
|
t.Run(tc.rmErr.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.rm.On("Delete", r.Context(), "repo1").Return(tc.rmErr)
|
|
hw.h.Delete(w, r)
|
|
resp := w.Result()
|
|
defer resp.Body.Close()
|
|
|
|
assert.Equal(t, tc.expectedStatusCode, resp.StatusCode)
|
|
hw.rm.AssertExpectations(t)
|
|
})
|
|
}
|
|
})
|
|
}
|
|
|
|
func TestSearch(t *testing.T) {
|
|
t.Run("invalid request params", func(t *testing.T) {
|
|
testCases := []struct {
|
|
desc string
|
|
params string
|
|
}{
|
|
{"invalid limit", "limit=z"},
|
|
{"invalid limit", "limit=100"},
|
|
{"invalid offset", "offset=z"},
|
|
{"invalid kind", "kind=z"},
|
|
{"invalid kind (one of them)", "kind=0&kind=z"},
|
|
}
|
|
for _, tc := range testCases {
|
|
t.Run(fmt.Sprintf("%s: %s", tc.desc, tc.params), func(t *testing.T) {
|
|
t.Parallel()
|
|
w := httptest.NewRecorder()
|
|
r, _ := http.NewRequest("GET", "/?"+tc.params, nil)
|
|
|
|
hw := newHandlersWrapper()
|
|
hw.h.Search(w, r)
|
|
resp := w.Result()
|
|
defer resp.Body.Close()
|
|
|
|
assert.Equal(t, http.StatusBadRequest, resp.StatusCode)
|
|
})
|
|
}
|
|
})
|
|
|
|
t.Run("invalid search input", func(t *testing.T) {
|
|
t.Parallel()
|
|
w := httptest.NewRecorder()
|
|
r, _ := http.NewRequest("GET", "/", nil)
|
|
|
|
hw := newHandlersWrapper()
|
|
hw.rm.On("SearchJSON", r.Context(), mock.Anything).Return(nil, hub.ErrInvalidInput)
|
|
hw.h.Search(w, r)
|
|
resp := w.Result()
|
|
defer resp.Body.Close()
|
|
|
|
assert.Equal(t, http.StatusBadRequest, resp.StatusCode)
|
|
hw.rm.AssertExpectations(t)
|
|
})
|
|
|
|
t.Run("valid authenticated request, search succeeded", func(t *testing.T) {
|
|
t.Parallel()
|
|
w := httptest.NewRecorder()
|
|
v := url.Values{}
|
|
v.Set("name", "n1")
|
|
v.Add("user", "u1")
|
|
v.Add("user", "u2")
|
|
v.Add("org", "o1")
|
|
v.Add("org", "o2")
|
|
v.Add("kind", "0")
|
|
v.Add("kind", "3")
|
|
v.Set("limit", "10")
|
|
v.Set("offset", "10")
|
|
r, _ := http.NewRequest("GET", "/?"+v.Encode(), nil)
|
|
r = r.WithContext(context.WithValue(r.Context(), hub.UserIDKey, "userID"))
|
|
|
|
hw := newHandlersWrapper()
|
|
hw.rm.On("SearchJSON", r.Context(), &hub.SearchRepositoryInput{
|
|
Name: "n1",
|
|
Kinds: []hub.RepositoryKind{hub.Helm, hub.OLM},
|
|
Orgs: []string{"o1", "o2"},
|
|
Users: []string{"u1", "u2"},
|
|
IncludeCredentials: false,
|
|
Limit: 10,
|
|
Offset: 10,
|
|
}).Return(&hub.JSONQueryResult{
|
|
Data: []byte("dataJSON"),
|
|
TotalCount: 1,
|
|
}, nil)
|
|
hw.h.Search(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, helpers.BuildCacheControlHeader(0), h.Get("Cache-Control"))
|
|
assert.Equal(t, "application/json", h.Get("Content-Type"))
|
|
assert.Equal(t, []byte("dataJSON"), data)
|
|
hw.rm.AssertExpectations(t)
|
|
})
|
|
|
|
t.Run("valid unauthenticated request, search succeeded", func(t *testing.T) {
|
|
t.Parallel()
|
|
w := httptest.NewRecorder()
|
|
r, _ := http.NewRequest("GET", "/", nil)
|
|
|
|
hw := newHandlersWrapper()
|
|
hw.rm.On("SearchJSON", r.Context(), &hub.SearchRepositoryInput{
|
|
Kinds: []hub.RepositoryKind{},
|
|
Limit: 20,
|
|
Offset: 0,
|
|
}).Return(&hub.JSONQueryResult{
|
|
Data: []byte("dataJSON"),
|
|
TotalCount: 1,
|
|
}, nil)
|
|
hw.h.Search(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, helpers.BuildCacheControlHeader(1*time.Hour), h.Get("Cache-Control"))
|
|
assert.Equal(t, "application/json", h.Get("Content-Type"))
|
|
assert.Equal(t, []byte("dataJSON"), data)
|
|
hw.rm.AssertExpectations(t)
|
|
})
|
|
|
|
t.Run("error searching repositories", func(t *testing.T) {
|
|
t.Parallel()
|
|
w := httptest.NewRecorder()
|
|
r, _ := http.NewRequest("GET", "/", nil)
|
|
|
|
hw := newHandlersWrapper()
|
|
hw.rm.On("SearchJSON", r.Context(), mock.Anything).Return(nil, tests.ErrFakeDB)
|
|
hw.h.Search(w, r)
|
|
resp := w.Result()
|
|
defer resp.Body.Close()
|
|
|
|
assert.Equal(t, http.StatusInternalServerError, resp.StatusCode)
|
|
hw.rm.AssertExpectations(t)
|
|
})
|
|
}
|
|
|
|
func TestTransfer(t *testing.T) {
|
|
t.Run("invalid input - missing repo name", func(t *testing.T) {
|
|
t.Parallel()
|
|
w := httptest.NewRecorder()
|
|
r, _ := http.NewRequest("PUT", "/", nil)
|
|
r = r.WithContext(context.WithValue(r.Context(), hub.UserIDKey, "userID"))
|
|
|
|
hw := newHandlersWrapper()
|
|
hw.rm.On("Transfer", r.Context(), "", "", false).Return(hub.ErrInvalidInput)
|
|
hw.h.Transfer(w, r)
|
|
resp := w.Result()
|
|
defer resp.Body.Close()
|
|
|
|
assert.Equal(t, http.StatusBadRequest, resp.StatusCode)
|
|
hw.rm.AssertExpectations(t)
|
|
})
|
|
|
|
t.Run("valid input", func(t *testing.T) {
|
|
testCases := []struct {
|
|
description string
|
|
err error
|
|
expectedStatusCode int
|
|
}{
|
|
{
|
|
"repository transfer succeeded",
|
|
nil,
|
|
http.StatusNoContent,
|
|
},
|
|
{
|
|
"error transferring repository (insufficient privilege)",
|
|
hub.ErrInsufficientPrivilege,
|
|
http.StatusForbidden,
|
|
},
|
|
{
|
|
"error transferring repository (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", "/?org=org1", nil)
|
|
r = r.WithContext(context.WithValue(r.Context(), hub.UserIDKey, "userID"))
|
|
rctx := &chi.Context{
|
|
URLParams: chi.RouteParams{
|
|
Keys: []string{"repoName"},
|
|
Values: []string{"repo1"},
|
|
},
|
|
}
|
|
r = r.WithContext(context.WithValue(r.Context(), chi.RouteCtxKey, rctx))
|
|
|
|
hw := newHandlersWrapper()
|
|
hw.rm.On("Transfer", r.Context(), "repo1", "org1", false).Return(tc.err)
|
|
hw.h.Transfer(w, r)
|
|
resp := w.Result()
|
|
defer resp.Body.Close()
|
|
|
|
assert.Equal(t, tc.expectedStatusCode, resp.StatusCode)
|
|
hw.rm.AssertExpectations(t)
|
|
})
|
|
}
|
|
})
|
|
}
|
|
|
|
func TestUpdate(t *testing.T) {
|
|
t.Run("invalid input", func(t *testing.T) {
|
|
testCases := []struct {
|
|
description string
|
|
repoJSON string
|
|
rmErr error
|
|
}{
|
|
{
|
|
"no repository provided",
|
|
"",
|
|
nil,
|
|
},
|
|
{
|
|
"invalid json",
|
|
"-",
|
|
nil,
|
|
},
|
|
{
|
|
"missing name",
|
|
`{"url": "https://repo1.url"}`,
|
|
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.repoJSON))
|
|
r = r.WithContext(context.WithValue(r.Context(), hub.UserIDKey, "userID"))
|
|
|
|
hw := newHandlersWrapper()
|
|
if tc.rmErr != nil {
|
|
hw.rm.On("Update", r.Context(), mock.Anything).Return(tc.rmErr)
|
|
}
|
|
hw.h.Update(w, r)
|
|
resp := w.Result()
|
|
defer resp.Body.Close()
|
|
|
|
assert.Equal(t, http.StatusBadRequest, resp.StatusCode)
|
|
hw.rm.AssertExpectations(t)
|
|
})
|
|
}
|
|
})
|
|
|
|
t.Run("valid repository provided", func(t *testing.T) {
|
|
repoJSON := `
|
|
{
|
|
"display_name": "Repository 1 updated",
|
|
"url": "https://repo1.url/updated"
|
|
}
|
|
`
|
|
repo := &hub.Repository{}
|
|
_ = json.Unmarshal([]byte(repoJSON), &repo)
|
|
|
|
testCases := []struct {
|
|
description string
|
|
err error
|
|
expectedStatusCode int
|
|
}{
|
|
{
|
|
"repository update succeeded",
|
|
nil,
|
|
http.StatusNoContent,
|
|
},
|
|
{
|
|
"error updating repository (insufficient privilege)",
|
|
hub.ErrInsufficientPrivilege,
|
|
http.StatusForbidden,
|
|
},
|
|
{
|
|
"error updating repository (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(repoJSON))
|
|
r = r.WithContext(context.WithValue(r.Context(), hub.UserIDKey, "userID"))
|
|
|
|
hw := newHandlersWrapper()
|
|
hw.rm.On("Update", r.Context(), repo).Return(tc.err)
|
|
hw.h.Update(w, r)
|
|
resp := w.Result()
|
|
defer resp.Body.Close()
|
|
|
|
assert.Equal(t, tc.expectedStatusCode, resp.StatusCode)
|
|
hw.rm.AssertExpectations(t)
|
|
})
|
|
}
|
|
})
|
|
}
|
|
|
|
type handlersWrapper struct {
|
|
cfg *viper.Viper
|
|
rm *repo.ManagerMock
|
|
h *Handlers
|
|
}
|
|
|
|
func newHandlersWrapper() *handlersWrapper {
|
|
cfg := viper.New()
|
|
cfg.Set("theme.colors.primary", "#417598")
|
|
cfg.Set("theme.colors.secondary", "#2D4857")
|
|
cfg.Set("theme.siteName", "Artifact Hub")
|
|
rm := &repo.ManagerMock{}
|
|
|
|
return &handlersWrapper{
|
|
cfg: cfg,
|
|
rm: rm,
|
|
h: NewHandlers(cfg, rm),
|
|
}
|
|
}
|