-
Notifications
You must be signed in to change notification settings - Fork 653
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
And handwritten missing paginators (#2310)
- Loading branch information
1 parent
609f64a
commit cd475ae
Showing
7 changed files
with
896 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,11 @@ | ||
{ | ||
"id": "6cb6bc26-277c-41be-84cb-8aa523a78989", | ||
"type": "feature", | ||
"collapse": true, | ||
"description": "Add handwritten paginators that were present in some services in the v1 SDK.", | ||
"modules": [ | ||
"service/amplifybackend", | ||
"service/dynamodb", | ||
"service/kinesis" | ||
] | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,96 @@ | ||
package amplifybackend | ||
|
||
import ( | ||
"context" | ||
"fmt" | ||
) | ||
|
||
// ListBackendJobsPaginatorOptions is the paginator options for ListBackendJobs | ||
type ListBackendJobsPaginatorOptions struct { | ||
// (Optional) The maximum number of shards to return in a single call | ||
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 | ||
} | ||
|
||
// ListBackendJobsPaginator is a paginator for ListBackendJobs | ||
type ListBackendJobsPaginator struct { | ||
options ListBackendJobsPaginatorOptions | ||
client ListBackendJobsAPIClient | ||
params *ListBackendJobsInput | ||
firstPage bool | ||
nextToken *string | ||
isTruncated bool | ||
} | ||
|
||
// ListBackendJobsAPIClient is a client that implements the ListBackendJobs operation. | ||
type ListBackendJobsAPIClient interface { | ||
ListBackendJobs(context.Context, *ListBackendJobsInput, ...func(*Options)) (*ListBackendJobsOutput, error) | ||
} | ||
|
||
// NewListBackendJobsPaginator returns a new ListBackendJobsPaginator | ||
func NewListBackendJobsPaginator(client ListBackendJobsAPIClient, params *ListBackendJobsInput, optFns ...func(options *ListBackendJobsPaginatorOptions)) *ListBackendJobsPaginator { | ||
if params == nil { | ||
params = &ListBackendJobsInput{} | ||
} | ||
|
||
options := ListBackendJobsPaginatorOptions{} | ||
options.Limit = params.MaxResults | ||
|
||
for _, fn := range optFns { | ||
fn(&options) | ||
} | ||
|
||
return &ListBackendJobsPaginator{ | ||
options: options, | ||
client: client, | ||
params: params, | ||
firstPage: true, | ||
nextToken: params.NextToken, | ||
} | ||
} | ||
|
||
// HasMorePages returns a boolean indicating whether more pages are available | ||
func (p *ListBackendJobsPaginator) HasMorePages() bool { | ||
return p.firstPage || p.isTruncated | ||
} | ||
|
||
// NextPage retrieves the next ListBackendJobs page. | ||
func (p *ListBackendJobsPaginator) NextPage(ctx context.Context, optFns ...func(*Options)) (*ListBackendJobsOutput, error) { | ||
if !p.HasMorePages() { | ||
return nil, fmt.Errorf("no more pages available") | ||
} | ||
|
||
params := *p.params | ||
params.NextToken = p.nextToken | ||
|
||
var limit int32 | ||
if p.options.Limit > 0 { | ||
limit = p.options.Limit | ||
} | ||
params.MaxResults = limit | ||
|
||
result, err := p.client.ListBackendJobs(ctx, ¶ms, optFns...) | ||
if err != nil { | ||
return nil, err | ||
} | ||
p.firstPage = false | ||
|
||
prevToken := p.nextToken | ||
p.isTruncated = result.NextToken != nil | ||
p.nextToken = nil | ||
if result.NextToken != nil { | ||
p.nextToken = result.NextToken | ||
} | ||
|
||
if p.options.StopOnDuplicateToken && | ||
prevToken != nil && | ||
p.nextToken != nil && | ||
*prevToken == *p.nextToken { | ||
p.isTruncated = false | ||
} | ||
|
||
return result, nil | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,241 @@ | ||
package amplifybackend | ||
|
||
import ( | ||
"context" | ||
"github.com/aws/aws-sdk-go-v2/service/amplifybackend/types" | ||
"testing" | ||
|
||
"github.com/aws/aws-sdk-go-v2/aws" | ||
) | ||
|
||
type mockListBackendJobsClient struct { | ||
outputs []*ListBackendJobsOutput | ||
inputs []*ListBackendJobsInput | ||
t *testing.T | ||
limit int32 | ||
} | ||
|
||
func (c *mockListBackendJobsClient) ListBackendJobs(ctx context.Context, input *ListBackendJobsInput, optFns ...func(*Options)) (*ListBackendJobsOutput, error) { | ||
c.inputs = append(c.inputs, input) | ||
requestCnt := len(c.inputs) | ||
testCurRequest(len(c.outputs), requestCnt, c.limit, input.MaxResults, c.t) | ||
return c.outputs[requestCnt-1], nil | ||
} | ||
|
||
type listBackendJobsTestCase struct { | ||
limit int32 | ||
requestCnt int | ||
stopOnDuplicationToken bool | ||
outputs []*ListBackendJobsOutput | ||
} | ||
|
||
func TestListBackendJobsPaginator(t *testing.T) { | ||
cases := map[string]listBackendJobsTestCase{ | ||
"page limit 3": { | ||
limit: 3, | ||
requestCnt: 3, | ||
outputs: []*ListBackendJobsOutput{ | ||
{ | ||
Jobs: []types.BackendJobRespObj{ | ||
{ | ||
AppId: aws.String("App"), | ||
JobId: aws.String("Job1"), | ||
}, | ||
{ | ||
AppId: aws.String("App"), | ||
JobId: aws.String("Job2"), | ||
}, | ||
{ | ||
AppId: aws.String("App"), | ||
JobId: aws.String("Job3"), | ||
}, | ||
}, | ||
NextToken: aws.String("token1"), | ||
}, | ||
{ | ||
Jobs: []types.BackendJobRespObj{ | ||
{ | ||
AppId: aws.String("App"), | ||
JobId: aws.String("Job4"), | ||
}, | ||
{ | ||
AppId: aws.String("App"), | ||
JobId: aws.String("Job5"), | ||
}, | ||
{ | ||
AppId: aws.String("App"), | ||
JobId: aws.String("Job6"), | ||
}, | ||
}, | ||
NextToken: aws.String("token2"), | ||
}, | ||
{ | ||
Jobs: []types.BackendJobRespObj{ | ||
{ | ||
AppId: aws.String("App"), | ||
JobId: aws.String("Job7"), | ||
}, | ||
{ | ||
AppId: aws.String("App"), | ||
JobId: aws.String("Job8"), | ||
}, | ||
{ | ||
AppId: aws.String("App"), | ||
JobId: aws.String("Job9"), | ||
}, | ||
}, | ||
}, | ||
}, | ||
}, | ||
"total count 2 due to nil nextToken": { | ||
limit: 3, | ||
requestCnt: 2, | ||
outputs: []*ListBackendJobsOutput{ | ||
{ | ||
Jobs: []types.BackendJobRespObj{ | ||
{ | ||
AppId: aws.String("App"), | ||
JobId: aws.String("Job1"), | ||
}, | ||
{ | ||
AppId: aws.String("App"), | ||
JobId: aws.String("Job2"), | ||
}, | ||
{ | ||
AppId: aws.String("App"), | ||
JobId: aws.String("Job3"), | ||
}, | ||
}, | ||
NextToken: aws.String("token1"), | ||
}, | ||
{ | ||
Jobs: []types.BackendJobRespObj{ | ||
{ | ||
AppId: aws.String("App"), | ||
JobId: aws.String("Job4"), | ||
}, | ||
{ | ||
AppId: aws.String("App"), | ||
JobId: aws.String("Job5"), | ||
}, | ||
{ | ||
AppId: aws.String("App"), | ||
JobId: aws.String("Job6"), | ||
}, | ||
}, | ||
}, | ||
{ | ||
Jobs: []types.BackendJobRespObj{ | ||
{ | ||
AppId: aws.String("App"), | ||
JobId: aws.String("Job7"), | ||
}, | ||
}, | ||
}, | ||
}, | ||
}, | ||
"total count 2 due to duplicate nextToken": { | ||
limit: 3, | ||
requestCnt: 2, | ||
stopOnDuplicationToken: true, | ||
outputs: []*ListBackendJobsOutput{ | ||
{ | ||
Jobs: []types.BackendJobRespObj{ | ||
{ | ||
AppId: aws.String("App"), | ||
JobId: aws.String("Job1"), | ||
}, | ||
{ | ||
AppId: aws.String("App"), | ||
JobId: aws.String("Job2"), | ||
}, | ||
{ | ||
AppId: aws.String("App"), | ||
JobId: aws.String("Job3"), | ||
}, | ||
}, | ||
NextToken: aws.String("token1"), | ||
}, | ||
{ | ||
Jobs: []types.BackendJobRespObj{ | ||
{ | ||
AppId: aws.String("App"), | ||
JobId: aws.String("Job4"), | ||
}, | ||
{ | ||
AppId: aws.String("App"), | ||
JobId: aws.String("Job5"), | ||
}, | ||
{ | ||
AppId: aws.String("App"), | ||
JobId: aws.String("Job6"), | ||
}, | ||
}, | ||
NextToken: aws.String("token1"), | ||
}, | ||
{ | ||
Jobs: []types.BackendJobRespObj{ | ||
{ | ||
AppId: aws.String("App"), | ||
JobId: aws.String("Job7"), | ||
}, | ||
{ | ||
AppId: aws.String("App"), | ||
JobId: aws.String("Job8"), | ||
}, | ||
{ | ||
AppId: aws.String("App"), | ||
JobId: aws.String("Job9"), | ||
}, | ||
}, | ||
}, | ||
}, | ||
}, | ||
} | ||
|
||
for name, c := range cases { | ||
t.Run(name, func(t *testing.T) { | ||
client := mockListBackendJobsClient{ | ||
t: t, | ||
outputs: c.outputs, | ||
inputs: []*ListBackendJobsInput{}, | ||
limit: c.limit, | ||
} | ||
paginator := NewListBackendJobsPaginator(&client, &ListBackendJobsInput{}, func(options *ListBackendJobsPaginatorOptions) { | ||
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) | ||
testTotalRequests(c.requestCnt, inputLen, t) | ||
for i := 1; i < inputLen; i++ { | ||
if *client.inputs[i].NextToken != *c.outputs[i-1].NextToken { | ||
t.Errorf("Expect next input's nextToken to be eaqul to %s, got %s", | ||
*c.outputs[i-1].NextToken, *client.inputs[i].NextToken) | ||
} | ||
} | ||
}) | ||
} | ||
} | ||
|
||
func testCurRequest(maxReqCnt, actualReqCnt int, expectLimit, actualLimit int32, t *testing.T) { | ||
if actualReqCnt > maxReqCnt { | ||
t.Errorf("Paginator calls client more than expected %d times", maxReqCnt) | ||
} | ||
if expectLimit != actualLimit { | ||
t.Errorf("Expect page limit to be %d, got %d", expectLimit, actualLimit) | ||
} | ||
} | ||
|
||
func testTotalRequests(expect, actual int, t *testing.T) { | ||
if actual != expect { | ||
t.Errorf("Expect total request number to be %d, got %d", expect, actual) | ||
} | ||
} |
Oops, something went wrong.