2023-08-11 13:12:13 +00:00
|
|
|
// Copyright (c) HashiCorp, Inc.
|
|
|
|
// SPDX-License-Identifier: BUSL-1.1
|
|
|
|
|
2023-12-13 15:06:39 +00:00
|
|
|
package dependency
|
2023-06-06 21:09:48 +00:00
|
|
|
|
|
|
|
import (
|
|
|
|
"context"
|
|
|
|
"testing"
|
|
|
|
|
|
|
|
"github.com/google/go-cmp/cmp/cmpopts"
|
2024-02-09 21:42:10 +00:00
|
|
|
"github.com/stretchr/testify/require"
|
|
|
|
|
2023-12-13 15:06:39 +00:00
|
|
|
"github.com/hashicorp/consul/internal/controller"
|
2024-02-09 21:42:10 +00:00
|
|
|
"github.com/hashicorp/consul/internal/resource"
|
|
|
|
"github.com/hashicorp/consul/internal/resource/resourcetest"
|
2023-06-06 21:09:48 +00:00
|
|
|
"github.com/hashicorp/consul/proto-public/pbresource"
|
2024-02-09 21:42:10 +00:00
|
|
|
pbdemo "github.com/hashicorp/consul/proto/private/pbdemo/v1"
|
2023-06-06 21:09:48 +00:00
|
|
|
"github.com/hashicorp/consul/proto/private/prototest"
|
2024-02-09 21:42:10 +00:00
|
|
|
"github.com/hashicorp/consul/sdk/testutil"
|
2023-06-06 21:09:48 +00:00
|
|
|
)
|
|
|
|
|
|
|
|
func resourceID(group string, version string, kind string, name string) *pbresource.ID {
|
|
|
|
return &pbresource.ID{
|
|
|
|
Type: &pbresource.Type{
|
|
|
|
Group: group,
|
|
|
|
GroupVersion: version,
|
|
|
|
Kind: kind,
|
|
|
|
},
|
|
|
|
Tenancy: &pbresource.Tenancy{
|
|
|
|
Partition: "default",
|
|
|
|
Namespace: "default",
|
|
|
|
},
|
|
|
|
Name: name,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
func TestMapOwner(t *testing.T) {
|
|
|
|
owner := resourceID("foo", "v99", "bar", "object")
|
|
|
|
|
|
|
|
res := &pbresource.Resource{
|
|
|
|
Id: resourceID("something", "v1", "else", "x"),
|
|
|
|
Owner: owner,
|
|
|
|
}
|
|
|
|
|
2023-12-13 15:06:39 +00:00
|
|
|
reqs, err := MapOwner(context.Background(), controller.Runtime{}, res)
|
2023-06-06 21:09:48 +00:00
|
|
|
require.NoError(t, err)
|
|
|
|
require.Len(t, reqs, 1)
|
|
|
|
prototest.AssertDeepEqual(t, owner, reqs[0].ID)
|
|
|
|
}
|
|
|
|
|
|
|
|
func TestMapOwnerFiltered(t *testing.T) {
|
|
|
|
mapper := MapOwnerFiltered(&pbresource.Type{
|
|
|
|
Group: "foo",
|
|
|
|
GroupVersion: "v1",
|
|
|
|
Kind: "bar",
|
|
|
|
})
|
|
|
|
|
|
|
|
type testCase struct {
|
|
|
|
owner *pbresource.ID
|
|
|
|
matches bool
|
|
|
|
}
|
|
|
|
|
|
|
|
cases := map[string]testCase{
|
|
|
|
"nil-owner": {
|
|
|
|
owner: nil,
|
|
|
|
matches: false,
|
|
|
|
},
|
|
|
|
"group-mismatch": {
|
|
|
|
owner: resourceID("other", "v1", "bar", "irrelevant"),
|
|
|
|
matches: false,
|
|
|
|
},
|
|
|
|
"group-version-mismatch": {
|
|
|
|
owner: resourceID("foo", "v2", "bar", "irrelevant"),
|
|
|
|
matches: false,
|
|
|
|
},
|
|
|
|
"kind-mismatch": {
|
|
|
|
owner: resourceID("foo", "v1", "baz", "irrelevant"),
|
|
|
|
matches: false,
|
|
|
|
},
|
|
|
|
"match": {
|
|
|
|
owner: resourceID("foo", "v1", "bar", "irrelevant"),
|
|
|
|
matches: true,
|
|
|
|
},
|
|
|
|
}
|
|
|
|
|
|
|
|
for name, tcase := range cases {
|
|
|
|
t.Run(name, func(t *testing.T) {
|
|
|
|
// the runtime is not used by the mapper so its fine to pass an empty struct
|
2023-12-13 15:06:39 +00:00
|
|
|
req, err := mapper(context.Background(), controller.Runtime{}, &pbresource.Resource{
|
2023-06-06 21:09:48 +00:00
|
|
|
Id: resourceID("foo", "v1", "other", "x"),
|
|
|
|
Owner: tcase.owner,
|
|
|
|
})
|
|
|
|
|
|
|
|
// The mapper has no error paths at present
|
|
|
|
require.NoError(t, err)
|
|
|
|
|
|
|
|
if tcase.matches {
|
|
|
|
require.NotNil(t, req)
|
|
|
|
require.Len(t, req, 1)
|
|
|
|
prototest.AssertDeepEqual(t, req[0].ID, tcase.owner, cmpopts.EquateEmpty())
|
|
|
|
} else {
|
|
|
|
require.Nil(t, req)
|
|
|
|
}
|
|
|
|
})
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
func TestReplaceType(t *testing.T) {
|
|
|
|
rtype := &pbresource.Type{
|
|
|
|
Group: "foo",
|
|
|
|
GroupVersion: "v1",
|
|
|
|
Kind: "bar",
|
|
|
|
}
|
|
|
|
|
|
|
|
tenant := &pbresource.Tenancy{
|
|
|
|
Partition: "not",
|
|
|
|
Namespace: "using",
|
|
|
|
}
|
|
|
|
|
|
|
|
in := &pbresource.Resource{
|
|
|
|
Id: &pbresource.ID{
|
|
|
|
Type: &pbresource.Type{
|
|
|
|
Group: "other",
|
|
|
|
GroupVersion: "v2",
|
|
|
|
Kind: "baz",
|
|
|
|
},
|
|
|
|
Tenancy: tenant,
|
|
|
|
Name: "arr-matey",
|
|
|
|
},
|
|
|
|
}
|
|
|
|
|
|
|
|
mapper := ReplaceType(rtype)
|
|
|
|
|
2023-12-13 15:06:39 +00:00
|
|
|
reqs, err := mapper(nil, controller.Runtime{}, in)
|
2023-06-06 21:09:48 +00:00
|
|
|
require.NoError(t, err)
|
|
|
|
require.Len(t, reqs, 1)
|
|
|
|
|
|
|
|
expected := &pbresource.ID{
|
|
|
|
Type: rtype,
|
|
|
|
Tenancy: tenant,
|
|
|
|
Name: "arr-matey",
|
|
|
|
}
|
|
|
|
prototest.AssertDeepEqual(t, expected, reqs[0].ID)
|
|
|
|
}
|
2024-02-09 21:42:10 +00:00
|
|
|
|
|
|
|
func TestMapDecoded(t *testing.T) {
|
|
|
|
mapper := MapDecoded[*pbdemo.Artist](func(_ context.Context, _ controller.Runtime, res *resource.DecodedResource[*pbdemo.Artist]) ([]controller.Request, error) {
|
|
|
|
return []controller.Request{
|
|
|
|
{
|
|
|
|
ID: &pbresource.ID{
|
|
|
|
Type: res.Id.Type,
|
|
|
|
Tenancy: res.Id.Tenancy,
|
|
|
|
// not realistic for how the Artist's Name is intended but we just want to pull
|
|
|
|
// some data out of the decoded portion and return it.
|
|
|
|
Name: res.Data.Name,
|
|
|
|
},
|
|
|
|
},
|
|
|
|
}, nil
|
|
|
|
})
|
|
|
|
|
|
|
|
for _, tenancy := range resourcetest.TestTenancies() {
|
|
|
|
t.Run(resourcetest.AppendTenancyInfo(t.Name(), tenancy), func(t *testing.T) {
|
|
|
|
ctx := testutil.TestContext(t)
|
|
|
|
|
|
|
|
res1 := resourcetest.Resource(pbdemo.ArtistType, "foo").
|
|
|
|
WithTenancy(tenancy).
|
|
|
|
WithData(t, &pbdemo.Artist{Name: "something"}).
|
|
|
|
Build()
|
|
|
|
|
|
|
|
res2 := resourcetest.Resource(pbdemo.ArtistType, "foo").
|
|
|
|
WithTenancy(tenancy).
|
|
|
|
// Wrong data type here to force an error in the outer decoder
|
|
|
|
WithData(t, &pbdemo.Album{Name: "else"}).
|
|
|
|
Build()
|
|
|
|
|
|
|
|
reqs, err := mapper(ctx, controller.Runtime{}, res1)
|
|
|
|
require.NoError(t, err)
|
|
|
|
require.Len(t, reqs, 1)
|
|
|
|
|
|
|
|
expected := &pbresource.ID{
|
|
|
|
Type: res1.Id.Type,
|
|
|
|
Tenancy: res1.Id.Tenancy,
|
|
|
|
Name: "something",
|
|
|
|
}
|
|
|
|
prototest.AssertDeepEqual(t, expected, reqs[0].ID)
|
|
|
|
|
|
|
|
reqs, err = mapper(ctx, controller.Runtime{}, res2)
|
|
|
|
require.Nil(t, reqs)
|
|
|
|
require.Error(t, err)
|
|
|
|
})
|
|
|
|
}
|
|
|
|
}
|