Skip to content

Commit

Permalink
(MINOR) Add new AssertRecordExistsInHostedZone function
Browse files Browse the repository at this point in the history
## Added
* A new method for asserting that a record exists in an AWS Route53 Hosted Zone has been added.
  • Loading branch information
mdb authored Dec 21, 2021
1 parent e949d01 commit 12e6c31
Show file tree
Hide file tree
Showing 2 changed files with 269 additions and 20 deletions.
72 changes: 67 additions & 5 deletions pkg/aws/route53.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,34 +3,96 @@
package aws

import (
"context"
"fmt"
"strings"
"testing"

"github.com/aws/aws-sdk-go-v2/service/route53"
"github.com/aws/aws-sdk-go-v2/service/route53/types"
"github.com/stretchr/testify/assert"
)

// Route53Client is an AWS Route53 API client.
// Typically, it's a [Route53](https://docs.aws.amazon.com/sdk-for-go/api/service/route53/#Route53).
// Typically, it's a [Route53](https://pkg.go.dev/github.com/aws/aws-sdk-go-v2/service/route53#Client).
type Route53Client interface {
ListHostedZonesByNameInput(*route53.ListHostedZonesByNameInput) (*route53.ListHostedZonesOutput, error)
ListResourceRecordSets(context.Context, *route53.ListResourceRecordSetsInput) (*route53.ListResourceRecordSetsOutput, error)
}

// AssertRoute53HostedZoneExists asserts whether or not the Route53 zone name
// it's passed is found amongst those reported by the AWS API.
func AssertRoute53HostedZoneExists(t *testing.T, client Route53Client, zoneName string) {
found := false
_, found, err := findZoneE(client, zoneName)

assert.Nil(t, err)
assert.True(t, found, fmt.Sprintf("'%s' not found", zoneName))
}

// AssertRecordInput is used as an input to the AssertRecordExistsInHostedZone method.
type AssertRecordInput struct {
// The record name.
RecordName string

// The record type.
RecordType types.RRType

// The zone name.
ZoneName string
}

// AssertRecordExistsInHostedZone asserts whether or not the Route53 record
// name it's passed exists amongst those associated with the the Route53 zone whose
// name it's passed.
func AssertRecordExistsInHostedZone(t *testing.T, ctx context.Context, client Route53Client, recordInput AssertRecordInput) {
recordFound := false
zoneName := recordInput.ZoneName
recordName := recordInput.RecordName

z, zoneFound, err := findZoneE(client, zoneName)

assert.Nil(t, err)
assert.True(t, zoneFound, fmt.Sprintf("zone '%s' not found", zoneName))

if !zoneFound {
return
}

recs, err := client.ListResourceRecordSets(ctx, &route53.ListResourceRecordSetsInput{
StartRecordName: &recordName,
HostedZoneId: z.Id,
})
assert.Nil(t, err)

for _, r := range recs.ResourceRecordSets {
if strings.ToLower(*r.Name) == strings.ToLower(recordName) && &recordInput.RecordType != nil && r.Type == recordInput.RecordType {
recordFound = true
break
}
}

assert.True(t, recordFound, fmt.Sprintf("record '%s' not found", recordName))
}

func findZoneE(client Route53Client, zoneName string) (*types.HostedZone, bool, error) {
zones, err := client.ListHostedZonesByNameInput(&route53.ListHostedZonesByNameInput{
DNSName: &zoneName,
})
assert.Nil(t, err)
if err != nil {
return nil, false, err
}

var zone *types.HostedZone
for _, n := range zones.HostedZones {
if zoneName == *n.Name {
found = true
zone = &n
break
}
}

assert.True(t, found, fmt.Sprintf("'%s' not found", zoneName))
if zone != nil {
return zone, true, nil
}

return nil, false, nil
}
217 changes: 202 additions & 15 deletions pkg/aws/route53_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,9 @@
package aws

import (
"context"
"errors"
"fmt"
"testing"

"github.com/aws/aws-sdk-go-v2/service/route53"
Expand All @@ -13,31 +15,37 @@ import (

type Route53ClientMock struct {
listHostedZonesOutput *route53.ListHostedZonesOutput
err error
listHostedZonesErr error

listResourceRecordSetsOutput *route53.ListResourceRecordSetsOutput
listResourceRecordSetsErr error
}

func NewMockClient(listHostedZonesOutput *route53.ListHostedZonesOutput, err error) Route53ClientMock {
return Route53ClientMock{
listHostedZonesOutput,
err,
}
func (c Route53ClientMock) ListHostedZonesByNameInput(input *route53.ListHostedZonesByNameInput) (*route53.ListHostedZonesOutput, error) {
return c.listHostedZonesOutput, c.listHostedZonesErr
}

func (c Route53ClientMock) ListHostedZonesByNameInput(listHostedZonesByNameInput *route53.ListHostedZonesByNameInput) (*route53.ListHostedZonesOutput, error) {
return c.listHostedZonesOutput, c.err
func (c Route53ClientMock) ListResourceRecordSets(ctx context.Context, input *route53.ListResourceRecordSetsInput) (*route53.ListResourceRecordSetsOutput, error) {
return c.listResourceRecordSetsOutput, c.listResourceRecordSetsErr
}

func TestAssertRoute53HostedZoneExists_NotFound(t *testing.T) {
fakeTest := &testing.T{}
client := NewMockClient(&route53.ListHostedZonesOutput{}, nil)
client := Route53ClientMock{
listHostedZonesOutput: &route53.ListHostedZonesOutput{},
listHostedZonesErr: nil,
}
AssertRoute53HostedZoneExists(fakeTest, client, "bar.com")

assert.True(t, fakeTest.Failed(), "expected AssertRoute53HostedZoneExists to fail")
}

func TestAssertRoute53HostedZoneExists_Error(t *testing.T) {
fakeTest := &testing.T{}
client := NewMockClient(&route53.ListHostedZonesOutput{}, errors.New("some error"))
client := Route53ClientMock{
listHostedZonesOutput: &route53.ListHostedZonesOutput{},
listHostedZonesErr: errors.New("some error"),
}
AssertRoute53HostedZoneExists(fakeTest, client, "foo.com")

assert.True(t, fakeTest.Failed(), "expected AssertRoute53HostedZoneExists to fail")
Expand All @@ -46,14 +54,193 @@ func TestAssertRoute53HostedZoneExists_Error(t *testing.T) {
func TestAssertRoute53HostedZoneExists_Found(t *testing.T) {
fakeTest := &testing.T{}
name := "foo.com"
client := NewMockClient(&route53.ListHostedZonesOutput{
HostedZones: []types.HostedZone{
types.HostedZone{
Name: &name,
client := Route53ClientMock{
listHostedZonesOutput: &route53.ListHostedZonesOutput{
HostedZones: []types.HostedZone{
types.HostedZone{
Name: &name,
},
},
},
}, nil)
listHostedZonesErr: nil,
}
AssertRoute53HostedZoneExists(fakeTest, client, name)

assert.False(t, fakeTest.Failed(), "expected AssertRoute53HostedZoneExists to pass")
}

func TestAssertRecordExistsInHostedZone_Found(t *testing.T) {
fakeTest := &testing.T{}
zoneName := "foo.com"
recordName := fmt.Sprintf("foo.%s", zoneName)
client := Route53ClientMock{
listHostedZonesOutput: &route53.ListHostedZonesOutput{
HostedZones: []types.HostedZone{
types.HostedZone{
Name: &zoneName,
},
},
},
listHostedZonesErr: nil,
listResourceRecordSetsOutput: &route53.ListResourceRecordSetsOutput{
ResourceRecordSets: []types.ResourceRecordSet{
types.ResourceRecordSet{
Name: &recordName,
},
},
},
listResourceRecordSetsErr: nil,
}

AssertRecordExistsInHostedZone(fakeTest, context.Background(), client, AssertRecordInput{
RecordName: recordName,
ZoneName: zoneName,
})

assert.False(t, fakeTest.Failed(), "expected AssertRecordExistsInZone to pass")
}

func TestAssertRecordExistsInHostedZone_RecordNotFound(t *testing.T) {
fakeTest := &testing.T{}
zoneName := "foo.com"
recordName := fmt.Sprintf("foo.%s", zoneName)
client := Route53ClientMock{
listHostedZonesOutput: &route53.ListHostedZonesOutput{
HostedZones: []types.HostedZone{
types.HostedZone{
Name: &zoneName,
},
},
},
listHostedZonesErr: nil,
listResourceRecordSetsOutput: &route53.ListResourceRecordSetsOutput{
ResourceRecordSets: []types.ResourceRecordSet{},
},
listResourceRecordSetsErr: nil,
}

AssertRecordExistsInHostedZone(fakeTest, context.Background(), client, AssertRecordInput{
RecordName: recordName,
ZoneName: zoneName,
})

assert.True(t, fakeTest.Failed(), "expected AssertRecordExistsInZone to fail")
}

func TestAssertRecordExistsInHostedZone_RecordTypeNotFound(t *testing.T) {
fakeTest := &testing.T{}
zoneName := "foo.com"
recordName := fmt.Sprintf("foo.%s", zoneName)
client := Route53ClientMock{
listHostedZonesOutput: &route53.ListHostedZonesOutput{
HostedZones: []types.HostedZone{
types.HostedZone{
Name: &zoneName,
},
},
},
listHostedZonesErr: nil,
listResourceRecordSetsOutput: &route53.ListResourceRecordSetsOutput{
ResourceRecordSets: []types.ResourceRecordSet{
types.ResourceRecordSet{
Name: &recordName,
Type: types.RRTypeA,
},
},
},
listResourceRecordSetsErr: nil,
}

AssertRecordExistsInHostedZone(fakeTest, context.Background(), client, AssertRecordInput{
RecordName: recordName,
RecordType: types.RRTypeSoa,
ZoneName: zoneName,
})

assert.True(t, fakeTest.Failed(), "expected AssertRecordExistsInZone to fail")
}

func TestAssertRecordExistsInHostedZone_ListResourceRecordSets_Error(t *testing.T) {
fakeTest := &testing.T{}
zoneName := "foo.com"
recordName := fmt.Sprintf("foo.%s", zoneName)
client := Route53ClientMock{
listHostedZonesOutput: &route53.ListHostedZonesOutput{
HostedZones: []types.HostedZone{
types.HostedZone{
Name: &zoneName,
},
},
},
listHostedZonesErr: nil,
listResourceRecordSetsOutput: &route53.ListResourceRecordSetsOutput{
ResourceRecordSets: []types.ResourceRecordSet{},
},
listResourceRecordSetsErr: errors.New("some error"),
}

AssertRecordExistsInHostedZone(fakeTest, context.Background(), client, AssertRecordInput{
RecordName: recordName,
ZoneName: zoneName,
})

assert.True(t, fakeTest.Failed(), "expected AssertRecordExistsInZone to fail")
}

func TestAssertRecordExistsInHostedZone_ZoneNotFound(t *testing.T) {
fakeTest := &testing.T{}
zoneName := "foo.com"
recordName := fmt.Sprintf("foo.%s", zoneName)
client := Route53ClientMock{
listHostedZonesOutput: &route53.ListHostedZonesOutput{
HostedZones: []types.HostedZone{},
},
listHostedZonesErr: nil,
listResourceRecordSetsOutput: &route53.ListResourceRecordSetsOutput{
ResourceRecordSets: []types.ResourceRecordSet{
types.ResourceRecordSet{
Name: &recordName,
},
},
},
listResourceRecordSetsErr: nil,
}

AssertRecordExistsInHostedZone(fakeTest, context.Background(), client, AssertRecordInput{
RecordName: recordName,
ZoneName: zoneName,
})

assert.True(t, fakeTest.Failed(), "expected AssertRecordExistsInZone to fail")
}

func TestAssertRecordExistsInHostedZone_ListHostedZonesByNameInput_Error(t *testing.T) {
fakeTest := &testing.T{}
zoneName := "foo.com"
recordName := fmt.Sprintf("foo.%s", zoneName)
client := Route53ClientMock{
listHostedZonesOutput: &route53.ListHostedZonesOutput{
HostedZones: []types.HostedZone{
types.HostedZone{
Name: &zoneName,
},
},
},
listHostedZonesErr: errors.New("some error"),
listResourceRecordSetsOutput: &route53.ListResourceRecordSetsOutput{
ResourceRecordSets: []types.ResourceRecordSet{
types.ResourceRecordSet{
Name: &recordName,
},
},
},
listResourceRecordSetsErr: nil,
}

AssertRecordExistsInHostedZone(fakeTest, context.Background(), client, AssertRecordInput{
RecordName: recordName,
ZoneName: zoneName,
})

assert.True(t, fakeTest.Failed(), "expected AssertRecordExistsInZone to fail")
}

0 comments on commit 12e6c31

Please sign in to comment.