aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--account.go12
-rw-r--r--bulk.go21
-rw-r--r--container.go25
-rw-r--r--container_iterator.go25
-rw-r--r--iterator.go9
-rw-r--r--largeobject.go47
-rw-r--r--object.go55
-rw-r--r--object_iterator.go25
-rw-r--r--request.go9
-rw-r--r--tests/account_test.go15
-rw-r--r--tests/bulk_delete_test.go13
-rw-r--r--tests/bulk_upload_test.go4
-rw-r--r--tests/container_iterator_test.go39
-rw-r--r--tests/container_test.go21
-rw-r--r--tests/field_test.go7
-rw-r--r--tests/largeobject_test.go134
-rw-r--r--tests/object_iterator_test.go53
-rw-r--r--tests/object_test.go67
-rw-r--r--tests/shared_test.go10
19 files changed, 304 insertions, 287 deletions
diff --git a/account.go b/account.go
index cdccc78..3b37b17 100644
--- a/account.go
+++ b/account.go
@@ -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()
diff --git a/bulk.go b/bulk.go
index e0d3f0b..f345345 100644
--- a/bulk.go
+++ b/bulk.go
@@ -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)
}
diff --git a/object.go b/object.go
index b32c412..1658273 100644
--- a/object.go
+++ b/object.go
@@ -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
}
diff --git a/request.go b/request.go
index aad08ea..ce9e8ac 100644
--- a/request.go
+++ b/request.go
@@ -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)
}
})