@@ -18,6 +18,7 @@ import (
1818 "github.com/aws/aws-sdk-go-v2/aws/retry"
1919 "github.com/aws/aws-sdk-go-v2/internal/awstesting"
2020 "github.com/aws/aws-sdk-go-v2/internal/awstesting/unit"
21+ "github.com/aws/aws-sdk-go-v2/internal/sdk"
2122 "github.com/aws/aws-sdk-go-v2/service/s3"
2223)
2324
@@ -349,10 +350,21 @@ func TestRequestInvocationIDHeaderHandler(t *testing.T) {
349350}
350351
351352func TestRetryMetricHeaderHandler (t * testing.T ) {
353+ nowTime := sdk .NowTime
354+ defer func () {
355+ sdk .NowTime = nowTime
356+ }()
357+ sdk .NowTime = func () time.Time {
358+ return time .Date (2020 , 2 , 2 , 0 , 0 , 0 , 0 , time .UTC )
359+ }
360+
352361 cases := map [string ]struct {
353- Attempt int
354- MaxAttempts int
355- Expect string
362+ Attempt int
363+ MaxAttempts int
364+ Client aws.HTTPClient
365+ ContextDeadline time.Time
366+ AttemptClockSkews []time.Duration
367+ Expect string
356368 }{
357369 "first attempt" : {
358370 Attempt : 1 , MaxAttempts : 3 ,
@@ -366,15 +378,43 @@ func TestRetryMetricHeaderHandler(t *testing.T) {
366378 Attempt : 10 ,
367379 Expect : "attempt=10" ,
368380 },
381+ "with ttl client timeout" : {
382+ Attempt : 2 , MaxAttempts : 3 ,
383+ AttemptClockSkews : []time.Duration {
384+ 10 * time .Second ,
385+ },
386+ Client : func () aws.HTTPClient {
387+ c := & aws.BuildableHTTPClient {}
388+ return c .WithTimeout (10 * time .Second )
389+ }(),
390+ Expect : "attempt=2; max=3; ttl=20200202T000020Z" ,
391+ },
392+ "with ttl context deadline" : {
393+ Attempt : 1 , MaxAttempts : 3 ,
394+ AttemptClockSkews : []time.Duration {
395+ 10 * time .Second ,
396+ },
397+ ContextDeadline : sdk .NowTime ().Add (10 * time .Second ),
398+ Expect : "attempt=1; max=3; ttl=20200202T000020Z" ,
399+ },
369400 }
370401
371402 for name , c := range cases {
372403 t .Run (name , func (t * testing.T ) {
373404 cfg := unit .Config ()
405+ if c .Client != nil {
406+ cfg .HTTPClient = c .Client
407+ }
374408 r := aws .New (cfg , aws.Metadata {}, cfg .Handlers , aws.NoOpRetryer {},
375409 & aws.Operation {}, & struct {}{}, struct {}{})
410+ if ! c .ContextDeadline .IsZero () {
411+ ctx , cancel := context .WithDeadline (r .Context (), c .ContextDeadline )
412+ defer cancel ()
413+ r .SetContext (ctx )
414+ }
376415
377416 r .AttemptNum = c .Attempt
417+ r .AttemptClockSkews = c .AttemptClockSkews
378418 r .Retryer = retry .AddWithMaxAttempts (r .Retryer , c .MaxAttempts )
379419
380420 defaults .RetryMetricHeaderHandler .Fn (r )
@@ -388,3 +428,92 @@ func TestRetryMetricHeaderHandler(t *testing.T) {
388428 })
389429 }
390430}
431+
432+ func TestAttemptClockSkewHandler (t * testing.T ) {
433+ cases := map [string ]struct {
434+ Req * aws.Request
435+ Expect []time.Duration
436+ }{
437+ "no response" : {Req : & aws.Request {}},
438+ "failed response" : {
439+ Req : & aws.Request {
440+ HTTPResponse : & http.Response {StatusCode : 0 , Header : http.Header {}},
441+ },
442+ },
443+ "no date header response" : {
444+ Req : & aws.Request {
445+ HTTPResponse : & http.Response {StatusCode : 200 , Header : http.Header {}},
446+ },
447+ },
448+ "invalid date header response" : {
449+ Req : & aws.Request {
450+ HTTPResponse : & http.Response {
451+ StatusCode : 200 ,
452+ Header : http.Header {"Date" : []string {"abc123" }},
453+ },
454+ },
455+ },
456+ "response at unset" : {
457+ Req : & aws.Request {
458+ HTTPResponse : & http.Response {
459+ StatusCode : 200 ,
460+ Header : http.Header {
461+ "Date" : []string {"Thu, 05 Mar 2020 22:25:15 GMT" },
462+ },
463+ },
464+ },
465+ },
466+ "first date response" : {
467+ Req : & aws.Request {
468+ HTTPResponse : & http.Response {
469+ StatusCode : 200 ,
470+ Header : http.Header {
471+ "Date" : []string {"Thu, 05 Mar 2020 22:25:15 GMT" },
472+ },
473+ },
474+ ResponseAt : time .Date (2020 , 3 , 5 , 22 , 25 , 17 , 0 , time .UTC ),
475+ },
476+ Expect : []time.Duration {- 2 * time .Second },
477+ },
478+ "subsequent date response" : {
479+ Req : & aws.Request {
480+ HTTPResponse : & http.Response {
481+ StatusCode : 200 ,
482+ Header : http.Header {
483+ "Date" : []string {"Thu, 05 Mar 2020 22:25:15 GMT" },
484+ },
485+ },
486+ ResponseAt : time .Date (2020 , 3 , 5 , 22 , 25 , 14 , 0 , time .UTC ),
487+ AttemptClockSkews : []time.Duration {
488+ - 2 * time .Second ,
489+ },
490+ },
491+ Expect : []time.Duration {
492+ - 2 * time .Second ,
493+ 1 * time .Second ,
494+ },
495+ },
496+ }
497+
498+ for name , c := range cases {
499+ t .Run (name , func (t * testing.T ) {
500+ r := new (aws.Request )
501+ * r = * c .Req
502+
503+ defaults .AttemptClockSkewHandler .Fn (r )
504+ if err := r .Error ; err != nil {
505+ t .Fatalf ("expect no error, got %v" , err )
506+ }
507+
508+ if e , a := len (c .Expect ), len (r .AttemptClockSkews ); e != a {
509+ t .Errorf ("expect %v skews, got %v" , e , a )
510+ }
511+
512+ for i , s := range r .AttemptClockSkews {
513+ if e , a := c .Expect [i ], s ; e != a {
514+ t .Errorf ("%d, expect %v skew, got %v" , i , e , a )
515+ }
516+ }
517+ })
518+ }
519+ }
0 commit comments