github.com/aavshr/aws-sdk-go@v1.41.3/service/s3/unmarshal_error_test.go (about)

     1  package s3_test
     2  
     3  import (
     4  	"bytes"
     5  	"fmt"
     6  	"io/ioutil"
     7  	"net/http"
     8  	"strings"
     9  	"testing"
    10  	"time"
    11  
    12  	"github.com/aavshr/aws-sdk-go/aws"
    13  	"github.com/aavshr/aws-sdk-go/aws/awserr"
    14  	"github.com/aavshr/aws-sdk-go/aws/request"
    15  	"github.com/aavshr/aws-sdk-go/awstesting/unit"
    16  	"github.com/aavshr/aws-sdk-go/service/s3"
    17  )
    18  
    19  type testErrorCase struct {
    20  	RespFn           func() *http.Response
    21  	ReqID, HostID    string
    22  	Code, Msg        string
    23  	WithoutStatusMsg bool
    24  }
    25  
    26  var testUnmarshalCases = []testErrorCase{
    27  	{
    28  		RespFn: func() *http.Response {
    29  			return &http.Response{
    30  				StatusCode: 301,
    31  				Header: http.Header{
    32  					"X-Amz-Request-Id": []string{"abc123"},
    33  					"X-Amz-Id-2":       []string{"321cba"},
    34  				},
    35  				Body:          ioutil.NopCloser(bytes.NewReader(nil)),
    36  				ContentLength: -1,
    37  			}
    38  		},
    39  		ReqID:  "abc123",
    40  		HostID: "321cba",
    41  		Code:   "BucketRegionError", Msg: "incorrect region, the bucket is not in 'mock-region' region",
    42  	},
    43  	{
    44  		RespFn: func() *http.Response {
    45  			return &http.Response{
    46  				StatusCode: 403,
    47  				Header: http.Header{
    48  					"X-Amz-Request-Id": []string{"abc123"},
    49  					"X-Amz-Id-2":       []string{"321cba"},
    50  				},
    51  				Body:          ioutil.NopCloser(bytes.NewReader(nil)),
    52  				ContentLength: 0,
    53  			}
    54  		},
    55  		ReqID:  "abc123",
    56  		HostID: "321cba",
    57  		Code:   "Forbidden", Msg: "Forbidden",
    58  	},
    59  	{
    60  		RespFn: func() *http.Response {
    61  			return &http.Response{
    62  				StatusCode: 400,
    63  				Header: http.Header{
    64  					"X-Amz-Request-Id": []string{"abc123"},
    65  					"X-Amz-Id-2":       []string{"321cba"},
    66  				},
    67  				Body:          ioutil.NopCloser(bytes.NewReader(nil)),
    68  				ContentLength: 0,
    69  			}
    70  		},
    71  		ReqID:  "abc123",
    72  		HostID: "321cba",
    73  		Code:   "BadRequest", Msg: "Bad Request",
    74  	},
    75  	{
    76  		RespFn: func() *http.Response {
    77  			return &http.Response{
    78  				StatusCode: 404,
    79  				Header: http.Header{
    80  					"X-Amz-Request-Id": []string{"abc123"},
    81  					"X-Amz-Id-2":       []string{"321cba"},
    82  				},
    83  				Body:          ioutil.NopCloser(bytes.NewReader(nil)),
    84  				ContentLength: 0,
    85  			}
    86  		},
    87  		ReqID:  "abc123",
    88  		HostID: "321cba",
    89  		Code:   "NotFound", Msg: "Not Found",
    90  	},
    91  	{
    92  		// SDK only reads request ID and host ID from the header. The values
    93  		// in message body are ignored.
    94  		RespFn: func() *http.Response {
    95  			body := `<Error><Code>SomeException</Code><Message>Exception message</Message><RequestId>ignored-request-id</RequestId><HostId>ignored-host-id</HostId></Error>`
    96  			return &http.Response{
    97  				StatusCode: 500,
    98  				Header: http.Header{
    99  					"X-Amz-Request-Id": []string{"taken-request-id"},
   100  					"X-Amz-Id-2":       []string{"taken-host-id"},
   101  				},
   102  				Body:          ioutil.NopCloser(strings.NewReader(body)),
   103  				ContentLength: int64(len(body)),
   104  			}
   105  		},
   106  		ReqID:  "taken-request-id",
   107  		HostID: "taken-host-id",
   108  		Code:   "SomeException", Msg: "Exception message",
   109  	},
   110  	{
   111  		RespFn: func() *http.Response {
   112  			return &http.Response{
   113  				StatusCode: 404,
   114  				Header: http.Header{
   115  					"X-Amz-Request-Id": []string{"abc123"},
   116  					"X-Amz-Id-2":       []string{"321cba"},
   117  				},
   118  				Body:          ioutil.NopCloser(bytes.NewReader(nil)),
   119  				ContentLength: -1,
   120  			}
   121  		},
   122  		ReqID:  "abc123",
   123  		HostID: "321cba",
   124  		Code:   "NotFound", Msg: "Not Found", WithoutStatusMsg: true,
   125  	},
   126  	{
   127  		RespFn: func() *http.Response {
   128  			return &http.Response{
   129  				StatusCode: 404,
   130  				Header: http.Header{
   131  					"X-Amz-Request-Id": []string{"abc123"},
   132  					"X-Amz-Id-2":       []string{"321cba"},
   133  				},
   134  				Body:          ioutil.NopCloser(bytes.NewReader(nil)),
   135  				ContentLength: -1,
   136  			}
   137  		},
   138  		ReqID:  "abc123",
   139  		HostID: "321cba",
   140  		Code:   "NotFound", Msg: "Not Found",
   141  	},
   142  }
   143  
   144  func TestUnmarshalError(t *testing.T) {
   145  	for i, c := range testUnmarshalCases {
   146  		s := s3.New(unit.Session)
   147  		s.Handlers.Send.Clear()
   148  		s.Handlers.Send.PushBack(func(r *request.Request) {
   149  			r.HTTPResponse = c.RespFn()
   150  			if !c.WithoutStatusMsg {
   151  				r.HTTPResponse.Status = fmt.Sprintf("%d%s",
   152  					r.HTTPResponse.StatusCode,
   153  					http.StatusText(r.HTTPResponse.StatusCode))
   154  			}
   155  		})
   156  		_, err := s.PutBucketAcl(&s3.PutBucketAclInput{
   157  			Bucket: aws.String("bucket"), ACL: aws.String("public-read"),
   158  		})
   159  
   160  		if err == nil {
   161  			t.Fatalf("%d, expected error, got nil", i)
   162  		}
   163  		if e, a := c.Code, err.(awserr.Error).Code(); e != a {
   164  			t.Errorf("%d, Code: expect %s, got %s", i, e, a)
   165  		}
   166  		if e, a := c.Msg, err.(awserr.Error).Message(); !strings.Contains(a, e) {
   167  			t.Errorf("%d, Message: expect %s, got %s", i, e, a)
   168  		}
   169  		if e, a := c.ReqID, err.(awserr.RequestFailure).RequestID(); e != a {
   170  			t.Errorf("%d, RequestID: expect %s, got %s", i, e, a)
   171  		}
   172  		if e, a := c.HostID, err.(s3.RequestFailure).HostID(); e != a {
   173  			t.Errorf("%d, HostID: expect %s, got %s", i, e, a)
   174  		}
   175  	}
   176  }
   177  
   178  const completeMultiResp = `
   179  163
   180  <?xml version="1.0" encoding="UTF-8"?>
   181  
   182  <CompleteMultipartUploadResult xmlns="http://s3.amazonaws.com/doc/2006-03-01/"><Location>https://bucket.s3-us-west-2.amazonaws.com/key</Location><Bucket>bucket</Bucket><Key>key</Key><ETag>&quot;a7d414b9133d6483d9a1c4e04e856e3b-2&quot;</ETag></CompleteMultipartUploadResult>
   183  0
   184  `
   185  
   186  func Test200NoErrorUnmarshalError(t *testing.T) {
   187  	s := s3.New(unit.Session)
   188  	s.Handlers.Send.Clear()
   189  	s.Handlers.Send.PushBack(func(r *request.Request) {
   190  		r.HTTPResponse = &http.Response{
   191  			StatusCode: 200,
   192  			Header: http.Header{
   193  				"X-Amz-Request-Id": []string{"abc123"},
   194  				"X-Amz-Id-2":       []string{"321cba"},
   195  			},
   196  			Body:          ioutil.NopCloser(strings.NewReader(completeMultiResp)),
   197  			ContentLength: -1,
   198  		}
   199  		r.HTTPResponse.Status = http.StatusText(r.HTTPResponse.StatusCode)
   200  	})
   201  	_, err := s.CompleteMultipartUpload(&s3.CompleteMultipartUploadInput{
   202  		Bucket: aws.String("bucket"), Key: aws.String("key"),
   203  		UploadId: aws.String("id"),
   204  		MultipartUpload: &s3.CompletedMultipartUpload{Parts: []*s3.CompletedPart{
   205  			{ETag: aws.String("etag"), PartNumber: aws.Int64(1)},
   206  		}},
   207  	})
   208  
   209  	if err != nil {
   210  		t.Fatalf("expect no error, got %v", err)
   211  	}
   212  }
   213  
   214  const completeMultiErrResp = `<Error><Code>SomeException</Code><Message>Exception message</Message></Error>`
   215  
   216  func Test200WithErrorUnmarshalError(t *testing.T) {
   217  	const expectAttempts = 4
   218  	s := s3.New(unit.Session, &aws.Config{
   219  		MaxRetries: aws.Int(expectAttempts - 1),
   220  		SleepDelay: func(time.Duration) {},
   221  	})
   222  
   223  	var attempts int
   224  	s.Handlers.Send.Clear()
   225  	s.Handlers.Send.PushBack(func(r *request.Request) {
   226  		attempts++
   227  
   228  		r.HTTPResponse = &http.Response{
   229  			StatusCode: 200,
   230  			Header: http.Header{
   231  				"X-Amz-Request-Id": []string{"abc123"},
   232  				"X-Amz-Id-2":       []string{"321cba"},
   233  			},
   234  			Body:          ioutil.NopCloser(strings.NewReader(completeMultiErrResp)),
   235  			ContentLength: -1,
   236  		}
   237  		r.HTTPResponse.Status = http.StatusText(r.HTTPResponse.StatusCode)
   238  	})
   239  
   240  	_, err := s.CompleteMultipartUpload(&s3.CompleteMultipartUploadInput{
   241  		Bucket: aws.String("bucket"), Key: aws.String("key"),
   242  		UploadId: aws.String("id"),
   243  		MultipartUpload: &s3.CompletedMultipartUpload{Parts: []*s3.CompletedPart{
   244  			{ETag: aws.String("etag"), PartNumber: aws.Int64(1)},
   245  		}},
   246  	})
   247  
   248  	if err == nil {
   249  		t.Fatalf("expected error, got nil")
   250  	}
   251  	if e, a := expectAttempts, attempts; e != a {
   252  		t.Errorf("expect %v attempts, got %v", e, a)
   253  	}
   254  	if e, a := "SomeException", err.(awserr.Error).Code(); e != a {
   255  		t.Errorf("Code: expect %s, got %s", e, a)
   256  	}
   257  	if e, a := "Exception message", err.(awserr.Error).Message(); e != a {
   258  		t.Errorf("Message: expect %s, got %s", e, a)
   259  	}
   260  	if e, a := "abc123", err.(s3.RequestFailure).RequestID(); e != a {
   261  		t.Errorf("RequestID: expect %s, got %s", e, a)
   262  	}
   263  	if e, a := "321cba", err.(s3.RequestFailure).HostID(); e != a {
   264  		t.Errorf("HostID: expect %s, got %s", e, a)
   265  	}
   266  }