mirror of https://github.com/artifacthub/hub.git
1974 lines
51 KiB
Go
1974 lines
51 KiB
Go
package repo
|
|
|
|
import (
|
|
"bytes"
|
|
"context"
|
|
"encoding/json"
|
|
"errors"
|
|
"fmt"
|
|
"io"
|
|
"net/http"
|
|
"os"
|
|
"strconv"
|
|
"strings"
|
|
"testing"
|
|
|
|
"github.com/artifacthub/hub/internal/authz"
|
|
"github.com/artifacthub/hub/internal/httpw"
|
|
"github.com/artifacthub/hub/internal/hub"
|
|
"github.com/artifacthub/hub/internal/oci"
|
|
"github.com/artifacthub/hub/internal/tests"
|
|
"github.com/artifacthub/hub/internal/util"
|
|
ocispec "github.com/opencontainers/image-spec/specs-go/v1"
|
|
"github.com/spf13/viper"
|
|
"github.com/stretchr/testify/assert"
|
|
"github.com/stretchr/testify/mock"
|
|
"github.com/stretchr/testify/require"
|
|
"gopkg.in/yaml.v2"
|
|
)
|
|
|
|
const repoID = "00000000-0000-0000-0000-000000000001"
|
|
|
|
var cfg = viper.New()
|
|
|
|
func TestAdd(t *testing.T) {
|
|
ctx := context.WithValue(context.Background(), hub.UserIDKey, "userID")
|
|
|
|
t.Run("user id not found in ctx", func(t *testing.T) {
|
|
t.Parallel()
|
|
m := NewManager(cfg, nil, nil, nil)
|
|
assert.Panics(t, func() {
|
|
_ = m.Add(context.Background(), "orgName", nil)
|
|
})
|
|
})
|
|
|
|
t.Run("invalid input", func(t *testing.T) {
|
|
testCases := []struct {
|
|
errMsg string
|
|
orgName string
|
|
r *hub.Repository
|
|
lErr error
|
|
}{
|
|
{
|
|
"invalid kind",
|
|
"org1",
|
|
&hub.Repository{
|
|
Kind: hub.RepositoryKind(100),
|
|
},
|
|
nil,
|
|
},
|
|
{
|
|
"name not provided",
|
|
"org1",
|
|
&hub.Repository{
|
|
Kind: hub.Helm,
|
|
Name: "",
|
|
},
|
|
nil,
|
|
},
|
|
{
|
|
"invalid name",
|
|
"org1",
|
|
&hub.Repository{
|
|
Kind: hub.Helm,
|
|
Name: "1repo",
|
|
URL: "https://repo1.com",
|
|
},
|
|
nil,
|
|
},
|
|
{
|
|
"invalid name",
|
|
"org1",
|
|
&hub.Repository{
|
|
Kind: hub.Helm,
|
|
Name: "repo_underscore",
|
|
URL: "https://repo1.com",
|
|
},
|
|
nil,
|
|
},
|
|
{
|
|
"invalid name",
|
|
"org1",
|
|
&hub.Repository{
|
|
Kind: hub.Helm,
|
|
Name: "REPO_UPPERCASE",
|
|
URL: "https://repo1.com",
|
|
},
|
|
nil,
|
|
},
|
|
{
|
|
"url not provided",
|
|
"org1",
|
|
&hub.Repository{
|
|
Kind: hub.Helm,
|
|
Name: "repo1",
|
|
URL: "",
|
|
},
|
|
nil,
|
|
},
|
|
{
|
|
"missing protocol scheme",
|
|
"org1",
|
|
&hub.Repository{
|
|
Kind: hub.Helm,
|
|
Name: "repo1",
|
|
URL: ":::///",
|
|
},
|
|
nil,
|
|
},
|
|
{
|
|
"scheme not supported",
|
|
"org1",
|
|
&hub.Repository{
|
|
Kind: hub.Helm,
|
|
Name: "repo1",
|
|
URL: "other://repo1.com",
|
|
},
|
|
nil,
|
|
},
|
|
{
|
|
"urls with credentials not allowed",
|
|
"org1",
|
|
&hub.Repository{
|
|
Kind: hub.Helm,
|
|
Name: "repo1",
|
|
URL: "https://user:pass@repo1.com",
|
|
},
|
|
nil,
|
|
},
|
|
{
|
|
"invalid url format",
|
|
"org1",
|
|
&hub.Repository{
|
|
Kind: hub.OLM,
|
|
Name: "repo1",
|
|
URL: "https://repo1.com",
|
|
},
|
|
nil,
|
|
},
|
|
{
|
|
"invalid url format",
|
|
"org1",
|
|
&hub.Repository{
|
|
Kind: hub.OLM,
|
|
Name: "repo1",
|
|
URL: "https://github.com/incomplete",
|
|
},
|
|
nil,
|
|
},
|
|
{
|
|
"invalid url format",
|
|
"org1",
|
|
&hub.Repository{
|
|
Kind: hub.Container,
|
|
Name: "repo1",
|
|
URL: "https://repo1.url",
|
|
},
|
|
nil,
|
|
},
|
|
{
|
|
"the url provided does not point to a valid Helm repository",
|
|
"org1",
|
|
&hub.Repository{
|
|
Kind: hub.Helm,
|
|
Name: "repo1",
|
|
URL: "https://repo1.com",
|
|
},
|
|
errors.New("error loading index file"),
|
|
},
|
|
{
|
|
"private repositories not allowed",
|
|
"org1",
|
|
&hub.Repository{
|
|
Kind: hub.Helm,
|
|
Name: "repo1",
|
|
URL: "https://repo1.com",
|
|
AuthUser: "user1",
|
|
AuthPass: "pass1",
|
|
},
|
|
nil,
|
|
},
|
|
{
|
|
"invalid container image data",
|
|
"org1",
|
|
&hub.Repository{
|
|
Kind: hub.Container,
|
|
Name: "repo1",
|
|
URL: "oci://registry.io/namespace/repo",
|
|
Data: json.RawMessage("{["),
|
|
},
|
|
nil,
|
|
},
|
|
{
|
|
"too many tags",
|
|
"org1",
|
|
&hub.Repository{
|
|
Kind: hub.Container,
|
|
Name: "repo1",
|
|
URL: "oci://registry.io/namespace/repo",
|
|
Data: json.RawMessage(`{
|
|
"tags": [
|
|
{"name": "tag1"},
|
|
{"name": "tag2"},
|
|
{"name": "tag3"},
|
|
{"name": "tag4"},
|
|
{"name": "tag5"},
|
|
{"name": "tag6"},
|
|
{"name": "tag7"},
|
|
{"name": "tag8"},
|
|
{"name": "tag9"},
|
|
{"name": "tag10"},
|
|
{"name": "tag11"}
|
|
]
|
|
}`),
|
|
},
|
|
nil,
|
|
},
|
|
}
|
|
for _, tc := range testCases {
|
|
t.Run(tc.errMsg, func(t *testing.T) {
|
|
t.Parallel()
|
|
l := &HelmIndexLoaderMock{}
|
|
if tc.lErr != nil {
|
|
l.On("LoadIndex", tc.r).Return(nil, "", tc.lErr)
|
|
} else {
|
|
l.On("LoadIndex", tc.r).Return(nil, "", nil).Maybe()
|
|
}
|
|
m := NewManager(cfg, nil, nil, nil, WithHelmIndexLoader(l))
|
|
|
|
err := m.Add(ctx, tc.orgName, tc.r)
|
|
assert.True(t, errors.Is(err, hub.ErrInvalidInput))
|
|
assert.Contains(t, err.Error(), tc.errMsg)
|
|
l.AssertExpectations(t)
|
|
})
|
|
}
|
|
})
|
|
|
|
t.Run("authorization failed", func(t *testing.T) {
|
|
t.Parallel()
|
|
r := &hub.Repository{
|
|
Name: "repo1",
|
|
DisplayName: "Repository 1",
|
|
URL: "https://repo1.com",
|
|
Kind: hub.Helm,
|
|
}
|
|
az := &authz.AuthorizerMock{}
|
|
az.On("Authorize", ctx, &hub.AuthorizeInput{
|
|
OrganizationName: "orgName",
|
|
UserID: "userID",
|
|
Action: hub.AddOrganizationRepository,
|
|
}).Return(tests.ErrFake)
|
|
l := &HelmIndexLoaderMock{}
|
|
l.On("LoadIndex", r).Return(nil, "", nil)
|
|
m := NewManager(cfg, nil, az, nil, WithHelmIndexLoader(l))
|
|
|
|
err := m.Add(ctx, "orgName", r)
|
|
assert.Equal(t, tests.ErrFake, err)
|
|
l.AssertExpectations(t)
|
|
az.AssertExpectations(t)
|
|
})
|
|
|
|
t.Run("database error", func(t *testing.T) {
|
|
testCases := []struct {
|
|
r *hub.Repository
|
|
dbErr error
|
|
expectedError error
|
|
}{
|
|
{
|
|
&hub.Repository{
|
|
Name: "repo1",
|
|
DisplayName: "Repository 1",
|
|
URL: "https://repo1.com",
|
|
Kind: hub.Helm,
|
|
},
|
|
tests.ErrFakeDB,
|
|
tests.ErrFakeDB,
|
|
},
|
|
{
|
|
&hub.Repository{
|
|
Name: "repo1",
|
|
DisplayName: "Repository 1",
|
|
URL: "https://repo1.com",
|
|
Kind: hub.Helm,
|
|
},
|
|
util.ErrDBInsufficientPrivilege,
|
|
hub.ErrInsufficientPrivilege,
|
|
},
|
|
}
|
|
for _, tc := range testCases {
|
|
t.Run(tc.dbErr.Error(), func(t *testing.T) {
|
|
t.Parallel()
|
|
db := &tests.DBMock{}
|
|
db.On("Exec", ctx, addRepoDBQ, "userID", "orgName", mock.Anything).Return(tc.dbErr)
|
|
az := &authz.AuthorizerMock{}
|
|
az.On("Authorize", ctx, &hub.AuthorizeInput{
|
|
OrganizationName: "orgName",
|
|
UserID: "userID",
|
|
Action: hub.AddOrganizationRepository,
|
|
}).Return(nil)
|
|
l := &HelmIndexLoaderMock{}
|
|
l.On("LoadIndex", tc.r).Return(nil, "", nil)
|
|
m := NewManager(cfg, db, az, nil, WithHelmIndexLoader(l))
|
|
|
|
err := m.Add(ctx, "orgName", tc.r)
|
|
assert.Equal(t, tc.expectedError, err)
|
|
db.AssertExpectations(t)
|
|
az.AssertExpectations(t)
|
|
l.AssertExpectations(t)
|
|
})
|
|
}
|
|
})
|
|
|
|
t.Run("add repository succeeded", func(t *testing.T) {
|
|
testCases := []struct {
|
|
r *hub.Repository
|
|
}{
|
|
{
|
|
&hub.Repository{
|
|
Name: "repo1",
|
|
DisplayName: "Repository 1",
|
|
URL: "https://repo1.com",
|
|
Kind: hub.Helm,
|
|
},
|
|
},
|
|
{
|
|
&hub.Repository{
|
|
Name: "repo2",
|
|
DisplayName: "Repository 2",
|
|
URL: "https://github.com/org2/repo2/path",
|
|
Kind: hub.OLM,
|
|
},
|
|
},
|
|
}
|
|
for i, tc := range testCases {
|
|
t.Run(strconv.Itoa(i), func(t *testing.T) {
|
|
t.Parallel()
|
|
db := &tests.DBMock{}
|
|
db.On("Exec", ctx, addRepoDBQ, "userID", "orgName", mock.Anything).Return(nil)
|
|
az := &authz.AuthorizerMock{}
|
|
az.On("Authorize", ctx, &hub.AuthorizeInput{
|
|
OrganizationName: "orgName",
|
|
UserID: "userID",
|
|
Action: hub.AddOrganizationRepository,
|
|
}).Return(nil)
|
|
l := &HelmIndexLoaderMock{}
|
|
if tc.r.Kind == hub.Helm {
|
|
l.On("LoadIndex", tc.r).Return(nil, "", nil)
|
|
}
|
|
m := NewManager(cfg, db, az, nil, WithHelmIndexLoader(l))
|
|
|
|
err := m.Add(ctx, "orgName", tc.r)
|
|
assert.NoError(t, err)
|
|
db.AssertExpectations(t)
|
|
az.AssertExpectations(t)
|
|
l.AssertExpectations(t)
|
|
})
|
|
}
|
|
})
|
|
}
|
|
|
|
func TestCheckAvailability(t *testing.T) {
|
|
ctx := context.Background()
|
|
|
|
t.Run("invalid input", func(t *testing.T) {
|
|
testCases := []struct {
|
|
errMsg string
|
|
resourceKind string
|
|
value string
|
|
}{
|
|
{
|
|
"invalid resource kind",
|
|
"invalid",
|
|
"value",
|
|
},
|
|
{
|
|
"invalid value",
|
|
"repositoryName",
|
|
"",
|
|
},
|
|
}
|
|
for _, tc := range testCases {
|
|
t.Run(tc.errMsg, func(t *testing.T) {
|
|
t.Parallel()
|
|
m := NewManager(cfg, nil, nil, nil)
|
|
_, err := m.CheckAvailability(context.Background(), tc.resourceKind, tc.value)
|
|
assert.True(t, errors.Is(err, hub.ErrInvalidInput))
|
|
assert.Contains(t, err.Error(), tc.errMsg)
|
|
})
|
|
}
|
|
})
|
|
|
|
t.Run("database query succeeded", func(t *testing.T) {
|
|
testCases := []struct {
|
|
resourceKind string
|
|
dbQuery string
|
|
available bool
|
|
}{
|
|
{
|
|
"repositoryName",
|
|
checkRepoNameAvailDBQ,
|
|
true,
|
|
},
|
|
{
|
|
"repositoryURL",
|
|
checkRepoURLAvailDBQ,
|
|
false,
|
|
},
|
|
}
|
|
for _, tc := range testCases {
|
|
t.Run(fmt.Sprintf("resource kind: %s", tc.resourceKind), func(t *testing.T) {
|
|
t.Parallel()
|
|
tc.dbQuery = fmt.Sprintf("select not exists (%s)", tc.dbQuery)
|
|
db := &tests.DBMock{}
|
|
db.On("QueryRow", ctx, tc.dbQuery, "value").Return(tc.available, nil)
|
|
m := NewManager(cfg, db, nil, nil)
|
|
|
|
available, err := m.CheckAvailability(ctx, tc.resourceKind, "value/")
|
|
assert.NoError(t, err)
|
|
assert.Equal(t, tc.available, available)
|
|
db.AssertExpectations(t)
|
|
})
|
|
}
|
|
})
|
|
|
|
t.Run("database error", func(t *testing.T) {
|
|
t.Parallel()
|
|
db := &tests.DBMock{}
|
|
dbQuery := fmt.Sprintf(`select not exists (%s)`, checkRepoNameAvailDBQ)
|
|
db.On("QueryRow", ctx, dbQuery, "value").Return(false, tests.ErrFakeDB)
|
|
m := NewManager(cfg, db, nil, nil)
|
|
|
|
available, err := m.CheckAvailability(ctx, "repositoryName", "value")
|
|
assert.Equal(t, tests.ErrFakeDB, err)
|
|
assert.False(t, available)
|
|
db.AssertExpectations(t)
|
|
})
|
|
}
|
|
|
|
func TestClaimOwnership(t *testing.T) {
|
|
userID := "userID"
|
|
userIDP := &userID
|
|
org := "org1"
|
|
orgP := &org
|
|
helmRepoJSON := []byte(`{"kind": 0, "url": "http://repo.url"}`)
|
|
opaRepoJSON := []byte(`{"kind": 2, "url": "http://repo.url"}`)
|
|
olmRepoJSON := []byte(`{"kind": 3, "url": "oci://repo.url"}`)
|
|
ctx := context.WithValue(context.Background(), hub.UserIDKey, userID)
|
|
mdYmlReq, _ := httpw.NewRequest("GET", "http://repo.url/artifacthub-repo.yml", nil)
|
|
mdYamlReq, _ := httpw.NewRequest("GET", "http://repo.url/artifacthub-repo.yaml", nil)
|
|
|
|
t.Run("user id not found in ctx", func(t *testing.T) {
|
|
t.Parallel()
|
|
m := NewManager(cfg, nil, nil, nil)
|
|
assert.Panics(t, func() {
|
|
_ = m.ClaimOwnership(context.Background(), "repo1", "")
|
|
})
|
|
})
|
|
|
|
t.Run("invalid input", func(t *testing.T) {
|
|
testCases := []struct {
|
|
errMsg string
|
|
repoName string
|
|
}{
|
|
{
|
|
"repository name not provided",
|
|
"",
|
|
},
|
|
}
|
|
for _, tc := range testCases {
|
|
t.Run(tc.errMsg, func(t *testing.T) {
|
|
t.Parallel()
|
|
m := NewManager(cfg, nil, nil, nil)
|
|
|
|
err := m.ClaimOwnership(ctx, tc.repoName, "")
|
|
assert.True(t, errors.Is(err, hub.ErrInvalidInput))
|
|
})
|
|
}
|
|
})
|
|
|
|
t.Run("ownership claim failed: database error getting repository", func(t *testing.T) {
|
|
t.Parallel()
|
|
db := &tests.DBMock{}
|
|
db.On("QueryRow", ctx, getRepoByNameDBQ, "repo1", true).Return(nil, tests.ErrFakeDB)
|
|
m := NewManager(cfg, db, nil, nil)
|
|
|
|
err := m.ClaimOwnership(ctx, "repo1", org)
|
|
assert.Equal(t, tests.ErrFakeDB, err)
|
|
db.AssertExpectations(t)
|
|
})
|
|
|
|
t.Run("ownership claim failed: error getting repository metadata", func(t *testing.T) {
|
|
t.Parallel()
|
|
db := &tests.DBMock{}
|
|
db.On("QueryRow", ctx, getRepoByNameDBQ, "repo1", true).Return(helmRepoJSON, nil)
|
|
hc := &tests.HTTPClientMock{}
|
|
hc.On("Do", mdYmlReq).Return(&http.Response{
|
|
Body: io.NopCloser(strings.NewReader("")),
|
|
StatusCode: http.StatusNotFound,
|
|
}, nil)
|
|
hc.On("Do", mdYamlReq).Return(&http.Response{
|
|
Body: io.NopCloser(strings.NewReader("")),
|
|
StatusCode: http.StatusNotFound,
|
|
}, nil)
|
|
m := NewManager(cfg, db, nil, hc)
|
|
|
|
err := m.ClaimOwnership(ctx, "repo1", org)
|
|
assert.Error(t, err)
|
|
db.AssertExpectations(t)
|
|
hc.AssertExpectations(t)
|
|
})
|
|
|
|
t.Run("ownership claim failed: database error getting user email", func(t *testing.T) {
|
|
t.Parallel()
|
|
db := &tests.DBMock{}
|
|
db.On("QueryRow", ctx, getRepoByNameDBQ, "repo1", true).Return(helmRepoJSON, nil)
|
|
db.On("QueryRow", ctx, getUserEmailDBQ, userID).Return("", tests.ErrFakeDB)
|
|
mdFile, _ := os.Open("testdata/artifacthub-repo.yml")
|
|
hc := &tests.HTTPClientMock{}
|
|
hc.On("Do", mdYmlReq).Return(&http.Response{
|
|
Body: mdFile,
|
|
StatusCode: http.StatusOK,
|
|
}, nil)
|
|
m := NewManager(cfg, db, nil, hc)
|
|
|
|
err := m.ClaimOwnership(ctx, "repo1", org)
|
|
assert.Equal(t, tests.ErrFakeDB, err)
|
|
db.AssertExpectations(t)
|
|
hc.AssertExpectations(t)
|
|
})
|
|
|
|
t.Run("ownership claim failed: user not in repository owners list", func(t *testing.T) {
|
|
t.Parallel()
|
|
db := &tests.DBMock{}
|
|
db.On("QueryRow", ctx, getRepoByNameDBQ, "repo1", true).Return(helmRepoJSON, nil)
|
|
db.On("QueryRow", ctx, getUserEmailDBQ, userID).Return("user1@email.com", nil)
|
|
mdFile, _ := os.Open("testdata/artifacthub-repo.yml")
|
|
hc := &tests.HTTPClientMock{}
|
|
hc.On("Do", mdYmlReq).Return(&http.Response{
|
|
Body: mdFile,
|
|
StatusCode: http.StatusOK,
|
|
}, nil)
|
|
m := NewManager(cfg, db, nil, hc)
|
|
|
|
err := m.ClaimOwnership(ctx, "repo1", org)
|
|
assert.Equal(t, hub.ErrInsufficientPrivilege, err)
|
|
db.AssertExpectations(t)
|
|
hc.AssertExpectations(t)
|
|
})
|
|
|
|
t.Run("ownership claim failed: olm oci repo", func(t *testing.T) {
|
|
t.Parallel()
|
|
db := &tests.DBMock{}
|
|
db.On("QueryRow", ctx, getRepoByNameDBQ, "repo1", true).Return(olmRepoJSON, nil)
|
|
m := NewManager(cfg, db, nil, nil)
|
|
|
|
err := m.ClaimOwnership(ctx, "repo1", org)
|
|
assert.True(t, errors.Is(err, hub.ErrInvalidInput))
|
|
db.AssertExpectations(t)
|
|
})
|
|
|
|
t.Run("ownership claim succeeded (helm)", func(t *testing.T) {
|
|
t.Parallel()
|
|
db := &tests.DBMock{}
|
|
db.On("QueryRow", ctx, getRepoByNameDBQ, "repo1", true).Return(helmRepoJSON, nil)
|
|
db.On("QueryRow", ctx, getUserEmailDBQ, userID).Return("owner1@email.com", nil)
|
|
db.On("Exec", ctx, transferRepoDBQ, "repo1", userIDP, orgP, true).Return(nil)
|
|
mdFile, _ := os.Open("testdata/artifacthub-repo.yml")
|
|
hc := &tests.HTTPClientMock{}
|
|
hc.On("Do", mdYmlReq).Return(&http.Response{
|
|
Body: mdFile,
|
|
StatusCode: http.StatusOK,
|
|
}, nil)
|
|
m := NewManager(cfg, db, nil, hc)
|
|
|
|
err := m.ClaimOwnership(ctx, "repo1", org)
|
|
assert.Nil(t, err)
|
|
db.AssertExpectations(t)
|
|
hc.AssertExpectations(t)
|
|
})
|
|
|
|
t.Run("ownership claim failed (opa): error cloning repository", func(t *testing.T) {
|
|
t.Parallel()
|
|
db := &tests.DBMock{}
|
|
db.On("QueryRow", ctx, getRepoByNameDBQ, "repo1", true).Return(opaRepoJSON, nil)
|
|
rc := &ClonerMock{}
|
|
var r *hub.Repository
|
|
_ = json.Unmarshal(opaRepoJSON, &r)
|
|
rc.On("CloneRepository", ctx, r).Return("", "", tests.ErrFake)
|
|
m := NewManager(cfg, db, nil, nil, withRepositoryCloner(rc))
|
|
|
|
err := m.ClaimOwnership(ctx, "repo1", org)
|
|
assert.Equal(t, tests.ErrFake, err)
|
|
db.AssertExpectations(t)
|
|
})
|
|
|
|
t.Run("ownership claim succeeded (opa)", func(t *testing.T) {
|
|
t.Parallel()
|
|
db := &tests.DBMock{}
|
|
db.On("QueryRow", ctx, getRepoByNameDBQ, "repo1", true).Return(opaRepoJSON, nil)
|
|
db.On("QueryRow", ctx, getUserEmailDBQ, userID).Return("owner1@email.com", nil)
|
|
db.On("Exec", ctx, transferRepoDBQ, "repo1", userIDP, orgP, true).Return(nil)
|
|
rc := &ClonerMock{}
|
|
var r *hub.Repository
|
|
_ = json.Unmarshal(opaRepoJSON, &r)
|
|
rc.On("CloneRepository", ctx, r).Return(".", "testdata", nil)
|
|
m := NewManager(cfg, db, nil, nil, withRepositoryCloner(rc))
|
|
|
|
err := m.ClaimOwnership(ctx, "repo1", org)
|
|
assert.Nil(t, err)
|
|
db.AssertExpectations(t)
|
|
rc.AssertExpectations(t)
|
|
})
|
|
}
|
|
|
|
func TestDelete(t *testing.T) {
|
|
ctx := context.WithValue(context.Background(), hub.UserIDKey, "userID")
|
|
|
|
t.Run("user id not found in ctx", func(t *testing.T) {
|
|
t.Parallel()
|
|
m := NewManager(cfg, nil, nil, nil)
|
|
assert.Panics(t, func() {
|
|
_ = m.Delete(context.Background(), "repo1")
|
|
})
|
|
})
|
|
|
|
t.Run("invalid input", func(t *testing.T) {
|
|
t.Parallel()
|
|
m := NewManager(cfg, nil, nil, nil)
|
|
err := m.Delete(ctx, "")
|
|
assert.True(t, errors.Is(err, hub.ErrInvalidInput))
|
|
})
|
|
|
|
t.Run("authorization failed", func(t *testing.T) {
|
|
t.Parallel()
|
|
db := &tests.DBMock{}
|
|
db.On("QueryRow", ctx, getRepoByNameDBQ, "repo1", false).Return([]byte(`
|
|
{
|
|
"repository_id": "00000000-0000-0000-0000-000000000001",
|
|
"name": "repo1",
|
|
"organization_name": "orgName"
|
|
}
|
|
`), nil)
|
|
az := &authz.AuthorizerMock{}
|
|
az.On("Authorize", ctx, &hub.AuthorizeInput{
|
|
OrganizationName: "orgName",
|
|
UserID: "userID",
|
|
Action: hub.DeleteOrganizationRepository,
|
|
}).Return(tests.ErrFake)
|
|
m := NewManager(cfg, db, az, nil)
|
|
|
|
err := m.Delete(ctx, "repo1")
|
|
assert.Equal(t, tests.ErrFake, err)
|
|
db.AssertExpectations(t)
|
|
az.AssertExpectations(t)
|
|
})
|
|
|
|
t.Run("database error", func(t *testing.T) {
|
|
testCases := []struct {
|
|
dbErr error
|
|
expectedError error
|
|
}{
|
|
{
|
|
tests.ErrFakeDB,
|
|
tests.ErrFakeDB,
|
|
},
|
|
{
|
|
util.ErrDBInsufficientPrivilege,
|
|
hub.ErrInsufficientPrivilege,
|
|
},
|
|
}
|
|
for _, tc := range testCases {
|
|
t.Run(tc.dbErr.Error(), func(t *testing.T) {
|
|
t.Parallel()
|
|
db := &tests.DBMock{}
|
|
db.On("QueryRow", ctx, getRepoByNameDBQ, "repo1", false).Return([]byte(`
|
|
{
|
|
"repository_id": "00000000-0000-0000-0000-000000000001",
|
|
"name": "repo1",
|
|
"organization_name": "orgName"
|
|
}
|
|
`), nil)
|
|
db.On("Exec", ctx, deleteRepoDBQ, "userID", "repo1").Return(tc.dbErr)
|
|
az := &authz.AuthorizerMock{}
|
|
az.On("Authorize", ctx, &hub.AuthorizeInput{
|
|
OrganizationName: "orgName",
|
|
UserID: "userID",
|
|
Action: hub.DeleteOrganizationRepository,
|
|
}).Return(nil)
|
|
m := NewManager(cfg, db, az, nil)
|
|
|
|
err := m.Delete(ctx, "repo1")
|
|
assert.Equal(t, tc.expectedError, err)
|
|
db.AssertExpectations(t)
|
|
az.AssertExpectations(t)
|
|
})
|
|
}
|
|
})
|
|
|
|
t.Run("delete repository succeeded", func(t *testing.T) {
|
|
t.Parallel()
|
|
db := &tests.DBMock{}
|
|
db.On("QueryRow", ctx, getRepoByNameDBQ, "repo1", false).Return([]byte(`
|
|
{
|
|
"repository_id": "00000000-0000-0000-0000-000000000001",
|
|
"name": "repo1",
|
|
"user_alias": "user1"
|
|
}
|
|
`), nil)
|
|
db.On("Exec", ctx, deleteRepoDBQ, "userID", "repo1").Return(nil)
|
|
m := NewManager(cfg, db, nil, nil)
|
|
|
|
err := m.Delete(ctx, "repo1")
|
|
assert.NoError(t, err)
|
|
db.AssertExpectations(t)
|
|
})
|
|
}
|
|
|
|
func TestGetByID(t *testing.T) {
|
|
ctx := context.Background()
|
|
|
|
t.Run("invalid input", func(t *testing.T) {
|
|
testCases := []struct {
|
|
repoID string
|
|
errStr string
|
|
}{
|
|
{
|
|
"",
|
|
"repository id not provided",
|
|
},
|
|
{
|
|
"invalid",
|
|
"invalid repository id",
|
|
},
|
|
}
|
|
for _, tc := range testCases {
|
|
t.Run(tc.errStr, func(t *testing.T) {
|
|
t.Parallel()
|
|
m := NewManager(cfg, nil, nil, nil)
|
|
|
|
_, err := m.GetByID(ctx, tc.repoID, false)
|
|
assert.True(t, errors.Is(err, hub.ErrInvalidInput))
|
|
assert.Contains(t, err.Error(), tc.errStr)
|
|
})
|
|
}
|
|
})
|
|
|
|
t.Run("database error", func(t *testing.T) {
|
|
t.Parallel()
|
|
db := &tests.DBMock{}
|
|
db.On("QueryRow", ctx, getRepoByIDDBQ, repoID, false).Return(nil, tests.ErrFakeDB)
|
|
m := NewManager(cfg, db, nil, nil)
|
|
|
|
r, err := m.GetByID(context.Background(), repoID, false)
|
|
assert.Equal(t, tests.ErrFakeDB, err)
|
|
assert.Nil(t, r)
|
|
db.AssertExpectations(t)
|
|
})
|
|
|
|
t.Run("database query succeeded", func(t *testing.T) {
|
|
t.Parallel()
|
|
db := &tests.DBMock{}
|
|
db.On("QueryRow", ctx, getRepoByIDDBQ, repoID, false).Return([]byte(`
|
|
{
|
|
"repository_id": "00000000-0000-0000-0000-000000000001",
|
|
"name": "repo1",
|
|
"display_name": "Repo 1",
|
|
"url": "https://repo1.com",
|
|
"kind": 0,
|
|
"verified_publisher": true,
|
|
"official": true,
|
|
"cncf": true
|
|
}
|
|
`), nil)
|
|
m := NewManager(cfg, db, nil, nil)
|
|
|
|
r, err := m.GetByID(context.Background(), repoID, false)
|
|
require.NoError(t, err)
|
|
assert.Equal(t, repoID, r.RepositoryID)
|
|
assert.Equal(t, "repo1", r.Name)
|
|
assert.Equal(t, "Repo 1", r.DisplayName)
|
|
assert.Equal(t, "https://repo1.com", r.URL)
|
|
assert.Equal(t, hub.Helm, r.Kind)
|
|
assert.True(t, r.VerifiedPublisher)
|
|
assert.True(t, r.Official)
|
|
assert.True(t, r.CNCF)
|
|
db.AssertExpectations(t)
|
|
})
|
|
}
|
|
|
|
func TestGetByName(t *testing.T) {
|
|
ctx := context.Background()
|
|
|
|
t.Run("invalid input", func(t *testing.T) {
|
|
t.Parallel()
|
|
m := NewManager(cfg, nil, nil, nil)
|
|
_, err := m.GetByName(ctx, "", false)
|
|
assert.True(t, errors.Is(err, hub.ErrInvalidInput))
|
|
})
|
|
|
|
t.Run("get existing repository by name", func(t *testing.T) {
|
|
t.Parallel()
|
|
db := &tests.DBMock{}
|
|
db.On("QueryRow", ctx, getRepoByNameDBQ, "repo1", false).Return([]byte(`
|
|
{
|
|
"repository_id": "00000000-0000-0000-0000-000000000001",
|
|
"name": "repo1",
|
|
"display_name": "Repo 1",
|
|
"url": "https://repo1.com",
|
|
"kind": 0,
|
|
"verified_publisher": true,
|
|
"official": true,
|
|
"cncf": true,
|
|
"user_alias": "user",
|
|
"organization_name": ""
|
|
}
|
|
`), nil)
|
|
m := NewManager(cfg, db, nil, nil)
|
|
|
|
r, err := m.GetByName(context.Background(), "repo1", false)
|
|
require.NoError(t, err)
|
|
assert.Equal(t, "00000000-0000-0000-0000-000000000001", r.RepositoryID)
|
|
assert.Equal(t, "repo1", r.Name)
|
|
assert.Equal(t, "Repo 1", r.DisplayName)
|
|
assert.Equal(t, "https://repo1.com", r.URL)
|
|
assert.Equal(t, hub.Helm, r.Kind)
|
|
assert.True(t, r.VerifiedPublisher)
|
|
assert.True(t, r.Official)
|
|
assert.True(t, r.CNCF)
|
|
db.AssertExpectations(t)
|
|
})
|
|
|
|
t.Run("database error", func(t *testing.T) {
|
|
t.Parallel()
|
|
db := &tests.DBMock{}
|
|
db.On("QueryRow", ctx, getRepoByNameDBQ, "repo1", false).Return(nil, tests.ErrFakeDB)
|
|
m := NewManager(cfg, db, nil, nil)
|
|
|
|
r, err := m.GetByName(context.Background(), "repo1", false)
|
|
assert.Equal(t, tests.ErrFakeDB, err)
|
|
assert.Nil(t, r)
|
|
db.AssertExpectations(t)
|
|
})
|
|
|
|
t.Run("invalid json data returned from database", func(t *testing.T) {
|
|
t.Parallel()
|
|
db := &tests.DBMock{}
|
|
db.On("QueryRow", ctx, getRepoByNameDBQ, "repo1", false).Return([]byte("invalid json"), nil)
|
|
m := NewManager(cfg, db, nil, nil)
|
|
|
|
r, err := m.GetByName(context.Background(), "repo1", false)
|
|
assert.Error(t, err)
|
|
assert.Nil(t, r)
|
|
db.AssertExpectations(t)
|
|
})
|
|
}
|
|
|
|
func TestGetMetadata(t *testing.T) {
|
|
repoURL := "http://url.test"
|
|
ymlReq, _ := httpw.NewRequest("GET", "http://url.test/artifacthub-repo.yml", nil)
|
|
yamlReq, _ := httpw.NewRequest("GET", "http://url.test/artifacthub-repo.yaml", nil)
|
|
ociRepoURL := "oci://registry/namespace/repo"
|
|
ociRef := fmt.Sprintf("%s:%s", strings.TrimPrefix(ociRepoURL, hub.RepositoryOCIPrefix), artifacthubTag)
|
|
expectedMetadata := &hub.RepositoryMetadata{
|
|
RepositoryID: "00000000-0000-0000-0000-000000000001",
|
|
Owners: []*hub.Owner{
|
|
{
|
|
Name: "owner1",
|
|
Email: "owner1@email.com",
|
|
},
|
|
},
|
|
}
|
|
expectedMetadataYaml, _ := yaml.Marshal(expectedMetadata)
|
|
|
|
t.Run("local file: metadata file not found", func(t *testing.T) {
|
|
t.Parallel()
|
|
m := NewManager(cfg, nil, nil, nil)
|
|
|
|
r := &hub.Repository{
|
|
Kind: hub.OPA,
|
|
}
|
|
_, err := m.GetMetadata(r, "testdata/not-exists")
|
|
assert.Error(t, err)
|
|
assert.Contains(t, err.Error(), "metadata not found")
|
|
})
|
|
|
|
t.Run("local file: error unmarshaling repository metadata file", func(t *testing.T) {
|
|
t.Parallel()
|
|
m := NewManager(cfg, nil, nil, nil)
|
|
|
|
r := &hub.Repository{
|
|
Kind: hub.OPA,
|
|
}
|
|
_, err := m.GetMetadata(r, "testdata/invalid")
|
|
assert.Error(t, err)
|
|
assert.Contains(t, err.Error(), "error unmarshaling repository metadata file")
|
|
})
|
|
|
|
t.Run("local file: invalid repository id", func(t *testing.T) {
|
|
t.Parallel()
|
|
m := NewManager(cfg, nil, nil, nil)
|
|
|
|
r := &hub.Repository{
|
|
Kind: hub.OPA,
|
|
}
|
|
_, err := m.GetMetadata(r, "testdata/invalid-repo-id")
|
|
assert.Error(t, err)
|
|
assert.Contains(t, err.Error(), "invalid repository id")
|
|
})
|
|
|
|
t.Run("local file: success fetching .yml", func(t *testing.T) {
|
|
t.Parallel()
|
|
m := NewManager(cfg, nil, nil, nil)
|
|
|
|
r := &hub.Repository{
|
|
Kind: hub.OPA,
|
|
}
|
|
md, err := m.GetMetadata(r, "testdata/valid-yml")
|
|
assert.Equal(t, expectedMetadata, md)
|
|
assert.NoError(t, err)
|
|
})
|
|
|
|
t.Run("local file: success .yaml", func(t *testing.T) {
|
|
t.Parallel()
|
|
m := NewManager(cfg, nil, nil, nil)
|
|
|
|
r := &hub.Repository{
|
|
Kind: hub.OPA,
|
|
}
|
|
md, err := m.GetMetadata(r, "testdata/valid-yaml")
|
|
assert.Equal(t, expectedMetadata, md)
|
|
assert.NoError(t, err)
|
|
})
|
|
|
|
t.Run("remote file (http): error downloading repository metadata file", func(t *testing.T) {
|
|
t.Parallel()
|
|
hc := &tests.HTTPClientMock{}
|
|
hc.On("Do", ymlReq).Return(nil, tests.ErrFake)
|
|
hc.On("Do", yamlReq).Return(nil, tests.ErrFake)
|
|
m := NewManager(cfg, nil, nil, hc)
|
|
|
|
r := &hub.Repository{
|
|
Kind: hub.Helm,
|
|
URL: repoURL,
|
|
}
|
|
_, err := m.GetMetadata(r, "")
|
|
assert.Error(t, err)
|
|
assert.Contains(t, err.Error(), "error downloading repository metadata file")
|
|
hc.AssertExpectations(t)
|
|
})
|
|
|
|
t.Run("remote file (http): metadata file not found", func(t *testing.T) {
|
|
t.Parallel()
|
|
hc := &tests.HTTPClientMock{}
|
|
hc.On("Do", ymlReq).Return(&http.Response{
|
|
Body: io.NopCloser(strings.NewReader("")),
|
|
StatusCode: http.StatusNotFound,
|
|
}, nil)
|
|
hc.On("Do", yamlReq).Return(&http.Response{
|
|
Body: io.NopCloser(strings.NewReader("")),
|
|
StatusCode: http.StatusNotFound,
|
|
}, nil)
|
|
m := NewManager(cfg, nil, nil, hc)
|
|
|
|
r := &hub.Repository{
|
|
Kind: hub.Helm,
|
|
URL: repoURL,
|
|
}
|
|
_, err := m.GetMetadata(r, "")
|
|
assert.Error(t, err)
|
|
assert.Contains(t, err.Error(), "metadata not found")
|
|
hc.AssertExpectations(t)
|
|
})
|
|
|
|
t.Run("remote file (http): unexpected status code received", func(t *testing.T) {
|
|
t.Parallel()
|
|
hc := &tests.HTTPClientMock{}
|
|
hc.On("Do", ymlReq).Return(&http.Response{
|
|
Body: io.NopCloser(strings.NewReader("")),
|
|
StatusCode: http.StatusForbidden,
|
|
}, nil)
|
|
hc.On("Do", yamlReq).Return(&http.Response{
|
|
Body: io.NopCloser(strings.NewReader("")),
|
|
StatusCode: http.StatusForbidden,
|
|
}, nil)
|
|
m := NewManager(cfg, nil, nil, hc)
|
|
|
|
r := &hub.Repository{
|
|
Kind: hub.Helm,
|
|
URL: repoURL,
|
|
}
|
|
_, err := m.GetMetadata(r, "")
|
|
assert.Error(t, err)
|
|
assert.Contains(t, err.Error(), "unexpected status code received")
|
|
hc.AssertExpectations(t)
|
|
})
|
|
|
|
t.Run("remote file (http): error reading repository metadata file", func(t *testing.T) {
|
|
t.Parallel()
|
|
hc := &tests.HTTPClientMock{}
|
|
hc.On("Do", ymlReq).Return(&http.Response{
|
|
Body: io.NopCloser(tests.ErrReader(0)),
|
|
StatusCode: http.StatusOK,
|
|
}, nil)
|
|
hc.On("Do", yamlReq).Return(&http.Response{
|
|
Body: io.NopCloser(tests.ErrReader(0)),
|
|
StatusCode: http.StatusOK,
|
|
}, nil)
|
|
m := NewManager(cfg, nil, nil, hc)
|
|
|
|
r := &hub.Repository{
|
|
Kind: hub.Helm,
|
|
URL: repoURL,
|
|
}
|
|
_, err := m.GetMetadata(r, "")
|
|
assert.Error(t, err)
|
|
assert.Contains(t, err.Error(), "error reading repository metadata file")
|
|
hc.AssertExpectations(t)
|
|
})
|
|
|
|
t.Run("remote file (http): success", func(t *testing.T) {
|
|
t.Parallel()
|
|
hc := &tests.HTTPClientMock{}
|
|
hc.On("Do", ymlReq).Return(&http.Response{
|
|
Body: io.NopCloser(bytes.NewReader(expectedMetadataYaml)),
|
|
StatusCode: http.StatusOK,
|
|
}, nil)
|
|
m := NewManager(cfg, nil, nil, hc)
|
|
|
|
r := &hub.Repository{
|
|
Kind: hub.Helm,
|
|
URL: repoURL,
|
|
}
|
|
md, err := m.GetMetadata(r, "")
|
|
assert.Equal(t, expectedMetadata, md)
|
|
assert.NoError(t, err)
|
|
hc.AssertExpectations(t)
|
|
})
|
|
|
|
t.Run("remote file (http - with creds): success", func(t *testing.T) {
|
|
t.Parallel()
|
|
hc := &tests.HTTPClientMock{}
|
|
ymlReqWithCreds := ymlReq.Clone(ymlReq.Context())
|
|
ymlReqWithCreds.SetBasicAuth("user", "pass")
|
|
hc.On("Do", ymlReqWithCreds).Return(&http.Response{
|
|
Body: io.NopCloser(bytes.NewReader(expectedMetadataYaml)),
|
|
StatusCode: http.StatusOK,
|
|
}, nil)
|
|
m := NewManager(cfg, nil, nil, hc)
|
|
|
|
r := &hub.Repository{
|
|
Kind: hub.Helm,
|
|
URL: repoURL,
|
|
AuthUser: "user",
|
|
AuthPass: "pass",
|
|
}
|
|
md, err := m.GetMetadata(r, "")
|
|
assert.Equal(t, expectedMetadata, md)
|
|
assert.NoError(t, err)
|
|
hc.AssertExpectations(t)
|
|
})
|
|
|
|
t.Run("remote file (http): success on yaml", func(t *testing.T) {
|
|
t.Parallel()
|
|
hc := &tests.HTTPClientMock{}
|
|
hc.On("Do", ymlReq).Return(&http.Response{
|
|
Body: io.NopCloser(strings.NewReader("")),
|
|
StatusCode: http.StatusNotFound,
|
|
}, nil)
|
|
hc.On("Do", yamlReq).Return(&http.Response{
|
|
Body: io.NopCloser(bytes.NewReader(expectedMetadataYaml)),
|
|
StatusCode: http.StatusOK,
|
|
}, nil)
|
|
m := NewManager(cfg, nil, nil, hc)
|
|
|
|
r := &hub.Repository{
|
|
Kind: hub.Helm,
|
|
URL: repoURL,
|
|
}
|
|
md, err := m.GetMetadata(r, "")
|
|
assert.Equal(t, expectedMetadata, md)
|
|
assert.NoError(t, err)
|
|
hc.AssertExpectations(t)
|
|
})
|
|
|
|
t.Run("remote file (oci): error pulling metadata layer", func(t *testing.T) {
|
|
t.Parallel()
|
|
op := &oci.PullerMock{}
|
|
op.On("PullLayer", mock.Anything, ociRef, MetadataLayerMediaType, "", "").
|
|
Return(ocispec.Descriptor{}, nil, tests.ErrFake)
|
|
m := NewManager(cfg, nil, nil, nil, WithOCIPuller(op))
|
|
|
|
r := &hub.Repository{
|
|
Kind: hub.Helm,
|
|
URL: ociRepoURL,
|
|
}
|
|
md, err := m.GetMetadata(r, "")
|
|
assert.Equal(t, tests.ErrFake, err)
|
|
assert.Nil(t, md)
|
|
op.AssertExpectations(t)
|
|
})
|
|
|
|
t.Run("remote file (oci): metadata layer not found", func(t *testing.T) {
|
|
t.Parallel()
|
|
op := &oci.PullerMock{}
|
|
op.On("PullLayer", mock.Anything, ociRef, MetadataLayerMediaType, "", "").
|
|
Return(ocispec.Descriptor{}, nil, oci.ErrLayerNotFound)
|
|
m := NewManager(cfg, nil, nil, nil, WithOCIPuller(op))
|
|
|
|
r := &hub.Repository{
|
|
Kind: hub.Helm,
|
|
URL: ociRepoURL,
|
|
}
|
|
md, err := m.GetMetadata(r, "")
|
|
assert.Equal(t, ErrMetadataNotFound, err)
|
|
assert.Nil(t, md)
|
|
op.AssertExpectations(t)
|
|
})
|
|
|
|
t.Run("remote file (oci): success", func(t *testing.T) {
|
|
t.Parallel()
|
|
op := &oci.PullerMock{}
|
|
op.On("PullLayer", mock.Anything, ociRef, MetadataLayerMediaType, "", "").
|
|
Return(ocispec.Descriptor{}, expectedMetadataYaml, nil)
|
|
m := NewManager(cfg, nil, nil, nil, WithOCIPuller(op))
|
|
|
|
r := &hub.Repository{
|
|
Kind: hub.Helm,
|
|
URL: ociRepoURL,
|
|
}
|
|
md, err := m.GetMetadata(r, "")
|
|
assert.Equal(t, expectedMetadata, md)
|
|
assert.NoError(t, err)
|
|
op.AssertExpectations(t)
|
|
})
|
|
|
|
t.Run("remote file (oci - with creds): success", func(t *testing.T) {
|
|
t.Parallel()
|
|
op := &oci.PullerMock{}
|
|
op.On("PullLayer", mock.Anything, ociRef, MetadataLayerMediaType, "user", "pass").
|
|
Return(ocispec.Descriptor{}, expectedMetadataYaml, nil)
|
|
m := NewManager(cfg, nil, nil, nil, WithOCIPuller(op))
|
|
|
|
r := &hub.Repository{
|
|
Kind: hub.Helm,
|
|
URL: ociRepoURL,
|
|
AuthUser: "user",
|
|
AuthPass: "pass",
|
|
}
|
|
md, err := m.GetMetadata(r, "")
|
|
assert.Equal(t, expectedMetadata, md)
|
|
assert.NoError(t, err)
|
|
op.AssertExpectations(t)
|
|
})
|
|
}
|
|
|
|
func TestGetPackagesDigest(t *testing.T) {
|
|
ctx := context.Background()
|
|
|
|
t.Run("invalid input", func(t *testing.T) {
|
|
t.Parallel()
|
|
m := NewManager(cfg, nil, nil, nil)
|
|
_, err := m.GetPackagesDigest(context.Background(), "invalid")
|
|
assert.True(t, errors.Is(err, hub.ErrInvalidInput))
|
|
})
|
|
|
|
t.Run("database query succeeded", func(t *testing.T) {
|
|
t.Parallel()
|
|
db := &tests.DBMock{}
|
|
db.On("QueryRow", ctx, getRepoPkgsDigestDBQ, "00000000-0000-0000-0000-000000000001").Return([]byte(`
|
|
{
|
|
"package1@1.0.0": "digest-package1-1.0.0",
|
|
"package1@0.0.9": "digest-package1-0.0.9",
|
|
"package2@1.0.0": "digest-package2-1.0.0",
|
|
"package2@0.0.9": "digest-package2-0.0.9"
|
|
}
|
|
`), nil)
|
|
m := NewManager(cfg, db, nil, nil)
|
|
|
|
pd, err := m.GetPackagesDigest(ctx, "00000000-0000-0000-0000-000000000001")
|
|
require.NoError(t, err)
|
|
assert.Len(t, pd, 4)
|
|
assert.Equal(t, "digest-package1-1.0.0", pd["package1@1.0.0"])
|
|
assert.Equal(t, "digest-package1-0.0.9", pd["package1@0.0.9"])
|
|
assert.Equal(t, "digest-package2-1.0.0", pd["package2@1.0.0"])
|
|
assert.Equal(t, "digest-package2-0.0.9", pd["package2@0.0.9"])
|
|
db.AssertExpectations(t)
|
|
})
|
|
}
|
|
|
|
func TestGetRemoteDigest(t *testing.T) {
|
|
ctx := context.Background()
|
|
helmHTTP := &hub.Repository{
|
|
Kind: hub.Helm,
|
|
Name: "repo1",
|
|
URL: "https://myrepo.url",
|
|
}
|
|
helmOCI := &hub.Repository{
|
|
Kind: hub.Helm,
|
|
Name: "repo1",
|
|
URL: "oci://myrepo.url/chart",
|
|
}
|
|
|
|
t.Run("helm-http: error loading index", func(t *testing.T) {
|
|
t.Parallel()
|
|
l := &HelmIndexLoaderMock{}
|
|
l.On("LoadIndex", helmHTTP).Return(nil, "", tests.ErrFake)
|
|
m := NewManager(cfg, nil, nil, nil, WithHelmIndexLoader(l))
|
|
|
|
digest, err := m.GetRemoteDigest(ctx, helmHTTP)
|
|
assert.Empty(t, digest)
|
|
assert.Equal(t, tests.ErrFake, err)
|
|
l.AssertExpectations(t)
|
|
})
|
|
|
|
t.Run("helm-http: success", func(t *testing.T) {
|
|
t.Parallel()
|
|
l := &HelmIndexLoaderMock{}
|
|
l.On("LoadIndex", helmHTTP).Return(nil, "digest", nil)
|
|
m := NewManager(cfg, nil, nil, nil, WithHelmIndexLoader(l))
|
|
|
|
digest, err := m.GetRemoteDigest(ctx, helmHTTP)
|
|
assert.Equal(t, "digest", digest)
|
|
assert.Nil(t, err)
|
|
l.AssertExpectations(t)
|
|
})
|
|
|
|
t.Run("helm-oci: error getting tags", func(t *testing.T) {
|
|
t.Parallel()
|
|
tg := &oci.TagsGetterMock{}
|
|
tg.On("Tags", ctx, helmOCI, true).Return(nil, tests.ErrFake)
|
|
m := NewManager(cfg, nil, nil, nil, WithOCITagsGetter(tg))
|
|
|
|
digest, err := m.GetRemoteDigest(ctx, helmOCI)
|
|
assert.Empty(t, digest)
|
|
assert.Equal(t, tests.ErrFake, err)
|
|
tg.AssertExpectations(t)
|
|
})
|
|
|
|
t.Run("helm-oci: success", func(t *testing.T) {
|
|
t.Parallel()
|
|
tg := &oci.TagsGetterMock{}
|
|
tg.On("Tags", ctx, helmOCI, true).Return([]string{"2.0.0", "1.0.0"}, nil)
|
|
m := NewManager(cfg, nil, nil, nil, WithOCITagsGetter(tg))
|
|
|
|
digest, err := m.GetRemoteDigest(ctx, helmOCI)
|
|
assert.Equal(t, "32b4478532e3fbd46940cfaa0b288bc328817cec9ef38e81c9d19a803bcff285", digest)
|
|
assert.Nil(t, err)
|
|
tg.AssertExpectations(t)
|
|
})
|
|
}
|
|
|
|
func TestSearch(t *testing.T) {
|
|
t.Parallel()
|
|
ctx := context.Background()
|
|
input := &hub.SearchRepositoryInput{}
|
|
|
|
t.Run("invalid input", func(t *testing.T) {
|
|
testCases := []struct {
|
|
errMsg string
|
|
input *hub.SearchRepositoryInput
|
|
}{
|
|
{
|
|
"invalid user alias",
|
|
&hub.SearchRepositoryInput{
|
|
Users: []string{""},
|
|
},
|
|
},
|
|
{
|
|
"invalid organization name",
|
|
&hub.SearchRepositoryInput{
|
|
Orgs: []string{""},
|
|
},
|
|
},
|
|
}
|
|
for _, tc := range testCases {
|
|
t.Run(tc.errMsg, func(t *testing.T) {
|
|
t.Parallel()
|
|
m := NewManager(cfg, nil, nil, nil)
|
|
result, err := m.Search(ctx, tc.input)
|
|
assert.True(t, errors.Is(err, hub.ErrInvalidInput))
|
|
assert.Contains(t, err.Error(), tc.errMsg)
|
|
assert.Nil(t, result)
|
|
})
|
|
}
|
|
})
|
|
|
|
t.Run("database query succeeded", func(t *testing.T) {
|
|
db := &tests.DBMock{}
|
|
db.On("QueryRow", ctx, searchRepositoriesDBQ, mock.Anything).Return([]interface{}{[]byte(`
|
|
[
|
|
{
|
|
"repository_id": "00000000-0000-0000-0000-000000000001",
|
|
"name": "repo1",
|
|
"display_name": "Repo 1",
|
|
"url": "https://repo1.com",
|
|
"kind": 0,
|
|
"verified_publisher": true,
|
|
"official": true
|
|
},
|
|
{
|
|
"repository_id": "00000000-0000-0000-0000-000000000002",
|
|
"name": "repo2",
|
|
"display_name": "Repo 2",
|
|
"url": "https://repo2.com",
|
|
"kind": 0,
|
|
"verified_publisher": true,
|
|
"official": true
|
|
},
|
|
{
|
|
"repository_id": "00000000-0000-0000-0000-000000000003",
|
|
"name": "repo3",
|
|
"display_name": "Repo 3",
|
|
"url": "https://repo3.com",
|
|
"kind": 1,
|
|
"verified_publisher": true,
|
|
"official": true
|
|
}
|
|
]
|
|
`), 3}, nil)
|
|
m := NewManager(cfg, db, nil, nil)
|
|
|
|
result, err := m.Search(ctx, input)
|
|
r := result.Repositories
|
|
|
|
require.NoError(t, err)
|
|
assert.Equal(t, 3, result.TotalCount)
|
|
assert.Len(t, r, 3)
|
|
assert.Equal(t, "00000000-0000-0000-0000-000000000001", r[0].RepositoryID)
|
|
assert.Equal(t, "repo1", r[0].Name)
|
|
assert.Equal(t, "Repo 1", r[0].DisplayName)
|
|
assert.Equal(t, "https://repo1.com", r[0].URL)
|
|
assert.Equal(t, hub.Helm, r[0].Kind)
|
|
assert.True(t, r[0].VerifiedPublisher)
|
|
assert.True(t, r[0].Official)
|
|
assert.Equal(t, "00000000-0000-0000-0000-000000000002", r[1].RepositoryID)
|
|
assert.Equal(t, "repo2", r[1].Name)
|
|
assert.Equal(t, "Repo 2", r[1].DisplayName)
|
|
assert.Equal(t, "https://repo2.com", r[1].URL)
|
|
assert.Equal(t, hub.Helm, r[1].Kind)
|
|
assert.True(t, r[1].VerifiedPublisher)
|
|
assert.True(t, r[1].Official)
|
|
assert.Equal(t, "00000000-0000-0000-0000-000000000003", r[2].RepositoryID)
|
|
assert.Equal(t, "repo3", r[2].Name)
|
|
assert.Equal(t, "Repo 3", r[2].DisplayName)
|
|
assert.Equal(t, "https://repo3.com", r[2].URL)
|
|
assert.Equal(t, hub.Falco, r[2].Kind)
|
|
assert.True(t, r[2].VerifiedPublisher)
|
|
assert.True(t, r[2].Official)
|
|
db.AssertExpectations(t)
|
|
})
|
|
|
|
t.Run("database error", func(t *testing.T) {
|
|
t.Parallel()
|
|
db := &tests.DBMock{}
|
|
db.On("QueryRow", ctx, searchRepositoriesDBQ, mock.Anything).Return(nil, tests.ErrFakeDB)
|
|
m := NewManager(cfg, db, nil, nil)
|
|
|
|
result, err := m.Search(ctx, input)
|
|
assert.Equal(t, tests.ErrFakeDB, err)
|
|
assert.Nil(t, result)
|
|
db.AssertExpectations(t)
|
|
})
|
|
}
|
|
|
|
func TestSearchJSON(t *testing.T) {
|
|
ctx := context.Background()
|
|
input := &hub.SearchRepositoryInput{}
|
|
|
|
t.Run("invalid input", func(t *testing.T) {
|
|
testCases := []struct {
|
|
errMsg string
|
|
input *hub.SearchRepositoryInput
|
|
}{
|
|
{
|
|
"invalid user alias",
|
|
&hub.SearchRepositoryInput{
|
|
Users: []string{""},
|
|
},
|
|
},
|
|
{
|
|
"invalid organization name",
|
|
&hub.SearchRepositoryInput{
|
|
Orgs: []string{""},
|
|
},
|
|
},
|
|
}
|
|
for _, tc := range testCases {
|
|
t.Run(tc.errMsg, func(t *testing.T) {
|
|
t.Parallel()
|
|
m := NewManager(cfg, nil, nil, nil)
|
|
result, err := m.SearchJSON(ctx, tc.input)
|
|
assert.True(t, errors.Is(err, hub.ErrInvalidInput))
|
|
assert.Contains(t, err.Error(), tc.errMsg)
|
|
assert.Nil(t, result)
|
|
})
|
|
}
|
|
})
|
|
|
|
t.Run("database query succeeded", func(t *testing.T) {
|
|
t.Parallel()
|
|
db := &tests.DBMock{}
|
|
db.On("QueryRow", ctx, searchRepositoriesDBQ, mock.Anything).
|
|
Return([]interface{}{[]byte("dataJSON"), 1}, nil)
|
|
m := NewManager(cfg, db, nil, nil)
|
|
|
|
result, err := m.SearchJSON(ctx, input)
|
|
assert.NoError(t, err)
|
|
assert.Equal(t, []byte("dataJSON"), result.Data)
|
|
assert.Equal(t, 1, result.TotalCount)
|
|
db.AssertExpectations(t)
|
|
})
|
|
|
|
t.Run("database error", func(t *testing.T) {
|
|
t.Parallel()
|
|
db := &tests.DBMock{}
|
|
db.On("QueryRow", ctx, searchRepositoriesDBQ, mock.Anything).Return(nil, tests.ErrFakeDB)
|
|
m := NewManager(cfg, db, nil, nil)
|
|
|
|
result, err := m.SearchJSON(ctx, input)
|
|
assert.Equal(t, tests.ErrFakeDB, err)
|
|
assert.Nil(t, result)
|
|
db.AssertExpectations(t)
|
|
})
|
|
}
|
|
|
|
func TestSetLastScanningResults(t *testing.T) {
|
|
ctx := context.Background()
|
|
|
|
t.Run("invalid input", func(t *testing.T) {
|
|
t.Parallel()
|
|
m := NewManager(cfg, nil, nil, nil)
|
|
err := m.SetLastScanningResults(ctx, "invalid", "errors")
|
|
assert.True(t, errors.Is(err, hub.ErrInvalidInput))
|
|
})
|
|
|
|
t.Run("database update succeeded", func(t *testing.T) {
|
|
t.Parallel()
|
|
db := &tests.DBMock{}
|
|
db.On("Exec", ctx, setLastScanningResultsDBQ, repoID, "errors", false).Return(nil)
|
|
m := NewManager(cfg, db, nil, nil)
|
|
|
|
err := m.SetLastScanningResults(ctx, repoID, "errors")
|
|
assert.NoError(t, err)
|
|
db.AssertExpectations(t)
|
|
})
|
|
|
|
t.Run("database error", func(t *testing.T) {
|
|
t.Parallel()
|
|
db := &tests.DBMock{}
|
|
db.On("Exec", ctx, setLastScanningResultsDBQ, repoID, "errors", false).Return(tests.ErrFakeDB)
|
|
m := NewManager(cfg, db, nil, nil)
|
|
|
|
err := m.SetLastScanningResults(ctx, repoID, "errors")
|
|
assert.Equal(t, tests.ErrFakeDB, err)
|
|
db.AssertExpectations(t)
|
|
})
|
|
}
|
|
|
|
func TestSetLastTrackingResults(t *testing.T) {
|
|
ctx := context.Background()
|
|
|
|
t.Run("invalid input", func(t *testing.T) {
|
|
t.Parallel()
|
|
m := NewManager(cfg, nil, nil, nil)
|
|
err := m.SetLastTrackingResults(ctx, "invalid", "errors")
|
|
assert.True(t, errors.Is(err, hub.ErrInvalidInput))
|
|
})
|
|
|
|
t.Run("database update succeeded", func(t *testing.T) {
|
|
t.Parallel()
|
|
db := &tests.DBMock{}
|
|
db.On("Exec", ctx, setLastTrackingResultsDBQ, repoID, "errors", false).Return(nil)
|
|
m := NewManager(cfg, db, nil, nil)
|
|
|
|
err := m.SetLastTrackingResults(ctx, repoID, "errors")
|
|
assert.NoError(t, err)
|
|
db.AssertExpectations(t)
|
|
})
|
|
|
|
t.Run("database error", func(t *testing.T) {
|
|
t.Parallel()
|
|
db := &tests.DBMock{}
|
|
db.On("Exec", ctx, setLastTrackingResultsDBQ, repoID, "errors", false).Return(tests.ErrFakeDB)
|
|
m := NewManager(cfg, db, nil, nil)
|
|
|
|
err := m.SetLastTrackingResults(ctx, repoID, "errors")
|
|
assert.Equal(t, tests.ErrFakeDB, err)
|
|
db.AssertExpectations(t)
|
|
})
|
|
}
|
|
|
|
func TestSetVerifiedPublisher(t *testing.T) {
|
|
ctx := context.Background()
|
|
|
|
t.Run("invalid input", func(t *testing.T) {
|
|
t.Parallel()
|
|
m := NewManager(cfg, nil, nil, nil)
|
|
err := m.SetVerifiedPublisher(ctx, "invalid", true)
|
|
assert.True(t, errors.Is(err, hub.ErrInvalidInput))
|
|
})
|
|
|
|
t.Run("database update succeeded", func(t *testing.T) {
|
|
t.Parallel()
|
|
db := &tests.DBMock{}
|
|
db.On("Exec", ctx, setVerifiedPublisherDBQ, repoID, true).Return(nil)
|
|
m := NewManager(cfg, db, nil, nil)
|
|
|
|
err := m.SetVerifiedPublisher(ctx, repoID, true)
|
|
assert.NoError(t, err)
|
|
db.AssertExpectations(t)
|
|
})
|
|
|
|
t.Run("database error", func(t *testing.T) {
|
|
t.Parallel()
|
|
db := &tests.DBMock{}
|
|
db.On("Exec", ctx, setVerifiedPublisherDBQ, repoID, true).Return(tests.ErrFakeDB)
|
|
m := NewManager(cfg, db, nil, nil)
|
|
|
|
err := m.SetVerifiedPublisher(ctx, repoID, true)
|
|
assert.Equal(t, tests.ErrFakeDB, err)
|
|
db.AssertExpectations(t)
|
|
})
|
|
}
|
|
|
|
func TestTransfer(t *testing.T) {
|
|
ctx := context.WithValue(context.Background(), hub.UserIDKey, "userID")
|
|
userID := "userID"
|
|
userIDP := &userID
|
|
org := "org1"
|
|
orgP := &org
|
|
|
|
t.Run("user id not found in ctx", func(t *testing.T) {
|
|
t.Parallel()
|
|
m := NewManager(cfg, nil, nil, nil)
|
|
assert.Panics(t, func() {
|
|
_ = m.Transfer(context.Background(), "repo1", "", false)
|
|
})
|
|
})
|
|
|
|
t.Run("invalid input", func(t *testing.T) {
|
|
testCases := []struct {
|
|
errMsg string
|
|
repoName string
|
|
}{
|
|
{
|
|
"repository name not provided",
|
|
"",
|
|
},
|
|
}
|
|
for _, tc := range testCases {
|
|
t.Run(tc.errMsg, func(t *testing.T) {
|
|
t.Parallel()
|
|
m := NewManager(cfg, nil, nil, nil)
|
|
|
|
err := m.Transfer(ctx, tc.repoName, "", false)
|
|
assert.True(t, errors.Is(err, hub.ErrInvalidInput))
|
|
})
|
|
}
|
|
})
|
|
|
|
t.Run("authorization failed", func(t *testing.T) {
|
|
t.Parallel()
|
|
db := &tests.DBMock{}
|
|
db.On("QueryRow", ctx, getRepoByNameDBQ, "repo1", false).Return([]byte(`
|
|
{
|
|
"repository_id": "00000000-0000-0000-0000-000000000001",
|
|
"name": "repo1",
|
|
"organization_name": "orgName"
|
|
}
|
|
`), nil)
|
|
az := &authz.AuthorizerMock{}
|
|
az.On("Authorize", ctx, &hub.AuthorizeInput{
|
|
OrganizationName: "orgName",
|
|
UserID: "userID",
|
|
Action: hub.TransferOrganizationRepository,
|
|
}).Return(tests.ErrFake)
|
|
m := NewManager(cfg, db, az, nil)
|
|
|
|
err := m.Transfer(ctx, "repo1", "orgDest", false)
|
|
assert.Equal(t, tests.ErrFake, err)
|
|
db.AssertExpectations(t)
|
|
az.AssertExpectations(t)
|
|
})
|
|
|
|
t.Run("database error", func(t *testing.T) {
|
|
testCases := []struct {
|
|
dbErr error
|
|
expectedError error
|
|
}{
|
|
{
|
|
tests.ErrFakeDB,
|
|
tests.ErrFakeDB,
|
|
},
|
|
{
|
|
util.ErrDBInsufficientPrivilege,
|
|
hub.ErrInsufficientPrivilege,
|
|
},
|
|
}
|
|
for _, tc := range testCases {
|
|
t.Run(tc.dbErr.Error(), func(t *testing.T) {
|
|
t.Parallel()
|
|
db := &tests.DBMock{}
|
|
db.On("QueryRow", ctx, getRepoByNameDBQ, "repo1", false).Return([]byte(`
|
|
{
|
|
"repository_id": "00000000-0000-0000-0000-000000000001",
|
|
"name": "repo1",
|
|
"organization_name": "orgName"
|
|
}
|
|
`), nil)
|
|
db.On("Exec", ctx, transferRepoDBQ, "repo1", userIDP, orgP, false).Return(tc.dbErr)
|
|
az := &authz.AuthorizerMock{}
|
|
az.On("Authorize", ctx, &hub.AuthorizeInput{
|
|
OrganizationName: "orgName",
|
|
UserID: "userID",
|
|
Action: hub.TransferOrganizationRepository,
|
|
}).Return(nil)
|
|
m := NewManager(cfg, db, az, nil)
|
|
|
|
err := m.Transfer(ctx, "repo1", org, false)
|
|
assert.Equal(t, tc.expectedError, err)
|
|
db.AssertExpectations(t)
|
|
az.AssertExpectations(t)
|
|
})
|
|
}
|
|
})
|
|
|
|
t.Run("transfer repository succeeded", func(t *testing.T) {
|
|
t.Parallel()
|
|
db := &tests.DBMock{}
|
|
db.On("QueryRow", ctx, getRepoByNameDBQ, "repo1", false).Return([]byte(`
|
|
{
|
|
"repository_id": "00000000-0000-0000-0000-000000000001",
|
|
"name": "repo1",
|
|
"user_alias": "user1"
|
|
}
|
|
`), nil)
|
|
db.On("Exec", ctx, transferRepoDBQ, "repo1", userIDP, orgP, false).Return(nil)
|
|
m := NewManager(cfg, db, nil, nil)
|
|
|
|
err := m.Transfer(ctx, "repo1", org, false)
|
|
assert.NoError(t, err)
|
|
db.AssertExpectations(t)
|
|
})
|
|
}
|
|
|
|
func TestUpdate(t *testing.T) {
|
|
ctx := context.WithValue(context.Background(), hub.UserIDKey, "userID")
|
|
|
|
t.Run("user id not found in ctx", func(t *testing.T) {
|
|
t.Parallel()
|
|
m := NewManager(cfg, nil, nil, nil)
|
|
assert.Panics(t, func() {
|
|
_ = m.Update(context.Background(), nil)
|
|
})
|
|
})
|
|
|
|
t.Run("invalid input", func(t *testing.T) {
|
|
testCases := []struct {
|
|
errMsg string
|
|
r *hub.Repository
|
|
lErr error
|
|
}{
|
|
{
|
|
"name not provided",
|
|
&hub.Repository{
|
|
Name: "",
|
|
},
|
|
nil,
|
|
},
|
|
{
|
|
"url not provided",
|
|
&hub.Repository{
|
|
Name: "repo1",
|
|
URL: "",
|
|
},
|
|
nil,
|
|
},
|
|
{
|
|
"missing protocol scheme",
|
|
&hub.Repository{
|
|
Kind: hub.Helm,
|
|
Name: "repo1",
|
|
URL: ":::///",
|
|
},
|
|
nil,
|
|
},
|
|
{
|
|
"scheme not supported",
|
|
&hub.Repository{
|
|
Kind: hub.Helm,
|
|
Name: "repo1",
|
|
URL: "other://repo1.com",
|
|
},
|
|
nil,
|
|
},
|
|
{
|
|
"urls with credentials not allowed",
|
|
&hub.Repository{
|
|
Kind: hub.Helm,
|
|
Name: "repo1",
|
|
URL: "https://user:pass@repo1.com",
|
|
},
|
|
nil,
|
|
},
|
|
{
|
|
"invalid url format",
|
|
&hub.Repository{
|
|
Kind: hub.OLM,
|
|
Name: "repo1",
|
|
URL: "https://repo1.com",
|
|
},
|
|
nil,
|
|
},
|
|
{
|
|
"invalid url format",
|
|
&hub.Repository{
|
|
Kind: hub.Container,
|
|
Name: "repo1",
|
|
URL: "https://repo1.url",
|
|
},
|
|
nil,
|
|
},
|
|
{
|
|
"the url provided does not point to a valid Helm repository",
|
|
&hub.Repository{
|
|
Name: "repo1",
|
|
URL: "https://repo1.com",
|
|
Kind: hub.Helm,
|
|
},
|
|
errors.New("error loading index file"),
|
|
},
|
|
{
|
|
"private repositories not allowed",
|
|
&hub.Repository{
|
|
Kind: hub.Helm,
|
|
Name: "repo1",
|
|
URL: "https://repo1.com",
|
|
AuthUser: "user1",
|
|
AuthPass: "pass1",
|
|
},
|
|
nil,
|
|
},
|
|
{
|
|
"invalid container image data",
|
|
&hub.Repository{
|
|
Kind: hub.Container,
|
|
Name: "repo1",
|
|
URL: "oci://registry.io/namespace/repo",
|
|
Data: json.RawMessage("{["),
|
|
},
|
|
nil,
|
|
},
|
|
{
|
|
"too many tags",
|
|
&hub.Repository{
|
|
Kind: hub.Container,
|
|
Name: "repo1",
|
|
URL: "oci://registry.io/namespace/repo",
|
|
Data: json.RawMessage(`{
|
|
"tags": [
|
|
{"name": "tag1"},
|
|
{"name": "tag2"},
|
|
{"name": "tag3"},
|
|
{"name": "tag4"},
|
|
{"name": "tag5"},
|
|
{"name": "tag6"},
|
|
{"name": "tag7"},
|
|
{"name": "tag8"},
|
|
{"name": "tag9"},
|
|
{"name": "tag10"},
|
|
{"name": "tag11"}
|
|
]
|
|
}`),
|
|
},
|
|
nil,
|
|
},
|
|
}
|
|
for _, tc := range testCases {
|
|
t.Run(tc.errMsg, func(t *testing.T) {
|
|
t.Parallel()
|
|
l := &HelmIndexLoaderMock{}
|
|
if tc.lErr != nil {
|
|
l.On("LoadIndex", tc.r).Return(nil, "", tc.lErr)
|
|
} else {
|
|
l.On("LoadIndex", tc.r).Return(nil, "", nil).Maybe()
|
|
}
|
|
m := NewManager(cfg, nil, nil, nil, WithHelmIndexLoader(l))
|
|
|
|
err := m.Update(ctx, tc.r)
|
|
assert.True(t, errors.Is(err, hub.ErrInvalidInput))
|
|
assert.Contains(t, err.Error(), tc.errMsg)
|
|
l.AssertExpectations(t)
|
|
})
|
|
}
|
|
})
|
|
|
|
t.Run("authorization failed", func(t *testing.T) {
|
|
t.Parallel()
|
|
r := &hub.Repository{
|
|
Name: "repo1",
|
|
DisplayName: "Repository 1",
|
|
URL: "https://repo1.com",
|
|
Kind: hub.Helm,
|
|
}
|
|
db := &tests.DBMock{}
|
|
db.On("QueryRow", ctx, getRepoByNameDBQ, "repo1", false).Return([]byte(`
|
|
{
|
|
"repository_id": "00000000-0000-0000-0000-000000000001",
|
|
"name": "repo1",
|
|
"organization_name": "orgName"
|
|
}
|
|
`), nil)
|
|
az := &authz.AuthorizerMock{}
|
|
az.On("Authorize", ctx, &hub.AuthorizeInput{
|
|
OrganizationName: "orgName",
|
|
UserID: "userID",
|
|
Action: hub.UpdateOrganizationRepository,
|
|
}).Return(tests.ErrFake)
|
|
l := &HelmIndexLoaderMock{}
|
|
l.On("LoadIndex", r).Return(nil, "", nil)
|
|
m := NewManager(cfg, db, az, nil, WithHelmIndexLoader(l))
|
|
|
|
err := m.Update(ctx, r)
|
|
assert.Equal(t, tests.ErrFake, err)
|
|
db.AssertExpectations(t)
|
|
az.AssertExpectations(t)
|
|
l.AssertExpectations(t)
|
|
})
|
|
|
|
t.Run("database error", func(t *testing.T) {
|
|
testCases := []struct {
|
|
r *hub.Repository
|
|
dbErr error
|
|
expectedError error
|
|
}{
|
|
{
|
|
&hub.Repository{
|
|
Name: "repo1",
|
|
DisplayName: "Repository 1",
|
|
URL: "https://repo1.com",
|
|
Kind: hub.Helm,
|
|
},
|
|
tests.ErrFakeDB,
|
|
tests.ErrFakeDB,
|
|
},
|
|
{
|
|
&hub.Repository{
|
|
Name: "repo1",
|
|
DisplayName: "Repository 1",
|
|
URL: "https://repo1.com",
|
|
Kind: hub.Helm,
|
|
},
|
|
util.ErrDBInsufficientPrivilege,
|
|
hub.ErrInsufficientPrivilege,
|
|
},
|
|
}
|
|
for _, tc := range testCases {
|
|
t.Run(tc.dbErr.Error(), func(t *testing.T) {
|
|
t.Parallel()
|
|
db := &tests.DBMock{}
|
|
db.On("QueryRow", ctx, getRepoByNameDBQ, "repo1", false).Return([]byte(`
|
|
{
|
|
"repository_id": "00000000-0000-0000-0000-000000000001",
|
|
"name": "repo1",
|
|
"organization_name": "orgName"
|
|
}
|
|
`), nil)
|
|
db.On("Exec", ctx, updateRepoDBQ, "userID", mock.Anything).Return(tc.dbErr)
|
|
az := &authz.AuthorizerMock{}
|
|
az.On("Authorize", ctx, &hub.AuthorizeInput{
|
|
OrganizationName: "orgName",
|
|
UserID: "userID",
|
|
Action: hub.UpdateOrganizationRepository,
|
|
}).Return(nil)
|
|
|
|
l := &HelmIndexLoaderMock{}
|
|
l.On("LoadIndex", tc.r).Return(nil, "", nil)
|
|
m := NewManager(cfg, db, az, nil, WithHelmIndexLoader(l))
|
|
|
|
err := m.Update(ctx, tc.r)
|
|
assert.Equal(t, tc.expectedError, err)
|
|
db.AssertExpectations(t)
|
|
az.AssertExpectations(t)
|
|
l.AssertExpectations(t)
|
|
})
|
|
}
|
|
})
|
|
|
|
t.Run("update repository succeeded", func(t *testing.T) {
|
|
testCases := []struct {
|
|
r *hub.Repository
|
|
}{
|
|
{
|
|
&hub.Repository{
|
|
Name: "repo1",
|
|
DisplayName: "Repository 1",
|
|
URL: "https://repo1.com",
|
|
Kind: hub.Helm,
|
|
},
|
|
},
|
|
{
|
|
&hub.Repository{
|
|
Name: "repo2",
|
|
DisplayName: "Repository 2",
|
|
URL: "https://github.com/org2/repo2/path",
|
|
Kind: hub.OLM,
|
|
},
|
|
},
|
|
}
|
|
for i, tc := range testCases {
|
|
t.Run(strconv.Itoa(i), func(t *testing.T) {
|
|
t.Parallel()
|
|
repoJSON, _ := json.Marshal(tc.r)
|
|
db := &tests.DBMock{}
|
|
db.On("QueryRow", ctx, getRepoByNameDBQ, tc.r.Name, false).Return(repoJSON, nil)
|
|
db.On("Exec", ctx, updateRepoDBQ, "userID", mock.Anything).Return(nil)
|
|
l := &HelmIndexLoaderMock{}
|
|
if tc.r.Kind == hub.Helm {
|
|
l.On("LoadIndex", tc.r).Return(nil, "", nil)
|
|
}
|
|
m := NewManager(cfg, db, nil, nil, WithHelmIndexLoader(l))
|
|
|
|
err := m.Update(ctx, tc.r)
|
|
assert.NoError(t, err)
|
|
db.AssertExpectations(t)
|
|
l.AssertExpectations(t)
|
|
})
|
|
}
|
|
})
|
|
}
|
|
|
|
func TestUpdateDigest(t *testing.T) {
|
|
ctx := context.Background()
|
|
repositoryID := "00000000-0000-0000-0000-000000000001"
|
|
digest := "digest"
|
|
|
|
t.Run("database update succeeded", func(t *testing.T) {
|
|
t.Parallel()
|
|
db := &tests.DBMock{}
|
|
db.On("Exec", ctx, updateRepoDigestDBQ, repositoryID, digest).Return(nil)
|
|
m := NewManager(cfg, db, nil, nil)
|
|
|
|
err := m.UpdateDigest(ctx, repositoryID, digest)
|
|
assert.NoError(t, err)
|
|
db.AssertExpectations(t)
|
|
})
|
|
|
|
t.Run("database error", func(t *testing.T) {
|
|
t.Parallel()
|
|
db := &tests.DBMock{}
|
|
db.On("Exec", ctx, updateRepoDigestDBQ, repositoryID, digest).Return(tests.ErrFakeDB)
|
|
m := NewManager(cfg, db, nil, nil)
|
|
|
|
err := m.UpdateDigest(ctx, repositoryID, digest)
|
|
assert.Equal(t, tests.ErrFakeDB, err)
|
|
db.AssertExpectations(t)
|
|
})
|
|
}
|
|
|
|
func withRepositoryCloner(rc hub.RepositoryCloner) func(m *Manager) {
|
|
return func(m *Manager) {
|
|
m.rc = rc
|
|
}
|
|
}
|