List Catalogs for Repo and API Handler (#288)
This commit is contained in:
1 parent
6bf4a5ce38
commit
7474e956dd
6 files changed
+274
-12
No files matched your search
@@ -1,6 +1,7 @@
|
||||
package hosts_test
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"net/http"
|
||||
"testing"
|
||||
|
||||
@@ -13,6 +14,67 @@ import (
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
|
||||
func TestCatalog_List(t *testing.T) {
|
||||
assert, require := assert.New(t), require.New(t)
|
||||
amId := "paum_1234567890"
|
||||
tc := controller.NewTestController(t, &controller.TestControllerOpts{
|
||||
DisableAuthorizationFailures: true,
|
||||
DefaultAuthMethodId: amId,
|
||||
DefaultLoginName: "user",
|
||||
DefaultPassword: "passpass",
|
||||
})
|
||||
defer tc.Shutdown()
|
||||
|
||||
client := tc.Client()
|
||||
_, proj := iam.TestScopes(t, tc.IamRepo())
|
||||
client.SetScopeId(proj.GetPublicId())
|
||||
catalogClient := hosts.NewHostCatalogsClient(client)
|
||||
|
||||
ul, apiErr, err := catalogClient.List(tc.Context())
|
||||
assert.NoError(err)
|
||||
assert.Nil(apiErr)
|
||||
assert.Empty(ul)
|
||||
|
||||
var expected []*hosts.HostCatalog
|
||||
for i := 0; i < 10; i++ {
|
||||
expected = append(expected, &hosts.HostCatalog{Name: fmt.Sprint(i)})
|
||||
}
|
||||
|
||||
expected[0], apiErr, err = catalogClient.Create(tc.Context(), "static", hosts.WithName(expected[0].Name))
|
||||
assert.NoError(err)
|
||||
assert.Nil(apiErr)
|
||||
|
||||
ul, apiErr, err = catalogClient.List(tc.Context())
|
||||
assert.NoError(err)
|
||||
assert.Nil(apiErr)
|
||||
assert.ElementsMatch(comparableSlice(expected[:1]), comparableSlice(ul))
|
||||
|
||||
for i := 1; i < 10; i++ {
|
||||
expected[i], apiErr, err = catalogClient.Create(tc.Context(), "static", hosts.WithName(expected[i].Name))
|
||||
assert.NoError(err)
|
||||
assert.Nil(apiErr)
|
||||
}
|
||||
ul, apiErr, err = catalogClient.List(tc.Context())
|
||||
require.NoError(err)
|
||||
assert.Nil(apiErr)
|
||||
assert.ElementsMatch(comparableSlice(expected), comparableSlice(ul))
|
||||
}
|
||||
|
||||
func comparableSlice(in []*hosts.HostCatalog) []hosts.HostCatalog {
|
||||
var filtered []hosts.HostCatalog
|
||||
for _, i := range in {
|
||||
p := hosts.HostCatalog{
|
||||
Id: i.Id,
|
||||
Name: i.Name,
|
||||
Description: i.Description,
|
||||
CreatedTime: i.CreatedTime,
|
||||
UpdatedTime: i.UpdatedTime,
|
||||
}
|
||||
filtered = append(filtered, p)
|
||||
}
|
||||
return filtered
|
||||
}
|
||||
|
||||
func TestCatalogs_Crud(t *testing.T) {
|
||||
assert, require := assert.New(t), require.New(t)
|
||||
amId := "paum_1234567890"
|
||||
|
||||
@@ -179,6 +179,25 @@ func (r *Repository) LookupCatalog(ctx context.Context, id string, opt ...Option
|
||||
return c, nil
|
||||
}
|
||||
|
||||
// ListCatalogs returns a slice of HostCatalogs for the scopeId. WithLimit is the only option supported.
|
||||
func (r *Repository) ListCatalogs(ctx context.Context, scopeId string, opt ...Option) ([]*HostCatalog, error) {
|
||||
if scopeId == "" {
|
||||
return nil, fmt.Errorf("list: static host catalog: missing scope id: %w", db.ErrInvalidParameter)
|
||||
}
|
||||
opts := getOpts(opt...)
|
||||
limit := r.defaultLimit
|
||||
if opts.withLimit != 0 {
|
||||
// non-zero signals an override of the default limit for the repo.
|
||||
limit = opts.withLimit
|
||||
}
|
||||
var hostCatalogs []*HostCatalog
|
||||
err := r.reader.SearchWhere(ctx, &hostCatalogs, "scope_id = ?", []interface{}{scopeId}, db.WithLimit(limit))
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("list: static host catalog: %w", err)
|
||||
}
|
||||
return hostCatalogs, nil
|
||||
}
|
||||
|
||||
// DeleteCatalog deletes id from the repository returning a count of the
|
||||
// number of records deleted.
|
||||
func (r *Repository) DeleteCatalog(ctx context.Context, id string, opt ...Option) (int, error) {
|
||||
|
||||
@@ -0,0 +1,34 @@
|
||||
package static
|
||||
|
||||
import (
|
||||
"context"
|
||||
"testing"
|
||||
|
||||
"github.com/hashicorp/boundary/internal/db"
|
||||
"github.com/jinzhu/gorm"
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
// TestCatalogs creates count number of static host catalogs to the provided DB
|
||||
// with the provided scope id. If any errors are encountered during the creation of
|
||||
// the host catalog, the test will fail.
|
||||
func TestCatalogs(t *testing.T, conn *gorm.DB, scopeId string, count int) []*HostCatalog {
|
||||
t.Helper()
|
||||
assert := assert.New(t)
|
||||
var cats []*HostCatalog
|
||||
for i := 0; i < count; i++ {
|
||||
cat, err := NewHostCatalog(scopeId)
|
||||
assert.NoError(err)
|
||||
assert.NotNil(cat)
|
||||
id, err := newHostCatalogId()
|
||||
assert.NoError(err)
|
||||
assert.NotEmpty(id)
|
||||
cat.PublicId = id
|
||||
|
||||
w := db.New(conn)
|
||||
err2 := w.Create(context.Background(), cat)
|
||||
assert.NoError(err2)
|
||||
cats = append(cats, cat)
|
||||
}
|
||||
return cats
|
||||
}
|
||||
@@ -0,0 +1,26 @@
|
||||
package static
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/hashicorp/boundary/internal/db"
|
||||
"github.com/hashicorp/boundary/internal/iam"
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
|
||||
func Test_TestCatalogs(t *testing.T) {
|
||||
assert, require := assert.New(t), require.New(t)
|
||||
conn, _ := db.TestSetup(t, "postgres")
|
||||
wrapper := db.TestWrapper(t)
|
||||
_, proj := iam.TestScopes(t, iam.TestRepo(t, conn, wrapper))
|
||||
require.NotNil(proj)
|
||||
assert.NotEmpty(proj.GetPublicId())
|
||||
|
||||
count := 4
|
||||
cs := TestCatalogs(t, conn, proj.GetPublicId(), count)
|
||||
assert.Len(cs, count)
|
||||
for _, c := range cs {
|
||||
assert.NotEmpty(c.GetPublicId())
|
||||
}
|
||||
}
|
||||
@@ -47,7 +47,21 @@ func NewService(repoFn common.StaticRepoFactory) (Service, error) {
|
||||
}
|
||||
|
||||
func (s Service) ListHostCatalogs(ctx context.Context, req *pbs.ListHostCatalogsRequest) (*pbs.ListHostCatalogsResponse, error) {
|
||||
return nil, status.Error(codes.Unimplemented, "Requested method is unimplemented for Host Catalogs.")
|
||||
authResults := auth.Verify(ctx)
|
||||
if authResults.Error != nil {
|
||||
return nil, authResults.Error
|
||||
}
|
||||
if err := validateListRequest(req); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
ul, err := s.listFromRepo(ctx, authResults.Scope.GetId())
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
for _, item := range ul {
|
||||
item.Scope = authResults.Scope
|
||||
}
|
||||
return &pbs.ListHostCatalogsResponse{Items: ul}, nil
|
||||
}
|
||||
|
||||
// GetHostCatalog implements the interface pbs.HostCatalogServiceServer.
|
||||
@@ -135,6 +149,22 @@ func (s Service) getFromRepo(ctx context.Context, id string) (*pb.HostCatalog, e
|
||||
return toProto(hc), nil
|
||||
}
|
||||
|
||||
func (s Service) listFromRepo(ctx context.Context, scopeId string) ([]*pb.HostCatalog, error) {
|
||||
repo, err := s.staticRepoFn()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
ul, err := repo.ListCatalogs(ctx, scopeId)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
var outUl []*pb.HostCatalog
|
||||
for _, u := range ul {
|
||||
outUl = append(outUl, toProto(u))
|
||||
}
|
||||
return outUl, nil
|
||||
}
|
||||
|
||||
func (s Service) createInRepo(ctx context.Context, projId string, item *pb.HostCatalog) (*pb.HostCatalog, error) {
|
||||
var opts []static.Option
|
||||
if item.GetName() != nil {
|
||||
@@ -240,6 +270,14 @@ func validateGetRequest(req *pbs.GetHostCatalogRequest) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func validateListRequest(req *pbs.ListHostCatalogsRequest) error {
|
||||
badFields := map[string]string{}
|
||||
if len(badFields) > 0 {
|
||||
return handlers.InvalidArgumentErrorf("Improperly formatted identifier.", badFields)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func validateCreateRequest(req *pbs.CreateHostCatalogRequest) error {
|
||||
badFields := map[string]string{}
|
||||
item := req.GetItem()
|
||||
|
||||
@@ -12,7 +12,7 @@ import (
|
||||
"github.com/hashicorp/boundary/internal/auth"
|
||||
"github.com/hashicorp/boundary/internal/db"
|
||||
pb "github.com/hashicorp/boundary/internal/gen/controller/api/resources/hosts"
|
||||
"github.com/hashicorp/boundary/internal/gen/controller/api/resources/scopes"
|
||||
scopepb "github.com/hashicorp/boundary/internal/gen/controller/api/resources/scopes"
|
||||
pbs "github.com/hashicorp/boundary/internal/gen/controller/api/services"
|
||||
"github.com/hashicorp/boundary/internal/host/static"
|
||||
"github.com/hashicorp/boundary/internal/iam"
|
||||
@@ -62,7 +62,7 @@ func TestGet(t *testing.T) {
|
||||
|
||||
pHostCatalog := &pb.HostCatalog{
|
||||
Id: hc.GetPublicId(),
|
||||
Scope: &scopes.ScopeInfo{Id: proj.GetPublicId(), Type: scope.Project.String()},
|
||||
Scope: &scopepb.ScopeInfo{Id: proj.GetPublicId(), Type: scope.Project.String()},
|
||||
Name: &wrappers.StringValue{Value: hc.GetName()},
|
||||
Description: &wrappers.StringValue{Value: hc.GetDescription()},
|
||||
CreatedTime: hc.CreateTime.GetTimestamp(),
|
||||
@@ -121,6 +121,89 @@ func TestGet(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func TestList(t *testing.T) {
|
||||
conn, _ := db.TestSetup(t, "postgres")
|
||||
rw := db.New(conn)
|
||||
wrapper := db.TestWrapper(t)
|
||||
kms := kms.TestKms(t, conn, wrapper)
|
||||
repoFn := func() (*static.Repository, error) {
|
||||
return static.NewRepository(rw, rw, kms)
|
||||
}
|
||||
iamRepo := iam.TestRepo(t, conn, wrapper)
|
||||
|
||||
_, pNoCatalogs := iam.TestScopes(t, iamRepo)
|
||||
_, pWithCatalogs := iam.TestScopes(t, iamRepo)
|
||||
_, pWithOtherCatalogs := iam.TestScopes(t, iamRepo)
|
||||
|
||||
var wantSomeCatalogs []*pb.HostCatalog
|
||||
for _, hc := range static.TestCatalogs(t, conn, pWithCatalogs.GetPublicId(), 3) {
|
||||
wantSomeCatalogs = append(wantSomeCatalogs, &pb.HostCatalog{
|
||||
Id: hc.GetPublicId(),
|
||||
CreatedTime: hc.GetCreateTime().GetTimestamp(),
|
||||
UpdatedTime: hc.GetUpdateTime().GetTimestamp(),
|
||||
Scope: &scopepb.ScopeInfo{Id: pWithCatalogs.GetPublicId(), Type: scope.Project.String()},
|
||||
Version: 1,
|
||||
Type: "static",
|
||||
})
|
||||
}
|
||||
|
||||
var wantOtherCatalogs []*pb.HostCatalog
|
||||
for _, hc := range static.TestCatalogs(t, conn, pWithOtherCatalogs.GetPublicId(), 3) {
|
||||
wantOtherCatalogs = append(wantOtherCatalogs, &pb.HostCatalog{
|
||||
Id: hc.GetPublicId(),
|
||||
CreatedTime: hc.GetCreateTime().GetTimestamp(),
|
||||
UpdatedTime: hc.GetUpdateTime().GetTimestamp(),
|
||||
Scope: &scopepb.ScopeInfo{Id: pWithOtherCatalogs.GetPublicId(), Type: scope.Project.String()},
|
||||
Version: 1,
|
||||
Type: "static",
|
||||
})
|
||||
}
|
||||
|
||||
cases := []struct {
|
||||
name string
|
||||
scopeId string
|
||||
res *pbs.ListHostCatalogsResponse
|
||||
errCode codes.Code
|
||||
}{
|
||||
{
|
||||
name: "List Some Catalogs",
|
||||
scopeId: pWithCatalogs.GetPublicId(),
|
||||
res: &pbs.ListHostCatalogsResponse{Items: wantSomeCatalogs},
|
||||
errCode: codes.OK,
|
||||
},
|
||||
{
|
||||
name: "List Other Catalogs",
|
||||
scopeId: pWithOtherCatalogs.GetPublicId(),
|
||||
res: &pbs.ListHostCatalogsResponse{Items: wantOtherCatalogs},
|
||||
errCode: codes.OK,
|
||||
},
|
||||
{
|
||||
name: "List No Catalogs",
|
||||
scopeId: pNoCatalogs.GetPublicId(),
|
||||
res: &pbs.ListHostCatalogsResponse{},
|
||||
errCode: codes.OK,
|
||||
},
|
||||
// TODO: When an auth method doesn't exist, we should return a 404 instead of an empty list.
|
||||
{
|
||||
name: "Unfound Catalogs",
|
||||
scopeId: scope.Project.Prefix() + "_DoesntExis",
|
||||
res: &pbs.ListHostCatalogsResponse{},
|
||||
errCode: codes.OK,
|
||||
},
|
||||
}
|
||||
for _, tc := range cases {
|
||||
t.Run(tc.name, func(t *testing.T) {
|
||||
assert, require := assert.New(t), require.New(t)
|
||||
s, err := host_catalogs.NewService(repoFn)
|
||||
require.NoError(err, "Couldn't create new auth_method service.")
|
||||
|
||||
got, gErr := s.ListHostCatalogs(auth.DisabledAuthTestContext(auth.WithScopeId(tc.scopeId)), &pbs.ListHostCatalogsRequest{})
|
||||
assert.Equal(tc.errCode, status.Code(gErr), "ListHostCatalogs() for scope %q got error %v, wanted %v", tc.scopeId, gErr, tc.errCode)
|
||||
assert.Empty(cmp.Diff(got, tc.res, protocmp.Transform()), "ListHostCatalogs() for scope %q got response %q, wanted %q", tc.scopeId, got, tc.res)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestDelete(t *testing.T) {
|
||||
t.Parallel()
|
||||
require := require.New(t)
|
||||
@@ -244,7 +327,7 @@ func TestCreate(t *testing.T) {
|
||||
res: &pbs.CreateHostCatalogResponse{
|
||||
Uri: fmt.Sprintf("scopes/%s/host-catalogs/%s_", proj.GetPublicId(), static.HostCatalogPrefix),
|
||||
Item: &pb.HostCatalog{
|
||||
Scope: &scopes.ScopeInfo{Id: proj.GetPublicId(), Type: scope.Project.String()},
|
||||
Scope: &scopepb.ScopeInfo{Id: proj.GetPublicId(), Type: scope.Project.String()},
|
||||
Name: &wrappers.StringValue{Value: "name"},
|
||||
Description: &wrappers.StringValue{Value: "desc"},
|
||||
Type: "static",
|
||||
@@ -373,7 +456,7 @@ func TestUpdate(t *testing.T) {
|
||||
res: &pbs.UpdateHostCatalogResponse{
|
||||
Item: &pb.HostCatalog{
|
||||
Id: hc.GetPublicId(),
|
||||
Scope: &scopes.ScopeInfo{Id: proj.GetPublicId(), Type: scope.Project.String()},
|
||||
Scope: &scopepb.ScopeInfo{Id: proj.GetPublicId(), Type: scope.Project.String()},
|
||||
Name: &wrappers.StringValue{Value: "new"},
|
||||
Description: &wrappers.StringValue{Value: "desc"},
|
||||
CreatedTime: hc.GetCreateTime().GetTimestamp(),
|
||||
@@ -396,7 +479,7 @@ func TestUpdate(t *testing.T) {
|
||||
res: &pbs.UpdateHostCatalogResponse{
|
||||
Item: &pb.HostCatalog{
|
||||
Id: hc.GetPublicId(),
|
||||
Scope: &scopes.ScopeInfo{Id: proj.GetPublicId(), Type: scope.Project.String()},
|
||||
Scope: &scopepb.ScopeInfo{Id: proj.GetPublicId(), Type: scope.Project.String()},
|
||||
Name: &wrappers.StringValue{Value: "new"},
|
||||
Description: &wrappers.StringValue{Value: "desc"},
|
||||
CreatedTime: hc.GetCreateTime().GetTimestamp(),
|
||||
@@ -450,7 +533,7 @@ func TestUpdate(t *testing.T) {
|
||||
res: &pbs.UpdateHostCatalogResponse{
|
||||
Item: &pb.HostCatalog{
|
||||
Id: hc.GetPublicId(),
|
||||
Scope: &scopes.ScopeInfo{Id: proj.GetPublicId(), Type: scope.Project.String()},
|
||||
Scope: &scopepb.ScopeInfo{Id: proj.GetPublicId(), Type: scope.Project.String()},
|
||||
Description: &wrappers.StringValue{Value: "default"},
|
||||
CreatedTime: hc.GetCreateTime().GetTimestamp(),
|
||||
Type: "static",
|
||||
@@ -471,7 +554,7 @@ func TestUpdate(t *testing.T) {
|
||||
res: &pbs.UpdateHostCatalogResponse{
|
||||
Item: &pb.HostCatalog{
|
||||
Id: hc.GetPublicId(),
|
||||
Scope: &scopes.ScopeInfo{Id: proj.GetPublicId(), Type: scope.Project.String()},
|
||||
Scope: &scopepb.ScopeInfo{Id: proj.GetPublicId(), Type: scope.Project.String()},
|
||||
Name: &wrappers.StringValue{Value: "default"},
|
||||
CreatedTime: hc.GetCreateTime().GetTimestamp(),
|
||||
Type: "static",
|
||||
@@ -493,7 +576,7 @@ func TestUpdate(t *testing.T) {
|
||||
res: &pbs.UpdateHostCatalogResponse{
|
||||
Item: &pb.HostCatalog{
|
||||
Id: hc.GetPublicId(),
|
||||
Scope: &scopes.ScopeInfo{Id: proj.GetPublicId(), Type: scope.Project.String()},
|
||||
Scope: &scopepb.ScopeInfo{Id: proj.GetPublicId(), Type: scope.Project.String()},
|
||||
Name: &wrappers.StringValue{Value: "updated"},
|
||||
Description: &wrappers.StringValue{Value: "default"},
|
||||
CreatedTime: hc.GetCreateTime().GetTimestamp(),
|
||||
@@ -516,7 +599,7 @@ func TestUpdate(t *testing.T) {
|
||||
res: &pbs.UpdateHostCatalogResponse{
|
||||
Item: &pb.HostCatalog{
|
||||
Id: hc.GetPublicId(),
|
||||
Scope: &scopes.ScopeInfo{Id: proj.GetPublicId(), Type: scope.Project.String()},
|
||||
Scope: &scopepb.ScopeInfo{Id: proj.GetPublicId(), Type: scope.Project.String()},
|
||||
Name: &wrappers.StringValue{Value: "default"},
|
||||
Description: &wrappers.StringValue{Value: "notignored"},
|
||||
CreatedTime: hc.GetCreateTime().GetTimestamp(),
|
||||
@@ -536,7 +619,7 @@ func TestUpdate(t *testing.T) {
|
||||
},
|
||||
Item: &pb.HostCatalog{
|
||||
Name: &wrappers.StringValue{Value: "new"},
|
||||
Scope: &scopes.ScopeInfo{Id: proj.GetPublicId(), Type: scope.Project.String()},
|
||||
Scope: &scopepb.ScopeInfo{Id: proj.GetPublicId(), Type: scope.Project.String()},
|
||||
Description: &wrappers.StringValue{Value: "desc"},
|
||||
},
|
||||
},
|
||||
@@ -551,7 +634,7 @@ func TestUpdate(t *testing.T) {
|
||||
},
|
||||
Item: &pb.HostCatalog{
|
||||
Id: "p_somethinge",
|
||||
Scope: &scopes.ScopeInfo{Id: proj.GetPublicId(), Type: scope.Project.String()},
|
||||
Scope: &scopepb.ScopeInfo{Id: proj.GetPublicId(), Type: scope.Project.String()},
|
||||
Name: &wrappers.StringValue{Value: "new"},
|
||||
Description: &wrappers.StringValue{Value: "new desc"},
|
||||
}},
|
||||
|
||||
Reference in new issue
Block a user