You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
boundary/internal/plugin/loopback/host_test.go

376 lines
9.2 KiB

// Copyright (c) HashiCorp, Inc.
// SPDX-License-Identifier: BUSL-1.1
package loopback
import (
"context"
"testing"
"github.com/hashicorp/boundary/sdk/pbs/controller/api/resources/hostcatalogs"
"github.com/hashicorp/boundary/sdk/pbs/controller/api/resources/hostsets"
plgpb "github.com/hashicorp/boundary/sdk/pbs/plugin"
ta "github.com/stretchr/testify/assert"
tr "github.com/stretchr/testify/require"
"google.golang.org/protobuf/types/known/structpb"
)
// TestLoopbackHostPlugin is a quick test of basic host service functionality.
func TestLoopbackHostPlugin(t *testing.T) {
require, assert := tr.New(t), ta.New(t)
ctx := context.Background()
plg, err := NewLoopbackPlugin()
require.NoError(err)
secretsMap := map[string]any{
"key1": "key2",
"baz": true,
}
secrets, err := structpb.NewStruct(secretsMap)
require.NoError(err)
// First, test that if we give it secrets, those secrets come back as
// persisted data
catResp, err := plg.OnCreateCatalog(ctx, &plgpb.OnCreateCatalogRequest{
Catalog: &hostcatalogs.HostCatalog{
Secrets: secrets,
},
})
require.NoError(err)
require.NotNil(catResp)
require.NotNil(catResp.GetPersisted())
require.NotNil(catResp.GetPersisted().GetSecrets())
assert.EqualValues(secretsMap, catResp.GetPersisted().GetSecrets().AsMap())
newSecretsMap := map[string]any{
"key1": "key2",
"baz": true,
}
newSecrets, err := structpb.NewStruct(newSecretsMap)
require.NoError(err)
// First, test that if we give it secrets, those secrets come back as
// persisted data
upResp, err := plg.OnUpdateCatalog(ctx, &plgpb.OnUpdateCatalogRequest{
CurrentCatalog: &hostcatalogs.HostCatalog{},
NewCatalog: &hostcatalogs.HostCatalog{
Secrets: newSecrets,
},
Persisted: &plgpb.HostCatalogPersisted{
Secrets: secrets,
},
})
require.NoError(err)
require.NotNil(upResp)
require.NotNil(upResp.GetPersisted())
require.NotNil(upResp.GetPersisted().GetSecrets())
assert.EqualValues(newSecretsMap, upResp.GetPersisted().GetSecrets().AsMap())
// Add data to some sets
hostInfo1 := map[string]any{
loopbackPluginHostInfoAttrField: map[string]any{
"set_ids": []any{"set1"},
"external_id": "host1",
"ip_addresses": []any{"1.2.3.4", "2.3.4.5"},
"dns_names": []any{"foo.com"},
},
}
attrs, err := structpb.NewStruct(hostInfo1)
require.NoError(err)
_, err = plg.OnCreateSet(ctx, &plgpb.OnCreateSetRequest{
Set: &hostsets.HostSet{
Id: "set1",
Attrs: &hostsets.HostSet_Attributes{
Attributes: attrs,
},
},
})
require.NoError(err)
hostInfo2 := map[string]any{
loopbackPluginHostInfoAttrField: map[string]any{
"set_ids": []any{"set2"},
"external_id": "host2",
"ip_addresses": []any{"5.6.7.8", "6.7.8.9"},
"dns_names": []any{"bar.com"},
},
}
attrs, err = structpb.NewStruct(hostInfo2)
require.NoError(err)
_, err = plg.OnCreateSet(ctx, &plgpb.OnCreateSetRequest{
Set: &hostsets.HostSet{
Id: "set2",
Attrs: &hostsets.HostSet_Attributes{
Attributes: attrs,
},
},
})
require.NoError(err)
// Define test struct and validation function
type testInfo struct {
name string
sets []string
found []map[string]any
}
validateSets := func(t *testing.T, tt testInfo) {
require, assert := tr.New(t), ta.New(t)
var hostSets []*hostsets.HostSet
for _, set := range tt.sets {
hostSets = append(hostSets, &hostsets.HostSet{Id: set})
}
resp, err := plg.ListHosts(ctx, &plgpb.ListHostsRequest{
Sets: hostSets,
})
require.NoError(err)
if len(tt.found) == 0 {
assert.Len(resp.GetHosts(), 0)
return
}
require.Greater(len(resp.GetHosts()), 0)
var found []map[string]any
for _, host := range resp.GetHosts() {
hostMap := map[string]any{
"external_id": host.GetExternalId(),
}
var sets []any
for _, set := range host.SetIds {
sets = append(sets, set)
}
var ips []any
for _, ip := range host.GetIpAddresses() {
ips = append(ips, ip)
}
var names []any
for _, name := range host.GetDnsNames() {
names = append(names, name)
}
if len(sets) > 0 {
hostMap["set_ids"] = sets
}
if len(ips) > 0 {
hostMap["ip_addresses"] = ips
}
if len(names) > 0 {
hostMap["dns_names"] = names
}
found = append(found, hostMap)
}
assert.ElementsMatch(tt.found, found)
}
// First set of tests: check that we can look up sets individually and
// together
setTests := []testInfo{
{
name: "set 1",
sets: []string{"set1"},
found: []map[string]any{
hostInfo1[loopbackPluginHostInfoAttrField].(map[string]any),
},
},
{
name: "set 2",
sets: []string{"set2"},
found: []map[string]any{
hostInfo2[loopbackPluginHostInfoAttrField].(map[string]any),
},
},
{
name: "sets 1 and 2",
sets: []string{"set1", "set2"},
found: []map[string]any{
hostInfo1[loopbackPluginHostInfoAttrField].(map[string]any),
hostInfo2[loopbackPluginHostInfoAttrField].(map[string]any),
},
},
}
for _, tt := range setTests {
t.Run(tt.name, func(t *testing.T) {
validateSets(t, tt)
})
}
// Remove a set
_, err = plg.OnDeleteSet(ctx, &plgpb.OnDeleteSetRequest{
Set: &hostsets.HostSet{
Id: "set1",
},
})
require.NoError(err)
// Run tests again, making sure we no longer find that host either
// individually or together
setTests = []testInfo{
{
name: "set 1 deleted",
sets: []string{"set1"},
found: []map[string]any{},
},
{
name: "set 2 not deleted",
sets: []string{"set2"},
found: []map[string]any{
hostInfo2[loopbackPluginHostInfoAttrField].(map[string]any),
},
},
{
name: "sets 1 and 2 set 1 deleted",
sets: []string{"set1", "set2"},
found: []map[string]any{
hostInfo2[loopbackPluginHostInfoAttrField].(map[string]any),
},
},
}
for _, tt := range setTests {
t.Run(tt.name, func(t *testing.T) {
validateSets(t, tt)
})
}
}
func TestLoopbackHostPluginArrays(t *testing.T) {
require := tr.New(t)
ctx := context.Background()
plg, err := NewLoopbackPlugin()
require.NoError(err)
// Add data to some sets
hostInfo1 := map[string]any{
loopbackPluginHostInfoAttrField: []any{
map[string]any{
"set_ids": []any{"set1"},
"external_id": "host1a",
"ip_addresses": []any{"1.2.3.4", "2.3.4.5"},
"dns_names": []any{"foo.com"},
},
map[string]any{
"set_ids": []any{"set1"},
"external_id": "host1b",
"ip_addresses": []any{"3.4.5.6", "4.5.6.7"},
"dns_names": []any{"bar.com"},
},
},
}
attrs, err := structpb.NewStruct(hostInfo1)
require.NoError(err)
_, err = plg.OnCreateSet(ctx, &plgpb.OnCreateSetRequest{
Set: &hostsets.HostSet{
Id: "set1",
Attrs: &hostsets.HostSet_Attributes{
Attributes: attrs,
},
},
})
require.NoError(err)
hostInfo2 := map[string]any{
loopbackPluginHostInfoAttrField: []any{
map[string]any{
"set_ids": []any{"set2"},
"external_id": "host2a",
"ip_addresses": []any{"10.20.30.40", "20.30.40.50"},
"dns_names": []any{"foz.com"},
},
map[string]any{
"set_ids": []any{"set2"},
"external_id": "host2b",
"ip_addresses": []any{"30.40.50.60", "40.50.60.70"},
"dns_names": []any{"baz.com"},
},
},
}
attrs, err = structpb.NewStruct(hostInfo2)
require.NoError(err)
_, err = plg.OnCreateSet(ctx, &plgpb.OnCreateSetRequest{
Set: &hostsets.HostSet{
Id: "set2",
Attrs: &hostsets.HostSet_Attributes{
Attributes: attrs,
},
},
})
require.NoError(err)
// Define test struct and validation function
type testInfo struct {
name string
sets []string
found []any
}
validateSets := func(t *testing.T, tt testInfo) {
require, assert := tr.New(t), ta.New(t)
var hostSets []*hostsets.HostSet
for _, set := range tt.sets {
hostSets = append(hostSets, &hostsets.HostSet{Id: set})
}
resp, err := plg.ListHosts(ctx, &plgpb.ListHostsRequest{
Sets: hostSets,
})
require.NoError(err)
if len(tt.found) == 0 {
assert.Len(resp.GetHosts(), 0)
return
}
require.Greater(len(resp.GetHosts()), 0)
var found []any
for _, host := range resp.GetHosts() {
hostMap := map[string]any{
"external_id": host.GetExternalId(),
}
var sets []any
for _, set := range host.SetIds {
sets = append(sets, set)
}
var ips []any
for _, ip := range host.GetIpAddresses() {
ips = append(ips, ip)
}
var names []any
for _, name := range host.GetDnsNames() {
names = append(names, name)
}
if len(sets) > 0 {
hostMap["set_ids"] = sets
}
if len(ips) > 0 {
hostMap["ip_addresses"] = ips
}
if len(names) > 0 {
hostMap["dns_names"] = names
}
found = append(found, hostMap)
}
assert.ElementsMatch(tt.found, found)
}
// First set of tests: check that we can look up sets individually and
// together
setTests := []testInfo{
{
name: "set 1",
sets: []string{"set1"},
found: hostInfo1[loopbackPluginHostInfoAttrField].([]any),
},
{
name: "set 2",
sets: []string{"set2"},
found: hostInfo2[loopbackPluginHostInfoAttrField].([]any),
},
{
name: "sets 1 and 2",
sets: []string{"set1", "set2"},
found: append(hostInfo1[loopbackPluginHostInfoAttrField].([]any),
hostInfo2[loopbackPluginHostInfoAttrField].([]any)...),
},
}
for _, tt := range setTests {
t.Run(tt.name, func(t *testing.T) {
validateSets(t, tt)
})
}
}