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

     1  //go:build go1.8
     2  // +build go1.8
     3  
     4  package s3manager_test
     5  
     6  import (
     7  	"bytes"
     8  	"fmt"
     9  	"io"
    10  	"io/ioutil"
    11  	random "math/rand"
    12  	"net/http"
    13  	"net/http/httptest"
    14  	"os"
    15  	"reflect"
    16  	"regexp"
    17  	"sort"
    18  	"strconv"
    19  	"strings"
    20  	"sync"
    21  	"testing"
    22  	"time"
    23  
    24  	"github.com/aavshr/aws-sdk-go/aws"
    25  	"github.com/aavshr/aws-sdk-go/aws/awserr"
    26  	"github.com/aavshr/aws-sdk-go/aws/awsutil"
    27  	"github.com/aavshr/aws-sdk-go/aws/request"
    28  	"github.com/aavshr/aws-sdk-go/awstesting"
    29  	"github.com/aavshr/aws-sdk-go/awstesting/unit"
    30  	"github.com/aavshr/aws-sdk-go/service/s3"
    31  	"github.com/aavshr/aws-sdk-go/service/s3/internal/s3testing"
    32  	"github.com/aavshr/aws-sdk-go/service/s3/s3manager"
    33  )
    34  
    35  var emptyList = []string{}
    36  
    37  const respMsg = `<?xml version="1.0" encoding="UTF-8"?>
    38  <CompleteMultipartUploadOutput>
    39     <Location>mockValue</Location>
    40     <Bucket>mockValue</Bucket>
    41     <Key>mockValue</Key>
    42     <ETag>mockValue</ETag>
    43  </CompleteMultipartUploadOutput>`
    44  
    45  func val(i interface{}, s string) interface{} {
    46  	v, err := awsutil.ValuesAtPath(i, s)
    47  	if err != nil || len(v) == 0 {
    48  		return nil
    49  	}
    50  	if _, ok := v[0].(io.Reader); ok {
    51  		return v[0]
    52  	}
    53  
    54  	if rv := reflect.ValueOf(v[0]); rv.Kind() == reflect.Ptr {
    55  		return rv.Elem().Interface()
    56  	}
    57  
    58  	return v[0]
    59  }
    60  
    61  func contains(src []string, s string) bool {
    62  	for _, v := range src {
    63  		if s == v {
    64  			return true
    65  		}
    66  	}
    67  	return false
    68  }
    69  
    70  func loggingSvc(ignoreOps []string) (*s3.S3, *[]string, *[]interface{}) {
    71  	var m sync.Mutex
    72  	partNum := 0
    73  	names := []string{}
    74  	params := []interface{}{}
    75  	svc := s3.New(unit.Session)
    76  	svc.Handlers.Unmarshal.Clear()
    77  	svc.Handlers.UnmarshalMeta.Clear()
    78  	svc.Handlers.UnmarshalError.Clear()
    79  	svc.Handlers.Send.Clear()
    80  	svc.Handlers.Send.PushBack(func(r *request.Request) {
    81  		m.Lock()
    82  		defer m.Unlock()
    83  
    84  		if !contains(ignoreOps, r.Operation.Name) {
    85  			names = append(names, r.Operation.Name)
    86  			params = append(params, r.Params)
    87  		}
    88  
    89  		r.HTTPResponse = &http.Response{
    90  			StatusCode: 200,
    91  			Body:       ioutil.NopCloser(bytes.NewReader([]byte(respMsg))),
    92  		}
    93  
    94  		switch data := r.Data.(type) {
    95  		case *s3.CreateMultipartUploadOutput:
    96  			data.UploadId = aws.String("UPLOAD-ID")
    97  		case *s3.UploadPartOutput:
    98  			partNum++
    99  			data.ETag = aws.String(fmt.Sprintf("ETAG%d", partNum))
   100  		case *s3.CompleteMultipartUploadOutput:
   101  			data.Location = aws.String("https://location")
   102  			data.VersionId = aws.String("VERSION-ID")
   103  			data.ETag = aws.String("ETAG")
   104  		case *s3.PutObjectOutput:
   105  			data.VersionId = aws.String("VERSION-ID")
   106  			data.ETag = aws.String("ETAG")
   107  		}
   108  	})
   109  
   110  	return svc, &names, &params
   111  }
   112  
   113  func buflen(i interface{}) int {
   114  	r := i.(io.Reader)
   115  	b, _ := ioutil.ReadAll(r)
   116  	return len(b)
   117  }
   118  
   119  func TestUploadOrderMulti(t *testing.T) {
   120  	s, ops, args := loggingSvc(emptyList)
   121  	u := s3manager.NewUploaderWithClient(s)
   122  
   123  	resp, err := u.Upload(&s3manager.UploadInput{
   124  		Bucket:               aws.String("Bucket"),
   125  		Key:                  aws.String("Key - value"),
   126  		Body:                 bytes.NewReader(buf12MB),
   127  		ServerSideEncryption: aws.String("aws:kms"),
   128  		SSEKMSKeyId:          aws.String("KmsId"),
   129  		ContentType:          aws.String("content/type"),
   130  	})
   131  
   132  	if err != nil {
   133  		t.Errorf("Expected no error but received %v", err)
   134  	}
   135  
   136  	expected := []string{"CreateMultipartUpload", "UploadPart", "UploadPart", "UploadPart", "CompleteMultipartUpload"}
   137  	if !reflect.DeepEqual(expected, *ops) {
   138  		t.Errorf("Expected %v, but received %v", expected, *ops)
   139  	}
   140  
   141  	if e, a := `https://s3.mock-region.amazonaws.com/Bucket/Key%20-%20value`, resp.Location; e != a {
   142  		t.Errorf("Expected %q, but received %q", e, a)
   143  	}
   144  
   145  	if "UPLOAD-ID" != resp.UploadID {
   146  		t.Errorf("Expected %q, but received %q", "UPLOAD-ID", resp.UploadID)
   147  	}
   148  
   149  	if "VERSION-ID" != *resp.VersionID {
   150  		t.Errorf("Expected %q, but received %q", "VERSION-ID", *resp.VersionID)
   151  	}
   152  
   153  	if "ETAG" != *resp.ETag {
   154  		t.Errorf("Expected %q, but received %q", "ETAG", *resp.ETag)
   155  	}
   156  
   157  	// Validate input values
   158  
   159  	// UploadPart
   160  	for i := 1; i < 5; i++ {
   161  		v := val((*args)[i], "UploadId")
   162  		if "UPLOAD-ID" != v {
   163  			t.Errorf("Expected %q, but received %q", "UPLOAD-ID", v)
   164  		}
   165  	}
   166  
   167  	// CompleteMultipartUpload
   168  	v := val((*args)[4], "UploadId")
   169  	if "UPLOAD-ID" != v {
   170  		t.Errorf("Expected %q, but received %q", "UPLOAD-ID", v)
   171  	}
   172  
   173  	for i := 0; i < 3; i++ {
   174  		e := val((*args)[4], fmt.Sprintf("MultipartUpload.Parts[%d].PartNumber", i))
   175  		if int64(i+1) != e.(int64) {
   176  			t.Errorf("Expected %d, but received %d", i+1, e)
   177  		}
   178  	}
   179  
   180  	vals := []string{
   181  		val((*args)[4], "MultipartUpload.Parts[0].ETag").(string),
   182  		val((*args)[4], "MultipartUpload.Parts[1].ETag").(string),
   183  		val((*args)[4], "MultipartUpload.Parts[2].ETag").(string),
   184  	}
   185  
   186  	for _, a := range vals {
   187  		if matched, err := regexp.MatchString(`^ETAG\d+$`, a); !matched || err != nil {
   188  			t.Errorf("Failed regexp expression `^ETAG\\d+$`")
   189  		}
   190  	}
   191  
   192  	// Custom headers
   193  	e := val((*args)[0], "ServerSideEncryption")
   194  	if e != "aws:kms" {
   195  		t.Errorf("Expected %q, but received %q", "aws:kms", e)
   196  	}
   197  
   198  	e = val((*args)[0], "SSEKMSKeyId")
   199  	if e != "KmsId" {
   200  		t.Errorf("Expected %q, but received %q", "KmsId", e)
   201  	}
   202  
   203  	e = val((*args)[0], "ContentType")
   204  	if e != "content/type" {
   205  		t.Errorf("Expected %q, but received %q", "content/type", e)
   206  	}
   207  }
   208  
   209  func TestUploadOrderMultiDifferentPartSize(t *testing.T) {
   210  	s, ops, args := loggingSvc(emptyList)
   211  	mgr := s3manager.NewUploaderWithClient(s, func(u *s3manager.Uploader) {
   212  		u.PartSize = 1024 * 1024 * 7
   213  		u.Concurrency = 1
   214  	})
   215  	_, err := mgr.Upload(&s3manager.UploadInput{
   216  		Bucket: aws.String("Bucket"),
   217  		Key:    aws.String("Key"),
   218  		Body:   bytes.NewReader(buf12MB),
   219  	})
   220  
   221  	if err != nil {
   222  		t.Errorf("Expected no error but received %v", err)
   223  	}
   224  
   225  	vals := []string{"CreateMultipartUpload", "UploadPart", "UploadPart", "CompleteMultipartUpload"}
   226  	if !reflect.DeepEqual(vals, *ops) {
   227  		t.Errorf("Expected %v, but received %v", vals, *ops)
   228  	}
   229  
   230  	// Part lengths
   231  	if len := buflen(val((*args)[1], "Body")); 1024*1024*7 != len {
   232  		t.Errorf("Expected %d, but received %d", 1024*1024*7, len)
   233  	}
   234  	if len := buflen(val((*args)[2], "Body")); 1024*1024*5 != len {
   235  		t.Errorf("Expected %d, but received %d", 1024*1024*5, len)
   236  	}
   237  }
   238  
   239  func TestUploadIncreasePartSize(t *testing.T) {
   240  	s, ops, args := loggingSvc(emptyList)
   241  	mgr := s3manager.NewUploaderWithClient(s, func(u *s3manager.Uploader) {
   242  		u.Concurrency = 1
   243  		u.MaxUploadParts = 2
   244  	})
   245  	_, err := mgr.Upload(&s3manager.UploadInput{
   246  		Bucket: aws.String("Bucket"),
   247  		Key:    aws.String("Key"),
   248  		Body:   bytes.NewReader(buf12MB),
   249  	})
   250  
   251  	if err != nil {
   252  		t.Errorf("Expected no error but received %v", err)
   253  	}
   254  
   255  	if int64(s3manager.DefaultDownloadPartSize) != mgr.PartSize {
   256  		t.Errorf("Expected %d, but received %d", s3manager.DefaultDownloadPartSize, mgr.PartSize)
   257  	}
   258  
   259  	vals := []string{"CreateMultipartUpload", "UploadPart", "UploadPart", "CompleteMultipartUpload"}
   260  	if !reflect.DeepEqual(vals, *ops) {
   261  		t.Errorf("Expected %v, but received %v", vals, *ops)
   262  	}
   263  
   264  	// Part lengths
   265  	if len := buflen(val((*args)[1], "Body")); (1024*1024*6)+1 != len {
   266  		t.Errorf("Expected %d, but received %d", (1024*1024*6)+1, len)
   267  	}
   268  
   269  	if len := buflen(val((*args)[2], "Body")); (1024*1024*6)-1 != len {
   270  		t.Errorf("Expected %d, but received %d", (1024*1024*6)-1, len)
   271  	}
   272  }
   273  
   274  func TestUploadFailIfPartSizeTooSmall(t *testing.T) {
   275  	mgr := s3manager.NewUploader(unit.Session, func(u *s3manager.Uploader) {
   276  		u.PartSize = 5
   277  	})
   278  	resp, err := mgr.Upload(&s3manager.UploadInput{
   279  		Bucket: aws.String("Bucket"),
   280  		Key:    aws.String("Key"),
   281  		Body:   bytes.NewReader(buf12MB),
   282  	})
   283  
   284  	if resp != nil {
   285  		t.Errorf("Expected response to be nil, but received %v", resp)
   286  	}
   287  
   288  	if err == nil {
   289  		t.Errorf("Expected error, but received nil")
   290  	}
   291  
   292  	aerr := err.(awserr.Error)
   293  	if e, a := "ConfigError", aerr.Code(); e != a {
   294  		t.Errorf("Expected %q, but received %q", e, a)
   295  	}
   296  
   297  	if e, a := "part size must be at least", aerr.Message(); !strings.Contains(a, e) {
   298  		t.Errorf("expect %v to be in %v", e, a)
   299  	}
   300  }
   301  
   302  func TestUploadOrderSingle(t *testing.T) {
   303  	s, ops, args := loggingSvc(emptyList)
   304  	mgr := s3manager.NewUploaderWithClient(s)
   305  	resp, err := mgr.Upload(&s3manager.UploadInput{
   306  		Bucket:               aws.String("Bucket"),
   307  		Key:                  aws.String("Key - value"),
   308  		Body:                 bytes.NewReader(buf2MB),
   309  		ServerSideEncryption: aws.String("aws:kms"),
   310  		SSEKMSKeyId:          aws.String("KmsId"),
   311  		ContentType:          aws.String("content/type"),
   312  	})
   313  
   314  	if err != nil {
   315  		t.Errorf("Expected no error but received %v", err)
   316  	}
   317  
   318  	if vals := []string{"PutObject"}; !reflect.DeepEqual(vals, *ops) {
   319  		t.Errorf("Expected %v, but received %v", vals, *ops)
   320  	}
   321  
   322  	if e, a := `https://s3.mock-region.amazonaws.com/Bucket/Key%20-%20value`, resp.Location; e != a {
   323  		t.Errorf("Expected %q, but received %q", e, a)
   324  	}
   325  
   326  	if e := "VERSION-ID"; e != *resp.VersionID {
   327  		t.Errorf("Expected %q, but received %q", e, *resp.VersionID)
   328  	}
   329  
   330  	if "ETAG" != *resp.ETag {
   331  		t.Errorf("Expected %q, but received %q", "ETAG", *resp.ETag)
   332  	}
   333  
   334  	if len(resp.UploadID) > 0 {
   335  		t.Errorf("Expected empty string, but received %q", resp.UploadID)
   336  	}
   337  
   338  	if e, a := "aws:kms", val((*args)[0], "ServerSideEncryption").(string); e != a {
   339  		t.Errorf("Expected %q, but received %q", e, a)
   340  	}
   341  
   342  	if e, a := "KmsId", val((*args)[0], "SSEKMSKeyId").(string); e != a {
   343  		t.Errorf("Expected %q, but received %q", e, a)
   344  	}
   345  
   346  	if e, a := "content/type", val((*args)[0], "ContentType").(string); e != a {
   347  		t.Errorf("Expected %q, but received %q", e, a)
   348  	}
   349  }
   350  
   351  func TestUploadOrderSingleFailure(t *testing.T) {
   352  	s, ops, _ := loggingSvc(emptyList)
   353  	s.Handlers.Send.PushBack(func(r *request.Request) {
   354  		r.HTTPResponse.StatusCode = 400
   355  	})
   356  	mgr := s3manager.NewUploaderWithClient(s)
   357  	resp, err := mgr.Upload(&s3manager.UploadInput{
   358  		Bucket: aws.String("Bucket"),
   359  		Key:    aws.String("Key"),
   360  		Body:   bytes.NewReader(buf2MB),
   361  	})
   362  
   363  	if err == nil {
   364  		t.Error("Expected error, but receievd nil")
   365  	}
   366  
   367  	if vals := []string{"PutObject"}; !reflect.DeepEqual(vals, *ops) {
   368  		t.Errorf("Expected %v, but received %v", vals, *ops)
   369  	}
   370  
   371  	if resp != nil {
   372  		t.Errorf("Expected response to be nil, but received %v", resp)
   373  	}
   374  }
   375  
   376  func TestUploadOrderZero(t *testing.T) {
   377  	s, ops, args := loggingSvc(emptyList)
   378  	mgr := s3manager.NewUploaderWithClient(s)
   379  	resp, err := mgr.Upload(&s3manager.UploadInput{
   380  		Bucket: aws.String("Bucket"),
   381  		Key:    aws.String("Key"),
   382  		Body:   bytes.NewReader(make([]byte, 0)),
   383  	})
   384  
   385  	if err != nil {
   386  		t.Errorf("Expected no error but received %v", err)
   387  	}
   388  
   389  	if vals := []string{"PutObject"}; !reflect.DeepEqual(vals, *ops) {
   390  		t.Errorf("Expected %v, but received %v", vals, *ops)
   391  	}
   392  
   393  	if len(resp.Location) == 0 {
   394  		t.Error("Expected Location to not be empty")
   395  	}
   396  
   397  	if len(resp.UploadID) > 0 {
   398  		t.Errorf("Expected empty string, but received %q", resp.UploadID)
   399  	}
   400  
   401  	if e, a := 0, buflen(val((*args)[0], "Body")); e != a {
   402  		t.Errorf("Expected %d, but received %d", e, a)
   403  	}
   404  }
   405  
   406  func TestUploadOrderMultiFailure(t *testing.T) {
   407  	s, ops, _ := loggingSvc(emptyList)
   408  	s.Handlers.Send.PushBack(func(r *request.Request) {
   409  		switch t := r.Data.(type) {
   410  		case *s3.UploadPartOutput:
   411  			if *t.ETag == "ETAG2" {
   412  				r.HTTPResponse.StatusCode = 400
   413  			}
   414  		}
   415  	})
   416  
   417  	mgr := s3manager.NewUploaderWithClient(s, func(u *s3manager.Uploader) {
   418  		u.Concurrency = 1
   419  	})
   420  	_, err := mgr.Upload(&s3manager.UploadInput{
   421  		Bucket: aws.String("Bucket"),
   422  		Key:    aws.String("Key"),
   423  		Body:   bytes.NewReader(buf12MB),
   424  	})
   425  
   426  	if err == nil {
   427  		t.Error("Expected error, but receievd nil")
   428  	}
   429  
   430  	if e, a := []string{"CreateMultipartUpload", "UploadPart", "UploadPart", "AbortMultipartUpload"}, *ops; !reflect.DeepEqual(e, a) {
   431  		t.Errorf("Expected %v, but received %v", e, a)
   432  	}
   433  }
   434  
   435  func TestUploadOrderMultiFailureOnComplete(t *testing.T) {
   436  	s, ops, _ := loggingSvc(emptyList)
   437  	s.Handlers.Send.PushBack(func(r *request.Request) {
   438  		switch r.Data.(type) {
   439  		case *s3.CompleteMultipartUploadOutput:
   440  			r.HTTPResponse.StatusCode = 400
   441  		}
   442  	})
   443  
   444  	mgr := s3manager.NewUploaderWithClient(s, func(u *s3manager.Uploader) {
   445  		u.Concurrency = 1
   446  	})
   447  	_, err := mgr.Upload(&s3manager.UploadInput{
   448  		Bucket: aws.String("Bucket"),
   449  		Key:    aws.String("Key"),
   450  		Body:   bytes.NewReader(buf12MB),
   451  	})
   452  
   453  	if err == nil {
   454  		t.Error("Expected error, but receievd nil")
   455  	}
   456  
   457  	if e, a := []string{"CreateMultipartUpload", "UploadPart", "UploadPart",
   458  		"UploadPart", "CompleteMultipartUpload", "AbortMultipartUpload"}, *ops; !reflect.DeepEqual(e, a) {
   459  		t.Errorf("Expected %v, but received %v", e, a)
   460  	}
   461  }
   462  
   463  func TestUploadOrderMultiFailureOnCreate(t *testing.T) {
   464  	s, ops, _ := loggingSvc(emptyList)
   465  	s.Handlers.Send.PushBack(func(r *request.Request) {
   466  		switch r.Data.(type) {
   467  		case *s3.CreateMultipartUploadOutput:
   468  			r.HTTPResponse.StatusCode = 400
   469  		}
   470  	})
   471  
   472  	mgr := s3manager.NewUploaderWithClient(s)
   473  	_, err := mgr.Upload(&s3manager.UploadInput{
   474  		Bucket: aws.String("Bucket"),
   475  		Key:    aws.String("Key"),
   476  		Body:   bytes.NewReader(make([]byte, 1024*1024*12)),
   477  	})
   478  
   479  	if err == nil {
   480  		t.Error("Expected error, but receievd nil")
   481  	}
   482  
   483  	if e, a := []string{"CreateMultipartUpload"}, *ops; !reflect.DeepEqual(e, a) {
   484  		t.Errorf("Expected %v, but received %v", e, a)
   485  	}
   486  }
   487  
   488  func TestUploadOrderMultiFailureLeaveParts(t *testing.T) {
   489  	s, ops, _ := loggingSvc(emptyList)
   490  	s.Handlers.Send.PushBack(func(r *request.Request) {
   491  		switch data := r.Data.(type) {
   492  		case *s3.UploadPartOutput:
   493  			if *data.ETag == "ETAG2" {
   494  				r.HTTPResponse.StatusCode = 400
   495  			}
   496  		}
   497  	})
   498  
   499  	mgr := s3manager.NewUploaderWithClient(s, func(u *s3manager.Uploader) {
   500  		u.Concurrency = 1
   501  		u.LeavePartsOnError = true
   502  	})
   503  	_, err := mgr.Upload(&s3manager.UploadInput{
   504  		Bucket: aws.String("Bucket"),
   505  		Key:    aws.String("Key"),
   506  		Body:   bytes.NewReader(make([]byte, 1024*1024*12)),
   507  	})
   508  
   509  	if err == nil {
   510  		t.Error("Expected error, but receievd nil")
   511  	}
   512  
   513  	if e, a := []string{"CreateMultipartUpload", "UploadPart", "UploadPart"}, *ops; !reflect.DeepEqual(e, a) {
   514  		t.Errorf("Expected %v, but received %v", e, a)
   515  	}
   516  }
   517  
   518  type failreader struct {
   519  	times     int
   520  	failCount int
   521  }
   522  
   523  func (f *failreader) Read(b []byte) (int, error) {
   524  	f.failCount++
   525  	if f.failCount >= f.times {
   526  		return 0, fmt.Errorf("random failure")
   527  	}
   528  	return len(b), nil
   529  }
   530  
   531  func TestUploadOrderReadFail1(t *testing.T) {
   532  	s, ops, _ := loggingSvc(emptyList)
   533  	mgr := s3manager.NewUploaderWithClient(s)
   534  	_, err := mgr.Upload(&s3manager.UploadInput{
   535  		Bucket: aws.String("Bucket"),
   536  		Key:    aws.String("Key"),
   537  		Body:   &failreader{times: 1},
   538  	})
   539  
   540  	if e, a := "ReadRequestBody", err.(awserr.Error).Code(); e != a {
   541  		t.Errorf("Expected %q, but received %q", e, a)
   542  	}
   543  
   544  	if e, a := err.(awserr.Error).OrigErr().Error(), "random failure"; e != a {
   545  		t.Errorf("Expected %q, but received %q", e, a)
   546  	}
   547  
   548  	if e, a := []string{}, *ops; !reflect.DeepEqual(e, a) {
   549  		t.Errorf("Expected %v, but received %v", e, a)
   550  	}
   551  }
   552  
   553  func TestUploadOrderReadFail2(t *testing.T) {
   554  	s, ops, _ := loggingSvc([]string{"UploadPart"})
   555  	mgr := s3manager.NewUploaderWithClient(s, func(u *s3manager.Uploader) {
   556  		u.Concurrency = 1
   557  	})
   558  	_, err := mgr.Upload(&s3manager.UploadInput{
   559  		Bucket: aws.String("Bucket"),
   560  		Key:    aws.String("Key"),
   561  		Body:   &failreader{times: 2},
   562  	})
   563  
   564  	if e, a := "MultipartUpload", err.(awserr.Error).Code(); e != a {
   565  		t.Errorf("Expected %q, but received %q", e, a)
   566  	}
   567  
   568  	if e, a := "ReadRequestBody", err.(awserr.Error).OrigErr().(awserr.Error).Code(); e != a {
   569  		t.Errorf("Expected %q, but received %q", e, a)
   570  	}
   571  
   572  	if errStr := err.(awserr.Error).OrigErr().Error(); !strings.Contains(errStr, "random failure") {
   573  		t.Errorf("Expected error to contains 'random failure', but was %q", errStr)
   574  	}
   575  
   576  	if e, a := []string{"CreateMultipartUpload", "AbortMultipartUpload"}, *ops; !reflect.DeepEqual(e, a) {
   577  		t.Errorf("Expected %v, but receievd %v", e, a)
   578  	}
   579  }
   580  
   581  type sizedReader struct {
   582  	size int
   583  	cur  int
   584  	err  error
   585  }
   586  
   587  func (s *sizedReader) Read(p []byte) (n int, err error) {
   588  	if s.cur >= s.size {
   589  		if s.err == nil {
   590  			s.err = io.EOF
   591  		}
   592  		return 0, s.err
   593  	}
   594  
   595  	n = len(p)
   596  	s.cur += len(p)
   597  	if s.cur > s.size {
   598  		n -= s.cur - s.size
   599  	}
   600  
   601  	return n, err
   602  }
   603  
   604  func TestUploadOrderMultiBufferedReader(t *testing.T) {
   605  	s, ops, args := loggingSvc(emptyList)
   606  	mgr := s3manager.NewUploaderWithClient(s)
   607  	_, err := mgr.Upload(&s3manager.UploadInput{
   608  		Bucket: aws.String("Bucket"),
   609  		Key:    aws.String("Key"),
   610  		Body:   &sizedReader{size: 1024 * 1024 * 12},
   611  	})
   612  
   613  	if err != nil {
   614  		t.Errorf("Expected no error but received %v", err)
   615  	}
   616  
   617  	if e, a := []string{"CreateMultipartUpload", "UploadPart", "UploadPart", "UploadPart", "CompleteMultipartUpload"}, *ops; !reflect.DeepEqual(e, a) {
   618  		t.Errorf("Expected %v, but receievd %v", e, a)
   619  	}
   620  
   621  	// Part lengths
   622  	parts := []int{
   623  		buflen(val((*args)[1], "Body")),
   624  		buflen(val((*args)[2], "Body")),
   625  		buflen(val((*args)[3], "Body")),
   626  	}
   627  	sort.Ints(parts)
   628  
   629  	if e, a := []int{1024 * 1024 * 2, 1024 * 1024 * 5, 1024 * 1024 * 5}, parts; !reflect.DeepEqual(e, a) {
   630  		t.Errorf("Expected %v, but receievd %v", e, a)
   631  	}
   632  }
   633  
   634  func TestUploadOrderMultiBufferedReaderPartial(t *testing.T) {
   635  	s, ops, args := loggingSvc(emptyList)
   636  	mgr := s3manager.NewUploaderWithClient(s)
   637  	_, err := mgr.Upload(&s3manager.UploadInput{
   638  		Bucket: aws.String("Bucket"),
   639  		Key:    aws.String("Key"),
   640  		Body:   &sizedReader{size: 1024 * 1024 * 12, err: io.EOF},
   641  	})
   642  
   643  	if err != nil {
   644  		t.Errorf("Expected no error but received %v", err)
   645  	}
   646  
   647  	if e, a := []string{"CreateMultipartUpload", "UploadPart", "UploadPart", "UploadPart", "CompleteMultipartUpload"}, *ops; !reflect.DeepEqual(e, a) {
   648  		t.Errorf("Expected %v, but receievd %v", e, a)
   649  	}
   650  
   651  	// Part lengths
   652  	parts := []int{
   653  		buflen(val((*args)[1], "Body")),
   654  		buflen(val((*args)[2], "Body")),
   655  		buflen(val((*args)[3], "Body")),
   656  	}
   657  	sort.Ints(parts)
   658  
   659  	if e, a := []int{1024 * 1024 * 2, 1024 * 1024 * 5, 1024 * 1024 * 5}, parts; !reflect.DeepEqual(e, a) {
   660  		t.Errorf("Expected %v, but receievd %v", e, a)
   661  	}
   662  }
   663  
   664  // TestUploadOrderMultiBufferedReaderEOF tests the edge case where the
   665  // file size is the same as part size.
   666  func TestUploadOrderMultiBufferedReaderEOF(t *testing.T) {
   667  	s, ops, args := loggingSvc(emptyList)
   668  	mgr := s3manager.NewUploaderWithClient(s)
   669  	_, err := mgr.Upload(&s3manager.UploadInput{
   670  		Bucket: aws.String("Bucket"),
   671  		Key:    aws.String("Key"),
   672  		Body:   &sizedReader{size: 1024 * 1024 * 10, err: io.EOF},
   673  	})
   674  
   675  	if err != nil {
   676  		t.Errorf("Expected no error but received %v", err)
   677  	}
   678  
   679  	if e, a := []string{"CreateMultipartUpload", "UploadPart", "UploadPart", "CompleteMultipartUpload"}, *ops; !reflect.DeepEqual(e, a) {
   680  		t.Errorf("Expected %v, but receievd %v", e, a)
   681  	}
   682  
   683  	// Part lengths
   684  	parts := []int{
   685  		buflen(val((*args)[1], "Body")),
   686  		buflen(val((*args)[2], "Body")),
   687  	}
   688  	sort.Ints(parts)
   689  
   690  	if e, a := []int{1024 * 1024 * 5, 1024 * 1024 * 5}, parts; !reflect.DeepEqual(e, a) {
   691  		t.Errorf("Expected %v, but receievd %v", e, a)
   692  	}
   693  }
   694  
   695  func TestUploadOrderMultiBufferedReaderExceedTotalParts(t *testing.T) {
   696  	s, ops, _ := loggingSvc([]string{"UploadPart"})
   697  	mgr := s3manager.NewUploaderWithClient(s, func(u *s3manager.Uploader) {
   698  		u.Concurrency = 1
   699  		u.MaxUploadParts = 2
   700  	})
   701  	resp, err := mgr.Upload(&s3manager.UploadInput{
   702  		Bucket: aws.String("Bucket"),
   703  		Key:    aws.String("Key"),
   704  		Body:   &sizedReader{size: 1024 * 1024 * 12},
   705  	})
   706  
   707  	if err == nil {
   708  		t.Error("Expected an error, but received nil")
   709  	}
   710  
   711  	if resp != nil {
   712  		t.Errorf("Expected nil, but receievd %v", resp)
   713  	}
   714  
   715  	if e, a := []string{"CreateMultipartUpload", "AbortMultipartUpload"}, *ops; !reflect.DeepEqual(e, a) {
   716  		t.Errorf("Expected %v, but receievd %v", e, a)
   717  	}
   718  
   719  	aerr := err.(awserr.Error)
   720  	if e, a := "MultipartUpload", aerr.Code(); e != a {
   721  		t.Errorf("Expected %q, but received %q", e, a)
   722  	}
   723  
   724  	if e, a := "TotalPartsExceeded", aerr.OrigErr().(awserr.Error).Code(); e != a {
   725  		t.Errorf("Expected %q, but received %q", e, a)
   726  	}
   727  
   728  	if !strings.Contains(aerr.Error(), "configured MaxUploadParts (2)") {
   729  		t.Errorf("Expected error to contain 'configured MaxUploadParts (2)', but receievd %q", aerr.Error())
   730  	}
   731  }
   732  
   733  func TestUploadOrderSingleBufferedReader(t *testing.T) {
   734  	s, ops, _ := loggingSvc(emptyList)
   735  	mgr := s3manager.NewUploaderWithClient(s)
   736  	resp, err := mgr.Upload(&s3manager.UploadInput{
   737  		Bucket: aws.String("Bucket"),
   738  		Key:    aws.String("Key"),
   739  		Body:   &sizedReader{size: 1024 * 1024 * 2},
   740  	})
   741  
   742  	if err != nil {
   743  		t.Errorf("Expected no error but received %v", err)
   744  	}
   745  
   746  	if e, a := []string{"PutObject"}, *ops; !reflect.DeepEqual(e, a) {
   747  		t.Errorf("Expected %v, but received %v", e, a)
   748  	}
   749  
   750  	if len(resp.Location) == 0 {
   751  		t.Error("Expected a value in Location but received empty string")
   752  	}
   753  
   754  	if len(resp.UploadID) > 0 {
   755  		t.Errorf("Expected empty string but received %q", resp.UploadID)
   756  	}
   757  }
   758  
   759  func TestUploadZeroLenObject(t *testing.T) {
   760  	requestMade := false
   761  	server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
   762  		requestMade = true
   763  		w.WriteHeader(http.StatusOK)
   764  	}))
   765  	defer server.Close()
   766  	mgr := s3manager.NewUploaderWithClient(s3.New(unit.Session, &aws.Config{
   767  		Endpoint: aws.String(server.URL),
   768  	}))
   769  	resp, err := mgr.Upload(&s3manager.UploadInput{
   770  		Bucket: aws.String("Bucket"),
   771  		Key:    aws.String("Key"),
   772  		Body:   strings.NewReader(""),
   773  	})
   774  
   775  	if err != nil {
   776  		t.Errorf("Expected no error but received %v", err)
   777  	}
   778  	if !requestMade {
   779  		t.Error("Expected request to have been made, but was not")
   780  	}
   781  
   782  	if len(resp.Location) == 0 {
   783  		t.Error("Expected a non-empty string value for Location")
   784  	}
   785  
   786  	if len(resp.UploadID) > 0 {
   787  		t.Errorf("Expected empty string, but received %q", resp.UploadID)
   788  	}
   789  }
   790  
   791  func TestUploadInputS3PutObjectInputPairity(t *testing.T) {
   792  	matchings := compareStructType(reflect.TypeOf(s3.PutObjectInput{}),
   793  		reflect.TypeOf(s3manager.UploadInput{}))
   794  	aOnly := []string{}
   795  	bOnly := []string{}
   796  
   797  	for k, c := range matchings {
   798  		if c == 1 && k != "ContentLength" {
   799  			aOnly = append(aOnly, k)
   800  		} else if c == 2 {
   801  			bOnly = append(bOnly, k)
   802  		}
   803  	}
   804  
   805  	if len(aOnly) > 0 {
   806  		t.Errorf("Expected empty array, but received %v", aOnly)
   807  	}
   808  
   809  	if len(bOnly) > 0 {
   810  		t.Errorf("Expected empty array, but received %v", bOnly)
   811  	}
   812  }
   813  
   814  type testIncompleteReader struct {
   815  	Size int64
   816  	read int64
   817  }
   818  
   819  func (r *testIncompleteReader) Read(p []byte) (n int, err error) {
   820  	r.read += int64(len(p))
   821  	if r.read >= r.Size {
   822  		return int(r.read - r.Size), io.ErrUnexpectedEOF
   823  	}
   824  	return len(p), nil
   825  }
   826  
   827  func TestUploadUnexpectedEOF(t *testing.T) {
   828  	s, ops, _ := loggingSvc(emptyList)
   829  	mgr := s3manager.NewUploaderWithClient(s, func(u *s3manager.Uploader) {
   830  		u.Concurrency = 1
   831  		u.PartSize = s3manager.MinUploadPartSize
   832  	})
   833  	_, err := mgr.Upload(&s3manager.UploadInput{
   834  		Bucket: aws.String("Bucket"),
   835  		Key:    aws.String("Key"),
   836  		Body: &testIncompleteReader{
   837  			Size: int64(s3manager.MinUploadPartSize + 1),
   838  		},
   839  	})
   840  	if err == nil {
   841  		t.Error("Expected error, but received none")
   842  	}
   843  
   844  	// Ensure upload started.
   845  	if e, a := "CreateMultipartUpload", (*ops)[0]; e != a {
   846  		t.Errorf("Expected %q, but received %q", e, a)
   847  	}
   848  
   849  	// Part may or may not be sent because of timing of sending parts and
   850  	// reading next part in upload manager. Just check for the last abort.
   851  	if e, a := "AbortMultipartUpload", (*ops)[len(*ops)-1]; e != a {
   852  		t.Errorf("Expected %q, but received %q", e, a)
   853  	}
   854  }
   855  
   856  func compareStructType(a, b reflect.Type) map[string]int {
   857  	if a.Kind() != reflect.Struct || b.Kind() != reflect.Struct {
   858  		panic(fmt.Sprintf("types must both be structs, got %v and %v", a.Kind(), b.Kind()))
   859  	}
   860  
   861  	aFields := enumFields(a)
   862  	bFields := enumFields(b)
   863  
   864  	matchings := map[string]int{}
   865  
   866  	for i := 0; i < len(aFields) || i < len(bFields); i++ {
   867  		if i < len(aFields) {
   868  			c := matchings[aFields[i].Name]
   869  			matchings[aFields[i].Name] = c + 1
   870  		}
   871  		if i < len(bFields) {
   872  			c := matchings[bFields[i].Name]
   873  			matchings[bFields[i].Name] = c + 2
   874  		}
   875  	}
   876  
   877  	return matchings
   878  }
   879  
   880  func enumFields(v reflect.Type) []reflect.StructField {
   881  	fields := []reflect.StructField{}
   882  
   883  	for i := 0; i < v.NumField(); i++ {
   884  		field := v.Field(i)
   885  		// Ignoreing anon fields
   886  		if field.PkgPath != "" {
   887  			// Ignore unexported fields
   888  			continue
   889  		}
   890  
   891  		fields = append(fields, field)
   892  	}
   893  
   894  	return fields
   895  }
   896  
   897  type fooReaderAt struct{}
   898  
   899  func (r *fooReaderAt) Read(p []byte) (n int, err error) {
   900  	return 12, io.EOF
   901  }
   902  
   903  func (r *fooReaderAt) ReadAt(p []byte, off int64) (n int, err error) {
   904  	return 12, io.EOF
   905  }
   906  
   907  func TestReaderAt(t *testing.T) {
   908  	svc := s3.New(unit.Session)
   909  	svc.Handlers.Unmarshal.Clear()
   910  	svc.Handlers.UnmarshalMeta.Clear()
   911  	svc.Handlers.UnmarshalError.Clear()
   912  	svc.Handlers.Send.Clear()
   913  
   914  	contentLen := ""
   915  	svc.Handlers.Send.PushBack(func(r *request.Request) {
   916  		contentLen = r.HTTPRequest.Header.Get("Content-Length")
   917  		r.HTTPResponse = &http.Response{
   918  			StatusCode: 200,
   919  			Body:       ioutil.NopCloser(bytes.NewReader([]byte{})),
   920  		}
   921  	})
   922  
   923  	mgr := s3manager.NewUploaderWithClient(svc, func(u *s3manager.Uploader) {
   924  		u.Concurrency = 1
   925  	})
   926  
   927  	_, err := mgr.Upload(&s3manager.UploadInput{
   928  		Bucket: aws.String("Bucket"),
   929  		Key:    aws.String("Key"),
   930  		Body:   &fooReaderAt{},
   931  	})
   932  
   933  	if err != nil {
   934  		t.Errorf("Expected no error but received %v", err)
   935  	}
   936  
   937  	if e, a := "12", contentLen; e != a {
   938  		t.Errorf("Expected %q, but received %q", e, a)
   939  	}
   940  }
   941  
   942  func TestSSE(t *testing.T) {
   943  	svc := s3.New(unit.Session)
   944  	svc.Handlers.Unmarshal.Clear()
   945  	svc.Handlers.UnmarshalMeta.Clear()
   946  	svc.Handlers.UnmarshalError.Clear()
   947  	svc.Handlers.ValidateResponse.Clear()
   948  	svc.Handlers.Send.Clear()
   949  	partNum := 0
   950  	mutex := &sync.Mutex{}
   951  
   952  	svc.Handlers.Send.PushBack(func(r *request.Request) {
   953  		mutex.Lock()
   954  		defer mutex.Unlock()
   955  		r.HTTPResponse = &http.Response{
   956  			StatusCode: 200,
   957  			Body:       ioutil.NopCloser(bytes.NewReader([]byte(respMsg))),
   958  		}
   959  		switch data := r.Data.(type) {
   960  		case *s3.CreateMultipartUploadOutput:
   961  			data.UploadId = aws.String("UPLOAD-ID")
   962  		case *s3.UploadPartOutput:
   963  			input := r.Params.(*s3.UploadPartInput)
   964  			if input.SSECustomerAlgorithm == nil {
   965  				t.Fatal("SSECustomerAlgoritm should not be nil")
   966  			}
   967  			if input.SSECustomerKey == nil {
   968  				t.Fatal("SSECustomerKey should not be nil")
   969  			}
   970  			partNum++
   971  			data.ETag = aws.String(fmt.Sprintf("ETAG%d", partNum))
   972  		case *s3.CompleteMultipartUploadOutput:
   973  			data.Location = aws.String("https://location")
   974  			data.VersionId = aws.String("VERSION-ID")
   975  		case *s3.PutObjectOutput:
   976  			data.VersionId = aws.String("VERSION-ID")
   977  		}
   978  
   979  	})
   980  
   981  	mgr := s3manager.NewUploaderWithClient(svc, func(u *s3manager.Uploader) {
   982  		u.Concurrency = 5
   983  	})
   984  
   985  	_, err := mgr.Upload(&s3manager.UploadInput{
   986  		Bucket:               aws.String("Bucket"),
   987  		Key:                  aws.String("Key"),
   988  		SSECustomerAlgorithm: aws.String("AES256"),
   989  		SSECustomerKey:       aws.String("foo"),
   990  		Body:                 bytes.NewBuffer(make([]byte, 1024*1024*10)),
   991  	})
   992  
   993  	if err != nil {
   994  		t.Fatal("Expected no error, but received" + err.Error())
   995  	}
   996  }
   997  
   998  func TestUploadWithContextCanceled(t *testing.T) {
   999  	u := s3manager.NewUploader(unit.Session)
  1000  
  1001  	params := s3manager.UploadInput{
  1002  		Bucket: aws.String("Bucket"),
  1003  		Key:    aws.String("Key"),
  1004  		Body:   bytes.NewReader(make([]byte, 0)),
  1005  	}
  1006  
  1007  	ctx := &awstesting.FakeContext{DoneCh: make(chan struct{})}
  1008  	ctx.Error = fmt.Errorf("context canceled")
  1009  	close(ctx.DoneCh)
  1010  
  1011  	_, err := u.UploadWithContext(ctx, &params)
  1012  	if err == nil {
  1013  		t.Fatalf("expected error, did not get one")
  1014  	}
  1015  	aerr := err.(awserr.Error)
  1016  	if e, a := request.CanceledErrorCode, aerr.Code(); e != a {
  1017  		t.Errorf("expected error code %q, got %q", e, a)
  1018  	}
  1019  	if e, a := "canceled", aerr.Message(); !strings.Contains(a, e) {
  1020  		t.Errorf("expected error message to contain %q, but did not %q", e, a)
  1021  	}
  1022  }
  1023  
  1024  // S3 Uploader incorrectly fails an upload if the content being uploaded
  1025  // has a size of MinPartSize * MaxUploadParts.
  1026  // Github:  aws/aws-sdk-go#2557
  1027  func TestUploadMaxPartsEOF(t *testing.T) {
  1028  	s, ops, _ := loggingSvc(emptyList)
  1029  	mgr := s3manager.NewUploaderWithClient(s, func(u *s3manager.Uploader) {
  1030  		u.Concurrency = 1
  1031  		u.PartSize = s3manager.DefaultUploadPartSize
  1032  		u.MaxUploadParts = 2
  1033  	})
  1034  	f := bytes.NewReader(make([]byte, int(mgr.PartSize)*mgr.MaxUploadParts))
  1035  
  1036  	r1 := io.NewSectionReader(f, 0, s3manager.DefaultUploadPartSize)
  1037  	r2 := io.NewSectionReader(f, s3manager.DefaultUploadPartSize, 2*s3manager.DefaultUploadPartSize)
  1038  	body := io.MultiReader(r1, r2)
  1039  
  1040  	_, err := mgr.Upload(&s3manager.UploadInput{
  1041  		Bucket: aws.String("Bucket"),
  1042  		Key:    aws.String("Key"),
  1043  		Body:   body,
  1044  	})
  1045  
  1046  	if err != nil {
  1047  		t.Fatalf("expect no error, got %v", err)
  1048  	}
  1049  
  1050  	expectOps := []string{
  1051  		"CreateMultipartUpload",
  1052  		"UploadPart",
  1053  		"UploadPart",
  1054  		"CompleteMultipartUpload",
  1055  	}
  1056  	if e, a := expectOps, *ops; !reflect.DeepEqual(e, a) {
  1057  		t.Errorf("expect %v ops, got %v", e, a)
  1058  	}
  1059  }
  1060  
  1061  func createTempFile(t *testing.T, size int64) (*os.File, func(*testing.T), error) {
  1062  	file, err := ioutil.TempFile(os.TempDir(), aws.SDKName+t.Name())
  1063  	if err != nil {
  1064  		return nil, nil, err
  1065  	}
  1066  	filename := file.Name()
  1067  	if err := file.Truncate(size); err != nil {
  1068  		return nil, nil, err
  1069  	}
  1070  
  1071  	return file,
  1072  		func(t *testing.T) {
  1073  			if err := file.Close(); err != nil {
  1074  				t.Errorf("failed to close temp file, %s, %v", filename, err)
  1075  			}
  1076  			if err := os.Remove(filename); err != nil {
  1077  				t.Errorf("failed to remove temp file, %s, %v", filename, err)
  1078  			}
  1079  		},
  1080  		nil
  1081  }
  1082  
  1083  func buildFailHandlers(tb testing.TB, parts, retry int) []http.Handler {
  1084  	handlers := make([]http.Handler, parts)
  1085  	for i := 0; i < len(handlers); i++ {
  1086  		handlers[i] = &failPartHandler{
  1087  			tb:             tb,
  1088  			failsRemaining: retry,
  1089  			successHandler: successPartHandler{tb: tb},
  1090  		}
  1091  	}
  1092  
  1093  	return handlers
  1094  }
  1095  
  1096  func TestUploadRetry(t *testing.T) {
  1097  	const numParts, retries = 3, 10
  1098  
  1099  	testFile, testFileCleanup, err := createTempFile(t, s3manager.DefaultUploadPartSize*numParts)
  1100  	if err != nil {
  1101  		t.Fatalf("failed to create test file, %v", err)
  1102  	}
  1103  	defer testFileCleanup(t)
  1104  
  1105  	cases := map[string]struct {
  1106  		Body         io.Reader
  1107  		PartHandlers func(testing.TB) []http.Handler
  1108  	}{
  1109  		"bytes.Buffer": {
  1110  			Body: bytes.NewBuffer(make([]byte, s3manager.DefaultUploadPartSize*numParts)),
  1111  			PartHandlers: func(tb testing.TB) []http.Handler {
  1112  				return buildFailHandlers(tb, numParts, retries)
  1113  			},
  1114  		},
  1115  		"bytes.Reader": {
  1116  			Body: bytes.NewReader(make([]byte, s3manager.DefaultUploadPartSize*numParts)),
  1117  			PartHandlers: func(tb testing.TB) []http.Handler {
  1118  				return buildFailHandlers(tb, numParts, retries)
  1119  			},
  1120  		},
  1121  		"os.File": {
  1122  			Body: testFile,
  1123  			PartHandlers: func(tb testing.TB) []http.Handler {
  1124  				return buildFailHandlers(tb, numParts, retries)
  1125  			},
  1126  		},
  1127  	}
  1128  
  1129  	for name, c := range cases {
  1130  		t.Run(name, func(t *testing.T) {
  1131  			mux := newMockS3UploadServer(t, c.PartHandlers(t))
  1132  			server := httptest.NewServer(mux)
  1133  			defer server.Close()
  1134  
  1135  			var logger aws.Logger
  1136  			var logLevel *aws.LogLevelType
  1137  			if v := os.Getenv("DEBUG_BODY"); len(v) != 0 {
  1138  				logger = t
  1139  				logLevel = aws.LogLevel(
  1140  					aws.LogDebugWithRequestErrors | aws.LogDebugWithRequestRetries,
  1141  				)
  1142  			}
  1143  			sess := unit.Session.Copy(&aws.Config{
  1144  				Endpoint:         aws.String(server.URL),
  1145  				S3ForcePathStyle: aws.Bool(true),
  1146  				DisableSSL:       aws.Bool(true),
  1147  				MaxRetries:       aws.Int(retries + 1),
  1148  				SleepDelay:       func(time.Duration) {},
  1149  
  1150  				Logger:   logger,
  1151  				LogLevel: logLevel,
  1152  				//Credentials: credentials.AnonymousCredentials,
  1153  			})
  1154  
  1155  			uploader := s3manager.NewUploader(sess, func(u *s3manager.Uploader) {
  1156  				//				u.Concurrency = 1
  1157  			})
  1158  			_, err := uploader.Upload(&s3manager.UploadInput{
  1159  				Bucket: aws.String("bucket"),
  1160  				Key:    aws.String("key"),
  1161  				Body:   c.Body,
  1162  			})
  1163  
  1164  			if err != nil {
  1165  				t.Fatalf("expect no error, got %v", err)
  1166  			}
  1167  		})
  1168  	}
  1169  }
  1170  
  1171  func TestUploadBufferStrategy(t *testing.T) {
  1172  	cases := map[string]struct {
  1173  		PartSize  int64
  1174  		Size      int64
  1175  		Strategy  s3manager.ReadSeekerWriteToProvider
  1176  		callbacks int
  1177  	}{
  1178  		"NoBuffer": {
  1179  			PartSize: s3manager.DefaultUploadPartSize,
  1180  			Strategy: nil,
  1181  		},
  1182  		"SinglePart": {
  1183  			PartSize:  s3manager.DefaultUploadPartSize,
  1184  			Size:      s3manager.DefaultUploadPartSize,
  1185  			Strategy:  &recordedBufferProvider{size: int(s3manager.DefaultUploadPartSize)},
  1186  			callbacks: 1,
  1187  		},
  1188  		"MultiPart": {
  1189  			PartSize:  s3manager.DefaultUploadPartSize,
  1190  			Size:      s3manager.DefaultUploadPartSize * 2,
  1191  			Strategy:  &recordedBufferProvider{size: int(s3manager.DefaultUploadPartSize)},
  1192  			callbacks: 2,
  1193  		},
  1194  	}
  1195  
  1196  	for name, tCase := range cases {
  1197  		t.Run(name, func(t *testing.T) {
  1198  			_ = tCase
  1199  			sess := unit.Session.Copy()
  1200  			svc := s3.New(sess)
  1201  			svc.Handlers.Unmarshal.Clear()
  1202  			svc.Handlers.UnmarshalMeta.Clear()
  1203  			svc.Handlers.UnmarshalError.Clear()
  1204  			svc.Handlers.Send.Clear()
  1205  			svc.Handlers.Send.PushBack(func(r *request.Request) {
  1206  				if r.Body != nil {
  1207  					io.Copy(ioutil.Discard, r.Body)
  1208  				}
  1209  
  1210  				r.HTTPResponse = &http.Response{
  1211  					StatusCode: 200,
  1212  					Body:       ioutil.NopCloser(bytes.NewReader([]byte(respMsg))),
  1213  				}
  1214  
  1215  				switch data := r.Data.(type) {
  1216  				case *s3.CreateMultipartUploadOutput:
  1217  					data.UploadId = aws.String("UPLOAD-ID")
  1218  				case *s3.UploadPartOutput:
  1219  					data.ETag = aws.String(fmt.Sprintf("ETAG%d", random.Int()))
  1220  				case *s3.CompleteMultipartUploadOutput:
  1221  					data.Location = aws.String("https://location")
  1222  					data.VersionId = aws.String("VERSION-ID")
  1223  				case *s3.PutObjectOutput:
  1224  					data.VersionId = aws.String("VERSION-ID")
  1225  				}
  1226  			})
  1227  
  1228  			uploader := s3manager.NewUploaderWithClient(svc, func(u *s3manager.Uploader) {
  1229  				u.PartSize = tCase.PartSize
  1230  				u.BufferProvider = tCase.Strategy
  1231  				u.Concurrency = 1
  1232  			})
  1233  
  1234  			expected := s3testing.GetTestBytes(int(tCase.Size))
  1235  			_, err := uploader.Upload(&s3manager.UploadInput{
  1236  				Bucket: aws.String("bucket"),
  1237  				Key:    aws.String("key"),
  1238  				Body:   bytes.NewReader(expected),
  1239  			})
  1240  			if err != nil {
  1241  				t.Fatalf("failed to upload file: %v", err)
  1242  			}
  1243  
  1244  			switch strat := tCase.Strategy.(type) {
  1245  			case *recordedBufferProvider:
  1246  				if !bytes.Equal(expected, strat.content) {
  1247  					t.Errorf("content buffered did not match expected")
  1248  				}
  1249  				if tCase.callbacks != strat.callbackCount {
  1250  					t.Errorf("expected %v, got %v callbacks", tCase.callbacks, strat.callbackCount)
  1251  				}
  1252  			}
  1253  		})
  1254  	}
  1255  }
  1256  
  1257  func TestUploaderValidARN(t *testing.T) {
  1258  	cases := map[string]struct {
  1259  		input   s3manager.UploadInput
  1260  		wantErr bool
  1261  	}{
  1262  		"standard bucket": {
  1263  			input: s3manager.UploadInput{
  1264  				Bucket: aws.String("test-bucket"),
  1265  				Key:    aws.String("test-key"),
  1266  				Body:   bytes.NewReader([]byte("test body content")),
  1267  			},
  1268  		},
  1269  		"accesspoint": {
  1270  			input: s3manager.UploadInput{
  1271  				Bucket: aws.String("arn:aws:s3:us-west-2:123456789012:accesspoint/myap"),
  1272  				Key:    aws.String("test-key"),
  1273  				Body:   bytes.NewReader([]byte("test body content")),
  1274  			},
  1275  		},
  1276  		"outpost accesspoint": {
  1277  			input: s3manager.UploadInput{
  1278  				Bucket: aws.String("arn:aws:s3-outposts:us-west-2:012345678901:outpost/op-1234567890123456/accesspoint/myaccesspoint"),
  1279  				Key:    aws.String("test-key"),
  1280  				Body:   bytes.NewReader([]byte("test body content")),
  1281  			},
  1282  		},
  1283  		"s3-object-lambda accesspoint": {
  1284  			input: s3manager.UploadInput{
  1285  				Bucket: aws.String("arn:aws:s3-object-lambda:us-west-2:123456789012:accesspoint/myap"),
  1286  				Key:    aws.String("test-key"),
  1287  				Body:   bytes.NewReader([]byte("test body content")),
  1288  			},
  1289  			wantErr: true,
  1290  		},
  1291  	}
  1292  
  1293  	for name, tt := range cases {
  1294  		t.Run(name, func(t *testing.T) {
  1295  			client, _, _ := loggingSvc(nil)
  1296  			client.Config.Region = aws.String("us-west-2")
  1297  			client.ClientInfo.SigningRegion = "us-west-2"
  1298  
  1299  			uploader := s3manager.NewUploaderWithClient(client)
  1300  
  1301  			_, err := uploader.Upload(&tt.input)
  1302  			if (err != nil) != tt.wantErr {
  1303  				t.Errorf("err: %v, wantErr: %v", err, tt.wantErr)
  1304  			}
  1305  		})
  1306  	}
  1307  }
  1308  
  1309  type mockS3UploadServer struct {
  1310  	*http.ServeMux
  1311  
  1312  	tb          testing.TB
  1313  	partHandler []http.Handler
  1314  }
  1315  
  1316  func newMockS3UploadServer(tb testing.TB, partHandler []http.Handler) *mockS3UploadServer {
  1317  	s := &mockS3UploadServer{
  1318  		ServeMux:    http.NewServeMux(),
  1319  		partHandler: partHandler,
  1320  		tb:          tb,
  1321  	}
  1322  
  1323  	s.HandleFunc("/", s.handleRequest)
  1324  
  1325  	return s
  1326  }
  1327  
  1328  func (s mockS3UploadServer) handleRequest(w http.ResponseWriter, r *http.Request) {
  1329  	defer r.Body.Close()
  1330  
  1331  	_, hasUploads := r.URL.Query()["uploads"]
  1332  
  1333  	switch {
  1334  	case r.Method == "POST" && hasUploads:
  1335  		// CreateMultipartUpload
  1336  		w.Header().Set("Content-Length", strconv.Itoa(len(createUploadResp)))
  1337  		w.Write([]byte(createUploadResp))
  1338  
  1339  	case r.Method == "PUT":
  1340  		// UploadPart
  1341  		partNumStr := r.URL.Query().Get("partNumber")
  1342  		id, err := strconv.Atoi(partNumStr)
  1343  		if err != nil {
  1344  			failRequest(w, 400, "BadRequest",
  1345  				fmt.Sprintf("unable to parse partNumber, %q, %v",
  1346  					partNumStr, err))
  1347  			return
  1348  		}
  1349  		id--
  1350  		if id < 0 || id >= len(s.partHandler) {
  1351  			failRequest(w, 400, "BadRequest",
  1352  				fmt.Sprintf("invalid partNumber %v", id))
  1353  			return
  1354  		}
  1355  		s.partHandler[id].ServeHTTP(w, r)
  1356  
  1357  	case r.Method == "POST":
  1358  		// CompleteMultipartUpload
  1359  		w.Header().Set("Content-Length", strconv.Itoa(len(completeUploadResp)))
  1360  		w.Write([]byte(completeUploadResp))
  1361  
  1362  	case r.Method == "DELETE":
  1363  		// AbortMultipartUpload
  1364  		w.Header().Set("Content-Length", strconv.Itoa(len(abortUploadResp)))
  1365  		w.WriteHeader(200)
  1366  		w.Write([]byte(abortUploadResp))
  1367  
  1368  	default:
  1369  		failRequest(w, 400, "BadRequest",
  1370  			fmt.Sprintf("invalid request %v %v", r.Method, r.URL))
  1371  	}
  1372  }
  1373  
  1374  func failRequest(w http.ResponseWriter, status int, code, msg string) {
  1375  	msg = fmt.Sprintf(baseRequestErrorResp, code, msg)
  1376  	w.Header().Set("Content-Length", strconv.Itoa(len(msg)))
  1377  	w.WriteHeader(status)
  1378  	w.Write([]byte(msg))
  1379  }
  1380  
  1381  type successPartHandler struct {
  1382  	tb testing.TB
  1383  }
  1384  
  1385  func (h successPartHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
  1386  	defer r.Body.Close()
  1387  
  1388  	n, err := io.Copy(ioutil.Discard, r.Body)
  1389  	if err != nil {
  1390  		failRequest(w, 400, "BadRequest",
  1391  			fmt.Sprintf("failed to read body, %v", err))
  1392  		return
  1393  	}
  1394  
  1395  	contLenStr := r.Header.Get("Content-Length")
  1396  	expectLen, err := strconv.ParseInt(contLenStr, 10, 64)
  1397  	if err != nil {
  1398  		h.tb.Logf("expect content-length, got %q, %v", contLenStr, err)
  1399  		failRequest(w, 400, "BadRequest",
  1400  			fmt.Sprintf("unable to get content-length %v", err))
  1401  		return
  1402  	}
  1403  	if e, a := expectLen, n; e != a {
  1404  		h.tb.Logf("expect %v read, got %v", e, a)
  1405  		failRequest(w, 400, "BadRequest",
  1406  			fmt.Sprintf(
  1407  				"content-length and body do not match, %v, %v", e, a))
  1408  		return
  1409  	}
  1410  
  1411  	w.Header().Set("Content-Length", strconv.Itoa(len(uploadPartResp)))
  1412  	w.Write([]byte(uploadPartResp))
  1413  }
  1414  
  1415  type failPartHandler struct {
  1416  	tb testing.TB
  1417  
  1418  	failsRemaining int
  1419  	successHandler http.Handler
  1420  }
  1421  
  1422  func (h *failPartHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
  1423  	defer r.Body.Close()
  1424  
  1425  	if h.failsRemaining == 0 && h.successHandler != nil {
  1426  		h.successHandler.ServeHTTP(w, r)
  1427  		return
  1428  	}
  1429  
  1430  	io.Copy(ioutil.Discard, r.Body)
  1431  
  1432  	failRequest(w, 500, "InternalException",
  1433  		fmt.Sprintf("mock error, partNumber %v", r.URL.Query().Get("partNumber")))
  1434  
  1435  	h.failsRemaining--
  1436  }
  1437  
  1438  type recordedBufferProvider struct {
  1439  	content       []byte
  1440  	size          int
  1441  	callbackCount int
  1442  }
  1443  
  1444  func (r *recordedBufferProvider) GetWriteTo(seeker io.ReadSeeker) (s3manager.ReadSeekerWriteTo, func()) {
  1445  	b := make([]byte, r.size)
  1446  	w := &s3manager.BufferedReadSeekerWriteTo{BufferedReadSeeker: s3manager.NewBufferedReadSeeker(seeker, b)}
  1447  
  1448  	return w, func() {
  1449  		r.content = append(r.content, b...)
  1450  		r.callbackCount++
  1451  	}
  1452  }
  1453  
  1454  const createUploadResp = `
  1455  <CreateMultipartUploadResponse>
  1456    <Bucket>bucket</Bucket>
  1457    <Key>key</Key>
  1458    <UploadId>abc123</UploadId>
  1459  </CreateMultipartUploadResponse>
  1460  `
  1461  const uploadPartResp = `
  1462  <UploadPartResponse>
  1463    <ETag>key</ETag>
  1464  </UploadPartResponse>
  1465  `
  1466  const baseRequestErrorResp = `
  1467  <Error>
  1468    <Code>%s</Code>
  1469    <Message>%s</Message>
  1470    <RequestId>request-id</RequestId>
  1471    <HostId>host-id</HostId>
  1472  </Error>
  1473  `
  1474  const completeUploadResp = `
  1475  <CompleteMultipartUploadResponse>
  1476    <Bucket>bucket</Bucket>
  1477    <Key>key</Key>
  1478    <ETag>key</ETag>
  1479    <Location>https://bucket.us-west-2.amazonaws.com/key</Location>
  1480    <UploadId>abc123</UploadId>
  1481  </CompleteMultipartUploadResponse>
  1482  `
  1483  
  1484  const abortUploadResp = `
  1485  <AbortMultipartUploadResponse>
  1486  </AbortMultipartUploadResponse>
  1487  `