[NET-6356] Add tenancy to Failover Tests (#19547)

* [NET-6356] Add tenancy to Failover Tests

* [NET-6438] Add tenancy to xDS Tests
- Added cleanup post test run

* [NET-6356] Add tenancy to failover Tests
- using t.Cleanup instead of defer delete
This commit is contained in:
Kumar Kavish 2023-11-10 01:14:09 +05:30 committed by GitHub
parent 4273616313
commit f09dbb99e9
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 282 additions and 195 deletions

View File

@ -5,6 +5,7 @@ package testing
import (
"context"
rtest "github.com/hashicorp/consul/internal/resource/resourcetest"
"testing"
"github.com/hashicorp/go-uuid"
@ -57,6 +58,23 @@ func RunResourceService(t *testing.T, registerFns ...func(resource.Registry)) pb
return RunResourceServiceWithConfig(t, svc.Config{}, registerFns...)
}
// RunResourceServiceWithTenancies runs a Resource Service with tenancies returned from TestTenancies.
func RunResourceServiceWithTenancies(t *testing.T, registerFns ...func(resource.Registry)) pbresource.ResourceServiceClient {
mockTenancyBridge := &svc.MockTenancyBridge{}
for _, tenant := range rtest.TestTenancies() {
mockTenancyBridge.On("PartitionExists", tenant.Partition).Return(true, nil)
mockTenancyBridge.On("NamespaceExists", tenant.Partition, tenant.Namespace).Return(true, nil)
mockTenancyBridge.On("IsPartitionMarkedForDeletion", tenant.Partition).Return(false, nil)
mockTenancyBridge.On("IsNamespaceMarkedForDeletion", tenant.Partition, tenant.Namespace).Return(false, nil)
}
cfg := &svc.Config{
TenancyBridge: mockTenancyBridge,
}
return RunResourceServiceWithConfig(t, *cfg, registerFns...)
}
// RunResourceServiceWithConfig runs a ResourceService with caller injectable config to ease mocking dependencies.
// Any nil config field is replaced with a reasonable default with the following behavior:
//

View File

@ -5,6 +5,7 @@ package failover
import (
"context"
"fmt"
"testing"
"github.com/stretchr/testify/suite"
@ -16,6 +17,7 @@ import (
"github.com/hashicorp/consul/internal/resource"
rtest "github.com/hashicorp/consul/internal/resource/resourcetest"
pbcatalog "github.com/hashicorp/consul/proto-public/pbcatalog/v2beta1"
"github.com/hashicorp/consul/proto-public/pbresource"
"github.com/hashicorp/consul/sdk/testutil"
)
@ -29,11 +31,13 @@ type controllerSuite struct {
failoverMapper FailoverMapper
ctl failoverPolicyReconciler
tenancies []*pbresource.Tenancy
}
func (suite *controllerSuite) SetupTest() {
suite.ctx = testutil.TestContext(suite.T())
client := svctest.RunResourceService(suite.T(), types.Register)
client := svctest.RunResourceServiceWithTenancies(suite.T(), types.Register, types.RegisterDNSPolicy)
suite.rt = controller.Runtime{
Client: client,
Logger: testutil.Logger(suite.T()),
@ -41,6 +45,8 @@ func (suite *controllerSuite) SetupTest() {
suite.client = rtest.NewClient(client)
suite.failoverMapper = failovermapper.New()
suite.tenancies = rtest.TestTenancies()
}
func (suite *controllerSuite) TestController() {
@ -53,216 +59,279 @@ func (suite *controllerSuite) TestController() {
mgr.SetRaftLeader(true)
go mgr.Run(suite.ctx)
// Create an advance pointer to some services.
apiServiceRef := resource.Reference(rtest.Resource(pbcatalog.ServiceType, "api").WithTenancy(resource.DefaultNamespacedTenancy()).ID(), "")
otherServiceRef := resource.Reference(rtest.Resource(pbcatalog.ServiceType, "other").WithTenancy(resource.DefaultNamespacedTenancy()).ID(), "")
suite.runTestCaseWithTenancies(func(tenancy *pbresource.Tenancy) {
// Create an advance pointer to some services.
apiServiceRef := resource.Reference(rtest.Resource(pbcatalog.ServiceType, "api").WithTenancy(tenancy).ID(), "")
otherServiceRef := resource.Reference(rtest.Resource(pbcatalog.ServiceType, "other").WithTenancy(tenancy).ID(), "")
// create a failover without any services
failoverData := &pbcatalog.FailoverPolicy{
Config: &pbcatalog.FailoverConfig{
Destinations: []*pbcatalog.FailoverDestination{{
Ref: apiServiceRef,
// create a failover without any services
failoverData := &pbcatalog.FailoverPolicy{
Config: &pbcatalog.FailoverConfig{
Destinations: []*pbcatalog.FailoverDestination{{
Ref: apiServiceRef,
}},
},
}
failover := rtest.Resource(pbcatalog.FailoverPolicyType, "api").
WithData(suite.T(), failoverData).
WithTenancy(tenancy).
Write(suite.T(), suite.client)
suite.T().Cleanup(suite.deleteResourceFunc(failover.Id))
suite.client.WaitForStatusCondition(suite.T(), failover.Id, StatusKey, ConditionMissingService)
// Provide the service.
apiServiceData := &pbcatalog.Service{
Workloads: &pbcatalog.WorkloadSelector{Prefixes: []string{"api-"}},
Ports: []*pbcatalog.ServicePort{{
TargetPort: "http",
Protocol: pbcatalog.Protocol_PROTOCOL_HTTP,
}},
},
}
failover := rtest.Resource(pbcatalog.FailoverPolicyType, "api").
WithData(suite.T(), failoverData).
Write(suite.T(), suite.client)
}
svc := rtest.Resource(pbcatalog.ServiceType, "api").
WithData(suite.T(), apiServiceData).
WithTenancy(tenancy).
Write(suite.T(), suite.client)
suite.client.WaitForStatusCondition(suite.T(), failover.Id, StatusKey, ConditionMissingService)
suite.T().Cleanup(suite.deleteResourceFunc(svc.Id))
// Provide the service.
apiServiceData := &pbcatalog.Service{
Workloads: &pbcatalog.WorkloadSelector{Prefixes: []string{"api-"}},
Ports: []*pbcatalog.ServicePort{{
TargetPort: "http",
Protocol: pbcatalog.Protocol_PROTOCOL_HTTP,
}},
}
_ = rtest.Resource(pbcatalog.ServiceType, "api").
WithData(suite.T(), apiServiceData).
Write(suite.T(), suite.client)
suite.client.WaitForStatusCondition(suite.T(), failover.Id, StatusKey, ConditionOK)
suite.client.WaitForStatusCondition(suite.T(), failover.Id, StatusKey, ConditionOK)
// Update the failover to reference an unknown port
failoverData = &pbcatalog.FailoverPolicy{
PortConfigs: map[string]*pbcatalog.FailoverConfig{
"http": {
Destinations: []*pbcatalog.FailoverDestination{{
Ref: apiServiceRef,
Port: "http",
}},
// Update the failover to reference an unknown port
failoverData = &pbcatalog.FailoverPolicy{
PortConfigs: map[string]*pbcatalog.FailoverConfig{
"http": {
Destinations: []*pbcatalog.FailoverDestination{{
Ref: apiServiceRef,
Port: "http",
}},
},
"admin": {
Destinations: []*pbcatalog.FailoverDestination{{
Ref: apiServiceRef,
Port: "admin",
}},
},
},
"admin": {
Destinations: []*pbcatalog.FailoverDestination{{
Ref: apiServiceRef,
Port: "admin",
}},
},
},
}
_ = rtest.Resource(pbcatalog.FailoverPolicyType, "api").
WithData(suite.T(), failoverData).
Write(suite.T(), suite.client)
suite.client.WaitForStatusCondition(suite.T(), failover.Id, StatusKey, ConditionUnknownPort("admin"))
}
svc = rtest.Resource(pbcatalog.FailoverPolicyType, "api").
WithData(suite.T(), failoverData).
WithTenancy(tenancy).
Write(suite.T(), suite.client)
// update the service to fix the stray reference, but point to a mesh port
apiServiceData = &pbcatalog.Service{
Workloads: &pbcatalog.WorkloadSelector{Prefixes: []string{"api-"}},
Ports: []*pbcatalog.ServicePort{
{
suite.T().Cleanup(suite.deleteResourceFunc(svc.Id))
suite.client.WaitForStatusCondition(suite.T(), failover.Id, StatusKey, ConditionUnknownPort("admin"))
// update the service to fix the stray reference, but point to a mesh port
apiServiceData = &pbcatalog.Service{
Workloads: &pbcatalog.WorkloadSelector{Prefixes: []string{"api-"}},
Ports: []*pbcatalog.ServicePort{
{
TargetPort: "http",
Protocol: pbcatalog.Protocol_PROTOCOL_HTTP,
},
{
TargetPort: "admin",
Protocol: pbcatalog.Protocol_PROTOCOL_MESH,
},
},
}
svc = rtest.Resource(pbcatalog.ServiceType, "api").
WithData(suite.T(), apiServiceData).
WithTenancy(tenancy).
Write(suite.T(), suite.client)
suite.T().Cleanup(suite.deleteResourceFunc(svc.Id))
suite.client.WaitForStatusCondition(suite.T(), failover.Id, StatusKey, ConditionUsingMeshDestinationPort(apiServiceRef, "admin"))
// update the service to fix the stray reference to not be a mesh port
apiServiceData = &pbcatalog.Service{
Workloads: &pbcatalog.WorkloadSelector{Prefixes: []string{"api-"}},
Ports: []*pbcatalog.ServicePort{
{
TargetPort: "http",
Protocol: pbcatalog.Protocol_PROTOCOL_HTTP,
},
{
TargetPort: "admin",
Protocol: pbcatalog.Protocol_PROTOCOL_HTTP,
},
},
}
svc = rtest.Resource(pbcatalog.ServiceType, "api").
WithData(suite.T(), apiServiceData).
WithTenancy(tenancy).
Write(suite.T(), suite.client)
suite.T().Cleanup(suite.deleteResourceFunc(svc.Id))
suite.client.WaitForStatusCondition(suite.T(), failover.Id, StatusKey, ConditionOK)
// change failover leg to point to missing service
failoverData = &pbcatalog.FailoverPolicy{
PortConfigs: map[string]*pbcatalog.FailoverConfig{
"http": {
Destinations: []*pbcatalog.FailoverDestination{{
Ref: apiServiceRef,
Port: "http",
}},
},
"admin": {
Destinations: []*pbcatalog.FailoverDestination{{
Ref: otherServiceRef,
Port: "admin",
}},
},
},
}
svc = rtest.Resource(pbcatalog.FailoverPolicyType, "api").
WithData(suite.T(), failoverData).
WithTenancy(tenancy).
Write(suite.T(), suite.client)
suite.T().Cleanup(suite.deleteResourceFunc(svc.Id))
suite.client.WaitForStatusCondition(suite.T(), failover.Id, StatusKey, ConditionMissingDestinationService(otherServiceRef))
// Create the missing service, but forget the port.
otherServiceData := &pbcatalog.Service{
Workloads: &pbcatalog.WorkloadSelector{Prefixes: []string{"other-"}},
Ports: []*pbcatalog.ServicePort{{
TargetPort: "http",
Protocol: pbcatalog.Protocol_PROTOCOL_HTTP,
},
{
TargetPort: "admin",
Protocol: pbcatalog.Protocol_PROTOCOL_MESH,
},
},
}
_ = rtest.Resource(pbcatalog.ServiceType, "api").
WithData(suite.T(), apiServiceData).
Write(suite.T(), suite.client)
suite.client.WaitForStatusCondition(suite.T(), failover.Id, StatusKey, ConditionUsingMeshDestinationPort(apiServiceRef, "admin"))
// update the service to fix the stray reference to not be a mesh port
apiServiceData = &pbcatalog.Service{
Workloads: &pbcatalog.WorkloadSelector{Prefixes: []string{"api-"}},
Ports: []*pbcatalog.ServicePort{
{
TargetPort: "http",
Protocol: pbcatalog.Protocol_PROTOCOL_HTTP,
},
{
TargetPort: "admin",
Protocol: pbcatalog.Protocol_PROTOCOL_HTTP,
},
},
}
_ = rtest.Resource(pbcatalog.ServiceType, "api").
WithData(suite.T(), apiServiceData).
Write(suite.T(), suite.client)
suite.client.WaitForStatusCondition(suite.T(), failover.Id, StatusKey, ConditionOK)
// change failover leg to point to missing service
failoverData = &pbcatalog.FailoverPolicy{
PortConfigs: map[string]*pbcatalog.FailoverConfig{
"http": {
Destinations: []*pbcatalog.FailoverDestination{{
Ref: apiServiceRef,
Port: "http",
}},
},
"admin": {
Destinations: []*pbcatalog.FailoverDestination{{
Ref: otherServiceRef,
Port: "admin",
}},
},
},
}
_ = rtest.Resource(pbcatalog.FailoverPolicyType, "api").
WithData(suite.T(), failoverData).
Write(suite.T(), suite.client)
suite.client.WaitForStatusCondition(suite.T(), failover.Id, StatusKey, ConditionMissingDestinationService(otherServiceRef))
// Create the missing service, but forget the port.
otherServiceData := &pbcatalog.Service{
Workloads: &pbcatalog.WorkloadSelector{Prefixes: []string{"other-"}},
Ports: []*pbcatalog.ServicePort{{
TargetPort: "http",
Protocol: pbcatalog.Protocol_PROTOCOL_HTTP,
}},
}
_ = rtest.Resource(pbcatalog.ServiceType, "other").
WithData(suite.T(), otherServiceData).
Write(suite.T(), suite.client)
suite.client.WaitForStatusCondition(suite.T(), failover.Id, StatusKey, ConditionUnknownDestinationPort(otherServiceRef, "admin"))
// fix the destination leg's port
otherServiceData = &pbcatalog.Service{
Workloads: &pbcatalog.WorkloadSelector{Prefixes: []string{"other-"}},
Ports: []*pbcatalog.ServicePort{
{
TargetPort: "http",
Protocol: pbcatalog.Protocol_PROTOCOL_HTTP,
},
{
TargetPort: "admin",
Protocol: pbcatalog.Protocol_PROTOCOL_HTTP,
},
},
}
_ = rtest.Resource(pbcatalog.ServiceType, "other").
WithData(suite.T(), otherServiceData).
Write(suite.T(), suite.client)
suite.client.WaitForStatusCondition(suite.T(), failover.Id, StatusKey, ConditionOK)
// Update the two services to use differnet port names so the easy path doesn't work
apiServiceData = &pbcatalog.Service{
Workloads: &pbcatalog.WorkloadSelector{Prefixes: []string{"api-"}},
Ports: []*pbcatalog.ServicePort{
{
TargetPort: "foo",
Protocol: pbcatalog.Protocol_PROTOCOL_HTTP,
},
{
TargetPort: "bar",
Protocol: pbcatalog.Protocol_PROTOCOL_HTTP,
},
},
}
_ = rtest.Resource(pbcatalog.ServiceType, "api").
WithData(suite.T(), apiServiceData).
Write(suite.T(), suite.client)
otherServiceData = &pbcatalog.Service{
Workloads: &pbcatalog.WorkloadSelector{Prefixes: []string{"other-"}},
Ports: []*pbcatalog.ServicePort{
{
TargetPort: "foo",
Protocol: pbcatalog.Protocol_PROTOCOL_HTTP,
},
{
TargetPort: "baz",
Protocol: pbcatalog.Protocol_PROTOCOL_HTTP,
},
},
}
_ = rtest.Resource(pbcatalog.ServiceType, "other").
WithData(suite.T(), otherServiceData).
Write(suite.T(), suite.client)
failoverData = &pbcatalog.FailoverPolicy{
Config: &pbcatalog.FailoverConfig{
Destinations: []*pbcatalog.FailoverDestination{{
Ref: otherServiceRef,
}},
},
}
failover = rtest.Resource(pbcatalog.FailoverPolicyType, "api").
WithData(suite.T(), failoverData).
Write(suite.T(), suite.client)
}
svc = rtest.Resource(pbcatalog.ServiceType, "other").
WithData(suite.T(), otherServiceData).
WithTenancy(tenancy).
Write(suite.T(), suite.client)
suite.client.WaitForStatusCondition(suite.T(), failover.Id, StatusKey, ConditionUnknownDestinationPort(otherServiceRef, "bar"))
suite.T().Cleanup(suite.deleteResourceFunc(svc.Id))
// and fix it the silly way by removing it from api+failover
apiServiceData = &pbcatalog.Service{
Workloads: &pbcatalog.WorkloadSelector{Prefixes: []string{"api-"}},
Ports: []*pbcatalog.ServicePort{
{
TargetPort: "foo",
Protocol: pbcatalog.Protocol_PROTOCOL_HTTP,
suite.client.WaitForStatusCondition(suite.T(), failover.Id, StatusKey, ConditionUnknownDestinationPort(otherServiceRef, "admin"))
// fix the destination leg's port
otherServiceData = &pbcatalog.Service{
Workloads: &pbcatalog.WorkloadSelector{Prefixes: []string{"other-"}},
Ports: []*pbcatalog.ServicePort{
{
TargetPort: "http",
Protocol: pbcatalog.Protocol_PROTOCOL_HTTP,
},
{
TargetPort: "admin",
Protocol: pbcatalog.Protocol_PROTOCOL_HTTP,
},
},
},
}
_ = rtest.Resource(pbcatalog.ServiceType, "api").
WithData(suite.T(), apiServiceData).
Write(suite.T(), suite.client)
}
svc = rtest.Resource(pbcatalog.ServiceType, "other").
WithData(suite.T(), otherServiceData).
WithTenancy(tenancy).
Write(suite.T(), suite.client)
suite.client.WaitForStatusCondition(suite.T(), failover.Id, StatusKey, ConditionOK)
suite.T().Cleanup(suite.deleteResourceFunc(svc.Id))
suite.client.WaitForStatusCondition(suite.T(), failover.Id, StatusKey, ConditionOK)
// Update the two services to use differnet port names so the easy path doesn't work
apiServiceData = &pbcatalog.Service{
Workloads: &pbcatalog.WorkloadSelector{Prefixes: []string{"api-"}},
Ports: []*pbcatalog.ServicePort{
{
TargetPort: "foo",
Protocol: pbcatalog.Protocol_PROTOCOL_HTTP,
},
{
TargetPort: "bar",
Protocol: pbcatalog.Protocol_PROTOCOL_HTTP,
},
},
}
svc = rtest.Resource(pbcatalog.ServiceType, "api").
WithData(suite.T(), apiServiceData).
WithTenancy(tenancy).
Write(suite.T(), suite.client)
suite.T().Cleanup(suite.deleteResourceFunc(svc.Id))
otherServiceData = &pbcatalog.Service{
Workloads: &pbcatalog.WorkloadSelector{Prefixes: []string{"other-"}},
Ports: []*pbcatalog.ServicePort{
{
TargetPort: "foo",
Protocol: pbcatalog.Protocol_PROTOCOL_HTTP,
},
{
TargetPort: "baz",
Protocol: pbcatalog.Protocol_PROTOCOL_HTTP,
},
},
}
svc = rtest.Resource(pbcatalog.ServiceType, "other").
WithData(suite.T(), otherServiceData).
WithTenancy(tenancy).
Write(suite.T(), suite.client)
suite.T().Cleanup(suite.deleteResourceFunc(svc.Id))
failoverData = &pbcatalog.FailoverPolicy{
Config: &pbcatalog.FailoverConfig{
Destinations: []*pbcatalog.FailoverDestination{{
Ref: otherServiceRef,
}},
},
}
failover = rtest.Resource(pbcatalog.FailoverPolicyType, "api").
WithData(suite.T(), failoverData).
WithTenancy(tenancy).
Write(suite.T(), suite.client)
suite.T().Cleanup(suite.deleteResourceFunc(failover.Id))
suite.client.WaitForStatusCondition(suite.T(), failover.Id, StatusKey, ConditionUnknownDestinationPort(otherServiceRef, "bar"))
// and fix it the silly way by removing it from api+failover
apiServiceData = &pbcatalog.Service{
Workloads: &pbcatalog.WorkloadSelector{Prefixes: []string{"api-"}},
Ports: []*pbcatalog.ServicePort{
{
TargetPort: "foo",
Protocol: pbcatalog.Protocol_PROTOCOL_HTTP,
},
},
}
svc = rtest.Resource(pbcatalog.ServiceType, "api").
WithData(suite.T(), apiServiceData).
WithTenancy(tenancy).
Write(suite.T(), suite.client)
suite.T().Cleanup(suite.deleteResourceFunc(svc.Id))
suite.client.WaitForStatusCondition(suite.T(), failover.Id, StatusKey, ConditionOK)
})
}
func TestFailoverController(t *testing.T) {
suite.Run(t, new(controllerSuite))
}
func (suite *controllerSuite) runTestCaseWithTenancies(testCase func(tenancy *pbresource.Tenancy)) {
for _, tenancy := range suite.tenancies {
suite.Run(suite.appendTenancyInfo(tenancy), func() {
testCase(tenancy)
})
}
}
func (suite *controllerSuite) appendTenancyInfo(tenancy *pbresource.Tenancy) string {
return fmt.Sprintf("%s_Namespace_%s_Partition", tenancy.Namespace, tenancy.Partition)
}
func (suite *controllerSuite) deleteResourceFunc(id *pbresource.ID) func() {
return func() {
suite.client.MustDelete(suite.T(), id)
}
}