mirror of https://github.com/status-im/consul.git
[CE] Test tenancies for exported-services config manager (#20678)
Sync controller tests from ENT
This commit is contained in:
parent
3f3477cdd3
commit
53afd8f4c5
|
@ -6,8 +6,11 @@ package v1compat
|
|||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"slices"
|
||||
"sort"
|
||||
|
||||
"golang.org/x/exp/maps"
|
||||
|
||||
"github.com/hashicorp/consul/acl"
|
||||
"github.com/hashicorp/consul/agent/structs"
|
||||
"github.com/hashicorp/consul/internal/controller"
|
||||
|
@ -25,6 +28,7 @@ const (
|
|||
controllerMetaKey = "managed-by-controller"
|
||||
)
|
||||
|
||||
//go:generate mockery --name AggregatedConfig --inpackage --with-expecter --filename mock_AggregatedConfig.go
|
||||
type AggregatedConfig interface {
|
||||
Start(context.Context)
|
||||
GetExportedServicesConfigEntry(context.Context, string, *acl.EnterpriseMeta) (*structs.ExportedServicesConfigEntry, error)
|
||||
|
@ -87,7 +91,9 @@ func (r *reconciler) Reconcile(ctx context.Context, rt controller.Runtime, req c
|
|||
entMeta.OverridePartition(req.ID.Tenancy.Partition)
|
||||
existing, err := r.config.GetExportedServicesConfigEntry(ctx, req.ID.Tenancy.Partition, entMeta)
|
||||
if err != nil {
|
||||
rt.Logger.Error("error getting exported service config entry", "error", err)
|
||||
// When we can't read the existing exported-services we purposely allow
|
||||
// reconciler to continue so we can still write a new one
|
||||
rt.Logger.Warn("error getting exported service config entry but continuing reconcile", "error", err)
|
||||
}
|
||||
|
||||
if existing != nil && existing.Meta["managed-by-controller"] != ControllerName {
|
||||
|
@ -117,7 +123,6 @@ func (r *reconciler) Reconcile(ctx context.Context, rt controller.Runtime, req c
|
|||
},
|
||||
index.IndexQueryOptions{Prefix: true},
|
||||
)
|
||||
|
||||
if err != nil {
|
||||
rt.Logger.Error("error retrieving partition exported services", "error", err)
|
||||
return err
|
||||
|
@ -133,9 +138,8 @@ func (r *reconciler) Reconcile(ctx context.Context, rt controller.Runtime, req c
|
|||
},
|
||||
index.IndexQueryOptions{Prefix: true},
|
||||
)
|
||||
|
||||
if err != nil {
|
||||
rt.Logger.Error("error retrieving namespace exported service", "error", err)
|
||||
rt.Logger.Error("error retrieving namespace exported services", "error", err)
|
||||
return err
|
||||
}
|
||||
|
||||
|
@ -149,7 +153,6 @@ func (r *reconciler) Reconcile(ctx context.Context, rt controller.Runtime, req c
|
|||
},
|
||||
index.IndexQueryOptions{Prefix: true},
|
||||
)
|
||||
|
||||
if err != nil {
|
||||
rt.Logger.Error("error retrieving exported services", "error", err)
|
||||
return err
|
||||
|
@ -243,24 +246,24 @@ func (c *exportConsumers) addConsumers(consumers []*pbmulticluster.ExportedServi
|
|||
func (c *exportConsumers) configEntryConsumers() []structs.ServiceConsumer {
|
||||
consumers := make([]structs.ServiceConsumer, 0, len(c.partitions)+len(c.peers)+len(c.samenessGroups))
|
||||
|
||||
partitions := keys(c.partitions)
|
||||
sort.Strings(partitions)
|
||||
partitions := maps.Keys(c.partitions)
|
||||
slices.Sort(partitions)
|
||||
for _, consumer := range partitions {
|
||||
consumers = append(consumers, structs.ServiceConsumer{
|
||||
Partition: consumer,
|
||||
})
|
||||
}
|
||||
|
||||
peers := keys(c.peers)
|
||||
sort.Strings(peers)
|
||||
peers := maps.Keys(c.peers)
|
||||
slices.Sort(peers)
|
||||
for _, consumer := range peers {
|
||||
consumers = append(consumers, structs.ServiceConsumer{
|
||||
Peer: consumer,
|
||||
})
|
||||
}
|
||||
|
||||
samenessGroups := keys(c.samenessGroups)
|
||||
sort.Strings(samenessGroups)
|
||||
samenessGroups := maps.Keys(c.samenessGroups)
|
||||
slices.Sort(samenessGroups)
|
||||
for _, consumer := range samenessGroups {
|
||||
consumers = append(consumers, structs.ServiceConsumer{
|
||||
SamenessGroup: consumer,
|
||||
|
@ -316,8 +319,8 @@ func (t *exportTracker) allExports() []structs.ExportedService {
|
|||
})
|
||||
}
|
||||
|
||||
namespaces := keys(t.namespaces)
|
||||
sort.Strings(namespaces)
|
||||
namespaces := maps.Keys(t.namespaces)
|
||||
slices.Sort(namespaces)
|
||||
for _, ns := range namespaces {
|
||||
exports = append(exports, structs.ExportedService{
|
||||
Name: "*",
|
||||
|
@ -326,7 +329,7 @@ func (t *exportTracker) allExports() []structs.ExportedService {
|
|||
})
|
||||
}
|
||||
|
||||
services := keys(t.services)
|
||||
services := maps.Keys(t.services)
|
||||
sort.Slice(services, func(i, j int) bool {
|
||||
// the partitions must already be equal because we are only
|
||||
// looking at resource exports for a single partition.
|
||||
|
|
|
@ -0,0 +1,428 @@
|
|||
// Copyright (c) HashiCorp, Inc.
|
||||
// SPDX-License-Identifier: BUSL-1.1
|
||||
|
||||
package v1compat
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/require"
|
||||
"github.com/stretchr/testify/suite"
|
||||
|
||||
"github.com/hashicorp/consul/acl"
|
||||
svctest "github.com/hashicorp/consul/agent/grpc-external/services/resource/testing"
|
||||
"github.com/hashicorp/consul/agent/structs"
|
||||
"github.com/hashicorp/consul/internal/catalog"
|
||||
"github.com/hashicorp/consul/internal/controller"
|
||||
"github.com/hashicorp/consul/internal/multicluster/internal/types"
|
||||
"github.com/hashicorp/consul/internal/resource"
|
||||
rtest "github.com/hashicorp/consul/internal/resource/resourcetest"
|
||||
pbmulticluster "github.com/hashicorp/consul/proto-public/pbmulticluster/v2"
|
||||
"github.com/hashicorp/consul/proto-public/pbresource"
|
||||
"github.com/hashicorp/consul/sdk/testutil"
|
||||
"github.com/hashicorp/consul/version/versiontest"
|
||||
)
|
||||
|
||||
type controllerSuite struct {
|
||||
suite.Suite
|
||||
ctx context.Context
|
||||
ctl *controller.TestController
|
||||
isEnterprise bool
|
||||
tenancies []*pbresource.Tenancy
|
||||
config *MockAggregatedConfig
|
||||
}
|
||||
|
||||
func (suite *controllerSuite) SetupTest() {
|
||||
suite.tenancies = rtest.TestTenancies()
|
||||
suite.isEnterprise = versiontest.IsEnterprise()
|
||||
suite.ctx = testutil.TestContext(suite.T())
|
||||
client := svctest.NewResourceServiceBuilder().
|
||||
WithRegisterFns(types.Register, catalog.RegisterTypes).
|
||||
WithTenancies(suite.tenancies...).
|
||||
Run(suite.T())
|
||||
|
||||
suite.config = NewMockAggregatedConfig(suite.T())
|
||||
suite.config.EXPECT().EventChannel().Return(make(chan controller.Event))
|
||||
suite.ctl = controller.NewTestController(
|
||||
Controller(suite.config),
|
||||
client,
|
||||
).WithLogger(testutil.Logger(suite.T()))
|
||||
}
|
||||
|
||||
// Test that we do nothing if V1 exports have not been replicated to v2 resources compatible with this controller
|
||||
func (suite *controllerSuite) TestReconcile_V1ExportsExist() {
|
||||
incompatibleConfig := &structs.ExportedServicesConfigEntry{
|
||||
Name: "v1Legacy",
|
||||
Meta: map[string]string{controllerMetaKey: "foo-controller"},
|
||||
}
|
||||
|
||||
suite.runTestCaseWithTenancies(func(tenancy *pbresource.Tenancy) {
|
||||
entMeta := acl.DefaultEnterpriseMeta()
|
||||
entMeta.OverridePartition(tenancy.Partition)
|
||||
|
||||
suite.config.EXPECT().
|
||||
GetExportedServicesConfigEntry(suite.ctx, tenancy.Partition, entMeta).
|
||||
Return(incompatibleConfig, nil)
|
||||
|
||||
resID := &pbresource.ID{
|
||||
Type: pbmulticluster.ComputedExportedServicesType,
|
||||
Tenancy: &pbresource.Tenancy{Partition: tenancy.Partition},
|
||||
Name: types.ComputedExportedServicesName,
|
||||
}
|
||||
err := suite.ctl.Reconcile(suite.ctx, controller.Request{ID: resID})
|
||||
require.NoError(suite.T(), err)
|
||||
})
|
||||
}
|
||||
|
||||
// Test that we do not stop reconciler even when we fail to retrieve the config entry
|
||||
func (suite *controllerSuite) TestReconcile_GetExportedServicesConfigEntry_Error() {
|
||||
suite.runTestCaseWithTenancies(func(tenancy *pbresource.Tenancy) {
|
||||
entMeta := acl.DefaultEnterpriseMeta()
|
||||
entMeta.OverridePartition(tenancy.Partition)
|
||||
|
||||
suite.config.EXPECT().
|
||||
GetExportedServicesConfigEntry(suite.ctx, tenancy.Partition, entMeta).
|
||||
Return(nil, fmt.Errorf("failed to retrieve config entry"))
|
||||
|
||||
resID := &pbresource.ID{
|
||||
Type: pbmulticluster.ComputedExportedServicesType,
|
||||
Tenancy: &pbresource.Tenancy{Partition: tenancy.Partition},
|
||||
Name: types.ComputedExportedServicesName,
|
||||
}
|
||||
err := suite.ctl.Reconcile(suite.ctx, controller.Request{ID: resID})
|
||||
require.NoError(suite.T(), err)
|
||||
})
|
||||
}
|
||||
|
||||
// Delete config entry for case where resources aren't found
|
||||
func (suite *controllerSuite) TestReconcile_DeleteConfig_MissingResources() {
|
||||
suite.runTestCaseWithTenancies(func(tenancy *pbresource.Tenancy) {
|
||||
entMeta := acl.DefaultEnterpriseMeta()
|
||||
entMeta.OverridePartition(tenancy.Partition)
|
||||
|
||||
configEntry := &structs.ExportedServicesConfigEntry{
|
||||
// v1 exported-services config entries must have a Name that is the partitions name
|
||||
Name: tenancy.Partition,
|
||||
Meta: map[string]string{
|
||||
controllerMetaKey: ControllerName,
|
||||
},
|
||||
EnterpriseMeta: acl.NewEnterpriseMetaWithPartition(tenancy.Partition, ""),
|
||||
}
|
||||
|
||||
suite.config.EXPECT().GetExportedServicesConfigEntry(suite.ctx, tenancy.Partition, entMeta).Return(configEntry, nil)
|
||||
suite.config.EXPECT().DeleteExportedServicesConfigEntry(suite.ctx, tenancy.Partition, entMeta).Return(nil)
|
||||
|
||||
resID := &pbresource.ID{
|
||||
Type: pbmulticluster.ComputedExportedServicesType,
|
||||
Tenancy: &pbresource.Tenancy{Partition: tenancy.Partition},
|
||||
Name: types.ComputedExportedServicesName,
|
||||
}
|
||||
err := suite.ctl.Reconcile(suite.ctx, controller.Request{ID: resID})
|
||||
require.NoError(suite.T(), err)
|
||||
})
|
||||
}
|
||||
|
||||
func (suite *controllerSuite) TestReconcile_NewExport_PartitionExport() {
|
||||
if !suite.isEnterprise {
|
||||
suite.T().Skip("this test should only run against the enterprise build")
|
||||
}
|
||||
|
||||
suite.runTestCaseWithTenancies(func(tenancy *pbresource.Tenancy) {
|
||||
entMeta := acl.DefaultEnterpriseMeta()
|
||||
entMeta.OverridePartition(tenancy.Partition)
|
||||
|
||||
// used as a return value for GetExportedServicesConfigEntry
|
||||
existingCE := &structs.ExportedServicesConfigEntry{
|
||||
// v1 exported-services config entries must have a Name that is the partitions name
|
||||
Name: tenancy.Partition,
|
||||
Meta: map[string]string{
|
||||
controllerMetaKey: ControllerName,
|
||||
},
|
||||
EnterpriseMeta: acl.NewEnterpriseMetaWithPartition(tenancy.Partition, ""),
|
||||
}
|
||||
suite.config.EXPECT().GetExportedServicesConfigEntry(suite.ctx, tenancy.Partition, entMeta).Return(existingCE, nil)
|
||||
|
||||
// expected config entry to be written by reconcile
|
||||
expectedCE := &structs.ExportedServicesConfigEntry{
|
||||
Name: tenancy.Partition,
|
||||
Services: []structs.ExportedService{
|
||||
{
|
||||
Name: "s1",
|
||||
Namespace: resource.DefaultNamespaceName,
|
||||
Consumers: []structs.ServiceConsumer{
|
||||
{
|
||||
Partition: "p1",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
Meta: map[string]string{
|
||||
controllerMetaKey: ControllerName,
|
||||
},
|
||||
EnterpriseMeta: *entMeta,
|
||||
}
|
||||
suite.config.EXPECT().WriteExportedServicesConfigEntry(suite.ctx, expectedCE).Return(nil)
|
||||
|
||||
name := "s1"
|
||||
expSv := &pbmulticluster.ExportedServices{
|
||||
Services: []string{name},
|
||||
Consumers: []*pbmulticluster.ExportedServicesConsumer{
|
||||
{ConsumerTenancy: &pbmulticluster.ExportedServicesConsumer_Partition{Partition: "p1"}},
|
||||
},
|
||||
}
|
||||
rtest.Resource(pbmulticluster.ExportedServicesType, "exported-svcs").
|
||||
WithData(suite.T(), expSv).
|
||||
WithTenancy(&pbresource.Tenancy{Partition: tenancy.Partition}).
|
||||
Write(suite.T(), suite.ctl.Runtime().Client)
|
||||
cesID := &pbresource.ID{
|
||||
Type: pbmulticluster.ComputedExportedServicesType,
|
||||
Tenancy: &pbresource.Tenancy{Partition: tenancy.Partition},
|
||||
Name: types.ComputedExportedServicesName,
|
||||
}
|
||||
err := suite.ctl.Reconcile(suite.ctx, controller.Request{ID: cesID})
|
||||
require.NoError(suite.T(), err)
|
||||
})
|
||||
}
|
||||
|
||||
func (suite *controllerSuite) TestReconcile_NewExport_PeerExport() {
|
||||
if !suite.isEnterprise {
|
||||
suite.T().Skip("this test should only run against the enterprise build")
|
||||
}
|
||||
|
||||
suite.runTestCaseWithTenancies(func(tenancy *pbresource.Tenancy) {
|
||||
entMeta := acl.DefaultEnterpriseMeta()
|
||||
entMeta.OverridePartition(tenancy.Partition)
|
||||
|
||||
// used as a return value for GetExportedServicesConfigEntry
|
||||
existingCE := &structs.ExportedServicesConfigEntry{
|
||||
// v1 exported-services config entries must have a Name that is the partitions name
|
||||
Name: tenancy.Partition,
|
||||
Meta: map[string]string{
|
||||
controllerMetaKey: ControllerName,
|
||||
},
|
||||
EnterpriseMeta: acl.NewEnterpriseMetaWithPartition(tenancy.Partition, ""),
|
||||
}
|
||||
suite.config.EXPECT().GetExportedServicesConfigEntry(suite.ctx, tenancy.Partition, entMeta).Return(existingCE, nil)
|
||||
|
||||
// expected config entry to be written by reconcile
|
||||
expectedCE := &structs.ExportedServicesConfigEntry{
|
||||
Name: tenancy.Partition,
|
||||
Services: []structs.ExportedService{
|
||||
{
|
||||
Name: "s1",
|
||||
Namespace: resource.DefaultNamespaceName,
|
||||
Consumers: []structs.ServiceConsumer{
|
||||
{
|
||||
Peer: "peer1",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
Meta: map[string]string{
|
||||
controllerMetaKey: ControllerName,
|
||||
},
|
||||
EnterpriseMeta: *entMeta,
|
||||
}
|
||||
suite.config.EXPECT().WriteExportedServicesConfigEntry(suite.ctx, expectedCE).Return(nil)
|
||||
|
||||
name := "s1"
|
||||
expSv := &pbmulticluster.ExportedServices{
|
||||
Services: []string{name},
|
||||
Consumers: []*pbmulticluster.ExportedServicesConsumer{
|
||||
{ConsumerTenancy: &pbmulticluster.ExportedServicesConsumer_Peer{Peer: "peer1"}},
|
||||
},
|
||||
}
|
||||
rtest.Resource(pbmulticluster.ExportedServicesType, "exported-svcs").
|
||||
WithData(suite.T(), expSv).
|
||||
WithTenancy(&pbresource.Tenancy{Partition: tenancy.Partition}).
|
||||
Write(suite.T(), suite.ctl.Runtime().Client)
|
||||
cesID := &pbresource.ID{
|
||||
Type: pbmulticluster.ComputedExportedServicesType,
|
||||
Tenancy: &pbresource.Tenancy{Partition: tenancy.Partition},
|
||||
Name: types.ComputedExportedServicesName,
|
||||
}
|
||||
err := suite.ctl.Reconcile(suite.ctx, controller.Request{ID: cesID})
|
||||
require.NoError(suite.T(), err)
|
||||
})
|
||||
}
|
||||
|
||||
func (suite *controllerSuite) TestReconcile_NewExport_SamenessGroupsExport() {
|
||||
if !suite.isEnterprise {
|
||||
suite.T().Skip("this test should only run against the enterprise build")
|
||||
}
|
||||
|
||||
suite.runTestCaseWithTenancies(func(tenancy *pbresource.Tenancy) {
|
||||
entMeta := acl.DefaultEnterpriseMeta()
|
||||
entMeta.OverridePartition(tenancy.Partition)
|
||||
|
||||
// used as a return value for GetExportedServicesConfigEntry
|
||||
existingCE := &structs.ExportedServicesConfigEntry{
|
||||
// v1 exported-services config entries must have a Name that is the partitions name
|
||||
Name: tenancy.Partition,
|
||||
Meta: map[string]string{
|
||||
controllerMetaKey: ControllerName,
|
||||
},
|
||||
EnterpriseMeta: acl.NewEnterpriseMetaWithPartition(tenancy.Partition, ""),
|
||||
}
|
||||
suite.config.EXPECT().GetExportedServicesConfigEntry(suite.ctx, tenancy.Partition, entMeta).Return(existingCE, nil)
|
||||
|
||||
// expected config entry to be written by reconcile
|
||||
expectedCE := &structs.ExportedServicesConfigEntry{
|
||||
Name: tenancy.Partition,
|
||||
Services: []structs.ExportedService{
|
||||
{
|
||||
Name: "s1",
|
||||
Namespace: resource.DefaultNamespaceName,
|
||||
Consumers: []structs.ServiceConsumer{
|
||||
{
|
||||
SamenessGroup: "sg1",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
Meta: map[string]string{
|
||||
controllerMetaKey: ControllerName,
|
||||
},
|
||||
EnterpriseMeta: *entMeta,
|
||||
}
|
||||
suite.config.EXPECT().WriteExportedServicesConfigEntry(suite.ctx, expectedCE).Return(nil)
|
||||
|
||||
name := "s1"
|
||||
expSv := &pbmulticluster.ExportedServices{
|
||||
Services: []string{name},
|
||||
Consumers: []*pbmulticluster.ExportedServicesConsumer{
|
||||
{ConsumerTenancy: &pbmulticluster.ExportedServicesConsumer_SamenessGroup{SamenessGroup: "sg1"}},
|
||||
},
|
||||
}
|
||||
rtest.Resource(pbmulticluster.ExportedServicesType, "exported-svcs").
|
||||
WithData(suite.T(), expSv).
|
||||
WithTenancy(&pbresource.Tenancy{Partition: tenancy.Partition}).
|
||||
Write(suite.T(), suite.ctl.Runtime().Client)
|
||||
cesID := &pbresource.ID{
|
||||
Type: pbmulticluster.ComputedExportedServicesType,
|
||||
Tenancy: &pbresource.Tenancy{Partition: tenancy.Partition},
|
||||
Name: types.ComputedExportedServicesName,
|
||||
}
|
||||
err := suite.ctl.Reconcile(suite.ctx, controller.Request{ID: cesID})
|
||||
require.NoError(suite.T(), err)
|
||||
})
|
||||
}
|
||||
|
||||
func (suite *controllerSuite) TestReconcile_MultipleExports() {
|
||||
if !suite.isEnterprise {
|
||||
suite.T().Skip("this test should only run against the enterprise build")
|
||||
}
|
||||
|
||||
suite.runTestCaseWithTenancies(func(tenancy *pbresource.Tenancy) {
|
||||
entMeta := acl.DefaultEnterpriseMeta()
|
||||
entMeta.OverridePartition(tenancy.Partition)
|
||||
configCE := &structs.ExportedServicesConfigEntry{
|
||||
// v1 exported-services config entries must have a Name that is the partitions name
|
||||
Name: tenancy.Partition,
|
||||
Meta: map[string]string{
|
||||
controllerMetaKey: ControllerName,
|
||||
},
|
||||
EnterpriseMeta: acl.NewEnterpriseMetaWithPartition(tenancy.Partition, ""),
|
||||
}
|
||||
|
||||
suite.config.EXPECT().
|
||||
GetExportedServicesConfigEntry(suite.ctx, tenancy.Partition, entMeta).
|
||||
Return(configCE, nil)
|
||||
|
||||
expSv1 := &pbmulticluster.ExportedServices{
|
||||
Services: []string{"s1"},
|
||||
Consumers: []*pbmulticluster.ExportedServicesConsumer{
|
||||
{ConsumerTenancy: &pbmulticluster.ExportedServicesConsumer_Partition{Partition: "p1"}},
|
||||
{ConsumerTenancy: &pbmulticluster.ExportedServicesConsumer_Partition{Partition: "p4"}},
|
||||
},
|
||||
}
|
||||
expSv2 := &pbmulticluster.ExportedServices{
|
||||
Services: []string{"s2"},
|
||||
Consumers: []*pbmulticluster.ExportedServicesConsumer{
|
||||
{ConsumerTenancy: &pbmulticluster.ExportedServicesConsumer_Partition{Partition: "p2"}},
|
||||
{ConsumerTenancy: &pbmulticluster.ExportedServicesConsumer_Peer{Peer: "peer1"}},
|
||||
},
|
||||
}
|
||||
expSv3 := &pbmulticluster.ExportedServices{
|
||||
Services: []string{"s1", "s3"},
|
||||
Consumers: []*pbmulticluster.ExportedServicesConsumer{
|
||||
{ConsumerTenancy: &pbmulticluster.ExportedServicesConsumer_Partition{Partition: "p3"}},
|
||||
{ConsumerTenancy: &pbmulticluster.ExportedServicesConsumer_SamenessGroup{SamenessGroup: "sg1"}},
|
||||
},
|
||||
}
|
||||
|
||||
for i, s := range []*pbmulticluster.ExportedServices{expSv1, expSv2, expSv3} {
|
||||
rtest.Resource(pbmulticluster.ExportedServicesType, fmt.Sprintf("exported-svcs-%d", i)).
|
||||
WithData(suite.T(), s).
|
||||
WithTenancy(&pbresource.Tenancy{Partition: tenancy.Partition}).
|
||||
Write(suite.T(), suite.ctl.Runtime().Client)
|
||||
}
|
||||
|
||||
cesID := &pbresource.ID{
|
||||
Type: pbmulticluster.ComputedExportedServicesType,
|
||||
Tenancy: &pbresource.Tenancy{Partition: tenancy.Partition},
|
||||
Name: types.ComputedExportedServicesName,
|
||||
}
|
||||
|
||||
// expected computed config entry to be written by reconcile
|
||||
computedConfigEntry := &structs.ExportedServicesConfigEntry{
|
||||
Name: tenancy.Partition,
|
||||
Meta: map[string]string{
|
||||
controllerMetaKey: ControllerName,
|
||||
},
|
||||
Services: []structs.ExportedService{
|
||||
{
|
||||
Name: "s3",
|
||||
Namespace: resource.DefaultNamespaceName,
|
||||
Consumers: []structs.ServiceConsumer{
|
||||
{Partition: "p3"},
|
||||
{SamenessGroup: "sg1"},
|
||||
},
|
||||
},
|
||||
{
|
||||
Name: "s2",
|
||||
Namespace: resource.DefaultNamespaceName,
|
||||
Consumers: []structs.ServiceConsumer{
|
||||
{Partition: "p2"},
|
||||
{Peer: "peer1"},
|
||||
},
|
||||
},
|
||||
{
|
||||
Name: "s1",
|
||||
Namespace: resource.DefaultNamespaceName,
|
||||
Consumers: []structs.ServiceConsumer{
|
||||
{Partition: "p1"},
|
||||
{Partition: "p3"},
|
||||
{Partition: "p4"},
|
||||
{SamenessGroup: "sg1"},
|
||||
},
|
||||
},
|
||||
},
|
||||
EnterpriseMeta: acl.NewEnterpriseMetaWithPartition(tenancy.Partition, resource.DefaultNamespaceName),
|
||||
}
|
||||
suite.config.EXPECT().
|
||||
WriteExportedServicesConfigEntry(suite.ctx, computedConfigEntry).
|
||||
Return(nil)
|
||||
|
||||
err := suite.ctl.Reconcile(suite.ctx, controller.Request{ID: cesID})
|
||||
require.NoError(suite.T(), err)
|
||||
})
|
||||
}
|
||||
|
||||
func (suite *controllerSuite) runTestCaseWithTenancies(testFunc func(*pbresource.Tenancy)) {
|
||||
for _, tenancy := range suite.tenancies {
|
||||
suite.Run(suite.appendTenancyInfo(tenancy), func() {
|
||||
testFunc(tenancy)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func (suite *controllerSuite) appendTenancyInfo(tenancy *pbresource.Tenancy) string {
|
||||
return fmt.Sprintf("%s_Namespace_%s_Partition", tenancy.Namespace, tenancy.Partition)
|
||||
}
|
||||
|
||||
func TestController(t *testing.T) {
|
||||
suite.Run(t, new(controllerSuite))
|
||||
}
|
|
@ -0,0 +1,262 @@
|
|||
// Code generated by mockery v2.20.0. DO NOT EDIT.
|
||||
|
||||
package v1compat
|
||||
|
||||
import (
|
||||
context "context"
|
||||
|
||||
acl "github.com/hashicorp/consul/acl"
|
||||
|
||||
controller "github.com/hashicorp/consul/internal/controller"
|
||||
|
||||
mock "github.com/stretchr/testify/mock"
|
||||
|
||||
structs "github.com/hashicorp/consul/agent/structs"
|
||||
)
|
||||
|
||||
// MockAggregatedConfig is an autogenerated mock type for the AggregatedConfig type
|
||||
type MockAggregatedConfig struct {
|
||||
mock.Mock
|
||||
}
|
||||
|
||||
type MockAggregatedConfig_Expecter struct {
|
||||
mock *mock.Mock
|
||||
}
|
||||
|
||||
func (_m *MockAggregatedConfig) EXPECT() *MockAggregatedConfig_Expecter {
|
||||
return &MockAggregatedConfig_Expecter{mock: &_m.Mock}
|
||||
}
|
||||
|
||||
// DeleteExportedServicesConfigEntry provides a mock function with given fields: _a0, _a1, _a2
|
||||
func (_m *MockAggregatedConfig) DeleteExportedServicesConfigEntry(_a0 context.Context, _a1 string, _a2 *acl.EnterpriseMeta) error {
|
||||
ret := _m.Called(_a0, _a1, _a2)
|
||||
|
||||
var r0 error
|
||||
if rf, ok := ret.Get(0).(func(context.Context, string, *acl.EnterpriseMeta) error); ok {
|
||||
r0 = rf(_a0, _a1, _a2)
|
||||
} else {
|
||||
r0 = ret.Error(0)
|
||||
}
|
||||
|
||||
return r0
|
||||
}
|
||||
|
||||
// MockAggregatedConfig_DeleteExportedServicesConfigEntry_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'DeleteExportedServicesConfigEntry'
|
||||
type MockAggregatedConfig_DeleteExportedServicesConfigEntry_Call struct {
|
||||
*mock.Call
|
||||
}
|
||||
|
||||
// DeleteExportedServicesConfigEntry is a helper method to define mock.On call
|
||||
// - _a0 context.Context
|
||||
// - _a1 string
|
||||
// - _a2 *acl.EnterpriseMeta
|
||||
func (_e *MockAggregatedConfig_Expecter) DeleteExportedServicesConfigEntry(_a0 interface{}, _a1 interface{}, _a2 interface{}) *MockAggregatedConfig_DeleteExportedServicesConfigEntry_Call {
|
||||
return &MockAggregatedConfig_DeleteExportedServicesConfigEntry_Call{Call: _e.mock.On("DeleteExportedServicesConfigEntry", _a0, _a1, _a2)}
|
||||
}
|
||||
|
||||
func (_c *MockAggregatedConfig_DeleteExportedServicesConfigEntry_Call) Run(run func(_a0 context.Context, _a1 string, _a2 *acl.EnterpriseMeta)) *MockAggregatedConfig_DeleteExportedServicesConfigEntry_Call {
|
||||
_c.Call.Run(func(args mock.Arguments) {
|
||||
run(args[0].(context.Context), args[1].(string), args[2].(*acl.EnterpriseMeta))
|
||||
})
|
||||
return _c
|
||||
}
|
||||
|
||||
func (_c *MockAggregatedConfig_DeleteExportedServicesConfigEntry_Call) Return(_a0 error) *MockAggregatedConfig_DeleteExportedServicesConfigEntry_Call {
|
||||
_c.Call.Return(_a0)
|
||||
return _c
|
||||
}
|
||||
|
||||
func (_c *MockAggregatedConfig_DeleteExportedServicesConfigEntry_Call) RunAndReturn(run func(context.Context, string, *acl.EnterpriseMeta) error) *MockAggregatedConfig_DeleteExportedServicesConfigEntry_Call {
|
||||
_c.Call.Return(run)
|
||||
return _c
|
||||
}
|
||||
|
||||
// EventChannel provides a mock function with given fields:
|
||||
func (_m *MockAggregatedConfig) EventChannel() chan controller.Event {
|
||||
ret := _m.Called()
|
||||
|
||||
var r0 chan controller.Event
|
||||
if rf, ok := ret.Get(0).(func() chan controller.Event); ok {
|
||||
r0 = rf()
|
||||
} else {
|
||||
if ret.Get(0) != nil {
|
||||
r0 = ret.Get(0).(chan controller.Event)
|
||||
}
|
||||
}
|
||||
|
||||
return r0
|
||||
}
|
||||
|
||||
// MockAggregatedConfig_EventChannel_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'EventChannel'
|
||||
type MockAggregatedConfig_EventChannel_Call struct {
|
||||
*mock.Call
|
||||
}
|
||||
|
||||
// EventChannel is a helper method to define mock.On call
|
||||
func (_e *MockAggregatedConfig_Expecter) EventChannel() *MockAggregatedConfig_EventChannel_Call {
|
||||
return &MockAggregatedConfig_EventChannel_Call{Call: _e.mock.On("EventChannel")}
|
||||
}
|
||||
|
||||
func (_c *MockAggregatedConfig_EventChannel_Call) Run(run func()) *MockAggregatedConfig_EventChannel_Call {
|
||||
_c.Call.Run(func(args mock.Arguments) {
|
||||
run()
|
||||
})
|
||||
return _c
|
||||
}
|
||||
|
||||
func (_c *MockAggregatedConfig_EventChannel_Call) Return(_a0 chan controller.Event) *MockAggregatedConfig_EventChannel_Call {
|
||||
_c.Call.Return(_a0)
|
||||
return _c
|
||||
}
|
||||
|
||||
func (_c *MockAggregatedConfig_EventChannel_Call) RunAndReturn(run func() chan controller.Event) *MockAggregatedConfig_EventChannel_Call {
|
||||
_c.Call.Return(run)
|
||||
return _c
|
||||
}
|
||||
|
||||
// GetExportedServicesConfigEntry provides a mock function with given fields: _a0, _a1, _a2
|
||||
func (_m *MockAggregatedConfig) GetExportedServicesConfigEntry(_a0 context.Context, _a1 string, _a2 *acl.EnterpriseMeta) (*structs.ExportedServicesConfigEntry, error) {
|
||||
ret := _m.Called(_a0, _a1, _a2)
|
||||
|
||||
var r0 *structs.ExportedServicesConfigEntry
|
||||
var r1 error
|
||||
if rf, ok := ret.Get(0).(func(context.Context, string, *acl.EnterpriseMeta) (*structs.ExportedServicesConfigEntry, error)); ok {
|
||||
return rf(_a0, _a1, _a2)
|
||||
}
|
||||
if rf, ok := ret.Get(0).(func(context.Context, string, *acl.EnterpriseMeta) *structs.ExportedServicesConfigEntry); ok {
|
||||
r0 = rf(_a0, _a1, _a2)
|
||||
} else {
|
||||
if ret.Get(0) != nil {
|
||||
r0 = ret.Get(0).(*structs.ExportedServicesConfigEntry)
|
||||
}
|
||||
}
|
||||
|
||||
if rf, ok := ret.Get(1).(func(context.Context, string, *acl.EnterpriseMeta) error); ok {
|
||||
r1 = rf(_a0, _a1, _a2)
|
||||
} else {
|
||||
r1 = ret.Error(1)
|
||||
}
|
||||
|
||||
return r0, r1
|
||||
}
|
||||
|
||||
// MockAggregatedConfig_GetExportedServicesConfigEntry_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'GetExportedServicesConfigEntry'
|
||||
type MockAggregatedConfig_GetExportedServicesConfigEntry_Call struct {
|
||||
*mock.Call
|
||||
}
|
||||
|
||||
// GetExportedServicesConfigEntry is a helper method to define mock.On call
|
||||
// - _a0 context.Context
|
||||
// - _a1 string
|
||||
// - _a2 *acl.EnterpriseMeta
|
||||
func (_e *MockAggregatedConfig_Expecter) GetExportedServicesConfigEntry(_a0 interface{}, _a1 interface{}, _a2 interface{}) *MockAggregatedConfig_GetExportedServicesConfigEntry_Call {
|
||||
return &MockAggregatedConfig_GetExportedServicesConfigEntry_Call{Call: _e.mock.On("GetExportedServicesConfigEntry", _a0, _a1, _a2)}
|
||||
}
|
||||
|
||||
func (_c *MockAggregatedConfig_GetExportedServicesConfigEntry_Call) Run(run func(_a0 context.Context, _a1 string, _a2 *acl.EnterpriseMeta)) *MockAggregatedConfig_GetExportedServicesConfigEntry_Call {
|
||||
_c.Call.Run(func(args mock.Arguments) {
|
||||
run(args[0].(context.Context), args[1].(string), args[2].(*acl.EnterpriseMeta))
|
||||
})
|
||||
return _c
|
||||
}
|
||||
|
||||
func (_c *MockAggregatedConfig_GetExportedServicesConfigEntry_Call) Return(_a0 *structs.ExportedServicesConfigEntry, _a1 error) *MockAggregatedConfig_GetExportedServicesConfigEntry_Call {
|
||||
_c.Call.Return(_a0, _a1)
|
||||
return _c
|
||||
}
|
||||
|
||||
func (_c *MockAggregatedConfig_GetExportedServicesConfigEntry_Call) RunAndReturn(run func(context.Context, string, *acl.EnterpriseMeta) (*structs.ExportedServicesConfigEntry, error)) *MockAggregatedConfig_GetExportedServicesConfigEntry_Call {
|
||||
_c.Call.Return(run)
|
||||
return _c
|
||||
}
|
||||
|
||||
// Start provides a mock function with given fields: _a0
|
||||
func (_m *MockAggregatedConfig) Start(_a0 context.Context) {
|
||||
_m.Called(_a0)
|
||||
}
|
||||
|
||||
// MockAggregatedConfig_Start_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'Start'
|
||||
type MockAggregatedConfig_Start_Call struct {
|
||||
*mock.Call
|
||||
}
|
||||
|
||||
// Start is a helper method to define mock.On call
|
||||
// - _a0 context.Context
|
||||
func (_e *MockAggregatedConfig_Expecter) Start(_a0 interface{}) *MockAggregatedConfig_Start_Call {
|
||||
return &MockAggregatedConfig_Start_Call{Call: _e.mock.On("Start", _a0)}
|
||||
}
|
||||
|
||||
func (_c *MockAggregatedConfig_Start_Call) Run(run func(_a0 context.Context)) *MockAggregatedConfig_Start_Call {
|
||||
_c.Call.Run(func(args mock.Arguments) {
|
||||
run(args[0].(context.Context))
|
||||
})
|
||||
return _c
|
||||
}
|
||||
|
||||
func (_c *MockAggregatedConfig_Start_Call) Return() *MockAggregatedConfig_Start_Call {
|
||||
_c.Call.Return()
|
||||
return _c
|
||||
}
|
||||
|
||||
func (_c *MockAggregatedConfig_Start_Call) RunAndReturn(run func(context.Context)) *MockAggregatedConfig_Start_Call {
|
||||
_c.Call.Return(run)
|
||||
return _c
|
||||
}
|
||||
|
||||
// WriteExportedServicesConfigEntry provides a mock function with given fields: _a0, _a1
|
||||
func (_m *MockAggregatedConfig) WriteExportedServicesConfigEntry(_a0 context.Context, _a1 *structs.ExportedServicesConfigEntry) error {
|
||||
ret := _m.Called(_a0, _a1)
|
||||
|
||||
var r0 error
|
||||
if rf, ok := ret.Get(0).(func(context.Context, *structs.ExportedServicesConfigEntry) error); ok {
|
||||
r0 = rf(_a0, _a1)
|
||||
} else {
|
||||
r0 = ret.Error(0)
|
||||
}
|
||||
|
||||
return r0
|
||||
}
|
||||
|
||||
// MockAggregatedConfig_WriteExportedServicesConfigEntry_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'WriteExportedServicesConfigEntry'
|
||||
type MockAggregatedConfig_WriteExportedServicesConfigEntry_Call struct {
|
||||
*mock.Call
|
||||
}
|
||||
|
||||
// WriteExportedServicesConfigEntry is a helper method to define mock.On call
|
||||
// - _a0 context.Context
|
||||
// - _a1 *structs.ExportedServicesConfigEntry
|
||||
func (_e *MockAggregatedConfig_Expecter) WriteExportedServicesConfigEntry(_a0 interface{}, _a1 interface{}) *MockAggregatedConfig_WriteExportedServicesConfigEntry_Call {
|
||||
return &MockAggregatedConfig_WriteExportedServicesConfigEntry_Call{Call: _e.mock.On("WriteExportedServicesConfigEntry", _a0, _a1)}
|
||||
}
|
||||
|
||||
func (_c *MockAggregatedConfig_WriteExportedServicesConfigEntry_Call) Run(run func(_a0 context.Context, _a1 *structs.ExportedServicesConfigEntry)) *MockAggregatedConfig_WriteExportedServicesConfigEntry_Call {
|
||||
_c.Call.Run(func(args mock.Arguments) {
|
||||
run(args[0].(context.Context), args[1].(*structs.ExportedServicesConfigEntry))
|
||||
})
|
||||
return _c
|
||||
}
|
||||
|
||||
func (_c *MockAggregatedConfig_WriteExportedServicesConfigEntry_Call) Return(_a0 error) *MockAggregatedConfig_WriteExportedServicesConfigEntry_Call {
|
||||
_c.Call.Return(_a0)
|
||||
return _c
|
||||
}
|
||||
|
||||
func (_c *MockAggregatedConfig_WriteExportedServicesConfigEntry_Call) RunAndReturn(run func(context.Context, *structs.ExportedServicesConfigEntry) error) *MockAggregatedConfig_WriteExportedServicesConfigEntry_Call {
|
||||
_c.Call.Return(run)
|
||||
return _c
|
||||
}
|
||||
|
||||
type mockConstructorTestingTNewMockAggregatedConfig interface {
|
||||
mock.TestingT
|
||||
Cleanup(func())
|
||||
}
|
||||
|
||||
// NewMockAggregatedConfig creates a new instance of MockAggregatedConfig. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations.
|
||||
func NewMockAggregatedConfig(t mockConstructorTestingTNewMockAggregatedConfig) *MockAggregatedConfig {
|
||||
mock := &MockAggregatedConfig{}
|
||||
mock.Mock.Test(t)
|
||||
|
||||
t.Cleanup(func() { mock.AssertExpectations(t) })
|
||||
|
||||
return mock
|
||||
}
|
Loading…
Reference in New Issue