mirror of
https://github.com/kubernetes-sigs/external-dns.git
synced 2026-05-04 22:26:11 +02:00
test(aws): introduce first fixture-based (#5092)
* wip: added tests and fixtures Signed-off-by: ivan katliarchuk <ivan.katliarchuk@gmail.com> * chore(aws-provider): tests with fixtures Signed-off-by: ivan katliarchuk <ivan.katliarchuk@gmail.com> * test(aws): introduce first fixture-based Signed-off-by: ivan katliarchuk <ivan.katliarchuk@gmail.com> --------- Signed-off-by: ivan katliarchuk <ivan.katliarchuk@gmail.com>
This commit is contained in:
parent
338ba0ab2a
commit
73c2f33239
49
internal/testutils/log.go
Normal file
49
internal/testutils/log.go
Normal file
@ -0,0 +1,49 @@
|
||||
/*
|
||||
Copyright 2025 The Kubernetes Authors.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package testutils
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"flag"
|
||||
"testing"
|
||||
|
||||
log "github.com/sirupsen/logrus"
|
||||
"k8s.io/klog/v2"
|
||||
)
|
||||
|
||||
// LogsToBuffer redirects log(s) output to a buffer for testing purposes
|
||||
//
|
||||
// Usage: LogsToBuffer(t)
|
||||
// Example:
|
||||
//
|
||||
// buf := LogsToBuffer(log.DebugLevel, t)
|
||||
// ... do something that logs ...
|
||||
// assert.Contains(t, buf.String(), "expected debug log message")
|
||||
func LogsToBuffer(level log.Level, t *testing.T) *bytes.Buffer {
|
||||
t.Helper()
|
||||
buf := new(bytes.Buffer)
|
||||
log.SetOutput(buf)
|
||||
log.SetLevel(level)
|
||||
klog.SetOutput(buf)
|
||||
flags := &flag.FlagSet{}
|
||||
klog.InitFlags(flags)
|
||||
// make sure klog doesn't write to stderr by default in tests
|
||||
_ = flags.Set("logtostderr", "false")
|
||||
_ = flags.Set("alsologtostderr", "false")
|
||||
_ = flags.Set("stderrthreshold", "4")
|
||||
return buf
|
||||
}
|
||||
76
provider/aws/aws_fixtures_test.go
Normal file
76
provider/aws/aws_fixtures_test.go
Normal file
@ -0,0 +1,76 @@
|
||||
/*
|
||||
Copyright 2025 The Kubernetes Authors.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package aws
|
||||
|
||||
import (
|
||||
"context"
|
||||
"testing"
|
||||
|
||||
log "github.com/sirupsen/logrus"
|
||||
"github.com/stretchr/testify/assert"
|
||||
"sigs.k8s.io/external-dns/internal/testutils"
|
||||
)
|
||||
|
||||
func TestAWSRecordsV1(t *testing.T) {
|
||||
var zones HostedZones
|
||||
unmarshalTestHelper("/fixtures/160-plus-zones.yaml", &zones, t)
|
||||
|
||||
stub := NewRoute53APIFixtureStub(&zones)
|
||||
provider := providerFilters(stub,
|
||||
WithZoneIDFilters(
|
||||
"Z10242883PKPS38KA4S6C", "Z10295763LSQ170JCTR78",
|
||||
"Z102957NOTEXISTS", "Z09418121E8V6WT4FASZE",
|
||||
),
|
||||
WithDomainFilters("w2.w1.ex.com", "ex.com"),
|
||||
)
|
||||
|
||||
ctx := context.Background()
|
||||
z, err := provider.Zones(ctx)
|
||||
assert.NoError(t, err)
|
||||
assert.EqualValues(t, 3, len(z))
|
||||
}
|
||||
|
||||
func TestAWSZonesFilterWithTags(t *testing.T) {
|
||||
var zones HostedZones
|
||||
unmarshalTestHelper("/fixtures/160-plus-zones.yaml", &zones, t)
|
||||
|
||||
stub := NewRoute53APIFixtureStub(&zones)
|
||||
provider := providerFilters(stub,
|
||||
WithZoneTagFilters([]string{"level=5", "owner=ext-dns"}),
|
||||
)
|
||||
|
||||
ctx := context.Background()
|
||||
z, err := provider.Zones(ctx)
|
||||
assert.NoError(t, err)
|
||||
assert.EqualValues(t, 24, len(z))
|
||||
assert.Equal(t, 169, stub.calls["listtagsforresource"])
|
||||
}
|
||||
|
||||
func TestAWSZonesSecondRequestHitsTheCache(t *testing.T) {
|
||||
var zones HostedZones
|
||||
unmarshalTestHelper("/fixtures/160-plus-zones.yaml", &zones, t)
|
||||
|
||||
stub := NewRoute53APIFixtureStub(&zones)
|
||||
provider := providerFilters(stub)
|
||||
|
||||
ctx := context.Background()
|
||||
_, err := provider.Zones(ctx)
|
||||
assert.NoError(t, err)
|
||||
b := testutils.LogsToBuffer(log.DebugLevel, t)
|
||||
_, _ = provider.Zones(ctx)
|
||||
assert.Contains(t, b.String(), "level=debug msg=\"Using cached zones list\"")
|
||||
}
|
||||
148
provider/aws/aws_utils_test.go
Normal file
148
provider/aws/aws_utils_test.go
Normal file
@ -0,0 +1,148 @@
|
||||
/*
|
||||
Copyright 2025 The Kubernetes Authors.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package aws
|
||||
|
||||
import (
|
||||
"context"
|
||||
"os"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/aws/aws-sdk-go-v2/service/route53"
|
||||
route53types "github.com/aws/aws-sdk-go-v2/service/route53/types"
|
||||
"github.com/stretchr/testify/assert"
|
||||
"gopkg.in/yaml.v3"
|
||||
"sigs.k8s.io/external-dns/endpoint"
|
||||
"sigs.k8s.io/external-dns/provider"
|
||||
)
|
||||
|
||||
type HostedZones struct {
|
||||
Zones []*HostedZone `yaml:"zones"`
|
||||
}
|
||||
|
||||
type HostedZone struct {
|
||||
Name string
|
||||
ID string
|
||||
Tags []route53types.Tag `yaml:"tags"`
|
||||
}
|
||||
|
||||
var _ Route53API = &Route53APIFixtureStub{}
|
||||
|
||||
type Route53APIFixtureStub struct {
|
||||
zones map[string]*route53types.HostedZone
|
||||
zoneTags map[string][]route53types.Tag
|
||||
calls map[string]int
|
||||
}
|
||||
|
||||
func providerFilters(client *Route53APIFixtureStub, options ...func(awsProvider *AWSProvider)) *AWSProvider {
|
||||
p := &AWSProvider{
|
||||
clients: map[string]Route53API{defaultAWSProfile: client},
|
||||
evaluateTargetHealth: false,
|
||||
dryRun: false,
|
||||
domainFilter: endpoint.NewDomainFilter([]string{}),
|
||||
zoneIDFilter: provider.NewZoneIDFilter([]string{}),
|
||||
zoneTypeFilter: provider.NewZoneTypeFilter(""),
|
||||
zoneTagFilter: provider.NewZoneTagFilter([]string{}),
|
||||
zonesCache: &zonesListCache{duration: 1 * time.Second},
|
||||
}
|
||||
for _, o := range options {
|
||||
o(p)
|
||||
}
|
||||
return p
|
||||
}
|
||||
|
||||
func WithDomainFilters(filters ...string) func(awsProvider *AWSProvider) {
|
||||
return func(awsProvider *AWSProvider) {
|
||||
awsProvider.domainFilter = endpoint.NewDomainFilter(filters)
|
||||
}
|
||||
}
|
||||
|
||||
func WithZoneIDFilters(filters ...string) func(awsProvider *AWSProvider) {
|
||||
return func(awsProvider *AWSProvider) {
|
||||
awsProvider.zoneIDFilter = provider.NewZoneIDFilter(filters)
|
||||
}
|
||||
}
|
||||
|
||||
func WithZoneTagFilters(filters []string) func(awsProvider *AWSProvider) {
|
||||
return func(awsProvider *AWSProvider) {
|
||||
awsProvider.zoneTagFilter = provider.NewZoneTagFilter(filters)
|
||||
}
|
||||
}
|
||||
|
||||
func NewRoute53APIFixtureStub(zones *HostedZones) *Route53APIFixtureStub {
|
||||
route53Zones := make(map[string]*route53types.HostedZone)
|
||||
zoneTags := make(map[string][]route53types.Tag)
|
||||
for _, zone := range zones.Zones {
|
||||
route53Zones[zone.ID] = &route53types.HostedZone{
|
||||
Id: &zone.ID,
|
||||
Name: &zone.Name,
|
||||
}
|
||||
zoneTags[cleanZoneID(zone.ID)] = zone.Tags
|
||||
}
|
||||
return &Route53APIFixtureStub{
|
||||
zones: route53Zones,
|
||||
zoneTags: zoneTags,
|
||||
calls: make(map[string]int),
|
||||
}
|
||||
}
|
||||
|
||||
func (r Route53APIFixtureStub) ListResourceRecordSets(ctx context.Context, input *route53.ListResourceRecordSetsInput, optFns ...func(options *route53.Options)) (*route53.ListResourceRecordSetsOutput, error) {
|
||||
// TODO implement me
|
||||
panic("implement me")
|
||||
}
|
||||
|
||||
func (r Route53APIFixtureStub) ChangeResourceRecordSets(ctx context.Context, input *route53.ChangeResourceRecordSetsInput, optFns ...func(options *route53.Options)) (*route53.ChangeResourceRecordSetsOutput, error) {
|
||||
// TODO implement me
|
||||
panic("implement me")
|
||||
}
|
||||
|
||||
func (r Route53APIFixtureStub) CreateHostedZone(ctx context.Context, input *route53.CreateHostedZoneInput, optFns ...func(*route53.Options)) (*route53.CreateHostedZoneOutput, error) {
|
||||
// TODO implement me
|
||||
panic("implement me")
|
||||
}
|
||||
|
||||
func (r Route53APIFixtureStub) ListHostedZones(ctx context.Context, input *route53.ListHostedZonesInput, optFns ...func(options *route53.Options)) (*route53.ListHostedZonesOutput, error) {
|
||||
r.calls["listhostedzones"]++
|
||||
output := &route53.ListHostedZonesOutput{}
|
||||
for _, zone := range r.zones {
|
||||
output.HostedZones = append(output.HostedZones, *zone)
|
||||
}
|
||||
return output, nil
|
||||
}
|
||||
|
||||
func (r Route53APIFixtureStub) ListTagsForResource(ctx context.Context, input *route53.ListTagsForResourceInput, optFns ...func(options *route53.Options)) (*route53.ListTagsForResourceOutput, error) {
|
||||
r.calls["listtagsforresource"]++
|
||||
tags := r.zoneTags[*input.ResourceId]
|
||||
return &route53.ListTagsForResourceOutput{
|
||||
ResourceTagSet: &route53types.ResourceTagSet{
|
||||
ResourceId: input.ResourceId,
|
||||
ResourceType: input.ResourceType,
|
||||
Tags: tags,
|
||||
},
|
||||
}, nil
|
||||
}
|
||||
|
||||
func unmarshalTestHelper(input string, obj any, t *testing.T) {
|
||||
t.Helper()
|
||||
path, _ := os.Getwd()
|
||||
file, err := os.Open(path + input)
|
||||
assert.NoError(t, err)
|
||||
defer file.Close()
|
||||
dec := yaml.NewDecoder(file)
|
||||
err = dec.Decode(obj)
|
||||
assert.NoError(t, err)
|
||||
}
|
||||
3215
provider/aws/fixtures/160-plus-zones.yaml
Normal file
3215
provider/aws/fixtures/160-plus-zones.yaml
Normal file
File diff suppressed because it is too large
Load Diff
Loading…
x
Reference in New Issue
Block a user