consul/internal/controller/dependency/cache_test.go

347 lines
8.9 KiB
Go

// Copyright (c) HashiCorp, Inc.
// SPDX-License-Identifier: BUSL-1.1
package dependency
import (
"context"
"testing"
"github.com/hashicorp/consul/internal/controller"
"github.com/hashicorp/consul/internal/controller/cache/cachemock"
"github.com/hashicorp/consul/internal/controller/dependency/dependencymock"
"github.com/hashicorp/consul/internal/resource"
"github.com/hashicorp/consul/internal/resource/resourcetest"
"github.com/hashicorp/consul/proto-public/pbresource"
"github.com/hashicorp/consul/proto/private/prototest"
"github.com/hashicorp/consul/sdk/testutil"
"github.com/hashicorp/go-hclog"
"github.com/stretchr/testify/mock"
"github.com/stretchr/testify/require"
"github.com/stretchr/testify/suite"
)
type cacheSuite struct {
suite.Suite
cache *cachemock.ReadOnlyCache
idMod *dependencymock.CacheIDModifier
res *pbresource.Resource
rt controller.Runtime
}
func (suite *cacheSuite) SetupTest() {
suite.res = resourcetest.Resource(fakeMapType, "foo").
WithTenancy(resource.DefaultNamespacedTenancy()).
Build()
suite.idMod = dependencymock.NewCacheIDModifier(suite.T())
suite.cache = cachemock.NewReadOnlyCache(suite.T())
suite.rt = controller.Runtime{
Cache: suite.cache,
Logger: testutil.Logger(suite.T()),
}
}
func (suite *cacheSuite) TestGetMapper_ModErr() {
suite.idMod.EXPECT().
Execute(mock.Anything, suite.rt, suite.res.Id).
Return(nil, injectedErr).
Once()
reqs, err := CacheGetMapper(suite.res.Id.Type, "doesnt-matter", suite.idMod.Execute)(
context.Background(),
suite.rt,
suite.res,
)
require.Nil(suite.T(), reqs)
require.ErrorIs(suite.T(), err, injectedErr)
}
func (suite *cacheSuite) TestGetMapper_CacheErr() {
id := resourceID("testing", "v1", "fake", "foo")
suite.idMod.EXPECT().
Execute(mock.Anything, suite.rt, suite.res.Id).
Return(id, nil).
Once()
suite.cache.EXPECT().
Get(suite.res.Id.Type, "fake-index", id).
Return(nil, injectedErr).
Once()
reqs, err := CacheGetMapper(suite.res.Id.Type, "fake-index", suite.idMod.Execute)(
context.Background(),
suite.rt,
suite.res,
)
require.Nil(suite.T(), reqs)
require.ErrorIs(suite.T(), err, injectedErr)
}
func (suite *cacheSuite) TestGetMapper_Ok() {
out := resourcetest.Resource(altFakeResourceType, "blah").
WithTenancy(resource.DefaultNamespacedTenancy()).
Build()
id := resourceID("testing", "v1", "fake", "foo")
suite.idMod.EXPECT().
Execute(mock.Anything, suite.rt, suite.res.Id).
Return(id, nil).
Once()
suite.cache.EXPECT().
Get(suite.res.Id.Type, "fake-index", id).
Return(out, nil).
Once()
reqs, err := CacheGetMapper(suite.res.Id.Type, "fake-index", suite.idMod.Execute)(
context.Background(),
suite.rt,
suite.res,
)
require.NoError(suite.T(), err)
require.Len(suite.T(), reqs, 1)
prototest.AssertDeepEqual(suite.T(), out.Id, reqs[0].ID)
}
func (suite *cacheSuite) TestListMapper_ModErr() {
suite.idMod.EXPECT().
Execute(mock.Anything, suite.rt, suite.res.Id).
Return(nil, injectedErr).
Once()
reqs, err := CacheListMapper(suite.res.Id.Type, "doesnt-matter", suite.idMod.Execute)(
context.Background(),
suite.rt,
suite.res,
)
require.Nil(suite.T(), reqs)
require.ErrorIs(suite.T(), err, injectedErr)
}
func (suite *cacheSuite) TestListMapper_CacheErr() {
id := resourceID("testing", "v1", "fake", "foo")
suite.idMod.EXPECT().
Execute(mock.Anything, suite.rt, suite.res.Id).
Return(id, nil).
Once()
suite.cache.EXPECT().
ListIterator(suite.res.Id.Type, "fake-index", id).
Return(nil, injectedErr).
Once()
reqs, err := CacheListMapper(suite.res.Id.Type, "fake-index", suite.idMod.Execute)(
context.Background(),
suite.rt,
suite.res,
)
require.Nil(suite.T(), reqs)
require.ErrorIs(suite.T(), err, injectedErr)
}
func (suite *cacheSuite) TestListMapper_Ok() {
out := resourcetest.Resource(altFakeResourceType, "blah").
WithTenancy(resource.DefaultNamespacedTenancy()).
Build()
out2 := resourcetest.Resource(altFakeResourceType, "blah2").
WithTenancy(resource.DefaultNamespacedTenancy()).
Build()
id := resourceID("testing", "v1", "fake", "foo")
suite.idMod.EXPECT().
Execute(mock.Anything, suite.rt, suite.res.Id).
Return(id, nil).
Once()
mockIter := cachemock.NewResourceIterator(suite.T())
mockIter.EXPECT().Next().Return(out).Once()
mockIter.EXPECT().Next().Return(out2).Once()
mockIter.EXPECT().Next().Return(nil).Once()
suite.cache.EXPECT().
ListIterator(suite.res.Id.Type, "fake-index", id).
Return(mockIter, nil).
Once()
reqs, err := CacheListMapper(suite.res.Id.Type, "fake-index", suite.idMod.Execute)(
context.Background(),
suite.rt,
suite.res,
)
require.NoError(suite.T(), err)
require.Len(suite.T(), reqs, 2)
expected := []controller.Request{
{ID: out.Id},
{ID: out2.Id},
}
prototest.AssertElementsMatch(suite.T(), expected, reqs)
}
func (suite *cacheSuite) TestParentsMapper_ModErr() {
suite.idMod.EXPECT().
Execute(mock.Anything, suite.rt, suite.res.Id).
Return(nil, injectedErr).
Once()
reqs, err := CacheParentsMapper(suite.res.Id.Type, "doesnt-matter", suite.idMod.Execute)(
context.Background(),
suite.rt,
suite.res,
)
require.Nil(suite.T(), reqs)
require.ErrorIs(suite.T(), err, injectedErr)
}
func (suite *cacheSuite) TestParentsMapper_CacheErr() {
id := resourceID("testing", "v1", "fake", "foo")
suite.idMod.EXPECT().
Execute(mock.Anything, suite.rt, suite.res.Id).
Return(id, nil).
Once()
suite.cache.EXPECT().
ParentsIterator(suite.res.Id.Type, "fake-index", id).
Return(nil, injectedErr).
Once()
reqs, err := CacheParentsMapper(suite.res.Id.Type, "fake-index", suite.idMod.Execute)(
context.Background(),
suite.rt,
suite.res,
)
require.Nil(suite.T(), reqs)
require.ErrorIs(suite.T(), err, injectedErr)
}
func (suite *cacheSuite) TestParentsMapper_Ok() {
out := resourcetest.Resource(altFakeResourceType, "blah").
WithTenancy(resource.DefaultNamespacedTenancy()).
Build()
out2 := resourcetest.Resource(altFakeResourceType, "blah2").
WithTenancy(resource.DefaultNamespacedTenancy()).
Build()
id := resourceID("testing", "v1", "fake", "foo")
suite.idMod.EXPECT().
Execute(mock.Anything, suite.rt, suite.res.Id).
Return(id, nil).
Once()
mockIter := cachemock.NewResourceIterator(suite.T())
mockIter.EXPECT().Next().Return(out).Once()
mockIter.EXPECT().Next().Return(out2).Once()
mockIter.EXPECT().Next().Return(nil).Once()
suite.cache.EXPECT().
ParentsIterator(suite.res.Id.Type, "fake-index", id).
Return(mockIter, nil).
Once()
reqs, err := CacheParentsMapper(suite.res.Id.Type, "fake-index", suite.idMod.Execute)(
context.Background(),
suite.rt,
suite.res,
)
require.NoError(suite.T(), err)
require.Len(suite.T(), reqs, 2)
expected := []controller.Request{
{ID: out.Id},
{ID: out2.Id},
}
prototest.AssertElementsMatch(suite.T(), expected, reqs)
}
func (suite *cacheSuite) TestListTransform_ModErr() {
suite.idMod.EXPECT().
Execute(mock.Anything, suite.rt, suite.res.Id).
Return(nil, injectedErr).
Once()
reqs, err := CacheListTransform(suite.res.Id.Type, "doesnt-matter", suite.idMod.Execute)(
context.Background(),
suite.rt,
suite.res,
)
require.Nil(suite.T(), reqs)
require.ErrorIs(suite.T(), err, injectedErr)
}
func (suite *cacheSuite) TestListTransform_CacheErr() {
id := resourceID("testing", "v1", "fake", "foo")
suite.idMod.EXPECT().
Execute(mock.Anything, suite.rt, suite.res.Id).
Return(id, nil).
Once()
suite.cache.EXPECT().
List(suite.res.Id.Type, "fake-index", id).
Return(nil, injectedErr).
Once()
resources, err := CacheListTransform(suite.res.Id.Type, "fake-index", suite.idMod.Execute)(
context.Background(),
suite.rt,
suite.res,
)
require.Nil(suite.T(), resources)
require.ErrorIs(suite.T(), err, injectedErr)
}
func (suite *cacheSuite) TestListTransform_Ok() {
out := resourcetest.Resource(altFakeResourceType, "blah").
WithTenancy(resource.DefaultNamespacedTenancy()).
Build()
out2 := resourcetest.Resource(altFakeResourceType, "blah2").
WithTenancy(resource.DefaultNamespacedTenancy()).
Build()
id := resourceID("testing", "v1", "fake", "foo")
suite.idMod.EXPECT().
Execute(mock.Anything, suite.rt, suite.res.Id).
Return(id, nil).
Once()
expected := []*pbresource.Resource{out, out2}
suite.cache.EXPECT().
List(suite.res.Id.Type, "fake-index", id).
Return(expected, nil).
Once()
resources, err := CacheListTransform(suite.res.Id.Type, "fake-index", suite.idMod.Execute)(
context.Background(),
suite.rt,
suite.res,
)
require.NoError(suite.T(), err)
prototest.AssertElementsMatch(suite.T(), expected, resources)
}
func TestCacheDependencies(t *testing.T) {
suite.Run(t, new(cacheSuite))
}
func TestReplaceCacheIDType(t *testing.T) {
rt := controller.Runtime{
// populate something to differentiate from zero value
Logger: hclog.Default(),
}
in := resourceID("testing", "v1", "pre-mod", "foo")
mod := ReplaceCacheIDType(fakeResourceType)
out, err := mod(context.Background(), rt, in)
require.NoError(t, err)
prototest.AssertDeepEqual(t, resource.ReplaceType(fakeResourceType, in), out)
}