package storage import ( "context" "errors" "testing" ) type listedParts struct { MultipartStore parts []Part calls int loop bool } func (s *listedParts) ListParts(ctx context.Context, u MultipartUpload, marker, limit int) (PartsPage, error) { s.calls++ if s.loop { return PartsPage{Parts: []Part{{Number: 1, ETag: "a", Size: 5 << 20}}, NextMarker: marker}, nil } end := min(marker+limit, len(s.parts)) next := 0 if end < len(s.parts) { next = end } return PartsPage{Parts: s.parts[marker:end], NextMarker: next}, nil } func TestVerifyPartsUsesProviderSizes(t *testing.T) { upload := MultipartUpload{Key: "file", UploadID: "id"} first := Part{Number: 1, ETag: "a", Size: 5 << 20} last := Part{Number: 2, ETag: "b", Size: 3} supplied := []Part{{Number: 1, ETag: "a", Size: 1}, {Number: 2, ETag: "b", Size: 1}} s := &listedParts{parts: []Part{first, last}} n, err := VerifyParts(context.Background(), s, upload, supplied, 6<<20) if err != nil || n != (5<<20)+3 { t.Fatal(n, err) } if _, err = VerifyParts(context.Background(), s, upload, supplied, 5<<20); !errors.Is(err, ErrTooLarge) { t.Fatal(err) } for _, parts := range [][]Part{nil, {last, first}, {first, first}, {{Number: 1, ETag: "changed"}, last}, {first}} { if _, err := VerifyParts(context.Background(), s, upload, parts, 6<<20); err == nil { t.Fatal("bad completion accepted", parts) } } s.parts[0].Size = 1 if _, err = VerifyParts(context.Background(), s, upload, supplied, 6<<20); err == nil { t.Fatal("small non-final part accepted") } } func TestVerifyPartsPagination(t *testing.T) { s := &listedParts{} for i := 1; i <= 1001; i++ { s.parts = append(s.parts, Part{Number: i, ETag: "etag", Size: 5 << 20}) } n, err := VerifyParts(context.Background(), s, MultipartUpload{Key: "file", UploadID: "id"}, s.parts, 10<<30) if err != nil || s.calls != 2 || n != 1001*(5<<20) { t.Fatal(n, s.calls, err) } }