Co-authored-by: hashicorp-copywrite[bot] <110428419+hashicorp-copywrite[bot]@users.noreply.github.com>
226 lines
5.8 KiB
Go
226 lines
5.8 KiB
Go
// Copyright IBM Corp. 2024, 2026
|
|
// SPDX-License-Identifier: MPL-2.0
|
|
|
|
package host
|
|
|
|
import (
|
|
"testing"
|
|
|
|
computepb "cloud.google.com/go/compute/apiv1/computepb"
|
|
cred "github.com/hashicorp/boundary-plugin-gcp/internal/credential"
|
|
"github.com/stretchr/testify/require"
|
|
"google.golang.org/grpc/codes"
|
|
"google.golang.org/grpc/status"
|
|
"google.golang.org/protobuf/types/known/structpb"
|
|
)
|
|
|
|
func TestGetCatalogAttributes(t *testing.T) {
|
|
cases := []struct {
|
|
name string
|
|
in *structpb.Struct
|
|
expected *CatalogAttributes
|
|
expectedErrContains string
|
|
}{
|
|
{
|
|
name: "missing project_id and zone",
|
|
in: &structpb.Struct{
|
|
Fields: make(map[string]*structpb.Value),
|
|
},
|
|
expectedErrContains: "attributes.project_id: missing required value \"project_id\", attributes.zone: missing required value \"zone\"",
|
|
},
|
|
{
|
|
name: "unknown fields",
|
|
in: &structpb.Struct{
|
|
Fields: map[string]*structpb.Value{
|
|
"project_id": structpb.NewStringValue("test-12345"),
|
|
"zone": structpb.NewStringValue("us-central-1a"),
|
|
"foo": structpb.NewBoolValue(true),
|
|
"bar": structpb.NewBoolValue(true),
|
|
},
|
|
},
|
|
expectedErrContains: "attributes.bar: unrecognized field, attributes.foo: unrecognized field",
|
|
},
|
|
{
|
|
name: "valid project and zone",
|
|
in: &structpb.Struct{
|
|
Fields: map[string]*structpb.Value{
|
|
"project_id": structpb.NewStringValue("test-12345"),
|
|
"zone": structpb.NewStringValue("us-central-1a"),
|
|
},
|
|
},
|
|
expected: &CatalogAttributes{&cred.CredentialAttributes{
|
|
ProjectId: "test-12345",
|
|
Zone: "us-central-1a",
|
|
}},
|
|
},
|
|
}
|
|
|
|
for _, tc := range cases {
|
|
tc := tc
|
|
t.Run(tc.name, func(t *testing.T) {
|
|
require := require.New(t)
|
|
|
|
actual, err := getCatalogAttributes(tc.in)
|
|
if tc.expectedErrContains != "" {
|
|
require.Error(err)
|
|
require.Contains(err.Error(), tc.expectedErrContains)
|
|
require.Equal(status.Code(err), codes.InvalidArgument)
|
|
return
|
|
}
|
|
|
|
require.NoError(err)
|
|
require.Equal(tc.expected, actual)
|
|
})
|
|
}
|
|
}
|
|
|
|
func TestGetSetAttributes(t *testing.T) {
|
|
cases := []struct {
|
|
name string
|
|
in map[string]any
|
|
normalized map[string]any
|
|
expected *SetAttributes
|
|
expectedErrContains string
|
|
}{
|
|
{
|
|
name: "missing",
|
|
in: map[string]any{},
|
|
expected: &SetAttributes{},
|
|
},
|
|
{
|
|
name: "valid example filter",
|
|
in: map[string]any{
|
|
ConstListInstancesFilter: "tags.items=my-tag AND -tags.items=my-other-tag) OR tags.items=alternative-tag",
|
|
},
|
|
expected: &SetAttributes{
|
|
Filters: []string{"tags.items=my-tag AND -tags.items=my-other-tag) OR tags.items=alternative-tag"},
|
|
},
|
|
},
|
|
{
|
|
name: "unknown fields",
|
|
in: map[string]any{
|
|
"foo": true,
|
|
"bar": true,
|
|
},
|
|
expectedErrContains: "attributes.bar: unrecognized field, attributes.foo: unrecognized field",
|
|
},
|
|
}
|
|
|
|
for _, tc := range cases {
|
|
tc := tc
|
|
t.Run(tc.name, func(t *testing.T) {
|
|
require := require.New(t)
|
|
|
|
input, err := structpb.NewStruct(tc.in)
|
|
require.NoError(err)
|
|
|
|
actual, err := getSetAttributes(input)
|
|
if tc.expectedErrContains != "" {
|
|
require.Error(err)
|
|
require.Contains(err.Error(), tc.expectedErrContains)
|
|
require.Equal(status.Code(err), codes.InvalidArgument)
|
|
return
|
|
}
|
|
|
|
require.NoError(err)
|
|
require.Equal(tc.expected, actual)
|
|
})
|
|
}
|
|
}
|
|
|
|
func TestBuildListInstancesRequest(t *testing.T) {
|
|
cases := []struct {
|
|
name string
|
|
attributes *SetAttributes
|
|
catalog *CatalogAttributes
|
|
expected *computepb.ListInstancesRequest
|
|
expectedErrContains string
|
|
}{
|
|
{
|
|
name: "valid request with single filter",
|
|
attributes: &SetAttributes{
|
|
Filters: []string{"tags.items=my-tag"},
|
|
},
|
|
catalog: &CatalogAttributes{
|
|
CredentialAttributes: &cred.CredentialAttributes{
|
|
ProjectId: "test-12345",
|
|
Zone: "us-central-1a",
|
|
},
|
|
},
|
|
expected: &computepb.ListInstancesRequest{
|
|
Project: "test-12345",
|
|
Zone: "us-central-1a",
|
|
Filter: stringPtr("tags.items=my-tag AND status = running"),
|
|
},
|
|
},
|
|
{
|
|
name: "valid request with multiple filters",
|
|
attributes: &SetAttributes{
|
|
Filters: []string{"tags.items=my-tag", "tags.items=my-other-tag"},
|
|
},
|
|
catalog: &CatalogAttributes{
|
|
CredentialAttributes: &cred.CredentialAttributes{
|
|
ProjectId: "test-12345",
|
|
Zone: "us-central-1a",
|
|
},
|
|
},
|
|
expected: &computepb.ListInstancesRequest{
|
|
Project: "test-12345",
|
|
Zone: "us-central-1a",
|
|
Filter: stringPtr("tags.items=my-tag AND tags.items=my-other-tag AND status = running"),
|
|
},
|
|
},
|
|
{
|
|
name: "error building filters",
|
|
attributes: &SetAttributes{
|
|
Filters: []string{"invalid-filter"},
|
|
},
|
|
catalog: &CatalogAttributes{
|
|
CredentialAttributes: &cred.CredentialAttributes{
|
|
ProjectId: "test-12345",
|
|
Zone: "us-central-1a",
|
|
},
|
|
},
|
|
expectedErrContains: "error building filters",
|
|
},
|
|
{
|
|
name: "valid request with no filters",
|
|
attributes: &SetAttributes{
|
|
Filters: []string{},
|
|
},
|
|
catalog: &CatalogAttributes{
|
|
CredentialAttributes: &cred.CredentialAttributes{
|
|
ProjectId: "test-12345",
|
|
Zone: "us-central-1a",
|
|
},
|
|
},
|
|
expected: &computepb.ListInstancesRequest{
|
|
Project: "test-12345",
|
|
Zone: "us-central-1a",
|
|
Filter: stringPtr("status = running"),
|
|
},
|
|
},
|
|
}
|
|
|
|
for _, tc := range cases {
|
|
tc := tc
|
|
t.Run(tc.name, func(t *testing.T) {
|
|
require := require.New(t)
|
|
|
|
actual, err := buildListInstancesRequest(tc.attributes, tc.catalog)
|
|
if tc.expectedErrContains != "" {
|
|
require.Error(err)
|
|
require.Contains(err.Error(), tc.expectedErrContains)
|
|
return
|
|
}
|
|
|
|
require.NoError(err)
|
|
require.Equal(tc.expected, actual)
|
|
})
|
|
}
|
|
}
|
|
|
|
func stringPtr(s string) *string {
|
|
return &s
|
|
}
|