New Upstream Snapshot - golang-github-ncw-swift
Ready changes
Summary
Merged new upstream version: 2.0.1 (was: 1.0.53).
Resulting package
Built on 2022-11-29T03:44 (took 4m34s)
The resulting binary packages can be installed (if you have the apt repository enabled) by running one of:
apt install -t fresh-snapshots golang-github-ncw-swift-dev
Lintian Result
Diff
diff --git a/.gitignore b/.gitignore
deleted file mode 100644
index 5cdbab7..0000000
--- a/.gitignore
+++ /dev/null
@@ -1,4 +0,0 @@
-*~
-*.pyc
-test-env*
-junk/
\ No newline at end of file
diff --git a/.golangci.yml b/.golangci.yml
new file mode 100644
index 0000000..a477186
--- /dev/null
+++ b/.golangci.yml
@@ -0,0 +1,24 @@
+# golangci-lint configuration options
+
+linters:
+ enable:
+ - deadcode
+ - errcheck
+ - goimports
+ # - revive
+ - ineffassign
+ - structcheck
+ - varcheck
+ - govet
+ - unconvert
+ disable-all: true
+
+issues:
+ # Enable some lints excluded by default
+ exclude-use-default: false
+
+ # Maximum issues count per one linter. Set to 0 to disable. Default is 50.
+ max-per-linter: 0
+
+ # Maximum count of issues with the same text. Set to 0 to disable. Default is 3.
+ max-same-issues: 0
diff --git a/.travis.yml b/.travis.yml
deleted file mode 100644
index 72364ac..0000000
--- a/.travis.yml
+++ /dev/null
@@ -1,61 +0,0 @@
-language: go
-sudo: false
-
-arch:
- - amd64
- - ppc64le
-
-go_import_path: github.com/ncw/swift
-
-go:
- - 1.2.x
- - 1.3.x
- - 1.4.x
- - 1.5.x
- - 1.6.x
- - 1.7.x
- - 1.8.x
- - 1.9.x
- - 1.10.x
- - 1.11.x
- - 1.12.x
- - 1.13.x
- - 1.14.x
- - master
-
-matrix:
- include:
- - go: 1.14.x
- env: TEST_REAL_SERVER=rackspace
- - go: 1.14.x
- env: TEST_REAL_SERVER=memset
- - go: 1.14.x
- arch: ppc64le
- env: TEST_REAL_SERVER=rackspace
- - go: 1.14.x
- arch: ppc64le
- env: TEST_REAL_SERVER=memset
- allow_failures:
- - go: 1.14.x
- env: TEST_REAL_SERVER=rackspace
- - go: 1.14.x
- env: TEST_REAL_SERVER=memset
- - go: 1.14.x
- arch: ppc64le
- env: TEST_REAL_SERVER=rackspace
- - go: 1.14.x
- arch: ppc64le
- env: TEST_REAL_SERVER=memset
-# Removed unsupported jobs for ppc64le
- exclude:
- - go: 1.2.x
- arch: ppc64le
- - go: 1.3.x
- arch: ppc64le
- - go: 1.4.x
- arch: ppc64le
-install: go test -i ./...
-script:
- - test -z "$(go fmt ./...)"
- - go test
- - ./travis_realserver.sh
diff --git a/README.md b/README.md
index 1965f73..daa6412 100644
--- a/README.md
+++ b/README.md
@@ -1,46 +1,43 @@
Swift
=====
-This package provides an easy to use library for interfacing with
-Swift / Openstack Object Storage / Rackspace cloud files from the Go
-Language
+This package provides an easy to use library for interfacing with Swift / Openstack Object Storage / Rackspace cloud
+files from the Go Language
-See here for package docs
-
- http://godoc.org/github.com/ncw/swift
-
-[![Build Status](https://api.travis-ci.org/ncw/swift.svg?branch=master)](https://travis-ci.org/ncw/swift) [![GoDoc](https://godoc.org/github.com/ncw/swift?status.svg)](https://godoc.org/github.com/ncw/swift)
+[![Build Status](https://github.com/ncw/swift/workflows/build/badge.svg?branch=master)](https://github.com/ncw/swift/actions)
+[![Go Reference](https://pkg.go.dev/badge/github.com/ncw/v2/swift.svg)](https://pkg.go.dev/github.com/ncw/swift/v2)
Install
-------
Use go to install the library
- go get github.com/ncw/swift
+ go get github.com/ncw/swift/v2
Usage
-----
See here for full package docs
-- http://godoc.org/github.com/ncw/swift
+- https://pkg.go.dev/github.com/ncw/swift/v2
Here is a short example from the docs
+
```go
-import "github.com/ncw/swift"
+import "github.com/ncw/swift/v2"
// Create a connection
c := swift.Connection{
- UserName: "user",
- ApiKey: "key",
- AuthUrl: "auth_url",
- Domain: "domain", // Name of the domain (v3 auth only)
- Tenant: "tenant", // Name of the tenant (v2 auth only)
+UserName: "user",
+ApiKey: "key",
+AuthUrl: "auth_url",
+Domain: "domain", // Name of the domain (v3 auth only)
+Tenant: "tenant", // Name of the tenant (v2 auth only)
}
// Authenticate
err := c.Authenticate()
if err != nil {
- panic(err)
+panic(err)
}
// List all the containers
containers, err := c.ContainerNames(nil)
@@ -48,6 +45,14 @@ fmt.Println(containers)
// etc...
```
+Migrating from `v1`
+-----
+The library has current major version v2. If you want to migrate from the first version of
+library `github.com/ncw/swift` you have to explicitly add the `/v2` suffix to the imports.
+
+Most of the exported functions were added a new `context.Context` parameter in the `v2`, which you will have to provide
+when migrating.
+
Additions
---------
@@ -56,11 +61,10 @@ The `rs` sub project contains a wrapper for the Rackspace specific CDN Managemen
Testing
-------
-To run the tests you can either use an embedded fake Swift server
-either use a real Openstack Swift server or a Rackspace Cloud files account.
+To run the tests you can either use an embedded fake Swift server either use a real Openstack Swift server or a
+Rackspace Cloud files account.
-When using a real Swift server, you need to set these environment variables
-before running the tests
+When using a real Swift server, you need to set these environment variables before running the tests
export SWIFT_API_USER='user'
export SWIFT_API_KEY='key'
@@ -99,8 +103,7 @@ Then run the tests with `go test`
License
-------
-This is free software under the terms of MIT license (check COPYING file
-included in this package).
+This is free software under the terms of MIT license (check COPYING file included in this package).
Contact and support
-------------------
@@ -161,3 +164,8 @@ Contributors
- Brandon WELSCH <dev@brandon-welsch.eu>
- Damien Tournoud <damien@platform.sh>
- Pedro Kiefer <pedro@kiefer.com.br>
+- Martin Chodur <m.chodur@seznam.cz>
+- Devendra <devendranath.thadi3@gmail.com>
+- timss <timsateroy@gmail.com>
+- Jos Houtman <jos@houtman.it>
+- Paul Collins <paul.collins@canonical.com>
diff --git a/auth.go b/auth.go
index 25654f4..ec56cc6 100644
--- a/auth.go
+++ b/auth.go
@@ -2,6 +2,7 @@ package swift
import (
"bytes"
+ "context"
"encoding/json"
"net/http"
"net/url"
@@ -14,9 +15,9 @@ import (
// This encapsulates the different authentication schemes in use
type Authenticator interface {
// Request creates an http.Request for the auth - return nil if not needed
- Request(*Connection) (*http.Request, error)
+ Request(context.Context, *Connection) (*http.Request, error)
// Response parses the http.Response
- Response(resp *http.Response) error
+ Response(ctx context.Context, resp *http.Response) error
// The public storage URL - set Internal to true to read
// internal/service net URL
StorageUrl(Internal bool) string
@@ -88,8 +89,8 @@ type v1Auth struct {
}
// v1 Authentication - make request
-func (auth *v1Auth) Request(c *Connection) (*http.Request, error) {
- req, err := http.NewRequest("GET", c.AuthUrl, nil)
+func (auth *v1Auth) Request(ctx context.Context, c *Connection) (*http.Request, error) {
+ req, err := http.NewRequestWithContext(ctx, "GET", c.AuthUrl, nil)
if err != nil {
return nil, err
}
@@ -100,7 +101,7 @@ func (auth *v1Auth) Request(c *Connection) (*http.Request, error) {
}
// v1 Authentication - read response
-func (auth *v1Auth) Response(resp *http.Response) error {
+func (auth *v1Auth) Response(_ context.Context, resp *http.Response) error {
auth.Headers = resp.Header
return nil
}
@@ -141,7 +142,7 @@ type v2Auth struct {
}
// v2 Authentication - make request
-func (auth *v2Auth) Request(c *Connection) (*http.Request, error) {
+func (auth *v2Auth) Request(ctx context.Context, c *Connection) (*http.Request, error) {
auth.Region = c.Region
// Toggle useApiKey if not first run and not OK yet
if auth.notFirst && !auth.useApiKeyOk {
@@ -176,7 +177,7 @@ func (auth *v2Auth) Request(c *Connection) (*http.Request, error) {
url += "/"
}
url += "tokens"
- req, err := http.NewRequest("POST", url, bytes.NewBuffer(body))
+ req, err := http.NewRequestWithContext(ctx, "POST", url, bytes.NewBuffer(body))
if err != nil {
return nil, err
}
@@ -186,7 +187,7 @@ func (auth *v2Auth) Request(c *Connection) (*http.Request, error) {
}
// v2 Authentication - read response
-func (auth *v2Auth) Response(resp *http.Response) error {
+func (auth *v2Auth) Response(_ context.Context, resp *http.Response) error {
auth.Auth = new(v2AuthResponse)
err := readJson(resp, auth.Auth)
// If successfully read Auth then no need to toggle useApiKey any more
diff --git a/auth_v3.go b/auth_v3.go
index 1e34ad8..89840d7 100644
--- a/auth_v3.go
+++ b/auth_v3.go
@@ -2,6 +2,7 @@ package swift
import (
"bytes"
+ "context"
"encoding/json"
"fmt"
"net/http"
@@ -13,7 +14,6 @@ const (
v3AuthMethodToken = "token"
v3AuthMethodPassword = "password"
v3AuthMethodApplicationCredential = "application_credential"
- v3CatalogTypeObjectStore = "object-store"
)
// V3 Authentication request
@@ -122,7 +122,7 @@ type v3Auth struct {
Headers http.Header
}
-func (auth *v3Auth) Request(c *Connection) (*http.Request, error) {
+func (auth *v3Auth) Request(ctx context.Context, c *Connection) (*http.Request, error) {
auth.Region = c.Region
var v3i interface{}
@@ -242,7 +242,7 @@ func (auth *v3Auth) Request(c *Connection) (*http.Request, error) {
url += "/"
}
url += "auth/tokens"
- req, err := http.NewRequest("POST", url, bytes.NewBuffer(body))
+ req, err := http.NewRequestWithContext(ctx, "POST", url, bytes.NewBuffer(body))
if err != nil {
return nil, err
}
@@ -251,7 +251,7 @@ func (auth *v3Auth) Request(c *Connection) (*http.Request, error) {
return req, nil
}
-func (auth *v3Auth) Response(resp *http.Response) error {
+func (auth *v3Auth) Response(_ context.Context, resp *http.Response) error {
auth.Auth = &v3AuthResponse{}
auth.Headers = resp.Header
err := readJson(resp, auth.Auth)
diff --git a/bin/update-authors.py b/bin/update-authors.py
index 2e10312..5df3e05 100755
--- a/bin/update-authors.py
+++ b/bin/update-authors.py
@@ -1,4 +1,4 @@
-#!/usr/bin/env python
+#!/usr/bin/env python3
"""
Update the README.md file with the authors from the git log
"""
@@ -23,16 +23,17 @@ def add_email(name, email):
"""
adds the email passed in to the end of authors
"""
- print "Adding %s <%s>" % (name, email)
+ print("Adding %s <%s>" % (name, email))
with open(AUTHORS, "a+") as fd:
- print >>fd, "- %s <%s>" % (name, email)
+ print("- %s <%s>" % (name, email), file=fd)
subprocess.check_call(["git", "commit", "-m", "Add %s to contributors" % name, AUTHORS])
def main():
out = subprocess.check_output(["git", "log", '--reverse', '--format=%an|%ae', "master"])
previous = load()
- for line in out.split("\n"):
+ for line in out.split(b"\n"):
+ line = line.decode("utf-8")
line = line.strip()
if line == "":
continue
diff --git a/compatibility_1_0.go b/compatibility_1_0.go
index 7b69a75..35709f6 100644
--- a/compatibility_1_0.go
+++ b/compatibility_1_0.go
@@ -1,5 +1,6 @@
// Go 1.0 compatibility functions
+//go:build !go1.1
// +build !go1.1
package swift
diff --git a/compatibility_1_1.go b/compatibility_1_1.go
index a4f9c3a..76545b1 100644
--- a/compatibility_1_1.go
+++ b/compatibility_1_1.go
@@ -1,5 +1,6 @@
// Go 1.1 and later compatibility functions
//
+//go:build go1.1
// +build go1.1
package swift
diff --git a/compatibility_1_6.go b/compatibility_1_6.go
index b443d01..9a1bf96 100644
--- a/compatibility_1_6.go
+++ b/compatibility_1_6.go
@@ -1,3 +1,4 @@
+//go:build go1.6
// +build go1.6
package swift
diff --git a/compatibility_not_1_6.go b/compatibility_not_1_6.go
index aabb44e..2957655 100644
--- a/compatibility_not_1_6.go
+++ b/compatibility_not_1_6.go
@@ -1,3 +1,4 @@
+//go:build !go1.6
// +build !go1.6
package swift
diff --git a/debian/changelog b/debian/changelog
index b664ae8..7cf118a 100644
--- a/debian/changelog
+++ b/debian/changelog
@@ -1,3 +1,9 @@
+golang-github-ncw-swift (2.0.1-1) UNRELEASED; urgency=low
+
+ * New upstream release.
+
+ -- Debian Janitor <janitor@jelmer.uk> Tue, 29 Nov 2022 03:41:16 -0000
+
golang-github-ncw-swift (1.0.53-2) unstable; urgency=medium
* Team upload.
diff --git a/dlo.go b/dlo.go
index 05a1927..da0684a 100644
--- a/dlo.go
+++ b/dlo.go
@@ -1,6 +1,7 @@
package swift
import (
+ "context"
"os"
"strings"
)
@@ -14,8 +15,8 @@ type DynamicLargeObjectCreateFile struct {
// returning an object which satisfies io.Writer, io.Seeker, io.Closer
// and io.ReaderFrom. The flags are as passes to the
// largeObjectCreate method.
-func (c *Connection) DynamicLargeObjectCreateFile(opts *LargeObjectOpts) (LargeObjectFile, error) {
- lo, err := c.largeObjectCreate(opts)
+func (c *Connection) DynamicLargeObjectCreateFile(ctx context.Context, opts *LargeObjectOpts) (LargeObjectFile, error) {
+ lo, err := c.largeObjectCreate(ctx, opts)
if err != nil {
return nil, err
}
@@ -28,29 +29,33 @@ func (c *Connection) DynamicLargeObjectCreateFile(opts *LargeObjectOpts) (LargeO
// DynamicLargeObjectCreate creates or truncates an existing dynamic
// large object returning a writeable object. This sets opts.Flags to
// an appropriate value before calling DynamicLargeObjectCreateFile
-func (c *Connection) DynamicLargeObjectCreate(opts *LargeObjectOpts) (LargeObjectFile, error) {
+func (c *Connection) DynamicLargeObjectCreate(ctx context.Context, opts *LargeObjectOpts) (LargeObjectFile, error) {
opts.Flags = os.O_TRUNC | os.O_CREATE
- return c.DynamicLargeObjectCreateFile(opts)
+ return c.DynamicLargeObjectCreateFile(ctx, opts)
}
// DynamicLargeObjectDelete deletes a dynamic large object and all of its segments.
-func (c *Connection) DynamicLargeObjectDelete(container string, path string) error {
- return c.LargeObjectDelete(container, path)
+func (c *Connection) DynamicLargeObjectDelete(ctx context.Context, container string, path string) error {
+ return c.LargeObjectDelete(ctx, container, path)
}
// DynamicLargeObjectMove moves a dynamic large object from srcContainer, srcObjectName to dstContainer, dstObjectName
-func (c *Connection) DynamicLargeObjectMove(srcContainer string, srcObjectName string, dstContainer string, dstObjectName string) error {
- info, headers, err := c.Object(srcContainer, srcObjectName)
+func (c *Connection) DynamicLargeObjectMove(ctx context.Context, srcContainer string, srcObjectName string, dstContainer string, dstObjectName string) error {
+ info, headers, err := c.Object(ctx, srcContainer, srcObjectName)
if err != nil {
return err
}
- segmentContainer, segmentPath := parseFullPath(headers["X-Object-Manifest"])
- if err := c.createDLOManifest(dstContainer, dstObjectName, segmentContainer+"/"+segmentPath, info.ContentType, sanitizeLargeObjectMoveHeaders(headers)); err != nil {
+ segmentContainer, segmentPath, err := parseFullPath(headers["X-Object-Manifest"])
+ if err != nil {
+ return err
+ }
+
+ if err := c.createDLOManifest(ctx, dstContainer, dstObjectName, segmentContainer+"/"+segmentPath, info.ContentType, sanitizeLargeObjectMoveHeaders(headers)); err != nil {
return err
}
- if err := c.ObjectDelete(srcContainer, srcObjectName); err != nil {
+ if err := c.ObjectDelete(ctx, srcContainer, srcObjectName); err != nil {
return err
}
@@ -68,12 +73,12 @@ func sanitizeLargeObjectMoveHeaders(headers Headers) Headers {
}
// createDLOManifest creates a dynamic large object manifest
-func (c *Connection) createDLOManifest(container string, objectName string, prefix string, contentType string, headers Headers) error {
+func (c *Connection) createDLOManifest(ctx context.Context, container string, objectName string, prefix string, contentType string, headers Headers) error {
if headers == nil {
headers = make(Headers)
}
headers["X-Object-Manifest"] = prefix
- manifest, err := c.ObjectCreate(container, objectName, false, "", contentType, headers)
+ manifest, err := c.ObjectCreate(ctx, container, objectName, false, "", contentType, headers)
if err != nil {
return err
}
@@ -87,20 +92,24 @@ func (c *Connection) createDLOManifest(container string, objectName string, pref
// Close satisfies the io.Closer interface
func (file *DynamicLargeObjectCreateFile) Close() error {
- return file.Flush()
+ return file.CloseWithContext(context.Background())
+}
+
+func (file *DynamicLargeObjectCreateFile) CloseWithContext(ctx context.Context) error {
+ return file.Flush(ctx)
}
-func (file *DynamicLargeObjectCreateFile) Flush() error {
- err := file.conn.createDLOManifest(file.container, file.objectName, file.segmentContainer+"/"+file.prefix, file.contentType, file.headers)
+func (file *DynamicLargeObjectCreateFile) Flush(ctx context.Context) error {
+ err := file.conn.createDLOManifest(ctx, file.container, file.objectName, file.segmentContainer+"/"+file.prefix, file.contentType, file.headers)
if err != nil {
return err
}
- return file.conn.waitForSegmentsToShowUp(file.container, file.objectName, file.Size())
+ return file.conn.waitForSegmentsToShowUp(ctx, file.container, file.objectName, file.Size())
}
-func (c *Connection) getAllDLOSegments(segmentContainer, segmentPath string) ([]Object, error) {
+func (c *Connection) getAllDLOSegments(ctx context.Context, segmentContainer, segmentPath string) ([]Object, error) {
//a simple container listing works 99.9% of the time
- segments, err := c.ObjectsAll(segmentContainer, &ObjectsOpts{Prefix: segmentPath})
+ segments, err := c.ObjectsAll(ctx, segmentContainer, &ObjectsOpts{Prefix: segmentPath})
if err != nil {
return nil, err
}
@@ -126,7 +135,7 @@ func (c *Connection) getAllDLOSegments(segmentContainer, segmentPath string) ([]
//guaranteed to return the correct metadata, except for the pathological
//case of an outage of large parts of the Swift cluster or its network,
//since every segment is only written once.)
- segment, _, err := c.Object(segmentContainer, segmentName)
+ segment, _, err := c.Object(ctx, segmentContainer, segmentName)
switch err {
case nil:
//found new segment -> add it in the correct position and keep
diff --git a/dlo_test.go b/dlo_test.go
index 55bbd51..1764a47 100644
--- a/dlo_test.go
+++ b/dlo_test.go
@@ -2,10 +2,12 @@ package swift
import (
"bytes"
- "github.com/ncw/swift/swifttest"
+ "context"
"net/http"
"testing"
"time"
+
+ "github.com/ncw/swift/v2/swifttest"
)
var srv *swifttest.SwiftServer
@@ -47,7 +49,7 @@ func initTestConnection(t *testing.T) (*Connection, error) {
Domain: "Default",
AuthVersion: 1,
}
- err = swiftCon.Authenticate()
+ err = swiftCon.Authenticate(context.Background())
return &swiftCon, err
}
func TestCases(t *testing.T) {
@@ -63,8 +65,9 @@ func TestCases(t *testing.T) {
}
func createContainers(containers []string, t *testing.T) {
+ ctx := context.Background()
for i := 0; i < len(containers); i++ {
- err = con.ContainerCreate(containers[i], nil) // Create container
+ err = con.ContainerCreate(ctx, containers[i], nil) // Create container
if err != nil {
t.Errorf("Fail at create container %s", containers[i])
}
@@ -72,6 +75,7 @@ func createContainers(containers []string, t *testing.T) {
}
func createDynamicObject(container, object string, t *testing.T) {
+ ctx := context.Background()
metadata := map[string]string{}
metadata["Custom-Field"] = "SomeValue"
ops := LargeObjectOpts{
@@ -83,16 +87,23 @@ func createDynamicObject(container, object string, t *testing.T) {
SegmentContainer: segmentContainer, // Name of the container to place segments
SegmentPrefix: "sg", // Prefix to use for the segments
}
- bigfile, err := con.DynamicLargeObjectCreate(&ops)
+ bigfile, err := con.DynamicLargeObjectCreate(ctx, &ops)
if err != nil {
t.Errorf("Fail at dynamic create Large Object")
}
- bigfile.Write(filecontent)
- bigfile.Close()
+ _, err = bigfile.WriteWithContext(ctx, filecontent)
+ if err != nil {
+ t.Errorf("WriteWithContext failed: %v", err)
+ }
+ err = bigfile.CloseWithContext(ctx)
+ if err != nil {
+ t.Errorf("CloseWithContext failed: %v", err)
+ }
checkObject(container, object, t)
}
func checkObject(container, object string, t *testing.T) {
- info, header, err := con.Object(container, object)
+ ctx := context.Background()
+ info, header, err := con.Object(ctx, container, object)
if err != nil {
t.Errorf("Fail at get Large Object metadata: %s", err.Error())
}
@@ -106,7 +117,7 @@ func checkObject(container, object string, t *testing.T) {
t.Errorf("Fail: lost custom metadata header")
}
- content, err := con.ObjectGetBytes(container, object)
+ content, err := con.ObjectGetBytes(ctx, container, object)
if err != nil {
t.Errorf("Fail at read Large Object : %s", err.Error())
}
@@ -116,13 +127,13 @@ func checkObject(container, object string, t *testing.T) {
}
func checkNotExistObject(container, object string, t *testing.T) {
- _, _, err = con.Object(container, object)
+ _, _, err = con.Object(context.Background(), container, object)
if err == nil || err.Error() != "Object Not Found" {
t.Errorf("Fail at checkNotExistObject object: %s", err)
}
}
func moveDynamicObject(sc, so, dc, do string, t *testing.T) {
- err = con.DynamicLargeObjectMove(sc, so, dc, do)
+ err = con.DynamicLargeObjectMove(context.Background(), sc, so, dc, do)
if err != nil {
t.Errorf("Fail at dynamic move Large Object: %s", err.Error())
}
@@ -130,12 +141,13 @@ func moveDynamicObject(sc, so, dc, do string, t *testing.T) {
checkObject(dc, do, t)
}
func deleteDynamicObject(container, object string, t *testing.T) {
- err = con.DynamicLargeObjectDelete(container, object)
+ ctx := context.Background()
+ err = con.DynamicLargeObjectDelete(ctx, container, object)
if err != nil {
t.Errorf("Fail at delte dynamic Large Object: %s", err.Error())
}
checkNotExistObject(container, object, t)
- objs, err := con.ObjectsAll(segmentContainer, nil)
+ objs, err := con.ObjectsAll(ctx, segmentContainer, nil)
if err != nil {
t.Errorf("Fail at check delte dynamic Large Object: %s", err.Error())
}
@@ -144,6 +156,7 @@ func deleteDynamicObject(container, object string, t *testing.T) {
}
}
func createStaticObject(container, object string, t *testing.T) {
+ ctx := context.Background()
metadata := map[string]string{}
metadata["Custom-Field"] = "SomeValue"
ops := LargeObjectOpts{
@@ -155,16 +168,22 @@ func createStaticObject(container, object string, t *testing.T) {
SegmentContainer: segmentContainer, // Name of the container to place segments
SegmentPrefix: "sg", // Prefix to use for the segments
}
- bigfile, err := con.StaticLargeObjectCreate(&ops)
+ bigfile, err := con.StaticLargeObjectCreate(ctx, &ops)
if err != nil {
t.Errorf("Fail at static create Large Object")
}
- bigfile.Write(filecontent)
- bigfile.Close()
+ _, err = bigfile.WriteWithContext(ctx, filecontent)
+ if err != nil {
+ t.Errorf("WriteWithContext failed: %v", err)
+ }
+ err = bigfile.CloseWithContext(ctx)
+ if err != nil {
+ t.Errorf("CloseWithContext failed: %v", err)
+ }
checkObject(container, object, t)
}
func moveStaticObject(sc, so, dc, do string, t *testing.T) {
- err = con.StaticLargeObjectMove(sc, so, dc, do)
+ err = con.StaticLargeObjectMove(context.Background(), sc, so, dc, do)
if err != nil {
t.Errorf("Fail at static move Large Object: %s", err.Error())
}
@@ -172,12 +191,13 @@ func moveStaticObject(sc, so, dc, do string, t *testing.T) {
checkObject(dc, do, t)
}
func deleteStaticObject(container, object string, t *testing.T) {
- err = con.StaticLargeObjectDelete(container, object)
+ ctx := context.Background()
+ err = con.StaticLargeObjectDelete(ctx, container, object)
if err != nil {
t.Errorf("Fail at delte dynamic Large Object: %s", err.Error())
}
checkNotExistObject(container, object, t)
- objs, err := con.ObjectsAll(segmentContainer, nil)
+ objs, err := con.ObjectsAll(ctx, segmentContainer, nil)
if err != nil {
t.Errorf("Fail at check delte dynamic Large Object: %s", err.Error())
}
diff --git a/example_test.go b/example_test.go
index 95ec965..42d2f0b 100644
--- a/example_test.go
+++ b/example_test.go
@@ -4,12 +4,14 @@
package swift_test
import (
+ "context"
"fmt"
- "github.com/ncw/swift"
+ "github.com/ncw/swift/v2"
)
func ExampleConnection() {
+ ctx := context.Background()
// Create a v1 auth connection
c := &swift.Connection{
// This should be your username
@@ -24,12 +26,15 @@ func ExampleConnection() {
}
// Authenticate
- err := c.Authenticate()
+ err := c.Authenticate(ctx)
if err != nil {
panic(err)
}
// List all the containers
- containers, err := c.ContainerNames(nil)
+ containers, err := c.ContainerNames(ctx, nil)
+ if err != nil {
+ panic(err)
+ }
fmt.Println(containers)
// etc...
@@ -61,8 +66,8 @@ func ExampleConnection_ObjectsWalk() {
defer rollback()
objects := make([]string, 0)
- err := c.ObjectsWalk(container, nil, func(opts *swift.ObjectsOpts) (interface{}, error) {
- newObjects, err := c.ObjectNames(container, opts)
+ err := c.ObjectsWalk(context.Background(), container, nil, func(ctx context.Context, opts *swift.ObjectsOpts) (interface{}, error) {
+ newObjects, err := c.ObjectNames(ctx, container, opts)
if err == nil {
objects = append(objects, newObjects...)
}
@@ -76,23 +81,24 @@ func ExampleConnection_VersionContainerCreate() {
defer rollback()
// Use the helper method to create the current and versions container.
- if err := c.VersionContainerCreate("cds", "cd-versions"); err != nil {
+ if err := c.VersionContainerCreate(context.Background(), "cds", "cd-versions"); err != nil {
fmt.Print(err.Error())
}
}
func ExampleConnection_VersionEnable() {
+ ctx := context.Background()
c, rollback := makeConnection(nil)
defer rollback()
// Build the containers manually and enable them.
- if err := c.ContainerCreate("movie-versions", nil); err != nil {
+ if err := c.ContainerCreate(ctx, "movie-versions", nil); err != nil {
fmt.Print(err.Error())
}
- if err := c.ContainerCreate("movies", nil); err != nil {
+ if err := c.ContainerCreate(ctx, "movies", nil); err != nil {
fmt.Print(err.Error())
}
- if err := c.VersionEnable("movies", "movie-versions"); err != nil {
+ if err := c.VersionEnable(ctx, "movies", "movie-versions"); err != nil {
fmt.Print(err.Error())
}
@@ -105,5 +111,8 @@ func ExampleConnection_VersionDisable() {
defer rollback()
// Disable versioning on a container. Note that this does not delete the versioning container.
- c.VersionDisable("movies")
+ err := c.VersionDisable(context.Background(), "movies")
+ if err != nil {
+ panic(err)
+ }
}
diff --git a/go.mod b/go.mod
index 29f6ee2..501c1ba 100644
--- a/go.mod
+++ b/go.mod
@@ -1 +1,3 @@
-module github.com/ncw/swift
+module github.com/ncw/swift/v2
+
+go 1.15
diff --git a/go.sum b/go.sum
new file mode 100644
index 0000000..e69de29
diff --git a/integration_test.sh b/integration_test.sh
new file mode 100755
index 0000000..6bcb988
--- /dev/null
+++ b/integration_test.sh
@@ -0,0 +1,57 @@
+#!/bin/bash
+# Run the swift tests against an openstack server from a swift all in
+# one docker image
+
+set -e
+
+NAME=swift-aio
+HOST=127.0.0.1
+PORT=8294
+AUTH=v1
+
+case $AUTH in
+ v1)
+ export SWIFT_AUTH_URL="http://${HOST}:${PORT}/auth/v1.0"
+ export SWIFT_API_USER='test:tester'
+ export SWIFT_API_KEY='testing'
+ ;;
+ v2)
+ # NB v2 auth doesn't work for unknown reasons!
+ export SWIFT_AUTH_URL="http://${HOST}:${PORT}/auth/v2.0"
+ export SWIFT_TENANT='tester'
+ export SWIFT_API_USER='test'
+ export SWIFT_API_KEY='testing'
+ ;;
+ *)
+ echo "Bad AUTH %AUTH"
+ exit 1
+ ;;
+esac
+
+
+echo "Starting test server"
+docker run --rm -d --name ${NAME} -p ${HOST}:${PORT}:8080 bouncestorage/swift-aio
+
+function cleanup {
+ echo "Killing test server"
+ docker kill ${NAME}
+}
+
+trap cleanup EXIT
+
+echo -n "Waiting for test server to startup"
+tries=30
+while [[ $tries -gt 0 ]]; do
+ echo -n "."
+ STATUS_RECEIVED=$(curl -s -o /dev/null -L -w ''%{http_code}'' ${SWIFT_AUTH_URL} || true)
+ if [[ ${STATUS_RECEIVED} -ge 200 ]]; then
+ break
+ fi
+ let tries-=1
+ sleep 1
+done
+echo "OK"
+
+echo "Running tests"
+go test -v
+
diff --git a/largeobjects.go b/largeobjects.go
index 038bef8..369ada7 100644
--- a/largeobjects.go
+++ b/largeobjects.go
@@ -3,12 +3,14 @@ package swift
import (
"bufio"
"bytes"
+ "context"
"crypto/rand"
"crypto/sha1"
"encoding/hex"
"errors"
"fmt"
"io"
+ "net/url"
"os"
gopath "path"
"strconv"
@@ -56,13 +58,17 @@ func getSegment(segmentPath string, partNumber int) string {
return fmt.Sprintf("%s/%016d", segmentPath, partNumber)
}
-func parseFullPath(manifest string) (container string, prefix string) {
+func parseFullPath(manifest string) (container string, prefix string, err error) {
+ manifest, err = url.PathUnescape(manifest)
+ if err != nil {
+ return
+ }
components := strings.SplitN(manifest, "/", 2)
container = components[0]
if len(components) > 1 {
prefix = components[1]
}
- return container, prefix
+ return container, prefix, nil
}
func (headers Headers) IsLargeObjectDLO() bool {
@@ -79,14 +85,17 @@ func (headers Headers) IsLargeObject() bool {
return headers.IsLargeObjectSLO() || headers.IsLargeObjectDLO()
}
-func (c *Connection) getAllSegments(container string, path string, headers Headers) (string, []Object, error) {
+func (c *Connection) getAllSegments(ctx context.Context, container string, path string, headers Headers) (string, []Object, error) {
if manifest, isDLO := headers["X-Object-Manifest"]; isDLO {
- segmentContainer, segmentPath := parseFullPath(manifest)
- segments, err := c.getAllDLOSegments(segmentContainer, segmentPath)
+ segmentContainer, segmentPath, err := parseFullPath(manifest)
+ if err != nil {
+ return segmentContainer, nil, err
+ }
+ segments, err := c.getAllDLOSegments(ctx, segmentContainer, segmentPath)
return segmentContainer, segments, err
}
if headers.IsLargeObjectSLO() {
- return c.getAllSLOSegments(container, path)
+ return c.getAllSLOSegments(ctx, container, path)
}
return "", nil, NotLargeObject
}
@@ -108,11 +117,14 @@ type LargeObjectOpts struct {
}
type LargeObjectFile interface {
- io.Writer
io.Seeker
+ io.Writer
io.Closer
+
+ WriteWithContext(ctx context.Context, p []byte) (n int, err error)
+ CloseWithContext(ctx context.Context) error
Size() int64
- Flush() error
+ Flush(ctx context.Context) error
}
// largeObjectCreate creates a large object at opts.Container, opts.ObjectName.
@@ -120,7 +132,7 @@ type LargeObjectFile interface {
// opts.Flags can have the following bits set
// os.TRUNC - remove the contents of the large object if it exists
// os.APPEND - write at the end of the large object
-func (c *Connection) largeObjectCreate(opts *LargeObjectOpts) (*largeObjectCreateFile, error) {
+func (c *Connection) largeObjectCreate(ctx context.Context, opts *LargeObjectOpts) (*largeObjectCreateFile, error) {
var (
segmentPath string
segmentContainer string
@@ -135,13 +147,16 @@ func (c *Connection) largeObjectCreate(opts *LargeObjectOpts) (*largeObjectCreat
return nil, err
}
- if info, headers, err := c.Object(opts.Container, opts.ObjectName); err == nil {
+ if info, headers, err := c.Object(ctx, opts.Container, opts.ObjectName); err == nil {
if opts.Flags&os.O_TRUNC != 0 {
- c.LargeObjectDelete(opts.Container, opts.ObjectName)
+ err := c.LargeObjectDelete(ctx, opts.Container, opts.ObjectName)
+ if err != nil {
+ return nil, err
+ }
} else {
currentLength = info.Bytes
if headers.IsLargeObject() {
- segmentContainer, segments, err = c.getAllSegments(opts.Container, opts.ObjectName, headers)
+ segmentContainer, segments, err = c.getAllSegments(ctx, opts.Container, opts.ObjectName, headers)
if err != nil {
return nil, err
}
@@ -149,7 +164,7 @@ func (c *Connection) largeObjectCreate(opts *LargeObjectOpts) (*largeObjectCreat
segmentPath = gopath.Dir(segments[0].Name)
}
} else {
- if err = c.ObjectMove(opts.Container, opts.ObjectName, opts.Container, getSegment(segmentPath, 1)); err != nil {
+ if err = c.ObjectMove(ctx, opts.Container, opts.ObjectName, opts.Container, getSegment(segmentPath, 1)); err != nil {
return nil, err
}
segments = append(segments, info)
@@ -198,15 +213,15 @@ func (c *Connection) largeObjectCreate(opts *LargeObjectOpts) (*largeObjectCreat
}
// LargeObjectDelete deletes the large object named by container, path
-func (c *Connection) LargeObjectDelete(container string, objectName string) error {
- _, headers, err := c.Object(container, objectName)
+func (c *Connection) LargeObjectDelete(ctx context.Context, container string, objectName string) error {
+ _, headers, err := c.Object(ctx, container, objectName)
if err != nil {
return err
}
var objects [][]string
if headers.IsLargeObject() {
- segmentContainer, segments, err := c.getAllSegments(container, objectName, headers)
+ segmentContainer, segments, err := c.getAllSegments(ctx, container, objectName, headers)
if err != nil {
return err
}
@@ -216,13 +231,13 @@ func (c *Connection) LargeObjectDelete(container string, objectName string) erro
}
objects = append(objects, []string{container, objectName})
- info, err := c.cachedQueryInfo()
+ info, err := c.cachedQueryInfo(ctx)
if err == nil && info.SupportsBulkDelete() && len(objects) > 0 {
filenames := make([]string, len(objects))
for i, obj := range objects {
filenames[i] = obj[0] + "/" + obj[1]
}
- _, err = c.doBulkDelete(filenames, nil)
+ _, err = c.doBulkDelete(ctx, filenames, nil)
// Don't fail on ObjectNotFound because eventual consistency
// makes this situation normal.
if err != nil && err != Forbidden && err != ObjectNotFound {
@@ -230,7 +245,7 @@ func (c *Connection) LargeObjectDelete(container string, objectName string) erro
}
} else {
for _, obj := range objects {
- if err := c.ObjectDelete(obj[0], obj[1]); err != nil {
+ if err := c.ObjectDelete(ctx, obj[0], obj[1]); err != nil {
return err
}
}
@@ -244,13 +259,13 @@ func (c *Connection) LargeObjectDelete(container string, objectName string) erro
// that have the prefix as indicated by the manifest.
// If the object is a Static Large Object (SLO), it retrieves the JSON content
// of the manifest and return all the segments of it.
-func (c *Connection) LargeObjectGetSegments(container string, path string) (string, []Object, error) {
- _, headers, err := c.Object(container, path)
+func (c *Connection) LargeObjectGetSegments(ctx context.Context, container string, path string) (string, []Object, error) {
+ _, headers, err := c.Object(ctx, container, path)
if err != nil {
return "", nil, err
}
- return c.getAllSegments(container, path, headers)
+ return c.getAllSegments(ctx, container, path, headers)
}
// Seek sets the offset for the next write operation
@@ -301,11 +316,11 @@ func withLORetry(expectedSize int64, fn func() (Headers, int64, error)) (err err
}
}
-func (c *Connection) waitForSegmentsToShowUp(container, objectName string, expectedSize int64) (err error) {
+func (c *Connection) waitForSegmentsToShowUp(ctx context.Context, container, objectName string, expectedSize int64) (err error) {
err = withLORetry(expectedSize, func() (Headers, int64, error) {
var info Object
var headers Headers
- info, headers, err = c.objectBase(container, objectName)
+ info, headers, err = c.objectBase(ctx, container, objectName)
if err != nil {
return headers, 0, err
}
@@ -314,8 +329,11 @@ func (c *Connection) waitForSegmentsToShowUp(container, objectName string, expec
return
}
-// Write satisfies the io.Writer interface
func (file *largeObjectCreateFile) Write(buf []byte) (int, error) {
+ return file.WriteWithContext(context.Background(), buf)
+}
+
+func (file *largeObjectCreateFile) WriteWithContext(ctx context.Context, buf []byte) (int, error) {
var sz int64
var relativeFilePos int
writeSegmentIdx := 0
@@ -329,7 +347,7 @@ func (file *largeObjectCreateFile) Write(buf []byte) (int, error) {
}
sizeToWrite := len(buf)
for offset := 0; offset < sizeToWrite; {
- newSegment, n, err := file.writeSegment(buf[offset:], writeSegmentIdx, relativeFilePos)
+ newSegment, n, err := file.writeSegment(ctx, buf[offset:], writeSegmentIdx, relativeFilePos)
if err != nil {
return 0, err
}
@@ -350,7 +368,7 @@ func (file *largeObjectCreateFile) Write(buf []byte) (int, error) {
return sizeToWrite, nil
}
-func (file *largeObjectCreateFile) writeSegment(buf []byte, writeSegmentIdx int, relativeFilePos int) (*Object, int, error) {
+func (file *largeObjectCreateFile) writeSegment(ctx context.Context, buf []byte, writeSegmentIdx int, relativeFilePos int) (obj *Object, n int, err error) {
var (
readers []io.Reader
existingSegment *Object
@@ -366,11 +384,16 @@ func (file *largeObjectCreateFile) writeSegment(buf []byte, writeSegmentIdx int,
if relativeFilePos > 0 {
headers := make(Headers)
headers["Range"] = "bytes=0-" + strconv.FormatInt(int64(relativeFilePos-1), 10)
- existingSegmentReader, _, err := file.conn.ObjectOpen(file.segmentContainer, segmentName, true, headers)
+ existingSegmentReader, _, err := file.conn.ObjectOpen(ctx, file.segmentContainer, segmentName, true, headers)
if err != nil {
return nil, 0, err
}
- defer existingSegmentReader.Close()
+ defer func() {
+ closeErr := existingSegmentReader.Close()
+ if closeErr != nil {
+ err = closeErr
+ }
+ }()
sizeToRead -= relativeFilePos
segmentSize += relativeFilePos
readers = []io.Reader{existingSegmentReader}
@@ -384,16 +407,21 @@ func (file *largeObjectCreateFile) writeSegment(buf []byte, writeSegmentIdx int,
if existingSegment != nil && segmentSize < int(existingSegment.Bytes) {
headers := make(Headers)
headers["Range"] = "bytes=" + strconv.FormatInt(int64(segmentSize), 10) + "-"
- tailSegmentReader, _, err := file.conn.ObjectOpen(file.segmentContainer, segmentName, true, headers)
+ tailSegmentReader, _, err := file.conn.ObjectOpen(ctx, file.segmentContainer, segmentName, true, headers)
if err != nil {
return nil, 0, err
}
- defer tailSegmentReader.Close()
+ defer func() {
+ closeErr := tailSegmentReader.Close()
+ if closeErr != nil {
+ err = closeErr
+ }
+ }()
segmentSize = int(existingSegment.Bytes)
readers = append(readers, tailSegmentReader)
}
segmentReader := io.MultiReader(readers...)
- headers, err := file.conn.ObjectPut(file.segmentContainer, segmentName, segmentReader, true, "", file.contentType, nil)
+ headers, err := file.conn.ObjectPut(ctx, file.segmentContainer, segmentName, segmentReader, true, "", file.contentType, nil)
if err != nil {
return nil, 0, err
}
@@ -416,11 +444,19 @@ type bufferedLargeObjectFile struct {
}
func (blo *bufferedLargeObjectFile) Close() error {
+ return blo.CloseWithContext(context.Background())
+}
+
+func (blo *bufferedLargeObjectFile) CloseWithContext(ctx context.Context) error {
err := blo.bw.Flush()
if err != nil {
return err
}
- return blo.LargeObjectFile.Close()
+ return blo.LargeObjectFile.CloseWithContext(ctx)
+}
+
+func (blo *bufferedLargeObjectFile) WriteWithContext(_ context.Context, p []byte) (n int, err error) {
+ return blo.Write(p)
}
func (blo *bufferedLargeObjectFile) Write(p []byte) (n int, err error) {
@@ -439,10 +475,10 @@ func (blo *bufferedLargeObjectFile) Size() int64 {
return blo.LargeObjectFile.Size() + int64(blo.bw.Buffered())
}
-func (blo *bufferedLargeObjectFile) Flush() error {
+func (blo *bufferedLargeObjectFile) Flush(ctx context.Context) error {
err := blo.bw.Flush()
if err != nil {
return err
}
- return blo.LargeObjectFile.Flush()
+ return blo.LargeObjectFile.Flush(ctx)
}
diff --git a/rs/rs.go b/rs/rs.go
index 34ee15a..ae9e5ac 100644
--- a/rs/rs.go
+++ b/rs/rs.go
@@ -1,11 +1,12 @@
package rs
import (
+ "context"
"errors"
"net/http"
"strconv"
- "github.com/ncw/swift"
+ "github.com/ncw/swift/v2"
)
// RsConnection is a RackSpace specific wrapper to the core swift library which
@@ -16,7 +17,7 @@ type RsConnection struct {
}
// manage is similar to the swift storage method, but uses the CDN Management URL for CDN specific calls.
-func (c *RsConnection) manage(p swift.RequestOpts) (resp *http.Response, headers swift.Headers, err error) {
+func (c *RsConnection) manage(ctx context.Context, p swift.RequestOpts) (resp *http.Response, headers swift.Headers, err error) {
p.OnReAuth = func() (string, error) {
if c.cdnUrl == "" {
c.cdnUrl = c.Auth.CdnUrl()
@@ -32,7 +33,7 @@ func (c *RsConnection) manage(p swift.RequestOpts) (resp *http.Response, headers
return nil, nil, err
}
}
- return c.Connection.Call(c.cdnUrl, p)
+ return c.Connection.Call(ctx, c.cdnUrl, p)
}
// ContainerCDNEnable enables a container for public CDN usage.
@@ -40,13 +41,13 @@ func (c *RsConnection) manage(p swift.RequestOpts) (resp *http.Response, headers
// Change the default TTL of 259200 seconds (72 hours) by passing in an integer value.
//
// This method can be called again to change the TTL.
-func (c *RsConnection) ContainerCDNEnable(container string, ttl int) (swift.Headers, error) {
+func (c *RsConnection) ContainerCDNEnable(ctx context.Context, container string, ttl int) (swift.Headers, error) {
h := swift.Headers{"X-CDN-Enabled": "true"}
if ttl > 0 {
h["X-TTL"] = strconv.Itoa(ttl)
}
- _, headers, err := c.manage(swift.RequestOpts{
+ _, headers, err := c.manage(ctx, swift.RequestOpts{
Container: container,
Operation: "PUT",
ErrorMap: swift.ContainerErrorMap,
@@ -57,10 +58,10 @@ func (c *RsConnection) ContainerCDNEnable(container string, ttl int) (swift.Head
}
// ContainerCDNDisable disables CDN access to a container.
-func (c *RsConnection) ContainerCDNDisable(container string) error {
+func (c *RsConnection) ContainerCDNDisable(ctx context.Context, container string) error {
h := swift.Headers{"X-CDN-Enabled": "false"}
- _, _, err := c.manage(swift.RequestOpts{
+ _, _, err := c.manage(ctx, swift.RequestOpts{
Container: container,
Operation: "PUT",
ErrorMap: swift.ContainerErrorMap,
@@ -71,8 +72,8 @@ func (c *RsConnection) ContainerCDNDisable(container string) error {
}
// ContainerCDNMeta returns the CDN metadata for a container.
-func (c *RsConnection) ContainerCDNMeta(container string) (swift.Headers, error) {
- _, headers, err := c.manage(swift.RequestOpts{
+func (c *RsConnection) ContainerCDNMeta(ctx context.Context, container string) (swift.Headers, error) {
+ _, headers, err := c.manage(ctx, swift.RequestOpts{
Container: container,
Operation: "HEAD",
ErrorMap: swift.ContainerErrorMap,
diff --git a/rs/rs_test.go b/rs/rs_test.go
index 7420515..9667ee3 100644
--- a/rs/rs_test.go
+++ b/rs/rs_test.go
@@ -2,10 +2,11 @@
package rs_test
import (
+ "context"
"os"
"testing"
- "github.com/ncw/swift/rs"
+ "github.com/ncw/swift/v2/rs"
)
var (
@@ -32,7 +33,7 @@ func TestAuthenticate(t *testing.T) {
c.UserName = UserName
c.ApiKey = ApiKey
c.AuthUrl = AuthUrl
- err := c.Authenticate()
+ err := c.Authenticate(context.Background())
if err != nil {
t.Fatal("Auth failed", err)
}
@@ -43,14 +44,14 @@ func TestAuthenticate(t *testing.T) {
// Setup
func TestContainerCreate(t *testing.T) {
- err := c.ContainerCreate(CONTAINER, nil)
+ err := c.ContainerCreate(context.Background(), CONTAINER, nil)
if err != nil {
t.Fatal(err)
}
}
func TestCDNEnable(t *testing.T) {
- headers, err := c.ContainerCDNEnable(CONTAINER, 0)
+ headers, err := c.ContainerCDNEnable(context.Background(), CONTAINER, 0)
if err != nil {
t.Error(err)
}
@@ -64,14 +65,14 @@ func TestOnReAuth(t *testing.T) {
c2.UserName = c.UserName
c2.ApiKey = c.ApiKey
c2.AuthUrl = c.AuthUrl
- _, err := c2.ContainerCDNEnable(CONTAINER, 0)
+ _, err := c2.ContainerCDNEnable(context.Background(), CONTAINER, 0)
if err != nil {
t.Fatalf("Failed to reauthenticate: %v", err)
}
}
func TestCDNMeta(t *testing.T) {
- headers, err := c.ContainerCDNMeta(CONTAINER)
+ headers, err := c.ContainerCDNMeta(context.Background(), CONTAINER)
if err != nil {
t.Error(err)
}
@@ -81,7 +82,7 @@ func TestCDNMeta(t *testing.T) {
}
func TestCDNDisable(t *testing.T) {
- err := c.ContainerCDNDisable(CONTAINER) // files stick in CDN until TTL expires
+ err := c.ContainerCDNDisable(context.Background(), CONTAINER) // files stick in CDN until TTL expires
if err != nil {
t.Error(err)
}
@@ -89,7 +90,7 @@ func TestCDNDisable(t *testing.T) {
// Teardown
func TestContainerDelete(t *testing.T) {
- err := c.ContainerDelete(CONTAINER)
+ err := c.ContainerDelete(context.Background(), CONTAINER)
if err != nil {
t.Fatal(err)
}
diff --git a/slo.go b/slo.go
index 6a10ddf..acbf5b1 100644
--- a/slo.go
+++ b/slo.go
@@ -2,6 +2,7 @@ package swift
import (
"bytes"
+ "context"
"encoding/json"
"errors"
"fmt"
@@ -37,8 +38,8 @@ type swiftSegment struct {
// an object which satisfies io.Writer, io.Seeker, io.Closer and
// io.ReaderFrom. The flags are as passed to the largeObjectCreate
// method.
-func (c *Connection) StaticLargeObjectCreateFile(opts *LargeObjectOpts) (LargeObjectFile, error) {
- info, err := c.cachedQueryInfo()
+func (c *Connection) StaticLargeObjectCreateFile(ctx context.Context, opts *LargeObjectOpts) (LargeObjectFile, error) {
+ info, err := c.cachedQueryInfo(ctx)
if err != nil || !info.SupportsSLO() {
return nil, SLONotSupported
}
@@ -46,7 +47,7 @@ func (c *Connection) StaticLargeObjectCreateFile(opts *LargeObjectOpts) (LargeOb
if realMinChunkSize > opts.MinChunkSize {
opts.MinChunkSize = realMinChunkSize
}
- lo, err := c.largeObjectCreate(opts)
+ lo, err := c.largeObjectCreate(ctx, opts)
if err != nil {
return nil, err
}
@@ -58,32 +59,32 @@ func (c *Connection) StaticLargeObjectCreateFile(opts *LargeObjectOpts) (LargeOb
// StaticLargeObjectCreate creates or truncates an existing static
// large object returning a writeable object. This sets opts.Flags to
// an appropriate value before calling StaticLargeObjectCreateFile
-func (c *Connection) StaticLargeObjectCreate(opts *LargeObjectOpts) (LargeObjectFile, error) {
+func (c *Connection) StaticLargeObjectCreate(ctx context.Context, opts *LargeObjectOpts) (LargeObjectFile, error) {
opts.Flags = os.O_TRUNC | os.O_CREATE
- return c.StaticLargeObjectCreateFile(opts)
+ return c.StaticLargeObjectCreateFile(ctx, opts)
}
// StaticLargeObjectDelete deletes a static large object and all of its segments.
-func (c *Connection) StaticLargeObjectDelete(container string, path string) error {
- info, err := c.cachedQueryInfo()
+func (c *Connection) StaticLargeObjectDelete(ctx context.Context, container string, path string) error {
+ info, err := c.cachedQueryInfo(ctx)
if err != nil || !info.SupportsSLO() {
return SLONotSupported
}
- return c.LargeObjectDelete(container, path)
+ return c.LargeObjectDelete(ctx, container, path)
}
// StaticLargeObjectMove moves a static large object from srcContainer, srcObjectName to dstContainer, dstObjectName
-func (c *Connection) StaticLargeObjectMove(srcContainer string, srcObjectName string, dstContainer string, dstObjectName string) error {
- swiftInfo, err := c.cachedQueryInfo()
+func (c *Connection) StaticLargeObjectMove(ctx context.Context, srcContainer string, srcObjectName string, dstContainer string, dstObjectName string) error {
+ swiftInfo, err := c.cachedQueryInfo(ctx)
if err != nil || !swiftInfo.SupportsSLO() {
return SLONotSupported
}
- info, headers, err := c.Object(srcContainer, srcObjectName)
+ info, headers, err := c.Object(ctx, srcContainer, srcObjectName)
if err != nil {
return err
}
- container, segments, err := c.getAllSegments(srcContainer, srcObjectName, headers)
+ container, segments, err := c.getAllSegments(ctx, srcContainer, srcObjectName, headers)
if err != nil {
return err
}
@@ -91,11 +92,11 @@ func (c *Connection) StaticLargeObjectMove(srcContainer string, srcObjectName st
//copy only metadata during move (other headers might not be safe for copying)
headers = headers.ObjectMetadata().ObjectHeaders()
- if err := c.createSLOManifest(dstContainer, dstObjectName, info.ContentType, container, segments, headers); err != nil {
+ if err := c.createSLOManifest(ctx, dstContainer, dstObjectName, info.ContentType, container, segments, headers); err != nil {
return err
}
- if err := c.ObjectDelete(srcContainer, srcObjectName); err != nil {
+ if err := c.ObjectDelete(ctx, srcContainer, srcObjectName); err != nil {
return err
}
@@ -103,7 +104,7 @@ func (c *Connection) StaticLargeObjectMove(srcContainer string, srcObjectName st
}
// createSLOManifest creates a static large object manifest
-func (c *Connection) createSLOManifest(container string, path string, contentType string, segmentContainer string, segments []Object, h Headers) error {
+func (c *Connection) createSLOManifest(ctx context.Context, container string, path string, contentType string, segmentContainer string, segments []Object, h Headers) error {
sloSegments := make([]swiftSegment, len(segments))
for i, segment := range segments {
sloSegments[i].Path = fmt.Sprintf("%s/%s", segmentContainer, segment.Name)
@@ -118,7 +119,7 @@ func (c *Connection) createSLOManifest(container string, path string, contentTyp
values := url.Values{}
values.Set("multipart-manifest", "put")
- if _, err := c.objectPut(container, path, bytes.NewBuffer(content), false, "", contentType, h, values); err != nil {
+ if _, err := c.objectPut(ctx, container, path, bytes.NewBuffer(content), false, "", contentType, h, values); err != nil {
return err
}
@@ -126,17 +127,21 @@ func (c *Connection) createSLOManifest(container string, path string, contentTyp
}
func (file *StaticLargeObjectCreateFile) Close() error {
- return file.Flush()
+ return file.CloseWithContext(context.Background())
}
-func (file *StaticLargeObjectCreateFile) Flush() error {
- if err := file.conn.createSLOManifest(file.container, file.objectName, file.contentType, file.segmentContainer, file.segments, file.headers); err != nil {
+func (file *StaticLargeObjectCreateFile) CloseWithContext(ctx context.Context) error {
+ return file.Flush(ctx)
+}
+
+func (file *StaticLargeObjectCreateFile) Flush(ctx context.Context) error {
+ if err := file.conn.createSLOManifest(ctx, file.container, file.objectName, file.contentType, file.segmentContainer, file.segments, file.headers); err != nil {
return err
}
- return file.conn.waitForSegmentsToShowUp(file.container, file.objectName, file.Size())
+ return file.conn.waitForSegmentsToShowUp(ctx, file.container, file.objectName, file.Size())
}
-func (c *Connection) getAllSLOSegments(container, path string) (string, []Object, error) {
+func (c *Connection) getAllSLOSegments(ctx context.Context, container, path string) (string, []Object, error) {
var (
segmentList []swiftSegment
segments []Object
@@ -147,7 +152,7 @@ func (c *Connection) getAllSLOSegments(container, path string) (string, []Object
values := url.Values{}
values.Set("multipart-manifest", "get")
- file, _, err := c.objectOpen(container, path, true, nil, values)
+ file, _, err := c.objectOpen(ctx, container, path, true, nil, values)
if err != nil {
return "", nil, err
}
@@ -157,9 +162,15 @@ func (c *Connection) getAllSLOSegments(container, path string) (string, []Object
return "", nil, err
}
- json.Unmarshal(content, &segmentList)
+ err = json.Unmarshal(content, &segmentList)
+ if err != nil {
+ return "", nil, err
+ }
for _, segment := range segmentList {
- segmentContainer, segPath = parseFullPath(segment.Name[1:])
+ segmentContainer, segPath, err = parseFullPath(segment.Name[1:])
+ if err != nil {
+ return "", nil, err
+ }
segments = append(segments, Object{
Name: segPath,
Bytes: segment.Bytes,
diff --git a/swift.go b/swift.go
index 59b68ce..c9357ee 100644
--- a/swift.go
+++ b/swift.go
@@ -3,6 +3,7 @@ package swift
import (
"bufio"
"bytes"
+ "context"
"crypto/hmac"
"crypto/md5"
"crypto/sha1"
@@ -31,8 +32,7 @@ const (
UploadTarGzip = "tar.gz" // Data format specifier for Connection.BulkUpload().
UploadTarBzip2 = "tar.bz2" // Data format specifier for Connection.BulkUpload().
allContainersLimit = 10000 // Number of containers to fetch at once
- allObjectsLimit = 10000 // Number objects to fetch at once
- allObjectsChanLimit = 1000 // ...when fetching to a channel
+ allObjectsChanLimit = 1000 // Number objects to fetch when fetching to a channel
)
// ObjectType is the type of the swift object, regular, static large,
@@ -72,7 +72,7 @@ const (
// import (
// "appengine/urlfetch"
// "fmt"
-// "github.com/ncw/swift"
+// "github.com/ncw/swift/v2"
// )
//
// func handler(w http.ResponseWriter, r *http.Request) {
@@ -125,9 +125,12 @@ type Connection struct {
Expires time.Time // time the token expires, may be Zero if unknown
client *http.Client
Auth Authenticator `json:"-" xml:"-"` // the current authenticator
- authLock *sync.Mutex // lock when R/W StorageUrl, AuthToken, Auth
+ authLock sync.Mutex // lock when R/W StorageUrl, AuthToken, Auth
// swiftInfo is filled after QueryInfo is called
swiftInfo SwiftInfo
+ // Workarounds for non-compliant servers that don't always return opts.Limit items per page
+ FetchUntilEmptyPage bool // Always fetch unless we received an empty page
+ PartialPageFetchThreshold int // Fetch if the current page is this percentage of opts.Limit
}
// setFromEnv reads the value that param points to (it must be a
@@ -386,7 +389,13 @@ func (c *Connection) parseHeaders(resp *http.Response, errorMap errorMap) error
func readHeaders(resp *http.Response) Headers {
headers := Headers{}
for key, values := range resp.Header {
- headers[key] = values[0]
+ // ETag header may be double quoted if following RFC 7232
+ // https://github.com/openstack/swift/blob/2.24.0/CHANGELOG#L9
+ if key == "Etag" {
+ headers[key] = strings.Trim(values[0], "\"")
+ } else {
+ headers[key] = values[0]
+ }
}
return headers
}
@@ -415,7 +424,6 @@ func (c *Connection) doTimeoutRequest(timer *time.Timer, req *http.Request) (*ht
cancelRequest(c.Transport, req)
return nil, TimeoutError
}
- panic("unreachable") // For Go 1.0
}
// Set defaults for any unset values
@@ -457,19 +465,16 @@ func (c *Connection) setDefaults() {
//
// If you don't call it before calling one of the connection methods
// then it will be called for you on the first access.
-func (c *Connection) Authenticate() (err error) {
- if c.authLock == nil {
- c.authLock = &sync.Mutex{}
- }
+func (c *Connection) Authenticate(ctx context.Context) (err error) {
c.authLock.Lock()
defer c.authLock.Unlock()
- return c.authenticate()
+ return c.authenticate(ctx)
}
// Internal implementation of Authenticate
//
// Call with authLock held
-func (c *Connection) authenticate() (err error) {
+func (c *Connection) authenticate(ctx context.Context) (err error) {
c.setDefaults()
// Flush the keepalives connection - if we are
@@ -486,7 +491,7 @@ func (c *Connection) authenticate() (err error) {
retries := 1
again:
var req *http.Request
- req, err = c.Auth.Request(c)
+ req, err = c.Auth.Request(ctx, c)
if err != nil {
return
}
@@ -514,7 +519,7 @@ again:
}
return
}
- err = c.Auth.Response(resp)
+ err = c.Auth.Response(ctx, resp)
if err != nil {
return
}
@@ -541,12 +546,12 @@ again:
// Get an authToken and url
//
// The Url may be updated if it needed to authenticate using the OnReAuth function
-func (c *Connection) getUrlAndAuthToken(targetUrlIn string, OnReAuth func() (string, error)) (targetUrlOut, authToken string, err error) {
+func (c *Connection) getUrlAndAuthToken(ctx context.Context, targetUrlIn string, OnReAuth func() (string, error)) (targetUrlOut, authToken string, err error) {
c.authLock.Lock()
defer c.authLock.Unlock()
targetUrlOut = targetUrlIn
if !c.authenticated() {
- err = c.authenticate()
+ err = c.authenticate(ctx)
if err != nil {
return
}
@@ -583,9 +588,6 @@ func (c *Connection) UnAuthenticate() {
//
// Doesn't actually check the credentials against the server.
func (c *Connection) Authenticated() bool {
- if c.authLock == nil {
- c.authLock = &sync.Mutex{}
- }
c.authLock.Lock()
defer c.authLock.Unlock()
return c.authenticated()
@@ -629,13 +631,21 @@ func (i SwiftInfo) SLOMinSegmentSize() int64 {
}
// Discover Swift configuration by doing a request against /info
-func (c *Connection) QueryInfo() (infos SwiftInfo, err error) {
- infoUrl, err := url.Parse(c.StorageUrl)
+func (c *Connection) QueryInfo(ctx context.Context) (infos SwiftInfo, err error) {
+ storageUrl, err := c.GetStorageUrl(ctx)
+ if err != nil {
+ return nil, err
+ }
+ infoUrl, err := url.Parse(storageUrl)
if err != nil {
return nil, err
}
infoUrl.Path = path.Join(infoUrl.Path, "..", "..", "info")
- resp, err := c.client.Get(infoUrl.String())
+ req, err := http.NewRequestWithContext(ctx, http.MethodGet, infoUrl.String(), nil)
+ if err != nil {
+ return nil, err
+ }
+ resp, err := c.client.Do(req)
if err == nil {
if resp.StatusCode != http.StatusOK {
drainAndClose(resp.Body, nil)
@@ -652,12 +662,12 @@ func (c *Connection) QueryInfo() (infos SwiftInfo, err error) {
return nil, err
}
-func (c *Connection) cachedQueryInfo() (infos SwiftInfo, err error) {
+func (c *Connection) cachedQueryInfo(ctx context.Context) (infos SwiftInfo, err error) {
c.authLock.Lock()
infos = c.swiftInfo
c.authLock.Unlock()
if infos == nil {
- infos, err = c.QueryInfo()
+ infos, err = c.QueryInfo(ctx)
if err != nil {
return
}
@@ -700,7 +710,7 @@ type RequestOpts struct {
// receives a 401 error which means the token has expired
//
// This method is exported so extensions can call it.
-func (c *Connection) Call(targetUrl string, p RequestOpts) (resp *http.Response, headers Headers, err error) {
+func (c *Connection) Call(ctx context.Context, targetUrl string, p RequestOpts) (resp *http.Response, headers Headers, err error) {
c.authLock.Lock()
c.setDefaults()
c.authLock.Unlock()
@@ -711,7 +721,7 @@ func (c *Connection) Call(targetUrl string, p RequestOpts) (resp *http.Response,
var req *http.Request
for {
var authToken string
- if targetUrl, authToken, err = c.getUrlAndAuthToken(targetUrl, p.OnReAuth); err != nil {
+ if targetUrl, authToken, err = c.getUrlAndAuthToken(ctx, targetUrl, p.OnReAuth); err != nil {
return //authentication failure
}
var URL *url.URL
@@ -734,7 +744,7 @@ func (c *Connection) Call(targetUrl string, p RequestOpts) (resp *http.Response,
if reader != nil {
reader = newWatchdogReader(reader, c.Timeout, timer)
}
- req, err = http.NewRequest(p.Operation, URL.String(), reader)
+ req, err = http.NewRequestWithContext(ctx, p.Operation, URL.String(), reader)
if err != nil {
return
}
@@ -809,14 +819,14 @@ func (c *Connection) Call(targetUrl string, p RequestOpts) (resp *http.Response,
//
// This will Authenticate if necessary, and re-authenticate if it
// receives a 401 error which means the token has expired
-func (c *Connection) storage(p RequestOpts) (resp *http.Response, headers Headers, err error) {
+func (c *Connection) storage(ctx context.Context, p RequestOpts) (resp *http.Response, headers Headers, err error) {
p.OnReAuth = func() (string, error) {
return c.StorageUrl, nil
}
c.authLock.Lock()
url := c.StorageUrl
c.authLock.Unlock()
- return c.Call(url, p)
+ return c.Call(ctx, url, p)
}
// readLines reads the response into an array of strings.
@@ -887,9 +897,9 @@ func (opts *ContainersOpts) parse() (url.Values, Headers) {
}
// ContainerNames returns a slice of names of containers in this account.
-func (c *Connection) ContainerNames(opts *ContainersOpts) ([]string, error) {
+func (c *Connection) ContainerNames(ctx context.Context, opts *ContainersOpts) ([]string, error) {
v, h := opts.parse()
- resp, _, err := c.storage(RequestOpts{
+ resp, _, err := c.storage(ctx, RequestOpts{
Operation: "GET",
Parameters: v,
ErrorMap: ContainerErrorMap,
@@ -911,10 +921,10 @@ type Container struct {
// Containers returns a slice of structures with full information as
// described in Container.
-func (c *Connection) Containers(opts *ContainersOpts) ([]Container, error) {
+func (c *Connection) Containers(ctx context.Context, opts *ContainersOpts) ([]Container, error) {
v, h := opts.parse()
v.Set("format", "json")
- resp, _, err := c.storage(RequestOpts{
+ resp, _, err := c.storage(ctx, RequestOpts{
Operation: "GET",
Parameters: v,
ErrorMap: ContainerErrorMap,
@@ -942,21 +952,36 @@ func containersAllOpts(opts *ContainersOpts) *ContainersOpts {
return &newOpts
}
+func (c *Connection) isLastPage(length int, limit int) bool {
+ if c.FetchUntilEmptyPage && length > 0 {
+ return false
+ }
+ if c.PartialPageFetchThreshold > 0 && limit > 0 {
+ if length*100/limit >= c.PartialPageFetchThreshold {
+ return false
+ }
+ }
+ if length < limit {
+ return true
+ }
+ return false
+}
+
// ContainersAll is like Containers but it returns all the Containers
//
// It calls Containers multiple times using the Marker parameter
//
// It has a default Limit parameter but you may pass in your own
-func (c *Connection) ContainersAll(opts *ContainersOpts) ([]Container, error) {
+func (c *Connection) ContainersAll(ctx context.Context, opts *ContainersOpts) ([]Container, error) {
opts = containersAllOpts(opts)
containers := make([]Container, 0)
for {
- newContainers, err := c.Containers(opts)
+ newContainers, err := c.Containers(ctx, opts)
if err != nil {
return nil, err
}
containers = append(containers, newContainers...)
- if len(newContainers) < opts.Limit {
+ if c.isLastPage(len(newContainers), opts.Limit) {
break
}
opts.Marker = newContainers[len(newContainers)-1].Name
@@ -969,16 +994,16 @@ func (c *Connection) ContainersAll(opts *ContainersOpts) ([]Container, error) {
// It calls ContainerNames multiple times using the Marker parameter
//
// It has a default Limit parameter but you may pass in your own
-func (c *Connection) ContainerNamesAll(opts *ContainersOpts) ([]string, error) {
+func (c *Connection) ContainerNamesAll(ctx context.Context, opts *ContainersOpts) ([]string, error) {
opts = containersAllOpts(opts)
containers := make([]string, 0)
for {
- newContainers, err := c.ContainerNames(opts)
+ newContainers, err := c.ContainerNames(ctx, opts)
if err != nil {
return nil, err
}
containers = append(containers, newContainers...)
- if len(newContainers) < opts.Limit {
+ if c.isLastPage(len(newContainers), opts.Limit) {
break
}
opts.Marker = newContainers[len(newContainers)-1]
@@ -1029,9 +1054,9 @@ func (opts *ObjectsOpts) parse() (url.Values, Headers) {
}
// ObjectNames returns a slice of names of objects in a given container.
-func (c *Connection) ObjectNames(container string, opts *ObjectsOpts) ([]string, error) {
+func (c *Connection) ObjectNames(ctx context.Context, container string, opts *ObjectsOpts) ([]string, error) {
v, h := opts.parse()
- resp, _, err := c.storage(RequestOpts{
+ resp, _, err := c.storage(ctx, RequestOpts{
Container: container,
Operation: "GET",
Parameters: v,
@@ -1065,10 +1090,10 @@ type Object struct {
// with ContentType 'application/directory'. These are not real
// objects but represent directories of objects which haven't had an
// object created for them.
-func (c *Connection) Objects(container string, opts *ObjectsOpts) ([]Object, error) {
+func (c *Connection) Objects(ctx context.Context, container string, opts *ObjectsOpts) ([]Object, error) {
v, h := opts.parse()
v.Set("format", "json")
- resp, _, err := c.storage(RequestOpts{
+ resp, _, err := c.storage(ctx, RequestOpts{
Container: container,
Operation: "GET",
Parameters: v,
@@ -1130,10 +1155,10 @@ func objectsAllOpts(opts *ObjectsOpts, Limit int) *ObjectsOpts {
// A closure defined by the caller to iterate through all objects
//
-// Call Objects or ObjectNames from here with the *ObjectOpts passed in
+// Call Objects or ObjectNames from here with the context.Context and *ObjectOpts passed in
//
// Do whatever is required with the results then return them
-type ObjectsWalkFn func(*ObjectsOpts) (interface{}, error)
+type ObjectsWalkFn func(context.Context, *ObjectsOpts) (interface{}, error)
// ObjectsWalk is uses to iterate through all the objects in chunks as
// returned by Objects or ObjectNames using the Marker and Limit
@@ -1145,10 +1170,10 @@ type ObjectsWalkFn func(*ObjectsOpts) (interface{}, error)
// Errors will be returned from this function
//
// It has a default Limit parameter but you may pass in your own
-func (c *Connection) ObjectsWalk(container string, opts *ObjectsOpts, walkFn ObjectsWalkFn) error {
+func (c *Connection) ObjectsWalk(ctx context.Context, container string, opts *ObjectsOpts, walkFn ObjectsWalkFn) error {
opts = objectsAllOpts(opts, allObjectsChanLimit)
for {
- objects, err := walkFn(opts)
+ objects, err := walkFn(ctx, opts)
if err != nil {
return err
}
@@ -1168,7 +1193,7 @@ func (c *Connection) ObjectsWalk(container string, opts *ObjectsOpts, walkFn Obj
default:
panic("Unknown type returned to ObjectsWalk")
}
- if n < opts.Limit {
+ if c.isLastPage(n, opts.Limit) {
break
}
opts.Marker = last
@@ -1179,10 +1204,10 @@ func (c *Connection) ObjectsWalk(container string, opts *ObjectsOpts, walkFn Obj
// ObjectsAll is like Objects but it returns an unlimited number of Objects in a slice
//
// It calls Objects multiple times using the Marker parameter
-func (c *Connection) ObjectsAll(container string, opts *ObjectsOpts) ([]Object, error) {
+func (c *Connection) ObjectsAll(ctx context.Context, container string, opts *ObjectsOpts) ([]Object, error) {
objects := make([]Object, 0)
- err := c.ObjectsWalk(container, opts, func(opts *ObjectsOpts) (interface{}, error) {
- newObjects, err := c.Objects(container, opts)
+ err := c.ObjectsWalk(ctx, container, opts, func(ctx context.Context, opts *ObjectsOpts) (interface{}, error) {
+ newObjects, err := c.Objects(ctx, container, opts)
if err == nil {
objects = append(objects, newObjects...)
}
@@ -1197,10 +1222,10 @@ func (c *Connection) ObjectsAll(container string, opts *ObjectsOpts) ([]Object,
// reset unless KeepMarker is set
//
// It has a default Limit parameter but you may pass in your own
-func (c *Connection) ObjectNamesAll(container string, opts *ObjectsOpts) ([]string, error) {
+func (c *Connection) ObjectNamesAll(ctx context.Context, container string, opts *ObjectsOpts) ([]string, error) {
objects := make([]string, 0)
- err := c.ObjectsWalk(container, opts, func(opts *ObjectsOpts) (interface{}, error) {
- newObjects, err := c.ObjectNames(container, opts)
+ err := c.ObjectsWalk(ctx, container, opts, func(ctx context.Context, opts *ObjectsOpts) (interface{}, error) {
+ newObjects, err := c.ObjectNames(ctx, container, opts)
if err == nil {
objects = append(objects, newObjects...)
}
@@ -1227,9 +1252,9 @@ func getInt64FromHeader(resp *http.Response, header string) (result int64, err e
}
// Account returns info about the account in an Account struct.
-func (c *Connection) Account() (info Account, headers Headers, err error) {
+func (c *Connection) Account(ctx context.Context) (info Account, headers Headers, err error) {
var resp *http.Response
- resp, headers, err = c.storage(RequestOpts{
+ resp, headers, err = c.storage(ctx, RequestOpts{
Operation: "HEAD",
ErrorMap: ContainerErrorMap,
NoResponse: true,
@@ -1262,8 +1287,8 @@ func (c *Connection) Account() (info Account, headers Headers, err error) {
// Add or update keys by mentioning them in the Headers.
//
// Remove keys by setting them to an empty string.
-func (c *Connection) AccountUpdate(h Headers) error {
- _, _, err := c.storage(RequestOpts{
+func (c *Connection) AccountUpdate(ctx context.Context, h Headers) error {
+ _, _, err := c.storage(ctx, RequestOpts{
Operation: "POST",
ErrorMap: ContainerErrorMap,
NoResponse: true,
@@ -1277,8 +1302,8 @@ func (c *Connection) AccountUpdate(h Headers) error {
// If you don't want to add Headers just pass in nil
//
// No error is returned if it already exists but the metadata if any will be updated.
-func (c *Connection) ContainerCreate(container string, h Headers) error {
- _, _, err := c.storage(RequestOpts{
+func (c *Connection) ContainerCreate(ctx context.Context, container string, h Headers) error {
+ _, _, err := c.storage(ctx, RequestOpts{
Container: container,
Operation: "PUT",
ErrorMap: ContainerErrorMap,
@@ -1291,8 +1316,8 @@ func (c *Connection) ContainerCreate(container string, h Headers) error {
// ContainerDelete deletes a container.
//
// May return ContainerDoesNotExist or ContainerNotEmpty
-func (c *Connection) ContainerDelete(container string) error {
- _, _, err := c.storage(RequestOpts{
+func (c *Connection) ContainerDelete(ctx context.Context, container string) error {
+ _, _, err := c.storage(ctx, RequestOpts{
Container: container,
Operation: "DELETE",
ErrorMap: ContainerErrorMap,
@@ -1303,9 +1328,9 @@ func (c *Connection) ContainerDelete(container string) error {
// Container returns info about a single container including any
// metadata in the headers.
-func (c *Connection) Container(container string) (info Container, headers Headers, err error) {
+func (c *Connection) Container(ctx context.Context, container string) (info Container, headers Headers, err error) {
var resp *http.Response
- resp, headers, err = c.storage(RequestOpts{
+ resp, headers, err = c.storage(ctx, RequestOpts{
Container: container,
Operation: "HEAD",
ErrorMap: ContainerErrorMap,
@@ -1332,8 +1357,8 @@ func (c *Connection) Container(container string) (info Container, headers Header
// Remove keys by setting them to an empty string.
//
// Container metadata can only be read with Container() not with Containers().
-func (c *Connection) ContainerUpdate(container string, h Headers) error {
- _, _, err := c.storage(RequestOpts{
+func (c *Connection) ContainerUpdate(ctx context.Context, container string, h Headers) error {
+ _, _, err := c.storage(ctx, RequestOpts{
Container: container,
Operation: "POST",
ErrorMap: ContainerErrorMap,
@@ -1469,7 +1494,7 @@ func objectPutHeaders(objectName string, checkHash *bool, Hash string, contentTy
//
// If contentType is set it will be used, otherwise one will be
// guessed from objectName using mime.TypeByExtension
-func (c *Connection) ObjectCreate(container string, objectName string, checkHash bool, Hash string, contentType string, h Headers) (file *ObjectCreateFile, err error) {
+func (c *Connection) ObjectCreate(ctx context.Context, container string, objectName string, checkHash bool, Hash string, contentType string, h Headers) (file *ObjectCreateFile, err error) {
extraHeaders := objectPutHeaders(objectName, &checkHash, Hash, contentType, h)
pipeReader, pipeWriter := io.Pipe()
file = &ObjectCreateFile{
@@ -1490,15 +1515,15 @@ func (c *Connection) ObjectCreate(container string, objectName string, checkHash
NoResponse: true,
ErrorMap: objectErrorMap,
}
- file.resp, file.headers, file.err = c.storage(opts)
+ file.resp, file.headers, file.err = c.storage(ctx, opts)
// Signal finished
- pipeReader.Close()
+ _ = pipeReader.Close()
close(file.done)
}()
return
}
-func (c *Connection) ObjectSymlinkCreate(container string, symlink string, targetAccount string, targetContainer string, targetObject string, targetEtag string) (headers Headers, err error) {
+func (c *Connection) ObjectSymlinkCreate(ctx context.Context, container string, symlink string, targetAccount string, targetContainer string, targetObject string, targetEtag string) (headers Headers, err error) {
EMPTY_MD5 := "d41d8cd98f00b204e9800998ecf8427e"
symHeaders := Headers{}
@@ -1510,18 +1535,18 @@ func (c *Connection) ObjectSymlinkCreate(container string, symlink string, targe
symHeaders["X-Symlink-Target-Etag"] = targetEtag
}
symHeaders["X-Symlink-Target"] = fmt.Sprintf("%s/%s", targetContainer, targetObject)
- _, err = c.ObjectPut(container, symlink, contents, true, EMPTY_MD5, "application/symlink", symHeaders)
+ _, err = c.ObjectPut(ctx, container, symlink, contents, true, EMPTY_MD5, "application/symlink", symHeaders)
return
}
-func (c *Connection) objectPut(container string, objectName string, contents io.Reader, checkHash bool, Hash string, contentType string, h Headers, parameters url.Values) (headers Headers, err error) {
+func (c *Connection) objectPut(ctx context.Context, container string, objectName string, contents io.Reader, checkHash bool, Hash string, contentType string, h Headers, parameters url.Values) (headers Headers, err error) {
extraHeaders := objectPutHeaders(objectName, &checkHash, Hash, contentType, h)
hash := md5.New()
var body io.Reader = contents
if checkHash {
body = io.TeeReader(contents, hash)
}
- _, headers, err = c.storage(RequestOpts{
+ _, headers, err = c.storage(ctx, RequestOpts{
Container: container,
ObjectName: objectName,
Operation: "PUT",
@@ -1566,27 +1591,31 @@ func (c *Connection) objectPut(container string, objectName string, contents io.
//
// If contentType is set it will be used, otherwise one will be
// guessed from objectName using mime.TypeByExtension
-func (c *Connection) ObjectPut(container string, objectName string, contents io.Reader, checkHash bool, Hash string, contentType string, h Headers) (headers Headers, err error) {
- return c.objectPut(container, objectName, contents, checkHash, Hash, contentType, h, nil)
+func (c *Connection) ObjectPut(ctx context.Context, container string, objectName string, contents io.Reader, checkHash bool, Hash string, contentType string, h Headers) (headers Headers, err error) {
+ return c.objectPut(ctx, container, objectName, contents, checkHash, Hash, contentType, h, nil)
}
// ObjectPutBytes creates an object from a []byte in a container.
//
// This is a simplified interface which checks the MD5.
-func (c *Connection) ObjectPutBytes(container string, objectName string, contents []byte, contentType string) (err error) {
+func (c *Connection) ObjectPutBytes(ctx context.Context, container string, objectName string, contents []byte, contentType string) (err error) {
buf := bytes.NewBuffer(contents)
h := Headers{"Content-Length": strconv.Itoa(len(contents))}
- _, err = c.ObjectPut(container, objectName, buf, true, "", contentType, h)
+ hash := md5.Sum(contents)
+ hashStr := hex.EncodeToString(hash[:])
+ _, err = c.ObjectPut(ctx, container, objectName, buf, true, hashStr, contentType, h)
return
}
// ObjectPutString creates an object from a string in a container.
//
// This is a simplified interface which checks the MD5
-func (c *Connection) ObjectPutString(container string, objectName string, contents string, contentType string) (err error) {
+func (c *Connection) ObjectPutString(ctx context.Context, container string, objectName string, contents string, contentType string) (err error) {
buf := strings.NewReader(contents)
h := Headers{"Content-Length": strconv.Itoa(len(contents))}
- _, err = c.ObjectPut(container, objectName, buf, true, "", contentType, h)
+ hash := md5.Sum([]byte(contents))
+ hashStr := hex.EncodeToString(hash[:])
+ _, err = c.ObjectPut(ctx, container, objectName, buf, true, hashStr, contentType, h)
return
}
@@ -1636,7 +1665,7 @@ func (file *ObjectOpenFile) Read(p []byte) (n int, err error) {
// unlike os.File
//
// Seek(0, 1) will return the current file pointer.
-func (file *ObjectOpenFile) Seek(offset int64, whence int) (newPos int64, err error) {
+func (file *ObjectOpenFile) Seek(ctx context.Context, offset int64, whence int) (newPos int64, err error) {
file.overSeeked = false
switch whence {
case 0: // relative to start
@@ -1674,7 +1703,7 @@ func (file *ObjectOpenFile) Seek(offset int64, whence int) (newPos int64, err er
} else {
delete(file.headers, "Range")
}
- newFile, _, err := file.connection.ObjectOpen(file.container, file.objectName, false, file.headers)
+ newFile, _, err := file.connection.ObjectOpen(ctx, file.container, file.objectName, false, file.headers)
if err != nil {
return
}
@@ -1688,9 +1717,9 @@ func (file *ObjectOpenFile) Seek(offset int64, whence int) (newPos int64, err er
// Length gets the objects content length either from a cached copy or
// from the server.
-func (file *ObjectOpenFile) Length() (int64, error) {
+func (file *ObjectOpenFile) Length(ctx context.Context) (int64, error) {
if !file.lengthOk {
- info, _, err := file.connection.Object(file.container, file.objectName)
+ info, _, err := file.connection.Object(ctx, file.container, file.objectName)
file.length = info.Bytes
file.lengthOk = (err == nil)
return file.length, err
@@ -1711,7 +1740,9 @@ func (file *ObjectOpenFile) Close() (err error) {
// Check the MD5 sum if requested
if file.checkHash {
- receivedMd5 := strings.ToLower(file.resp.Header.Get("Etag"))
+ // ETag header may be double quoted if following RFC 7232
+ // https://github.com/openstack/swift/blob/2.24.0/CHANGELOG#L9
+ receivedMd5 := strings.ToLower(strings.Trim(file.resp.Header.Get("Etag"), "\""))
calculatedMd5 := fmt.Sprintf("%x", file.hash.Sum(nil))
if receivedMd5 != calculatedMd5 {
err = ObjectCorrupted
@@ -1727,11 +1758,7 @@ func (file *ObjectOpenFile) Close() (err error) {
return
}
-// Check it satisfies the interfaces
-var _ io.ReadCloser = &ObjectOpenFile{}
-var _ io.Seeker = &ObjectOpenFile{}
-
-func (c *Connection) objectOpenBase(container string, objectName string, checkHash bool, h Headers, parameters url.Values) (file *ObjectOpenFile, headers Headers, err error) {
+func (c *Connection) objectOpenBase(ctx context.Context, container string, objectName string, checkHash bool, h Headers, parameters url.Values) (file *ObjectOpenFile, headers Headers, err error) {
var resp *http.Response
opts := RequestOpts{
Container: container,
@@ -1741,7 +1768,7 @@ func (c *Connection) objectOpenBase(container string, objectName string, checkHa
Headers: h,
Parameters: parameters,
}
- resp, headers, err = c.storage(opts)
+ resp, headers, err = c.storage(ctx, opts)
if err != nil {
return
}
@@ -1771,9 +1798,9 @@ func (c *Connection) objectOpenBase(container string, objectName string, checkHa
return
}
-func (c *Connection) objectOpen(container string, objectName string, checkHash bool, h Headers, parameters url.Values) (file *ObjectOpenFile, headers Headers, err error) {
+func (c *Connection) objectOpen(ctx context.Context, container string, objectName string, checkHash bool, h Headers, parameters url.Values) (file *ObjectOpenFile, headers Headers, err error) {
err = withLORetry(0, func() (Headers, int64, error) {
- file, headers, err = c.objectOpenBase(container, objectName, checkHash, h, parameters)
+ file, headers, err = c.objectOpenBase(ctx, container, objectName, checkHash, h, parameters)
if err != nil {
return headers, 0, err
}
@@ -1805,8 +1832,8 @@ func (c *Connection) objectOpen(container string, objectName string, checkHash b
// you will need to download everything in the manifest separately.
//
// headers["Content-Type"] will give the content type if desired.
-func (c *Connection) ObjectOpen(container string, objectName string, checkHash bool, h Headers) (file *ObjectOpenFile, headers Headers, err error) {
- return c.objectOpen(container, objectName, checkHash, h, nil)
+func (c *Connection) ObjectOpen(ctx context.Context, container string, objectName string, checkHash bool, h Headers) (file *ObjectOpenFile, headers Headers, err error) {
+ return c.objectOpen(ctx, container, objectName, checkHash, h, nil)
}
// ObjectGet gets the object into the io.Writer contents.
@@ -1818,8 +1845,8 @@ func (c *Connection) ObjectOpen(container string, objectName string, checkHash b
// server. If it is wrong then it will return ObjectCorrupted.
//
// headers["Content-Type"] will give the content type if desired.
-func (c *Connection) ObjectGet(container string, objectName string, contents io.Writer, checkHash bool, h Headers) (headers Headers, err error) {
- file, headers, err := c.ObjectOpen(container, objectName, checkHash, h)
+func (c *Connection) ObjectGet(ctx context.Context, container string, objectName string, contents io.Writer, checkHash bool, h Headers) (headers Headers, err error) {
+ file, headers, err := c.ObjectOpen(ctx, container, objectName, checkHash, h)
if err != nil {
return
}
@@ -1831,9 +1858,9 @@ func (c *Connection) ObjectGet(container string, objectName string, contents io.
// ObjectGetBytes returns an object as a []byte.
//
// This is a simplified interface which checks the MD5
-func (c *Connection) ObjectGetBytes(container string, objectName string) (contents []byte, err error) {
+func (c *Connection) ObjectGetBytes(ctx context.Context, container string, objectName string) (contents []byte, err error) {
var buf bytes.Buffer
- _, err = c.ObjectGet(container, objectName, &buf, true, nil)
+ _, err = c.ObjectGet(ctx, container, objectName, &buf, true, nil)
contents = buf.Bytes()
return
}
@@ -1841,9 +1868,9 @@ func (c *Connection) ObjectGetBytes(container string, objectName string) (conten
// ObjectGetString returns an object as a string.
//
// This is a simplified interface which checks the MD5
-func (c *Connection) ObjectGetString(container string, objectName string) (contents string, err error) {
+func (c *Connection) ObjectGetString(ctx context.Context, container string, objectName string) (contents string, err error) {
var buf bytes.Buffer
- _, err = c.ObjectGet(container, objectName, &buf, true, nil)
+ _, err = c.ObjectGet(ctx, container, objectName, &buf, true, nil)
contents = buf.String()
return
}
@@ -1851,8 +1878,8 @@ func (c *Connection) ObjectGetString(container string, objectName string) (conte
// ObjectDelete deletes the object.
//
// May return ObjectNotFound if the object isn't found
-func (c *Connection) ObjectDelete(container string, objectName string) error {
- _, _, err := c.storage(RequestOpts{
+func (c *Connection) ObjectDelete(ctx context.Context, container string, objectName string) error {
+ _, _, err := c.storage(ctx, RequestOpts{
Container: container,
ObjectName: objectName,
Operation: "DELETE",
@@ -1863,8 +1890,15 @@ func (c *Connection) ObjectDelete(container string, objectName string) error {
// ObjectTempUrl returns a temporary URL for an object
func (c *Connection) ObjectTempUrl(container string, objectName string, secretKey string, method string, expires time.Time) string {
+ c.authLock.Lock()
+ storageUrl := c.StorageUrl
+ c.authLock.Unlock()
+ if storageUrl == "" {
+ return "" // Cannot do better without changing the interface
+ }
+
mac := hmac.New(sha1.New, []byte(secretKey))
- prefix, _ := url.Parse(c.StorageUrl)
+ prefix, _ := url.Parse(storageUrl)
body := fmt.Sprintf("%s\n%d\n%s/%s/%s", method, expires.Unix(), prefix.Path, container, objectName)
mac.Write([]byte(body))
sig := hex.EncodeToString(mac.Sum(nil))
@@ -1909,7 +1943,7 @@ type BulkDeleteResult struct {
Headers Headers // Response HTTP headers.
}
-func (c *Connection) doBulkDelete(objects []string, h Headers) (result BulkDeleteResult, err error) {
+func (c *Connection) doBulkDelete(ctx context.Context, objects []string, h Headers) (result BulkDeleteResult, err error) {
var buffer bytes.Buffer
for _, s := range objects {
u := url.URL{Path: s}
@@ -1923,7 +1957,7 @@ func (c *Connection) doBulkDelete(objects []string, h Headers) (result BulkDelet
for key, value := range h {
extraHeaders[key] = value
}
- resp, headers, err := c.storage(RequestOpts{
+ resp, headers, err := c.storage(ctx, RequestOpts{
Operation: "DELETE",
Parameters: url.Values{"bulk-delete": []string{"1"}},
Headers: extraHeaders,
@@ -1967,8 +2001,8 @@ func (c *Connection) doBulkDelete(objects []string, h Headers) (result BulkDelet
// See also:
// * http://docs.openstack.org/trunk/openstack-object-storage/admin/content/object-storage-bulk-delete.html
// * http://docs.rackspace.com/files/api/v1/cf-devguide/content/Bulk_Delete-d1e2338.html
-func (c *Connection) BulkDelete(container string, objectNames []string) (result BulkDeleteResult, err error) {
- return c.BulkDeleteHeaders(container, objectNames, nil)
+func (c *Connection) BulkDelete(ctx context.Context, container string, objectNames []string) (result BulkDeleteResult, err error) {
+ return c.BulkDeleteHeaders(ctx, container, objectNames, nil)
}
// BulkDeleteHeaders deletes multiple objectNames from container in one operation.
@@ -1979,7 +2013,7 @@ func (c *Connection) BulkDelete(container string, objectNames []string) (result
// See also:
// * http://docs.openstack.org/trunk/openstack-object-storage/admin/content/object-storage-bulk-delete.html
// * http://docs.rackspace.com/files/api/v1/cf-devguide/content/Bulk_Delete-d1e2338.html
-func (c *Connection) BulkDeleteHeaders(container string, objectNames []string, h Headers) (result BulkDeleteResult, err error) {
+func (c *Connection) BulkDeleteHeaders(ctx context.Context, container string, objectNames []string, h Headers) (result BulkDeleteResult, err error) {
if len(objectNames) == 0 {
result.Errors = make(map[string]error)
return
@@ -1988,7 +2022,7 @@ func (c *Connection) BulkDeleteHeaders(container string, objectNames []string, h
for i, name := range objectNames {
fullPaths[i] = fmt.Sprintf("/%s/%s", container, name)
}
- return c.doBulkDelete(fullPaths, h)
+ return c.doBulkDelete(ctx, fullPaths, h)
}
// BulkUploadResult stores results of BulkUpload().
@@ -2021,14 +2055,14 @@ type BulkUploadResult struct {
// See also:
// * http://docs.openstack.org/trunk/openstack-object-storage/admin/content/object-storage-extract-archive.html
// * http://docs.rackspace.com/files/api/v1/cf-devguide/content/Extract_Archive-d1e2338.html
-func (c *Connection) BulkUpload(uploadPath string, dataStream io.Reader, format string, h Headers) (result BulkUploadResult, err error) {
+func (c *Connection) BulkUpload(ctx context.Context, uploadPath string, dataStream io.Reader, format string, h Headers) (result BulkUploadResult, err error) {
extraHeaders := Headers{"Accept": "application/json"}
for key, value := range h {
extraHeaders[key] = value
}
// The following code abuses Container parameter intentionally.
// The best fix might be to rename Container to UploadPath.
- resp, headers, err := c.storage(RequestOpts{
+ resp, headers, err := c.storage(ctx, RequestOpts{
Container: uploadPath,
Operation: "PUT",
Parameters: url.Values{"extract-archive": []string{format}},
@@ -2073,9 +2107,9 @@ func (c *Connection) BulkUpload(uploadPath string, dataStream io.Reader, format
// May return ObjectNotFound.
//
// Use headers.ObjectMetadata() to read the metadata in the Headers.
-func (c *Connection) Object(container string, objectName string) (info Object, headers Headers, err error) {
+func (c *Connection) Object(ctx context.Context, container string, objectName string) (info Object, headers Headers, err error) {
err = withLORetry(0, func() (Headers, int64, error) {
- info, headers, err = c.objectBase(container, objectName)
+ info, headers, err = c.objectBase(ctx, container, objectName)
if err != nil {
return headers, 0, err
}
@@ -2084,9 +2118,9 @@ func (c *Connection) Object(container string, objectName string) (info Object, h
return
}
-func (c *Connection) objectBase(container string, objectName string) (info Object, headers Headers, err error) {
+func (c *Connection) objectBase(ctx context.Context, container string, objectName string) (info Object, headers Headers, err error) {
var resp *http.Response
- resp, headers, err = c.storage(RequestOpts{
+ resp, headers, err = c.storage(ctx, RequestOpts{
Container: container,
ObjectName: objectName,
Operation: "HEAD",
@@ -2124,7 +2158,9 @@ func (c *Connection) objectBase(container string, objectName string) (info Objec
}
}
- info.Hash = resp.Header.Get("Etag")
+ // ETag header may be double quoted if following RFC 7232
+ // https://github.com/openstack/swift/blob/2.24.0/CHANGELOG#L9
+ info.Hash = strings.Trim(resp.Header.Get("Etag"), "\"")
if resp.Header.Get("X-Object-Manifest") != "" {
info.ObjectType = DynamicLargeObjectType
} else if resp.Header.Get("X-Static-Large-Object") != "" {
@@ -2156,8 +2192,8 @@ func (c *Connection) objectBase(container string, objectName string) (info Objec
// other headers such as Content-Type or CORS headers.
//
// May return ObjectNotFound.
-func (c *Connection) ObjectUpdate(container string, objectName string, h Headers) error {
- _, _, err := c.storage(RequestOpts{
+func (c *Connection) ObjectUpdate(ctx context.Context, container string, objectName string, h Headers) error {
+ _, _, err := c.storage(ctx, RequestOpts{
Container: container,
ObjectName: objectName,
Operation: "POST",
@@ -2186,7 +2222,7 @@ func urlPathEscape(in string) string {
//
// You can use this to copy an object to itself - this is the only way
// to update the content type of an object.
-func (c *Connection) ObjectCopy(srcContainer string, srcObjectName string, dstContainer string, dstObjectName string, h Headers) (headers Headers, err error) {
+func (c *Connection) ObjectCopy(ctx context.Context, srcContainer string, srcObjectName string, dstContainer string, dstObjectName string, h Headers) (headers Headers, err error) {
// Meta stuff
extraHeaders := map[string]string{
"Destination": urlPathEscape(dstContainer + "/" + dstObjectName),
@@ -2194,7 +2230,7 @@ func (c *Connection) ObjectCopy(srcContainer string, srcObjectName string, dstCo
for key, value := range h {
extraHeaders[key] = value
}
- _, headers, err = c.storage(RequestOpts{
+ _, headers, err = c.storage(ctx, RequestOpts{
Container: srcContainer,
ObjectName: srcObjectName,
Operation: "COPY",
@@ -2212,12 +2248,12 @@ func (c *Connection) ObjectCopy(srcContainer string, srcObjectName string, dstCo
// All metadata is preserved.
//
// The destination container must exist before the copy.
-func (c *Connection) ObjectMove(srcContainer string, srcObjectName string, dstContainer string, dstObjectName string) (err error) {
- _, err = c.ObjectCopy(srcContainer, srcObjectName, dstContainer, dstObjectName, nil)
+func (c *Connection) ObjectMove(ctx context.Context, srcContainer string, srcObjectName string, dstContainer string, dstObjectName string) (err error) {
+ _, err = c.ObjectCopy(ctx, srcContainer, srcObjectName, dstContainer, dstObjectName, nil)
if err != nil {
return
}
- return c.ObjectDelete(srcContainer, srcObjectName)
+ return c.ObjectDelete(ctx, srcContainer, srcObjectName)
}
// ObjectUpdateContentType updates the content type of an object
@@ -2225,9 +2261,9 @@ func (c *Connection) ObjectMove(srcContainer string, srcObjectName string, dstCo
// This is a convenience method which calls ObjectCopy
//
// All other metadata is preserved.
-func (c *Connection) ObjectUpdateContentType(container string, objectName string, contentType string) (err error) {
+func (c *Connection) ObjectUpdateContentType(ctx context.Context, container string, objectName string, contentType string) (err error) {
h := Headers{"Content-Type": contentType}
- _, err = c.ObjectCopy(container, objectName, container, objectName, h)
+ _, err = c.ObjectCopy(ctx, container, objectName, container, objectName, h)
return
}
@@ -2239,14 +2275,14 @@ func (c *Connection) ObjectUpdateContentType(container string, objectName string
//
// If the server doesn't support versioning then it will return
// Forbidden however it will have created both the containers at that point.
-func (c *Connection) VersionContainerCreate(current, version string) error {
- if err := c.ContainerCreate(version, nil); err != nil {
+func (c *Connection) VersionContainerCreate(ctx context.Context, current, version string) error {
+ if err := c.ContainerCreate(ctx, version, nil); err != nil {
return err
}
- if err := c.ContainerCreate(current, nil); err != nil {
+ if err := c.ContainerCreate(ctx, current, nil); err != nil {
return err
}
- if err := c.VersionEnable(current, version); err != nil {
+ if err := c.VersionEnable(ctx, current, version); err != nil {
return err
}
return nil
@@ -2255,13 +2291,13 @@ func (c *Connection) VersionContainerCreate(current, version string) error {
// VersionEnable enables versioning on the current container with version as the tracking container.
//
// May return Forbidden if this isn't supported by the server
-func (c *Connection) VersionEnable(current, version string) error {
+func (c *Connection) VersionEnable(ctx context.Context, current, version string) error {
h := Headers{"X-Versions-Location": version}
- if err := c.ContainerUpdate(current, h); err != nil {
+ if err := c.ContainerUpdate(ctx, current, h); err != nil {
return err
}
// Check to see if the header was set properly
- _, headers, err := c.Container(current)
+ _, headers, err := c.Container(ctx, current)
if err != nil {
return err
}
@@ -2273,9 +2309,9 @@ func (c *Connection) VersionEnable(current, version string) error {
}
// VersionDisable disables versioning on the current container.
-func (c *Connection) VersionDisable(current string) error {
+func (c *Connection) VersionDisable(ctx context.Context, current string) error {
h := Headers{"X-Versions-Location": ""}
- if err := c.ContainerUpdate(current, h); err != nil {
+ if err := c.ContainerUpdate(ctx, current, h); err != nil {
return err
}
return nil
@@ -2284,10 +2320,25 @@ func (c *Connection) VersionDisable(current string) error {
// VersionObjectList returns a list of older versions of the object.
//
// Objects are returned in the format <length><object_name>/<timestamp>
-func (c *Connection) VersionObjectList(version, object string) ([]string, error) {
+func (c *Connection) VersionObjectList(ctx context.Context, version, object string) ([]string, error) {
opts := &ObjectsOpts{
// <3-character zero-padded hexadecimal character length><object name>/
Prefix: fmt.Sprintf("%03x", len(object)) + object + "/",
}
- return c.ObjectNames(version, opts)
+ return c.ObjectNames(ctx, version, opts)
+}
+
+// GetStorageUrl returns Swift storage URL.
+func (c *Connection) GetStorageUrl(ctx context.Context) (string, error) {
+ c.authLock.Lock()
+ defer c.authLock.Unlock()
+
+ // Return cached URL even if authentication has expired
+ if c.StorageUrl == "" {
+ err := c.authenticate(ctx)
+ if err != nil {
+ return "", err
+ }
+ }
+ return c.StorageUrl, nil
}
diff --git a/swift_internal_test.go b/swift_internal_test.go
index 894fd8f..cddf739 100644
--- a/swift_internal_test.go
+++ b/swift_internal_test.go
@@ -6,6 +6,7 @@
package swift
import (
+ "context"
"fmt"
"io"
"net"
@@ -149,13 +150,15 @@ func handle(w http.ResponseWriter, r *http.Request) {
func NewSwiftServer() *SwiftServer {
server := &SwiftServer{}
http.HandleFunc("/", handle)
- go http.ListenAndServe(TEST_ADDRESS, nil)
+ go func() {
+ _ = http.ListenAndServe(TEST_ADDRESS, nil)
+ }()
fmt.Print("Waiting for server to start ")
for {
fmt.Print(".")
conn, err := net.Dial("tcp", TEST_ADDRESS)
if err == nil {
- conn.Close()
+ _ = conn.Close()
fmt.Println(" Started")
break
}
@@ -316,7 +319,8 @@ func TestInternalAuthenticate(t *testing.T) {
}).Url("/v1.0")
defer server.Finished()
- err := c.Authenticate()
+ ctx := context.Background()
+ err := c.Authenticate(ctx)
if err != nil {
t.Fatal(err)
}
@@ -336,7 +340,7 @@ func TestInternalAuthenticateDenied(t *testing.T) {
server.AddCheck(t).Error(401, "DENIED")
defer server.Finished()
c.UnAuthenticate()
- err := c.Authenticate()
+ err := c.Authenticate(context.Background())
if err != AuthorizationFailed {
t.Fatal("Expecting AuthorizationFailed", err)
}
@@ -351,7 +355,8 @@ func TestInternalAuthenticateBad(t *testing.T) {
"X-Storage-Url": PROXY_URL,
})
defer server.Finished()
- err := c.Authenticate()
+ ctx := context.Background()
+ err := c.Authenticate(ctx)
checkError(t, err, 0, "Response didn't have storage url and auth token")
if c.Authenticated() {
t.Fatal("Expecting not authenticated")
@@ -360,14 +365,14 @@ func TestInternalAuthenticateBad(t *testing.T) {
server.AddCheck(t).Out(Headers{
"X-Auth-Token": AUTH_TOKEN,
})
- err = c.Authenticate()
+ err = c.Authenticate(ctx)
checkError(t, err, 0, "Response didn't have storage url and auth token")
if c.Authenticated() {
t.Fatal("Expecting not authenticated")
}
server.AddCheck(t)
- err = c.Authenticate()
+ err = c.Authenticate(ctx)
checkError(t, err, 0, "Response didn't have storage url and auth token")
if c.Authenticated() {
t.Fatal("Expecting not authenticated")
@@ -377,7 +382,7 @@ func TestInternalAuthenticateBad(t *testing.T) {
"X-Storage-Url": PROXY_URL,
"X-Auth-Token": AUTH_TOKEN,
})
- err = c.Authenticate()
+ err = c.Authenticate(ctx)
if err != nil {
t.Fatal(err)
}
@@ -391,7 +396,7 @@ func testContainerNames(t *testing.T, rx string, expected []string) {
"User-Agent": DefaultUserAgent,
"X-Auth-Token": AUTH_TOKEN,
}).Tx(rx).Url("/proxy")
- containers, err := c.ContainerNames(nil)
+ containers, err := c.ContainerNames(context.Background(), nil)
if err != nil {
t.Fatal(err)
}
@@ -420,7 +425,10 @@ func TestInternalObjectPutBytes(t *testing.T) {
"Content-Type": "text/plain",
}).Rx("12345")
defer server.Finished()
- c.ObjectPutBytes("container", "object", []byte{'1', '2', '3', '4', '5'}, "text/plain")
+ err := c.ObjectPutBytes(context.Background(), "container", "object", []byte{'1', '2', '3', '4', '5'}, "text/plain")
+ if err != nil {
+ t.Fatal("ObjectPutBytes", err)
+ }
}
func TestInternalObjectPutString(t *testing.T) {
@@ -431,20 +439,23 @@ func TestInternalObjectPutString(t *testing.T) {
"Content-Type": "text/plain",
}).Rx("12345")
defer server.Finished()
- c.ObjectPutString("container", "object", "12345", "text/plain")
+ err := c.ObjectPutString(context.Background(), "container", "object", "12345", "text/plain")
+ if err != nil {
+ t.Fatal(err)
+ }
}
func TestSetFromEnv(t *testing.T) {
// String
s := ""
- os.Setenv("POTATO", "")
+ _ = os.Setenv("POTATO", "")
err := setFromEnv(&s, "POTATO")
if err != nil {
t.Fatal(err)
}
- os.Setenv("POTATO", "this is a test")
+ _ = os.Setenv("POTATO", "this is a test")
err = setFromEnv(&s, "POTATO")
if err != nil {
t.Fatal(err)
@@ -453,7 +464,7 @@ func TestSetFromEnv(t *testing.T) {
t.Fatal("incorrect", s)
}
- os.Setenv("POTATO", "new")
+ _ = os.Setenv("POTATO", "new")
err = setFromEnv(&s, "POTATO")
if err != nil {
t.Fatal(err)
@@ -465,7 +476,7 @@ func TestSetFromEnv(t *testing.T) {
// Integer
i := 0
- os.Setenv("POTATO", "42")
+ _ = os.Setenv("POTATO", "42")
err = setFromEnv(&i, "POTATO")
if err != nil {
t.Fatal(err)
@@ -474,7 +485,7 @@ func TestSetFromEnv(t *testing.T) {
t.Fatal("incorrect", i)
}
- os.Setenv("POTATO", "43")
+ _ = os.Setenv("POTATO", "43")
err = setFromEnv(&i, "POTATO")
if err != nil {
t.Fatal(err)
@@ -484,7 +495,7 @@ func TestSetFromEnv(t *testing.T) {
}
i = 0
- os.Setenv("POTATO", "not a number")
+ _ = os.Setenv("POTATO", "not a number")
err = setFromEnv(&i, "POTATO")
if err == nil {
t.Fatal("expecting error but didn't get one")
@@ -492,7 +503,7 @@ func TestSetFromEnv(t *testing.T) {
// bool
var b bool
- os.Setenv("POTATO", "1")
+ _ = os.Setenv("POTATO", "1")
err = setFromEnv(&b, "POTATO")
if err != nil {
t.Fatal(err)
@@ -503,7 +514,7 @@ func TestSetFromEnv(t *testing.T) {
// time.Duration
var dt time.Duration
- os.Setenv("POTATO", "5s")
+ _ = os.Setenv("POTATO", "5s")
err = setFromEnv(&dt, "POTATO")
if err != nil {
t.Fatal(err)
@@ -514,7 +525,7 @@ func TestSetFromEnv(t *testing.T) {
// EndpointType
var e EndpointType
- os.Setenv("POTATO", "internal")
+ _ = os.Setenv("POTATO", "internal")
err = setFromEnv(&e, "POTATO")
if err != nil {
t.Fatal(err)
@@ -530,13 +541,13 @@ func TestSetFromEnv(t *testing.T) {
t.Fatal("expecting error")
}
- os.Setenv("POTATO", "")
+ _ = os.Setenv("POTATO", "")
}
func TestApplyEnvironment(t *testing.T) {
// We've tested all the setting logic above, so just do a quick test here
c := new(Connection)
- os.Setenv("GOSWIFT_CONNECT_TIMEOUT", "100s")
+ _ = os.Setenv("GOSWIFT_CONNECT_TIMEOUT", "100s")
err := c.ApplyEnvironment()
if err != nil {
t.Fatal(err)
@@ -546,7 +557,7 @@ func TestApplyEnvironment(t *testing.T) {
}
c.ConnectTimeout = 0
- os.Setenv("GOSWIFT_CONNECT_TIMEOUT", "parse error")
+ _ = os.Setenv("GOSWIFT_CONNECT_TIMEOUT", "parse error")
err = c.ApplyEnvironment()
if err == nil {
t.Fatal("expecting error")
@@ -555,7 +566,7 @@ func TestApplyEnvironment(t *testing.T) {
t.Fatal("timeout incorrect", c.ConnectTimeout)
}
- os.Setenv("GOSWIFT_CONNECT_TIMEOUT", "")
+ _ = os.Setenv("GOSWIFT_CONNECT_TIMEOUT", "")
}
func TestApplyEnvironmentAll(t *testing.T) {
@@ -605,7 +616,7 @@ func TestApplyEnvironmentAll(t *testing.T) {
item := &items[i]
if item.phase == phase {
item.oldValue = os.Getenv(item.name) // save old value
- os.Setenv(item.name, item.value) // set new value
+ _ = os.Setenv(item.name, item.value) // set new value
}
}
@@ -621,9 +632,140 @@ func TestApplyEnvironmentAll(t *testing.T) {
if !reflect.DeepEqual(item.want, got) {
t.Errorf("%s: %v != %v", item.name, item.want, got)
}
- os.Setenv(item.name, item.oldValue) // restore old value
+ _ = os.Setenv(item.name, item.oldValue) // restore old value
}
}
}
}
+
+func TestIsLastPage(t *testing.T) {
+ conn := &Connection{}
+ testPaging(t, conn, []pagingTest{
+ {
+ length: 0,
+ limit: 1000,
+ expected: true,
+ },
+ {
+ length: 850,
+ limit: 1000,
+ expected: true,
+ },
+ {
+ length: 950,
+ limit: 1000,
+ expected: true,
+ },
+ {
+ length: 1000,
+ limit: 1000,
+ expected: false,
+ },
+ // For completeness
+ {
+ length: 0,
+ limit: 0,
+ expected: false,
+ },
+ {
+ length: 2000,
+ limit: 1000,
+ expected: false,
+ },
+ })
+
+}
+
+func TestFetchUntilEmptyPageWorkaround(t *testing.T) {
+ conn := &Connection{
+ FetchUntilEmptyPage: true,
+ }
+ testPaging(t, conn, []pagingTest{
+ {
+ length: 0,
+ limit: 1000,
+ expected: true,
+ },
+ {
+ length: 850,
+ limit: 1000,
+ expected: false,
+ },
+ {
+ length: 950,
+ limit: 1000,
+ expected: false,
+ },
+ {
+ length: 1000,
+ limit: 1000,
+ expected: false,
+ },
+ // For completeness
+ {
+ length: 0,
+ limit: 0,
+ expected: false,
+ },
+ {
+ length: 2000,
+ limit: 1000,
+ expected: false,
+ },
+ })
+}
+
+func TestPartialPageFetchThreshold(t *testing.T) {
+ conn := &Connection{
+ PartialPageFetchThreshold: 90,
+ }
+ testPaging(t, conn, []pagingTest{
+ {
+ length: 0,
+ limit: 1000,
+ expected: true,
+ },
+ {
+ length: 850,
+ limit: 1000,
+ expected: true,
+ },
+ {
+ length: 950,
+ limit: 1000,
+ expected: false,
+ },
+ {
+ length: 1000,
+ limit: 1000,
+ expected: false,
+ },
+ // For completeness
+ {
+ length: 0,
+ limit: 0,
+ expected: false,
+ },
+ {
+ length: 2000,
+ limit: 1000,
+ expected: false,
+ },
+ })
+
+}
+
+type pagingTest struct {
+ length int
+ limit int
+ expected bool
+}
+
+func testPaging(t *testing.T, conn *Connection, testCases []pagingTest) {
+ for _, tCase := range testCases {
+ if actual := conn.isLastPage(tCase.length, tCase.limit); actual != tCase.expected {
+ t.Fatalf("isLastPage(%d, %d) returned %t, expected %t", tCase.length, tCase.limit, actual, tCase.expected)
+ }
+ }
+}
diff --git a/swift_test.go b/swift_test.go
index 6c10935..f75ad8e 100644
--- a/swift_test.go
+++ b/swift_test.go
@@ -15,6 +15,7 @@ package swift_test
import (
"archive/tar"
"bytes"
+ "context"
"crypto/md5"
"crypto/rand"
"crypto/tls"
@@ -33,8 +34,8 @@ import (
"testing"
"time"
- "github.com/ncw/swift"
- "github.com/ncw/swift/swifttest"
+ "github.com/ncw/swift/v2"
+ "github.com/ncw/swift/v2/swifttest"
)
var (
@@ -144,8 +145,9 @@ func makeConnection(t *testing.T) (*swift.Connection, func()) {
}
func makeConnectionAuth(t *testing.T) (*swift.Connection, func()) {
+ ctx := context.Background()
c, rollback := makeConnection(t)
- err := c.Authenticate()
+ err := c.Authenticate(ctx)
if err != nil {
t.Fatal("Auth failed", err)
}
@@ -153,32 +155,35 @@ func makeConnectionAuth(t *testing.T) (*swift.Connection, func()) {
}
func makeConnectionWithContainer(t *testing.T) (*swift.Connection, func()) {
+ ctx := context.Background()
c, rollback := makeConnectionAuth(t)
- err := c.ContainerCreate(CONTAINER, m1.ContainerHeaders())
+ err := c.ContainerCreate(ctx, CONTAINER, m1.ContainerHeaders())
if err != nil {
t.Fatal(err)
}
return c, func() {
- c.ContainerDelete(CONTAINER)
+ _ = c.ContainerDelete(ctx, CONTAINER)
rollback()
}
}
func makeConnectionWithObject(t *testing.T) (*swift.Connection, func()) {
+ ctx := context.Background()
c, rollback := makeConnectionWithContainer(t)
- err := c.ObjectPutString(CONTAINER, OBJECT, CONTENTS, "")
+ err := c.ObjectPutString(ctx, CONTAINER, OBJECT, CONTENTS, "")
if err != nil {
t.Fatal(err)
}
return c, func() {
- c.ObjectDelete(CONTAINER, OBJECT)
+ _ = c.ObjectDelete(ctx, CONTAINER, OBJECT)
rollback()
}
}
func makeConnectionWithObjectHeaders(t *testing.T) (*swift.Connection, func()) {
+ ctx := context.Background()
c, rollback := makeConnectionWithObject(t)
- err := c.ObjectUpdate(CONTAINER, OBJECT, m1.ObjectHeaders())
+ err := c.ObjectUpdate(ctx, CONTAINER, OBJECT, m1.ObjectHeaders())
if err != nil {
t.Fatal(err)
}
@@ -186,11 +191,12 @@ func makeConnectionWithObjectHeaders(t *testing.T) (*swift.Connection, func()) {
}
func makeConnectionWithVersionsContainer(t *testing.T) (*swift.Connection, func()) {
+ ctx := context.Background()
c, rollback := makeConnectionAuth(t)
- err := c.VersionContainerCreate(CURRENT_CONTAINER, VERSIONS_CONTAINER)
+ err := c.VersionContainerCreate(ctx, CURRENT_CONTAINER, VERSIONS_CONTAINER)
newRollback := func() {
- c.ContainerDelete(CURRENT_CONTAINER)
- c.ContainerDelete(VERSIONS_CONTAINER)
+ _ = c.ContainerDelete(ctx, CURRENT_CONTAINER)
+ _ = c.ContainerDelete(ctx, VERSIONS_CONTAINER)
rollback()
}
if err != nil {
@@ -204,34 +210,36 @@ func makeConnectionWithVersionsContainer(t *testing.T) (*swift.Connection, func(
}
func makeConnectionWithVersionsObject(t *testing.T) (*swift.Connection, func()) {
+ ctx := context.Background()
c, rollback := makeConnectionWithVersionsContainer(t)
- if err := c.ObjectPutString(CURRENT_CONTAINER, OBJECT, CONTENTS, ""); err != nil {
+ if err := c.ObjectPutString(ctx, CURRENT_CONTAINER, OBJECT, CONTENTS, ""); err != nil {
t.Fatal(err)
}
// Version 2
- if err := c.ObjectPutString(CURRENT_CONTAINER, OBJECT, CONTENTS2, ""); err != nil {
+ if err := c.ObjectPutString(ctx, CURRENT_CONTAINER, OBJECT, CONTENTS2, ""); err != nil {
t.Fatal(err)
}
// Version 3
- if err := c.ObjectPutString(CURRENT_CONTAINER, OBJECT, CONTENTS2, ""); err != nil {
+ if err := c.ObjectPutString(ctx, CURRENT_CONTAINER, OBJECT, CONTENTS2, ""); err != nil {
t.Fatal(err)
}
return c, func() {
for i := 0; i < 3; i++ {
- c.ObjectDelete(CURRENT_CONTAINER, OBJECT)
+ _ = c.ObjectDelete(ctx, CURRENT_CONTAINER, OBJECT)
}
rollback()
}
}
func makeConnectionWithSegmentsContainer(t *testing.T) (*swift.Connection, func()) {
+ ctx := context.Background()
c, rollback := makeConnectionWithContainer(t)
- err := c.ContainerCreate(SEGMENTS_CONTAINER, swift.Headers{})
+ err := c.ContainerCreate(ctx, SEGMENTS_CONTAINER, swift.Headers{})
if err != nil {
t.Fatal(err)
}
return c, func() {
- err = c.ContainerDelete(SEGMENTS_CONTAINER)
+ err = c.ContainerDelete(ctx, SEGMENTS_CONTAINER)
if err != nil {
t.Fatal(err)
}
@@ -240,13 +248,14 @@ func makeConnectionWithSegmentsContainer(t *testing.T) (*swift.Connection, func(
}
func makeConnectionWithDLO(t *testing.T) (*swift.Connection, func()) {
+ ctx := context.Background()
c, rollback := makeConnectionWithSegmentsContainer(t)
opts := swift.LargeObjectOpts{
Container: CONTAINER,
ObjectName: OBJECT,
ContentType: "image/jpeg",
}
- out, err := c.DynamicLargeObjectCreate(&opts)
+ out, err := c.DynamicLargeObjectCreate(ctx, &opts)
if err != nil {
t.Fatal(err)
}
@@ -256,24 +265,25 @@ func makeConnectionWithDLO(t *testing.T) (*swift.Connection, func()) {
t.Fatal(err)
}
}
- err = out.Close()
+ err = out.CloseWithContext(ctx)
if err != nil {
t.Error(err)
}
return c, func() {
- c.DynamicLargeObjectDelete(CONTAINER, OBJECT)
+ _ = c.DynamicLargeObjectDelete(ctx, CONTAINER, OBJECT)
rollback()
}
}
func makeConnectionWithSLO(t *testing.T) (*swift.Connection, func()) {
+ ctx := context.Background()
c, rollback := makeConnectionWithSegmentsContainer(t)
opts := swift.LargeObjectOpts{
Container: CONTAINER,
ObjectName: OBJECT,
ContentType: "image/jpeg",
}
- out, err := c.StaticLargeObjectCreate(&opts)
+ out, err := c.StaticLargeObjectCreate(ctx, &opts)
if err != nil {
if err == swift.SLONotSupported {
t.Skip("SLO not supported")
@@ -287,12 +297,12 @@ func makeConnectionWithSLO(t *testing.T) (*swift.Connection, func()) {
t.Fatal(err)
}
}
- err = out.Close()
+ err = out.CloseWithContext(ctx)
if err != nil {
t.Error(err)
}
return c, func() {
- c.StaticLargeObjectDelete(CONTAINER, OBJECT)
+ _ = c.StaticLargeObjectDelete(ctx, CONTAINER, OBJECT)
rollback()
}
}
@@ -303,12 +313,14 @@ func isV3Api() bool {
}
func getSwinftInfo(t *testing.T) (info swift.SwiftInfo, err error) {
+ ctx := context.Background()
c, rollback := makeConnectionAuth(t)
defer rollback()
- return c.QueryInfo()
+ return c.QueryInfo(ctx)
}
func TestTransport(t *testing.T) {
+ ctx := context.Background()
c, rollback := makeConnection(t)
defer rollback()
@@ -326,7 +338,7 @@ func TestTransport(t *testing.T) {
c.Transport = tr
- err := c.Authenticate()
+ err := c.Authenticate(ctx)
if err != nil {
t.Fatal("Auth failed", err)
}
@@ -337,13 +349,14 @@ func TestTransport(t *testing.T) {
// The following Test functions are run in order - this one must come before the others!
func TestV1V2Authenticate(t *testing.T) {
+ ctx := context.Background()
if isV3Api() {
return
}
c, rollback := makeConnection(t)
defer rollback()
- err := c.Authenticate()
+ err := c.Authenticate(ctx)
if err != nil {
t.Fatal("Auth failed", err)
}
@@ -353,6 +366,7 @@ func TestV1V2Authenticate(t *testing.T) {
}
func TestV3AuthenticateWithDomainNameAndTenantId(t *testing.T) {
+ ctx := context.Background()
if !isV3Api() {
return
}
@@ -365,7 +379,7 @@ func TestV3AuthenticateWithDomainNameAndTenantId(t *testing.T) {
c.TenantId = os.Getenv("SWIFT_TENANT_ID")
c.DomainId = ""
- err := c.Authenticate()
+ err := c.Authenticate(ctx)
if err != nil {
t.Fatal("Auth failed", err)
}
@@ -375,6 +389,7 @@ func TestV3AuthenticateWithDomainNameAndTenantId(t *testing.T) {
}
func TestV3TrustWithTrustId(t *testing.T) {
+ ctx := context.Background()
if !isV3Api() {
return
}
@@ -384,7 +399,7 @@ func TestV3TrustWithTrustId(t *testing.T) {
c.TrustId = os.Getenv("SWIFT_TRUST_ID")
- err := c.Authenticate()
+ err := c.Authenticate(ctx)
if err != nil {
t.Fatal("Auth failed", err)
}
@@ -394,6 +409,7 @@ func TestV3TrustWithTrustId(t *testing.T) {
}
func TestV3AuthenticateWithDomainIdAndTenantId(t *testing.T) {
+ ctx := context.Background()
if !isV3Api() {
return
}
@@ -406,7 +422,7 @@ func TestV3AuthenticateWithDomainIdAndTenantId(t *testing.T) {
c.TenantId = os.Getenv("SWIFT_TENANT_ID")
c.DomainId = os.Getenv("SWIFT_API_DOMAIN_ID")
- err := c.Authenticate()
+ err := c.Authenticate(ctx)
if err != nil {
t.Fatal("Auth failed", err)
}
@@ -416,6 +432,7 @@ func TestV3AuthenticateWithDomainIdAndTenantId(t *testing.T) {
}
func TestV3AuthenticateWithDomainNameAndTenantName(t *testing.T) {
+ ctx := context.Background()
if !isV3Api() {
return
}
@@ -428,7 +445,7 @@ func TestV3AuthenticateWithDomainNameAndTenantName(t *testing.T) {
c.TenantId = ""
c.DomainId = ""
- err := c.Authenticate()
+ err := c.Authenticate(ctx)
if err != nil {
t.Fatal("Auth failed", err)
}
@@ -438,6 +455,7 @@ func TestV3AuthenticateWithDomainNameAndTenantName(t *testing.T) {
}
func TestV3AuthenticateWithDomainIdAndTenantName(t *testing.T) {
+ ctx := context.Background()
if !isV3Api() {
return
}
@@ -450,7 +468,7 @@ func TestV3AuthenticateWithDomainIdAndTenantName(t *testing.T) {
c.TenantId = ""
c.DomainId = os.Getenv("SWIFT_API_DOMAIN_ID")
- err := c.Authenticate()
+ err := c.Authenticate(ctx)
if err != nil {
t.Fatal("Auth failed", err)
}
@@ -463,6 +481,7 @@ func TestV3AuthenticateWithDomainIdAndTenantName(t *testing.T) {
//
// Run with -race to test
func TestAuthenticateRace(t *testing.T) {
+ ctx := context.Background()
c, rollback := makeConnection(t)
defer rollback()
var wg sync.WaitGroup
@@ -470,12 +489,12 @@ func TestAuthenticateRace(t *testing.T) {
wg.Add(1)
go func() {
defer wg.Done()
- err := c.Authenticate()
+ err := c.Authenticate(ctx)
if err != nil {
- t.Fatal("Auth failed", err)
+ t.Error("Auth failed", err)
}
if !c.Authenticated() {
- t.Fatal("Not authenticated")
+ t.Error("Not authenticated")
}
}()
}
@@ -484,6 +503,7 @@ func TestAuthenticateRace(t *testing.T) {
// Test a connection can be serialized and unserialized with JSON
func TestSerializeConnectionJson(t *testing.T) {
+ ctx := context.Background()
c, rollback := makeConnectionAuth(t)
defer rollback()
serializedConnection, err := json.Marshal(c)
@@ -498,7 +518,7 @@ func TestSerializeConnectionJson(t *testing.T) {
if !c2.Authenticated() {
t.Fatal("Should be authenticated")
}
- _, _, err = c2.Account()
+ _, _, err = c2.Account(ctx)
if err != nil {
t.Fatalf("Failed to use unserialized connection: %v", err)
}
@@ -506,6 +526,7 @@ func TestSerializeConnectionJson(t *testing.T) {
// Test a connection can be serialized and unserialized with XML
func TestSerializeConnectionXml(t *testing.T) {
+ ctx := context.Background()
c, rollback := makeConnectionAuth(t)
defer rollback()
serializedConnection, err := xml.Marshal(c)
@@ -520,7 +541,7 @@ func TestSerializeConnectionXml(t *testing.T) {
if !c2.Authenticated() {
t.Fatal("Should be authenticated")
}
- _, _, err = c2.Account()
+ _, _, err = c2.Account(ctx)
if err != nil {
t.Fatalf("Failed to use unserialized connection: %v", err)
}
@@ -528,19 +549,21 @@ func TestSerializeConnectionXml(t *testing.T) {
// Test the reauthentication logic
func TestOnReAuth(t *testing.T) {
+ ctx := context.Background()
c, rollback := makeConnectionAuth(t)
defer rollback()
c.UnAuthenticate()
- _, _, err := c.Account()
+ _, _, err := c.Account(ctx)
if err != nil {
t.Fatalf("Failed to reauthenticate: %v", err)
}
}
func TestAccount(t *testing.T) {
+ ctx := context.Background()
c, rollback := makeConnectionAuth(t)
defer rollback()
- info, headers, err := c.Account()
+ info, headers, err := c.Account(ctx)
if err != nil {
t.Fatal(err)
}
@@ -572,14 +595,15 @@ func compareMaps(t *testing.T, a, b map[string]string) {
}
func TestAccountUpdate(t *testing.T) {
+ ctx := context.Background()
c, rollback := makeConnectionAuth(t)
defer rollback()
- err := c.AccountUpdate(m1.AccountHeaders())
+ err := c.AccountUpdate(ctx, m1.AccountHeaders())
if err != nil {
t.Fatal(err)
}
- _, headers, err := c.Account()
+ _, headers, err := c.Account(ctx)
if err != nil {
t.Fatal(err)
}
@@ -587,12 +611,12 @@ func TestAccountUpdate(t *testing.T) {
delete(m, "temp-url-key") // remove X-Account-Meta-Temp-URL-Key if set
compareMaps(t, m, map[string]string{"hello": "1", "potato-salad": "2"})
- err = c.AccountUpdate(m2.AccountHeaders())
+ err = c.AccountUpdate(ctx, m2.AccountHeaders())
if err != nil {
t.Fatal(err)
}
- _, headers, err = c.Account()
+ _, headers, err = c.Account(ctx)
if err != nil {
t.Fatal(err)
}
@@ -602,22 +626,24 @@ func TestAccountUpdate(t *testing.T) {
}
func TestContainerCreate(t *testing.T) {
+ ctx := context.Background()
c, rollback := makeConnectionAuth(t)
defer rollback()
- err := c.ContainerCreate(CONTAINER, m1.ContainerHeaders())
+ err := c.ContainerCreate(ctx, CONTAINER, m1.ContainerHeaders())
if err != nil {
t.Fatal(err)
}
- err = c.ContainerDelete(CONTAINER)
+ err = c.ContainerDelete(ctx, CONTAINER)
if err != nil {
t.Fatal(err)
}
}
func TestContainer(t *testing.T) {
+ ctx := context.Background()
c, rollback := makeConnectionWithContainer(t)
defer rollback()
- info, headers, err := c.Container(CONTAINER)
+ info, headers, err := c.Container(ctx, CONTAINER)
if err != nil {
t.Fatal(err)
}
@@ -634,13 +660,14 @@ func TestContainer(t *testing.T) {
}
func TestContainersAll(t *testing.T) {
+ ctx := context.Background()
c, rollback := makeConnectionWithContainer(t)
defer rollback()
- containers1, err := c.ContainersAll(nil)
+ containers1, err := c.ContainersAll(ctx, nil)
if err != nil {
t.Fatal(err)
}
- containers2, err := c.Containers(nil)
+ containers2, err := c.Containers(ctx, nil)
if err != nil {
t.Fatal(err)
}
@@ -655,13 +682,14 @@ func TestContainersAll(t *testing.T) {
}
func TestContainersAllWithLimit(t *testing.T) {
+ ctx := context.Background()
c, rollback := makeConnectionWithContainer(t)
defer rollback()
- containers1, err := c.ContainersAll(&swift.ContainersOpts{Limit: 1})
+ containers1, err := c.ContainersAll(ctx, &swift.ContainersOpts{Limit: 1})
if err != nil {
t.Fatal(err)
}
- containers2, err := c.Containers(nil)
+ containers2, err := c.Containers(ctx, nil)
if err != nil {
t.Fatal(err)
}
@@ -676,13 +704,14 @@ func TestContainersAllWithLimit(t *testing.T) {
}
func TestContainerUpdate(t *testing.T) {
+ ctx := context.Background()
c, rollback := makeConnectionWithContainer(t)
defer rollback()
- err := c.ContainerUpdate(CONTAINER, m2.ContainerHeaders())
+ err := c.ContainerUpdate(ctx, CONTAINER, m2.ContainerHeaders())
if err != nil {
t.Fatal(err)
}
- _, headers, err := c.Container(CONTAINER)
+ _, headers, err := c.Container(ctx, CONTAINER)
if err != nil {
t.Fatal(err)
}
@@ -690,9 +719,10 @@ func TestContainerUpdate(t *testing.T) {
}
func TestContainerNames(t *testing.T) {
+ ctx := context.Background()
c, rollback := makeConnectionWithContainer(t)
defer rollback()
- containers, err := c.ContainerNames(nil)
+ containers, err := c.ContainerNames(ctx, nil)
if err != nil {
t.Fatal(err)
}
@@ -709,13 +739,14 @@ func TestContainerNames(t *testing.T) {
}
func TestContainerNamesAll(t *testing.T) {
+ ctx := context.Background()
c, rollback := makeConnectionWithContainer(t)
defer rollback()
- containers1, err := c.ContainerNamesAll(nil)
+ containers1, err := c.ContainerNamesAll(ctx, nil)
if err != nil {
t.Fatal(err)
}
- containers2, err := c.ContainerNames(nil)
+ containers2, err := c.ContainerNames(ctx, nil)
if err != nil {
t.Fatal(err)
}
@@ -730,13 +761,14 @@ func TestContainerNamesAll(t *testing.T) {
}
func TestContainerNamesAllWithLimit(t *testing.T) {
+ ctx := context.Background()
c, rollback := makeConnectionWithContainer(t)
defer rollback()
- containers1, err := c.ContainerNamesAll(&swift.ContainersOpts{Limit: 1})
+ containers1, err := c.ContainerNamesAll(ctx, &swift.ContainersOpts{Limit: 1})
if err != nil {
t.Fatal(err)
}
- containers2, err := c.ContainerNames(nil)
+ containers2, err := c.ContainerNames(ctx, nil)
if err != nil {
t.Fatal(err)
}
@@ -751,20 +783,21 @@ func TestContainerNamesAllWithLimit(t *testing.T) {
}
func TestObjectPutString(t *testing.T) {
+ ctx := context.Background()
c, rollback := makeConnectionWithContainer(t)
defer rollback()
- err := c.ObjectPutString(CONTAINER, OBJECT, CONTENTS, "")
+ err := c.ObjectPutString(ctx, CONTAINER, OBJECT, CONTENTS, "")
if err != nil {
t.Fatal(err)
}
defer func() {
- err = c.ObjectDelete(CONTAINER, OBJECT)
+ err = c.ObjectDelete(ctx, CONTAINER, OBJECT)
if err != nil {
t.Fatal(err)
}
}()
- info, _, err := c.Object(CONTAINER, OBJECT)
+ info, _, err := c.Object(ctx, CONTAINER, OBJECT)
if err != nil {
t.Error(err)
}
@@ -780,6 +813,7 @@ func TestObjectPutString(t *testing.T) {
}
func TestObjectPut(t *testing.T) {
+ ctx := context.Background()
c, rollback := makeConnectionWithContainer(t)
defer rollback()
@@ -788,7 +822,7 @@ func TestObjectPut(t *testing.T) {
// Set content size incorrectly - should produce an error
headers["Content-Length"] = strconv.FormatInt(CONTENT_SIZE-1, 10)
contents := bytes.NewBufferString(CONTENTS)
- h, err := c.ObjectPut(CONTAINER, OBJECT, contents, true, CONTENT_MD5, "text/plain", headers)
+ _, err := c.ObjectPut(ctx, CONTAINER, OBJECT, contents, true, CONTENT_MD5, "text/plain", headers)
if err == nil {
t.Fatal("Expecting error but didn't get one")
}
@@ -796,12 +830,12 @@ func TestObjectPut(t *testing.T) {
// Now set content size correctly
contents = bytes.NewBufferString(CONTENTS)
headers["Content-Length"] = strconv.FormatInt(CONTENT_SIZE, 10)
- h, err = c.ObjectPut(CONTAINER, OBJECT, contents, true, CONTENT_MD5, "text/plain", headers)
+ h, err := c.ObjectPut(ctx, CONTAINER, OBJECT, contents, true, CONTENT_MD5, "text/plain", headers)
if err != nil {
t.Fatal(err)
}
defer func() {
- err = c.ObjectDelete(CONTAINER, OBJECT)
+ err = c.ObjectDelete(ctx, CONTAINER, OBJECT)
if err != nil {
t.Fatal(err)
}
@@ -812,7 +846,7 @@ func TestObjectPut(t *testing.T) {
}
// Fetch object info and compare
- info, _, err := c.Object(CONTAINER, OBJECT)
+ info, _, err := c.Object(ctx, CONTAINER, OBJECT)
if err != nil {
t.Error(err)
}
@@ -828,6 +862,7 @@ func TestObjectPut(t *testing.T) {
}
func TestObjectPutWithReauth(t *testing.T) {
+ ctx := context.Background()
if !swift.IS_AT_LEAST_GO_16 {
return
}
@@ -838,12 +873,12 @@ func TestObjectPutWithReauth(t *testing.T) {
c.AuthToken = "expiredtoken"
r := strings.NewReader(CONTENTS)
- _, err := c.ObjectPut(CONTAINER, OBJECT, r, true, "", "text/plain", nil)
+ _, err := c.ObjectPut(ctx, CONTAINER, OBJECT, r, true, "", "text/plain", nil)
if err != nil {
t.Fatal(err)
}
- info, _, err := c.Object(CONTAINER, OBJECT)
+ info, _, err := c.Object(ctx, CONTAINER, OBJECT)
if err != nil {
t.Error(err)
}
@@ -859,6 +894,7 @@ func TestObjectPutWithReauth(t *testing.T) {
}
func TestObjectPutStringWithReauth(t *testing.T) {
+ ctx := context.Background()
if !swift.IS_AT_LEAST_GO_16 {
return
}
@@ -868,12 +904,12 @@ func TestObjectPutStringWithReauth(t *testing.T) {
// Simulate that our auth token expired
c.AuthToken = "expiredtoken"
- err := c.ObjectPutString(CONTAINER, OBJECT, CONTENTS, "")
+ err := c.ObjectPutString(ctx, CONTAINER, OBJECT, CONTENTS, "")
if err != nil {
t.Fatal(err)
}
- info, _, err := c.Object(CONTAINER, OBJECT)
+ info, _, err := c.Object(ctx, CONTAINER, OBJECT)
if err != nil {
t.Error(err)
}
@@ -889,20 +925,21 @@ func TestObjectPutStringWithReauth(t *testing.T) {
}
func TestObjectEmpty(t *testing.T) {
+ ctx := context.Background()
c, rollback := makeConnectionWithContainer(t)
defer rollback()
- err := c.ObjectPutString(CONTAINER, EMPTYOBJECT, "", "")
+ err := c.ObjectPutString(ctx, CONTAINER, EMPTYOBJECT, "", "")
if err != nil {
t.Fatal(err)
}
defer func() {
- err = c.ObjectDelete(CONTAINER, EMPTYOBJECT)
+ err = c.ObjectDelete(ctx, CONTAINER, EMPTYOBJECT)
if err != nil {
t.Error(err)
}
}()
- info, _, err := c.Object(CONTAINER, EMPTYOBJECT)
+ info, _, err := c.Object(ctx, CONTAINER, EMPTYOBJECT)
if err != nil {
t.Error(err)
}
@@ -918,6 +955,7 @@ func TestObjectEmpty(t *testing.T) {
}
func TestSymlinkObject(t *testing.T) {
+ ctx := context.Background()
info, err := getSwinftInfo(t)
if err != nil {
t.Fatal(err)
@@ -931,30 +969,30 @@ func TestSymlinkObject(t *testing.T) {
defer rollback()
// write target objects
- err = c.ObjectPutBytes(CONTAINER, OBJECT, []byte(CONTENTS), "text/potato")
+ err = c.ObjectPutBytes(ctx, CONTAINER, OBJECT, []byte(CONTENTS), "text/potato")
if err != nil {
t.Fatal(err)
}
defer func() {
- err = c.ObjectDelete(CONTAINER, OBJECT)
+ err = c.ObjectDelete(ctx, CONTAINER, OBJECT)
if err != nil {
t.Error(err)
}
}()
// test dynamic link
- _, err = c.ObjectSymlinkCreate(CONTAINER, SYMLINK_OBJECT, "", CONTAINER, OBJECT, "")
+ _, err = c.ObjectSymlinkCreate(ctx, CONTAINER, SYMLINK_OBJECT, "", CONTAINER, OBJECT, "")
if err != nil {
t.Fatal(err)
}
defer func() {
- err = c.ObjectDelete(CONTAINER, SYMLINK_OBJECT)
+ err = c.ObjectDelete(ctx, CONTAINER, SYMLINK_OBJECT)
if err != nil {
t.Error(err)
}
}()
- md, _, err := c.Object(CONTAINER, SYMLINK_OBJECT)
+ md, _, err := c.Object(ctx, CONTAINER, SYMLINK_OBJECT)
if err != nil {
t.Error(err)
}
@@ -971,6 +1009,7 @@ func TestSymlinkObject(t *testing.T) {
}
func TestStaticSymlinkObject(t *testing.T) {
+ ctx := context.Background()
info, err := getSwinftInfo(t)
if err != nil {
t.Fatal(err)
@@ -989,12 +1028,12 @@ func TestStaticSymlinkObject(t *testing.T) {
defer rollback()
// write target objects
- err = c.ObjectPutBytes(CONTAINER, OBJECT2, []byte(CONTENTS2), "text/tomato")
+ err = c.ObjectPutBytes(ctx, CONTAINER, OBJECT2, []byte(CONTENTS2), "text/tomato")
if err != nil {
t.Fatal(err)
}
defer func() {
- err = c.ObjectDelete(CONTAINER, OBJECT2)
+ err = c.ObjectDelete(ctx, CONTAINER, OBJECT2)
if err != nil {
t.Error(err)
}
@@ -1002,23 +1041,23 @@ func TestStaticSymlinkObject(t *testing.T) {
// test static link
// first with the wrong target etag
- _, err = c.ObjectSymlinkCreate(CONTAINER, SYMLINK_OBJECT2, "", CONTAINER, OBJECT2, CONTENT_MD5)
+ _, err = c.ObjectSymlinkCreate(ctx, CONTAINER, SYMLINK_OBJECT2, "", CONTAINER, OBJECT2, CONTENT_MD5)
if err == nil {
t.Error("Symlink with wrong target etag should have failed")
}
- _, err = c.ObjectSymlinkCreate(CONTAINER, SYMLINK_OBJECT2, "", CONTAINER, OBJECT2, CONTENT2_MD5)
+ _, err = c.ObjectSymlinkCreate(ctx, CONTAINER, SYMLINK_OBJECT2, "", CONTAINER, OBJECT2, CONTENT2_MD5)
if err != nil {
t.Fatal(err)
}
defer func() {
- err = c.ObjectDelete(CONTAINER, SYMLINK_OBJECT2)
+ err = c.ObjectDelete(ctx, CONTAINER, SYMLINK_OBJECT2)
if err != nil {
t.Error(err)
}
}()
- md, _, err := c.Object(CONTAINER, SYMLINK_OBJECT2)
+ md, _, err := c.Object(ctx, CONTAINER, SYMLINK_OBJECT2)
if err != nil {
t.Error(err)
}
@@ -1034,20 +1073,21 @@ func TestStaticSymlinkObject(t *testing.T) {
}
func TestObjectPutBytes(t *testing.T) {
+ ctx := context.Background()
c, rollback := makeConnectionWithContainer(t)
defer rollback()
- err := c.ObjectPutBytes(CONTAINER, OBJECT, []byte(CONTENTS), "")
+ err := c.ObjectPutBytes(ctx, CONTAINER, OBJECT, []byte(CONTENTS), "")
if err != nil {
t.Fatal(err)
}
defer func() {
- err = c.ObjectDelete(CONTAINER, OBJECT)
+ err = c.ObjectDelete(ctx, CONTAINER, OBJECT)
if err != nil {
t.Error(err)
}
}()
- info, _, err := c.Object(CONTAINER, OBJECT)
+ info, _, err := c.Object(ctx, CONTAINER, OBJECT)
if err != nil {
t.Error(err)
}
@@ -1063,20 +1103,21 @@ func TestObjectPutBytes(t *testing.T) {
}
func TestObjectPutMimeType(t *testing.T) {
+ ctx := context.Background()
c, rollback := makeConnectionWithContainer(t)
defer rollback()
- err := c.ObjectPutString(CONTAINER, "test.jpg", CONTENTS, "")
+ err := c.ObjectPutString(ctx, CONTAINER, "test.jpg", CONTENTS, "")
if err != nil {
t.Fatal(err)
}
defer func() {
- err = c.ObjectDelete(CONTAINER, "test.jpg")
+ err = c.ObjectDelete(ctx, CONTAINER, "test.jpg")
if err != nil {
t.Error(err)
}
}()
- info, _, err := c.Object(CONTAINER, "test.jpg")
+ info, _, err := c.Object(ctx, CONTAINER, "test.jpg")
if err != nil {
t.Error(err)
}
@@ -1086,14 +1127,15 @@ func TestObjectPutMimeType(t *testing.T) {
}
func TestObjectCreate(t *testing.T) {
+ ctx := context.Background()
c, rollback := makeConnectionWithContainer(t)
defer rollback()
- out, err := c.ObjectCreate(CONTAINER, OBJECT2, true, "", "", nil)
+ out, err := c.ObjectCreate(ctx, CONTAINER, OBJECT2, true, "", "", nil)
if err != nil {
t.Fatal(err)
}
defer func() {
- err = c.ObjectDelete(CONTAINER, OBJECT2)
+ err = c.ObjectDelete(ctx, CONTAINER, OBJECT2)
if err != nil {
t.Error(err)
}
@@ -1102,7 +1144,7 @@ func TestObjectCreate(t *testing.T) {
hash := md5.New()
out2 := io.MultiWriter(out, buf, hash)
for i := 0; i < 100; i++ {
- fmt.Fprintf(out2, "%d %s\n", i, CONTENTS)
+ _, _ = fmt.Fprintf(out2, "%d %s\n", i, CONTENTS)
}
// Ensure Headers fails if called prematurely
_, err = out.Headers()
@@ -1114,7 +1156,7 @@ func TestObjectCreate(t *testing.T) {
t.Error(err)
}
expected := buf.String()
- contents, err := c.ObjectGetString(CONTAINER, OBJECT2)
+ contents, err := c.ObjectGetString(ctx, CONTAINER, OBJECT2)
if err != nil {
t.Error(err)
}
@@ -1138,7 +1180,7 @@ func TestObjectCreate(t *testing.T) {
}
// Now with hash instead
- out, err = c.ObjectCreate(CONTAINER, OBJECT2, false, fmt.Sprintf("%x", hash.Sum(nil)), "", nil)
+ out, err = c.ObjectCreate(ctx, CONTAINER, OBJECT2, false, fmt.Sprintf("%x", hash.Sum(nil)), "", nil)
if err != nil {
t.Fatal(err)
}
@@ -1150,7 +1192,7 @@ func TestObjectCreate(t *testing.T) {
if err != nil {
t.Error(err)
}
- contents, err = c.ObjectGetString(CONTAINER, OBJECT2)
+ contents, err = c.ObjectGetString(ctx, CONTAINER, OBJECT2)
if err != nil {
t.Error(err)
}
@@ -1159,12 +1201,12 @@ func TestObjectCreate(t *testing.T) {
}
// Now with bad hash
- out, err = c.ObjectCreate(CONTAINER, OBJECT2, false, CONTENT_MD5, "", nil)
+ out, err = c.ObjectCreate(ctx, CONTAINER, OBJECT2, false, CONTENT_MD5, "", nil)
if err != nil {
t.Fatal(err)
}
// FIXME: work around bug which produces 503 not 422 for empty corrupted files
- fmt.Fprintf(out, "Sausage")
+ _, _ = fmt.Fprintf(out, "Sausage")
err = out.Close()
if err != swift.ObjectCorrupted {
t.Error("Expecting object corrupted not", err)
@@ -1172,15 +1214,16 @@ func TestObjectCreate(t *testing.T) {
}
func TestObjectCreateAbort(t *testing.T) {
+ ctx := context.Background()
c, rollback := makeConnectionWithContainer(t)
defer rollback()
- out, err := c.ObjectCreate(CONTAINER, OBJECT2, true, "", "", nil)
+ out, err := c.ObjectCreate(ctx, CONTAINER, OBJECT2, true, "", "", nil)
if err != nil {
t.Fatal(err)
}
defer func() {
- _ = c.ObjectDelete(CONTAINER, OBJECT2) // Ignore error
+ _ = c.ObjectDelete(ctx, CONTAINER, OBJECT2) // Ignore error
}()
expectedContents := "foo"
@@ -1195,16 +1238,17 @@ func TestObjectCreateAbort(t *testing.T) {
t.Errorf("Unexpected error %#v", err)
}
- _, err = c.ObjectGetString(CONTAINER, OBJECT2)
+ _, err = c.ObjectGetString(ctx, CONTAINER, OBJECT2)
if err != swift.ObjectNotFound {
t.Errorf("Unexpected error: %#v", err)
}
}
func TestObjectGetString(t *testing.T) {
+ ctx := context.Background()
c, rollback := makeConnectionWithObject(t)
defer rollback()
- contents, err := c.ObjectGetString(CONTAINER, OBJECT)
+ contents, err := c.ObjectGetString(ctx, CONTAINER, OBJECT)
if err != nil {
t.Fatal(err)
}
@@ -1214,9 +1258,10 @@ func TestObjectGetString(t *testing.T) {
}
func TestObjectGetBytes(t *testing.T) {
+ ctx := context.Background()
c, rollback := makeConnectionWithObject(t)
defer rollback()
- contents, err := c.ObjectGetBytes(CONTAINER, OBJECT)
+ contents, err := c.ObjectGetBytes(ctx, CONTAINER, OBJECT)
if err != nil {
t.Fatal(err)
}
@@ -1226,9 +1271,10 @@ func TestObjectGetBytes(t *testing.T) {
}
func TestObjectOpen(t *testing.T) {
+ ctx := context.Background()
c, rollback := makeConnectionWithObject(t)
defer rollback()
- file, _, err := c.ObjectOpen(CONTAINER, OBJECT, true, nil)
+ file, _, err := c.ObjectOpen(ctx, CONTAINER, OBJECT, true, nil)
if err != nil {
t.Fatal(err)
}
@@ -1250,9 +1296,10 @@ func TestObjectOpen(t *testing.T) {
}
func TestObjectOpenPartial(t *testing.T) {
+ ctx := context.Background()
c, rollback := makeConnectionWithObject(t)
defer rollback()
- file, _, err := c.ObjectOpen(CONTAINER, OBJECT, true, nil)
+ file, _, err := c.ObjectOpen(ctx, CONTAINER, OBJECT, true, nil)
if err != nil {
t.Fatal(err)
}
@@ -1274,14 +1321,15 @@ func TestObjectOpenPartial(t *testing.T) {
}
func TestObjectOpenLength(t *testing.T) {
+ ctx := context.Background()
c, rollback := makeConnectionWithObject(t)
defer rollback()
- file, _, err := c.ObjectOpen(CONTAINER, OBJECT, true, nil)
+ file, _, err := c.ObjectOpen(ctx, CONTAINER, OBJECT, true, nil)
if err != nil {
t.Fatal(err)
}
// FIXME ideally this would check both branches of the Length() code
- n, err := file.Length()
+ n, err := file.Length(ctx)
if err != nil {
t.Fatal(err)
}
@@ -1295,9 +1343,10 @@ func TestObjectOpenLength(t *testing.T) {
}
func TestObjectOpenNotModified(t *testing.T) {
+ ctx := context.Background()
c, rollback := makeConnectionWithObject(t)
defer rollback()
- _, _, err := c.ObjectOpen(CONTAINER, OBJECT, true, swift.Headers{
+ _, _, err := c.ObjectOpen(ctx, CONTAINER, OBJECT, true, swift.Headers{
"If-None-Match": CONTENT_MD5,
})
if err != swift.NotModified {
@@ -1306,6 +1355,7 @@ func TestObjectOpenNotModified(t *testing.T) {
}
func TestObjectOpenSeek(t *testing.T) {
+ ctx := context.Background()
c, rollback := makeConnectionWithObject(t)
defer rollback()
@@ -1331,7 +1381,7 @@ func TestObjectOpenSeek(t *testing.T) {
{2, -4, 1},
}
- file, _, err := c.ObjectOpen(CONTAINER, OBJECT, true, nil)
+ file, _, err := c.ObjectOpen(ctx, CONTAINER, OBJECT, true, nil)
if err != nil {
t.Fatal(err)
}
@@ -1339,7 +1389,7 @@ func TestObjectOpenSeek(t *testing.T) {
for _, p := range plan {
if p.whence >= 0 {
var result int64
- result, err = file.Seek(p.offset, p.whence)
+ result, err = file.Seek(ctx, p.offset, p.whence)
if err != nil {
t.Fatal(err, p)
}
@@ -1372,13 +1422,14 @@ func TestObjectOpenSeek(t *testing.T) {
// Test seeking to the end to find the file size
func TestObjectOpenSeekEnd(t *testing.T) {
+ ctx := context.Background()
c, rollback := makeConnectionWithObject(t)
defer rollback()
- file, _, err := c.ObjectOpen(CONTAINER, OBJECT, true, nil)
+ file, _, err := c.ObjectOpen(ctx, CONTAINER, OBJECT, true, nil)
if err != nil {
t.Fatal(err)
}
- n, err := file.Seek(0, 2) // seek to end
+ n, err := file.Seek(ctx, 0, 2) // seek to end
if err != nil {
t.Fatal(err)
}
@@ -1397,7 +1448,7 @@ func TestObjectOpenSeekEnd(t *testing.T) {
}
// Now seek back to start and check we can read the file
- n, err = file.Seek(0, 0) // seek to start
+ n, err = file.Seek(ctx, 0, 0) // seek to start
if err != nil {
t.Fatal(err)
}
@@ -1416,9 +1467,10 @@ func TestObjectOpenSeekEnd(t *testing.T) {
}
func TestObjectUpdate(t *testing.T) {
+ ctx := context.Background()
c, rollback := makeConnectionWithObject(t)
defer rollback()
- err := c.ObjectUpdate(CONTAINER, OBJECT, m1.ObjectHeaders())
+ err := c.ObjectUpdate(ctx, CONTAINER, OBJECT, m1.ObjectHeaders())
if err != nil {
t.Fatal(err)
}
@@ -1432,9 +1484,10 @@ func checkTime(t *testing.T, when time.Time, low, high int) {
}
func TestObject(t *testing.T) {
+ ctx := context.Background()
c, rollback := makeConnectionWithObjectHeaders(t)
defer rollback()
- object, headers, err := c.Object(CONTAINER, OBJECT)
+ object, headers, err := c.Object(ctx, CONTAINER, OBJECT)
if err != nil {
t.Fatal(err)
}
@@ -1446,13 +1499,14 @@ func TestObject(t *testing.T) {
}
func TestObjectUpdate2(t *testing.T) {
+ ctx := context.Background()
c, rollback := makeConnectionWithObjectHeaders(t)
defer rollback()
- err := c.ObjectUpdate(CONTAINER, OBJECT, m2.ObjectHeaders())
+ err := c.ObjectUpdate(ctx, CONTAINER, OBJECT, m2.ObjectHeaders())
if err != nil {
t.Fatal(err)
}
- _, headers, err := c.Object(CONTAINER, OBJECT)
+ _, headers, err := c.Object(ctx, CONTAINER, OBJECT)
if err != nil {
t.Fatal(err)
}
@@ -1460,9 +1514,10 @@ func TestObjectUpdate2(t *testing.T) {
}
func TestContainers(t *testing.T) {
+ ctx := context.Background()
c, rollback := makeConnectionWithObjectHeaders(t)
defer rollback()
- containers, err := c.Containers(nil)
+ containers, err := c.Containers(ctx, nil)
if err != nil {
t.Fatal(err)
}
@@ -1488,9 +1543,10 @@ func TestContainers(t *testing.T) {
}
func TestObjectNames(t *testing.T) {
+ ctx := context.Background()
c, rollback := makeConnectionWithObjectHeaders(t)
defer rollback()
- objects, err := c.ObjectNames(CONTAINER, nil)
+ objects, err := c.ObjectNames(ctx, CONTAINER, nil)
if err != nil {
t.Fatal(err)
}
@@ -1500,9 +1556,10 @@ func TestObjectNames(t *testing.T) {
}
func TestObjectNamesAll(t *testing.T) {
+ ctx := context.Background()
c, rollback := makeConnectionWithObjectHeaders(t)
defer rollback()
- objects, err := c.ObjectNamesAll(CONTAINER, nil)
+ objects, err := c.ObjectNamesAll(ctx, CONTAINER, nil)
if err != nil {
t.Fatal(err)
}
@@ -1512,9 +1569,10 @@ func TestObjectNamesAll(t *testing.T) {
}
func TestObjectNamesAllWithLimit(t *testing.T) {
+ ctx := context.Background()
c, rollback := makeConnectionWithObjectHeaders(t)
defer rollback()
- objects, err := c.ObjectNamesAll(CONTAINER, &swift.ObjectsOpts{Limit: 1})
+ objects, err := c.ObjectNamesAll(ctx, CONTAINER, &swift.ObjectsOpts{Limit: 1})
if err != nil {
t.Fatal(err)
}
@@ -1524,11 +1582,12 @@ func TestObjectNamesAllWithLimit(t *testing.T) {
}
func TestObjectsWalk(t *testing.T) {
+ ctx := context.Background()
c, rollback := makeConnectionWithObjectHeaders(t)
defer rollback()
objects := make([]string, 0)
- err := c.ObjectsWalk(container, nil, func(opts *swift.ObjectsOpts) (interface{}, error) {
- newObjects, err := c.ObjectNames(CONTAINER, opts)
+ err := c.ObjectsWalk(ctx, container, nil, func(ctx context.Context, opts *swift.ObjectsOpts) (interface{}, error) {
+ newObjects, err := c.ObjectNames(ctx, CONTAINER, opts)
if err == nil {
objects = append(objects, newObjects...)
}
@@ -1543,9 +1602,10 @@ func TestObjectsWalk(t *testing.T) {
}
func TestObjects(t *testing.T) {
+ ctx := context.Background()
c, rollback := makeConnectionWithObjectHeaders(t)
defer rollback()
- objects, err := c.Objects(CONTAINER, &swift.ObjectsOpts{Delimiter: '/'})
+ objects, err := c.Objects(ctx, CONTAINER, &swift.ObjectsOpts{Delimiter: '/'})
if err != nil {
t.Fatal(err)
}
@@ -1560,17 +1620,20 @@ func TestObjects(t *testing.T) {
}
func TestObjectsDirectory(t *testing.T) {
+ ctx := context.Background()
c, rollback := makeConnectionWithObjectHeaders(t)
defer rollback()
- err := c.ObjectPutString(CONTAINER, "directory", "", "application/directory")
+ err := c.ObjectPutString(ctx, CONTAINER, "directory", "", "application/directory")
if err != nil {
t.Fatal(err)
}
- defer c.ObjectDelete(CONTAINER, "directory")
+ defer func() {
+ _ = c.ObjectDelete(ctx, CONTAINER, "directory")
+ }()
// Look for the directory object and check we aren't confusing
// it with a pseudo directory object
- objects, err := c.Objects(CONTAINER, &swift.ObjectsOpts{Delimiter: '/'})
+ objects, err := c.Objects(ctx, CONTAINER, &swift.ObjectsOpts{Delimiter: '/'})
if err != nil {
t.Fatal(err)
}
@@ -1594,16 +1657,19 @@ func TestObjectsDirectory(t *testing.T) {
}
func TestObjectsPseudoDirectory(t *testing.T) {
+ ctx := context.Background()
c, rollback := makeConnectionWithObjectHeaders(t)
defer rollback()
- err := c.ObjectPutString(CONTAINER, "directory/puppy.jpg", "cute puppy", "")
+ err := c.ObjectPutString(ctx, CONTAINER, "directory/puppy.jpg", "cute puppy", "")
if err != nil {
t.Fatal(err)
}
- defer c.ObjectDelete(CONTAINER, "directory/puppy.jpg")
+ defer func() {
+ _ = c.ObjectDelete(ctx, CONTAINER, "directory/puppy.jpg")
+ }()
// Look for the pseudo directory
- objects, err := c.Objects(CONTAINER, &swift.ObjectsOpts{Delimiter: '/'})
+ objects, err := c.Objects(ctx, CONTAINER, &swift.ObjectsOpts{Delimiter: '/'})
if err != nil {
t.Fatal(err)
}
@@ -1625,7 +1691,7 @@ func TestObjectsPseudoDirectory(t *testing.T) {
}
// Look in the pseudo directory now
- objects, err = c.Objects(CONTAINER, &swift.ObjectsOpts{Delimiter: '/', Path: "directory/"})
+ objects, err = c.Objects(ctx, CONTAINER, &swift.ObjectsOpts{Delimiter: '/', Path: "directory/"})
if err != nil {
t.Fatal(err)
}
@@ -1640,9 +1706,10 @@ func TestObjectsPseudoDirectory(t *testing.T) {
}
func TestObjectsAll(t *testing.T) {
+ ctx := context.Background()
c, rollback := makeConnectionWithObjectHeaders(t)
defer rollback()
- objects, err := c.ObjectsAll(CONTAINER, nil)
+ objects, err := c.ObjectsAll(ctx, CONTAINER, nil)
if err != nil {
t.Fatal(err)
}
@@ -1652,9 +1719,10 @@ func TestObjectsAll(t *testing.T) {
}
func TestObjectsAllWithLimit(t *testing.T) {
+ ctx := context.Background()
c, rollback := makeConnectionWithObjectHeaders(t)
defer rollback()
- objects, err := c.ObjectsAll(CONTAINER, &swift.ObjectsOpts{Limit: 1})
+ objects, err := c.ObjectsAll(ctx, CONTAINER, &swift.ObjectsOpts{Limit: 1})
if err != nil {
t.Fatal(err)
}
@@ -1664,9 +1732,10 @@ func TestObjectsAllWithLimit(t *testing.T) {
}
func TestObjectNamesWithPath(t *testing.T) {
+ ctx := context.Background()
c, rollback := makeConnectionWithObjectHeaders(t)
defer rollback()
- objects, err := c.ObjectNames(CONTAINER, &swift.ObjectsOpts{Delimiter: '/', Path: ""})
+ objects, err := c.ObjectNames(ctx, CONTAINER, &swift.ObjectsOpts{Delimiter: '/', Path: ""})
if err != nil {
t.Fatal(err)
}
@@ -1674,7 +1743,7 @@ func TestObjectNamesWithPath(t *testing.T) {
t.Error("Bad listing with path", objects)
}
// fmt.Println(objects)
- objects, err = c.ObjectNames(CONTAINER, &swift.ObjectsOpts{Delimiter: '/', Path: "Downloads/"})
+ objects, err = c.ObjectNames(ctx, CONTAINER, &swift.ObjectsOpts{Delimiter: '/', Path: "Downloads/"})
if err != nil {
t.Fatal(err)
}
@@ -1684,33 +1753,36 @@ func TestObjectNamesWithPath(t *testing.T) {
}
func TestObjectCopy(t *testing.T) {
+ ctx := context.Background()
c, rollback := makeConnectionWithObjectHeaders(t)
defer rollback()
- _, err := c.ObjectCopy(CONTAINER, OBJECT, CONTAINER, OBJECT2, nil)
+ _, err := c.ObjectCopy(ctx, CONTAINER, OBJECT, CONTAINER, OBJECT2, nil)
if err != nil {
t.Fatal(err)
}
- err = c.ObjectDelete(CONTAINER, OBJECT2)
+ err = c.ObjectDelete(ctx, CONTAINER, OBJECT2)
if err != nil {
t.Fatal(err)
}
}
func TestObjectCopyDifficultName(t *testing.T) {
+ ctx := context.Background()
c, rollback := makeConnectionWithObjectHeaders(t)
defer rollback()
const dest = OBJECT + "?param %30%31%32 £100"
- _, err := c.ObjectCopy(CONTAINER, OBJECT, CONTAINER, dest, nil)
+ _, err := c.ObjectCopy(ctx, CONTAINER, OBJECT, CONTAINER, dest, nil)
if err != nil {
t.Fatal(err)
}
- err = c.ObjectDelete(CONTAINER, dest)
+ err = c.ObjectDelete(ctx, CONTAINER, dest)
if err != nil {
t.Fatal(err)
}
}
func TestObjectCopyWithMetadata(t *testing.T) {
+ ctx := context.Background()
c, rollback := makeConnectionWithObjectHeaders(t)
defer rollback()
m := swift.Metadata{}
@@ -1718,18 +1790,18 @@ func TestObjectCopyWithMetadata(t *testing.T) {
m["hello"] = "9"
h := m.ObjectHeaders()
h["Content-Type"] = "image/jpeg"
- _, err := c.ObjectCopy(CONTAINER, OBJECT, CONTAINER, OBJECT2, h)
+ _, err := c.ObjectCopy(ctx, CONTAINER, OBJECT, CONTAINER, OBJECT2, h)
if err != nil {
t.Fatal(err)
}
defer func() {
- err = c.ObjectDelete(CONTAINER, OBJECT2)
+ err = c.ObjectDelete(ctx, CONTAINER, OBJECT2)
if err != nil {
t.Fatal(err)
}
}()
// Re-read the metadata to see if it is correct
- _, headers, err := c.Object(CONTAINER, OBJECT2)
+ _, headers, err := c.Object(ctx, CONTAINER, OBJECT2)
if err != nil {
t.Fatal(err)
}
@@ -1740,24 +1812,25 @@ func TestObjectCopyWithMetadata(t *testing.T) {
}
func TestObjectMove(t *testing.T) {
+ ctx := context.Background()
c, rollback := makeConnectionWithObjectHeaders(t)
defer rollback()
- err := c.ObjectMove(CONTAINER, OBJECT, CONTAINER, OBJECT2)
+ err := c.ObjectMove(ctx, CONTAINER, OBJECT, CONTAINER, OBJECT2)
if err != nil {
t.Fatal(err)
}
testExistenceAfterDelete(t, c, CONTAINER, OBJECT)
- _, _, err = c.Object(CONTAINER, OBJECT2)
+ _, _, err = c.Object(ctx, CONTAINER, OBJECT2)
if err != nil {
t.Fatal(err)
}
- err = c.ObjectMove(CONTAINER, OBJECT2, CONTAINER, OBJECT)
+ err = c.ObjectMove(ctx, CONTAINER, OBJECT2, CONTAINER, OBJECT)
if err != nil {
t.Fatal(err)
}
testExistenceAfterDelete(t, c, CONTAINER, OBJECT2)
- _, headers, err := c.Object(CONTAINER, OBJECT)
+ _, headers, err := c.Object(ctx, CONTAINER, OBJECT)
if err != nil {
t.Fatal(err)
}
@@ -1765,14 +1838,15 @@ func TestObjectMove(t *testing.T) {
}
func TestObjectUpdateContentType(t *testing.T) {
+ ctx := context.Background()
c, rollback := makeConnectionWithObjectHeaders(t)
defer rollback()
- err := c.ObjectUpdateContentType(CONTAINER, OBJECT, "text/potato")
+ err := c.ObjectUpdateContentType(ctx, CONTAINER, OBJECT, "text/potato")
if err != nil {
t.Fatal(err)
}
// Re-read the metadata to see if it is correct
- _, headers, err := c.Object(CONTAINER, OBJECT)
+ _, headers, err := c.Object(ctx, CONTAINER, OBJECT)
if err != nil {
t.Fatal(err)
}
@@ -1783,12 +1857,13 @@ func TestObjectUpdateContentType(t *testing.T) {
}
func TestVersionContainerCreate(t *testing.T) {
+ ctx := context.Background()
c, rollback := makeConnectionAuth(t)
defer rollback()
- err := c.VersionContainerCreate(CURRENT_CONTAINER, VERSIONS_CONTAINER)
+ err := c.VersionContainerCreate(ctx, CURRENT_CONTAINER, VERSIONS_CONTAINER)
defer func() {
- c.ContainerDelete(CURRENT_CONTAINER)
- c.ContainerDelete(VERSIONS_CONTAINER)
+ _ = c.ContainerDelete(ctx, CURRENT_CONTAINER)
+ _ = c.ContainerDelete(ctx, VERSIONS_CONTAINER)
}()
if err != nil {
if err == swift.Forbidden {
@@ -1800,6 +1875,7 @@ func TestVersionContainerCreate(t *testing.T) {
}
func TestVersionObjectAdd(t *testing.T) {
+ ctx := context.Background()
c, rollback := makeConnectionWithVersionsContainer(t)
defer rollback()
if skipVersionTests {
@@ -1807,43 +1883,43 @@ func TestVersionObjectAdd(t *testing.T) {
return
}
// Version 1
- if err := c.ObjectPutString(CURRENT_CONTAINER, OBJECT, CONTENTS, ""); err != nil {
+ if err := c.ObjectPutString(ctx, CURRENT_CONTAINER, OBJECT, CONTENTS, ""); err != nil {
t.Fatal(err)
}
defer func() {
- err := c.ObjectDelete(CURRENT_CONTAINER, OBJECT)
+ err := c.ObjectDelete(ctx, CURRENT_CONTAINER, OBJECT)
if err != nil {
t.Fatal(err)
}
}()
- if contents, err := c.ObjectGetString(CURRENT_CONTAINER, OBJECT); err != nil {
+ if contents, err := c.ObjectGetString(ctx, CURRENT_CONTAINER, OBJECT); err != nil {
t.Fatal(err)
} else if contents != CONTENTS {
t.Error("Contents wrong")
}
// Version 2
- if err := c.ObjectPutString(CURRENT_CONTAINER, OBJECT, CONTENTS2, ""); err != nil {
+ if err := c.ObjectPutString(ctx, CURRENT_CONTAINER, OBJECT, CONTENTS2, ""); err != nil {
t.Fatal(err)
}
defer func() {
- err := c.ObjectDelete(CURRENT_CONTAINER, OBJECT)
+ err := c.ObjectDelete(ctx, CURRENT_CONTAINER, OBJECT)
if err != nil {
t.Fatal(err)
}
}()
- if contents, err := c.ObjectGetString(CURRENT_CONTAINER, OBJECT); err != nil {
+ if contents, err := c.ObjectGetString(ctx, CURRENT_CONTAINER, OBJECT); err != nil {
t.Fatal(err)
} else if contents != CONTENTS2 {
t.Error("Contents wrong")
}
// Version 3
- if err := c.ObjectPutString(CURRENT_CONTAINER, OBJECT, CONTENTS2, ""); err != nil {
+ if err := c.ObjectPutString(ctx, CURRENT_CONTAINER, OBJECT, CONTENTS2, ""); err != nil {
t.Fatal(err)
}
defer func() {
- err := c.ObjectDelete(CURRENT_CONTAINER, OBJECT)
+ err := c.ObjectDelete(ctx, CURRENT_CONTAINER, OBJECT)
if err != nil {
t.Fatal(err)
}
@@ -1851,13 +1927,14 @@ func TestVersionObjectAdd(t *testing.T) {
}
func TestVersionObjectList(t *testing.T) {
+ ctx := context.Background()
c, rollback := makeConnectionWithVersionsObject(t)
defer rollback()
if skipVersionTests {
t.Log("Server doesn't support Versions - skipping test")
return
}
- list, err := c.VersionObjectList(VERSIONS_CONTAINER, OBJECT)
+ list, err := c.VersionObjectList(ctx, VERSIONS_CONTAINER, OBJECT)
if err != nil {
t.Fatal(err)
}
@@ -1868,6 +1945,7 @@ func TestVersionObjectList(t *testing.T) {
}
func TestVersionObjectDelete(t *testing.T) {
+ ctx := context.Background()
c, rollback := makeConnectionWithVersionsObject(t)
defer rollback()
if skipVersionTests {
@@ -1875,17 +1953,17 @@ func TestVersionObjectDelete(t *testing.T) {
return
}
// Delete Version 3
- if err := c.ObjectDelete(CURRENT_CONTAINER, OBJECT); err != nil {
+ if err := c.ObjectDelete(ctx, CURRENT_CONTAINER, OBJECT); err != nil {
t.Fatal(err)
}
// Delete Version 2
- if err := c.ObjectDelete(CURRENT_CONTAINER, OBJECT); err != nil {
+ if err := c.ObjectDelete(ctx, CURRENT_CONTAINER, OBJECT); err != nil {
t.Fatal(err)
}
// Contents should be reverted to Version 1
- if contents, err := c.ObjectGetString(CURRENT_CONTAINER, OBJECT); err != nil {
+ if contents, err := c.ObjectGetString(ctx, CURRENT_CONTAINER, OBJECT); err != nil {
t.Fatal(err)
} else if contents != CONTENTS {
t.Error("Contents wrong")
@@ -1893,6 +1971,7 @@ func TestVersionObjectDelete(t *testing.T) {
}
func TestVersionDeleteContent(t *testing.T) {
+ ctx := context.Background()
c, rollback := makeConnectionWithVersionsObject(t)
defer rollback()
if skipVersionTests {
@@ -1900,18 +1979,18 @@ func TestVersionDeleteContent(t *testing.T) {
return
}
// Delete Version 3
- if err := c.ObjectDelete(CURRENT_CONTAINER, OBJECT); err != nil {
+ if err := c.ObjectDelete(ctx, CURRENT_CONTAINER, OBJECT); err != nil {
t.Fatal(err)
}
// Delete Version 2
- if err := c.ObjectDelete(CURRENT_CONTAINER, OBJECT); err != nil {
+ if err := c.ObjectDelete(ctx, CURRENT_CONTAINER, OBJECT); err != nil {
t.Fatal(err)
}
// Delete Version 1
- if err := c.ObjectDelete(CURRENT_CONTAINER, OBJECT); err != nil {
+ if err := c.ObjectDelete(ctx, CURRENT_CONTAINER, OBJECT); err != nil {
t.Fatal(err)
}
- if err := c.ObjectDelete(CURRENT_CONTAINER, OBJECT); err != swift.ObjectNotFound {
+ if err := c.ObjectDelete(ctx, CURRENT_CONTAINER, OBJECT); err != swift.ObjectNotFound {
t.Fatalf("Expecting Object not found error, got: %v", err)
}
}
@@ -1919,8 +1998,9 @@ func TestVersionDeleteContent(t *testing.T) {
// Check for non existence after delete
// May have to do it a few times to wait for swift to be consistent.
func testExistenceAfterDelete(t *testing.T, c *swift.Connection, container, object string) {
+ ctx := context.Background()
for i := 10; i <= 0; i-- {
- _, _, err := c.Object(container, object)
+ _, _, err := c.Object(ctx, container, object)
if err == swift.ObjectNotFound {
break
}
@@ -1932,23 +2012,25 @@ func testExistenceAfterDelete(t *testing.T, c *swift.Connection, container, obje
}
func TestObjectDelete(t *testing.T) {
+ ctx := context.Background()
c, rollback := makeConnectionWithObject(t)
defer rollback()
- err := c.ObjectDelete(CONTAINER, OBJECT)
+ err := c.ObjectDelete(ctx, CONTAINER, OBJECT)
if err != nil {
t.Fatal(err)
}
testExistenceAfterDelete(t, c, CONTAINER, OBJECT)
- err = c.ObjectDelete(CONTAINER, OBJECT)
+ err = c.ObjectDelete(ctx, CONTAINER, OBJECT)
if err != swift.ObjectNotFound {
t.Fatal("Expecting Object not found", err)
}
}
func TestBulkDelete(t *testing.T) {
+ ctx := context.Background()
c, rollback := makeConnectionWithContainer(t)
defer rollback()
- result, err := c.BulkDelete(CONTAINER, []string{OBJECT})
+ result, err := c.BulkDelete(ctx, CONTAINER, []string{OBJECT})
if err == swift.Forbidden {
t.Log("Server doesn't support BulkDelete - skipping test")
return
@@ -1962,11 +2044,11 @@ func TestBulkDelete(t *testing.T) {
if result.NumberDeleted != 0 {
t.Error("Expected 0, actual:", result.NumberDeleted)
}
- err = c.ObjectPutString(CONTAINER, OBJECT, CONTENTS, "")
+ err = c.ObjectPutString(ctx, CONTAINER, OBJECT, CONTENTS, "")
if err != nil {
t.Fatal(err)
}
- result, err = c.BulkDelete(CONTAINER, []string{OBJECT2, OBJECT})
+ result, err = c.BulkDelete(ctx, CONTAINER, []string{OBJECT2, OBJECT})
if err != nil {
t.Fatal(err)
}
@@ -1980,6 +2062,7 @@ func TestBulkDelete(t *testing.T) {
}
func TestBulkUpload(t *testing.T) {
+ ctx := context.Background()
c, rollback := makeConnectionWithContainer(t)
defer rollback()
buffer := new(bytes.Buffer)
@@ -2004,7 +2087,7 @@ func TestBulkUpload(t *testing.T) {
t.Fatal(err)
}
- result, err := c.BulkUpload(CONTAINER, buffer, swift.UploadTar, nil)
+ result, err := c.BulkUpload(ctx, CONTAINER, buffer, swift.UploadTar, nil)
if err == swift.Forbidden {
t.Log("Server doesn't support BulkUpload - skipping test")
return
@@ -2013,11 +2096,11 @@ func TestBulkUpload(t *testing.T) {
t.Fatal(err)
}
defer func() {
- err = c.ObjectDelete(CONTAINER, OBJECT)
+ err = c.ObjectDelete(ctx, CONTAINER, OBJECT)
if err != nil {
t.Fatal(err)
}
- err = c.ObjectDelete(CONTAINER, OBJECT2)
+ err = c.ObjectDelete(ctx, CONTAINER, OBJECT2)
if err != nil {
t.Fatal(err)
}
@@ -2027,31 +2110,32 @@ func TestBulkUpload(t *testing.T) {
}
t.Log("Errors:", result.Errors)
- _, _, err = c.Object(CONTAINER, OBJECT)
+ _, _, err = c.Object(ctx, CONTAINER, OBJECT)
if err != nil {
t.Error("Expecting object to be found")
}
- _, _, err = c.Object(CONTAINER, OBJECT2)
+ _, _, err = c.Object(ctx, CONTAINER, OBJECT2)
if err != nil {
t.Error("Expecting object to be found")
}
}
func TestObjectDifficultName(t *testing.T) {
+ ctx := context.Background()
c, rollback := makeConnectionWithContainer(t)
defer rollback()
const name = `hello? sausage/êé/Hello, 世界/ " ' @ < > & ?/`
- err := c.ObjectPutString(CONTAINER, name, CONTENTS, "")
+ err := c.ObjectPutString(ctx, CONTAINER, name, CONTENTS, "")
if err != nil {
t.Fatal(err)
}
defer func() {
- err = c.ObjectDelete(CONTAINER, name)
+ err = c.ObjectDelete(ctx, CONTAINER, name)
if err != nil {
t.Fatal(err)
}
}()
- objects, err := c.ObjectNamesAll(CONTAINER, nil)
+ objects, err := c.ObjectNamesAll(ctx, CONTAINER, nil)
if err != nil {
t.Error(err)
}
@@ -2068,14 +2152,15 @@ func TestObjectDifficultName(t *testing.T) {
}
func TestTempUrl(t *testing.T) {
+ ctx := context.Background()
c, rollback := makeConnectionWithContainer(t)
defer rollback()
- err := c.ObjectPutBytes(CONTAINER, OBJECT, []byte(CONTENTS), "")
+ err := c.ObjectPutBytes(ctx, CONTAINER, OBJECT, []byte(CONTENTS), "")
if err != nil {
t.Fatal(err)
}
defer func() {
- err = c.ObjectDelete(CONTAINER, OBJECT)
+ err = c.ObjectDelete(ctx, CONTAINER, OBJECT)
if err != nil {
t.Fatal(err)
}
@@ -2083,7 +2168,7 @@ func TestTempUrl(t *testing.T) {
m := swift.Metadata{}
m["temp-url-key"] = SECRET_KEY
- err = c.AccountUpdate(m.AccountHeaders())
+ err = c.AccountUpdate(ctx, m.AccountHeaders())
if err != nil {
t.Fatal(err)
}
@@ -2094,7 +2179,12 @@ func TestTempUrl(t *testing.T) {
if err != nil {
t.Fatal("Failed to retrieve file from temporary url")
}
- defer resp.Body.Close()
+ defer func() {
+ err := resp.Body.Close()
+ if err != nil {
+ t.Error("Close failed", err)
+ }
+ }()
if resp.StatusCode == 401 {
t.Log("Server doesn't support tempurl")
} else if resp.StatusCode != 200 {
@@ -2109,7 +2199,12 @@ func TestTempUrl(t *testing.T) {
if err != nil {
t.Fatal("Failed to retrieve file from temporary url")
}
- defer resp.Body.Close()
+ defer func() {
+ err := resp.Body.Close()
+ if err != nil {
+ t.Error("Close failed", err)
+ }
+ }()
if resp.StatusCode != 401 {
t.Fatal("Expecting server to forbid access to object")
}
@@ -2117,9 +2212,10 @@ func TestTempUrl(t *testing.T) {
}
func TestQueryInfo(t *testing.T) {
+ ctx := context.Background()
c, rollback := makeConnectionAuth(t)
defer rollback()
- infos, err := c.QueryInfo()
+ infos, err := c.QueryInfo(ctx)
if err != nil {
t.Log("Server doesn't support querying info")
return
@@ -2130,6 +2226,7 @@ func TestQueryInfo(t *testing.T) {
}
func TestDLOCreate(t *testing.T) {
+ ctx := context.Background()
c, rollback := makeConnectionWithSegmentsContainer(t)
defer rollback()
@@ -2138,12 +2235,12 @@ func TestDLOCreate(t *testing.T) {
ObjectName: OBJECT,
ContentType: "image/jpeg",
}
- out, err := c.DynamicLargeObjectCreate(&opts)
+ out, err := c.DynamicLargeObjectCreate(ctx, &opts)
if err != nil {
t.Fatal(err)
}
defer func() {
- err = c.DynamicLargeObjectDelete(CONTAINER, OBJECT)
+ err = c.DynamicLargeObjectDelete(ctx, CONTAINER, OBJECT)
if err != nil {
t.Fatal(err)
}
@@ -2157,19 +2254,19 @@ func TestDLOCreate(t *testing.T) {
t.Fatal(err)
}
}
- err = out.Close()
+ err = out.CloseWithContext(ctx)
if err != nil {
t.Error(err)
}
expected := buf.String()
- contents, err := c.ObjectGetString(CONTAINER, OBJECT)
+ contents, err := c.ObjectGetString(ctx, CONTAINER, OBJECT)
if err != nil {
t.Error(err)
}
if contents != expected {
t.Errorf("Contents wrong, expected %q, got: %q", expected, contents)
}
- info, _, err := c.Object(CONTAINER, OBJECT)
+ info, _, err := c.Object(ctx, CONTAINER, OBJECT)
if err != nil {
t.Fatal(err)
}
@@ -2182,6 +2279,7 @@ func TestDLOCreate(t *testing.T) {
}
func TestDLOInsert(t *testing.T) {
+ ctx := context.Background()
c, rollback := makeConnectionWithDLO(t)
defer rollback()
opts := swift.LargeObjectOpts{
@@ -2190,7 +2288,7 @@ func TestDLOInsert(t *testing.T) {
CheckHash: true,
ContentType: "image/jpeg",
}
- out, err := c.DynamicLargeObjectCreateFile(&opts)
+ out, err := c.DynamicLargeObjectCreateFile(ctx, &opts)
if err != nil {
t.Fatal(err)
}
@@ -2201,13 +2299,13 @@ func TestDLOInsert(t *testing.T) {
if err != nil {
t.Fatal(err)
}
- fmt.Fprintf(buf, "\n%d %s\n", 1, CONTENTS)
- err = out.Close()
+ _, _ = fmt.Fprintf(buf, "\n%d %s\n", 1, CONTENTS)
+ err = out.CloseWithContext(ctx)
if err != nil {
t.Error(err)
}
expected := buf.String()
- contents, err := c.ObjectGetString(CONTAINER, OBJECT)
+ contents, err := c.ObjectGetString(ctx, CONTAINER, OBJECT)
if err != nil {
t.Error(err)
}
@@ -2217,6 +2315,7 @@ func TestDLOInsert(t *testing.T) {
}
func TestDLOAppend(t *testing.T) {
+ ctx := context.Background()
c, rollback := makeConnectionWithDLO(t)
defer rollback()
opts := swift.LargeObjectOpts{
@@ -2226,12 +2325,15 @@ func TestDLOAppend(t *testing.T) {
CheckHash: true,
ContentType: "image/jpeg",
}
- out, err := c.DynamicLargeObjectCreateFile(&opts)
+ out, err := c.DynamicLargeObjectCreateFile(ctx, &opts)
if err != nil {
t.Fatal(err)
}
- contents, err := c.ObjectGetString(CONTAINER, OBJECT)
+ contents, err := c.ObjectGetString(ctx, CONTAINER, OBJECT)
+ if err != nil {
+ t.Fatal(err)
+ }
buf := bytes.NewBuffer([]byte(contents))
multi := io.MultiWriter(buf, out)
for i := 0; i < 2; i++ {
@@ -2240,12 +2342,12 @@ func TestDLOAppend(t *testing.T) {
t.Fatal(err)
}
}
- err = out.Close()
+ err = out.CloseWithContext(ctx)
if err != nil {
t.Error(err)
}
expected := buf.String()
- contents, err = c.ObjectGetString(CONTAINER, OBJECT)
+ contents, err = c.ObjectGetString(ctx, CONTAINER, OBJECT)
if err != nil {
t.Error(err)
}
@@ -2255,6 +2357,7 @@ func TestDLOAppend(t *testing.T) {
}
func TestDLOTruncate(t *testing.T) {
+ ctx := context.Background()
c, rollback := makeConnectionWithDLO(t)
defer rollback()
opts := swift.LargeObjectOpts{
@@ -2264,7 +2367,7 @@ func TestDLOTruncate(t *testing.T) {
CheckHash: true,
ContentType: "image/jpeg",
}
- out, err := c.DynamicLargeObjectCreateFile(&opts)
+ out, err := c.DynamicLargeObjectCreateFile(ctx, &opts)
if err != nil {
t.Fatal(err)
}
@@ -2275,12 +2378,12 @@ func TestDLOTruncate(t *testing.T) {
if err != nil {
t.Fatal(err)
}
- err = out.Close()
+ err = out.CloseWithContext(ctx)
if err != nil {
t.Error(err)
}
expected := buf.String()
- contents, err := c.ObjectGetString(CONTAINER, OBJECT)
+ contents, err := c.ObjectGetString(ctx, CONTAINER, OBJECT)
if err != nil {
t.Error(err)
}
@@ -2290,25 +2393,26 @@ func TestDLOTruncate(t *testing.T) {
}
func TestDLOMove(t *testing.T) {
+ ctx := context.Background()
c, rollback := makeConnectionWithDLO(t)
defer rollback()
- contents, err := c.ObjectGetString(CONTAINER, OBJECT)
+ contents, err := c.ObjectGetString(ctx, CONTAINER, OBJECT)
if err != nil {
t.Fatal(err)
}
- err = c.DynamicLargeObjectMove(CONTAINER, OBJECT, CONTAINER, OBJECT2)
+ err = c.DynamicLargeObjectMove(ctx, CONTAINER, OBJECT, CONTAINER, OBJECT2)
if err != nil {
t.Fatal(err)
}
defer func() {
- err = c.DynamicLargeObjectDelete(CONTAINER, OBJECT2)
+ err = c.DynamicLargeObjectDelete(ctx, CONTAINER, OBJECT2)
if err != nil {
t.Fatal(err)
}
}()
- contents2, err := c.ObjectGetString(CONTAINER, OBJECT2)
+ contents2, err := c.ObjectGetString(ctx, CONTAINER, OBJECT2)
if err != nil {
t.Fatal(err)
}
@@ -2319,6 +2423,7 @@ func TestDLOMove(t *testing.T) {
}
func TestDLONoSegmentContainer(t *testing.T) {
+ ctx := context.Background()
c, rollback := makeConnectionWithDLO(t)
defer rollback()
opts := swift.LargeObjectOpts{
@@ -2327,7 +2432,7 @@ func TestDLONoSegmentContainer(t *testing.T) {
ContentType: "image/jpeg",
SegmentContainer: CONTAINER,
}
- out, err := c.DynamicLargeObjectCreate(&opts)
+ out, err := c.DynamicLargeObjectCreate(ctx, &opts)
if err != nil {
t.Fatal(err)
}
@@ -2340,12 +2445,12 @@ func TestDLONoSegmentContainer(t *testing.T) {
t.Fatal(err)
}
}
- err = out.Close()
+ err = out.CloseWithContext(ctx)
if err != nil {
t.Error(err)
}
expected := buf.String()
- contents, err := c.ObjectGetString(CONTAINER, OBJECT)
+ contents, err := c.ObjectGetString(ctx, CONTAINER, OBJECT)
if err != nil {
t.Error(err)
}
@@ -2355,6 +2460,7 @@ func TestDLONoSegmentContainer(t *testing.T) {
}
func TestDLOCreateMissingSegmentsInList(t *testing.T) {
+ ctx := context.Background()
c, rollback := makeConnectionWithContainer(t)
defer rollback()
@@ -2369,17 +2475,17 @@ func TestDLOCreateMissingSegmentsInList(t *testing.T) {
w.Header().Set(k, v[0])
}
w.WriteHeader(recorder.Code)
- w.Write([]byte("null\n"))
+ _, _ = w.Write([]byte("null\n"))
})
defer srv.UnsetOverride(listURL)
headers := swift.Headers{}
- err := c.ContainerCreate(SEGMENTS_CONTAINER, headers)
+ err := c.ContainerCreate(ctx, SEGMENTS_CONTAINER, headers)
if err != nil {
t.Fatal(err)
}
defer func() {
- err = c.ContainerDelete(SEGMENTS_CONTAINER)
+ err = c.ContainerDelete(ctx, SEGMENTS_CONTAINER)
if err != nil {
t.Fatal(err)
}
@@ -2390,12 +2496,12 @@ func TestDLOCreateMissingSegmentsInList(t *testing.T) {
ObjectName: OBJECT,
ContentType: "image/jpeg",
}
- out, err := c.DynamicLargeObjectCreate(&opts)
+ out, err := c.DynamicLargeObjectCreate(ctx, &opts)
if err != nil {
t.Fatal(err)
}
defer func() {
- err = c.DynamicLargeObjectDelete(CONTAINER, OBJECT)
+ err = c.DynamicLargeObjectDelete(ctx, CONTAINER, OBJECT)
if err != nil {
t.Fatal(err)
}
@@ -2409,12 +2515,12 @@ func TestDLOCreateMissingSegmentsInList(t *testing.T) {
t.Fatal(err)
}
}
- err = out.Close()
+ err = out.CloseWithContext(ctx)
if err != nil {
t.Error(err)
}
expected := buf.String()
- contents, err := c.ObjectGetString(CONTAINER, OBJECT)
+ contents, err := c.ObjectGetString(ctx, CONTAINER, OBJECT)
if err != nil {
t.Error(err)
}
@@ -2424,6 +2530,7 @@ func TestDLOCreateMissingSegmentsInList(t *testing.T) {
}
func TestDLOCreateIncorrectSize(t *testing.T) {
+ ctx := context.Background()
c, rollback := makeConnectionWithContainer(t)
defer rollback()
@@ -2446,17 +2553,17 @@ func TestDLOCreateIncorrectSize(t *testing.T) {
}
}
w.WriteHeader(recorder.Code)
- w.Write(recorder.Body.Bytes())
+ _, _ = w.Write(recorder.Body.Bytes())
})
defer srv.UnsetOverride(listURL)
headers := swift.Headers{}
- err := c.ContainerCreate(SEGMENTS_CONTAINER, headers)
+ err := c.ContainerCreate(ctx, SEGMENTS_CONTAINER, headers)
if err != nil {
t.Fatal(err)
}
defer func() {
- err = c.ContainerDelete(SEGMENTS_CONTAINER)
+ err = c.ContainerDelete(ctx, SEGMENTS_CONTAINER)
if err != nil {
t.Fatal(err)
}
@@ -2467,12 +2574,12 @@ func TestDLOCreateIncorrectSize(t *testing.T) {
ObjectName: OBJECT,
ContentType: "image/jpeg",
}
- out, err := c.DynamicLargeObjectCreate(&opts)
+ out, err := c.DynamicLargeObjectCreate(ctx, &opts)
if err != nil {
t.Fatal(err)
}
defer func() {
- err = c.DynamicLargeObjectDelete(CONTAINER, OBJECT)
+ err = c.DynamicLargeObjectDelete(ctx, CONTAINER, OBJECT)
if err != nil {
t.Fatal(err)
}
@@ -2485,7 +2592,7 @@ func TestDLOCreateIncorrectSize(t *testing.T) {
t.Fatal(err)
}
}
- err = out.Close()
+ err = out.CloseWithContext(ctx)
if err != nil {
t.Error(err)
}
@@ -2493,7 +2600,7 @@ func TestDLOCreateIncorrectSize(t *testing.T) {
t.Errorf("Unexpected HEAD requests count, expected %d, got: %d", expectedHeadCount, headCount)
}
expected := buf.String()
- contents, err := c.ObjectGetString(CONTAINER, OBJECT)
+ contents, err := c.ObjectGetString(ctx, CONTAINER, OBJECT)
if err != nil {
t.Error(err)
}
@@ -2503,6 +2610,7 @@ func TestDLOCreateIncorrectSize(t *testing.T) {
}
func TestDLOConcurrentWrite(t *testing.T) {
+ ctx := context.Background()
c, rollback := makeConnectionWithSegmentsContainer(t)
defer rollback()
@@ -2517,12 +2625,12 @@ func TestDLOConcurrentWrite(t *testing.T) {
ObjectName: objName,
ContentType: "image/jpeg",
}
- out, err := c.DynamicLargeObjectCreate(&opts)
+ out, err := c.DynamicLargeObjectCreate(ctx, &opts)
if err != nil {
t.Fatal(err)
}
defer func() {
- err = c.DynamicLargeObjectDelete(CONTAINER, objName)
+ err = c.DynamicLargeObjectDelete(ctx, CONTAINER, objName)
if err != nil {
t.Fatal(err)
}
@@ -2544,12 +2652,12 @@ func TestDLOConcurrentWrite(t *testing.T) {
t.Fatalf("expected to write %d, got: %d", chunkSize, n)
}
}
- err = out.Close()
+ err = out.CloseWithContext(ctx)
if err != nil {
t.Error(err)
}
expected := buf.String()
- contents, err := c.ObjectGetString(CONTAINER, objName)
+ contents, err := c.ObjectGetString(ctx, CONTAINER, objName)
if err != nil {
t.Error(err)
}
@@ -2570,6 +2678,7 @@ func TestDLOConcurrentWrite(t *testing.T) {
}
func TestDLOSegmentation(t *testing.T) {
+ ctx := context.Background()
c, rollback := makeConnectionWithSegmentsContainer(t)
defer rollback()
@@ -2582,7 +2691,7 @@ func TestDLOSegmentation(t *testing.T) {
}
testSegmentation(t, c, func() swift.LargeObjectFile {
- out, err := c.DynamicLargeObjectCreate(&opts)
+ out, err := c.DynamicLargeObjectCreate(ctx, &opts)
if err != nil {
t.Fatal(err)
}
@@ -2625,6 +2734,7 @@ func TestDLOSegmentation(t *testing.T) {
}
func TestDLOSegmentationBuffered(t *testing.T) {
+ ctx := context.Background()
c, rollback := makeConnectionWithSegmentsContainer(t)
defer rollback()
@@ -2636,7 +2746,7 @@ func TestDLOSegmentationBuffered(t *testing.T) {
}
testSegmentation(t, c, func() swift.LargeObjectFile {
- out, err := c.DynamicLargeObjectCreate(&opts)
+ out, err := c.DynamicLargeObjectCreate(ctx, &opts)
if err != nil {
t.Fatal(err)
}
@@ -2679,6 +2789,7 @@ func TestDLOSegmentationBuffered(t *testing.T) {
}
func TestSLOCreate(t *testing.T) {
+ ctx := context.Background()
c, rollback := makeConnectionWithSegmentsContainer(t)
defer rollback()
@@ -2687,7 +2798,7 @@ func TestSLOCreate(t *testing.T) {
ObjectName: OBJECT,
ContentType: "image/jpeg",
}
- out, err := c.StaticLargeObjectCreate(&opts)
+ out, err := c.StaticLargeObjectCreate(ctx, &opts)
if err != nil {
if err == swift.SLONotSupported {
t.Skip("SLO not supported")
@@ -2696,7 +2807,7 @@ func TestSLOCreate(t *testing.T) {
t.Fatal(err)
}
defer func() {
- err = c.StaticLargeObjectDelete(CONTAINER, OBJECT)
+ err = c.StaticLargeObjectDelete(ctx, CONTAINER, OBJECT)
if err != nil {
t.Fatal(err)
}
@@ -2710,19 +2821,19 @@ func TestSLOCreate(t *testing.T) {
t.Fatal(err)
}
}
- err = out.Close()
+ err = out.CloseWithContext(ctx)
if err != nil {
t.Error(err)
}
expected := buf.String()
- contents, err := c.ObjectGetString(CONTAINER, OBJECT)
+ contents, err := c.ObjectGetString(ctx, CONTAINER, OBJECT)
if err != nil {
t.Error(err)
}
if contents != expected {
t.Errorf("Contents wrong, expected %q, got: %q", expected, contents)
}
- info, _, err := c.Object(CONTAINER, OBJECT)
+ info, _, err := c.Object(ctx, CONTAINER, OBJECT)
if err != nil {
t.Fatal(err)
}
@@ -2735,6 +2846,7 @@ func TestSLOCreate(t *testing.T) {
}
func TestSLOInsert(t *testing.T) {
+ ctx := context.Background()
c, rollback := makeConnectionWithSLO(t)
defer rollback()
opts := swift.LargeObjectOpts{
@@ -2742,7 +2854,7 @@ func TestSLOInsert(t *testing.T) {
ObjectName: OBJECT,
ContentType: "image/jpeg",
}
- out, err := c.StaticLargeObjectCreateFile(&opts)
+ out, err := c.StaticLargeObjectCreateFile(ctx, &opts)
if err != nil {
t.Fatal(err)
}
@@ -2753,13 +2865,13 @@ func TestSLOInsert(t *testing.T) {
if err != nil {
t.Fatal(err)
}
- fmt.Fprintf(buf, "\n%d %s\n", 1, CONTENTS)
- err = out.Close()
+ _, _ = fmt.Fprintf(buf, "\n%d %s\n", 1, CONTENTS)
+ err = out.CloseWithContext(ctx)
if err != nil {
t.Error(err)
}
expected := buf.String()
- contents, err := c.ObjectGetString(CONTAINER, OBJECT)
+ contents, err := c.ObjectGetString(ctx, CONTAINER, OBJECT)
if err != nil {
t.Error(err)
}
@@ -2769,6 +2881,7 @@ func TestSLOInsert(t *testing.T) {
}
func TestSLOAppend(t *testing.T) {
+ ctx := context.Background()
c, rollback := makeConnectionWithSLO(t)
defer rollback()
opts := swift.LargeObjectOpts{
@@ -2778,12 +2891,15 @@ func TestSLOAppend(t *testing.T) {
CheckHash: true,
ContentType: "image/jpeg",
}
- out, err := c.StaticLargeObjectCreateFile(&opts)
+ out, err := c.StaticLargeObjectCreateFile(ctx, &opts)
if err != nil {
t.Fatal(err)
}
- contents, err := c.ObjectGetString(CONTAINER, OBJECT)
+ contents, err := c.ObjectGetString(ctx, CONTAINER, OBJECT)
+ if err != nil {
+ t.Fatal(err)
+ }
buf := bytes.NewBuffer([]byte(contents))
multi := io.MultiWriter(buf, out)
for i := 0; i < 2; i++ {
@@ -2792,12 +2908,12 @@ func TestSLOAppend(t *testing.T) {
t.Fatal(err)
}
}
- err = out.Close()
+ err = out.CloseWithContext(ctx)
if err != nil {
t.Error(err)
}
expected := buf.String()
- contents, err = c.ObjectGetString(CONTAINER, OBJECT)
+ contents, err = c.ObjectGetString(ctx, CONTAINER, OBJECT)
if err != nil {
t.Error(err)
}
@@ -2807,25 +2923,26 @@ func TestSLOAppend(t *testing.T) {
}
func TestSLOMove(t *testing.T) {
+ ctx := context.Background()
c, rollback := makeConnectionWithSLO(t)
defer rollback()
- contents, err := c.ObjectGetString(CONTAINER, OBJECT)
+ contents, err := c.ObjectGetString(ctx, CONTAINER, OBJECT)
if err != nil {
t.Fatal(err)
}
- err = c.StaticLargeObjectMove(CONTAINER, OBJECT, CONTAINER, OBJECT2)
+ err = c.StaticLargeObjectMove(ctx, CONTAINER, OBJECT, CONTAINER, OBJECT2)
if err != nil {
t.Fatal(err)
}
defer func() {
- err = c.StaticLargeObjectDelete(CONTAINER, OBJECT2)
+ err = c.StaticLargeObjectDelete(ctx, CONTAINER, OBJECT2)
if err != nil {
t.Fatal(err)
}
}()
- contents2, err := c.ObjectGetString(CONTAINER, OBJECT2)
+ contents2, err := c.ObjectGetString(ctx, CONTAINER, OBJECT2)
if err != nil {
t.Fatal(err)
}
@@ -2836,6 +2953,7 @@ func TestSLOMove(t *testing.T) {
}
func TestSLONoSegmentContainer(t *testing.T) {
+ ctx := context.Background()
c, rollback := makeConnectionWithSLO(t)
defer rollback()
@@ -2845,7 +2963,7 @@ func TestSLONoSegmentContainer(t *testing.T) {
ContentType: "image/jpeg",
SegmentContainer: CONTAINER,
}
- out, err := c.StaticLargeObjectCreate(&opts)
+ out, err := c.StaticLargeObjectCreate(ctx, &opts)
if err != nil {
t.Fatal(err)
}
@@ -2858,12 +2976,12 @@ func TestSLONoSegmentContainer(t *testing.T) {
t.Fatal(err)
}
}
- err = out.Close()
+ err = out.CloseWithContext(ctx)
if err != nil {
t.Error(err)
}
expected := buf.String()
- contents, err := c.ObjectGetString(CONTAINER, OBJECT)
+ contents, err := c.ObjectGetString(ctx, CONTAINER, OBJECT)
if err != nil {
t.Error(err)
}
@@ -2871,13 +2989,14 @@ func TestSLONoSegmentContainer(t *testing.T) {
t.Errorf("Contents wrong, expected %q, got: %q", expected, contents)
}
- err = c.StaticLargeObjectDelete(CONTAINER, OBJECT)
+ err = c.StaticLargeObjectDelete(ctx, CONTAINER, OBJECT)
if err != nil {
t.Fatal(err)
}
}
func TestSLOMinChunkSize(t *testing.T) {
+ ctx := context.Background()
c, rollback := makeConnectionWithSegmentsContainer(t)
defer rollback()
if srv == nil {
@@ -2886,10 +3005,10 @@ func TestSLOMinChunkSize(t *testing.T) {
}
srv.SetOverride("/info", func(w http.ResponseWriter, r *http.Request, recorder *httptest.ResponseRecorder) {
- w.Write([]byte(`{"slo": {"min_segment_size": 4}}`))
+ _, _ = w.Write([]byte(`{"slo": {"min_segment_size": 4}}`))
})
defer srv.UnsetOverride("/info")
- c.QueryInfo()
+ _, _ = c.QueryInfo(ctx)
opts := swift.LargeObjectOpts{
Container: CONTAINER,
@@ -2901,7 +3020,7 @@ func TestSLOMinChunkSize(t *testing.T) {
}
testSLOSegmentation(t, c, func() swift.LargeObjectFile {
- out, err := c.StaticLargeObjectCreate(&opts)
+ out, err := c.StaticLargeObjectCreate(ctx, &opts)
if err != nil {
t.Fatal(err)
}
@@ -2910,6 +3029,7 @@ func TestSLOMinChunkSize(t *testing.T) {
}
func TestSLOSegmentation(t *testing.T) {
+ ctx := context.Background()
c, rollback := makeConnectionWithSegmentsContainer(t)
defer rollback()
opts := swift.LargeObjectOpts{
@@ -2921,7 +3041,7 @@ func TestSLOSegmentation(t *testing.T) {
NoBuffer: true,
}
testSLOSegmentation(t, c, func() swift.LargeObjectFile {
- out, err := c.StaticLargeObjectCreate(&opts)
+ out, err := c.StaticLargeObjectCreate(ctx, &opts)
if err != nil {
if err == swift.SLONotSupported {
t.Skip("SLO not supported")
@@ -2933,6 +3053,7 @@ func TestSLOSegmentation(t *testing.T) {
}
func TestSLOSegmentationBuffered(t *testing.T) {
+ ctx := context.Background()
c, rollback := makeConnectionWithSegmentsContainer(t)
defer rollback()
opts := swift.LargeObjectOpts{
@@ -2943,7 +3064,7 @@ func TestSLOSegmentationBuffered(t *testing.T) {
MinChunkSize: 4,
}
testSegmentation(t, c, func() swift.LargeObjectFile {
- out, err := c.StaticLargeObjectCreate(&opts)
+ out, err := c.StaticLargeObjectCreate(ctx, &opts)
if err != nil {
if err == swift.SLONotSupported {
t.Skip("SLO not supported")
@@ -3035,11 +3156,12 @@ type segmentTest struct {
}
func testSegmentation(t *testing.T, c *swift.Connection, createObj func() swift.LargeObjectFile, testCases []segmentTest) {
+ ctx := context.Background()
var err error
runTestCase := func(tCase segmentTest) {
out := createObj()
defer func() {
- err = c.LargeObjectDelete(CONTAINER, OBJECT)
+ err = c.LargeObjectDelete(ctx, CONTAINER, OBJECT)
if err != nil {
t.Fatal(err)
}
@@ -3056,31 +3178,31 @@ func testSegmentation(t *testing.T, c *swift.Connection, createObj func() swift.
}
}
}
- err = out.Close()
+ err = out.CloseWithContext(ctx)
if err != nil {
t.Error(err)
}
- contents, err := c.ObjectGetString(CONTAINER, OBJECT)
+ contents, err := c.ObjectGetString(ctx, CONTAINER, OBJECT)
if err != nil {
t.Error(err)
}
if contents != tCase.expectedValue {
t.Errorf("Contents wrong, expected %q, got: %q", tCase.expectedValue, contents)
}
- container, objects, err := c.LargeObjectGetSegments(CONTAINER, OBJECT)
+ container, objects, err := c.LargeObjectGetSegments(ctx, CONTAINER, OBJECT)
if err != nil {
t.Error(err)
}
if container != SEGMENTS_CONTAINER {
t.Errorf("Segments container wrong, expected %q, got: %q", SEGMENTS_CONTAINER, container)
}
- _, headers, err := c.Object(CONTAINER, OBJECT)
+ _, headers, err := c.Object(ctx, CONTAINER, OBJECT)
if err != nil {
t.Fatal(err)
}
if headers.IsLargeObjectSLO() {
var info swift.SwiftInfo
- info, err = c.QueryInfo()
+ info, err = c.QueryInfo(ctx)
if err != nil {
t.Fatal(err)
}
@@ -3092,7 +3214,7 @@ func testSegmentation(t *testing.T, c *swift.Connection, createObj func() swift.
var segContents []string
for _, obj := range objects {
var value string
- value, err = c.ObjectGetString(SEGMENTS_CONTAINER, obj.Name)
+ value, err = c.ObjectGetString(ctx, SEGMENTS_CONTAINER, obj.Name)
if err != nil {
t.Error(err)
}
@@ -3108,23 +3230,25 @@ func testSegmentation(t *testing.T, c *swift.Connection, createObj func() swift.
}
func TestContainerDelete(t *testing.T) {
+ ctx := context.Background()
c, rollback := makeConnectionWithContainer(t)
defer rollback()
- err := c.ContainerDelete(CONTAINER)
+ err := c.ContainerDelete(ctx, CONTAINER)
if err != nil {
t.Fatal(err)
}
- err = c.ContainerDelete(CONTAINER)
+ err = c.ContainerDelete(ctx, CONTAINER)
if err != swift.ContainerNotFound {
t.Fatal("Expecting container not found", err)
}
- _, _, err = c.Container(CONTAINER)
+ _, _, err = c.Container(ctx, CONTAINER)
if err != swift.ContainerNotFound {
t.Fatal("Expecting container not found", err)
}
}
func TestUnAuthenticate(t *testing.T) {
+ ctx := context.Background()
c, rollback := makeConnectionAuth(t)
defer rollback()
c.UnAuthenticate()
@@ -3132,7 +3256,7 @@ func TestUnAuthenticate(t *testing.T) {
t.Fatal("Shouldn't be authenticated")
}
// Test re-authenticate
- err := c.Authenticate()
+ err := c.Authenticate(ctx)
if err != nil {
t.Fatal("ReAuth failed", err)
}
diff --git a/swifttest/server.go b/swifttest/server.go
index d7dd748..a6bd6b5 100644
--- a/swifttest/server.go
+++ b/swifttest/server.go
@@ -34,7 +34,6 @@ import (
"strings"
"sync"
"sync/atomic"
- "testing"
"time"
)
@@ -51,8 +50,6 @@ type SwiftServer struct {
// See https://golang.org/pkg/sync/atomic/#pkg-note-BUG for more details.
reqId int64
sync.RWMutex
- t *testing.T
- mu sync.Mutex
Listener net.Listener
AuthURL string
URL string
@@ -145,7 +142,6 @@ type container struct {
sync.RWMutex
metadata
name string
- ctime time.Time
objects map[string]*object
}
@@ -188,15 +184,6 @@ type containerResource struct {
container *container // non-nil if the container already exists.
}
-var responseParams = map[string]bool{
- "content-type": true,
- "content-language": true,
- "expires": true,
- "cache-control": true,
- "content-disposition": true,
- "content-encoding": true,
-}
-
func fatalf(code int, codeStr string, errf string, a ...interface{}) {
panic(&swiftError{
statusCode: code,
@@ -319,9 +306,15 @@ func (r containerResource) get(a *action) interface{} {
} else {
for _, item := range objects {
if obj, ok := item.(*object); ok {
- a.w.Write([]byte(obj.name + "\n"))
+ _, err := a.w.Write([]byte(obj.name + "\n"))
+ if err != nil {
+ fatalf(500, "WriteFailed", "Write failed")
+ }
} else if subdir, ok := item.(Subdir); ok {
- a.w.Write([]byte(subdir.Subdir + "\n"))
+ _, err := a.w.Write([]byte(subdir.Subdir + "\n"))
+ if err != nil {
+ fatalf(500, "WriteFailed", "Write failed")
+ }
}
}
return nil
@@ -398,7 +391,12 @@ func (r containerResource) put(a *action) interface{} {
if err != nil {
fatalf(400, "TODO", "Invalid tar.gz")
}
- defer gzr.Close()
+ defer func() {
+ err := gzr.Close()
+ if err != nil {
+ fatalf(400, "CloseFailed", "Close failed")
+ }
+ }()
reader = tar.NewReader(gzr)
case "tar.bz2":
bzr := bzip2.NewReader(dataReader)
@@ -660,7 +658,10 @@ func (objr objectResource) get(a *action) interface{} {
} else if value, ok := obj.meta["X-Static-Large-Object"]; ok && value[0] == "True" && a.req.URL.Query().Get("multipart-manifest") != "get" {
var segments []io.Reader
var segmentList []segment
- json.Unmarshal(obj.data, &segmentList)
+ err := json.Unmarshal(obj.data, &segmentList)
+ if err != nil {
+ fatalf(400, "BadParameters", "Unmarshal failed.")
+ }
cursor := 0
size := 0
sum := md5.New()
@@ -769,7 +770,10 @@ func (objr objectResource) put(a *action) interface{} {
a.req.Header.Set("X-Static-Large-Object", "True")
var segments []segment
- json.Unmarshal(data, &segments)
+ err := json.Unmarshal(data, &segments)
+ if err != nil {
+ fatalf(400, "BadParameters", "Unmarshal failed.")
+ }
for i := range segments {
segments[i].Name = "/" + segments[i].Path
segments[i].Path = ""
@@ -901,7 +905,10 @@ func (objr objectResource) copy(a *action) interface{} {
func (s *SwiftServer) serveHTTP(w http.ResponseWriter, req *http.Request) {
// ignore error from ParseForm as it's usually spurious.
- req.ParseForm()
+ err := req.ParseForm()
+ if err != nil {
+ fatalf(400, "BadParameters", "Parse form failed.")
+ }
if fn := s.override[req.URL.Path]; fn != nil {
originalRW := w
@@ -954,8 +961,8 @@ func (s *SwiftServer) serveHTTP(w http.ResponseWriter, req *http.Request) {
_, _ = rand.Read(r)
id := fmt.Sprintf("%X", r)
w.Header().Set("X-Storage-Url", s.URL+"/AUTH_"+username)
- w.Header().Set("X-Auth-Token", "AUTH_tk"+string(id))
- w.Header().Set("X-Storage-Token", "AUTH_tk"+string(id))
+ w.Header().Set("X-Auth-Token", "AUTH_tk"+id)
+ w.Header().Set("X-Storage-Token", "AUTH_tk"+id)
s.Sessions[id] = &session{
username: username,
}
@@ -1016,7 +1023,6 @@ func (s *SwiftServer) serveHTTP(w http.ResponseWriter, req *http.Request) {
if !ok {
s.RUnlock()
panic(notAuthorized())
- return
}
a.user = s.Accounts[session.username]
@@ -1046,9 +1052,15 @@ func (s *SwiftServer) serveHTTP(w http.ResponseWriter, req *http.Request) {
} else {
switch r := resp.(type) {
case string:
- w.Write([]byte(r))
+ _, err := w.Write([]byte(r))
+ if err != nil {
+ fatalf(500, "WriteFailed", "Write failed.")
+ }
default:
- w.Write(resp.([]byte))
+ _, err := w.Write(resp.([]byte))
+ if err != nil {
+ fatalf(500, "WriteFailed", "Write failed.")
+ }
}
}
}
@@ -1195,7 +1207,10 @@ func (rootResource) get(a *action) interface{} {
Name: container.name,
})
} else {
- a.w.Write([]byte(container.name + "\n"))
+ _, err := a.w.Write([]byte(container.name + "\n"))
+ if err != nil {
+ fatalf(500, "WriteFailed", "Write failed.")
+ }
}
}
@@ -1275,7 +1290,10 @@ func (r rootResource) delete(a *action) interface{} {
}
resp := fmt.Sprintf("Number Deleted: %d\nNumber Not Found: %d\nErrors: \nResponse Status: 200 OK\n", nb, notFound)
- a.w.Write([]byte(resp))
+ _, err = a.w.Write([]byte(resp))
+ if err != nil {
+ fatalf(500, "WriteFailed", "Write failed.")
+ }
return nil
}
@@ -1310,13 +1328,15 @@ func NewSwiftServer(address string) (*SwiftServer, error) {
Containers: make(map[string]*container),
}
- go http.Serve(l, http.HandlerFunc(func(w http.ResponseWriter, req *http.Request) {
- server.serveHTTP(w, req)
- }))
+ go func() {
+ _ = http.Serve(l, http.HandlerFunc(func(w http.ResponseWriter, req *http.Request) {
+ server.serveHTTP(w, req)
+ }))
+ }()
return server, nil
}
func (srv *SwiftServer) Close() {
- srv.Listener.Close()
+ _ = srv.Listener.Close()
}
diff --git a/timeout_reader.go b/timeout_reader.go
index 88ae733..7715902 100644
--- a/timeout_reader.go
+++ b/timeout_reader.go
@@ -47,7 +47,6 @@ func (t *timeoutReader) Read(p []byte) (int, error) {
t.cancel()
return 0, TimeoutError
}
- panic("unreachable") // for Go 1.0
}
// Close the channel
diff --git a/timeout_reader_test.go b/timeout_reader_test.go
index 2348617..5eba093 100644
--- a/timeout_reader_test.go
+++ b/timeout_reader_test.go
@@ -67,7 +67,7 @@ func TestTimeoutReaderNoTimeout(t *testing.T) {
if test.closed {
t.Fatal("Shouldn't be closed")
}
- tr.Close()
+ _ = tr.Close()
if !test.closed {
t.Fatal("Should be closed")
}
@@ -100,7 +100,7 @@ func TestTimeoutReaderTimeout(t *testing.T) {
if test.closed {
t.Fatal("Shouldn't be closed")
}
- tr.Close()
+ _ = tr.Close()
if !test.closed {
t.Fatal("Should be closed")
}
Debdiff
[The following lists of changes regard files as different if they have different names, permissions or owners.]
Files in second set of .debs but not in first
-rw-r--r-- root/root /usr/share/gocode/src/github.com/ncw/swift/go.sum
No differences were encountered in the control files