Files
threshold/internal/daemon/controller/handlers/verifiers_test.go
T
Todd b58dada40d Move the server daemons into their own package (#2061)
* Move the server daemons into their own package

With this change the internal/server package now is dedicated to the server domain (workers and controllers) and not to the server daemons.
The hope is that this will make it easier to keep the daemons decoupled from the representation of the servers in the database.
2022-05-09 12:45:10 -07:00

478 lines
11 KiB
Go

package handlers
import (
"errors"
"testing"
pbs "github.com/hashicorp/boundary/internal/gen/controller/api/services"
pb "github.com/hashicorp/boundary/sdk/pbs/controller/api/resources/users"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
"google.golang.org/protobuf/types/known/fieldmaskpb"
"google.golang.org/protobuf/types/known/timestamppb"
"google.golang.org/protobuf/types/known/wrapperspb"
)
func errorIncludesFields(t *testing.T, err error, wantFields []string) {
t.Helper()
var apiErr *ApiError
require.True(t, errors.As(err, &apiErr))
var gotFields []string
for _, d := range apiErr.Inner.GetDetails().GetRequestFields() {
gotFields = append(gotFields, d.GetName())
}
assert.ElementsMatch(t, gotFields, wantFields)
}
// Throughout this test we will use the User requests, but we could use any request
// message. User was picked arbitrarily.
func TestValidId(t *testing.T) {
assert.True(t, ValidId(Id("prefix_somerandomid"), "prefix"))
assert.True(t, ValidId(Id("prefix_somerandomid"), "notprefix", "prefix"))
assert.True(t, ValidId(Id("prefix_short"), "prefix"))
assert.True(t, ValidId(Id("prefix_thisisalongidentifierwhichstillworks"), "prefix"))
assert.False(t, ValidId(Id("prefixsomerandomid"), "prefix"))
assert.False(t, ValidId(Id("prefixsomerandomid"), "prefix", "alsobadprefix"))
assert.False(t, ValidId(Id("prefix_this has spaces"), "prefix"))
assert.False(t, ValidId(Id("prefix_includes-dash"), "prefix"))
assert.False(t, ValidId(Id("prefix_other@strange!characters"), "prefix"))
assert.False(t, ValidId(Id("prefix_short"), "short"))
}
func TestValidNameDescription(t *testing.T) {
assert.True(t, ValidNameDescription("foobar"))
assert.False(t, ValidNameDescription("foo\u200Bbar"))
}
func TestValidateGetRequest(t *testing.T) {
cases := []struct {
name string
prefix string
req GetRequest
valFn CustomValidatorFunc
badFields []string
}{
{
name: "noopvalidator no error",
prefix: "prefix",
req: &pbs.GetUserRequest{
Id: "prefix_someidentifier",
},
valFn: NoopValidatorFn,
},
{
name: "noopvalidator bad prefix",
prefix: "bad",
req: &pbs.GetUserRequest{
Id: "prefix_someidentifier",
},
valFn: NoopValidatorFn,
badFields: []string{"id"},
},
{
name: "custom field error",
prefix: "prefix",
req: &pbs.GetUserRequest{
Id: "prefix_someidentifier",
},
valFn: func() map[string]string {
return map[string]string{"test": "test"}
},
badFields: []string{"test"},
},
{
name: "both custom error and prefix",
prefix: "bad",
req: &pbs.GetUserRequest{
Id: "prefix_someidentifier",
},
valFn: func() map[string]string {
return map[string]string{"test": "test"}
},
badFields: []string{"id", "test"},
},
}
for _, tc := range cases {
t.Run(tc.name, func(t *testing.T) {
err := ValidateGetRequest(tc.valFn, tc.req, tc.prefix)
if len(tc.badFields) == 0 {
if !assert.NoError(t, err) {
errorIncludesFields(t, err, []string{})
}
return
}
errorIncludesFields(t, err, tc.badFields)
})
}
}
func TestValidateDeleteRequest(t *testing.T) {
cases := []struct {
name string
prefix string
req DeleteRequest
valFn CustomValidatorFunc
badFields []string
}{
{
name: "noopvalidator no error",
prefix: "prefix",
req: &pbs.DeleteUserRequest{
Id: "prefix_someidentifier",
},
valFn: NoopValidatorFn,
},
{
name: "noopvalidator bad prefix",
prefix: "bad",
req: &pbs.DeleteUserRequest{
Id: "prefix_someidentifier",
},
valFn: NoopValidatorFn,
badFields: []string{"id"},
},
{
name: "custom field error",
prefix: "prefix",
req: &pbs.DeleteUserRequest{
Id: "prefix_someidentifier",
},
valFn: func() map[string]string {
return map[string]string{"test": "test"}
},
badFields: []string{"test"},
},
{
name: "both custom error and prefix",
prefix: "bad",
req: &pbs.DeleteUserRequest{
Id: "prefix_someidentifier",
},
valFn: func() map[string]string {
return map[string]string{"test": "test"}
},
badFields: []string{"id", "test"},
},
}
for _, tc := range cases {
t.Run(tc.name, func(t *testing.T) {
err := ValidateDeleteRequest(tc.valFn, tc.req, tc.prefix)
if len(tc.badFields) == 0 {
if !assert.NoError(t, err) {
errorIncludesFields(t, err, []string{})
}
return
}
errorIncludesFields(t, err, tc.badFields)
})
}
}
func TestValidateCreateRequest(t *testing.T) {
cases := []struct {
name string
item ApiResource
valFn CustomValidatorFunc
badFields []string
}{
{
name: "valid",
item: &pb.User{},
valFn: NoopValidatorFn,
},
{
name: "disallow set id",
item: &pb.User{
Id: "anything",
},
valFn: NoopValidatorFn,
badFields: []string{"id"},
},
{
name: "disallow set created",
item: &pb.User{
CreatedTime: timestamppb.Now(),
},
valFn: NoopValidatorFn,
badFields: []string{"created_time"},
},
{
name: "disallow set updated",
item: &pb.User{
UpdatedTime: timestamppb.Now(),
},
valFn: NoopValidatorFn,
badFields: []string{"updated_time"},
},
{
name: "disallow set version",
item: &pb.User{
Version: 4,
},
valFn: NoopValidatorFn,
badFields: []string{"version"},
},
{
name: "custom validator error",
item: &pb.User{},
valFn: func() map[string]string {
return map[string]string{"test": "test"}
},
badFields: []string{"test"},
},
{
name: "disallow several fields",
item: &pb.User{
Id: "anything",
CreatedTime: timestamppb.Now(),
Version: 4,
},
valFn: func() map[string]string {
return map[string]string{"test": "test"}
},
badFields: []string{"id", "created_time", "version", "test"},
},
{
name: "good name",
item: &pb.User{
Name: wrapperspb.String("foobar"),
},
valFn: NoopValidatorFn,
},
{
name: "bad name",
item: &pb.User{
Name: wrapperspb.String("foo\u200Bbar"),
},
valFn: NoopValidatorFn,
badFields: []string{"name"},
},
{
name: "good description",
item: &pb.User{
Description: wrapperspb.String("foobar"),
},
valFn: NoopValidatorFn,
},
{
name: "bad description",
item: &pb.User{
Description: wrapperspb.String("foo\u200Bbar"),
},
valFn: NoopValidatorFn,
badFields: []string{"description"},
},
}
for _, tc := range cases {
t.Run(tc.name, func(t *testing.T) {
err := ValidateCreateRequest(tc.item, tc.valFn)
if len(tc.badFields) == 0 {
if !assert.NoError(t, err) {
errorIncludesFields(t, err, []string{})
}
return
}
errorIncludesFields(t, err, tc.badFields)
})
}
}
func TestValidateUpdateRequest(t *testing.T) {
cases := []struct {
name string
prefix string
req UpdateRequest
item ApiResource
valFn CustomValidatorFunc
badFields []string
}{
{
name: "valid",
prefix: "prefix",
req: &pbs.UpdateUserRequest{
Id: "prefix_something",
UpdateMask: &fieldmaskpb.FieldMask{Paths: []string{"anything"}},
},
item: &pb.User{
Version: 1,
},
valFn: NoopValidatorFn,
},
{
name: "missing mask",
prefix: "prefix",
req: &pbs.UpdateUserRequest{
Id: "prefix_something",
},
item: &pb.User{
Version: 1,
},
valFn: NoopValidatorFn,
badFields: []string{"update_mask"},
},
{
name: "bad id",
prefix: "prefix",
req: &pbs.UpdateUserRequest{
Id: "mismatched_prefix",
UpdateMask: &fieldmaskpb.FieldMask{Paths: []string{"anything"}},
},
item: &pb.User{
Version: 1,
},
valFn: NoopValidatorFn,
badFields: []string{"id"},
},
{
name: "good name",
prefix: "prefix",
req: &pbs.UpdateUserRequest{
Id: "prefix_something",
UpdateMask: &fieldmaskpb.FieldMask{Paths: []string{"anything"}},
},
item: &pb.User{
Version: 1,
Name: wrapperspb.String("foobar"),
},
valFn: NoopValidatorFn,
},
{
name: "bad name",
prefix: "prefix",
req: &pbs.UpdateUserRequest{
Id: "prefix_something",
UpdateMask: &fieldmaskpb.FieldMask{Paths: []string{"anything"}},
},
item: &pb.User{
Version: 1,
Name: wrapperspb.String("foo\u200Bbar"),
},
valFn: NoopValidatorFn,
badFields: []string{"name"},
},
{
name: "good description",
prefix: "prefix",
req: &pbs.UpdateUserRequest{
Id: "prefix_something",
UpdateMask: &fieldmaskpb.FieldMask{Paths: []string{"anything"}},
},
item: &pb.User{
Version: 1,
Description: wrapperspb.String("foobar"),
},
valFn: NoopValidatorFn,
},
{
name: "bad description",
prefix: "prefix",
req: &pbs.UpdateUserRequest{
Id: "prefix_something",
UpdateMask: &fieldmaskpb.FieldMask{Paths: []string{"anything"}},
},
item: &pb.User{
Version: 1,
Description: wrapperspb.String("foo\u200Bbar"),
},
valFn: NoopValidatorFn,
badFields: []string{"description"},
},
{
name: "missing version",
prefix: "prefix",
req: &pbs.UpdateUserRequest{
Id: "prefix_something",
UpdateMask: &fieldmaskpb.FieldMask{Paths: []string{"anything"}},
},
item: &pb.User{},
valFn: NoopValidatorFn,
badFields: []string{"version"},
},
{
name: "bad create time",
prefix: "prefix",
req: &pbs.UpdateUserRequest{
Id: "prefix_something",
UpdateMask: &fieldmaskpb.FieldMask{Paths: []string{"anything"}},
},
item: &pb.User{
Version: 1,
CreatedTime: timestamppb.Now(),
},
valFn: NoopValidatorFn,
badFields: []string{"created_time"},
},
{
name: "bad updated time",
prefix: "prefix",
req: &pbs.UpdateUserRequest{
Id: "prefix_something",
UpdateMask: &fieldmaskpb.FieldMask{Paths: []string{"anything"}},
},
item: &pb.User{
Version: 1,
UpdatedTime: timestamppb.Now(),
},
valFn: NoopValidatorFn,
badFields: []string{"updated_time"},
},
{
name: "bad defined id on item",
prefix: "prefix",
req: &pbs.UpdateUserRequest{
Id: "prefix_something",
UpdateMask: &fieldmaskpb.FieldMask{Paths: []string{"anything"}},
},
item: &pb.User{
Id: "prefix_something",
Version: 1,
},
valFn: NoopValidatorFn,
badFields: []string{"id"},
},
{
name: "custom validator error",
prefix: "prefix",
req: &pbs.UpdateUserRequest{
Id: "prefix_something",
UpdateMask: &fieldmaskpb.FieldMask{Paths: []string{"anything"}},
},
item: &pb.User{
Version: 1,
},
valFn: func() map[string]string {
return map[string]string{
"test": "test",
}
},
badFields: []string{"test"},
},
{
name: "multiple",
prefix: "prefix",
req: &pbs.UpdateUserRequest{},
item: &pb.User{},
valFn: NoopValidatorFn,
badFields: []string{"id", "update_mask", "version"},
},
}
for _, tc := range cases {
t.Run(tc.name, func(t *testing.T) {
err := ValidateUpdateRequest(tc.req, tc.item, tc.valFn, tc.prefix)
if len(tc.badFields) == 0 {
if !assert.NoError(t, err) {
errorIncludesFields(t, err, []string{})
}
return
}
errorIncludesFields(t, err, tc.badFields)
})
}
}