From 7ac4be51c026070876f1c9a3f84665a634635fdb Mon Sep 17 00:00:00 2001 From: Michael Gaffney Date: Thu, 13 Aug 2020 14:00:15 -0400 Subject: [PATCH] Refactor static host package (#263) * Refactor: inline tablename constants * Refactor: move functionality to new files --- internal/host/static/gorm.go | 64 -- internal/host/static/gorm_test.go | 159 ----- internal/host/static/host.go | 51 ++ internal/host/static/host_catalog.go | 76 ++ internal/host/static/host_catalog_test.go | 172 +++++ internal/host/static/host_set.go | 47 ++ internal/host/static/host_set_member.go | 46 ++ internal/host/static/host_set_member_test.go | 103 +++ internal/host/static/host_set_test.go | 168 +++++ internal/host/static/host_test.go | 216 ++++++ internal/host/static/public_ids.go | 38 + internal/host/static/repository.go | 217 ------ .../host/static/repository_host_catalog.go | 204 ++++++ .../static/repository_host_catalog_test.go | 670 ++++++++++++++++++ internal/host/static/repository_test.go | 662 ----------------- internal/host/static/static.go | 151 ---- internal/host/static/static_test.go | 474 ------------- 17 files changed, 1791 insertions(+), 1727 deletions(-) delete mode 100644 internal/host/static/gorm.go delete mode 100644 internal/host/static/gorm_test.go create mode 100644 internal/host/static/host.go create mode 100644 internal/host/static/host_catalog.go create mode 100644 internal/host/static/host_catalog_test.go create mode 100644 internal/host/static/host_set.go create mode 100644 internal/host/static/host_set_member.go create mode 100644 internal/host/static/host_set_member_test.go create mode 100644 internal/host/static/host_set_test.go create mode 100644 internal/host/static/host_test.go create mode 100644 internal/host/static/public_ids.go create mode 100644 internal/host/static/repository_host_catalog.go create mode 100644 internal/host/static/repository_host_catalog_test.go delete mode 100644 internal/host/static/static.go delete mode 100644 internal/host/static/static_test.go diff --git a/internal/host/static/gorm.go b/internal/host/static/gorm.go deleted file mode 100644 index a3450c3e4..000000000 --- a/internal/host/static/gorm.go +++ /dev/null @@ -1,64 +0,0 @@ -package static - -const ( - defaultHostCatalogTableName = "static_host_catalog" - defaultHostTableName = "static_host" - defaultHostSetTableName = "static_host_set" - defaultHostSetMemberTableName = "static_host_set_member" -) - -// TableName returns the table name for the host catalog. -func (c *HostCatalog) TableName() string { - if c.tableName != "" { - return c.tableName - } - return defaultHostCatalogTableName -} - -// SetTableName sets the table name. If the caller attempts to -// set the name to "" the name will be reset to the default name. -func (c *HostCatalog) SetTableName(n string) { - c.tableName = n -} - -// TableName returns the table name for the host. -func (h *Host) TableName() string { - if h.tableName != "" { - return h.tableName - } - return defaultHostTableName -} - -// SetTableName sets the table name. If the caller attempts to -// set the name to "" the name will be reset to the default name. -func (h *Host) SetTableName(n string) { - h.tableName = n -} - -// TableName returns the table name for the host set. -func (s *HostSet) TableName() string { - if s.tableName != "" { - return s.tableName - } - return defaultHostSetTableName -} - -// SetTableName sets the table name. If the caller attempts to -// set the name to "" the name will be reset to the default name. -func (s *HostSet) SetTableName(n string) { - s.tableName = n -} - -// TableName returns the table name for the host set. -func (m *HostSetMember) TableName() string { - if m.tableName != "" { - return m.tableName - } - return defaultHostSetMemberTableName -} - -// SetTableName sets the table name. If the caller attempts to -// set the name to "" the name will be reset to the default name. -func (m *HostSetMember) SetTableName(n string) { - m.tableName = n -} diff --git a/internal/host/static/gorm_test.go b/internal/host/static/gorm_test.go deleted file mode 100644 index 6be728f96..000000000 --- a/internal/host/static/gorm_test.go +++ /dev/null @@ -1,159 +0,0 @@ -package static - -import ( - "testing" - - "github.com/hashicorp/boundary/internal/host/static/store" - "github.com/stretchr/testify/assert" - "github.com/stretchr/testify/require" -) - -func TestHostCatalog_SetTableName(t *testing.T) { - defaultTableName := defaultHostCatalogTableName - tests := []struct { - name string - initialName string - setNameTo string - want string - }{ - { - name: "new-name", - initialName: "", - setNameTo: "new-name", - want: "new-name", - }, - { - name: "reset to default", - initialName: "initial", - setNameTo: "", - want: defaultTableName, - }, - } - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - assert, require := assert.New(t), require.New(t) - def := allocCatalog() - require.Equal(defaultTableName, def.TableName()) - s := &HostCatalog{ - HostCatalog: &store.HostCatalog{}, - tableName: tt.initialName, - } - s.SetTableName(tt.setNameTo) - assert.Equal(tt.want, s.TableName()) - }) - } -} - -func TestHost_SetTableName(t *testing.T) { - defaultTableName := defaultHostTableName - tests := []struct { - name string - initialName string - setNameTo string - want string - }{ - { - name: "new-name", - initialName: "", - setNameTo: "new-name", - want: "new-name", - }, - { - name: "reset to default", - initialName: "initial", - setNameTo: "", - want: defaultTableName, - }, - } - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - assert, require := assert.New(t), require.New(t) - def := &Host{ - Host: &store.Host{}, - } - require.Equal(defaultTableName, def.TableName()) - s := &Host{ - Host: &store.Host{}, - tableName: tt.initialName, - } - s.SetTableName(tt.setNameTo) - assert.Equal(tt.want, s.TableName()) - }) - } -} - -func TestHostSet_SetTableName(t *testing.T) { - defaultTableName := defaultHostSetTableName - tests := []struct { - name string - initialName string - setNameTo string - want string - }{ - { - name: "new-name", - initialName: "", - setNameTo: "new-name", - want: "new-name", - }, - { - name: "reset to default", - initialName: "initial", - setNameTo: "", - want: defaultTableName, - }, - } - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - assert, require := assert.New(t), require.New(t) - def := &HostSet{ - HostSet: &store.HostSet{}, - } - require.Equal(defaultTableName, def.TableName()) - s := &HostSet{ - HostSet: &store.HostSet{}, - tableName: tt.initialName, - } - s.SetTableName(tt.setNameTo) - assert.Equal(tt.want, s.TableName()) - }) - } -} - -func TestHostSetMember_SetTableName(t *testing.T) { - defaultTableName := defaultHostSetMemberTableName - tests := []struct { - name string - initialName string - setNameTo string - want string - }{ - { - name: "new-name", - initialName: "", - setNameTo: "new-name", - want: "new-name", - }, - { - name: "reset to default", - initialName: "initial", - setNameTo: "", - want: defaultTableName, - }, - } - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - assert, require := assert.New(t), require.New(t) - def := &HostSetMember{ - HostSetMember: &store.HostSetMember{}, - } - require.Equal(defaultTableName, def.TableName()) - s := &HostSetMember{ - HostSetMember: &store.HostSetMember{}, - tableName: tt.initialName, - } - s.SetTableName(tt.setNameTo) - assert.Equal(tt.want, s.TableName()) - }) - } -} diff --git a/internal/host/static/host.go b/internal/host/static/host.go new file mode 100644 index 000000000..e95365b86 --- /dev/null +++ b/internal/host/static/host.go @@ -0,0 +1,51 @@ +package static + +import ( + "fmt" + + "github.com/hashicorp/boundary/internal/db" + "github.com/hashicorp/boundary/internal/host/static/store" +) + +// A Host contains a static address. +type Host struct { + *store.Host + tableName string `gorm:"-"` +} + +// NewHost creates a new in memory Host for address assigned to catalogId. +// Name and description are the only valid options. All other options are +// ignored. +func NewHost(catalogId, address string, opt ...Option) (*Host, error) { + if catalogId == "" { + return nil, fmt.Errorf("new: static host: no catalog id: %w", db.ErrInvalidParameter) + } + if address == "" { + return nil, fmt.Errorf("new: static host: no address: %w", db.ErrInvalidParameter) + } + + opts := getOpts(opt...) + host := &Host{ + Host: &store.Host{ + StaticHostCatalogId: catalogId, + Address: address, + Name: opts.withName, + Description: opts.withDescription, + }, + } + return host, nil +} + +// TableName returns the table name for the host. +func (h *Host) TableName() string { + if h.tableName != "" { + return h.tableName + } + return "static_host" +} + +// SetTableName sets the table name. If the caller attempts to +// set the name to "" the name will be reset to the default name. +func (h *Host) SetTableName(n string) { + h.tableName = n +} diff --git a/internal/host/static/host_catalog.go b/internal/host/static/host_catalog.go new file mode 100644 index 000000000..e8c9f31e5 --- /dev/null +++ b/internal/host/static/host_catalog.go @@ -0,0 +1,76 @@ +package static + +import ( + "fmt" + + "github.com/hashicorp/boundary/internal/db" + "github.com/hashicorp/boundary/internal/host/static/store" + "github.com/hashicorp/boundary/internal/oplog" + "google.golang.org/protobuf/proto" +) + +// A HostCatalog contains static hosts and static host sets. It is owned by +// a scope. +type HostCatalog struct { + *store.HostCatalog + tableName string `gorm:"-"` +} + +// NewHostCatalog creates a new in memory HostCatalog assigned to scopeId. +// Name and description are the only valid options. All other options are +// ignored. +func NewHostCatalog(scopeId string, opt ...Option) (*HostCatalog, error) { + if scopeId == "" { + return nil, fmt.Errorf("new: static host catalog: no scope id: %w", db.ErrInvalidParameter) + } + + opts := getOpts(opt...) + hc := &HostCatalog{ + HostCatalog: &store.HostCatalog{ + ScopeId: scopeId, + Name: opts.withName, + Description: opts.withDescription, + }, + } + return hc, nil +} + +func (c *HostCatalog) clone() *HostCatalog { + cp := proto.Clone(c.HostCatalog) + return &HostCatalog{ + HostCatalog: cp.(*store.HostCatalog), + } +} + +// TableName returns the table name for the host catalog. +func (c *HostCatalog) TableName() string { + if c.tableName != "" { + return c.tableName + } + return "static_host_catalog" +} + +// SetTableName sets the table name. If the caller attempts to +// set the name to "" the name will be reset to the default name. +func (c *HostCatalog) SetTableName(n string) { + c.tableName = n +} + +func allocCatalog() *HostCatalog { + fresh := &HostCatalog{ + HostCatalog: &store.HostCatalog{}, + } + return fresh +} + +func newCatalogMetadata(c *HostCatalog, op oplog.OpType) oplog.Metadata { + metadata := oplog.Metadata{ + "resource-public-id": []string{c.GetPublicId()}, + "resource-type": []string{"static host catalog"}, + "op-type": []string{op.String()}, + } + if c.ScopeId != "" { + metadata["scope-id"] = []string{c.ScopeId} + } + return metadata +} diff --git a/internal/host/static/host_catalog_test.go b/internal/host/static/host_catalog_test.go new file mode 100644 index 000000000..24a89c3c9 --- /dev/null +++ b/internal/host/static/host_catalog_test.go @@ -0,0 +1,172 @@ +package static + +import ( + "context" + "testing" + + "github.com/hashicorp/boundary/internal/db" + "github.com/hashicorp/boundary/internal/host/static/store" + "github.com/hashicorp/boundary/internal/iam" + "github.com/jinzhu/gorm" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" +) + +func TestHostCatalog_New(t *testing.T) { + conn, _ := db.TestSetup(t, "postgres") + _, prj := iam.TestScopes(t, conn) + + type args struct { + scopeId string + opts []Option + } + + var tests = []struct { + name string + args args + want *HostCatalog + wantErr bool + }{ + { + name: "blank-scopeId", + args: args{ + scopeId: "", + }, + want: nil, + wantErr: true, + }, + { + name: "valid-no-options", + args: args{ + scopeId: prj.GetPublicId(), + }, + want: &HostCatalog{ + HostCatalog: &store.HostCatalog{ + ScopeId: prj.GetPublicId(), + }, + }, + }, + { + name: "valid-with-name", + args: args{ + scopeId: prj.GetPublicId(), + opts: []Option{ + WithName("test-name"), + }, + }, + want: &HostCatalog{ + HostCatalog: &store.HostCatalog{ + ScopeId: prj.GetPublicId(), + Name: "test-name", + }, + }, + }, + { + name: "valid-with-description", + args: args{ + scopeId: prj.GetPublicId(), + opts: []Option{ + WithDescription("test-description"), + }, + }, + want: &HostCatalog{ + HostCatalog: &store.HostCatalog{ + ScopeId: prj.GetPublicId(), + Description: "test-description", + }, + }, + }, + } + + for _, tt := range tests { + tt := tt + t.Run(tt.name, func(t *testing.T) { + assert := assert.New(t) + got, err := NewHostCatalog(tt.args.scopeId, tt.args.opts...) + if tt.wantErr { + assert.Error(err) + assert.Nil(got) + } else { + assert.NoError(err) + if assert.NotNil(got) { + assert.Emptyf(got.PublicId, "PublicId set") + assert.Equal(tt.want, got) + + id, err := newHostCatalogId() + assert.NoError(err) + + tt.want.PublicId = id + got.PublicId = id + + w := db.New(conn) + err2 := w.Create(context.Background(), got) + assert.NoError(err2) + } + } + }) + } +} + +func testCatalogs(t *testing.T, conn *gorm.DB, count int) []*HostCatalog { + t.Helper() + assert := assert.New(t) + _, prj := iam.TestScopes(t, conn) + var cats []*HostCatalog + for i := 0; i < count; i++ { + cat, err := NewHostCatalog(prj.GetPublicId()) + 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 +} + +func testCatalog(t *testing.T, conn *gorm.DB) *HostCatalog { + t.Helper() + cats := testCatalogs(t, conn, 1) + return cats[0] +} + +func TestHostCatalog_SetTableName(t *testing.T) { + defaultTableName := "static_host_catalog" + tests := []struct { + name string + initialName string + setNameTo string + want string + }{ + { + name: "new-name", + initialName: "", + setNameTo: "new-name", + want: "new-name", + }, + { + name: "reset to default", + initialName: "initial", + setNameTo: "", + want: defaultTableName, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + assert, require := assert.New(t), require.New(t) + def := allocCatalog() + require.Equal(defaultTableName, def.TableName()) + s := &HostCatalog{ + HostCatalog: &store.HostCatalog{}, + tableName: tt.initialName, + } + s.SetTableName(tt.setNameTo) + assert.Equal(tt.want, s.TableName()) + }) + } +} diff --git a/internal/host/static/host_set.go b/internal/host/static/host_set.go new file mode 100644 index 000000000..320094a79 --- /dev/null +++ b/internal/host/static/host_set.go @@ -0,0 +1,47 @@ +package static + +import ( + "fmt" + + "github.com/hashicorp/boundary/internal/db" + "github.com/hashicorp/boundary/internal/host/static/store" +) + +// A HostSet is a collection of hosts from the set's catalog. +type HostSet struct { + *store.HostSet + tableName string `gorm:"-"` +} + +// NewHostSet creates a new in memory HostSet assigned to catalogId. +// Name and description are the only valid options. All other options are +// ignored. +func NewHostSet(catalogId string, opt ...Option) (*HostSet, error) { + if catalogId == "" { + return nil, fmt.Errorf("new: static host set: no catalog id: %w", db.ErrInvalidParameter) + } + + opts := getOpts(opt...) + set := &HostSet{ + HostSet: &store.HostSet{ + StaticHostCatalogId: catalogId, + Name: opts.withName, + Description: opts.withDescription, + }, + } + return set, nil +} + +// TableName returns the table name for the host set. +func (s *HostSet) TableName() string { + if s.tableName != "" { + return s.tableName + } + return "static_host_set" +} + +// SetTableName sets the table name. If the caller attempts to +// set the name to "" the name will be reset to the default name. +func (s *HostSet) SetTableName(n string) { + s.tableName = n +} diff --git a/internal/host/static/host_set_member.go b/internal/host/static/host_set_member.go new file mode 100644 index 000000000..4d8cc63bf --- /dev/null +++ b/internal/host/static/host_set_member.go @@ -0,0 +1,46 @@ +package static + +import ( + "fmt" + + "github.com/hashicorp/boundary/internal/db" + "github.com/hashicorp/boundary/internal/host/static/store" +) + +// A HostSetMember represents the membership of a host in a host set. +type HostSetMember struct { + *store.HostSetMember + tableName string `gorm:"-"` +} + +// NewHostSetMember creates a new in memory HostSetMember representing the +// membership of hostId in hostSetId. +func NewHostSetMember(hostSetId, hostId string, opt ...Option) (*HostSetMember, error) { + if hostSetId == "" { + return nil, fmt.Errorf("new: static host set member: no host set id: %w", db.ErrInvalidParameter) + } + if hostId == "" { + return nil, fmt.Errorf("new: static host set member: no host id: %w", db.ErrInvalidParameter) + } + member := &HostSetMember{ + HostSetMember: &store.HostSetMember{ + StaticHostSetId: hostSetId, + StaticHostId: hostId, + }, + } + return member, nil +} + +// TableName returns the table name for the host set. +func (m *HostSetMember) TableName() string { + if m.tableName != "" { + return m.tableName + } + return "static_host_set_member" +} + +// SetTableName sets the table name. If the caller attempts to +// set the name to "" the name will be reset to the default name. +func (m *HostSetMember) SetTableName(n string) { + m.tableName = n +} diff --git a/internal/host/static/host_set_member_test.go b/internal/host/static/host_set_member_test.go new file mode 100644 index 000000000..19a50cbdc --- /dev/null +++ b/internal/host/static/host_set_member_test.go @@ -0,0 +1,103 @@ +package static + +import ( + "context" + "testing" + + "github.com/hashicorp/boundary/internal/db" + "github.com/hashicorp/boundary/internal/host/static/store" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" +) + +func TestHostSetMember_New(t *testing.T) { + conn, _ := db.TestSetup(t, "postgres") + conn.LogMode(false) + + cats := testCatalogs(t, conn, 2) + + blueCat := cats[0] + blueSets := testSets(t, conn, blueCat.GetPublicId(), 2) + blueHosts := testHosts(t, conn, blueCat.GetPublicId(), 2) + + // TODO(mgaffney) 05/2020: + // these will be needed when the repository code is done + // greenCat := cats[1] + // greenSets := testSets(t, conn, greenCat.GetPublicId(), 2) + // greenHosts := testHosts(t, conn, greenCat.GetPublicId(), 2) + + var tests = []struct { + name string + set *HostSet + host *Host + wantErr bool + }{ + { + name: "valid-host-in-set", + set: blueSets[0], + host: blueHosts[0], + }, + // { + // name: "invalid-diff-catalogs", + // set: greenSets[0], + // host: blueHosts[0], + // wantErr: true, + // }, + } + for _, tt := range tests { + tt := tt + t.Run(tt.name, func(t *testing.T) { + assert := assert.New(t) + got, err := NewHostSetMember(tt.set.PublicId, tt.host.PublicId) + if tt.wantErr { + assert.Error(err) + assert.Nil(got) + } else { + assert.NoError(err) + if assert.NotNil(got) { + w := db.New(conn) + err2 := w.Create(context.Background(), got) + assert.NoError(err2) + } + } + }) + } +} + +func TestHostSetMember_SetTableName(t *testing.T) { + defaultTableName := "static_host_set_member" + tests := []struct { + name string + initialName string + setNameTo string + want string + }{ + { + name: "new-name", + initialName: "", + setNameTo: "new-name", + want: "new-name", + }, + { + name: "reset to default", + initialName: "initial", + setNameTo: "", + want: defaultTableName, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + assert, require := assert.New(t), require.New(t) + def := &HostSetMember{ + HostSetMember: &store.HostSetMember{}, + } + require.Equal(defaultTableName, def.TableName()) + s := &HostSetMember{ + HostSetMember: &store.HostSetMember{}, + tableName: tt.initialName, + } + s.SetTableName(tt.setNameTo) + assert.Equal(tt.want, s.TableName()) + }) + } +} diff --git a/internal/host/static/host_set_test.go b/internal/host/static/host_set_test.go new file mode 100644 index 000000000..76337f707 --- /dev/null +++ b/internal/host/static/host_set_test.go @@ -0,0 +1,168 @@ +package static + +import ( + "context" + "testing" + + "github.com/hashicorp/boundary/internal/db" + "github.com/hashicorp/boundary/internal/host/static/store" + "github.com/jinzhu/gorm" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" +) + +func TestHostSet_New(t *testing.T) { + conn, _ := db.TestSetup(t, "postgres") + cat := testCatalog(t, conn) + + conn.LogMode(false) + type args struct { + catalogId string + opts []Option + } + + var tests = []struct { + name string + args args + want *HostSet + wantErr bool + }{ + { + name: "blank-catalogId", + args: args{ + catalogId: "", + }, + want: nil, + wantErr: true, + }, + { + name: "valid-no-options", + args: args{ + catalogId: cat.GetPublicId(), + }, + want: &HostSet{ + HostSet: &store.HostSet{ + StaticHostCatalogId: cat.GetPublicId(), + }, + }, + }, + { + name: "valid-with-name", + args: args{ + catalogId: cat.GetPublicId(), + opts: []Option{ + WithName("test-name"), + }, + }, + want: &HostSet{ + HostSet: &store.HostSet{ + StaticHostCatalogId: cat.GetPublicId(), + Name: "test-name", + }, + }, + }, + { + name: "valid-with-description", + args: args{ + catalogId: cat.GetPublicId(), + opts: []Option{ + WithDescription("test-description"), + }, + }, + want: &HostSet{ + HostSet: &store.HostSet{ + StaticHostCatalogId: cat.GetPublicId(), + Description: "test-description", + }, + }, + }, + } + + for _, tt := range tests { + tt := tt + t.Run(tt.name, func(t *testing.T) { + assert := assert.New(t) + got, err := NewHostSet(tt.args.catalogId, tt.args.opts...) + if tt.wantErr { + assert.Error(err) + assert.Nil(got) + } else { + assert.NoError(err) + if assert.NotNil(got) { + assert.Emptyf(got.PublicId, "PublicId set") + assert.Equal(tt.want, got) + + id, err := newHostSetId() + assert.NoError(err) + + tt.want.PublicId = id + got.PublicId = id + + w := db.New(conn) + err2 := w.Create(context.Background(), got) + assert.NoError(err2) + } + } + }) + } +} + +func testSets(t *testing.T, conn *gorm.DB, catalogId string, count int) []*HostSet { + t.Helper() + assert := assert.New(t) + var sets []*HostSet + + for i := 0; i < count; i++ { + set, err := NewHostSet(catalogId) + assert.NoError(err) + assert.NotNil(set) + id, err := newHostSetId() + assert.NoError(err) + assert.NotEmpty(id) + set.PublicId = id + + w := db.New(conn) + err2 := w.Create(context.Background(), set) + assert.NoError(err2) + sets = append(sets, set) + } + return sets +} + +func TestHostSet_SetTableName(t *testing.T) { + defaultTableName := "static_host_set" + tests := []struct { + name string + initialName string + setNameTo string + want string + }{ + { + name: "new-name", + initialName: "", + setNameTo: "new-name", + want: "new-name", + }, + { + name: "reset to default", + initialName: "initial", + setNameTo: "", + want: defaultTableName, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + assert, require := assert.New(t), require.New(t) + def := &HostSet{ + HostSet: &store.HostSet{}, + } + require.Equal(defaultTableName, def.TableName()) + s := &HostSet{ + HostSet: &store.HostSet{}, + tableName: tt.initialName, + } + s.SetTableName(tt.setNameTo) + assert.Equal(tt.want, s.TableName()) + }) + } +} diff --git a/internal/host/static/host_test.go b/internal/host/static/host_test.go new file mode 100644 index 000000000..dbb814f2f --- /dev/null +++ b/internal/host/static/host_test.go @@ -0,0 +1,216 @@ +package static + +import ( + "context" + "fmt" + "testing" + + "github.com/hashicorp/boundary/internal/db" + "github.com/hashicorp/boundary/internal/host/static/store" + "github.com/jinzhu/gorm" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" +) +func TestHost_New(t *testing.T) { + conn, _ := db.TestSetup(t, "postgres") + cat := testCatalog(t, conn) + + conn.LogMode(false) + type args struct { + catalogId string + address string + opts []Option + } + + var tests = []struct { + name string + args args + want *Host + wantCreateErr bool + wantWriteErr bool + }{ + { + name: "blank-catalogId", + args: args{ + catalogId: "", + address: "127.0.0.1", + }, + want: nil, + wantCreateErr: true, + }, + { + name: "blank-address", + args: args{ + catalogId: cat.GetPublicId(), + address: "", + }, + want: nil, + wantCreateErr: true, + }, + { + name: "address-to-short", + args: args{ + catalogId: cat.GetPublicId(), + address: "1234567", + }, + want: &Host{ + Host: &store.Host{ + StaticHostCatalogId: cat.GetPublicId(), + Address: "1234567", + }, + }, + wantWriteErr: true, + }, + { + name: "minimum-address", + args: args{ + catalogId: cat.GetPublicId(), + address: "12345678", + }, + want: &Host{ + Host: &store.Host{ + StaticHostCatalogId: cat.GetPublicId(), + Address: "12345678", + }, + }, + }, + { + name: "valid-no-options", + args: args{ + catalogId: cat.GetPublicId(), + address: "127.0.0.1", + }, + want: &Host{ + Host: &store.Host{ + StaticHostCatalogId: cat.GetPublicId(), + Address: "127.0.0.1", + }, + }, + }, + { + name: "valid-with-name", + args: args{ + catalogId: cat.GetPublicId(), + address: "127.0.0.1", + opts: []Option{ + WithName("test-name"), + }, + }, + want: &Host{ + Host: &store.Host{ + StaticHostCatalogId: cat.GetPublicId(), + Address: "127.0.0.1", + Name: "test-name", + }, + }, + }, + { + name: "valid-with-description", + args: args{ + catalogId: cat.GetPublicId(), + address: "127.0.0.1", + opts: []Option{ + WithDescription("test-description"), + }, + }, + want: &Host{ + Host: &store.Host{ + StaticHostCatalogId: cat.GetPublicId(), + Address: "127.0.0.1", + Description: "test-description", + }, + }, + }, + } + + for _, tt := range tests { + tt := tt + t.Run(tt.name, func(t *testing.T) { + assert := assert.New(t) + got, err := NewHost(tt.args.catalogId, tt.args.address, tt.args.opts...) + if tt.wantCreateErr { + assert.Error(err) + assert.Nil(got) + } else { + assert.NoError(err) + if assert.NotNil(got) { + assert.Emptyf(got.PublicId, "PublicId set") + assert.Equal(tt.want, got) + + id, err := newHostId() + assert.NoError(err) + + tt.want.PublicId = id + got.PublicId = id + + w := db.New(conn) + err2 := w.Create(context.Background(), got) + if tt.wantWriteErr { + assert.Error(err2) + } + } + } + }) + } +} + +func testHosts(t *testing.T, conn *gorm.DB, catalogId string, count int) []*Host { + t.Helper() + assert := assert.New(t) + var hosts []*Host + + for i := 0; i < count; i++ { + host, err := NewHost(catalogId, fmt.Sprintf("%s-%d", catalogId, i)) + assert.NoError(err) + assert.NotNil(host) + + id, err := newHostCatalogId() + assert.NoError(err) + assert.NotEmpty(id) + host.PublicId = id + + w := db.New(conn) + err2 := w.Create(context.Background(), host) + assert.NoError(err2) + hosts = append(hosts, host) + } + return hosts +} + +func TestHost_SetTableName(t *testing.T) { + defaultTableName := "static_host" + tests := []struct { + name string + initialName string + setNameTo string + want string + }{ + { + name: "new-name", + initialName: "", + setNameTo: "new-name", + want: "new-name", + }, + { + name: "reset to default", + initialName: "initial", + setNameTo: "", + want: defaultTableName, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + assert, require := assert.New(t), require.New(t) + def := &Host{ + Host: &store.Host{}, + } + require.Equal(defaultTableName, def.TableName()) + s := &Host{ + Host: &store.Host{}, + tableName: tt.initialName, + } + s.SetTableName(tt.setNameTo) + assert.Equal(tt.want, s.TableName()) + }) + } +} diff --git a/internal/host/static/public_ids.go b/internal/host/static/public_ids.go new file mode 100644 index 000000000..6372c4186 --- /dev/null +++ b/internal/host/static/public_ids.go @@ -0,0 +1,38 @@ +package static + +import ( + "fmt" + + "github.com/hashicorp/boundary/internal/db" +) + +// PublicId prefixes for the resources in the static package. +const ( + HostCatalogPrefix = "sthc" + HostSetPrefix = "sths" + HostPrefix = "sth" +) + +func newHostCatalogId() (string, error) { + id, err := db.NewPublicId(HostCatalogPrefix) + if err != nil { + return "", fmt.Errorf("new host catalog id: %w", err) + } + return id, err +} + +func newHostId() (string, error) { + id, err := db.NewPublicId(HostPrefix) + if err != nil { + return "", fmt.Errorf("new host id: %w", err) + } + return id, err +} + +func newHostSetId() (string, error) { + id, err := db.NewPublicId(HostSetPrefix) + if err != nil { + return "", fmt.Errorf("new host set id: %w", err) + } + return id, err +} diff --git a/internal/host/static/repository.go b/internal/host/static/repository.go index c8dc06d45..0c54ab87b 100644 --- a/internal/host/static/repository.go +++ b/internal/host/static/repository.go @@ -1,15 +1,11 @@ package static import ( - "context" "fmt" - "strings" wrapping "github.com/hashicorp/go-kms-wrapping" "github.com/hashicorp/boundary/internal/db" - "github.com/hashicorp/boundary/internal/host/static/store" - "github.com/hashicorp/boundary/internal/oplog" ) // A Repository stores and retrieves the persistent types in the static @@ -39,216 +35,3 @@ func NewRepository(r db.Reader, w db.Writer, wrapper wrapping.Wrapper) (*Reposit wrapper: wrapper, }, nil } - -// CreateCatalog inserts c into the repository and returns a new -// HostCatalog containing the catalog's PublicId. c is not changed. c must -// contain a valid ScopeID. c must not contain a PublicId. The PublicId is -// generated and assigned by the this method. opt is ignored. -// -// Both c.Name and c.Description are optional. If c.Name is set, it must be -// unique within c.ScopeID. -// -// Both c.CreateTime and c.UpdateTime are ignored. -func (r *Repository) CreateCatalog(ctx context.Context, c *HostCatalog, opt ...Option) (*HostCatalog, error) { - if c == nil { - return nil, fmt.Errorf("create: static host catalog: %w", db.ErrNilParameter) - } - if c.HostCatalog == nil { - return nil, fmt.Errorf("create: static host catalog: embedded HostCatalog: %w", db.ErrNilParameter) - } - if c.ScopeId == "" { - return nil, fmt.Errorf("create: static host catalog: no scope id: %w", db.ErrInvalidParameter) - } - if c.PublicId != "" { - return nil, fmt.Errorf("create: static host catalog: public id not empty: %w", db.ErrInvalidParameter) - } - c = c.clone() - - id, err := newHostCatalogId() - if err != nil { - return nil, fmt.Errorf("create: static host catalog: %w", err) - } - c.PublicId = id - - metadata := newCatalogMetadata(c, oplog.OpType_OP_TYPE_CREATE) - - var newHostCatalog *HostCatalog - _, err = r.writer.DoTx( - ctx, - db.StdRetryCnt, - db.ExpBackoff{}, - func(_ db.Reader, w db.Writer) error { - newHostCatalog = c.clone() - return w.Create( - ctx, - newHostCatalog, - db.WithOplog(r.wrapper, metadata), - ) - }, - ) - - if err != nil { - if db.IsUniqueError(err) { - return nil, fmt.Errorf("create: static host catalog: in scope: %s: name %s already exists: %w", - c.ScopeId, c.Name, db.ErrNotUnique) - } - return nil, fmt.Errorf("create: static host catalog: in scope: %s: %w", c.ScopeId, err) - } - return newHostCatalog, nil -} - -// UpdateCatalog updates the repository entry for c.PublicId with the -// values in c for the fields listed in fieldMask. It returns a new -// HostCatalog containing the updated values and a count of the number of -// records updated. c is not changed. -// -// c must contain a valid PublicId. Only c.Name and c.Description can be -// updated. If c.Name is set to a non-empty string, it must be unique -// within c.ScopeID. -// -// An attribute of c will be set to NULL in the database if the attribute -// in c is the zero value and it is included in fieldMask. -func (r *Repository) UpdateCatalog(ctx context.Context, c *HostCatalog, version uint32, fieldMask []string, opt ...Option) (*HostCatalog, int, error) { - if c == nil { - return nil, db.NoRowsAffected, fmt.Errorf("update: static host catalog: %w", db.ErrNilParameter) - } - if c.HostCatalog == nil { - return nil, db.NoRowsAffected, fmt.Errorf("update: static host catalog: embedded HostCatalog: %w", db.ErrNilParameter) - } - if c.PublicId == "" { - return nil, db.NoRowsAffected, fmt.Errorf("update: static host catalog: missing public id: %w", db.ErrInvalidParameter) - } - if len(fieldMask) == 0 { - return nil, db.NoRowsAffected, fmt.Errorf("update: static host catalog: %w", db.ErrEmptyFieldMask) - } - - var dbMask, nullFields []string - for _, f := range fieldMask { - switch { - case strings.EqualFold("name", f) && c.Name == "": - nullFields = append(nullFields, "name") - case strings.EqualFold("name", f) && c.Name != "": - dbMask = append(dbMask, "name") - case strings.EqualFold("description", f) && c.Description == "": - nullFields = append(nullFields, "description") - case strings.EqualFold("description", f) && c.Description != "": - dbMask = append(dbMask, "description") - - default: - return nil, db.NoRowsAffected, fmt.Errorf("update: static host catalog: field: %s: %w", f, db.ErrInvalidFieldMask) - } - } - c = c.clone() - - metadata := newCatalogMetadata(c, oplog.OpType_OP_TYPE_UPDATE) - - var rowsUpdated int - var returnedCatalog *HostCatalog - _, err := r.writer.DoTx( - ctx, - db.StdRetryCnt, - db.ExpBackoff{}, - func(_ db.Reader, w db.Writer) error { - returnedCatalog = c.clone() - var err error - rowsUpdated, err = w.Update( - ctx, - returnedCatalog, - dbMask, - nullFields, - db.WithOplog(r.wrapper, metadata), - db.WithVersion(&version), - ) - if err == nil && rowsUpdated > 1 { - return db.ErrMultipleRecords - } - return err - }, - ) - - if err != nil { - if db.IsUniqueError(err) { - return nil, db.NoRowsAffected, fmt.Errorf("update: static host catalog: %s: name %s already exists: %w", - c.PublicId, c.Name, db.ErrNotUnique) - } - return nil, db.NoRowsAffected, fmt.Errorf("update: static host catalog: %s: %w", c.PublicId, err) - } - - return returnedCatalog, rowsUpdated, nil -} - -// LookupCatalog returns the HostCatalog for id. Returns nil, nil if no -// HostCatalog is found for id. -func (r *Repository) LookupCatalog(ctx context.Context, id string, opt ...Option) (*HostCatalog, error) { - if id == "" { - return nil, fmt.Errorf("lookup: static host catalog: missing public id: %w", db.ErrInvalidParameter) - } - c := allocCatalog() - c.PublicId = id - if err := r.reader.LookupByPublicId(ctx, c); err != nil { - if err == db.ErrRecordNotFound { - return nil, nil - } - return nil, fmt.Errorf("lookup: static host catalog: %s: %w", id, err) - } - return c, 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) { - if id == "" { - return db.NoRowsAffected, fmt.Errorf("delete: static host catalog: missing public id: %w", db.ErrInvalidParameter) - } - - c := allocCatalog() - c.PublicId = id - - metadata := newCatalogMetadata(c, oplog.OpType_OP_TYPE_DELETE) - - var rowsDeleted int - var deleteCatalog *HostCatalog - _, err := r.writer.DoTx( - ctx, - db.StdRetryCnt, - db.ExpBackoff{}, - func(_ db.Reader, w db.Writer) error { - deleteCatalog = c.clone() - var err error - rowsDeleted, err = w.Delete( - ctx, - deleteCatalog, - db.WithOplog(r.wrapper, metadata), - ) - if err == nil && rowsDeleted > 1 { - return db.ErrMultipleRecords - } - return err - }, - ) - - if err != nil { - return db.NoRowsAffected, fmt.Errorf("delete: static host catalog: %s: %w", c.PublicId, err) - } - - return rowsDeleted, nil -} - -func allocCatalog() *HostCatalog { - fresh := &HostCatalog{ - HostCatalog: &store.HostCatalog{}, - } - return fresh -} - -func newCatalogMetadata(c *HostCatalog, op oplog.OpType) oplog.Metadata { - metadata := oplog.Metadata{ - "resource-public-id": []string{c.GetPublicId()}, - "resource-type": []string{"static host catalog"}, - "op-type": []string{op.String()}, - } - if c.ScopeId != "" { - metadata["scope-id"] = []string{c.ScopeId} - } - return metadata -} diff --git a/internal/host/static/repository_host_catalog.go b/internal/host/static/repository_host_catalog.go new file mode 100644 index 000000000..04b60be4f --- /dev/null +++ b/internal/host/static/repository_host_catalog.go @@ -0,0 +1,204 @@ +package static + +import ( + "context" + "fmt" + "strings" + + "github.com/hashicorp/boundary/internal/db" + "github.com/hashicorp/boundary/internal/oplog" +) + +// CreateCatalog inserts c into the repository and returns a new +// HostCatalog containing the catalog's PublicId. c is not changed. c must +// contain a valid ScopeID. c must not contain a PublicId. The PublicId is +// generated and assigned by the this method. opt is ignored. +// +// Both c.Name and c.Description are optional. If c.Name is set, it must be +// unique within c.ScopeID. +// +// Both c.CreateTime and c.UpdateTime are ignored. +func (r *Repository) CreateCatalog(ctx context.Context, c *HostCatalog, opt ...Option) (*HostCatalog, error) { + if c == nil { + return nil, fmt.Errorf("create: static host catalog: %w", db.ErrNilParameter) + } + if c.HostCatalog == nil { + return nil, fmt.Errorf("create: static host catalog: embedded HostCatalog: %w", db.ErrNilParameter) + } + if c.ScopeId == "" { + return nil, fmt.Errorf("create: static host catalog: no scope id: %w", db.ErrInvalidParameter) + } + if c.PublicId != "" { + return nil, fmt.Errorf("create: static host catalog: public id not empty: %w", db.ErrInvalidParameter) + } + c = c.clone() + + id, err := newHostCatalogId() + if err != nil { + return nil, fmt.Errorf("create: static host catalog: %w", err) + } + c.PublicId = id + + metadata := newCatalogMetadata(c, oplog.OpType_OP_TYPE_CREATE) + + var newHostCatalog *HostCatalog + _, err = r.writer.DoTx( + ctx, + db.StdRetryCnt, + db.ExpBackoff{}, + func(_ db.Reader, w db.Writer) error { + newHostCatalog = c.clone() + return w.Create( + ctx, + newHostCatalog, + db.WithOplog(r.wrapper, metadata), + ) + }, + ) + + if err != nil { + if db.IsUniqueError(err) { + return nil, fmt.Errorf("create: static host catalog: in scope: %s: name %s already exists: %w", + c.ScopeId, c.Name, db.ErrNotUnique) + } + return nil, fmt.Errorf("create: static host catalog: in scope: %s: %w", c.ScopeId, err) + } + return newHostCatalog, nil +} + +// UpdateCatalog updates the repository entry for c.PublicId with the +// values in c for the fields listed in fieldMask. It returns a new +// HostCatalog containing the updated values and a count of the number of +// records updated. c is not changed. +// +// c must contain a valid PublicId. Only c.Name and c.Description can be +// updated. If c.Name is set to a non-empty string, it must be unique +// within c.ScopeID. +// +// An attribute of c will be set to NULL in the database if the attribute +// in c is the zero value and it is included in fieldMask. +func (r *Repository) UpdateCatalog(ctx context.Context, c *HostCatalog, version uint32, fieldMask []string, opt ...Option) (*HostCatalog, int, error) { + if c == nil { + return nil, db.NoRowsAffected, fmt.Errorf("update: static host catalog: %w", db.ErrNilParameter) + } + if c.HostCatalog == nil { + return nil, db.NoRowsAffected, fmt.Errorf("update: static host catalog: embedded HostCatalog: %w", db.ErrNilParameter) + } + if c.PublicId == "" { + return nil, db.NoRowsAffected, fmt.Errorf("update: static host catalog: missing public id: %w", db.ErrInvalidParameter) + } + if len(fieldMask) == 0 { + return nil, db.NoRowsAffected, fmt.Errorf("update: static host catalog: %w", db.ErrEmptyFieldMask) + } + + var dbMask, nullFields []string + for _, f := range fieldMask { + switch { + case strings.EqualFold("name", f) && c.Name == "": + nullFields = append(nullFields, "name") + case strings.EqualFold("name", f) && c.Name != "": + dbMask = append(dbMask, "name") + case strings.EqualFold("description", f) && c.Description == "": + nullFields = append(nullFields, "description") + case strings.EqualFold("description", f) && c.Description != "": + dbMask = append(dbMask, "description") + + default: + return nil, db.NoRowsAffected, fmt.Errorf("update: static host catalog: field: %s: %w", f, db.ErrInvalidFieldMask) + } + } + c = c.clone() + + metadata := newCatalogMetadata(c, oplog.OpType_OP_TYPE_UPDATE) + + var rowsUpdated int + var returnedCatalog *HostCatalog + _, err := r.writer.DoTx( + ctx, + db.StdRetryCnt, + db.ExpBackoff{}, + func(_ db.Reader, w db.Writer) error { + returnedCatalog = c.clone() + var err error + rowsUpdated, err = w.Update( + ctx, + returnedCatalog, + dbMask, + nullFields, + db.WithOplog(r.wrapper, metadata), + db.WithVersion(&version), + ) + if err == nil && rowsUpdated > 1 { + return db.ErrMultipleRecords + } + return err + }, + ) + + if err != nil { + if db.IsUniqueError(err) { + return nil, db.NoRowsAffected, fmt.Errorf("update: static host catalog: %s: name %s already exists: %w", + c.PublicId, c.Name, db.ErrNotUnique) + } + return nil, db.NoRowsAffected, fmt.Errorf("update: static host catalog: %s: %w", c.PublicId, err) + } + + return returnedCatalog, rowsUpdated, nil +} + +// LookupCatalog returns the HostCatalog for id. Returns nil, nil if no +// HostCatalog is found for id. +func (r *Repository) LookupCatalog(ctx context.Context, id string, opt ...Option) (*HostCatalog, error) { + if id == "" { + return nil, fmt.Errorf("lookup: static host catalog: missing public id: %w", db.ErrInvalidParameter) + } + c := allocCatalog() + c.PublicId = id + if err := r.reader.LookupByPublicId(ctx, c); err != nil { + if err == db.ErrRecordNotFound { + return nil, nil + } + return nil, fmt.Errorf("lookup: static host catalog: %s: %w", id, err) + } + return c, 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) { + if id == "" { + return db.NoRowsAffected, fmt.Errorf("delete: static host catalog: missing public id: %w", db.ErrInvalidParameter) + } + + c := allocCatalog() + c.PublicId = id + + metadata := newCatalogMetadata(c, oplog.OpType_OP_TYPE_DELETE) + + var rowsDeleted int + var deleteCatalog *HostCatalog + _, err := r.writer.DoTx( + ctx, + db.StdRetryCnt, + db.ExpBackoff{}, + func(_ db.Reader, w db.Writer) error { + deleteCatalog = c.clone() + var err error + rowsDeleted, err = w.Delete( + ctx, + deleteCatalog, + db.WithOplog(r.wrapper, metadata), + ) + if err == nil && rowsDeleted > 1 { + return db.ErrMultipleRecords + } + return err + }, + ) + + if err != nil { + return db.NoRowsAffected, fmt.Errorf("delete: static host catalog: %s: %w", c.PublicId, err) + } + + return rowsDeleted, nil +} diff --git a/internal/host/static/repository_host_catalog_test.go b/internal/host/static/repository_host_catalog_test.go new file mode 100644 index 000000000..f3eebe632 --- /dev/null +++ b/internal/host/static/repository_host_catalog_test.go @@ -0,0 +1,670 @@ +package static + +import ( + "context" + "errors" + "strings" + "testing" + + "github.com/hashicorp/boundary/internal/db" + dbassert "github.com/hashicorp/boundary/internal/db/assert" + "github.com/hashicorp/boundary/internal/host/static/store" + "github.com/hashicorp/boundary/internal/iam" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" +) + +func TestRepository_CreateCatalog(t *testing.T) { + conn, _ := db.TestSetup(t, "postgres") + rw := db.New(conn) + wrapper := db.TestWrapper(t) + + var tests = []struct { + name string + in *HostCatalog + opts []Option + want *HostCatalog + wantIsErr error + }{ + { + name: "nil-catalog", + wantIsErr: db.ErrNilParameter, + }, + { + name: "nil-embedded-catalog", + in: &HostCatalog{}, + wantIsErr: db.ErrNilParameter, + }, + { + name: "valid-no-options", + in: &HostCatalog{ + HostCatalog: &store.HostCatalog{}, + }, + want: &HostCatalog{ + HostCatalog: &store.HostCatalog{}, + }, + }, + { + name: "valid-with-name", + in: &HostCatalog{ + HostCatalog: &store.HostCatalog{ + Name: "test-name-repo", + }, + }, + want: &HostCatalog{ + HostCatalog: &store.HostCatalog{ + Name: "test-name-repo", + }, + }, + }, + { + name: "valid-with-description", + in: &HostCatalog{ + HostCatalog: &store.HostCatalog{ + Description: ("test-description-repo"), + }, + }, + want: &HostCatalog{ + HostCatalog: &store.HostCatalog{ + Description: ("test-description-repo"), + }, + }, + }, + } + + for _, tt := range tests { + tt := tt + t.Run(tt.name, func(t *testing.T) { + assert := assert.New(t) + repo, err := NewRepository(rw, rw, wrapper) + assert.NoError(err) + assert.NotNil(repo) + _, prj := iam.TestScopes(t, conn) + if tt.in != nil && tt.in.HostCatalog != nil { + tt.in.ScopeId = prj.GetPublicId() + assert.Empty(tt.in.PublicId) + } + got, err := repo.CreateCatalog(context.Background(), tt.in, tt.opts...) + if tt.wantIsErr != nil { + assert.Truef(errors.Is(err, tt.wantIsErr), "want err: %q got: %q", tt.wantIsErr, err) + assert.Nil(got) + return + } + assert.NoError(err) + assert.Empty(tt.in.PublicId) + assert.NotNil(got) + assertPublicId(t, "sthc", got.PublicId) + assert.NotSame(tt.in, got) + assert.Equal(tt.want.Name, got.Name) + assert.Equal(tt.want.Description, got.Description) + assert.Equal(got.CreateTime, got.UpdateTime) + }) + } + + t.Run("invalid-duplicate-names", func(t *testing.T) { + assert := assert.New(t) + repo, err := NewRepository(rw, rw, wrapper) + assert.NoError(err) + assert.NotNil(repo) + + _, prj := iam.TestScopes(t, conn) + in := &HostCatalog{ + HostCatalog: &store.HostCatalog{ + ScopeId: prj.GetPublicId(), + Name: "test-name-repo", + }, + } + + got, err := repo.CreateCatalog(context.Background(), in) + assert.NoError(err) + assert.NotNil(got) + assertPublicId(t, "sthc", got.PublicId) + assert.NotSame(in, got) + assert.Equal(in.Name, got.Name) + assert.Equal(in.Description, got.Description) + assert.Equal(got.CreateTime, got.UpdateTime) + + got2, err := repo.CreateCatalog(context.Background(), in) + assert.Truef(errors.Is(err, db.ErrNotUnique), "want err: %v got: %v", db.ErrNotUnique, err) + assert.Nil(got2) + }) + + t.Run("valid-duplicate-names-diff-scopes", func(t *testing.T) { + assert := assert.New(t) + repo, err := NewRepository(rw, rw, wrapper) + assert.NoError(err) + assert.NotNil(repo) + + org, prj := iam.TestScopes(t, conn) + in := &HostCatalog{ + HostCatalog: &store.HostCatalog{ + Name: "test-name-repo", + }, + } + in2 := in.clone() + + in.ScopeId = prj.GetPublicId() + got, err := repo.CreateCatalog(context.Background(), in) + assert.NoError(err) + assert.NotNil(got) + assertPublicId(t, "sthc", got.PublicId) + assert.NotSame(in, got) + assert.Equal(in.Name, got.Name) + assert.Equal(in.Description, got.Description) + assert.Equal(got.CreateTime, got.UpdateTime) + + in2.ScopeId = org.GetPublicId() + got2, err := repo.CreateCatalog(context.Background(), in2) + assert.NoError(err) + assert.NotNil(got2) + assertPublicId(t, "sthc", got2.PublicId) + assert.NotSame(in2, got2) + assert.Equal(in2.Name, got2.Name) + assert.Equal(in2.Description, got2.Description) + assert.Equal(got2.CreateTime, got2.UpdateTime) + }) +} + +func assertPublicId(t *testing.T, prefix, actual string) { + t.Helper() + assert.NotEmpty(t, actual) + parts := strings.Split(actual, "_") + assert.Equalf(t, 2, len(parts), "want one '_' in PublicId, got multiple in %q", actual) + assert.Equalf(t, prefix, parts[0], "PublicId want prefix: %q, got: %q in %q", prefix, parts[0], actual) +} + +func TestRepository_UpdateCatalog(t *testing.T) { + conn, _ := db.TestSetup(t, "postgres") + rw := db.New(conn) + wrapper := db.TestWrapper(t) + + changeName := func(s string) func(*HostCatalog) *HostCatalog { + return func(c *HostCatalog) *HostCatalog { + c.Name = s + return c + } + } + + changeDescription := func(s string) func(*HostCatalog) *HostCatalog { + return func(c *HostCatalog) *HostCatalog { + c.Description = s + return c + } + } + + makeNil := func() func(*HostCatalog) *HostCatalog { + return func(c *HostCatalog) *HostCatalog { + return nil + } + } + + makeEmbeddedNil := func() func(*HostCatalog) *HostCatalog { + return func(c *HostCatalog) *HostCatalog { + return &HostCatalog{} + } + } + + deletePublicId := func() func(*HostCatalog) *HostCatalog { + return func(c *HostCatalog) *HostCatalog { + c.PublicId = "" + return c + } + } + + nonExistentPublicId := func() func(*HostCatalog) *HostCatalog { + return func(c *HostCatalog) *HostCatalog { + c.PublicId = "sthc_OOOOOOOOOO" + return c + } + } + + combine := func(fns ...func(c *HostCatalog) *HostCatalog) func(*HostCatalog) *HostCatalog { + return func(c *HostCatalog) *HostCatalog { + for _, fn := range fns { + c = fn(c) + } + return c + } + } + + var tests = []struct { + name string + orig *HostCatalog + chgFn func(*HostCatalog) *HostCatalog + masks []string + want *HostCatalog + wantCount int + wantIsErr error + }{ + { + name: "nil-catalog", + orig: &HostCatalog{ + HostCatalog: &store.HostCatalog{}, + }, + chgFn: makeNil(), + masks: []string{"Name", "Description"}, + wantIsErr: db.ErrNilParameter, + }, + { + name: "nil-embedded-catalog", + orig: &HostCatalog{ + HostCatalog: &store.HostCatalog{}, + }, + chgFn: makeEmbeddedNil(), + masks: []string{"Name", "Description"}, + wantIsErr: db.ErrNilParameter, + }, + { + name: "no-public-id", + orig: &HostCatalog{ + HostCatalog: &store.HostCatalog{}, + }, + chgFn: deletePublicId(), + masks: []string{"Name", "Description"}, + wantIsErr: db.ErrInvalidParameter, + }, + { + name: "updating-non-existent-catalog", + orig: &HostCatalog{ + HostCatalog: &store.HostCatalog{ + Name: "test-name-repo", + }, + }, + chgFn: combine(nonExistentPublicId(), changeName("test-update-name-repo")), + masks: []string{"Name"}, + wantIsErr: db.ErrRecordNotFound, + }, + { + name: "empty-field-mask", + orig: &HostCatalog{ + HostCatalog: &store.HostCatalog{ + Name: "test-name-repo", + }, + }, + chgFn: changeName("test-update-name-repo"), + wantIsErr: db.ErrEmptyFieldMask, + }, + { + name: "read-only-fields-in-field-mask", + orig: &HostCatalog{ + HostCatalog: &store.HostCatalog{ + Name: "test-name-repo", + }, + }, + chgFn: changeName("test-update-name-repo"), + masks: []string{"PublicId", "CreateTime", "UpdateTime", "ScopeId"}, + wantIsErr: db.ErrInvalidFieldMask, + }, + { + name: "unknown-field-in-field-mask", + orig: &HostCatalog{ + HostCatalog: &store.HostCatalog{ + Name: "test-name-repo", + }, + }, + chgFn: changeName("test-update-name-repo"), + masks: []string{"Bilbo"}, + wantIsErr: db.ErrInvalidFieldMask, + }, + { + name: "change-name", + orig: &HostCatalog{ + HostCatalog: &store.HostCatalog{ + Name: "test-name-repo", + }, + }, + chgFn: changeName("test-update-name-repo"), + masks: []string{"Name"}, + want: &HostCatalog{ + HostCatalog: &store.HostCatalog{ + Name: "test-update-name-repo", + }, + }, + wantCount: 1, + }, + { + name: "change-description", + orig: &HostCatalog{ + HostCatalog: &store.HostCatalog{ + Description: "test-description-repo", + }, + }, + chgFn: changeDescription("test-update-description-repo"), + masks: []string{"Description"}, + want: &HostCatalog{ + HostCatalog: &store.HostCatalog{ + Description: "test-update-description-repo", + }, + }, + wantCount: 1, + }, + { + name: "change-name-and-description", + orig: &HostCatalog{ + HostCatalog: &store.HostCatalog{ + Name: "test-name-repo", + Description: "test-description-repo", + }, + }, + chgFn: combine(changeDescription("test-update-description-repo"), changeName("test-update-name-repo")), + masks: []string{"Name", "Description"}, + want: &HostCatalog{ + HostCatalog: &store.HostCatalog{ + Name: "test-update-name-repo", + Description: "test-update-description-repo", + }, + }, + wantCount: 1, + }, + { + name: "delete-name", + orig: &HostCatalog{ + HostCatalog: &store.HostCatalog{ + Name: "test-name-repo", + Description: "test-description-repo", + }, + }, + masks: []string{"Name"}, + chgFn: combine(changeDescription("test-update-description-repo"), changeName("")), + want: &HostCatalog{ + HostCatalog: &store.HostCatalog{ + Description: "test-description-repo", + }, + }, + wantCount: 1, + }, + { + name: "delete-description", + orig: &HostCatalog{ + HostCatalog: &store.HostCatalog{ + Name: "test-name-repo", + Description: "test-description-repo", + }, + }, + masks: []string{"Description"}, + chgFn: combine(changeDescription(""), changeName("test-update-name-repo")), + want: &HostCatalog{ + HostCatalog: &store.HostCatalog{ + Name: "test-name-repo", + }, + }, + wantCount: 1, + }, + { + name: "do-not-delete-name", + orig: &HostCatalog{ + HostCatalog: &store.HostCatalog{ + Name: "test-name-repo", + Description: "test-description-repo", + }, + }, + masks: []string{"Description"}, + chgFn: combine(changeDescription("test-update-description-repo"), changeName("")), + want: &HostCatalog{ + HostCatalog: &store.HostCatalog{ + Name: "test-name-repo", + Description: "test-update-description-repo", + }, + }, + wantCount: 1, + }, + { + name: "do-not-delete-description", + orig: &HostCatalog{ + HostCatalog: &store.HostCatalog{ + Name: "test-name-repo", + Description: "test-description-repo", + }, + }, + masks: []string{"Name"}, + chgFn: combine(changeDescription(""), changeName("test-update-name-repo")), + want: &HostCatalog{ + HostCatalog: &store.HostCatalog{ + Name: "test-update-name-repo", + Description: "test-description-repo", + }, + }, + wantCount: 1, + }, + } + + for _, tt := range tests { + tt := tt + t.Run(tt.name, func(t *testing.T) { + assert := assert.New(t) + repo, err := NewRepository(rw, rw, wrapper) + assert.NoError(err) + assert.NotNil(repo) + _, prj := iam.TestScopes(t, conn) + tt.orig.ScopeId = prj.GetPublicId() + orig, err := repo.CreateCatalog(context.Background(), tt.orig) + require.NoError(t, err) + require.NotNil(t, orig) + + if tt.chgFn != nil { + orig = tt.chgFn(orig) + } + got, gotCount, err := repo.UpdateCatalog(context.Background(), orig, 1, tt.masks) + if tt.wantIsErr != nil { + assert.Truef(errors.Is(err, tt.wantIsErr), "want err: %q got: %q", tt.wantIsErr, err) + assert.Equal(tt.wantCount, gotCount, "row count") + assert.Nil(got) + return + } + assert.NoError(err) + assert.Empty(tt.orig.PublicId) + assert.NotNil(got) + assertPublicId(t, "sthc", got.PublicId) + assert.Equal(tt.wantCount, gotCount, "row count") + assert.NotSame(tt.orig, got) + assert.Equal(tt.orig.ScopeId, got.ScopeId) + dbassert := dbassert.New(t, rw) + if tt.want.Name == "" { + dbassert.IsNull(got, "name") + return + } + assert.Equal(tt.want.Name, got.Name) + if tt.want.Description == "" { + dbassert.IsNull(got, "description") + return + } + assert.Equal(tt.want.Description, got.Description) + }) + } + + t.Run("invalid-duplicate-names", func(t *testing.T) { + assert := assert.New(t) + repo, err := NewRepository(rw, rw, wrapper) + assert.NoError(err) + assert.NotNil(repo) + + name := "test-dup-name" + cats := testCatalogs(t, conn, 2) + c1 := cats[0] + c1.Name = name + got1, gotCount1, err := repo.UpdateCatalog(context.Background(), c1, 1, []string{"name"}) + assert.NoError(err) + assert.NotNil(got1) + assert.Equal(name, got1.Name) + assert.Equal(1, gotCount1, "row count") + + c2 := cats[1] + c2.Name = name + got2, gotCount2, err := repo.UpdateCatalog(context.Background(), c2, 1, []string{"name"}) + assert.Truef(errors.Is(err, db.ErrNotUnique), "want err: %v got: %v", db.ErrNotUnique, err) + assert.Nil(got2) + assert.Equal(db.NoRowsAffected, gotCount2, "row count") + }) + + t.Run("valid-duplicate-names-diff-scopes", func(t *testing.T) { + assert := assert.New(t) + repo, err := NewRepository(rw, rw, wrapper) + assert.NoError(err) + assert.NotNil(repo) + + org, prj := iam.TestScopes(t, conn) + in := &HostCatalog{ + HostCatalog: &store.HostCatalog{ + Name: "test-name-repo", + }, + } + in2 := in.clone() + + in.ScopeId = prj.GetPublicId() + got, err := repo.CreateCatalog(context.Background(), in) + assert.NoError(err) + assert.NotNil(got) + assertPublicId(t, "sthc", got.PublicId) + assert.NotSame(in, got) + assert.Equal(in.Name, got.Name) + assert.Equal(in.Description, got.Description) + + in2.ScopeId = org.GetPublicId() + in2.Name = "first-name" + got2, err := repo.CreateCatalog(context.Background(), in2) + assert.NoError(err) + assert.NotNil(got2) + got2.Name = got.Name + got3, gotCount3, err := repo.UpdateCatalog(context.Background(), got2, 1, []string{"name"}) + assert.NoError(err) + assert.NotNil(got3) + assert.NotSame(got2, got3) + assert.Equal(got.Name, got3.Name) + assert.Equal(got2.Description, got3.Description) + assert.Equal(1, gotCount3, "row count") + }) + + t.Run("change-scope-id", func(t *testing.T) { + assert := assert.New(t) + repo, err := NewRepository(rw, rw, wrapper) + assert.NoError(err) + assert.NotNil(repo) + + c1, c2 := testCatalog(t, conn), testCatalog(t, conn) + assert.NotEqual(c1.ScopeId, c2.ScopeId) + orig := c1.clone() + + c1.ScopeId = c2.ScopeId + assert.Equal(c1.ScopeId, c2.ScopeId) + + got1, gotCount1, err := repo.UpdateCatalog(context.Background(), c1, 1, []string{"name"}) + + assert.NoError(err) + assert.NotNil(got1) + assert.Equal(orig.ScopeId, got1.ScopeId) + assert.Equal(1, gotCount1, "row count") + }) +} + +func TestRepository_LookupCatalog(t *testing.T) { + conn, _ := db.TestSetup(t, "postgres") + cat := testCatalog(t, conn) + badId, err := newHostCatalogId() + assert.NoError(t, err) + assert.NotNil(t, badId) + + rw := db.New(conn) + wrapper := db.TestWrapper(t) + + var tests = []struct { + name string + id string + want *HostCatalog + wantErr error + }{ + { + name: "found", + id: cat.GetPublicId(), + want: cat, + }, + { + name: "not-found", + id: badId, + want: nil, + }, + { + name: "bad-public-id", + id: "", + want: nil, + wantErr: db.ErrInvalidParameter, + }, + } + + for _, tt := range tests { + tt := tt + t.Run(tt.name, func(t *testing.T) { + assert := assert.New(t) + repo, err := NewRepository(rw, rw, wrapper) + assert.NoError(err) + assert.NotNil(repo) + + got, err := repo.LookupCatalog(context.Background(), tt.id) + if tt.wantErr != nil { + assert.Truef(errors.Is(err, tt.wantErr), "want err: %q got: %q", tt.wantErr, err) + return + } + assert.NoError(err) + + switch { + case tt.want == nil: + assert.Nil(got) + case tt.want != nil: + assert.NotNil(got) + assert.Equal(got, tt.want) + } + }) + } +} + +func TestRepository_DeleteCatalog(t *testing.T) { + conn, _ := db.TestSetup(t, "postgres") + cat := testCatalog(t, conn) + badId, err := newHostCatalogId() + assert.NoError(t, err) + assert.NotNil(t, badId) + + rw := db.New(conn) + wrapper := db.TestWrapper(t) + + var tests = []struct { + name string + id string + want int + wantErr error + }{ + { + name: "found", + id: cat.GetPublicId(), + want: 1, + }, + { + name: "not-found", + id: badId, + want: 0, + }, + { + name: "bad-public-id", + id: "", + want: 0, + wantErr: db.ErrInvalidParameter, + }, + } + + for _, tt := range tests { + tt := tt + t.Run(tt.name, func(t *testing.T) { + assert := assert.New(t) + repo, err := NewRepository(rw, rw, wrapper) + assert.NoError(err) + assert.NotNil(repo) + + got, err := repo.DeleteCatalog(context.Background(), tt.id) + if tt.wantErr != nil { + assert.Truef(errors.Is(err, tt.wantErr), "want err: %q got: %q", tt.wantErr, err) + return + } + assert.NoError(err) + assert.Equal(tt.want, got, "row count") + }) + } +} diff --git a/internal/host/static/repository_test.go b/internal/host/static/repository_test.go index 1b85e5383..fa31da458 100644 --- a/internal/host/static/repository_test.go +++ b/internal/host/static/repository_test.go @@ -1,20 +1,13 @@ package static import ( - "context" "errors" - "strings" "testing" wrapping "github.com/hashicorp/go-kms-wrapping" "github.com/stretchr/testify/assert" - "github.com/stretchr/testify/require" - - dbassert "github.com/hashicorp/boundary/internal/db/assert" "github.com/hashicorp/boundary/internal/db" - "github.com/hashicorp/boundary/internal/host/static/store" - "github.com/hashicorp/boundary/internal/iam" ) func TestRepository_New(t *testing.T) { @@ -104,658 +97,3 @@ func TestRepository_New(t *testing.T) { }) } } - -func TestRepository_CreateCatalog(t *testing.T) { - conn, _ := db.TestSetup(t, "postgres") - rw := db.New(conn) - wrapper := db.TestWrapper(t) - - var tests = []struct { - name string - in *HostCatalog - opts []Option - want *HostCatalog - wantIsErr error - }{ - { - name: "nil-catalog", - wantIsErr: db.ErrNilParameter, - }, - { - name: "nil-embedded-catalog", - in: &HostCatalog{}, - wantIsErr: db.ErrNilParameter, - }, - { - name: "valid-no-options", - in: &HostCatalog{ - HostCatalog: &store.HostCatalog{}, - }, - want: &HostCatalog{ - HostCatalog: &store.HostCatalog{}, - }, - }, - { - name: "valid-with-name", - in: &HostCatalog{ - HostCatalog: &store.HostCatalog{ - Name: "test-name-repo", - }, - }, - want: &HostCatalog{ - HostCatalog: &store.HostCatalog{ - Name: "test-name-repo", - }, - }, - }, - { - name: "valid-with-description", - in: &HostCatalog{ - HostCatalog: &store.HostCatalog{ - Description: ("test-description-repo"), - }, - }, - want: &HostCatalog{ - HostCatalog: &store.HostCatalog{ - Description: ("test-description-repo"), - }, - }, - }, - } - - for _, tt := range tests { - tt := tt - t.Run(tt.name, func(t *testing.T) { - assert := assert.New(t) - repo, err := NewRepository(rw, rw, wrapper) - assert.NoError(err) - assert.NotNil(repo) - _, prj := iam.TestScopes(t, conn) - if tt.in != nil && tt.in.HostCatalog != nil { - tt.in.ScopeId = prj.GetPublicId() - assert.Empty(tt.in.PublicId) - } - got, err := repo.CreateCatalog(context.Background(), tt.in, tt.opts...) - if tt.wantIsErr != nil { - assert.Truef(errors.Is(err, tt.wantIsErr), "want err: %q got: %q", tt.wantIsErr, err) - assert.Nil(got) - return - } - assert.NoError(err) - assert.Empty(tt.in.PublicId) - assert.NotNil(got) - assertPublicId(t, "sthc", got.PublicId) - assert.NotSame(tt.in, got) - assert.Equal(tt.want.Name, got.Name) - assert.Equal(tt.want.Description, got.Description) - assert.Equal(got.CreateTime, got.UpdateTime) - }) - } - - t.Run("invalid-duplicate-names", func(t *testing.T) { - assert := assert.New(t) - repo, err := NewRepository(rw, rw, wrapper) - assert.NoError(err) - assert.NotNil(repo) - - _, prj := iam.TestScopes(t, conn) - in := &HostCatalog{ - HostCatalog: &store.HostCatalog{ - ScopeId: prj.GetPublicId(), - Name: "test-name-repo", - }, - } - - got, err := repo.CreateCatalog(context.Background(), in) - assert.NoError(err) - assert.NotNil(got) - assertPublicId(t, "sthc", got.PublicId) - assert.NotSame(in, got) - assert.Equal(in.Name, got.Name) - assert.Equal(in.Description, got.Description) - assert.Equal(got.CreateTime, got.UpdateTime) - - got2, err := repo.CreateCatalog(context.Background(), in) - assert.Truef(errors.Is(err, db.ErrNotUnique), "want err: %v got: %v", db.ErrNotUnique, err) - assert.Nil(got2) - }) - - t.Run("valid-duplicate-names-diff-scopes", func(t *testing.T) { - assert := assert.New(t) - repo, err := NewRepository(rw, rw, wrapper) - assert.NoError(err) - assert.NotNil(repo) - - org, prj := iam.TestScopes(t, conn) - in := &HostCatalog{ - HostCatalog: &store.HostCatalog{ - Name: "test-name-repo", - }, - } - in2 := in.clone() - - in.ScopeId = prj.GetPublicId() - got, err := repo.CreateCatalog(context.Background(), in) - assert.NoError(err) - assert.NotNil(got) - assertPublicId(t, "sthc", got.PublicId) - assert.NotSame(in, got) - assert.Equal(in.Name, got.Name) - assert.Equal(in.Description, got.Description) - assert.Equal(got.CreateTime, got.UpdateTime) - - in2.ScopeId = org.GetPublicId() - got2, err := repo.CreateCatalog(context.Background(), in2) - assert.NoError(err) - assert.NotNil(got2) - assertPublicId(t, "sthc", got2.PublicId) - assert.NotSame(in2, got2) - assert.Equal(in2.Name, got2.Name) - assert.Equal(in2.Description, got2.Description) - assert.Equal(got2.CreateTime, got2.UpdateTime) - }) -} - -func assertPublicId(t *testing.T, prefix, actual string) { - t.Helper() - assert.NotEmpty(t, actual) - parts := strings.Split(actual, "_") - assert.Equalf(t, 2, len(parts), "want one '_' in PublicId, got multiple in %q", actual) - assert.Equalf(t, prefix, parts[0], "PublicId want prefix: %q, got: %q in %q", prefix, parts[0], actual) -} - -func TestRepository_UpdateCatalog(t *testing.T) { - conn, _ := db.TestSetup(t, "postgres") - rw := db.New(conn) - wrapper := db.TestWrapper(t) - - changeName := func(s string) func(*HostCatalog) *HostCatalog { - return func(c *HostCatalog) *HostCatalog { - c.Name = s - return c - } - } - - changeDescription := func(s string) func(*HostCatalog) *HostCatalog { - return func(c *HostCatalog) *HostCatalog { - c.Description = s - return c - } - } - - makeNil := func() func(*HostCatalog) *HostCatalog { - return func(c *HostCatalog) *HostCatalog { - return nil - } - } - - makeEmbeddedNil := func() func(*HostCatalog) *HostCatalog { - return func(c *HostCatalog) *HostCatalog { - return &HostCatalog{} - } - } - - deletePublicId := func() func(*HostCatalog) *HostCatalog { - return func(c *HostCatalog) *HostCatalog { - c.PublicId = "" - return c - } - } - - nonExistentPublicId := func() func(*HostCatalog) *HostCatalog { - return func(c *HostCatalog) *HostCatalog { - c.PublicId = "sthc_OOOOOOOOOO" - return c - } - } - - combine := func(fns ...func(c *HostCatalog) *HostCatalog) func(*HostCatalog) *HostCatalog { - return func(c *HostCatalog) *HostCatalog { - for _, fn := range fns { - c = fn(c) - } - return c - } - } - - var tests = []struct { - name string - orig *HostCatalog - chgFn func(*HostCatalog) *HostCatalog - masks []string - want *HostCatalog - wantCount int - wantIsErr error - }{ - { - name: "nil-catalog", - orig: &HostCatalog{ - HostCatalog: &store.HostCatalog{}, - }, - chgFn: makeNil(), - masks: []string{"Name", "Description"}, - wantIsErr: db.ErrNilParameter, - }, - { - name: "nil-embedded-catalog", - orig: &HostCatalog{ - HostCatalog: &store.HostCatalog{}, - }, - chgFn: makeEmbeddedNil(), - masks: []string{"Name", "Description"}, - wantIsErr: db.ErrNilParameter, - }, - { - name: "no-public-id", - orig: &HostCatalog{ - HostCatalog: &store.HostCatalog{}, - }, - chgFn: deletePublicId(), - masks: []string{"Name", "Description"}, - wantIsErr: db.ErrInvalidParameter, - }, - { - name: "updating-non-existent-catalog", - orig: &HostCatalog{ - HostCatalog: &store.HostCatalog{ - Name: "test-name-repo", - }, - }, - chgFn: combine(nonExistentPublicId(), changeName("test-update-name-repo")), - masks: []string{"Name"}, - wantIsErr: db.ErrRecordNotFound, - }, - { - name: "empty-field-mask", - orig: &HostCatalog{ - HostCatalog: &store.HostCatalog{ - Name: "test-name-repo", - }, - }, - chgFn: changeName("test-update-name-repo"), - wantIsErr: db.ErrEmptyFieldMask, - }, - { - name: "read-only-fields-in-field-mask", - orig: &HostCatalog{ - HostCatalog: &store.HostCatalog{ - Name: "test-name-repo", - }, - }, - chgFn: changeName("test-update-name-repo"), - masks: []string{"PublicId", "CreateTime", "UpdateTime", "ScopeId"}, - wantIsErr: db.ErrInvalidFieldMask, - }, - { - name: "unknown-field-in-field-mask", - orig: &HostCatalog{ - HostCatalog: &store.HostCatalog{ - Name: "test-name-repo", - }, - }, - chgFn: changeName("test-update-name-repo"), - masks: []string{"Bilbo"}, - wantIsErr: db.ErrInvalidFieldMask, - }, - { - name: "change-name", - orig: &HostCatalog{ - HostCatalog: &store.HostCatalog{ - Name: "test-name-repo", - }, - }, - chgFn: changeName("test-update-name-repo"), - masks: []string{"Name"}, - want: &HostCatalog{ - HostCatalog: &store.HostCatalog{ - Name: "test-update-name-repo", - }, - }, - wantCount: 1, - }, - { - name: "change-description", - orig: &HostCatalog{ - HostCatalog: &store.HostCatalog{ - Description: "test-description-repo", - }, - }, - chgFn: changeDescription("test-update-description-repo"), - masks: []string{"Description"}, - want: &HostCatalog{ - HostCatalog: &store.HostCatalog{ - Description: "test-update-description-repo", - }, - }, - wantCount: 1, - }, - { - name: "change-name-and-description", - orig: &HostCatalog{ - HostCatalog: &store.HostCatalog{ - Name: "test-name-repo", - Description: "test-description-repo", - }, - }, - chgFn: combine(changeDescription("test-update-description-repo"), changeName("test-update-name-repo")), - masks: []string{"Name", "Description"}, - want: &HostCatalog{ - HostCatalog: &store.HostCatalog{ - Name: "test-update-name-repo", - Description: "test-update-description-repo", - }, - }, - wantCount: 1, - }, - { - name: "delete-name", - orig: &HostCatalog{ - HostCatalog: &store.HostCatalog{ - Name: "test-name-repo", - Description: "test-description-repo", - }, - }, - masks: []string{"Name"}, - chgFn: combine(changeDescription("test-update-description-repo"), changeName("")), - want: &HostCatalog{ - HostCatalog: &store.HostCatalog{ - Description: "test-description-repo", - }, - }, - wantCount: 1, - }, - { - name: "delete-description", - orig: &HostCatalog{ - HostCatalog: &store.HostCatalog{ - Name: "test-name-repo", - Description: "test-description-repo", - }, - }, - masks: []string{"Description"}, - chgFn: combine(changeDescription(""), changeName("test-update-name-repo")), - want: &HostCatalog{ - HostCatalog: &store.HostCatalog{ - Name: "test-name-repo", - }, - }, - wantCount: 1, - }, - { - name: "do-not-delete-name", - orig: &HostCatalog{ - HostCatalog: &store.HostCatalog{ - Name: "test-name-repo", - Description: "test-description-repo", - }, - }, - masks: []string{"Description"}, - chgFn: combine(changeDescription("test-update-description-repo"), changeName("")), - want: &HostCatalog{ - HostCatalog: &store.HostCatalog{ - Name: "test-name-repo", - Description: "test-update-description-repo", - }, - }, - wantCount: 1, - }, - { - name: "do-not-delete-description", - orig: &HostCatalog{ - HostCatalog: &store.HostCatalog{ - Name: "test-name-repo", - Description: "test-description-repo", - }, - }, - masks: []string{"Name"}, - chgFn: combine(changeDescription(""), changeName("test-update-name-repo")), - want: &HostCatalog{ - HostCatalog: &store.HostCatalog{ - Name: "test-update-name-repo", - Description: "test-description-repo", - }, - }, - wantCount: 1, - }, - } - - for _, tt := range tests { - tt := tt - t.Run(tt.name, func(t *testing.T) { - assert := assert.New(t) - repo, err := NewRepository(rw, rw, wrapper) - assert.NoError(err) - assert.NotNil(repo) - _, prj := iam.TestScopes(t, conn) - tt.orig.ScopeId = prj.GetPublicId() - orig, err := repo.CreateCatalog(context.Background(), tt.orig) - require.NoError(t, err) - require.NotNil(t, orig) - - if tt.chgFn != nil { - orig = tt.chgFn(orig) - } - got, gotCount, err := repo.UpdateCatalog(context.Background(), orig, 1, tt.masks) - if tt.wantIsErr != nil { - assert.Truef(errors.Is(err, tt.wantIsErr), "want err: %q got: %q", tt.wantIsErr, err) - assert.Equal(tt.wantCount, gotCount, "row count") - assert.Nil(got) - return - } - assert.NoError(err) - assert.Empty(tt.orig.PublicId) - assert.NotNil(got) - assertPublicId(t, "sthc", got.PublicId) - assert.Equal(tt.wantCount, gotCount, "row count") - assert.NotSame(tt.orig, got) - assert.Equal(tt.orig.ScopeId, got.ScopeId) - dbassert := dbassert.New(t, rw) - if tt.want.Name == "" { - dbassert.IsNull(got, "name") - return - } - assert.Equal(tt.want.Name, got.Name) - if tt.want.Description == "" { - dbassert.IsNull(got, "description") - return - } - assert.Equal(tt.want.Description, got.Description) - }) - } - - t.Run("invalid-duplicate-names", func(t *testing.T) { - assert := assert.New(t) - repo, err := NewRepository(rw, rw, wrapper) - assert.NoError(err) - assert.NotNil(repo) - - name := "test-dup-name" - cats := testCatalogs(t, conn, 2) - c1 := cats[0] - c1.Name = name - got1, gotCount1, err := repo.UpdateCatalog(context.Background(), c1, 1, []string{"name"}) - assert.NoError(err) - assert.NotNil(got1) - assert.Equal(name, got1.Name) - assert.Equal(1, gotCount1, "row count") - - c2 := cats[1] - c2.Name = name - got2, gotCount2, err := repo.UpdateCatalog(context.Background(), c2, 1, []string{"name"}) - assert.Truef(errors.Is(err, db.ErrNotUnique), "want err: %v got: %v", db.ErrNotUnique, err) - assert.Nil(got2) - assert.Equal(db.NoRowsAffected, gotCount2, "row count") - }) - - t.Run("valid-duplicate-names-diff-scopes", func(t *testing.T) { - assert := assert.New(t) - repo, err := NewRepository(rw, rw, wrapper) - assert.NoError(err) - assert.NotNil(repo) - - org, prj := iam.TestScopes(t, conn) - in := &HostCatalog{ - HostCatalog: &store.HostCatalog{ - Name: "test-name-repo", - }, - } - in2 := in.clone() - - in.ScopeId = prj.GetPublicId() - got, err := repo.CreateCatalog(context.Background(), in) - assert.NoError(err) - assert.NotNil(got) - assertPublicId(t, "sthc", got.PublicId) - assert.NotSame(in, got) - assert.Equal(in.Name, got.Name) - assert.Equal(in.Description, got.Description) - - in2.ScopeId = org.GetPublicId() - in2.Name = "first-name" - got2, err := repo.CreateCatalog(context.Background(), in2) - assert.NoError(err) - assert.NotNil(got2) - got2.Name = got.Name - got3, gotCount3, err := repo.UpdateCatalog(context.Background(), got2, 1, []string{"name"}) - assert.NoError(err) - assert.NotNil(got3) - assert.NotSame(got2, got3) - assert.Equal(got.Name, got3.Name) - assert.Equal(got2.Description, got3.Description) - assert.Equal(1, gotCount3, "row count") - }) - - t.Run("change-scope-id", func(t *testing.T) { - assert := assert.New(t) - repo, err := NewRepository(rw, rw, wrapper) - assert.NoError(err) - assert.NotNil(repo) - - c1, c2 := testCatalog(t, conn), testCatalog(t, conn) - assert.NotEqual(c1.ScopeId, c2.ScopeId) - orig := c1.clone() - - c1.ScopeId = c2.ScopeId - assert.Equal(c1.ScopeId, c2.ScopeId) - - got1, gotCount1, err := repo.UpdateCatalog(context.Background(), c1, 1, []string{"name"}) - - assert.NoError(err) - assert.NotNil(got1) - assert.Equal(orig.ScopeId, got1.ScopeId) - assert.Equal(1, gotCount1, "row count") - }) -} - -func TestRepository_LookupCatalog(t *testing.T) { - conn, _ := db.TestSetup(t, "postgres") - cat := testCatalog(t, conn) - badId, err := newHostCatalogId() - assert.NoError(t, err) - assert.NotNil(t, badId) - - rw := db.New(conn) - wrapper := db.TestWrapper(t) - - var tests = []struct { - name string - id string - want *HostCatalog - wantErr error - }{ - { - name: "found", - id: cat.GetPublicId(), - want: cat, - }, - { - name: "not-found", - id: badId, - want: nil, - }, - { - name: "bad-public-id", - id: "", - want: nil, - wantErr: db.ErrInvalidParameter, - }, - } - - for _, tt := range tests { - tt := tt - t.Run(tt.name, func(t *testing.T) { - assert := assert.New(t) - repo, err := NewRepository(rw, rw, wrapper) - assert.NoError(err) - assert.NotNil(repo) - - got, err := repo.LookupCatalog(context.Background(), tt.id) - if tt.wantErr != nil { - assert.Truef(errors.Is(err, tt.wantErr), "want err: %q got: %q", tt.wantErr, err) - return - } - assert.NoError(err) - - switch { - case tt.want == nil: - assert.Nil(got) - case tt.want != nil: - assert.NotNil(got) - assert.Equal(got, tt.want) - } - }) - } -} - -func TestRepository_DeleteCatalog(t *testing.T) { - conn, _ := db.TestSetup(t, "postgres") - cat := testCatalog(t, conn) - badId, err := newHostCatalogId() - assert.NoError(t, err) - assert.NotNil(t, badId) - - rw := db.New(conn) - wrapper := db.TestWrapper(t) - - var tests = []struct { - name string - id string - want int - wantErr error - }{ - { - name: "found", - id: cat.GetPublicId(), - want: 1, - }, - { - name: "not-found", - id: badId, - want: 0, - }, - { - name: "bad-public-id", - id: "", - want: 0, - wantErr: db.ErrInvalidParameter, - }, - } - - for _, tt := range tests { - tt := tt - t.Run(tt.name, func(t *testing.T) { - assert := assert.New(t) - repo, err := NewRepository(rw, rw, wrapper) - assert.NoError(err) - assert.NotNil(repo) - - got, err := repo.DeleteCatalog(context.Background(), tt.id) - if tt.wantErr != nil { - assert.Truef(errors.Is(err, tt.wantErr), "want err: %q got: %q", tt.wantErr, err) - return - } - assert.NoError(err) - assert.Equal(tt.want, got, "row count") - }) - } -} diff --git a/internal/host/static/static.go b/internal/host/static/static.go deleted file mode 100644 index d36c53f82..000000000 --- a/internal/host/static/static.go +++ /dev/null @@ -1,151 +0,0 @@ -package static - -import ( - "fmt" - - "github.com/hashicorp/boundary/internal/db" - "github.com/hashicorp/boundary/internal/host/static/store" - "google.golang.org/protobuf/proto" -) - -// A HostCatalog contains static hosts and static host sets. It is owned by -// a scope. -type HostCatalog struct { - *store.HostCatalog - tableName string `gorm:"-"` -} - -// NewHostCatalog creates a new in memory HostCatalog assigned to scopeId. -// Name and description are the only valid options. All other options are -// ignored. -func NewHostCatalog(scopeId string, opt ...Option) (*HostCatalog, error) { - if scopeId == "" { - return nil, fmt.Errorf("new: static host catalog: no scope id: %w", db.ErrInvalidParameter) - } - - opts := getOpts(opt...) - hc := &HostCatalog{ - HostCatalog: &store.HostCatalog{ - ScopeId: scopeId, - Name: opts.withName, - Description: opts.withDescription, - }, - } - return hc, nil -} - -func (c *HostCatalog) clone() *HostCatalog { - cp := proto.Clone(c.HostCatalog) - return &HostCatalog{ - HostCatalog: cp.(*store.HostCatalog), - } -} - -// A Host contains a static address. -type Host struct { - *store.Host - tableName string `gorm:"-"` -} - -// NewHost creates a new in memory Host for address assigned to catalogId. -// Name and description are the only valid options. All other options are -// ignored. -func NewHost(catalogId, address string, opt ...Option) (*Host, error) { - if catalogId == "" { - return nil, fmt.Errorf("new: static host: no catalog id: %w", db.ErrInvalidParameter) - } - if address == "" { - return nil, fmt.Errorf("new: static host: no address: %w", db.ErrInvalidParameter) - } - - opts := getOpts(opt...) - host := &Host{ - Host: &store.Host{ - StaticHostCatalogId: catalogId, - Address: address, - Name: opts.withName, - Description: opts.withDescription, - }, - } - return host, nil -} - -// A HostSet is a collection of hosts from the set's catalog. -type HostSet struct { - *store.HostSet - tableName string `gorm:"-"` -} - -// NewHostSet creates a new in memory HostSet assigned to catalogId. -// Name and description are the only valid options. All other options are -// ignored. -func NewHostSet(catalogId string, opt ...Option) (*HostSet, error) { - if catalogId == "" { - return nil, fmt.Errorf("new: static host set: no catalog id: %w", db.ErrInvalidParameter) - } - - opts := getOpts(opt...) - set := &HostSet{ - HostSet: &store.HostSet{ - StaticHostCatalogId: catalogId, - Name: opts.withName, - Description: opts.withDescription, - }, - } - return set, nil -} - -// A HostSetMember represents the membership of a host in a host set. -type HostSetMember struct { - *store.HostSetMember - tableName string `gorm:"-"` -} - -// NewHostSetMember creates a new in memory HostSetMember representing the -// membership of hostId in hostSetId. -func NewHostSetMember(hostSetId, hostId string, opt ...Option) (*HostSetMember, error) { - if hostSetId == "" { - return nil, fmt.Errorf("new: static host set member: no host set id: %w", db.ErrInvalidParameter) - } - if hostId == "" { - return nil, fmt.Errorf("new: static host set member: no host id: %w", db.ErrInvalidParameter) - } - member := &HostSetMember{ - HostSetMember: &store.HostSetMember{ - StaticHostSetId: hostSetId, - StaticHostId: hostId, - }, - } - return member, nil -} - -// PublicId prefixes for the resources in the static package. -const ( - HostCatalogPrefix = "sthc" - HostSetPrefix = "sths" - HostPrefix = "sth" -) - -func newHostCatalogId() (string, error) { - id, err := db.NewPublicId(HostCatalogPrefix) - if err != nil { - return "", fmt.Errorf("new host catalog id: %w", err) - } - return id, err -} - -func newHostId() (string, error) { - id, err := db.NewPublicId(HostPrefix) - if err != nil { - return "", fmt.Errorf("new host id: %w", err) - } - return id, err -} - -func newHostSetId() (string, error) { - id, err := db.NewPublicId(HostSetPrefix) - if err != nil { - return "", fmt.Errorf("new host set id: %w", err) - } - return id, err -} diff --git a/internal/host/static/static_test.go b/internal/host/static/static_test.go deleted file mode 100644 index 2859c5445..000000000 --- a/internal/host/static/static_test.go +++ /dev/null @@ -1,474 +0,0 @@ -package static - -import ( - "context" - "fmt" - "testing" - - "github.com/hashicorp/boundary/internal/db" - "github.com/hashicorp/boundary/internal/host/static/store" - "github.com/hashicorp/boundary/internal/iam" - "github.com/jinzhu/gorm" - "github.com/stretchr/testify/assert" -) - -func TestHostCatalog_New(t *testing.T) { - conn, _ := db.TestSetup(t, "postgres") - _, prj := iam.TestScopes(t, conn) - - type args struct { - scopeId string - opts []Option - } - - var tests = []struct { - name string - args args - want *HostCatalog - wantErr bool - }{ - { - name: "blank-scopeId", - args: args{ - scopeId: "", - }, - want: nil, - wantErr: true, - }, - { - name: "valid-no-options", - args: args{ - scopeId: prj.GetPublicId(), - }, - want: &HostCatalog{ - HostCatalog: &store.HostCatalog{ - ScopeId: prj.GetPublicId(), - }, - }, - }, - { - name: "valid-with-name", - args: args{ - scopeId: prj.GetPublicId(), - opts: []Option{ - WithName("test-name"), - }, - }, - want: &HostCatalog{ - HostCatalog: &store.HostCatalog{ - ScopeId: prj.GetPublicId(), - Name: "test-name", - }, - }, - }, - { - name: "valid-with-description", - args: args{ - scopeId: prj.GetPublicId(), - opts: []Option{ - WithDescription("test-description"), - }, - }, - want: &HostCatalog{ - HostCatalog: &store.HostCatalog{ - ScopeId: prj.GetPublicId(), - Description: "test-description", - }, - }, - }, - } - - for _, tt := range tests { - tt := tt - t.Run(tt.name, func(t *testing.T) { - assert := assert.New(t) - got, err := NewHostCatalog(tt.args.scopeId, tt.args.opts...) - if tt.wantErr { - assert.Error(err) - assert.Nil(got) - } else { - assert.NoError(err) - if assert.NotNil(got) { - assert.Emptyf(got.PublicId, "PublicId set") - assert.Equal(tt.want, got) - - id, err := newHostCatalogId() - assert.NoError(err) - - tt.want.PublicId = id - got.PublicId = id - - w := db.New(conn) - err2 := w.Create(context.Background(), got) - assert.NoError(err2) - } - } - }) - } -} - -func testCatalogs(t *testing.T, conn *gorm.DB, count int) []*HostCatalog { - t.Helper() - assert := assert.New(t) - _, prj := iam.TestScopes(t, conn) - var cats []*HostCatalog - for i := 0; i < count; i++ { - cat, err := NewHostCatalog(prj.GetPublicId()) - 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 -} - -func testCatalog(t *testing.T, conn *gorm.DB) *HostCatalog { - t.Helper() - cats := testCatalogs(t, conn, 1) - return cats[0] -} - -func TestHost_New(t *testing.T) { - conn, _ := db.TestSetup(t, "postgres") - cat := testCatalog(t, conn) - - conn.LogMode(false) - type args struct { - catalogId string - address string - opts []Option - } - - var tests = []struct { - name string - args args - want *Host - wantCreateErr bool - wantWriteErr bool - }{ - { - name: "blank-catalogId", - args: args{ - catalogId: "", - address: "127.0.0.1", - }, - want: nil, - wantCreateErr: true, - }, - { - name: "blank-address", - args: args{ - catalogId: cat.GetPublicId(), - address: "", - }, - want: nil, - wantCreateErr: true, - }, - { - name: "address-to-short", - args: args{ - catalogId: cat.GetPublicId(), - address: "1234567", - }, - want: &Host{ - Host: &store.Host{ - StaticHostCatalogId: cat.GetPublicId(), - Address: "1234567", - }, - }, - wantWriteErr: true, - }, - { - name: "minimum-address", - args: args{ - catalogId: cat.GetPublicId(), - address: "12345678", - }, - want: &Host{ - Host: &store.Host{ - StaticHostCatalogId: cat.GetPublicId(), - Address: "12345678", - }, - }, - }, - { - name: "valid-no-options", - args: args{ - catalogId: cat.GetPublicId(), - address: "127.0.0.1", - }, - want: &Host{ - Host: &store.Host{ - StaticHostCatalogId: cat.GetPublicId(), - Address: "127.0.0.1", - }, - }, - }, - { - name: "valid-with-name", - args: args{ - catalogId: cat.GetPublicId(), - address: "127.0.0.1", - opts: []Option{ - WithName("test-name"), - }, - }, - want: &Host{ - Host: &store.Host{ - StaticHostCatalogId: cat.GetPublicId(), - Address: "127.0.0.1", - Name: "test-name", - }, - }, - }, - { - name: "valid-with-description", - args: args{ - catalogId: cat.GetPublicId(), - address: "127.0.0.1", - opts: []Option{ - WithDescription("test-description"), - }, - }, - want: &Host{ - Host: &store.Host{ - StaticHostCatalogId: cat.GetPublicId(), - Address: "127.0.0.1", - Description: "test-description", - }, - }, - }, - } - - for _, tt := range tests { - tt := tt - t.Run(tt.name, func(t *testing.T) { - assert := assert.New(t) - got, err := NewHost(tt.args.catalogId, tt.args.address, tt.args.opts...) - if tt.wantCreateErr { - assert.Error(err) - assert.Nil(got) - } else { - assert.NoError(err) - if assert.NotNil(got) { - assert.Emptyf(got.PublicId, "PublicId set") - assert.Equal(tt.want, got) - - id, err := newHostId() - assert.NoError(err) - - tt.want.PublicId = id - got.PublicId = id - - w := db.New(conn) - err2 := w.Create(context.Background(), got) - if tt.wantWriteErr { - assert.Error(err2) - } - } - } - }) - } -} - -func TestHostSet_New(t *testing.T) { - conn, _ := db.TestSetup(t, "postgres") - cat := testCatalog(t, conn) - - conn.LogMode(false) - type args struct { - catalogId string - opts []Option - } - - var tests = []struct { - name string - args args - want *HostSet - wantErr bool - }{ - { - name: "blank-catalogId", - args: args{ - catalogId: "", - }, - want: nil, - wantErr: true, - }, - { - name: "valid-no-options", - args: args{ - catalogId: cat.GetPublicId(), - }, - want: &HostSet{ - HostSet: &store.HostSet{ - StaticHostCatalogId: cat.GetPublicId(), - }, - }, - }, - { - name: "valid-with-name", - args: args{ - catalogId: cat.GetPublicId(), - opts: []Option{ - WithName("test-name"), - }, - }, - want: &HostSet{ - HostSet: &store.HostSet{ - StaticHostCatalogId: cat.GetPublicId(), - Name: "test-name", - }, - }, - }, - { - name: "valid-with-description", - args: args{ - catalogId: cat.GetPublicId(), - opts: []Option{ - WithDescription("test-description"), - }, - }, - want: &HostSet{ - HostSet: &store.HostSet{ - StaticHostCatalogId: cat.GetPublicId(), - Description: "test-description", - }, - }, - }, - } - - for _, tt := range tests { - tt := tt - t.Run(tt.name, func(t *testing.T) { - assert := assert.New(t) - got, err := NewHostSet(tt.args.catalogId, tt.args.opts...) - if tt.wantErr { - assert.Error(err) - assert.Nil(got) - } else { - assert.NoError(err) - if assert.NotNil(got) { - assert.Emptyf(got.PublicId, "PublicId set") - assert.Equal(tt.want, got) - - id, err := newHostSetId() - assert.NoError(err) - - tt.want.PublicId = id - got.PublicId = id - - w := db.New(conn) - err2 := w.Create(context.Background(), got) - assert.NoError(err2) - } - } - }) - } -} - -func testHosts(t *testing.T, conn *gorm.DB, catalogId string, count int) []*Host { - t.Helper() - assert := assert.New(t) - var hosts []*Host - - for i := 0; i < count; i++ { - host, err := NewHost(catalogId, fmt.Sprintf("%s-%d", catalogId, i)) - assert.NoError(err) - assert.NotNil(host) - - id, err := newHostCatalogId() - assert.NoError(err) - assert.NotEmpty(id) - host.PublicId = id - - w := db.New(conn) - err2 := w.Create(context.Background(), host) - assert.NoError(err2) - hosts = append(hosts, host) - } - return hosts -} - -func testSets(t *testing.T, conn *gorm.DB, catalogId string, count int) []*HostSet { - t.Helper() - assert := assert.New(t) - var sets []*HostSet - - for i := 0; i < count; i++ { - set, err := NewHostSet(catalogId) - assert.NoError(err) - assert.NotNil(set) - id, err := newHostSetId() - assert.NoError(err) - assert.NotEmpty(id) - set.PublicId = id - - w := db.New(conn) - err2 := w.Create(context.Background(), set) - assert.NoError(err2) - sets = append(sets, set) - } - return sets -} - -func TestHostSetMember_New(t *testing.T) { - conn, _ := db.TestSetup(t, "postgres") - conn.LogMode(false) - - cats := testCatalogs(t, conn, 2) - - blueCat := cats[0] - blueSets := testSets(t, conn, blueCat.GetPublicId(), 2) - blueHosts := testHosts(t, conn, blueCat.GetPublicId(), 2) - - // TODO(mgaffney) 05/2020: - // these will be needed when the repository code is done - // greenCat := cats[1] - // greenSets := testSets(t, conn, greenCat.GetPublicId(), 2) - // greenHosts := testHosts(t, conn, greenCat.GetPublicId(), 2) - - var tests = []struct { - name string - set *HostSet - host *Host - wantErr bool - }{ - { - name: "valid-host-in-set", - set: blueSets[0], - host: blueHosts[0], - }, - // { - // name: "invalid-diff-catalogs", - // set: greenSets[0], - // host: blueHosts[0], - // wantErr: true, - // }, - } - for _, tt := range tests { - tt := tt - t.Run(tt.name, func(t *testing.T) { - assert := assert.New(t) - got, err := NewHostSetMember(tt.set.PublicId, tt.host.PublicId) - if tt.wantErr { - assert.Error(err) - assert.Nil(got) - } else { - assert.NoError(err) - if assert.NotNil(got) { - w := db.New(conn) - err2 := w.Create(context.Background(), got) - assert.NoError(err2) - } - } - }) - } -}