2023-03-28 22:48:58 +00:00
|
|
|
// Copyright (c) HashiCorp, Inc.
|
|
|
|
// SPDX-License-Identifier: MPL-2.0
|
|
|
|
|
2023-04-11 11:10:14 +00:00
|
|
|
package resource_test
|
2023-03-14 18:30:25 +00:00
|
|
|
|
|
|
|
import (
|
|
|
|
"testing"
|
|
|
|
|
2023-04-11 11:10:14 +00:00
|
|
|
"github.com/hashicorp/consul/acl"
|
|
|
|
"github.com/hashicorp/consul/agent/grpc-external/testutils"
|
|
|
|
"github.com/hashicorp/consul/internal/resource"
|
|
|
|
"github.com/hashicorp/consul/internal/resource/demo"
|
2023-03-14 18:30:25 +00:00
|
|
|
"github.com/hashicorp/consul/proto-public/pbresource"
|
|
|
|
"github.com/stretchr/testify/assert"
|
2023-04-11 11:10:14 +00:00
|
|
|
"github.com/stretchr/testify/require"
|
2023-03-14 18:30:25 +00:00
|
|
|
)
|
|
|
|
|
|
|
|
func TestRegister(t *testing.T) {
|
2023-04-11 11:10:14 +00:00
|
|
|
r := resource.NewRegistry()
|
2023-03-14 18:30:25 +00:00
|
|
|
|
|
|
|
serviceType := &pbresource.Type{
|
|
|
|
Group: "mesh",
|
|
|
|
GroupVersion: "v1",
|
|
|
|
Kind: "service",
|
|
|
|
}
|
|
|
|
|
2023-04-11 11:10:14 +00:00
|
|
|
// register success
|
|
|
|
serviceRegistration := resource.Registration{Type: serviceType}
|
2023-03-14 18:30:25 +00:00
|
|
|
r.Register(serviceRegistration)
|
|
|
|
|
|
|
|
// register existing should panic
|
2023-04-11 11:10:14 +00:00
|
|
|
assertRegisterPanics(t, r.Register, serviceRegistration, "resource type mesh.v1.service already registered")
|
2023-03-14 18:30:25 +00:00
|
|
|
|
|
|
|
// register empty Group should panic
|
2023-04-11 11:10:14 +00:00
|
|
|
assertRegisterPanics(t, r.Register, resource.Registration{
|
2023-03-14 18:30:25 +00:00
|
|
|
Type: &pbresource.Type{
|
|
|
|
Group: "",
|
|
|
|
GroupVersion: "v1",
|
|
|
|
Kind: "service",
|
|
|
|
},
|
|
|
|
}, "type field(s) cannot be empty")
|
|
|
|
|
|
|
|
// register empty GroupVersion should panic
|
2023-04-11 11:10:14 +00:00
|
|
|
assertRegisterPanics(t, r.Register, resource.Registration{
|
2023-03-14 18:30:25 +00:00
|
|
|
Type: &pbresource.Type{
|
|
|
|
Group: "mesh",
|
|
|
|
GroupVersion: "",
|
|
|
|
Kind: "service",
|
|
|
|
},
|
|
|
|
}, "type field(s) cannot be empty")
|
|
|
|
|
|
|
|
// register empty Kind should panic
|
2023-04-11 11:10:14 +00:00
|
|
|
assertRegisterPanics(t, r.Register, resource.Registration{
|
2023-03-14 18:30:25 +00:00
|
|
|
Type: &pbresource.Type{
|
|
|
|
Group: "mesh",
|
|
|
|
GroupVersion: "v1",
|
|
|
|
Kind: "",
|
|
|
|
},
|
|
|
|
}, "type field(s) cannot be empty")
|
|
|
|
}
|
|
|
|
|
2023-04-11 11:55:32 +00:00
|
|
|
func TestRegister_Defaults(t *testing.T) {
|
2023-04-11 11:10:14 +00:00
|
|
|
r := resource.NewRegistry()
|
2023-04-12 21:50:07 +00:00
|
|
|
r.Register(resource.Registration{Type: demo.TypeV2Artist})
|
2023-04-11 11:10:14 +00:00
|
|
|
artist, err := demo.GenerateV2Artist()
|
|
|
|
require.NoError(t, err)
|
|
|
|
|
|
|
|
reg, ok := r.Resolve(demo.TypeV2Artist)
|
|
|
|
require.True(t, ok)
|
|
|
|
|
|
|
|
// verify default read hook requires operator:read
|
|
|
|
require.NoError(t, reg.ACLs.Read(testutils.ACLOperatorRead(t), artist.Id))
|
|
|
|
require.True(t, acl.IsErrPermissionDenied(reg.ACLs.Read(testutils.ACLNoPermissions(t), artist.Id)))
|
|
|
|
|
|
|
|
// verify default write hook requires operator:write
|
2023-04-12 21:22:44 +00:00
|
|
|
require.NoError(t, reg.ACLs.Write(testutils.ACLOperatorWrite(t), artist.Id))
|
|
|
|
require.True(t, acl.IsErrPermissionDenied(reg.ACLs.Write(testutils.ACLNoPermissions(t), artist.Id)))
|
2023-04-11 11:10:14 +00:00
|
|
|
|
|
|
|
// verify default list hook requires operator:read
|
|
|
|
require.NoError(t, reg.ACLs.List(testutils.ACLOperatorRead(t), artist.Id.Tenancy))
|
|
|
|
require.True(t, acl.IsErrPermissionDenied(reg.ACLs.List(testutils.ACLNoPermissions(t), artist.Id.Tenancy)))
|
2023-04-11 11:55:32 +00:00
|
|
|
|
|
|
|
// verify default validate is a no-op
|
|
|
|
require.NoError(t, reg.Validate(nil))
|
2023-04-12 21:50:07 +00:00
|
|
|
|
|
|
|
// verify default mutate is a no-op
|
|
|
|
require.NoError(t, reg.Mutate(nil))
|
2023-04-11 11:10:14 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
func assertRegisterPanics(t *testing.T, registerFn func(reg resource.Registration), registration resource.Registration, panicString string) {
|
2023-03-14 18:30:25 +00:00
|
|
|
defer func() {
|
|
|
|
if r := recover(); r == nil {
|
|
|
|
t.Errorf("expected panic, but none occurred")
|
|
|
|
} else {
|
|
|
|
errstr, ok := r.(string)
|
|
|
|
if !ok {
|
|
|
|
t.Errorf("unexpected error type returned from panic")
|
|
|
|
} else if errstr != panicString {
|
|
|
|
t.Errorf("expected %s error message but got: %s", panicString, errstr)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}()
|
|
|
|
|
|
|
|
registerFn(registration)
|
|
|
|
}
|
|
|
|
|
|
|
|
func TestResolve(t *testing.T) {
|
2023-04-11 11:10:14 +00:00
|
|
|
r := resource.NewRegistry()
|
2023-03-14 18:30:25 +00:00
|
|
|
|
|
|
|
serviceType := &pbresource.Type{
|
|
|
|
Group: "mesh",
|
|
|
|
GroupVersion: "v1",
|
|
|
|
Kind: "service",
|
|
|
|
}
|
|
|
|
|
|
|
|
// not found
|
|
|
|
_, ok := r.Resolve(serviceType)
|
|
|
|
assert.False(t, ok)
|
|
|
|
|
|
|
|
// found
|
2023-04-11 11:10:14 +00:00
|
|
|
r.Register(resource.Registration{Type: serviceType})
|
2023-03-14 18:30:25 +00:00
|
|
|
registration, ok := r.Resolve(serviceType)
|
|
|
|
assert.True(t, ok)
|
|
|
|
assert.Equal(t, registration.Type, serviceType)
|
|
|
|
}
|