Skip to content

Commit

Permalink
Merge pull request #1984 from RanVaknin/r53-paginators-a
Browse files Browse the repository at this point in the history
R53 paginators a
  • Loading branch information
RanVaknin committed Apr 21, 2023
2 parents f5a61a0 + 04fc1d7 commit 8a47843
Show file tree
Hide file tree
Showing 3 changed files with 268 additions and 0 deletions.
8 changes: 8 additions & 0 deletions .changelog/85820b40858247f8a975883ac9ae7fb3.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
{
"id": "85820b40-8582-47f8-a975-883ac9ae7fb3",
"type": "feature",
"description": "added paginator for listResourceRecordSets",
"modules": [
"service/route53"
]
}
113 changes: 113 additions & 0 deletions service/route53/handwritten_paginators.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,113 @@
package route53

import (
"context"
"fmt"
"github.com/aws/aws-sdk-go-v2/service/route53/types"
)

// ListResourceRecordSetsAPIClient is a client that implements the ListResourceRecordSets
// operation
type ListResourceRecordSetsAPIClient interface {
ListResourceRecordSets(context.Context, *ListResourceRecordSetsInput, ...func(*Options)) (*ListResourceRecordSetsOutput, error)
}

var _ ListResourceRecordSetsAPIClient = (*Client)(nil)

// ListResourceRecordSetsPaginatorOptions is the paginator options for ListResourceRecordSets
type ListResourceRecordSetsPaginatorOptions struct {
// (Optional) The maximum number of ResourceRecordSets that you want Amazon Route 53 to
// return.
Limit int32

// Set to true if pagination should stop if the service returns a pagination token
// that matches the most recent token provided to the service.
StopOnDuplicateToken bool
}

// ListResourceRecordSetsPaginator is a paginator for ListResourceRecordSets
type ListResourceRecordSetsPaginator struct {
options ListResourceRecordSetsPaginatorOptions
client ListResourceRecordSetsAPIClient
params *ListResourceRecordSetsInput
firstPage bool
startRecordName *string
startRecordType types.RRType
startRecordIdentifier *string
isTruncated bool
}

// NewListResourceRecordSetsPaginator returns a new ListResourceRecordSetsPaginator
func NewListResourceRecordSetsPaginator(client ListResourceRecordSetsAPIClient, params *ListResourceRecordSetsInput, optFns ...func(*ListResourceRecordSetsPaginatorOptions)) *ListResourceRecordSetsPaginator {
if params == nil {
params = &ListResourceRecordSetsInput{}
}

options := ListResourceRecordSetsPaginatorOptions{}
if params.MaxItems != nil {
options.Limit = *params.MaxItems
}

for _, fn := range optFns {
fn(&options)
}

return &ListResourceRecordSetsPaginator{
options: options,
client: client,
params: params,
firstPage: true,
startRecordName: params.StartRecordName,
startRecordType: params.StartRecordType,
startRecordIdentifier: params.StartRecordIdentifier,
}
}

// HasMorePages returns a boolean indicating whether more pages are available
func (p *ListResourceRecordSetsPaginator) HasMorePages() bool {
return p.firstPage || p.isTruncated
}

// NextPage retrieves the next ListResourceRecordSets page.
func (p *ListResourceRecordSetsPaginator) NextPage(ctx context.Context, optFns ...func(*Options)) (*ListResourceRecordSetsOutput, error) {
if !p.HasMorePages() {
return nil, fmt.Errorf("no more pages available")
}

params := *p.params
params.StartRecordName = p.startRecordName
params.StartRecordIdentifier = p.startRecordIdentifier
params.StartRecordType = p.startRecordType

var limit *int32
if p.options.Limit > 0 {
limit = &p.options.Limit
}
params.MaxItems = limit

result, err := p.client.ListResourceRecordSets(ctx, &params, optFns...)
if err != nil {
return nil, err
}
p.firstPage = false

prevToken := p.startRecordName
p.isTruncated = result.IsTruncated
p.startRecordName = nil
p.startRecordIdentifier = nil
p.startRecordType = ""
if result.IsTruncated {
p.startRecordName = result.NextRecordName
p.startRecordIdentifier = result.NextRecordIdentifier
p.startRecordType = result.NextRecordType
}

if p.options.StopOnDuplicateToken &&
prevToken != nil &&
p.startRecordName != nil &&
*prevToken == *p.startRecordName {
p.isTruncated = false
}

return result, nil
}
147 changes: 147 additions & 0 deletions service/route53/handwritten_paginators_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,147 @@
package route53

import (
"context"
"github.com/aws/aws-sdk-go-v2/aws"
"github.com/aws/aws-sdk-go-v2/service/route53/types"
"testing"
)

type mockListResourceRecordSetsClient struct {
outputs []*ListResourceRecordSetsOutput
inputs []*ListResourceRecordSetsInput
t *testing.T
}

func (c *mockListResourceRecordSetsClient) ListResourceRecordSets(ctx context.Context, input *ListResourceRecordSetsInput, optFns ...func(*Options)) (*ListResourceRecordSetsOutput, error) {
c.inputs = append(c.inputs, input)
requestCnt := len(c.inputs)
if *input.MaxItems != *c.outputs[requestCnt-1].MaxItems {
c.t.Errorf("Expect page limit to be %d, got %d", *c.outputs[requestCnt-1].MaxItems, *input.MaxItems)
}
if outputLen := len(c.outputs); requestCnt > outputLen {
c.t.Errorf("Paginator calls client more than expected %d times", outputLen)
}
return c.outputs[requestCnt-1], nil
}

type listRRSTestCase struct {
limit int32
requestCnt int
stopOnDuplicationToken bool
outputs []*ListResourceRecordSetsOutput
}

func TestListResourceRecordSetsPaginator(t *testing.T) {
cases := map[string]listRRSTestCase{
"page limit 5": {
limit: 5,
requestCnt: 3,
outputs: []*ListResourceRecordSetsOutput{
&ListResourceRecordSetsOutput{
MaxItems: aws.Int32(5),
NextRecordName: aws.String("testRecord1"),
NextRecordIdentifier: aws.String("testID1"),
NextRecordType: types.RRTypeA,
IsTruncated: true,
},
&ListResourceRecordSetsOutput{
MaxItems: aws.Int32(5),
NextRecordName: aws.String("testRecord2"),
NextRecordIdentifier: aws.String("testID2"),
NextRecordType: types.RRTypeA,
IsTruncated: true,
},
&ListResourceRecordSetsOutput{
MaxItems: aws.Int32(5),
NextRecordName: aws.String("testRecord3"),
NextRecordIdentifier: aws.String("testID3"),
NextRecordType: types.RRTypeA,
IsTruncated: false,
},
},
},
"page limit 10 with duplicate record": {
limit: 10,
requestCnt: 4,
stopOnDuplicationToken: true,
outputs: []*ListResourceRecordSetsOutput{
&ListResourceRecordSetsOutput{
MaxItems: aws.Int32(10),
NextRecordName: aws.String("testRecord1"),
NextRecordIdentifier: aws.String("testID1"),
NextRecordType: types.RRTypeA,
IsTruncated: true,
},
&ListResourceRecordSetsOutput{
MaxItems: aws.Int32(10),
NextRecordName: aws.String("testRecord2"),
NextRecordIdentifier: aws.String("testID2"),
NextRecordType: types.RRTypeA,
IsTruncated: true,
},
&ListResourceRecordSetsOutput{
MaxItems: aws.Int32(10),
NextRecordName: aws.String("testRecord3"),
NextRecordIdentifier: aws.String("testID3"),
NextRecordType: types.RRTypeA,
IsTruncated: true,
},
&ListResourceRecordSetsOutput{
MaxItems: aws.Int32(10),
NextRecordName: aws.String("testRecord3"),
NextRecordIdentifier: aws.String("testID3"),
NextRecordType: types.RRTypeA,
IsTruncated: true,
},
&ListResourceRecordSetsOutput{
MaxItems: aws.Int32(10),
NextRecordName: aws.String("testRecord5"),
NextRecordIdentifier: aws.String("testID5"),
NextRecordType: types.RRTypeA,
IsTruncated: false,
},
},
},
}

for name, c := range cases {
t.Run(name, func(t *testing.T) {
client := mockListResourceRecordSetsClient{
inputs: []*ListResourceRecordSetsInput{},
outputs: c.outputs,
t: t,
}

paginator := NewListResourceRecordSetsPaginator(&client, &ListResourceRecordSetsInput{}, func(options *ListResourceRecordSetsPaginatorOptions) {
options.Limit = c.limit
options.StopOnDuplicateToken = c.stopOnDuplicationToken
})
for paginator.HasMorePages() {
_, err := paginator.NextPage(context.TODO())
if err != nil {
t.Errorf("error: %v", err)
}
}

inputLen := len(client.inputs)
if inputLen != c.requestCnt {
t.Errorf("Expect total request number to be %d, got %d", c.requestCnt, inputLen)
}
for i := 1; i < inputLen; i++ {
if *client.inputs[i].StartRecordName != *c.outputs[i-1].NextRecordName {
t.Errorf("Expect next input's RecordName to be eaqul to %s, got %s",
*c.outputs[i-1].NextRecordName, *client.inputs[i].StartRecordName)
}
if *client.inputs[i].StartRecordIdentifier != *c.outputs[i-1].NextRecordIdentifier {
t.Errorf("Expect next input's RecordIdentifier to be eaqul to %s, got %s",
*c.outputs[i-1].NextRecordIdentifier, *client.inputs[i].StartRecordIdentifier)
}
if client.inputs[i].StartRecordType != c.outputs[i-1].NextRecordType {
t.Errorf("Expect next input's RecordType to be eaqul to %s, got %s",
c.outputs[i-1].NextRecordType, client.inputs[i].StartRecordType)
}
}
})
}
}

0 comments on commit 8a47843

Please sign in to comment.