Refactor static host package (#263)

* Refactor: inline tablename constants

* Refactor: move functionality to new files
This commit is contained in:
Michael Gaffney authored and GitHub committed 2020-08-13 14:00:15 -04:00
1 parent b75a6fc5e5
commit 7ac4be51c0
17 files changed
+1791 -1727

No files matched your search

-64
View File
@@ -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
}
-159
View File
@@ -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())
})
}
}
+51
View File
@@ -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
}
+76
View File
@@ -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
}
+172
View File
@@ -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())
})
}
}
+47
View File
@@ -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
}
+46
View File
@@ -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
}
@@ -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())
})
}
}
+168
View File
@@ -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())
})
}
}
+216
View File
@@ -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())
})
}
}
+38
View File
@@ -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
}
-217
View File
@@ -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
}
@@ -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
}
@@ -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")
})
}
}
-662
View File
@@ -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")
})
}
}
-151
View File
@@ -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
}
-474
View File
@@ -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)
}
}
})
}
}