// SendHandler is a request handler to send service request using HTTP client. func SendHandler(r *Request) { var err error r.HTTPResponse, err = r.Service.Config.HTTPClient.Do(r.HTTPRequest) if err != nil { // Capture the case where url.Error is returned for error processing // response. e.g. 301 without location header comes back as string // error and r.HTTPResponse is nil. Other url redirect errors will // comeback in a similar method. if e, ok := err.(*url.Error); ok { if s := reStatusCode.FindStringSubmatch(e.Error()); s != nil { code, _ := strconv.ParseInt(s[1], 10, 64) r.HTTPResponse = &http.Response{ StatusCode: int(code), Status: http.StatusText(int(code)), Body: ioutil.NopCloser(bytes.NewReader([]byte{})), } return } } if r.HTTPResponse == nil { // Add a dummy request response object to ensure the HTTPResponse // value is consistent. r.HTTPResponse = &http.Response{ StatusCode: int(0), Status: http.StatusText(int(0)), Body: ioutil.NopCloser(bytes.NewReader([]byte{})), } } // Catch all other request errors. r.Error = awserr.New("RequestError", "send request failed", err) r.Retryable = aws.Bool(true) // network errors are retryable } }
// AfterRetryHandler performs final checks to determine if the request should // be retried and how long to delay. func AfterRetryHandler(r *Request) { // If one of the other handlers already set the retry state // we don't want to override it based on the service's state if r.Retryable == nil { r.Retryable = aws.Bool(r.Service.ShouldRetry(r)) } if r.WillRetry() { r.RetryDelay = r.Service.RetryRules(r) sleepDelay(r.RetryDelay) // when the expired token exception occurs the credentials // need to be expired locally so that the next request to // get credentials will trigger a credentials refresh. if r.Error != nil { if err, ok := r.Error.(awserr.Error); ok { if isCodeExpiredCreds(err.Code()) { r.Config.Credentials.Expire() } } } r.RetryCount++ r.Error = nil } }
// Use S3 for simplicity func TestPaginationTruncation(t *testing.T) { count := 0 client := s3.New(nil) reqNum := &count resps := []*s3.ListObjectsOutput{ {IsTruncated: aws.Bool(true), Contents: []*s3.Object{{Key: aws.String("Key1")}}}, {IsTruncated: aws.Bool(true), Contents: []*s3.Object{{Key: aws.String("Key2")}}}, {IsTruncated: aws.Bool(false), Contents: []*s3.Object{{Key: aws.String("Key3")}}}, {IsTruncated: aws.Bool(true), Contents: []*s3.Object{{Key: aws.String("Key4")}}}, } client.Handlers.Send.Clear() // mock sending client.Handlers.Unmarshal.Clear() client.Handlers.UnmarshalMeta.Clear() client.Handlers.ValidateResponse.Clear() client.Handlers.Unmarshal.PushBack(func(r *service.Request) { r.Data = resps[*reqNum] *reqNum++ }) params := &s3.ListObjectsInput{Bucket: aws.String("bucket")} results := []string{} err := client.ListObjectsPages(params, func(p *s3.ListObjectsOutput, last bool) bool { results = append(results, *p.Contents[0].Key) return true }) assert.Equal(t, []string{"Key1", "Key2", "Key3"}, results) assert.Nil(t, err) // Try again without truncation token at all count = 0 resps[1].IsTruncated = nil resps[2].IsTruncated = aws.Bool(true) results = []string{} err = client.ListObjectsPages(params, func(p *s3.ListObjectsOutput, last bool) bool { results = append(results, *p.Contents[0].Key) return true }) assert.Equal(t, []string{"Key1", "Key2"}, results) assert.Nil(t, err) }
func TestMultipleHandlers(t *testing.T) { r := &Request{} l := HandlerList{} l.PushBack(func(r *Request) { r.Data = nil }) l.PushFront(func(r *Request) { r.Data = aws.Bool(true) }) l.Run(r) if r.Data != nil { t.Error("Expected handler to execute") } }
func TestNoErrors(t *testing.T) { input := &StructShape{ RequiredList: []*ConditionalStructShape{}, RequiredMap: map[string]*ConditionalStructShape{ "key1": {Name: aws.String("Name")}, "key2": {Name: aws.String("Name")}, }, RequiredBool: aws.Bool(true), OptionalStruct: &ConditionalStructShape{Name: aws.String("Name")}, } req := NewRequest(testSvc, &Operation{}, input, nil) ValidateParameters(req) assert.NoError(t, req.Error) }
func TestMetadataNotAvailable(t *testing.T) { c := ec2metadata.New(nil) c.Handlers.Send.Clear() c.Handlers.Send.PushBack(func(r *service.Request) { r.HTTPResponse = &http.Response{ StatusCode: int(0), Status: http.StatusText(int(0)), Body: ioutil.NopCloser(bytes.NewReader([]byte{})), } r.Error = awserr.New("RequestError", "send request failed", nil) r.Retryable = aws.Bool(true) // network errors are retryable }) available := c.Available() assert.False(t, available) }
func TestNestedMissingRequiredParameters(t *testing.T) { input := &StructShape{ RequiredList: []*ConditionalStructShape{{}}, RequiredMap: map[string]*ConditionalStructShape{ "key1": {Name: aws.String("Name")}, "key2": {}, }, RequiredBool: aws.Bool(true), OptionalStruct: &ConditionalStructShape{}, } req := NewRequest(testSvc, &Operation{}, input, nil) ValidateParameters(req) assert.Error(t, req.Error) assert.Equal(t, "InvalidParameter", req.Error.(awserr.Error).Code()) assert.Equal(t, "3 validation errors:\n- missing required parameter: RequiredList[0].Name\n- missing required parameter: RequiredMap[\"key2\"].Name\n- missing required parameter: OptionalStruct.Name", req.Error.(awserr.Error).Message()) }