diff options
| author | Sandro Jäckel <sandro.jaeckel@gmail.com> | 2024-07-01 16:12:52 +0200 |
|---|---|---|
| committer | Sandro Jäckel <sandro.jaeckel@gmail.com> | 2024-07-01 16:12:52 +0200 |
| commit | b7683ab8dcdeca10ff52d626a285edcf7c1db719 (patch) | |
| tree | fcf486f49df855f2803981c753ed775b1305f6c8 | |
| parent | 5a783c56a98c225569abfa6fb12fdf55297fee9e (diff) | |
| download | go-schwift-b7683ab8dcdeca10ff52d626a285edcf7c1db719.tar.gz | |
Remove context from struct, add ctx as first args to many functions
| -rw-r--r-- | account.go | 12 | ||||
| -rw-r--r-- | bulk.go | 21 | ||||
| -rw-r--r-- | container.go | 25 | ||||
| -rw-r--r-- | container_iterator.go | 25 | ||||
| -rw-r--r-- | iterator.go | 9 | ||||
| -rw-r--r-- | largeobject.go | 47 | ||||
| -rw-r--r-- | object.go | 55 | ||||
| -rw-r--r-- | object_iterator.go | 25 | ||||
| -rw-r--r-- | request.go | 9 | ||||
| -rw-r--r-- | tests/account_test.go | 15 | ||||
| -rw-r--r-- | tests/bulk_delete_test.go | 13 | ||||
| -rw-r--r-- | tests/bulk_upload_test.go | 4 | ||||
| -rw-r--r-- | tests/container_iterator_test.go | 39 | ||||
| -rw-r--r-- | tests/container_test.go | 21 | ||||
| -rw-r--r-- | tests/field_test.go | 7 | ||||
| -rw-r--r-- | tests/largeobject_test.go | 134 | ||||
| -rw-r--r-- | tests/object_iterator_test.go | 53 | ||||
| -rw-r--r-- | tests/object_test.go | 67 | ||||
| -rw-r--r-- | tests/shared_test.go | 10 |
19 files changed, 304 insertions, 287 deletions
@@ -98,7 +98,7 @@ func (a *Account) Backend() Backend { // // WARNING: This method is not thread-safe. Calling it concurrently on the same // object results in undefined behavior. -func (a *Account) Headers() (AccountHeaders, error) { +func (a *Account) Headers(ctx context.Context) (AccountHeaders, error) { if a.headers != nil { return *a.headers, nil } @@ -106,7 +106,7 @@ func (a *Account) Headers() (AccountHeaders, error) { resp, err := Request{ Method: "HEAD", ExpectStatusCodes: []int{204}, - }.Do(a.backend) + }.Do(ctx, a.backend) if err != nil { return AccountHeaders{}, err } @@ -134,12 +134,12 @@ func (a *Account) Invalidate() { // attribute take precedence over those in opts.Headers. // // A successful POST request implies Invalidate() since it may change metadata. -func (a *Account) Update(headers AccountHeaders, opts *RequestOptions) error { +func (a *Account) Update(ctx context.Context, headers AccountHeaders, opts *RequestOptions) error { resp, err := Request{ Method: "POST", Options: cloneRequestOptions(opts, headers.Headers), ExpectStatusCodes: []int{204}, - }.Do(a.backend) + }.Do(ctx, a.backend) if err == nil { a.Invalidate() resp.Body.Close() @@ -151,13 +151,13 @@ func (a *Account) Update(headers AccountHeaders, opts *RequestOptions) error { // available to reseller admins, not to regular users. // // A successful PUT request implies Invalidate() since it may change metadata. -func (a *Account) Create(opts *RequestOptions) error { +func (a *Account) Create(ctx context.Context, opts *RequestOptions) error { resp, err := Request{ Method: "PUT", Options: opts, ExpectStatusCodes: []int{201, 202}, DrainResponseBody: true, - }.Do(a.backend) + }.Do(ctx, a.backend) if err == nil { a.Invalidate() resp.Body.Close() @@ -19,6 +19,7 @@ package schwift import ( + "context" "encoding/json" "fmt" "io" @@ -65,7 +66,7 @@ const ( // // This operation returns (0, ErrNotSupported) if the server does not support // bulk-uploading. -func (a *Account) BulkUpload(uploadPath string, format BulkUploadFormat, contents io.Reader, opts *RequestOptions) (int, error) { +func (a *Account) BulkUpload(ctx context.Context, uploadPath string, format BulkUploadFormat, contents io.Reader, opts *RequestOptions) (int, error) { caps, err := a.Capabilities() if err != nil { return 0, err @@ -89,7 +90,7 @@ func (a *Account) BulkUpload(uploadPath string, format BulkUploadFormat, content req.ObjectName = fields[1] } - resp, err := req.Do(a.backend) //nolint:bodyclose // parseBulkResponse does the close + resp, err := req.Do(ctx, a.backend) //nolint:bodyclose // parseBulkResponse does the close if err != nil { return 0, err } @@ -143,7 +144,7 @@ func makeBulkObjectError(fullName string, statusCode int) BulkObjectError { // The objects may be located in multiple containers, but they and the // containers must all be located in the given account. (Otherwise, // ErrAccountMismatch is returned.) -func (a *Account) BulkDelete(objects []*Object, containers []*Container, opts *RequestOptions) (numDeleted, numNotFound int, deleteError error) { +func (a *Account) BulkDelete(ctx context.Context, objects []*Object, containers []*Container, opts *RequestOptions) (numDeleted, numNotFound int, deleteError error) { // validate that all given objects are in this account for _, obj := range objects { if !a.IsEqualTo(obj.Container().Account()) { @@ -162,7 +163,7 @@ func (a *Account) BulkDelete(objects []*Object, containers []*Container, opts *R return 0, 0, err } if caps.BulkDelete == nil || !capabilities.AllowBulkDelete { - return a.bulkDeleteSingle(objects, containers, opts) + return a.bulkDeleteSingle(ctx, objects, containers, opts) } chunkSize := int(caps.BulkDelete.MaximumDeletesPerRequest) @@ -190,7 +191,7 @@ func (a *Account) BulkDelete(objects []*Object, containers []*Container, opts *R chunk := names[0:chunkSize] names = names[chunkSize:] - numDeletedNow, numNotFoundNow, err := a.bulkDelete(chunk, opts) + numDeletedNow, numNotFoundNow, err := a.bulkDelete(ctx, chunk, opts) numDeleted += numDeletedNow numNotFound += numNotFoundNow if err != nil { @@ -203,7 +204,7 @@ func (a *Account) BulkDelete(objects []*Object, containers []*Container, opts *R // Implementation of BulkDelete() for servers that *do not* support bulk // deletion. -func (a *Account) bulkDeleteSingle(objects []*Object, containers []*Container, opts *RequestOptions) (numDeleted, numNotFound int, err error) { +func (a *Account) bulkDeleteSingle(ctx context.Context, objects []*Object, containers []*Container, opts *RequestOptions) (numDeleted, numNotFound int, err error) { var errs []BulkObjectError handleSingleError := func(containerName, objectName string, err error) error { @@ -228,7 +229,7 @@ func (a *Account) bulkDeleteSingle(objects []*Object, containers []*Container, o } for _, obj := range objects { - err := obj.Delete(nil, opts) // this implies Invalidate() + err := obj.Delete(ctx, nil, opts) // this implies Invalidate() err = handleSingleError(obj.Container().Name(), obj.Name(), err) if err != nil { return numDeleted, numNotFound, err @@ -236,7 +237,7 @@ func (a *Account) bulkDeleteSingle(objects []*Object, containers []*Container, o } for _, container := range containers { - err := container.Delete(opts) // this implies Invalidate() + err := container.Delete(ctx, opts) // this implies Invalidate() err = handleSingleError(container.Name(), "", err) if err != nil { return numDeleted, numNotFound, err @@ -256,7 +257,7 @@ func (a *Account) bulkDeleteSingle(objects []*Object, containers []*Container, o // Implementation of BulkDelete() for servers that *do* support bulk deletion. // This function is called *after* chunking, so `len(names) <= // account.Capabilities.BulkDelete.MaximumDeletesPerRequest`. -func (a *Account) bulkDelete(names []string, opts *RequestOptions) (numDeleted, numNotFound int, err error) { +func (a *Account) bulkDelete(ctx context.Context, names []string, opts *RequestOptions) (numDeleted, numNotFound int, err error) { req := Request{ Method: "DELETE", Body: strings.NewReader(strings.Join(names, "\n") + "\n"), @@ -266,7 +267,7 @@ func (a *Account) bulkDelete(names []string, opts *RequestOptions) (numDeleted, req.Options.Headers.Set("Accept", "application/json") req.Options.Headers.Set("Content-Type", "text/plain") req.Options.Values.Set("bulk-delete", "true") - resp, err := req.Do(a.backend) //nolint:bodyclose // parseBulkResponse does the close + resp, err := req.Do(ctx, a.backend) //nolint:bodyclose // parseBulkResponse does the close if err != nil { return 0, 0, err } diff --git a/container.go b/container.go index e5c57f3..7ddd415 100644 --- a/container.go +++ b/container.go @@ -19,6 +19,7 @@ package schwift import ( + "context" "net/http" ) @@ -60,8 +61,8 @@ func (c *Container) Name() string { // Exists checks if this container exists, potentially by issuing a HEAD request // if no Headers() have been cached yet. -func (c *Container) Exists() (bool, error) { - _, err := c.Headers() +func (c *Container) Exists(ctx context.Context) (bool, error) { + _, err := c.Headers(ctx) if Is(err, http.StatusNotFound) { return false, nil } else if err != nil { @@ -77,7 +78,7 @@ func (c *Container) Exists() (bool, error) { // // WARNING: This method is not thread-safe. Calling it concurrently on the same // object results in undefined behavior. -func (c *Container) Headers() (ContainerHeaders, error) { +func (c *Container) Headers(ctx context.Context) (ContainerHeaders, error) { if c.headers != nil { return *c.headers, nil } @@ -86,7 +87,7 @@ func (c *Container) Headers() (ContainerHeaders, error) { Method: "HEAD", ContainerName: c.name, ExpectStatusCodes: []int{204}, - }.Do(c.a.backend) + }.Do(ctx, c.a.backend) if err != nil { return ContainerHeaders{}, err } @@ -107,13 +108,13 @@ func (c *Container) Headers() (ContainerHeaders, error) { // If you are not sure whether the container exists, use Create() instead. // // A successful POST request implies Invalidate() since it may change metadata. -func (c *Container) Update(headers ContainerHeaders, opts *RequestOptions) error { +func (c *Container) Update(ctx context.Context, headers ContainerHeaders, opts *RequestOptions) error { resp, err := Request{ Method: "POST", ContainerName: c.name, Options: cloneRequestOptions(opts, headers.Headers), ExpectStatusCodes: []int{204}, - }.Do(c.a.backend) + }.Do(ctx, c.a.backend) if err == nil { c.Invalidate() resp.Body.Close() @@ -127,14 +128,14 @@ func (c *Container) Update(headers ContainerHeaders, opts *RequestOptions) error // This function can be used regardless of whether the container exists or not. // // A successful PUT request implies Invalidate() since it may change metadata. -func (c *Container) Create(opts *RequestOptions) error { +func (c *Container) Create(ctx context.Context, opts *RequestOptions) error { resp, err := Request{ Method: "PUT", ContainerName: c.name, Options: opts, ExpectStatusCodes: []int{201, 202}, DrainResponseBody: true, - }.Do(c.a.backend) + }.Do(ctx, c.a.backend) if err == nil { c.Invalidate() resp.Body.Close() @@ -150,13 +151,13 @@ func (c *Container) Create(opts *RequestOptions) error { // This operation fails with http.StatusNotFound if the container does not exist. // // A successful DELETE request implies Invalidate(). -func (c *Container) Delete(opts *RequestOptions) error { +func (c *Container) Delete(ctx context.Context, opts *RequestOptions) error { resp, err := Request{ Method: "DELETE", ContainerName: c.name, Options: opts, ExpectStatusCodes: []int{204}, - }.Do(c.a.backend) + }.Do(ctx, c.a.backend) if err == nil { c.Invalidate() resp.Body.Close() @@ -180,13 +181,13 @@ func (c *Container) Invalidate() { // with freshly constructed Container instances like so: // // container, err := account.Container("documents").EnsureExists() -func (c *Container) EnsureExists() (*Container, error) { +func (c *Container) EnsureExists(ctx context.Context) (*Container, error) { resp, err := Request{ Method: "PUT", ContainerName: c.name, ExpectStatusCodes: []int{201, 202}, DrainResponseBody: true, - }.Do(c.a.backend) + }.Do(ctx, c.a.backend) if err == nil { resp.Body.Close() } diff --git a/container_iterator.go b/container_iterator.go index ef0a77c..9ff9be9 100644 --- a/container_iterator.go +++ b/container_iterator.go @@ -19,6 +19,7 @@ package schwift import ( + "context" "fmt" "time" ) @@ -86,8 +87,8 @@ func (i *ContainerIterator) getBase() *iteratorBase { // // This method offers maximal flexibility, but most users will prefer the // simpler interfaces offered by Collect() and Foreach(). -func (i *ContainerIterator) NextPage(limit int) ([]*Container, error) { - names, err := i.getBase().nextPage(limit) +func (i *ContainerIterator) NextPage(ctx context.Context, limit int) ([]*Container, error) { + names, err := i.getBase().nextPage(ctx, limit) if err != nil { return nil, err } @@ -100,7 +101,7 @@ func (i *ContainerIterator) NextPage(limit int) ([]*Container, error) { } // NextPageDetailed is like NextPage, but includes basic metadata. -func (i *ContainerIterator) NextPageDetailed(limit int) ([]ContainerInfo, error) { +func (i *ContainerIterator) NextPageDetailed(ctx context.Context, limit int) ([]ContainerInfo, error) { b := i.getBase() var document []struct { @@ -109,7 +110,7 @@ func (i *ContainerIterator) NextPageDetailed(limit int) ([]ContainerInfo, error) LastModifiedStr string `json:"last_modified"` Name string `json:"name"` } - err := b.nextPageDetailed(limit, &document) + err := b.nextPageDetailed(ctx, limit, &document) if err != nil { return nil, err } @@ -137,9 +138,9 @@ func (i *ContainerIterator) NextPageDetailed(limit int) ([]ContainerInfo, error) // Foreach lists the container names matching this iterator and calls the // callback once for every container. Iteration is aborted when a GET request fails, // or when the callback returns a non-nil error. -func (i *ContainerIterator) Foreach(callback func(*Container) error) error { +func (i *ContainerIterator) Foreach(ctx context.Context, callback func(*Container) error) error { for { - containers, err := i.NextPage(-1) + containers, err := i.NextPage(ctx, -1) if err != nil { return err } @@ -156,9 +157,9 @@ func (i *ContainerIterator) Foreach(callback func(*Container) error) error { } // ForeachDetailed is like Foreach, but includes basic metadata. -func (i *ContainerIterator) ForeachDetailed(callback func(ContainerInfo) error) error { +func (i *ContainerIterator) ForeachDetailed(ctx context.Context, callback func(ContainerInfo) error) error { for { - infos, err := i.NextPageDetailed(-1) + infos, err := i.NextPageDetailed(ctx, -1) if err != nil { return err } @@ -177,10 +178,10 @@ func (i *ContainerIterator) ForeachDetailed(callback func(ContainerInfo) error) // Collect lists all container names matching this iterator. For large sets of // containers that cannot be retrieved at once, Collect handles paging behind // the scenes. The return value is always the complete set of containers. -func (i *ContainerIterator) Collect() ([]*Container, error) { +func (i *ContainerIterator) Collect(ctx context.Context) ([]*Container, error) { var result []*Container for { - containers, err := i.NextPage(-1) + containers, err := i.NextPage(ctx, -1) if err != nil { return nil, err } @@ -192,10 +193,10 @@ func (i *ContainerIterator) Collect() ([]*Container, error) { } // CollectDetailed is like Collect, but includes basic metadata. -func (i *ContainerIterator) CollectDetailed() ([]ContainerInfo, error) { +func (i *ContainerIterator) CollectDetailed(ctx context.Context) ([]ContainerInfo, error) { var result []ContainerInfo for { - infos, err := i.NextPageDetailed(-1) + infos, err := i.NextPageDetailed(ctx, -1) if err != nil { return nil, err } diff --git a/iterator.go b/iterator.go index 8d451ac..ba5e6f6 100644 --- a/iterator.go +++ b/iterator.go @@ -19,6 +19,7 @@ package schwift import ( + "context" "encoding/json" "net/http" "strconv" @@ -114,11 +115,11 @@ func (b *iteratorBase) request(limit int, detailed bool) Request { return r } -func (b *iteratorBase) nextPage(limit int) ([]string, error) { +func (b *iteratorBase) nextPage(ctx context.Context, limit int) ([]string, error) { if b.eof { return nil, nil } - resp, err := b.request(limit, false).Do(b.i.getAccount().backend) + resp, err := b.request(limit, false).Do(ctx, b.i.getAccount().backend) if err != nil { return nil, err } @@ -143,11 +144,11 @@ func (b *iteratorBase) nextPage(limit int) ([]string, error) { return result, b.i.putHeader(resp.Header) } -func (b *iteratorBase) nextPageDetailed(limit int, data interface{}) error { +func (b *iteratorBase) nextPageDetailed(ctx context.Context, limit int, data interface{}) error { if b.eof { return nil } - resp, err := b.request(limit, true).Do(b.i.getAccount().backend) + resp, err := b.request(limit, true).Do(ctx, b.i.getAccount().backend) if err != nil { return err } diff --git a/largeobject.go b/largeobject.go index 44acca7..e77779b 100644 --- a/largeobject.go +++ b/largeobject.go @@ -20,6 +20,7 @@ package schwift import ( "bytes" + "context" "crypto/md5" //nolint:gosec // Etag uses md5 "encoding/base64" "encoding/hex" @@ -214,8 +215,8 @@ func (lo *LargeObject) SegmentObjects() []*Object { // AsLargeObject opens an existing large object. If the given object does not // exist, or if it is not a large object, ErrNotLarge will be returned. In this // case, Object.AsNewLargeObject() needs to be used instead. -func (o *Object) AsLargeObject() (*LargeObject, error) { - exists, err := o.Exists() +func (o *Object) AsLargeObject(ctx context.Context) (*LargeObject, error) { + exists, err := o.Exists(ctx) if err != nil { return nil, err } @@ -225,15 +226,15 @@ func (o *Object) AsLargeObject() (*LargeObject, error) { h := o.headers if h.IsDynamicLargeObject() { - return o.asDLO(h.Get("X-Object-Manifest")) + return o.asDLO(ctx, h.Get("X-Object-Manifest")) } if h.IsStaticLargeObject() { - return o.asSLO() + return o.asSLO(ctx) } return nil, ErrNotLarge } -func (o *Object) asDLO(manifestStr string) (*LargeObject, error) { +func (o *Object) asDLO(ctx context.Context, manifestStr string) (*LargeObject, error) { manifest := strings.SplitN(manifestStr, "/", 2) if len(manifest) < 2 { return nil, ErrNotLarge @@ -248,7 +249,7 @@ func (o *Object) asDLO(manifestStr string) (*LargeObject, error) { iter := lo.segmentContainer.Objects() iter.Prefix = lo.segmentPrefix - segmentInfos, err := iter.CollectDetailed() + segmentInfos, err := iter.CollectDetailed(ctx) if err != nil { return nil, err } @@ -264,13 +265,13 @@ func (o *Object) asDLO(manifestStr string) (*LargeObject, error) { return lo, nil } -func (o *Object) asSLO() (*LargeObject, error) { +func (o *Object) asSLO(ctx context.Context) (*LargeObject, error) { opts := RequestOptions{ Values: make(url.Values), } opts.Values.Set("multipart-manifest", "get") opts.Values.Set("format", "raw") - buf, err := o.Download(&opts).AsByteSlice() + buf, err := o.Download(ctx, &opts).AsByteSlice() if err != nil { return nil, err } @@ -409,14 +410,14 @@ func parseHTTPRange(str string) (offsetVal int64, lengthVal uint64, ok bool) { // Object.AsLargeObject() followed by Truncate(), except that segmenting options // are initialized from the method's SegmentingOptions argument rather than from // the existing manifest. -func (o *Object) AsNewLargeObject(sopts SegmentingOptions, topts *TruncateOptions) (*LargeObject, error) { +func (o *Object) AsNewLargeObject(ctx context.Context, sopts SegmentingOptions, topts *TruncateOptions) (*LargeObject, error) { // we only need to load the existing large object if we want to do something // with the old segments if topts != nil && topts.DeleteSegments { - lo, err := o.AsLargeObject() + lo, err := o.AsLargeObject(ctx) switch { case err == nil: - err := lo.Truncate(topts) + err := lo.Truncate(ctx, topts) if err != nil { return nil, err } @@ -475,8 +476,8 @@ type TruncateOptions struct { // Truncate removes all segments from a large object's manifest. The manifest is // not written by this call, so WriteManifest() usually needs to be called // afterwards. -func (lo *LargeObject) Truncate(opts *TruncateOptions) error { - _, _, err := lo.object.c.a.BulkDelete(lo.SegmentObjects(), nil, nil) +func (lo *LargeObject) Truncate(ctx context.Context, opts *TruncateOptions) error { + _, _, err := lo.object.c.a.BulkDelete(ctx, lo.SegmentObjects(), nil, nil) if err == nil { lo.segments = nil } @@ -660,7 +661,7 @@ func (lo *LargeObject) AddSegment(segment SegmentInfo) error { // // This function uploads segment objects, so it may return any error that // Object.Upload() returns, see documentation over there. -func (lo *LargeObject) Append(contents io.Reader, segmentSizeBytes int64, opts *RequestOptions) error { +func (lo *LargeObject) Append(ctx context.Context, contents io.Reader, segmentSizeBytes int64, opts *RequestOptions) error { if segmentSizeBytes < 0 { panic("segmentSizeBytes may not be negative") } @@ -689,7 +690,7 @@ func (lo *LargeObject) Append(contents io.Reader, segmentSizeBytes int64, opts * } obj := lo.NextSegmentObject() - err := obj.Upload(&tracker, nil, opts) + err := obj.Upload(ctx, &tracker, nil, opts) if err != nil { return err } @@ -756,22 +757,22 @@ func (r *lengthAndEtagTrackingReader) Read(buf []byte) (int, error) { // For dynamic large objects, this method does not generate a PUT request // if the object already exists and has the correct manifest (i.e. // SegmentContainer and SegmentPrefix have not been changed). -func (lo *LargeObject) WriteManifest(opts *RequestOptions) error { +func (lo *LargeObject) WriteManifest(ctx context.Context, opts *RequestOptions) error { switch lo.strategy { case StaticLargeObject: - return lo.writeSLOManifest(opts) + return lo.writeSLOManifest(ctx, opts) case DynamicLargeObject: - return lo.writeDLOManifest(opts) + return lo.writeDLOManifest(ctx, opts) default: panic("no such strategy") } } -func (lo *LargeObject) writeDLOManifest(opts *RequestOptions) error { +func (lo *LargeObject) writeDLOManifest(ctx context.Context, opts *RequestOptions) error { manifest := lo.segmentContainer.Name() + "/" + lo.segmentPrefix // check if the manifest is already set correctly - headers, err := lo.object.Headers() + headers, err := lo.object.Headers(ctx) if err != nil && !Is(err, http.StatusNotFound) { return err } @@ -782,10 +783,10 @@ func (lo *LargeObject) writeDLOManifest(opts *RequestOptions) error { // write manifest; make sure that this is a DLO opts = cloneRequestOptions(opts, nil) opts.Headers.Set("X-Object-Manifest", manifest) - return lo.object.Upload(nil, nil, opts) + return lo.object.Upload(ctx, nil, nil, opts) } -func (lo *LargeObject) writeSLOManifest(opts *RequestOptions) error { +func (lo *LargeObject) writeSLOManifest(ctx context.Context, opts *RequestOptions) error { sloSegments := make([]sloSegmentInfo, len(lo.segments)) for idx, s := range lo.segments { if len(s.Data) > 0 { @@ -820,5 +821,5 @@ func (lo *LargeObject) writeSLOManifest(opts *RequestOptions) error { opts = cloneRequestOptions(opts, nil) opts.Headers.Del("X-Object-Manifest") // ensure sanity :) opts.Values.Set("multipart-manifest", "put") - return lo.object.Upload(bytes.NewReader(manifest), nil, opts) + return lo.object.Upload(ctx, bytes.NewReader(manifest), nil, opts) } @@ -20,6 +20,7 @@ package schwift import ( "bytes" + "context" "crypto/hmac" "crypto/md5" //nolint:gosec // Etag uses md5 "crypto/sha1" //nolint:gosec // Used by swift @@ -89,8 +90,8 @@ func (o *Object) FullName() string { // Exists checks if this object exists, potentially by issuing a HEAD request // if no Headers() have been cached yet. -func (o *Object) Exists() (bool, error) { - _, err := o.Headers() +func (o *Object) Exists(ctx context.Context) (bool, error) { + _, err := o.Headers(ctx) if Is(err, http.StatusNotFound) { return false, nil } else if err != nil { @@ -109,12 +110,12 @@ func (o *Object) Exists() (bool, error) { // // WARNING: This method is not thread-safe. Calling it concurrently on the same // object results in undefined behavior. -func (o *Object) Headers() (ObjectHeaders, error) { +func (o *Object) Headers(ctx context.Context) (ObjectHeaders, error) { if o.headers != nil { return *o.headers, nil } - hdr, err := o.fetchHeaders(nil) + hdr, err := o.fetchHeaders(ctx, nil) if err != nil { return ObjectHeaders{}, err } @@ -122,7 +123,7 @@ func (o *Object) Headers() (ObjectHeaders, error) { return *hdr, nil } -func (o *Object) fetchHeaders(opts *RequestOptions) (*ObjectHeaders, error) { +func (o *Object) fetchHeaders(ctx context.Context, opts *RequestOptions) (*ObjectHeaders, error) { resp, err := Request{ Method: "HEAD", ContainerName: o.c.name, @@ -132,7 +133,7 @@ func (o *Object) fetchHeaders(opts *RequestOptions) (*ObjectHeaders, error) { // this returns 200 instead of 204 ExpectStatusCodes: []int{http.StatusOK}, DrainResponseBody: true, - }.Do(o.c.a.backend) + }.Do(ctx, o.c.a.backend) if err != nil { return nil, err } @@ -148,14 +149,14 @@ func (o *Object) fetchHeaders(opts *RequestOptions) (*ObjectHeaders, error) { // This operation fails with http.StatusNotFound if the object does not exist. // // A successful POST request implies Invalidate() since it may change metadata. -func (o *Object) Update(headers ObjectHeaders, opts *RequestOptions) error { +func (o *Object) Update(ctx context.Context, headers ObjectHeaders, opts *RequestOptions) error { resp, err := Request{ Method: "POST", ContainerName: o.c.name, ObjectName: o.name, Options: cloneRequestOptions(opts, headers.Headers), ExpectStatusCodes: []int{http.StatusAccepted}, - }.Do(o.c.a.backend) + }.Do(ctx, o.c.a.backend) if err == nil { o.Invalidate() resp.Body.Close() @@ -205,7 +206,7 @@ type UploadOptions struct { // This function can be used regardless of whether the object exists or not. // // A successful PUT request implies Invalidate() since it may change metadata. -func (o *Object) Upload(content io.Reader, opts *UploadOptions, ropts *RequestOptions) error { +func (o *Object) Upload(ctx context.Context, content io.Reader, opts *UploadOptions, ropts *RequestOptions) error { if opts == nil { opts = &UploadOptions{} } @@ -247,7 +248,7 @@ func (o *Object) Upload(content io.Reader, opts *UploadOptions, ropts *RequestOp // the segments after successfully uploading the new object to decrease the // chance of an inconsistent state following an upload error var err error - lo, err = o.AsLargeObject() + lo, err = o.AsLargeObject(ctx) switch { case err == nil: // okay, delete segments at the end @@ -268,7 +269,7 @@ func (o *Object) Upload(content io.Reader, opts *UploadOptions, ropts *RequestOp Body: content, ExpectStatusCodes: []int{201}, DrainResponseBody: true, - }.Do(o.c.a.backend) + }.Do(ctx, o.c.a.backend) if err != nil { return err } @@ -283,7 +284,7 @@ func (o *Object) Upload(content io.Reader, opts *UploadOptions, ropts *RequestOp } if opts.DeleteSegments && lo != nil { - _, _, err := lo.object.c.a.BulkDelete(lo.SegmentObjects(), nil, nil) + _, _, err := lo.object.c.a.BulkDelete(ctx, lo.SegmentObjects(), nil, nil) if err != nil { return err } @@ -361,11 +362,11 @@ func tryComputeEtag(content io.Reader, headers ObjectHeaders) error { // }) // // If you do not need an io.Writer, always use Upload instead. -func (o *Object) UploadFromWriter(opts *UploadOptions, ropts *RequestOptions, callback func(io.Writer) error) error { +func (o *Object) UploadFromWriter(ctx context.Context, opts *UploadOptions, ropts *RequestOptions, callback func(io.Writer) error) error { reader, writer := io.Pipe() errChan := make(chan error) go func() { - err := o.Upload(reader, opts, ropts) + err := o.Upload(ctx, reader, opts, ropts) reader.CloseWithError(err) // stop the writer if it is still writing errChan <- err }() @@ -386,21 +387,21 @@ type DeleteOptions struct { // This operation fails with http.StatusNotFound if the object does not exist. // // A successful DELETE request implies Invalidate(). -func (o *Object) Delete(opts *DeleteOptions, ropts *RequestOptions) error { +func (o *Object) Delete(ctx context.Context, opts *DeleteOptions, ropts *RequestOptions) error { if opts == nil { opts = &DeleteOptions{} } if opts.DeleteSegments { - exists, err := o.Exists() + exists, err := o.Exists(ctx) if err != nil { return err } if exists { - lo, err := o.AsLargeObject() + lo, err := o.AsLargeObject(ctx) switch { case err == nil: // is large object - delete segments and the object itself in one step - _, _, err := o.c.a.BulkDelete(append(lo.SegmentObjects(), o), nil, nil) + _, _, err := o.c.a.BulkDelete(ctx, append(lo.SegmentObjects(), o), nil, nil) o.Invalidate() return err case errors.Is(err, ErrNotLarge): @@ -418,7 +419,7 @@ func (o *Object) Delete(opts *DeleteOptions, ropts *RequestOptions) error { ObjectName: o.name, Options: ropts, ExpectStatusCodes: []int{http.StatusNoContent}, - }.Do(o.c.a.backend) + }.Do(ctx, o.c.a.backend) if err == nil { o.Invalidate() resp.Body.Close() @@ -451,14 +452,14 @@ func (o *Object) Invalidate() { // // WARNING: This method is not thread-safe. Calling it concurrently on the same // object results in undefined behavior. -func (o *Object) Download(opts *RequestOptions) DownloadedObject { +func (o *Object) Download(ctx context.Context, opts *RequestOptions) DownloadedObject { resp, err := Request{ Method: "GET", ContainerName: o.c.name, ObjectName: o.name, Options: opts, ExpectStatusCodes: []int{http.StatusOK}, - }.Do(o.c.a.backend) //nolint:bodyclose // body is returned and must be closed by the user + }.Do(ctx, o.c.a.backend) //nolint:bodyclose // body is returned and must be closed by the user var body io.ReadCloser if err == nil { newHeaders := ObjectHeaders{headersFromHTTP(resp.Header)} @@ -488,7 +489,7 @@ type CopyOptions struct { // // A successful COPY implies target.Invalidate() since it may change the // target's metadata. -func (o *Object) CopyTo(target *Object, opts *CopyOptions, ropts *RequestOptions) error { +func (o *Object) CopyTo(ctx context.Context, target *Object, opts *CopyOptions, ropts *RequestOptions) error { ropts = cloneRequestOptions(ropts, nil) ropts.Headers.Set("Destination", target.FullName()) if o.c.a.name != target.c.a.name { @@ -510,7 +511,7 @@ func (o *Object) CopyTo(target *Object, opts *CopyOptions, ropts *RequestOptions Options: ropts, ExpectStatusCodes: []int{http.StatusCreated}, DrainResponseBody: true, - }.Do(o.c.a.backend) + }.Do(ctx, o.c.a.backend) if err == nil { target.Invalidate() resp.Body.Close() @@ -531,7 +532,7 @@ type SymlinkOptions struct { // this operation. // // A successful PUT request implies Invalidate() since it may change metadata. -func (o *Object) SymlinkTo(target *Object, opts *SymlinkOptions, ropts *RequestOptions) error { +func (o *Object) SymlinkTo(ctx context.Context, target *Object, opts *SymlinkOptions, ropts *RequestOptions) error { ropts = cloneRequestOptions(ropts, nil) ropts.Headers.Set("X-Symlink-Target", target.FullName()) if !target.c.a.IsEqualTo(o.c.a) { @@ -550,7 +551,7 @@ func (o *Object) SymlinkTo(target *Object, opts *SymlinkOptions, ropts *RequestO } } - return o.Upload(nil, uopts, ropts) + return o.Upload(ctx, nil, uopts, ropts) } // SymlinkHeaders is similar to Headers, but if the object is a symlink, it @@ -571,9 +572,9 @@ func (o *Object) SymlinkTo(target *Object, opts *SymlinkOptions, ropts *RequestO // // WARNING: This method is not thread-safe. Calling it concurrently on the same // object results in undefined behavior. -func (o *Object) SymlinkHeaders() (headers ObjectHeaders, target *Object, err error) { +func (o *Object) SymlinkHeaders(ctx context.Context) (headers ObjectHeaders, target *Object, err error) { if o.symlinkHeaders == nil { - o.symlinkHeaders, err = o.fetchHeaders(&RequestOptions{ + o.symlinkHeaders, err = o.fetchHeaders(ctx, &RequestOptions{ Values: url.Values{"symlink": []string{"get"}}, }) if err != nil { diff --git a/object_iterator.go b/object_iterator.go index c6efa78..314b9bf 100644 --- a/object_iterator.go +++ b/object_iterator.go @@ -19,6 +19,7 @@ package schwift import ( + "context" "fmt" "regexp" "time" @@ -103,8 +104,8 @@ func (i *ObjectIterator) getBase() *iteratorBase { // // This method offers maximal flexibility, but most users will prefer the // simpler interfaces offered by Collect() and Foreach(). -func (i *ObjectIterator) NextPage(limit int) ([]*Object, error) { - names, err := i.getBase().nextPage(limit) +func (i *ObjectIterator) NextPage(ctx context.Context, limit int) ([]*Object, error) { + names, err := i.getBase().nextPage(ctx, limit) if err != nil { return nil, err } @@ -120,7 +121,7 @@ func (i *ObjectIterator) NextPage(limit int) ([]*Object, error) { var symlinkPathRx = regexp.MustCompile(`^/v1/([^/]+)/([^/]+)/(.+)$`) // NextPageDetailed is like NextPage, but includes basic metadata. -func (i *ObjectIterator) NextPageDetailed(limit int) ([]ObjectInfo, error) { +func (i *ObjectIterator) NextPageDetailed(ctx context.Context, limit int) ([]ObjectInfo, error) { b := i.getBase() var document []struct { @@ -134,7 +135,7 @@ func (i *ObjectIterator) NextPageDetailed(limit int) ([]ObjectInfo, error) { // or just this: Subdir string `json:"subdir"` } - err := b.nextPageDetailed(limit, &document) + err := b.nextPageDetailed(ctx, limit, &document) if err != nil { return nil, err } @@ -182,9 +183,9 @@ func (i *ObjectIterator) NextPageDetailed(limit int) ([]ObjectInfo, error) { // Foreach lists the object names matching this iterator and calls the // callback once for every object. Iteration is aborted when a GET request fails, // or when the callback returns a non-nil error. -func (i *ObjectIterator) Foreach(callback func(*Object) error) error { +func (i *ObjectIterator) Foreach(ctx context.Context, callback func(*Object) error) error { for { - objects, err := i.NextPage(-1) + objects, err := i.NextPage(ctx, -1) if err != nil { return err } @@ -201,9 +202,9 @@ func (i *ObjectIterator) Foreach(callback func(*Object) error) error { } // ForeachDetailed is like Foreach, but includes basic metadata. -func (i *ObjectIterator) ForeachDetailed(callback func(ObjectInfo) error) error { +func (i *ObjectIterator) ForeachDetailed(ctx context.Context, callback func(ObjectInfo) error) error { for { - infos, err := i.NextPageDetailed(-1) + infos, err := i.NextPageDetailed(ctx, -1) if err != nil { return err } @@ -222,10 +223,10 @@ func (i *ObjectIterator) ForeachDetailed(callback func(ObjectInfo) error) error // Collect lists all object names matching this iterator. For large sets of // objects that cannot be retrieved at once, Collect handles paging behind // the scenes. The return value is always the complete set of objects. -func (i *ObjectIterator) Collect() ([]*Object, error) { +func (i *ObjectIterator) Collect(ctx context.Context) ([]*Object, error) { var result []*Object for { - objects, err := i.NextPage(-1) + objects, err := i.NextPage(ctx, -1) if err != nil { return nil, err } @@ -237,10 +238,10 @@ func (i *ObjectIterator) Collect() ([]*Object, error) { } // CollectDetailed is like Collect, but includes basic metadata. -func (i *ObjectIterator) CollectDetailed() ([]ObjectInfo, error) { +func (i *ObjectIterator) CollectDetailed(ctx context.Context) ([]ObjectInfo, error) { var result []ObjectInfo for { - infos, err := i.NextPageDetailed(-1) + infos, err := i.NextPageDetailed(ctx, -1) if err != nil { return nil, err } @@ -40,7 +40,6 @@ import ( type RequestOptions struct { Headers Headers Values url.Values - Context context.Context //nolint: containedctx // ignored for now to not break the API } func cloneRequestOptions(orig *RequestOptions, additional Headers) *RequestOptions { @@ -55,7 +54,6 @@ func cloneRequestOptions(orig *RequestOptions, additional Headers) *RequestOptio for k, v := range orig.Values { result.Values[k] = v } - result.Context = orig.Context } for k, v := range additional { result.Headers[k] = v @@ -106,7 +104,7 @@ func (r Request) URL(backend Backend, values url.Values) (string, error) { } // Do executes this request on the given Backend. -func (r Request) Do(backend Backend) (*http.Response, error) { +func (r Request) Do(ctx context.Context, backend Backend) (*http.Response, error) { // build URL var values url.Values if r.Options != nil { @@ -118,7 +116,7 @@ func (r Request) Do(backend Backend) (*http.Response, error) { } // build request - req, err := http.NewRequest(r.Method, uri, r.Body) + req, err := http.NewRequestWithContext(ctx, r.Method, uri, r.Body) if err != nil { return nil, err } @@ -127,9 +125,6 @@ func (r Request) Do(backend Backend) (*http.Response, error) { for k, v := range r.Options.Headers { req.Header[k] = []string{v} } - if r.Options.Context != nil { - req = req.WithContext(r.Options.Context) - } } if r.Body != nil { req.Header.Set("Expect", "100-continue") diff --git a/tests/account_test.go b/tests/account_test.go index dc108ad..c44bf7f 100644 --- a/tests/account_test.go +++ b/tests/account_test.go @@ -19,6 +19,7 @@ package tests import ( + "context" "testing" "github.com/majewsky/schwift" @@ -26,7 +27,7 @@ import ( func TestAccountBasic(t *testing.T) { testWithAccount(t, func(a *schwift.Account) { - hdr, err := a.Headers() + hdr, err := a.Headers(context.TODO()) if !expectSuccess(t, err) { t.FailNow() } @@ -46,12 +47,12 @@ func TestAccountMetadata(t *testing.T) { hdr := schwift.NewAccountHeaders() hdr.Metadata().Set("schwift-test1", "first") hdr.Metadata().Set("schwift-test2", "second") - err := a.Update(hdr, nil) + err := a.Update(context.TODO(), hdr, nil) if !expectSuccess(t, err) { t.FailNow() } - hdr, err = a.Headers() + hdr, err = a.Headers(context.TODO()) if !expectSuccess(t, err) { t.FailNow() } @@ -61,12 +62,12 @@ func TestAccountMetadata(t *testing.T) { // test deleting some metadata hdr = schwift.NewAccountHeaders() hdr.Metadata().Clear("schwift-test1") - err = a.Update(hdr, nil) + err = a.Update(context.TODO(), hdr, nil) if !expectSuccess(t, err) { t.FailNow() } - hdr, err = a.Headers() + hdr, err = a.Headers(context.TODO()) if !expectSuccess(t, err) { t.FailNow() } @@ -78,12 +79,12 @@ func TestAccountMetadata(t *testing.T) { hdr.Metadata().Set("schwift-test1", "will not be set") hdr.Metadata().Del("schwift-test1") hdr.Metadata().Set("schwift-test2", "changed") - err = a.Update(hdr, nil) + err = a.Update(context.TODO(), hdr, nil) if !expectSuccess(t, err) { t.FailNow() } - hdr, err = a.Headers() + hdr, err = a.Headers(context.TODO()) if !expectSuccess(t, err) { t.FailNow() } diff --git a/tests/bulk_delete_test.go b/tests/bulk_delete_test.go index 0643a7c..102d092 100644 --- a/tests/bulk_delete_test.go +++ b/tests/bulk_delete_test.go @@ -19,6 +19,7 @@ package tests import ( + "context" "fmt" "strings" "testing" @@ -30,18 +31,18 @@ import ( func TestBulkDeleteSuccess(t *testing.T) { testWithAccount(t, func(a *schwift.Account) { testWithAndWithoutBulkDeleteSupport(func() { - c, err := a.Container("schwift-test-bulkdelete").EnsureExists() + c, err := a.Container("schwift-test-bulkdelete").EnsureExists(context.TODO()) expectSuccess(t, err) objs, err := createTestObjects(c) expectSuccess(t, err) - numDeleted, numNotFound, err := c.Account().BulkDelete(objs, nil, nil) + numDeleted, numNotFound, err := c.Account().BulkDelete(context.TODO(), objs, nil, nil) expectSuccess(t, err) expectInt(t, numDeleted, len(objs)) expectInt(t, numNotFound, 0) expectContainerExistence(t, c, true) - numDeleted, numNotFound, err = c.Account().BulkDelete(objs, nil, nil) + numDeleted, numNotFound, err = c.Account().BulkDelete(context.TODO(), objs, nil, nil) expectSuccess(t, err) expectInt(t, numDeleted, 0) expectInt(t, numNotFound, len(objs)) @@ -51,7 +52,7 @@ func TestBulkDeleteSuccess(t *testing.T) { expectSuccess(t, err) cs := []*schwift.Container{c} - numDeleted, numNotFound, err = c.Account().BulkDelete(objs, cs, nil) + numDeleted, numNotFound, err = c.Account().BulkDelete(context.TODO(), objs, cs, nil) expectSuccess(t, err) expectInt(t, numDeleted, len(objs)+1) expectInt(t, numNotFound, 0) @@ -71,7 +72,7 @@ func TestBulkDeleteError(t *testing.T) { // not deleting all objects should lead to 409 Conflict when deleting the Container // (NOTE: actual Swift returns 400 here although I don't understand why // even after reading its code) - numDeleted, numNotFound, err := c.Account().BulkDelete(objs, cs, nil) + numDeleted, numNotFound, err := c.Account().BulkDelete(context.TODO(), objs, cs, nil) expectInt(t, numDeleted, len(objs)) expectInt(t, numNotFound, 0) t.Logf("err = %#v\n", err) @@ -87,7 +88,7 @@ func createTestObjects(c *schwift.Container) ([]*schwift.Object, error) { var objs []*schwift.Object for idx := 1; idx <= 5; idx++ { obj := c.Object(fmt.Sprintf("object%d", idx)) - err := obj.Upload(strings.NewReader("example"), nil, nil) + err := obj.Upload(context.TODO(), strings.NewReader("example"), nil, nil) if err != nil { return nil, err } diff --git a/tests/bulk_upload_test.go b/tests/bulk_upload_test.go index cb64168..35285ea 100644 --- a/tests/bulk_upload_test.go +++ b/tests/bulk_upload_test.go @@ -21,6 +21,7 @@ package tests import ( "archive/tar" "bytes" + "context" "strings" "testing" @@ -38,6 +39,7 @@ func TestBulkUploadSuccess(t *testing.T) { obj2.FullName(): []byte("world"), }) n, err := c.Account().BulkUpload( + context.TODO(), "", // upload path schwift.BulkUploadTar, bytes.NewReader(archive), @@ -56,6 +58,7 @@ func TestBulkUploadSuccess(t *testing.T) { func TestBulkUploadArchiveError(t *testing.T) { testWithContainer(t, func(c *schwift.Container) { n, err := c.Account().BulkUpload( + context.TODO(), c.Name(), // upload path schwift.BulkUploadTar, strings.NewReader("This is not the TAR archive you're looking for."), @@ -81,6 +84,7 @@ func TestBulkUploadObjectError(t *testing.T) { obj2.Name(): []byte("world"), }) n, err := c.Account().BulkUpload( + context.TODO(), c.Name(), // upload path schwift.BulkUploadTar, bytes.NewReader(archive), diff --git a/tests/container_iterator_test.go b/tests/container_iterator_test.go index cb482c1..91679f5 100644 --- a/tests/container_iterator_test.go +++ b/tests/container_iterator_test.go @@ -19,6 +19,7 @@ package tests import ( + "context" "fmt" "testing" @@ -33,52 +34,52 @@ func TestContainerIterator(t *testing.T) { // create test containers that can be listed for idx := 1; idx <= 4; idx++ { - _, err := a.Container(cname(idx)).EnsureExists() + _, err := a.Container(cname(idx)).EnsureExists(context.TODO()) expectSuccess(t, err) } // test iteration with empty last page iter := a.Containers() iter.Prefix = "schwift-test-listing" - cs, err := iter.NextPage(2) + cs, err := iter.NextPage(context.TODO(), 2) expectSuccess(t, err) expectContainerNames(t, cs, cname(1), cname(2)) - cs, err = iter.NextPage(2) + cs, err = iter.NextPage(context.TODO(), 2) expectSuccess(t, err) expectContainerNames(t, cs, cname(3), cname(4)) - cs, err = iter.NextPage(2) + cs, err = iter.NextPage(context.TODO(), 2) expectSuccess(t, err) expectContainerNames(t, cs) - cs, err = iter.NextPage(2) + cs, err = iter.NextPage(context.TODO(), 2) expectSuccess(t, err) expectContainerNames(t, cs) // test iteration with partial last page iter = a.Containers() iter.Prefix = "schwift-test-listing" - cs, err = iter.NextPage(3) + cs, err = iter.NextPage(context.TODO(), 3) expectSuccess(t, err) expectContainerNames(t, cs, cname(1), cname(2), cname(3)) - cs, err = iter.NextPage(3) + cs, err = iter.NextPage(context.TODO(), 3) expectSuccess(t, err) expectContainerNames(t, cs, cname(4)) - cs, err = iter.NextPage(4) + cs, err = iter.NextPage(context.TODO(), 4) expectSuccess(t, err) expectContainerNames(t, cs) // test detailed iteration iter = a.Containers() iter.Prefix = "schwift-test-listing" - cis, err := iter.NextPageDetailed(2) + cis, err := iter.NextPageDetailed(context.TODO(), 2) expectSuccess(t, err) expectContainerInfos(t, cis, cname(1), cname(2)) - cis, err = iter.NextPageDetailed(3) + cis, err = iter.NextPageDetailed(context.TODO(), 3) expectSuccess(t, err) expectContainerInfos(t, cis, cname(3), cname(4)) - cis, err = iter.NextPageDetailed(3) + cis, err = iter.NextPageDetailed(context.TODO(), 3) expectSuccess(t, err) expectContainerInfos(t, cis) - cis, err = iter.NextPageDetailed(3) + cis, err = iter.NextPageDetailed(context.TODO(), 3) expectSuccess(t, err) expectContainerInfos(t, cis) @@ -87,7 +88,7 @@ func TestContainerIterator(t *testing.T) { iter = a.Containers() iter.Prefix = "schwift-test-listing" idx := 0 - expectSuccess(t, iter.Foreach(func(c *schwift.Container) error { + expectSuccess(t, iter.Foreach(context.TODO(), func(c *schwift.Container) error { idx++ expectString(t, c.Name(), cname(idx)) return nil @@ -100,7 +101,7 @@ func TestContainerIterator(t *testing.T) { iter = a.Containers() iter.Prefix = "schwift-test-listing" idx = 0 - expectSuccess(t, iter.ForeachDetailed(func(info schwift.ContainerInfo) error { + expectSuccess(t, iter.ForeachDetailed(context.TODO(), func(info schwift.ContainerInfo) error { idx++ expectString(t, info.Container.Name(), cname(idx)) return nil @@ -111,29 +112,29 @@ func TestContainerIterator(t *testing.T) { // test Collect iter = a.Containers() iter.Prefix = "schwift-test-listing" - cs, err = iter.Collect() + cs, err = iter.Collect(context.TODO()) expectSuccess(t, err) expectContainerNames(t, cs, cname(1), cname(2), cname(3), cname(4)) // test CollectDetailed iter = a.Containers() iter.Prefix = "schwift-test-listing" - cis, err = iter.CollectDetailed() + cis, err = iter.CollectDetailed(context.TODO()) expectSuccess(t, err) expectContainerInfos(t, cis, cname(1), cname(2), cname(3), cname(4)) // cleanup iter = a.Containers() iter.Prefix = "schwift-test-listing" - expectSuccess(t, iter.Foreach(func(c *schwift.Container) error { - return c.Delete(nil) + expectSuccess(t, iter.Foreach(context.TODO(), func(c *schwift.Container) error { + return c.Delete(context.TODO(), nil) })) }) } func expectAccountHeadersCached(t *testing.T, a *schwift.Account) { requestCountBefore := a.Backend().(*RequestCountingBackend).Count - _, err := a.Headers() + _, err := a.Headers(context.TODO()) expectSuccess(t, err) requestCountAfter := a.Backend().(*RequestCountingBackend).Count diff --git a/tests/container_test.go b/tests/container_test.go index da05506..0ddd3bb 100644 --- a/tests/container_test.go +++ b/tests/container_test.go @@ -19,6 +19,7 @@ package tests import ( + "context" "fmt" "net/http" "testing" @@ -36,35 +37,35 @@ func TestContainerLifecycle(t *testing.T) { t.Errorf("expected c.Account() = %#v, got %#v instead\n", a, c.Account()) } - exists, err := c.Exists() + exists, err := c.Exists(context.TODO()) expectSuccess(t, err) expectBool(t, exists, false) - _, err = c.Headers() + _, err = c.Headers(context.TODO()) expectError(t, err, fmt.Sprintf("could not HEAD %q in Swift: expected 204 response, got 404 instead", containerName)) expectBool(t, schwift.Is(err, http.StatusNotFound), true) expectBool(t, schwift.Is(err, http.StatusNoContent), false) // DELETE should be idempotent and not return success on non-existence, but // OpenStack LOVES to be inconsistent with everything (including, notably, itself) - err = c.Delete(nil) + err = c.Delete(context.TODO(), nil) expectError(t, err, fmt.Sprintf("could not DELETE %q in Swift: expected 204 response, got 404 instead: <html><h1>Not Found</h1><p>The resource could not be found.</p></html>", containerName)) - err = c.Create(nil) + err = c.Create(context.TODO(), nil) expectSuccess(t, err) - exists, err = c.Exists() + exists, err = c.Exists(context.TODO()) expectSuccess(t, err) expectBool(t, exists, true) - err = c.Delete(nil) + err = c.Delete(context.TODO(), nil) expectSuccess(t, err) }) } func TestContainerUpdate(t *testing.T) { testWithContainer(t, func(c *schwift.Container) { - hdr, err := c.Headers() + hdr, err := c.Headers(context.TODO()) expectSuccess(t, err) expectBool(t, hdr.ObjectCount().Exists(), true) expectUint64(t, hdr.ObjectCount().Get(), 0) @@ -73,10 +74,10 @@ func TestContainerUpdate(t *testing.T) { hdr.ObjectCountQuota().Set(23) hdr.BytesUsedQuota().Set(42) - err = c.Update(hdr, nil) + err = c.Update(context.TODO(), hdr, nil) expectSuccess(t, err) - hdr, err = c.Headers() + hdr, err = c.Headers(context.TODO()) expectSuccess(t, err) expectUint64(t, hdr.BytesUsedQuota().Get(), 42) expectUint64(t, hdr.ObjectCountQuota().Get(), 23) @@ -86,7 +87,7 @@ func TestContainerUpdate(t *testing.T) { func expectContainerExistence(t *testing.T, c *schwift.Container, expectedExists bool) { t.Helper() c.Invalidate() - actualExists, err := c.Exists() + actualExists, err := c.Exists(context.TODO()) expectSuccess(t, err) expectBool(t, actualExists, expectedExists) } diff --git a/tests/field_test.go b/tests/field_test.go index cd27c99..868ed87 100644 --- a/tests/field_test.go +++ b/tests/field_test.go @@ -19,6 +19,7 @@ package tests import ( + "context" "net/http" "strconv" "testing" @@ -62,7 +63,7 @@ func TestFieldString(t *testing.T) { func TestFieldTimestamp(t *testing.T) { testWithAccount(t, func(a *schwift.Account) { - hdr, err := a.Headers() + hdr, err := a.Headers(context.TODO()) if !expectSuccess(t, err) { return } @@ -88,12 +89,12 @@ func TestFieldTimestamp(t *testing.T) { func TestFieldHTTPTimestamp(t *testing.T) { testWithContainer(t, func(c *schwift.Container) { obj := c.Object("test") - err := obj.Upload(nil, nil, nil) + err := obj.Upload(context.TODO(), nil, nil, nil) if !expectSuccess(t, err) { return } - hdr, err := obj.Headers() + hdr, err := obj.Headers(context.TODO()) if !expectSuccess(t, err) { return } diff --git a/tests/largeobject_test.go b/tests/largeobject_test.go index 96be854..ac171fd 100644 --- a/tests/largeobject_test.go +++ b/tests/largeobject_test.go @@ -20,6 +20,7 @@ package tests import ( "bytes" + "context" "fmt" "strings" "testing" @@ -37,7 +38,7 @@ func TestLargeObjectsBasic(t *testing.T) { testWithContainer(t, func(c *schwift.Container) { foreachLargeObjectStrategy(func(strategy schwift.LargeObjectStrategy, strategyStr string) { obj := c.Object(strategyStr + "-largeobject") - _, err := obj.AsLargeObject() + _, err := obj.AsLargeObject(context.TODO()) expectError(t, err, schwift.ErrNotLarge.Error()) segment1 := getRandomSegmentContent(128) @@ -46,14 +47,14 @@ func TestLargeObjectsBasic(t *testing.T) { segment4 := getRandomSegmentContent(128) // basic write example - lo, err := obj.AsNewLargeObject(schwift.SegmentingOptions{ + lo, err := obj.AsNewLargeObject(context.TODO(), schwift.SegmentingOptions{ SegmentContainer: c, SegmentPrefix: strategyStr + "-segments/", Strategy: strategy, }, nil) expectSuccess(t, err) - expectSuccess(t, lo.Append(bytes.NewReader([]byte(segment1+segment2)), 128, nil)) - expectSuccess(t, lo.WriteManifest(nil)) + expectSuccess(t, lo.Append(context.TODO(), bytes.NewReader([]byte(segment1+segment2)), 128, nil)) + expectSuccess(t, lo.WriteManifest(context.TODO(), nil)) expectObjectContent(t, obj, []byte(segment1+segment2)) expectLargeObject(t, obj, []schwift.SegmentInfo{ @@ -70,12 +71,12 @@ func TestLargeObjectsBasic(t *testing.T) { }) // basic append example - lo, err = obj.AsLargeObject() + lo, err = obj.AsLargeObject(context.TODO()) expectSuccess(t, err) expectLargeObjectSetup(t, lo, strategy, fmt.Sprintf("%s/%s-segments/", c.Name(), strategyStr)) - expectSuccess(t, lo.Append(bytes.NewReader([]byte(segment3+segment4)), 128, nil)) - expectSuccess(t, lo.WriteManifest(nil)) + expectSuccess(t, lo.Append(context.TODO(), bytes.NewReader([]byte(segment3+segment4)), 128, nil)) + expectSuccess(t, lo.WriteManifest(context.TODO(), nil)) expectObjectContent(t, obj, []byte(segment1+segment2+segment3+segment4)) expectLargeObject(t, obj, []schwift.SegmentInfo{ @@ -102,9 +103,9 @@ func TestLargeObjectsBasic(t *testing.T) { }) // basic truncate example - lo, err = obj.AsLargeObject() + lo, err = obj.AsLargeObject(context.TODO()) expectSuccess(t, err) - err = lo.Truncate(&schwift.TruncateOptions{ + err = lo.Truncate(context.TODO(), &schwift.TruncateOptions{ DeleteSegments: true, }) expectSuccess(t, err) @@ -114,12 +115,12 @@ func TestLargeObjectsBasic(t *testing.T) { // verify that segments were deleted iter := c.Objects() iter.Prefix = lo.SegmentPrefix() - names, err := iter.Collect() + names, err := iter.Collect(context.TODO()) expectSuccess(t, err) expectObjectNames(t, names) - expectSuccess(t, lo.Append(bytes.NewReader([]byte(segment3+segment4)), 128, nil)) - expectSuccess(t, lo.WriteManifest(nil)) + expectSuccess(t, lo.Append(context.TODO(), bytes.NewReader([]byte(segment3+segment4)), 128, nil)) + expectSuccess(t, lo.WriteManifest(context.TODO(), nil)) expectObjectContent(t, obj, []byte(segment3+segment4)) expectLargeObject(t, obj, []schwift.SegmentInfo{ @@ -143,7 +144,7 @@ func TestLargeObjectExpiration(t *testing.T) { foreachLargeObjectStrategy(func(strategy schwift.LargeObjectStrategy, strategyStr string) { segment := getRandomSegmentContent(128) obj := c.Object(strategyStr + "-largeobject") - lo, err := obj.AsNewLargeObject(schwift.SegmentingOptions{ + lo, err := obj.AsNewLargeObject(context.TODO(), schwift.SegmentingOptions{ SegmentContainer: c, SegmentPrefix: strategyStr + "-segments/", Strategy: strategy, @@ -155,17 +156,17 @@ func TestLargeObjectExpiration(t *testing.T) { headers := schwift.NewObjectHeaders() headers.ExpiresAt().Set(expirationTime) - expectSuccess(t, lo.Append(bytes.NewReader([]byte(segment)), 128, headers.ToOpts())) - expectSuccess(t, lo.WriteManifest(headers.ToOpts())) + expectSuccess(t, lo.Append(context.TODO(), bytes.NewReader([]byte(segment)), 128, headers.ToOpts())) + expectSuccess(t, lo.WriteManifest(context.TODO(), headers.ToOpts())) // check object expiration - hdr, err := obj.Headers() + hdr, err := obj.Headers(context.TODO()) expectSuccess(t, err) objectExpiration := hdr.ExpiresAt().Get().Format("2006-01-02 15:04:05 +00:00 MST") expectString(t, objectExpiration, expirationTime.Format("2006-01-02 15:04:05 +00:00 MST")) // check segment expiration - hdr, err = c.Object(strategyStr + "-segments/0000000000000001").Headers() + hdr, err = c.Object(strategyStr + "-segments/0000000000000001").Headers(context.TODO()) expectSuccess(t, err) objectExpiration = hdr.ExpiresAt().Get().Format("2006-01-02 15:04:05 +00:00 MST") expectString(t, objectExpiration, expirationTime.Format("2006-01-02 15:04:05 +00:00 MST")) @@ -179,7 +180,7 @@ func TestTruncateDuringOverwrite(t *testing.T) { obj := c.Object("largeobject") // setup phase: create a large object - lo, err := obj.AsNewLargeObject(schwift.SegmentingOptions{ + lo, err := obj.AsNewLargeObject(context.TODO(), schwift.SegmentingOptions{ SegmentContainer: c, SegmentPrefix: "segments/", Strategy: strategy, @@ -188,24 +189,24 @@ func TestTruncateDuringOverwrite(t *testing.T) { segment1 := getRandomSegmentContent(128) segment2 := getRandomSegmentContent(128) - expectSuccess(t, lo.Append(bytes.NewReader([]byte(segment1)), 0, nil)) - expectSuccess(t, lo.Append(bytes.NewReader([]byte(segment2)), 0, nil)) - expectSuccess(t, lo.WriteManifest(nil)) + expectSuccess(t, lo.Append(context.TODO(), bytes.NewReader([]byte(segment1)), 0, nil)) + expectSuccess(t, lo.Append(context.TODO(), bytes.NewReader([]byte(segment2)), 0, nil)) + expectSuccess(t, lo.WriteManifest(context.TODO(), nil)) expectObjectExistence(t, c.Object("segments/0000000000000001"), true) expectObjectExistence(t, c.Object("segments/0000000000000002"), true) // test phase: truncate using AsNewLargeObject - lo, err = obj.AsNewLargeObject(schwift.SegmentingOptions{ + lo, err = obj.AsNewLargeObject(context.TODO(), schwift.SegmentingOptions{ SegmentContainer: c, Strategy: strategy, }, &schwift.TruncateOptions{ DeleteSegments: true, }) expectSuccess(t, err) - expectSuccess(t, lo.Append(bytes.NewReader([]byte(segment1)), 0, nil)) - expectSuccess(t, lo.Append(bytes.NewReader([]byte(segment2)), 0, nil)) - expectSuccess(t, lo.WriteManifest(nil)) + expectSuccess(t, lo.Append(context.TODO(), bytes.NewReader([]byte(segment1)), 0, nil)) + expectSuccess(t, lo.Append(context.TODO(), bytes.NewReader([]byte(segment2)), 0, nil)) + expectSuccess(t, lo.WriteManifest(context.TODO(), nil)) expectObjectExistence(t, c.Object("segments/0000000000000001"), false) expectObjectExistence(t, c.Object("segments/0000000000000002"), false) @@ -216,8 +217,8 @@ func TestTruncateDuringOverwrite(t *testing.T) { func TestOpenRegularObjectAsLargeObject(t *testing.T) { testWithContainer(t, func(c *schwift.Container) { o := c.Object("foo") - expectSuccess(t, o.Upload(bytes.NewReader(objectExampleContent), nil, nil)) - _, err := o.AsLargeObject() + expectSuccess(t, o.Upload(context.TODO(), bytes.NewReader(objectExampleContent), nil, nil)) + _, err := o.AsLargeObject(context.TODO()) expectError(t, err, schwift.ErrNotLarge.Error()) }) } @@ -225,7 +226,7 @@ func TestOpenRegularObjectAsLargeObject(t *testing.T) { func TestSLOWithDataSegment(t *testing.T) { testWithContainer(t, func(c *schwift.Container) { o := c.Object("foo") - lo, err := o.AsNewLargeObject(schwift.SegmentingOptions{ + lo, err := o.AsNewLargeObject(context.TODO(), schwift.SegmentingOptions{ SegmentContainer: c, SegmentPrefix: "segments/", Strategy: schwift.StaticLargeObject, @@ -236,10 +237,10 @@ func TestSLOWithDataSegment(t *testing.T) { dataSegment := schwift.SegmentInfo{Data: []byte("---")} segment2 := getRandomSegmentContent(128) - expectSuccess(t, lo.Append(bytes.NewReader([]byte(segment1)), 0, nil)) + expectSuccess(t, lo.Append(context.TODO(), bytes.NewReader([]byte(segment1)), 0, nil)) expectSuccess(t, lo.AddSegment(dataSegment)) - expectSuccess(t, lo.Append(bytes.NewReader([]byte(segment2)), 0, nil)) - expectSuccess(t, lo.WriteManifest(nil)) + expectSuccess(t, lo.Append(context.TODO(), bytes.NewReader([]byte(segment2)), 0, nil)) + expectSuccess(t, lo.WriteManifest(context.TODO(), nil)) expectObjectContent(t, o, []byte(segment1+string(dataSegment.Data)+segment2)) expectLargeObject(t, o, []schwift.SegmentInfo{ @@ -258,7 +259,7 @@ func TestSLOWithDataSegment(t *testing.T) { // check that truncating this does not try to delete the nil segment.Object // in the data segment - expectSuccess(t, lo.Truncate(&schwift.TruncateOptions{ + expectSuccess(t, lo.Truncate(context.TODO(), &schwift.TruncateOptions{ DeleteSegments: true, })) }) @@ -268,10 +269,10 @@ func TestSLOWithRangeSegments(t *testing.T) { testWithContainer(t, func(c *schwift.Container) { segmentStr := "<aaa>X<bbb>X<ccc>" segmentObj := c.Object("segment") - expectSuccess(t, segmentObj.Upload(bytes.NewReader([]byte(segmentStr)), nil, nil)) + expectSuccess(t, segmentObj.Upload(context.TODO(), bytes.NewReader([]byte(segmentStr)), nil, nil)) o := c.Object("largeobject") - lo, err := o.AsNewLargeObject(schwift.SegmentingOptions{ + lo, err := o.AsNewLargeObject(context.TODO(), schwift.SegmentingOptions{ SegmentContainer: c, SegmentPrefix: "segments/", Strategy: schwift.StaticLargeObject, @@ -293,7 +294,7 @@ func TestSLOWithRangeSegments(t *testing.T) { RangeOffset: -1, RangeLength: 5, })) - expectSuccess(t, lo.WriteManifest(nil)) + expectSuccess(t, lo.WriteManifest(context.TODO(), nil)) expectObjectContent(t, o, []byte( strings.ReplaceAll(segmentStr, "X", ""), @@ -328,7 +329,7 @@ func TestSLOGuessSegmentPrefix(t *testing.T) { obj := c.Object("largeobject") // setup phase: create an SLO - lo, err := obj.AsNewLargeObject(schwift.SegmentingOptions{ + lo, err := obj.AsNewLargeObject(context.TODO(), schwift.SegmentingOptions{ SegmentContainer: c, SegmentPrefix: "foo/bar/baz/", }, nil) @@ -336,12 +337,12 @@ func TestSLOGuessSegmentPrefix(t *testing.T) { segment1 := getRandomSegmentContent(128) segment2 := getRandomSegmentContent(128) - expectSuccess(t, lo.Append(bytes.NewReader([]byte(segment1)), 0, nil)) - expectSuccess(t, lo.Append(bytes.NewReader([]byte(segment2)), 0, nil)) - expectSuccess(t, lo.WriteManifest(nil)) + expectSuccess(t, lo.Append(context.TODO(), bytes.NewReader([]byte(segment1)), 0, nil)) + expectSuccess(t, lo.Append(context.TODO(), bytes.NewReader([]byte(segment2)), 0, nil)) + expectSuccess(t, lo.WriteManifest(context.TODO(), nil)) // now create a fresh SLO and check if it infers the correct SegmentPrefix - lo, err = obj.AsLargeObject() + lo, err = obj.AsLargeObject(context.TODO()) expectSuccess(t, err) expectString(t, lo.SegmentContainer().Name(), c.Name()) expectString(t, lo.SegmentPrefix(), "foo/bar/baz/") @@ -354,7 +355,7 @@ func TestDeleteLargeObjectAndKeepSegments(t *testing.T) { obj := c.Object("largeobject") // setup phase: create a large object - lo, err := obj.AsNewLargeObject(schwift.SegmentingOptions{ + lo, err := obj.AsNewLargeObject(context.TODO(), schwift.SegmentingOptions{ SegmentContainer: c, SegmentPrefix: "foo/bar/baz/", Strategy: strategy, @@ -363,16 +364,16 @@ func TestDeleteLargeObjectAndKeepSegments(t *testing.T) { segment1 := getRandomSegmentContent(128) segment2 := getRandomSegmentContent(128) - expectSuccess(t, lo.Append(bytes.NewReader([]byte(segment1)), 0, nil)) - expectSuccess(t, lo.Append(bytes.NewReader([]byte(segment2)), 0, nil)) - expectSuccess(t, lo.WriteManifest(nil)) + expectSuccess(t, lo.Append(context.TODO(), bytes.NewReader([]byte(segment1)), 0, nil)) + expectSuccess(t, lo.Append(context.TODO(), bytes.NewReader([]byte(segment2)), 0, nil)) + expectSuccess(t, lo.WriteManifest(context.TODO(), nil)) // test deletion that keeps segments - expectSuccess(t, obj.Delete(nil, nil)) + expectSuccess(t, obj.Delete(context.TODO(), nil, nil)) iter := c.Objects() iter.Prefix = lo.SegmentPrefix() - names, err := iter.Collect() + names, err := iter.Collect(context.TODO()) expectSuccess(t, err) expectObjectNames(t, names, "foo/bar/baz/0000000000000001", @@ -387,7 +388,7 @@ func TestDeleteLargeObjectIncludingSegments(t *testing.T) { obj := c.Object("largeobject") // setup phase: create a large object - lo, err := obj.AsNewLargeObject(schwift.SegmentingOptions{ + lo, err := obj.AsNewLargeObject(context.TODO(), schwift.SegmentingOptions{ SegmentContainer: c, SegmentPrefix: "foo/bar/baz/", Strategy: strategy, @@ -396,16 +397,16 @@ func TestDeleteLargeObjectIncludingSegments(t *testing.T) { segment1 := getRandomSegmentContent(128) segment2 := getRandomSegmentContent(128) - expectSuccess(t, lo.Append(bytes.NewReader([]byte(segment1)), 0, nil)) - expectSuccess(t, lo.Append(bytes.NewReader([]byte(segment2)), 0, nil)) - expectSuccess(t, lo.WriteManifest(nil)) + expectSuccess(t, lo.Append(context.TODO(), bytes.NewReader([]byte(segment1)), 0, nil)) + expectSuccess(t, lo.Append(context.TODO(), bytes.NewReader([]byte(segment2)), 0, nil)) + expectSuccess(t, lo.WriteManifest(context.TODO(), nil)) // test deletion that keeps segments - expectSuccess(t, obj.Delete(&schwift.DeleteOptions{DeleteSegments: true}, nil)) + expectSuccess(t, obj.Delete(context.TODO(), &schwift.DeleteOptions{DeleteSegments: true}, nil)) iter := c.Objects() iter.Prefix = lo.SegmentPrefix() - names, err := iter.Collect() + names, err := iter.Collect(context.TODO()) expectSuccess(t, err) expectObjectNames(t, names) }) @@ -418,7 +419,7 @@ func TestOverwriteLargeObjectAndKeepSegments(t *testing.T) { obj := c.Object("largeobject") // setup phase: create a large object - lo, err := obj.AsNewLargeObject(schwift.SegmentingOptions{ + lo, err := obj.AsNewLargeObject(context.TODO(), schwift.SegmentingOptions{ SegmentContainer: c, SegmentPrefix: "foo/bar/baz/", Strategy: strategy, @@ -427,16 +428,16 @@ func TestOverwriteLargeObjectAndKeepSegments(t *testing.T) { segment1 := getRandomSegmentContent(128) segment2 := getRandomSegmentContent(128) - expectSuccess(t, lo.Append(bytes.NewReader([]byte(segment1)), 0, nil)) - expectSuccess(t, lo.Append(bytes.NewReader([]byte(segment2)), 0, nil)) - expectSuccess(t, lo.WriteManifest(nil)) + expectSuccess(t, lo.Append(context.TODO(), bytes.NewReader([]byte(segment1)), 0, nil)) + expectSuccess(t, lo.Append(context.TODO(), bytes.NewReader([]byte(segment2)), 0, nil)) + expectSuccess(t, lo.WriteManifest(context.TODO(), nil)) // test overwriting that keeps segments - expectSuccess(t, obj.Upload(bytes.NewReader(objectExampleContent), nil, nil)) + expectSuccess(t, obj.Upload(context.TODO(), bytes.NewReader(objectExampleContent), nil, nil)) iter := c.Objects() iter.Prefix = lo.SegmentPrefix() - names, err := iter.Collect() + names, err := iter.Collect(context.TODO()) expectSuccess(t, err) expectObjectNames(t, names, "foo/bar/baz/0000000000000001", @@ -451,7 +452,7 @@ func TestOverwriteLargeObjectIncludingSegments(t *testing.T) { obj := c.Object("largeobject") // setup phase: create a large object - lo, err := obj.AsNewLargeObject(schwift.SegmentingOptions{ + lo, err := obj.AsNewLargeObject(context.TODO(), schwift.SegmentingOptions{ SegmentContainer: c, SegmentPrefix: "foo/bar/baz/", Strategy: strategy, @@ -460,12 +461,13 @@ func TestOverwriteLargeObjectIncludingSegments(t *testing.T) { segment1 := getRandomSegmentContent(128) segment2 := getRandomSegmentContent(128) - expectSuccess(t, lo.Append(bytes.NewReader([]byte(segment1)), 0, nil)) - expectSuccess(t, lo.Append(bytes.NewReader([]byte(segment2)), 0, nil)) - expectSuccess(t, lo.WriteManifest(nil)) + expectSuccess(t, lo.Append(context.TODO(), bytes.NewReader([]byte(segment1)), 0, nil)) + expectSuccess(t, lo.Append(context.TODO(), bytes.NewReader([]byte(segment2)), 0, nil)) + expectSuccess(t, lo.WriteManifest(context.TODO(), nil)) // test overwriting that deletes segments expectSuccess(t, obj.Upload( + context.TODO(), bytes.NewReader(objectExampleContent), &schwift.UploadOptions{DeleteSegments: true}, nil, @@ -473,12 +475,13 @@ func TestOverwriteLargeObjectIncludingSegments(t *testing.T) { iter := c.Objects() iter.Prefix = lo.SegmentPrefix() - names, err := iter.Collect() + names, err := iter.Collect(context.TODO()) expectSuccess(t, err) expectObjectNames(t, names) // test overwriting that wants to delete segments, but there aren't any expectSuccess(t, obj.Upload( + context.TODO(), bytes.NewReader(objectExampleContent), &schwift.UploadOptions{DeleteSegments: true}, nil, @@ -486,6 +489,7 @@ func TestOverwriteLargeObjectIncludingSegments(t *testing.T) { // while we're at it, test the same for deletion expectSuccess(t, obj.Delete( + context.TODO(), &schwift.DeleteOptions{DeleteSegments: true}, nil, )) @@ -497,7 +501,7 @@ func TestAddInvalidSegments(t *testing.T) { foreachLargeObjectStrategy(func(strategy schwift.LargeObjectStrategy, strategyStr string) { testWithContainer(t, func(c *schwift.Container) { obj := c.Object("largeobject") - lo, err := obj.AsNewLargeObject(schwift.SegmentingOptions{ + lo, err := obj.AsNewLargeObject(context.TODO(), schwift.SegmentingOptions{ SegmentContainer: c, Strategy: strategy, }, nil) @@ -566,7 +570,7 @@ func TestAddInvalidSegments(t *testing.T) { func expectLargeObject(t *testing.T, obj *schwift.Object, expected []schwift.SegmentInfo) { t.Helper() expectObjectExistence(t, obj, true) - lo, err := obj.AsLargeObject() + lo, err := obj.AsLargeObject(context.TODO()) expectSuccess(t, err) if lo == nil { t.FailNow() diff --git a/tests/object_iterator_test.go b/tests/object_iterator_test.go index 2f9143d..b997562 100644 --- a/tests/object_iterator_test.go +++ b/tests/object_iterator_test.go @@ -20,6 +20,7 @@ package tests import ( "bytes" + "context" "fmt" "strings" "testing" @@ -40,52 +41,52 @@ func TestObjectIterator(t *testing.T) { for idx := 1; idx <= 4; idx++ { hdr := schwift.NewObjectHeaders() hdr.ContentType().Set("application/json") - err := c.Object(oname(idx)).Upload(bytes.NewReader(objectExampleContent), nil, hdr.ToOpts()) + err := c.Object(oname(idx)).Upload(context.TODO(), bytes.NewReader(objectExampleContent), nil, hdr.ToOpts()) expectSuccess(t, err) } // test iteration with empty last page iter := c.Objects() iter.Prefix = "schwift-test-listing" - os, err := iter.NextPage(2) + os, err := iter.NextPage(context.TODO(), 2) expectSuccess(t, err) expectObjectNames(t, os, oname(1), oname(2)) - os, err = iter.NextPage(2) + os, err = iter.NextPage(context.TODO(), 2) expectSuccess(t, err) expectObjectNames(t, os, oname(3), oname(4)) - os, err = iter.NextPage(2) + os, err = iter.NextPage(context.TODO(), 2) expectSuccess(t, err) expectObjectNames(t, os) - os, err = iter.NextPage(2) + os, err = iter.NextPage(context.TODO(), 2) expectSuccess(t, err) expectObjectNames(t, os) // test iteration with partial last page iter = c.Objects() iter.Prefix = "schwift-test-listing" - os, err = iter.NextPage(3) + os, err = iter.NextPage(context.TODO(), 3) expectSuccess(t, err) expectObjectNames(t, os, oname(1), oname(2), oname(3)) - os, err = iter.NextPage(3) + os, err = iter.NextPage(context.TODO(), 3) expectSuccess(t, err) expectObjectNames(t, os, oname(4)) - os, err = iter.NextPage(4) + os, err = iter.NextPage(context.TODO(), 4) expectSuccess(t, err) expectObjectNames(t, os) // test detailed iteration iter = c.Objects() iter.Prefix = "schwift-test-listing" - ois, err := iter.NextPageDetailed(2) + ois, err := iter.NextPageDetailed(context.TODO(), 2) expectSuccess(t, err) expectObjectInfos(t, ois, oname(1), oname(2)) - ois, err = iter.NextPageDetailed(3) + ois, err = iter.NextPageDetailed(context.TODO(), 3) expectSuccess(t, err) expectObjectInfos(t, ois, oname(3), oname(4)) - ois, err = iter.NextPageDetailed(3) + ois, err = iter.NextPageDetailed(context.TODO(), 3) expectSuccess(t, err) expectObjectInfos(t, ois) - ois, err = iter.NextPageDetailed(3) + ois, err = iter.NextPageDetailed(context.TODO(), 3) expectSuccess(t, err) expectObjectInfos(t, ois) @@ -94,7 +95,7 @@ func TestObjectIterator(t *testing.T) { iter = c.Objects() iter.Prefix = "schwift-test-listing" idx := 0 - expectSuccess(t, iter.Foreach(func(o *schwift.Object) error { + expectSuccess(t, iter.Foreach(context.TODO(), func(o *schwift.Object) error { idx++ expectString(t, o.Name(), oname(idx)) return nil @@ -107,7 +108,7 @@ func TestObjectIterator(t *testing.T) { iter = c.Objects() iter.Prefix = "schwift-test-listing" idx = 0 - expectSuccess(t, iter.ForeachDetailed(func(info schwift.ObjectInfo) error { + expectSuccess(t, iter.ForeachDetailed(context.TODO(), func(info schwift.ObjectInfo) error { idx++ expectString(t, info.Object.Name(), oname(idx)) return nil @@ -118,14 +119,14 @@ func TestObjectIterator(t *testing.T) { // test Collect iter = c.Objects() iter.Prefix = "schwift-test-listing" - os, err = iter.Collect() + os, err = iter.Collect(context.TODO()) expectSuccess(t, err) expectObjectNames(t, os, oname(1), oname(2), oname(3), oname(4)) // test CollectDetailed iter = c.Objects() iter.Prefix = "schwift-test-listing" - ois, err = iter.CollectDetailed() + ois, err = iter.CollectDetailed(context.TODO()) expectSuccess(t, err) expectObjectInfos(t, ois, oname(1), oname(2), oname(3), oname(4)) }) @@ -146,20 +147,20 @@ func TestPseudoDirectories(t *testing.T) { for _, name := range objectNames { hdr := schwift.NewObjectHeaders() hdr.ContentType().Set("application/json") - err := c.Object(name).Upload(bytes.NewReader(objectExampleContent), nil, hdr.ToOpts()) + err := c.Object(name).Upload(context.TODO(), bytes.NewReader(objectExampleContent), nil, hdr.ToOpts()) expectSuccess(t, err) } // test iteration with Delimiter and no Prefix iter := c.Objects() iter.Delimiter = "/" - os, err := iter.Collect() + os, err := iter.Collect(context.TODO()) expectSuccess(t, err) expectObjectNames(t, os, "foo/") iter = c.Objects() iter.Delimiter = "/" - ois, err := iter.CollectDetailed() + ois, err := iter.CollectDetailed(context.TODO()) expectSuccess(t, err) expectObjectInfos(t, ois, "subdir:foo/") @@ -167,14 +168,14 @@ func TestPseudoDirectories(t *testing.T) { iter = c.Objects() iter.Prefix = "foo/" iter.Delimiter = "/" - os, err = iter.Collect() + os, err = iter.Collect(context.TODO()) expectSuccess(t, err) expectObjectNames(t, os, "foo/1", "foo/2", "foo/3", "foo/bar", "foo/bar/") iter = c.Objects() iter.Prefix = "foo/" iter.Delimiter = "/" - ois, err = iter.CollectDetailed() + ois, err = iter.CollectDetailed(context.TODO()) expectSuccess(t, err) expectObjectInfos(t, ois, "foo/1", "foo/2", "foo/3", "foo/bar", "subdir:foo/bar/") }) @@ -190,20 +191,20 @@ func TestObjectIteratorWithSymlinks(t *testing.T) { for _, name := range objectNames { hdr := schwift.NewObjectHeaders() hdr.ContentType().Set("application/json") - err := c.Object(name).Upload(bytes.NewReader(objectExampleContent), nil, hdr.ToOpts()) + err := c.Object(name).Upload(context.TODO(), bytes.NewReader(objectExampleContent), nil, hdr.ToOpts()) expectSuccess(t, err) } // create a test symlink - expectSuccess(t, c.Object("foo/2").SymlinkTo(c.Object("foo/1"), nil, nil)) + expectSuccess(t, c.Object("foo/2").SymlinkTo(context.TODO(), c.Object("foo/1"), nil, nil)) iter := c.Objects() - os, err := iter.Collect() + os, err := iter.Collect(context.TODO()) expectSuccess(t, err) expectObjectNames(t, os, "foo/1", "foo/2", "foo/3") iter = c.Objects() - ois, err := iter.CollectDetailed() + ois, err := iter.CollectDetailed(context.TODO()) expectSuccess(t, err) expectObjectInfos(t, ois, "foo/1", "symlink:foo/2>foo/1", "foo/3") }) @@ -211,7 +212,7 @@ func TestObjectIteratorWithSymlinks(t *testing.T) { func expectContainerHeadersCached(t *testing.T, c *schwift.Container) { requestCountBefore := c.Account().Backend().(*RequestCountingBackend).Count - _, err := c.Headers() + _, err := c.Headers(context.TODO()) expectSuccess(t, err) requestCountAfter := c.Account().Backend().(*RequestCountingBackend).Count diff --git a/tests/object_test.go b/tests/object_test.go index 81925d6..18c78f7 100644 --- a/tests/object_test.go +++ b/tests/object_test.go @@ -20,6 +20,7 @@ package tests import ( "bytes" + "context" "fmt" "io" "net/http" @@ -41,22 +42,22 @@ func TestObjectLifecycle(t *testing.T) { } expectObjectExistence(t, o, false) - _, err := o.Headers() + _, err := o.Headers(context.TODO()) expectError(t, err, fmt.Sprintf("could not HEAD %q in Swift: expected 200 response, got 404 instead", o.FullName())) expectBool(t, schwift.Is(err, http.StatusNotFound), true) expectBool(t, schwift.Is(err, http.StatusNoContent), false) // DELETE should be idempotent and not return success on non-existence, but // OpenStack LOVES to be inconsistent with everything (including, notably, itself) - err = o.Delete(nil, nil) + err = o.Delete(context.TODO(), nil, nil) expectError(t, err, fmt.Sprintf("could not DELETE %q in Swift: expected 204 response, got 404 instead: <html><h1>Not Found</h1><p>The resource could not be found.</p></html>", o.FullName())) - err = o.Upload(bytes.NewReader([]byte("test")), nil, nil) + err = o.Upload(context.TODO(), bytes.NewReader([]byte("test")), nil, nil) expectSuccess(t, err) expectObjectExistence(t, o, true) - err = o.Delete(nil, nil) + err = o.Delete(context.TODO(), nil, nil) expectSuccess(t, err) }) } @@ -65,31 +66,31 @@ func TestObjectUpload(t *testing.T) { testWithContainer(t, func(c *schwift.Container) { // test upload with bytes.Reader obj := c.Object("upload1") - err := obj.Upload(bytes.NewReader(objectExampleContent), nil, nil) + err := obj.Upload(context.TODO(), bytes.NewReader(objectExampleContent), nil, nil) expectSuccess(t, err) expectObjectContent(t, obj, objectExampleContent) // test upload with bytes.Buffer obj = c.Object("upload2") - err = obj.Upload(bytes.NewBuffer(objectExampleContent), nil, nil) + err = obj.Upload(context.TODO(), bytes.NewBuffer(objectExampleContent), nil, nil) expectSuccess(t, err) expectObjectContent(t, obj, objectExampleContent) // test upload with strings.Reader obj = c.Object("upload3") - err = obj.Upload(strings.NewReader(string(objectExampleContent)), nil, nil) + err = obj.Upload(context.TODO(), strings.NewReader(string(objectExampleContent)), nil, nil) expectSuccess(t, err) expectObjectContent(t, obj, objectExampleContent) // test upload with opaque io.Reader obj = c.Object("upload4") - err = obj.Upload(opaqueReader{bytes.NewReader(objectExampleContent)}, nil, nil) + err = obj.Upload(context.TODO(), opaqueReader{bytes.NewReader(objectExampleContent)}, nil, nil) expectSuccess(t, err) expectObjectContent(t, obj, objectExampleContent) // test upload with io.Writer obj = c.Object("upload5") - err = obj.UploadFromWriter(nil, nil, func(w io.Writer) error { + err = obj.UploadFromWriter(context.TODO(), nil, nil, func(w io.Writer) error { _, err := w.Write(objectExampleContent) return err }) @@ -98,13 +99,13 @@ func TestObjectUpload(t *testing.T) { // test upload with empty reader (should create zero-byte-sized object) obj = c.Object("upload6") - err = obj.Upload(eofReader{}, nil, nil) + err = obj.Upload(context.TODO(), eofReader{}, nil, nil) expectSuccess(t, err) expectObjectContent(t, obj, nil) // test upload without reader (should create zero-byte-sized object) obj = c.Object("upload7") - err = obj.Upload(nil, nil, nil) + err = obj.Upload(context.TODO(), nil, nil, nil) expectSuccess(t, err) expectObjectContent(t, obj, nil) }) @@ -128,21 +129,21 @@ func TestObjectDownload(t *testing.T) { testWithContainer(t, func(c *schwift.Container) { // upload example object obj := c.Object("example") - err := obj.Upload(bytes.NewReader(objectExampleContent), nil, nil) + err := obj.Upload(context.TODO(), bytes.NewReader(objectExampleContent), nil, nil) expectSuccess(t, err) // test download as string - str, err := obj.Download(nil).AsString() + str, err := obj.Download(context.TODO(), nil).AsString() expectSuccess(t, err) expectString(t, str, string(objectExampleContent)) // test download as byte slice - buf, err := obj.Download(nil).AsByteSlice() + buf, err := obj.Download(context.TODO(), nil).AsByteSlice() expectSuccess(t, err) expectString(t, string(buf), string(objectExampleContent)) // test download as io.ReadCloser slice - reader, err := obj.Download(nil).AsReadCloser() + reader, err := obj.Download(context.TODO(), nil).AsReadCloser() expectSuccess(t, err) buf = make([]byte, 4) _, err = reader.Read(buf) @@ -164,23 +165,23 @@ func TestObjectUpdate(t *testing.T) { // test that metadata update fails for non-existing object newHeaders := schwift.NewObjectHeaders() newHeaders.ContentType().Set("application/json") - err := obj.Update(newHeaders, nil) + err := obj.Update(context.TODO(), newHeaders, nil) expectBool(t, schwift.Is(err, http.StatusNotFound), true) expectError(t, err, fmt.Sprintf("could not POST %q in Swift: expected 202 response, got 404 instead: <html><h1>Not Found</h1><p>The resource could not be found.</p></html>", obj.FullName())) // create object - err = obj.Upload(nil, nil, nil) + err = obj.Upload(context.TODO(), nil, nil, nil) expectSuccess(t, err) - hdr, err := obj.Headers() + hdr, err := obj.Headers(context.TODO()) expectSuccess(t, err) expectString(t, hdr.ContentType().Get(), "application/octet-stream") // now the metadata update should work - err = obj.Update(newHeaders, nil) + err = obj.Update(context.TODO(), newHeaders, nil) expectSuccess(t, err) obj.Invalidate() - hdr, err = obj.Headers() + hdr, err = obj.Headers(context.TODO()) expectSuccess(t, err) expectString(t, hdr.ContentType().Get(), "application/json") }) @@ -189,12 +190,12 @@ func TestObjectUpdate(t *testing.T) { func TestObjectCopy(t *testing.T) { testWithContainer(t, func(c *schwift.Container) { obj1 := c.Object("location1") - err := obj1.Upload(bytes.NewReader(objectExampleContent), nil, nil) + err := obj1.Upload(context.TODO(), bytes.NewReader(objectExampleContent), nil, nil) expectSuccess(t, err) expectObjectExistence(t, obj1, true) obj2 := c.Object("location2") - expectSuccess(t, obj1.CopyTo(obj2, nil, nil)) + expectSuccess(t, obj1.CopyTo(context.TODO(), obj2, nil, nil)) expectObjectExistence(t, obj1, true) expectObjectExistence(t, obj2, true) expectObjectContent(t, obj2, objectExampleContent) @@ -205,39 +206,39 @@ func TestSymlinkOperations(t *testing.T) { testWithContainer(t, func(c *schwift.Container) { // create a test object that we can link to obj1 := c.Object("target") - err := obj1.Upload(bytes.NewReader(objectExampleContent), nil, nil) + err := obj1.Upload(context.TODO(), bytes.NewReader(objectExampleContent), nil, nil) expectSuccess(t, err) expectObjectExistence(t, obj1, true) // create a symlink obj2 := c.Object("symlink") - expectSuccess(t, obj2.SymlinkTo(obj1, nil, nil)) + expectSuccess(t, obj2.SymlinkTo(context.TODO(), obj1, nil, nil)) expectObjectExistence(t, obj2, true) expectObjectSymlink(t, obj2, obj1) expectObjectContent(t, obj2, objectExampleContent) // overwrite symlink with normal object otherContent := []byte("abc") - expectSuccess(t, obj2.Upload(bytes.NewReader(otherContent), nil, nil)) + expectSuccess(t, obj2.Upload(context.TODO(), bytes.NewReader(otherContent), nil, nil)) expectObjectExistence(t, obj2, true) expectObjectSymlink(t, obj2, nil) expectObjectContent(t, obj2, otherContent) // overwrite normal object with symlink - expectSuccess(t, obj2.SymlinkTo(obj1, nil, nil)) + expectSuccess(t, obj2.SymlinkTo(context.TODO(), obj1, nil, nil)) expectObjectExistence(t, obj2, true) expectObjectSymlink(t, obj2, obj1) expectObjectContent(t, obj2, objectExampleContent) // deep-copy symlink obj3 := c.Object("copy") - expectSuccess(t, obj2.CopyTo(obj3, nil, nil)) + expectSuccess(t, obj2.CopyTo(context.TODO(), obj3, nil, nil)) expectObjectExistence(t, obj3, true) expectObjectSymlink(t, obj3, nil) expectObjectContent(t, obj3, objectExampleContent) // shallow-copy symlink - expectSuccess(t, obj2.CopyTo(obj3, &schwift.CopyOptions{ + expectSuccess(t, obj2.CopyTo(context.TODO(), obj3, &schwift.CopyOptions{ ShallowCopySymlinks: true, }, nil)) expectObjectExistence(t, obj3, true) @@ -245,7 +246,7 @@ func TestSymlinkOperations(t *testing.T) { expectObjectContent(t, obj3, objectExampleContent) // delete symlink - expectSuccess(t, obj2.Delete(nil, nil)) + expectSuccess(t, obj2.Delete(context.TODO(), nil, nil)) expectObjectExistence(t, obj2, false) }) } @@ -256,18 +257,18 @@ func TestSymlinkOperations(t *testing.T) { func expectObjectExistence(t *testing.T, obj *schwift.Object, expectedExists bool) { t.Helper() obj.Invalidate() - actualExists, err := obj.Exists() + actualExists, err := obj.Exists(context.TODO()) expectSuccess(t, err) expectBool(t, actualExists, expectedExists) } func expectObjectContent(t *testing.T, obj *schwift.Object, expected []byte) { t.Helper() - str, err := obj.Download(nil).AsString() + str, err := obj.Download(context.TODO(), nil).AsString() expectSuccess(t, err) expectString(t, str, string(expected)) obj.Invalidate() - hdr, err := obj.Headers() + hdr, err := obj.Headers(context.TODO()) expectSuccess(t, err) if !hdr.IsLargeObject() { expectString(t, hdr.Etag().Get(), etagOf(expected)) @@ -276,7 +277,7 @@ func expectObjectContent(t *testing.T, obj *schwift.Object, expected []byte) { func expectObjectSymlink(t *testing.T, source, expectedTarget *schwift.Object) { t.Helper() - _, target, err := source.SymlinkHeaders() + _, target, err := source.SymlinkHeaders(context.TODO()) if expectedTarget == nil { switch err { case nil: diff --git a/tests/shared_test.go b/tests/shared_test.go index a3ef610..1154b83 100644 --- a/tests/shared_test.go +++ b/tests/shared_test.go @@ -87,19 +87,19 @@ func testWithAccount(t *testing.T, testCode func(a *schwift.Account)) { func testWithContainer(t *testing.T, testCode func(c *schwift.Container)) { testWithAccount(t, func(a *schwift.Account) { containerName := getRandomName() - container, err := a.Container(containerName).EnsureExists() + container, err := a.Container(containerName).EnsureExists(context.TODO()) expectSuccess(t, err) testCode(container) // cleanup - exists, err := container.Exists() + exists, err := container.Exists(context.TODO()) expectSuccess(t, err) if exists { - expectSuccess(t, container.Objects().Foreach(func(o *schwift.Object) error { - return o.Delete(nil, nil) + expectSuccess(t, container.Objects().Foreach(context.TODO(), func(o *schwift.Object) error { + return o.Delete(context.TODO(), nil, nil) })) - err = container.Delete(nil) + err = container.Delete(context.TODO(), nil) expectSuccess(t, err) } }) |
