Skip to content

Commit ed4e5c9

Browse files
authored
aws: Fix Pagination handling of empty string NextToken (#94)
Fixes the SDK's handling of a Pagination NextToken's value being an empty string compared to a nil value. The SDK was expecting NextToken's to always be unset (nil) and treating any non-nil value as a valid value. This was not the case in MediaLive's List APIs. As those APIs return a empty string value instead of null or not setting the field at all. This issue exists in both the v1 and v2 SDKs. Fix #84
1 parent 694c387 commit ed4e5c9

File tree

2 files changed

+105
-13
lines changed

2 files changed

+105
-13
lines changed

aws/request_pagination.go

Lines changed: 21 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -141,13 +141,29 @@ func (r *Request) nextPageTokens() []interface{} {
141141
tokens := []interface{}{}
142142
tokenAdded := false
143143
for _, outToken := range r.Operation.OutputTokens {
144-
v, _ := awsutil.ValuesAtPath(r.Data, outToken)
145-
if len(v) > 0 {
146-
tokens = append(tokens, v[0])
147-
tokenAdded = true
148-
} else {
144+
vs, _ := awsutil.ValuesAtPath(r.Data, outToken)
145+
146+
if len(vs) == 0 {
149147
tokens = append(tokens, nil)
148+
continue
149+
}
150+
v := vs[0]
151+
152+
switch tv := v.(type) {
153+
case *string:
154+
if len(StringValue(tv)) == 0 {
155+
tokens = append(tokens, nil)
156+
continue
157+
}
158+
case string:
159+
if len(tv) == 0 {
160+
tokens = append(tokens, nil)
161+
continue
162+
}
150163
}
164+
165+
tokenAdded = true
166+
tokens = append(tokens, v)
151167
}
152168
if !tokenAdded {
153169
return nil

aws/request_pagination_test.go

Lines changed: 84 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -511,15 +511,15 @@ func TestPaginationWithContextNilInput(t *testing.T) {
511511
}
512512
}
513513

514-
type testPageInput struct {
515-
NextToken string
516-
}
517-
type testPageOutput struct {
518-
Value string
519-
NextToken *string
520-
}
521-
522514
func TestPagination_Standalone(t *testing.T) {
515+
type testPageInput struct {
516+
NextToken string
517+
}
518+
type testPageOutput struct {
519+
Value string
520+
NextToken *string
521+
}
522+
523523
expect := []struct {
524524
Value, PrevToken, NextToken string
525525
}{
@@ -586,6 +586,82 @@ func TestPagination_Standalone(t *testing.T) {
586586
}
587587
}
588588

589+
func TestPagination_Standalone_Pointers(t *testing.T) {
590+
type testPageInput struct {
591+
NextToken *string
592+
}
593+
type testPageOutput struct {
594+
Value *string
595+
NextToken *string
596+
}
597+
598+
expect := []struct {
599+
Value, PrevToken, NextToken *string
600+
}{
601+
{aws.String("FirstValue"), aws.String("InitalToken"), aws.String("FirstToken")},
602+
{aws.String("SecondValue"), aws.String("FirstToken"), aws.String("SecondToken")},
603+
{aws.String("ThirdValue"), aws.String("SecondToken"), nil},
604+
}
605+
input := testPageInput{
606+
NextToken: expect[0].PrevToken,
607+
}
608+
609+
c := awstesting.NewClient(unit.Config())
610+
i := 0
611+
p := aws.Pagination{
612+
NewRequest: func() (*aws.Request, error) {
613+
r := c.NewRequest(
614+
&aws.Operation{
615+
Name: "Operation",
616+
Paginator: &aws.Paginator{
617+
InputTokens: []string{"NextToken"},
618+
OutputTokens: []string{"NextToken"},
619+
},
620+
},
621+
&input, &testPageOutput{},
622+
)
623+
// Setup handlers for testing
624+
r.Handlers.Clear()
625+
r.Handlers.Build.PushBack(func(req *aws.Request) {
626+
in := req.Params.(*testPageInput)
627+
if e, a := aws.StringValue(expect[i].PrevToken), aws.StringValue(in.NextToken); e != a {
628+
t.Errorf("%d, expect NextToken input %q, got %q", i, e, a)
629+
}
630+
})
631+
r.Handlers.Unmarshal.PushBack(func(req *aws.Request) {
632+
out := &testPageOutput{
633+
Value: expect[i].Value,
634+
}
635+
if expect[i].NextToken != nil {
636+
next := *expect[i].NextToken
637+
out.NextToken = aws.String(next)
638+
}
639+
req.Data = out
640+
})
641+
return r, nil
642+
},
643+
}
644+
645+
for p.Next() {
646+
data := p.Page().(*testPageOutput)
647+
648+
if e, a := expect[i].Value, data.Value; e != a {
649+
t.Errorf("%d, expect Value to be %q, got %q", i, e, a)
650+
}
651+
if e, a := aws.StringValue(expect[i].NextToken), aws.StringValue(data.NextToken); e != a {
652+
t.Errorf("%d, expect NextToken to be %q, got %q", i, e, a)
653+
}
654+
655+
i++
656+
}
657+
if e, a := len(expect), i; e != a {
658+
t.Errorf("expected to process %d pages, did %d", e, a)
659+
}
660+
if err := p.Err(); err != nil {
661+
t.Fatalf("%d, expected no error, got %v", i, err)
662+
}
663+
}
664+
589665
// Benchmarks
590666
var benchResps = []dynamodb.ListTablesOutput{
591667
{TableNames: []string{"TABLE", "NXT"}, LastEvaluatedTableName: aws.String("NXT")},

0 commit comments

Comments
 (0)