diff --git a/plugin/attributes.go b/plugin/attributes.go index 5b5c1b4..d5c1044 100644 --- a/plugin/attributes.go +++ b/plugin/attributes.go @@ -74,18 +74,18 @@ func getCatalogSecrets(in *structpb.Struct) (*CatalogSecrets, error) { var err error result.AccessKeyId, err = getStringValue(in, constAccessKeyId, true) if err != nil { - badFields["access_key_id"] = err.Error() + badFields[fmt.Sprintf("secrets.%s", constAccessKeyId)] = err.Error() } delete(unknownFields, constAccessKeyId) result.SecretAccessKey, err = getStringValue(in, constSecretAccessKey, true) if err != nil { - badFields["secret_access_key"] = err.Error() + badFields[fmt.Sprintf("secrets.%s", constSecretAccessKey)] = err.Error() } delete(unknownFields, constSecretAccessKey) for s := range unknownFields { - badFields[fmt.Sprintf("attributes.%s", s)] = "Unrecognized field" + badFields[fmt.Sprintf("secrets.%s", s)] = "Unrecognized field" } if len(badFields) > 0 { @@ -108,9 +108,13 @@ func getSetAttributes(in *structpb.Struct) (*SetAttributes, error) { // here for now. Make this more complex if we add more attributes // to host sets. unknownFields := structFields(in) + badFields := make(map[string]string) delete(unknownFields, constDescribeInstancesFilters) - if len(unknownFields) != 0 { - return nil, status.Errorf(codes.InvalidArgument, "unknown set attribute fields provided: %s", keysAsString(unknownFields)) + for a := range unknownFields { + badFields[fmt.Sprintf("attributes.%s", a)] = "Unrecognized field" + } + if len(badFields) > 0 { + return nil, invalidArgumentError("Error in the attributes provided", badFields) } // Mapstructure complains if it expects a slice as output and sees a scalar diff --git a/plugin/attributes_test.go b/plugin/attributes_test.go index 728fd9f..650c50d 100644 --- a/plugin/attributes_test.go +++ b/plugin/attributes_test.go @@ -5,6 +5,8 @@ import ( "time" "github.com/stretchr/testify/require" + "google.golang.org/grpc/codes" + "google.golang.org/grpc/status" "google.golang.org/protobuf/types/known/structpb" ) @@ -68,6 +70,7 @@ func TestGetCatalogAttributes(t *testing.T) { if tc.expectedErrContains != "" { require.Error(err) require.Contains(err.Error(), tc.expectedErrContains) + require.Equal(status.Code(err), codes.InvalidArgument) return } @@ -104,7 +107,7 @@ func TestGetCatalogSecrets(t *testing.T) { "foo": true, "bar": true, }), - expectedErrContains: "attributes.bar: Unrecognized field, attributes.foo: Unrecognized field", + expectedErrContains: "secrets.bar: Unrecognized field, secrets.foo: Unrecognized field", }, { name: "good", @@ -127,6 +130,7 @@ func TestGetCatalogSecrets(t *testing.T) { if tc.expectedErrContains != "" { require.Error(err) require.Contains(err.Error(), tc.expectedErrContains) + require.Equal(status.Code(err), codes.InvalidArgument) return } @@ -170,7 +174,7 @@ func TestGetSetAttributes(t *testing.T) { "foo": true, "bar": true, }), - expectedErrContains: "unknown set attribute fields provided: bar, foo", + expectedErrContains: "attributes.bar: Unrecognized field, attributes.foo: Unrecognized field", }, { name: "good", @@ -194,6 +198,7 @@ func TestGetSetAttributes(t *testing.T) { if tc.expectedErrContains != "" { require.Error(err) require.Contains(err.Error(), tc.expectedErrContains) + require.Equal(status.Code(err), codes.InvalidArgument) return } @@ -414,6 +419,7 @@ func TestValidateRegion(t *testing.T) { err := validateRegion(tc.in) if tc.expectedErr != "" { require.Contains(err.Error(), tc.expectedErr) + require.Equal(status.Code(err), codes.InvalidArgument) return } diff --git a/plugin/plugin.go b/plugin/plugin.go index fbe8bb8..fedac13 100644 --- a/plugin/plugin.go +++ b/plugin/plugin.go @@ -70,7 +70,7 @@ func (p *AwsPlugin) OnCreateCatalog(ctx context.Context, req *pb.OnCreateCatalog withSecretAccessKey(catalogSecrets.SecretAccessKey), }, p.testStateOpts...)...) if err != nil { - return nil, fmt.Errorf("error setting up persisted state: %w", err) + return nil, status.Errorf(codes.InvalidArgument, "error setting up persisted state: %s", err) } // Try to rotate the credentials if we're not skipping them. @@ -198,7 +198,7 @@ func (p *AwsPlugin) OnDeleteCatalog(ctx context.Context, req *pb.OnDeleteCatalog // credentials to ensure that it has the proper permissions to do // it. if err := state.DeleteCreds(); err != nil { - return nil, status.Errorf(codes.FailedPrecondition, "error removing rotated credentials during catalog deletion: %s", err) + return nil, status.Errorf(codes.Aborted, "error removing rotated credentials during catalog deletion: %s", err) } } @@ -218,11 +218,11 @@ func (p *AwsPlugin) OnCreateSet(ctx context.Context, req *pb.OnCreateSetRequest) catalogAttributes, err := getCatalogAttributes(catalogAttrsRaw) if err != nil { - return nil, fmt.Errorf("integrity error in host catalog attributes: %w", err) + return nil, err } if err := validateRegion(catalogAttributes.Region); err != nil { - return nil, fmt.Errorf("integrity error in host catalog attributes: %w", err) + return nil, err } state, err := awsCatalogPersistedStateFromProto(req.GetPersisted(), p.testStateOpts...) @@ -240,7 +240,7 @@ func (p *AwsPlugin) OnCreateSet(ctx context.Context, req *pb.OnCreateSetRequest) } setAttrs, err := getSetAttributes(set.GetAttributes()) if err != nil { - return nil, fmt.Errorf("error parsing set attributes: %w", err) + return nil, err } ec2Client, err := state.EC2Client(catalogAttributes.Region) @@ -279,11 +279,11 @@ func (p *AwsPlugin) OnUpdateSet(ctx context.Context, req *pb.OnUpdateSetRequest) catalogAttributes, err := getCatalogAttributes(catalogAttrsRaw) if err != nil { - return nil, fmt.Errorf("integrity error in host catalog attributes: %w", err) + return nil, err } if err := validateRegion(catalogAttributes.Region); err != nil { - return nil, fmt.Errorf("integrity error in host catalog attributes: %w", err) + return nil, err } state, err := awsCatalogPersistedStateFromProto(req.GetPersisted(), p.testStateOpts...) @@ -303,7 +303,7 @@ func (p *AwsPlugin) OnUpdateSet(ctx context.Context, req *pb.OnUpdateSetRequest) } setAttrs, err := getSetAttributes(set.GetAttributes()) if err != nil { - return nil, fmt.Errorf("error parsing set attributes: %w", err) + return nil, err } ec2Client, err := state.EC2Client(catalogAttributes.Region) @@ -348,11 +348,11 @@ func (p *AwsPlugin) ListHosts(ctx context.Context, req *pb.ListHostsRequest) (*p catalogAttributes, err := getCatalogAttributes(catalogAttrsRaw) if err != nil { - return nil, fmt.Errorf("integrity error in host catalog attributes: %w", err) + return nil, err } if err := validateRegion(catalogAttributes.Region); err != nil { - return nil, fmt.Errorf("integrity error in host catalog attributes: %w", err) + return nil, err } state, err := awsCatalogPersistedStateFromProto(req.GetPersisted(), p.testStateOpts...) @@ -385,7 +385,7 @@ func (p *AwsPlugin) ListHosts(ctx context.Context, req *pb.ListHostsRequest) (*p } setAttrs, err := getSetAttributes(set.GetAttributes()) if err != nil { - return nil, fmt.Errorf("error parsing set attributes: %w", err) + return nil, err } input, err := buildDescribeInstancesInput(setAttrs, false) diff --git a/plugin/plugin_test.go b/plugin/plugin_test.go index 5a45be3..7982f96 100644 --- a/plugin/plugin_test.go +++ b/plugin/plugin_test.go @@ -14,6 +14,8 @@ import ( pb "github.com/hashicorp/boundary/sdk/pbs/plugin" "github.com/hashicorp/go-secure-stdlib/awsutil" "github.com/stretchr/testify/require" + "google.golang.org/grpc/codes" + "google.golang.org/grpc/status" "google.golang.org/protobuf/types/known/structpb" ) @@ -23,11 +25,13 @@ func TestPluginOnCreateCatalogErr(t *testing.T) { req *pb.OnCreateCatalogRequest opts []awsCatalogPersistedStateOption expectedErrContains string + expectedErrCode codes.Code }{ { name: "nil catalog", req: &pb.OnCreateCatalogRequest{}, expectedErrContains: "catalog is nil", + expectedErrCode: codes.InvalidArgument, }, { name: "nil secrets", @@ -35,6 +39,7 @@ func TestPluginOnCreateCatalogErr(t *testing.T) { Catalog: &hostcatalogs.HostCatalog{}, }, expectedErrContains: "secrets are required", + expectedErrCode: codes.InvalidArgument, }, { name: "nil attributes", @@ -44,6 +49,7 @@ func TestPluginOnCreateCatalogErr(t *testing.T) { }, }, expectedErrContains: "attributes are required", + expectedErrCode: codes.InvalidArgument, }, { name: "error reading attributes", @@ -54,6 +60,7 @@ func TestPluginOnCreateCatalogErr(t *testing.T) { }, }, expectedErrContains: "missing required value \"region\"", + expectedErrCode: codes.InvalidArgument, }, { name: "error reading secrets", @@ -66,6 +73,7 @@ func TestPluginOnCreateCatalogErr(t *testing.T) { }, }, expectedErrContains: "missing required value \"access_key_id\"", + expectedErrCode: codes.InvalidArgument, }, { name: "invalid region", @@ -81,6 +89,7 @@ func TestPluginOnCreateCatalogErr(t *testing.T) { }, }, expectedErrContains: "not a valid region: foobar", + expectedErrCode: codes.InvalidArgument, }, { name: "persisted state setup error", @@ -101,6 +110,7 @@ func TestPluginOnCreateCatalogErr(t *testing.T) { }, }, expectedErrContains: fmt.Sprintf("error setting up persisted state: %s", testOptionErr), + expectedErrCode: codes.InvalidArgument, }, { name: "rotation error", @@ -125,6 +135,7 @@ func TestPluginOnCreateCatalogErr(t *testing.T) { }), }, expectedErrContains: fmt.Sprintf("error during credential rotation: error rotating credentials: error calling CreateAccessKey: error calling aws.GetUser: %s", testGetUserErr), + expectedErrCode: codes.InvalidArgument, }, { name: "validation error", @@ -150,6 +161,7 @@ func TestPluginOnCreateCatalogErr(t *testing.T) { }), }, expectedErrContains: fmt.Sprintf("error during credential validation: error validating credentials: %s", testGetCallerIdentityErr), + expectedErrCode: codes.InvalidArgument, }, } @@ -162,6 +174,7 @@ func TestPluginOnCreateCatalogErr(t *testing.T) { } _, err := p.OnCreateCatalog(context.Background(), tc.req) require.Contains(err.Error(), tc.expectedErrContains) + require.Equal(status.Code(err).String(), tc.expectedErrCode.String()) }) } } @@ -172,11 +185,13 @@ func TestPluginOnUpdateCatalogErr(t *testing.T) { req *pb.OnUpdateCatalogRequest opts []awsCatalogPersistedStateOption expectedErrContains string + expectedErrCode codes.Code }{ { name: "nil new catalog", req: &pb.OnUpdateCatalogRequest{}, expectedErrContains: "new catalog is nil", + expectedErrCode: codes.InvalidArgument, }, { name: "nil new attributes", @@ -186,6 +201,7 @@ func TestPluginOnUpdateCatalogErr(t *testing.T) { }, }, expectedErrContains: "new catalog missing attributes", + expectedErrCode: codes.InvalidArgument, }, { name: "error reading attributes", @@ -196,6 +212,7 @@ func TestPluginOnUpdateCatalogErr(t *testing.T) { }, }, expectedErrContains: "missing required value \"region\"", + expectedErrCode: codes.InvalidArgument, }, { name: "invalid region", @@ -207,6 +224,7 @@ func TestPluginOnUpdateCatalogErr(t *testing.T) { }, }, expectedErrContains: "not a valid region: foobar", + expectedErrCode: codes.InvalidArgument, }, { name: "persisted state setup error", @@ -230,6 +248,7 @@ func TestPluginOnUpdateCatalogErr(t *testing.T) { }, }, expectedErrContains: fmt.Sprintf("error loading persisted state: %s", testOptionErr), + expectedErrCode: codes.InvalidArgument, }, { name: "cannot disable rotation for already rotated credentials", @@ -249,6 +268,7 @@ func TestPluginOnUpdateCatalogErr(t *testing.T) { }, }, expectedErrContains: "cannot disable rotation for already-rotated credentials", + expectedErrCode: codes.FailedPrecondition, }, { name: "error reading secrets", @@ -268,6 +288,7 @@ func TestPluginOnUpdateCatalogErr(t *testing.T) { }, }, expectedErrContains: "missing required value \"access_key_id\"", + expectedErrCode: codes.InvalidArgument, }, { name: "updating secrets, replace error", @@ -300,6 +321,7 @@ func TestPluginOnUpdateCatalogErr(t *testing.T) { }), }, expectedErrContains: fmt.Sprintf("error attempting to replace credentials: error deleting old access key: %s", testDeleteAccessKeyErr), + expectedErrCode: codes.InvalidArgument, }, { name: "rotation error", @@ -326,6 +348,7 @@ func TestPluginOnUpdateCatalogErr(t *testing.T) { }), }, expectedErrContains: fmt.Sprintf("error during credential rotation: error rotating credentials: error calling CreateAccessKey: error calling aws.GetUser: %s", testGetUserErr), + expectedErrCode: codes.InvalidArgument, }, } @@ -338,6 +361,7 @@ func TestPluginOnUpdateCatalogErr(t *testing.T) { } _, err := p.OnUpdateCatalog(context.Background(), tc.req) require.Contains(err.Error(), tc.expectedErrContains) + require.Equal(status.Code(err).String(), tc.expectedErrCode.String()) }) } } @@ -348,6 +372,7 @@ func TestPluginOnDeleteCatalogErr(t *testing.T) { req *pb.OnDeleteCatalogRequest opts []awsCatalogPersistedStateOption expectedErrContains string + expectedErrCode codes.Code }{ { name: "persisted state setup error", @@ -371,6 +396,7 @@ func TestPluginOnDeleteCatalogErr(t *testing.T) { }, }, expectedErrContains: fmt.Sprintf("error loading persisted state: %s", testOptionErr), + expectedErrCode: codes.InvalidArgument, }, { name: "delete error", @@ -398,6 +424,7 @@ func TestPluginOnDeleteCatalogErr(t *testing.T) { }), }, expectedErrContains: fmt.Sprintf("error removing rotated credentials during catalog deletion: error deleting old access key: %s", testDeleteAccessKeyErr), + expectedErrCode: codes.Aborted, }, } @@ -410,22 +437,24 @@ func TestPluginOnDeleteCatalogErr(t *testing.T) { } _, err := p.OnDeleteCatalog(context.Background(), tc.req) require.Contains(err.Error(), tc.expectedErrContains) + require.Equal(status.Code(err).String(), tc.expectedErrCode.String()) }) } } func TestPluginOnCreateSetErr(t *testing.T) { cases := []struct { - name string - req *pb.OnCreateSetRequest - opts []awsCatalogPersistedStateOption - expectedErrContains string - expectedErrContains2 string + name string + req *pb.OnCreateSetRequest + opts []awsCatalogPersistedStateOption + expectedErrContains string + expectedErrCode codes.Code }{ { name: "nil catalog", req: &pb.OnCreateSetRequest{}, expectedErrContains: "catalog is nil", + expectedErrCode: codes.InvalidArgument, }, { name: "nil catalog attributes", @@ -435,6 +464,7 @@ func TestPluginOnCreateSetErr(t *testing.T) { }, }, expectedErrContains: "catalog missing attributes", + expectedErrCode: codes.InvalidArgument, }, { name: "error reading catalog attributes", @@ -444,8 +474,8 @@ func TestPluginOnCreateSetErr(t *testing.T) { Attributes: new(structpb.Struct), }, }, - expectedErrContains: "integrity error in host catalog attributes: ", - expectedErrContains2: "missing required value \"region\"", + expectedErrContains: "missing required value \"region\"", + expectedErrCode: codes.InvalidArgument, }, { name: "invalid region", @@ -456,8 +486,8 @@ func TestPluginOnCreateSetErr(t *testing.T) { }), }, }, - expectedErrContains: "integrity error in host catalog attributes: ", - expectedErrContains2: "not a valid region: foobar", + expectedErrContains: "not a valid region: foobar", + expectedErrCode: codes.InvalidArgument, }, { name: "persisted state setup error", @@ -481,6 +511,7 @@ func TestPluginOnCreateSetErr(t *testing.T) { }, }, expectedErrContains: fmt.Sprintf("error loading persisted state: %s", testOptionErr), + expectedErrCode: codes.InvalidArgument, }, { name: "nil set", @@ -499,6 +530,7 @@ func TestPluginOnCreateSetErr(t *testing.T) { }, }, expectedErrContains: "set is nil", + expectedErrCode: codes.InvalidArgument, }, { name: "nil attributes in set", @@ -518,6 +550,7 @@ func TestPluginOnCreateSetErr(t *testing.T) { Set: &hostsets.HostSet{}, }, expectedErrContains: "set missing attributes", + expectedErrCode: codes.InvalidArgument, }, { name: "set attribute load error", @@ -541,8 +574,8 @@ func TestPluginOnCreateSetErr(t *testing.T) { }), }, }, - expectedErrContains: "error parsing set attributes: ", - expectedErrContains2: "unknown set attribute fields provided: bar, foo", + expectedErrContains: "attributes.bar: Unrecognized field, attributes.foo: Unrecognized field", + expectedErrCode: codes.InvalidArgument, }, { name: "client load error", @@ -571,6 +604,7 @@ func TestPluginOnCreateSetErr(t *testing.T) { }), }, expectedErrContains: fmt.Sprintf("error getting EC2 client: error getting AWS session: error reading options in NewCredentialsConfig: %s", testOptionErr), + expectedErrCode: codes.InvalidArgument, }, { name: "DescribeInstances error", @@ -600,6 +634,7 @@ func TestPluginOnCreateSetErr(t *testing.T) { )), }, expectedErrContains: fmt.Sprintf("error performing dry run of DescribeInstances: %s", testDescribeInstancesError), + expectedErrCode: codes.InvalidArgument, }, { name: "DescribeInstances non-error array filter", @@ -628,6 +663,7 @@ func TestPluginOnCreateSetErr(t *testing.T) { )), }, expectedErrContains: "query error: DescribeInstances DryRun should have returned error, but none was found", + expectedErrCode: codes.FailedPrecondition, }, { name: "DescribeInstances non-error string filter", @@ -656,6 +692,7 @@ func TestPluginOnCreateSetErr(t *testing.T) { )), }, expectedErrContains: "query error: DescribeInstances DryRun should have returned error, but none was found", + expectedErrCode: codes.FailedPrecondition, }, } @@ -668,25 +705,24 @@ func TestPluginOnCreateSetErr(t *testing.T) { } _, err := p.OnCreateSet(context.Background(), tc.req) require.Contains(err.Error(), tc.expectedErrContains) - if tc.expectedErrContains2 != "" { - require.Contains(err.Error(), tc.expectedErrContains2) - } + require.Equal(status.Code(err).String(), tc.expectedErrCode.String()) }) } } func TestPluginOnUpdateSetErr(t *testing.T) { cases := []struct { - name string - req *pb.OnUpdateSetRequest - opts []awsCatalogPersistedStateOption - expectedErrContains string - expectedErrContains2 string + name string + req *pb.OnUpdateSetRequest + opts []awsCatalogPersistedStateOption + expectedErrContains string + expectedErrCode codes.Code }{ { name: "nil catalog", req: &pb.OnUpdateSetRequest{}, expectedErrContains: "catalog is nil", + expectedErrCode: codes.InvalidArgument, }, { name: "nil catalog attributes", @@ -696,6 +732,7 @@ func TestPluginOnUpdateSetErr(t *testing.T) { }, }, expectedErrContains: "catalog missing attributes", + expectedErrCode: codes.InvalidArgument, }, { name: "catalog attribute load error", @@ -705,8 +742,8 @@ func TestPluginOnUpdateSetErr(t *testing.T) { Attributes: new(structpb.Struct), }, }, - expectedErrContains: "integrity error in host catalog attributes: ", - expectedErrContains2: "missing required value \"region\"", + expectedErrContains: "missing required value \"region\"", + expectedErrCode: codes.InvalidArgument, }, { name: "invalid region", @@ -718,8 +755,8 @@ func TestPluginOnUpdateSetErr(t *testing.T) { }), }, }, - expectedErrContains: "integrity error in host catalog attributes: ", - expectedErrContains2: "not a valid region: foobar", + expectedErrContains: "not a valid region: foobar", + expectedErrCode: codes.InvalidArgument, }, { name: "persisted state setup error", @@ -743,6 +780,7 @@ func TestPluginOnUpdateSetErr(t *testing.T) { }, }, expectedErrContains: fmt.Sprintf("error loading persisted state: %s", testOptionErr), + expectedErrCode: codes.InvalidArgument, }, { name: "nil set", @@ -761,6 +799,7 @@ func TestPluginOnUpdateSetErr(t *testing.T) { }, }, expectedErrContains: "new set is nil", + expectedErrCode: codes.InvalidArgument, }, { name: "nil attributes in set", @@ -780,6 +819,7 @@ func TestPluginOnUpdateSetErr(t *testing.T) { NewSet: &hostsets.HostSet{}, }, expectedErrContains: "new set missing attributes", + expectedErrCode: codes.InvalidArgument, }, { name: "set attribute load error", @@ -803,8 +843,8 @@ func TestPluginOnUpdateSetErr(t *testing.T) { }), }, }, - expectedErrContains: "error parsing set attributes: ", - expectedErrContains2: "unknown set attribute fields provided: bar, foo", + expectedErrContains: "attributes.bar: Unrecognized field, attributes.foo: Unrecognized field", + expectedErrCode: codes.InvalidArgument, }, { name: "client load error", @@ -833,6 +873,7 @@ func TestPluginOnUpdateSetErr(t *testing.T) { }), }, expectedErrContains: fmt.Sprintf("error getting EC2 client: error getting AWS session: error reading options in NewCredentialsConfig: %s", testOptionErr), + expectedErrCode: codes.InvalidArgument, }, { name: "DescribeInstances error", @@ -862,6 +903,7 @@ func TestPluginOnUpdateSetErr(t *testing.T) { )), }, expectedErrContains: fmt.Sprintf("error performing dry run of DescribeInstances: %s", testDescribeInstancesError), + expectedErrCode: codes.InvalidArgument, }, { name: "DescribeInstances non-error", @@ -890,6 +932,7 @@ func TestPluginOnUpdateSetErr(t *testing.T) { )), }, expectedErrContains: "query error: DescribeInstances DryRun should have returned error, but none was found", + expectedErrCode: codes.FailedPrecondition, }, } @@ -902,25 +945,24 @@ func TestPluginOnUpdateSetErr(t *testing.T) { } _, err := p.OnUpdateSet(context.Background(), tc.req) require.Contains(err.Error(), tc.expectedErrContains) - if tc.expectedErrContains2 != "" { - require.Contains(err.Error(), tc.expectedErrContains2) - } + require.Equal(status.Code(err).String(), tc.expectedErrCode.String()) }) } } func TestPluginListHostsErr(t *testing.T) { cases := []struct { - name string - req *pb.ListHostsRequest - opts []awsCatalogPersistedStateOption - expectedErrContains string - expectedErrContains2 string + name string + req *pb.ListHostsRequest + opts []awsCatalogPersistedStateOption + expectedErrContains string + expectedErrCode codes.Code }{ { name: "nil catalog", req: &pb.ListHostsRequest{}, expectedErrContains: "catalog is nil", + expectedErrCode: codes.InvalidArgument, }, { name: "nil catalog attributes", @@ -930,6 +972,7 @@ func TestPluginListHostsErr(t *testing.T) { }, }, expectedErrContains: "catalog missing attributes", + expectedErrCode: codes.InvalidArgument, }, { name: "error reading catalog attributes", @@ -939,8 +982,8 @@ func TestPluginListHostsErr(t *testing.T) { Attributes: new(structpb.Struct), }, }, - expectedErrContains: "integrity error in host catalog attributes: ", - expectedErrContains2: "missing required value \"region\"", + expectedErrContains: "attributes.region: missing required value \"region\"", + expectedErrCode: codes.InvalidArgument, }, { name: "invalid region", @@ -952,8 +995,8 @@ func TestPluginListHostsErr(t *testing.T) { }), }, }, - expectedErrContains: "integrity error in host catalog attributes: ", - expectedErrContains2: "not a valid region: foobar", + expectedErrContains: "not a valid region: ", + expectedErrCode: codes.InvalidArgument, }, { name: "persisted state setup error", @@ -977,6 +1020,7 @@ func TestPluginListHostsErr(t *testing.T) { }, }, expectedErrContains: fmt.Sprintf("error loading persisted state: %s", testOptionErr), + expectedErrCode: codes.InvalidArgument, }, { name: "nil sets", @@ -995,6 +1039,7 @@ func TestPluginListHostsErr(t *testing.T) { }, }, expectedErrContains: "sets is nil", + expectedErrCode: codes.InvalidArgument, }, { name: "set missing id", @@ -1014,6 +1059,7 @@ func TestPluginListHostsErr(t *testing.T) { Sets: []*hostsets.HostSet{&hostsets.HostSet{}}, }, expectedErrContains: "set missing id", + expectedErrCode: codes.InvalidArgument, }, { name: "set missing attributes", @@ -1037,6 +1083,7 @@ func TestPluginListHostsErr(t *testing.T) { }, }, expectedErrContains: "set missing attributes", + expectedErrCode: codes.InvalidArgument, }, { name: "set attribute load error", @@ -1063,8 +1110,8 @@ func TestPluginListHostsErr(t *testing.T) { }, }, }, - expectedErrContains: "error parsing set attributes: ", - expectedErrContains2: "unknown set attribute fields provided: bar, foo", + expectedErrContains: "attributes.bar: Unrecognized field, attributes.foo: Unrecognized field", + expectedErrCode: codes.InvalidArgument, }, { name: "client load error", @@ -1096,6 +1143,7 @@ func TestPluginListHostsErr(t *testing.T) { }), }, expectedErrContains: fmt.Sprintf("error getting EC2 client: error getting AWS session: error reading options in NewCredentialsConfig: %s", testOptionErr), + expectedErrCode: codes.InvalidArgument, }, { name: "DescribeInstances error", @@ -1128,6 +1176,7 @@ func TestPluginListHostsErr(t *testing.T) { )), }, expectedErrContains: fmt.Sprintf("error running DescribeInstances for host set id \"foobar\": %s", testDescribeInstancesError), + expectedErrCode: codes.InvalidArgument, }, { name: "awsInstanceToHost error", @@ -1172,6 +1221,7 @@ func TestPluginListHostsErr(t *testing.T) { )), }, expectedErrContains: "error processing host results for host set id \"foobar\": response integrity error: missing instance id", + expectedErrCode: codes.InvalidArgument, }, } @@ -1184,9 +1234,7 @@ func TestPluginListHostsErr(t *testing.T) { } _, err := p.ListHosts(context.Background(), tc.req) require.Contains(err.Error(), tc.expectedErrContains) - if tc.expectedErrContains2 != "" { - require.Contains(err.Error(), tc.expectedErrContains2) - } + require.Equal(status.Code(err).String(), tc.expectedErrCode.String()) }) } }