1package request_test
2
3import (
4	"reflect"
5	"testing"
6
7	"github.com/aws/aws-sdk-go/aws"
8	"github.com/aws/aws-sdk-go/aws/request"
9	"github.com/aws/aws-sdk-go/awstesting"
10	"github.com/aws/aws-sdk-go/awstesting/unit"
11	"github.com/aws/aws-sdk-go/service/dynamodb"
12	"github.com/aws/aws-sdk-go/service/route53"
13	"github.com/aws/aws-sdk-go/service/s3"
14)
15
16// Use DynamoDB methods for simplicity
17func TestPaginationQueryPage(t *testing.T) {
18	db := dynamodb.New(unit.Session)
19	tokens, pages, numPages, gotToEnd := []map[string]*dynamodb.AttributeValue{}, []map[string]*dynamodb.AttributeValue{}, 0, false
20
21	reqNum := 0
22	resps := []*dynamodb.QueryOutput{
23		{
24			LastEvaluatedKey: map[string]*dynamodb.AttributeValue{"key": {S: aws.String("key1")}},
25			Count:            aws.Int64(1),
26			Items: []map[string]*dynamodb.AttributeValue{
27				{
28					"key": {S: aws.String("key1")},
29				},
30			},
31		},
32		{
33			LastEvaluatedKey: map[string]*dynamodb.AttributeValue{"key": {S: aws.String("key2")}},
34			Count:            aws.Int64(1),
35			Items: []map[string]*dynamodb.AttributeValue{
36				{
37					"key": {S: aws.String("key2")},
38				},
39			},
40		},
41		{
42			LastEvaluatedKey: map[string]*dynamodb.AttributeValue{},
43			Count:            aws.Int64(1),
44			Items: []map[string]*dynamodb.AttributeValue{
45				{
46					"key": {S: aws.String("key3")},
47				},
48			},
49		},
50	}
51
52	db.Handlers.Send.Clear() // mock sending
53	db.Handlers.Unmarshal.Clear()
54	db.Handlers.UnmarshalMeta.Clear()
55	db.Handlers.ValidateResponse.Clear()
56	db.Handlers.Build.PushBack(func(r *request.Request) {
57		in := r.Params.(*dynamodb.QueryInput)
58		if in == nil {
59			tokens = append(tokens, nil)
60		} else if len(in.ExclusiveStartKey) != 0 {
61			tokens = append(tokens, in.ExclusiveStartKey)
62		}
63	})
64	db.Handlers.Unmarshal.PushBack(func(r *request.Request) {
65		r.Data = resps[reqNum]
66		reqNum++
67	})
68
69	params := &dynamodb.QueryInput{
70		Limit:     aws.Int64(2),
71		TableName: aws.String("tablename"),
72	}
73	err := db.QueryPages(params, func(p *dynamodb.QueryOutput, last bool) bool {
74		numPages++
75		pages = append(pages, p.Items...)
76		if last {
77			if gotToEnd {
78				t.Errorf("last=true happened twice")
79			}
80			gotToEnd = true
81		}
82		return true
83	})
84	if err != nil {
85		t.Errorf("expect nil, %v", err)
86	}
87
88	if e, a :=
89		[]map[string]*dynamodb.AttributeValue{
90			{"key": {S: aws.String("key1")}},
91			{"key": {S: aws.String("key2")}},
92		}, tokens; !reflect.DeepEqual(e, a) {
93		t.Errorf("expect %v, got %v", e, a)
94	}
95	if e, a :=
96		[]map[string]*dynamodb.AttributeValue{
97			{"key": {S: aws.String("key1")}},
98			{"key": {S: aws.String("key2")}},
99			{"key": {S: aws.String("key3")}},
100		}, pages; !reflect.DeepEqual(e, a) {
101		t.Errorf("expect %v, got %v", e, a)
102	}
103	if e, a := 3, numPages; e != a {
104		t.Errorf("expect %v, got %v", e, a)
105	}
106	if !gotToEnd {
107		t.Errorf("expect true")
108	}
109	if params.ExclusiveStartKey != nil {
110		t.Errorf("expect nil, %v", err)
111	}
112}
113
114// Use DynamoDB methods for simplicity
115func TestPagination(t *testing.T) {
116	db := dynamodb.New(unit.Session)
117	tokens, pages, numPages, gotToEnd := []string{}, []string{}, 0, false
118
119	reqNum := 0
120	resps := []*dynamodb.ListTablesOutput{
121		{TableNames: []*string{aws.String("Table1"), aws.String("Table2")}, LastEvaluatedTableName: aws.String("Table2")},
122		{TableNames: []*string{aws.String("Table3"), aws.String("Table4")}, LastEvaluatedTableName: aws.String("Table4")},
123		{TableNames: []*string{aws.String("Table5")}},
124	}
125
126	db.Handlers.Send.Clear() // mock sending
127	db.Handlers.Unmarshal.Clear()
128	db.Handlers.UnmarshalMeta.Clear()
129	db.Handlers.ValidateResponse.Clear()
130	db.Handlers.Build.PushBack(func(r *request.Request) {
131		in := r.Params.(*dynamodb.ListTablesInput)
132		if in == nil {
133			tokens = append(tokens, "")
134		} else if in.ExclusiveStartTableName != nil {
135			tokens = append(tokens, *in.ExclusiveStartTableName)
136		}
137	})
138	db.Handlers.Unmarshal.PushBack(func(r *request.Request) {
139		r.Data = resps[reqNum]
140		reqNum++
141	})
142
143	params := &dynamodb.ListTablesInput{Limit: aws.Int64(2)}
144	err := db.ListTablesPages(params, func(p *dynamodb.ListTablesOutput, last bool) bool {
145		numPages++
146		for _, t := range p.TableNames {
147			pages = append(pages, *t)
148		}
149		if last {
150			if gotToEnd {
151				t.Errorf("last=true happened twice")
152			}
153			gotToEnd = true
154		}
155		return true
156	})
157
158	if e, a := []string{"Table2", "Table4"}, tokens; !reflect.DeepEqual(e, a) {
159		t.Errorf("expect %v, got %v", e, a)
160	}
161	if e, a := []string{"Table1", "Table2", "Table3", "Table4", "Table5"}, pages; !reflect.DeepEqual(e, a) {
162		t.Errorf("expect %v, got %v", e, a)
163	}
164	if e, a := 3, numPages; e != a {
165		t.Errorf("expect %v, got %v", e, a)
166	}
167	if !gotToEnd {
168		t.Errorf("expect true")
169	}
170	if err != nil {
171		t.Errorf("expect nil, %v", err)
172	}
173	if params.ExclusiveStartTableName != nil {
174		t.Errorf("expect nil, %v", err)
175	}
176}
177
178// Use DynamoDB methods for simplicity
179func TestPaginationEachPage(t *testing.T) {
180	db := dynamodb.New(unit.Session)
181	tokens, pages, numPages, gotToEnd := []string{}, []string{}, 0, false
182
183	reqNum := 0
184	resps := []*dynamodb.ListTablesOutput{
185		{TableNames: []*string{aws.String("Table1"), aws.String("Table2")}, LastEvaluatedTableName: aws.String("Table2")},
186		{TableNames: []*string{aws.String("Table3"), aws.String("Table4")}, LastEvaluatedTableName: aws.String("Table4")},
187		{TableNames: []*string{aws.String("Table5")}},
188	}
189
190	db.Handlers.Send.Clear() // mock sending
191	db.Handlers.Unmarshal.Clear()
192	db.Handlers.UnmarshalMeta.Clear()
193	db.Handlers.ValidateResponse.Clear()
194	db.Handlers.Build.PushBack(func(r *request.Request) {
195		in := r.Params.(*dynamodb.ListTablesInput)
196		if in == nil {
197			tokens = append(tokens, "")
198		} else if in.ExclusiveStartTableName != nil {
199			tokens = append(tokens, *in.ExclusiveStartTableName)
200		}
201	})
202	db.Handlers.Unmarshal.PushBack(func(r *request.Request) {
203		r.Data = resps[reqNum]
204		reqNum++
205	})
206
207	params := &dynamodb.ListTablesInput{Limit: aws.Int64(2)}
208	req, _ := db.ListTablesRequest(params)
209	err := req.EachPage(func(p interface{}, last bool) bool {
210		numPages++
211		for _, t := range p.(*dynamodb.ListTablesOutput).TableNames {
212			pages = append(pages, *t)
213		}
214		if last {
215			if gotToEnd {
216				t.Errorf("last=true happened twice")
217			}
218			gotToEnd = true
219		}
220
221		return true
222	})
223
224	if e, a := []string{"Table2", "Table4"}, tokens; !reflect.DeepEqual(e, a) {
225		t.Errorf("expect %v, got %v", e, a)
226	}
227	if e, a := []string{"Table1", "Table2", "Table3", "Table4", "Table5"}, pages; !reflect.DeepEqual(e, a) {
228		t.Errorf("expect %v, got %v", e, a)
229	}
230	if e, a := 3, numPages; e != a {
231		t.Errorf("expect %v, got %v", e, a)
232	}
233	if !gotToEnd {
234		t.Errorf("expect true")
235	}
236	if err != nil {
237		t.Errorf("expect nil, %v", err)
238	}
239}
240
241// Use DynamoDB methods for simplicity
242func TestPaginationEarlyExit(t *testing.T) {
243	db := dynamodb.New(unit.Session)
244	numPages, gotToEnd := 0, false
245
246	reqNum := 0
247	resps := []*dynamodb.ListTablesOutput{
248		{TableNames: []*string{aws.String("Table1"), aws.String("Table2")}, LastEvaluatedTableName: aws.String("Table2")},
249		{TableNames: []*string{aws.String("Table3"), aws.String("Table4")}, LastEvaluatedTableName: aws.String("Table4")},
250		{TableNames: []*string{aws.String("Table5")}},
251	}
252
253	db.Handlers.Send.Clear() // mock sending
254	db.Handlers.Unmarshal.Clear()
255	db.Handlers.UnmarshalMeta.Clear()
256	db.Handlers.ValidateResponse.Clear()
257	db.Handlers.Unmarshal.PushBack(func(r *request.Request) {
258		r.Data = resps[reqNum]
259		reqNum++
260	})
261
262	params := &dynamodb.ListTablesInput{Limit: aws.Int64(2)}
263	err := db.ListTablesPages(params, func(p *dynamodb.ListTablesOutput, last bool) bool {
264		numPages++
265		if numPages == 2 {
266			return false
267		}
268		if last {
269			if gotToEnd {
270				t.Errorf("last=true happened twice")
271			}
272			gotToEnd = true
273		}
274		return true
275	})
276
277	if e, a := 2, numPages; e != a {
278		t.Errorf("expect %v, got %v", e, a)
279	}
280	if gotToEnd {
281		t.Errorf("expect false")
282	}
283	if err != nil {
284		t.Errorf("expect nil, %v", err)
285	}
286}
287
288func TestSkipPagination(t *testing.T) {
289	client := s3.New(unit.Session)
290	client.Handlers.Send.Clear() // mock sending
291	client.Handlers.Unmarshal.Clear()
292	client.Handlers.UnmarshalMeta.Clear()
293	client.Handlers.ValidateResponse.Clear()
294	client.Handlers.Unmarshal.PushBack(func(r *request.Request) {
295		r.Data = &s3.HeadBucketOutput{}
296	})
297
298	req, _ := client.HeadBucketRequest(&s3.HeadBucketInput{Bucket: aws.String("bucket")})
299
300	numPages, gotToEnd := 0, false
301	req.EachPage(func(p interface{}, last bool) bool {
302		numPages++
303		if last {
304			gotToEnd = true
305		}
306		return true
307	})
308	if e, a := 1, numPages; e != a {
309		t.Errorf("expect %v, got %v", e, a)
310	}
311	if !gotToEnd {
312		t.Errorf("expect true")
313	}
314}
315
316// Use S3 for simplicity
317func TestPaginationTruncation(t *testing.T) {
318	client := s3.New(unit.Session)
319
320	reqNum := 0
321	resps := []*s3.ListObjectsOutput{
322		{IsTruncated: aws.Bool(true), Contents: []*s3.Object{{Key: aws.String("Key1")}}},
323		{IsTruncated: aws.Bool(true), Contents: []*s3.Object{{Key: aws.String("Key2")}}},
324		{IsTruncated: aws.Bool(false), Contents: []*s3.Object{{Key: aws.String("Key3")}}},
325		{IsTruncated: aws.Bool(true), Contents: []*s3.Object{{Key: aws.String("Key4")}}},
326	}
327
328	client.Handlers.Send.Clear() // mock sending
329	client.Handlers.Unmarshal.Clear()
330	client.Handlers.UnmarshalMeta.Clear()
331	client.Handlers.ValidateResponse.Clear()
332	client.Handlers.Unmarshal.PushBack(func(r *request.Request) {
333		r.Data = resps[reqNum]
334		reqNum++
335	})
336
337	params := &s3.ListObjectsInput{Bucket: aws.String("bucket")}
338
339	results := []string{}
340	err := client.ListObjectsPages(params, func(p *s3.ListObjectsOutput, last bool) bool {
341		results = append(results, *p.Contents[0].Key)
342		return true
343	})
344
345	if e, a := []string{"Key1", "Key2", "Key3"}, results; !reflect.DeepEqual(e, a) {
346		t.Errorf("expect %v, got %v", e, a)
347	}
348	if err != nil {
349		t.Errorf("expect nil, %v", err)
350	}
351
352	// Try again without truncation token at all
353	reqNum = 0
354	resps[1].IsTruncated = nil
355	resps[2].IsTruncated = aws.Bool(true)
356	results = []string{}
357	err = client.ListObjectsPages(params, func(p *s3.ListObjectsOutput, last bool) bool {
358		results = append(results, *p.Contents[0].Key)
359		return true
360	})
361
362	if e, a := []string{"Key1", "Key2"}, results; !reflect.DeepEqual(e, a) {
363		t.Errorf("expect %v, got %v", e, a)
364	}
365	if err != nil {
366		t.Errorf("expect nil, %v", err)
367	}
368}
369
370func TestPaginationNilToken(t *testing.T) {
371	client := route53.New(unit.Session)
372
373	reqNum := 0
374	resps := []*route53.ListResourceRecordSetsOutput{
375		{
376			ResourceRecordSets: []*route53.ResourceRecordSet{
377				{Name: aws.String("first.example.com.")},
378			},
379			IsTruncated:          aws.Bool(true),
380			NextRecordName:       aws.String("second.example.com."),
381			NextRecordType:       aws.String("MX"),
382			NextRecordIdentifier: aws.String("second"),
383			MaxItems:             aws.String("1"),
384		},
385		{
386			ResourceRecordSets: []*route53.ResourceRecordSet{
387				{Name: aws.String("second.example.com.")},
388			},
389			IsTruncated:    aws.Bool(true),
390			NextRecordName: aws.String("third.example.com."),
391			NextRecordType: aws.String("MX"),
392			MaxItems:       aws.String("1"),
393		},
394		{
395			ResourceRecordSets: []*route53.ResourceRecordSet{
396				{Name: aws.String("third.example.com.")},
397			},
398			IsTruncated: aws.Bool(false),
399			MaxItems:    aws.String("1"),
400		},
401	}
402	client.Handlers.Send.Clear() // mock sending
403	client.Handlers.Unmarshal.Clear()
404	client.Handlers.UnmarshalMeta.Clear()
405	client.Handlers.ValidateResponse.Clear()
406
407	idents := []string{}
408	client.Handlers.Build.PushBack(func(r *request.Request) {
409		p := r.Params.(*route53.ListResourceRecordSetsInput)
410		idents = append(idents, aws.StringValue(p.StartRecordIdentifier))
411
412	})
413	client.Handlers.Unmarshal.PushBack(func(r *request.Request) {
414		r.Data = resps[reqNum]
415		reqNum++
416	})
417
418	params := &route53.ListResourceRecordSetsInput{
419		HostedZoneId: aws.String("id-zone"),
420	}
421
422	results := []string{}
423	err := client.ListResourceRecordSetsPages(params, func(p *route53.ListResourceRecordSetsOutput, last bool) bool {
424		results = append(results, *p.ResourceRecordSets[0].Name)
425		return true
426	})
427
428	if err != nil {
429		t.Errorf("expect nil, %v", err)
430	}
431	if e, a := []string{"", "second", ""}, idents; !reflect.DeepEqual(e, a) {
432		t.Errorf("expect %v, got %v", e, a)
433	}
434	if e, a := []string{"first.example.com.", "second.example.com.", "third.example.com."}, results; !reflect.DeepEqual(e, a) {
435		t.Errorf("expect %v, got %v", e, a)
436	}
437}
438
439func TestPaginationNilInput(t *testing.T) {
440	// Code generation doesn't have a great way to verify the code is correct
441	// other than being run via unit tests in the SDK. This should be fixed
442	// So code generation can be validated independently.
443
444	client := s3.New(unit.Session)
445	client.Handlers.Validate.Clear()
446	client.Handlers.Send.Clear() // mock sending
447	client.Handlers.Unmarshal.Clear()
448	client.Handlers.UnmarshalMeta.Clear()
449	client.Handlers.ValidateResponse.Clear()
450	client.Handlers.Unmarshal.PushBack(func(r *request.Request) {
451		r.Data = &s3.ListObjectsOutput{}
452	})
453
454	gotToEnd := false
455	numPages := 0
456	err := client.ListObjectsPages(nil, func(p *s3.ListObjectsOutput, last bool) bool {
457		numPages++
458		if last {
459			gotToEnd = true
460		}
461		return true
462	})
463
464	if err != nil {
465		t.Fatalf("expect no error, but got %v", err)
466	}
467	if e, a := 1, numPages; e != a {
468		t.Errorf("expect %d number pages but got %d", e, a)
469	}
470	if !gotToEnd {
471		t.Errorf("expect to of gotten to end, did not")
472	}
473}
474
475func TestPaginationWithContextNilInput(t *testing.T) {
476	// Code generation doesn't have a great way to verify the code is correct
477	// other than being run via unit tests in the SDK. This should be fixed
478	// So code generation can be validated independently.
479
480	client := s3.New(unit.Session)
481	client.Handlers.Validate.Clear()
482	client.Handlers.Send.Clear() // mock sending
483	client.Handlers.Unmarshal.Clear()
484	client.Handlers.UnmarshalMeta.Clear()
485	client.Handlers.ValidateResponse.Clear()
486	client.Handlers.Unmarshal.PushBack(func(r *request.Request) {
487		r.Data = &s3.ListObjectsOutput{}
488	})
489
490	gotToEnd := false
491	numPages := 0
492	ctx := &awstesting.FakeContext{DoneCh: make(chan struct{})}
493	err := client.ListObjectsPagesWithContext(ctx, nil, func(p *s3.ListObjectsOutput, last bool) bool {
494		numPages++
495		if last {
496			gotToEnd = true
497		}
498		return true
499	})
500
501	if err != nil {
502		t.Fatalf("expect no error, but got %v", err)
503	}
504	if e, a := 1, numPages; e != a {
505		t.Errorf("expect %d number pages but got %d", e, a)
506	}
507	if !gotToEnd {
508		t.Errorf("expect to of gotten to end, did not")
509	}
510}
511
512func TestPagination_Standalone(t *testing.T) {
513	type testPageInput struct {
514		NextToken *string
515	}
516	type testPageOutput struct {
517		Value     *string
518		NextToken *string
519	}
520	type testCase struct {
521		Value, PrevToken, NextToken *string
522	}
523
524	type testCaseList struct {
525		StopOnSameToken bool
526		Cases           []testCase
527	}
528
529	cases := []testCaseList{
530		{
531			Cases: []testCase{
532				{aws.String("FirstValue"), aws.String("InitalToken"), aws.String("FirstToken")},
533				{aws.String("SecondValue"), aws.String("FirstToken"), aws.String("SecondToken")},
534				{aws.String("ThirdValue"), aws.String("SecondToken"), nil},
535			},
536			StopOnSameToken: false,
537		},
538		{
539			Cases: []testCase{
540				{aws.String("FirstValue"), aws.String("InitalToken"), aws.String("FirstToken")},
541				{aws.String("SecondValue"), aws.String("FirstToken"), aws.String("SecondToken")},
542				{aws.String("ThirdValue"), aws.String("SecondToken"), aws.String("")},
543			},
544			StopOnSameToken: false,
545		},
546		{
547			Cases: []testCase{
548				{aws.String("FirstValue"), aws.String("InitalToken"), aws.String("FirstToken")},
549				{aws.String("SecondValue"), aws.String("FirstToken"), aws.String("SecondToken")},
550				{nil, aws.String("SecondToken"), aws.String("SecondToken")},
551			},
552			StopOnSameToken: true,
553		},
554		{
555			Cases: []testCase{
556				{aws.String("FirstValue"), aws.String("InitalToken"), aws.String("FirstToken")},
557				{aws.String("SecondValue"), aws.String("FirstToken"), aws.String("SecondToken")},
558				{aws.String("SecondValue"), aws.String("SecondToken"), aws.String("SecondToken")},
559			},
560			StopOnSameToken: true,
561		},
562	}
563
564	for _, testcase := range cases {
565		c := testcase.Cases
566		input := testPageInput{
567			NextToken: c[0].PrevToken,
568		}
569
570		svc := awstesting.NewClient()
571		i := 0
572		p := request.Pagination{
573			EndPageOnSameToken: testcase.StopOnSameToken,
574			NewRequest: func() (*request.Request, error) {
575				r := svc.NewRequest(
576					&request.Operation{
577						Name: "Operation",
578						Paginator: &request.Paginator{
579							InputTokens:  []string{"NextToken"},
580							OutputTokens: []string{"NextToken"},
581						},
582					},
583					&input, &testPageOutput{},
584				)
585				// Setup handlers for testing
586				r.Handlers.Clear()
587				r.Handlers.Build.PushBack(func(req *request.Request) {
588					if e, a := len(c), i+1; a > e {
589						t.Fatalf("expect no more than %d requests, got %d", e, a)
590					}
591					in := req.Params.(*testPageInput)
592					if e, a := aws.StringValue(c[i].PrevToken), aws.StringValue(in.NextToken); e != a {
593						t.Errorf("%d, expect NextToken input %q, got %q", i, e, a)
594					}
595				})
596				r.Handlers.Unmarshal.PushBack(func(req *request.Request) {
597					out := &testPageOutput{
598						Value: c[i].Value,
599					}
600					if c[i].NextToken != nil {
601						next := *c[i].NextToken
602						out.NextToken = aws.String(next)
603					}
604					req.Data = out
605				})
606				return r, nil
607			},
608		}
609
610		for p.Next() {
611			data := p.Page().(*testPageOutput)
612
613			if e, a := aws.StringValue(c[i].Value), aws.StringValue(data.Value); e != a {
614				t.Errorf("%d, expect Value to be %q, got %q", i, e, a)
615			}
616			if e, a := aws.StringValue(c[i].NextToken), aws.StringValue(data.NextToken); e != a {
617				t.Errorf("%d, expect NextToken to be %q, got %q", i, e, a)
618			}
619
620			i++
621		}
622		if e, a := len(c), i; e != a {
623			t.Errorf("expected to process %d pages, did %d", e, a)
624		}
625		if err := p.Err(); err != nil {
626			t.Fatalf("%d, expected no error, got %v", i, err)
627		}
628	}
629}
630
631// Benchmarks
632var benchResps = []*dynamodb.ListTablesOutput{
633	{TableNames: []*string{aws.String("TABLE"), aws.String("NXT")}, LastEvaluatedTableName: aws.String("NXT")},
634	{TableNames: []*string{aws.String("TABLE"), aws.String("NXT")}, LastEvaluatedTableName: aws.String("NXT")},
635	{TableNames: []*string{aws.String("TABLE"), aws.String("NXT")}, LastEvaluatedTableName: aws.String("NXT")},
636	{TableNames: []*string{aws.String("TABLE"), aws.String("NXT")}, LastEvaluatedTableName: aws.String("NXT")},
637	{TableNames: []*string{aws.String("TABLE"), aws.String("NXT")}, LastEvaluatedTableName: aws.String("NXT")},
638	{TableNames: []*string{aws.String("TABLE"), aws.String("NXT")}, LastEvaluatedTableName: aws.String("NXT")},
639	{TableNames: []*string{aws.String("TABLE"), aws.String("NXT")}, LastEvaluatedTableName: aws.String("NXT")},
640	{TableNames: []*string{aws.String("TABLE"), aws.String("NXT")}, LastEvaluatedTableName: aws.String("NXT")},
641	{TableNames: []*string{aws.String("TABLE"), aws.String("NXT")}, LastEvaluatedTableName: aws.String("NXT")},
642	{TableNames: []*string{aws.String("TABLE"), aws.String("NXT")}, LastEvaluatedTableName: aws.String("NXT")},
643	{TableNames: []*string{aws.String("TABLE"), aws.String("NXT")}, LastEvaluatedTableName: aws.String("NXT")},
644	{TableNames: []*string{aws.String("TABLE"), aws.String("NXT")}, LastEvaluatedTableName: aws.String("NXT")},
645	{TableNames: []*string{aws.String("TABLE"), aws.String("NXT")}, LastEvaluatedTableName: aws.String("NXT")},
646	{TableNames: []*string{aws.String("TABLE")}},
647}
648
649var benchDb = func() *dynamodb.DynamoDB {
650	db := dynamodb.New(unit.Session)
651	db.Handlers.Send.Clear() // mock sending
652	db.Handlers.Unmarshal.Clear()
653	db.Handlers.UnmarshalMeta.Clear()
654	db.Handlers.ValidateResponse.Clear()
655	return db
656}
657
658func BenchmarkCodegenIterator(b *testing.B) {
659	reqNum := 0
660	db := benchDb()
661	db.Handlers.Unmarshal.PushBack(func(r *request.Request) {
662		r.Data = benchResps[reqNum]
663		reqNum++
664	})
665
666	input := &dynamodb.ListTablesInput{Limit: aws.Int64(2)}
667	iter := func(fn func(*dynamodb.ListTablesOutput, bool) bool) error {
668		page, _ := db.ListTablesRequest(input)
669		for ; page != nil; page = page.NextPage() {
670			page.Send()
671			out := page.Data.(*dynamodb.ListTablesOutput)
672			if result := fn(out, !page.HasNextPage()); page.Error != nil || !result {
673				return page.Error
674			}
675		}
676		return nil
677	}
678
679	for i := 0; i < b.N; i++ {
680		reqNum = 0
681		iter(func(p *dynamodb.ListTablesOutput, last bool) bool {
682			return true
683		})
684	}
685}
686
687func BenchmarkEachPageIterator(b *testing.B) {
688	reqNum := 0
689	db := benchDb()
690	db.Handlers.Unmarshal.PushBack(func(r *request.Request) {
691		r.Data = benchResps[reqNum]
692		reqNum++
693	})
694
695	input := &dynamodb.ListTablesInput{Limit: aws.Int64(2)}
696	for i := 0; i < b.N; i++ {
697		reqNum = 0
698		req, _ := db.ListTablesRequest(input)
699		req.EachPage(func(p interface{}, last bool) bool {
700			return true
701		})
702	}
703}
704