| ... | ... |
@@ -212,18 +212,11 @@ func (cli *Client) getAPIPath(p string, query url.Values) string {
|
| 212 | 212 |
var apiPath string |
| 213 | 213 |
if cli.version != "" {
|
| 214 | 214 |
v := strings.TrimPrefix(cli.version, "v") |
| 215 |
- apiPath = path.Join(cli.basePath, "/v"+v+p) |
|
| 215 |
+ apiPath = path.Join(cli.basePath, "/v"+v, p) |
|
| 216 | 216 |
} else {
|
| 217 | 217 |
apiPath = path.Join(cli.basePath, p) |
| 218 | 218 |
} |
| 219 |
- |
|
| 220 |
- u := &url.URL{
|
|
| 221 |
- Path: apiPath, |
|
| 222 |
- } |
|
| 223 |
- if len(query) > 0 {
|
|
| 224 |
- u.RawQuery = query.Encode() |
|
| 225 |
- } |
|
| 226 |
- return u.String() |
|
| 219 |
+ return (&url.URL{Path: apiPath, RawQuery: query.Encode()}).String()
|
|
| 227 | 220 |
} |
| 228 | 221 |
|
| 229 | 222 |
// ClientVersion returns the API version used by this client. |
| ... | ... |
@@ -105,11 +105,11 @@ func TestNewEnvClient(t *testing.T) {
|
| 105 | 105 |
} |
| 106 | 106 |
|
| 107 | 107 |
func TestGetAPIPath(t *testing.T) {
|
| 108 |
- cases := []struct {
|
|
| 109 |
- v string |
|
| 110 |
- p string |
|
| 111 |
- q url.Values |
|
| 112 |
- e string |
|
| 108 |
+ testcases := []struct {
|
|
| 109 |
+ version string |
|
| 110 |
+ path string |
|
| 111 |
+ query url.Values |
|
| 112 |
+ expected string |
|
| 113 | 113 |
}{
|
| 114 | 114 |
{"", "/containers/json", nil, "/containers/json"},
|
| 115 | 115 |
{"", "/containers/json", url.Values{}, "/containers/json"},
|
| ... | ... |
@@ -123,16 +123,10 @@ func TestGetAPIPath(t *testing.T) {
|
| 123 | 123 |
{"v1.22", "/networks/kiwl$%^", nil, "/v1.22/networks/kiwl$%25%5E"},
|
| 124 | 124 |
} |
| 125 | 125 |
|
| 126 |
- for _, cs := range cases {
|
|
| 127 |
- c, err := NewClient("unix:///var/run/docker.sock", cs.v, nil, nil)
|
|
| 128 |
- if err != nil {
|
|
| 129 |
- t.Fatal(err) |
|
| 130 |
- } |
|
| 131 |
- g := c.getAPIPath(cs.p, cs.q) |
|
| 132 |
- assert.Equal(t, g, cs.e) |
|
| 133 |
- |
|
| 134 |
- err = c.Close() |
|
| 135 |
- assert.NoError(t, err) |
|
| 126 |
+ for _, testcase := range testcases {
|
|
| 127 |
+ c := Client{version: testcase.version, basePath: "/"}
|
|
| 128 |
+ actual := c.getAPIPath(testcase.path, testcase.query) |
|
| 129 |
+ assert.Equal(t, actual, testcase.expected) |
|
| 136 | 130 |
} |
| 137 | 131 |
} |
| 138 | 132 |
|
| ... | ... |
@@ -5,6 +5,7 @@ import ( |
| 5 | 5 |
"encoding/json" |
| 6 | 6 |
"io/ioutil" |
| 7 | 7 |
"net/http" |
| 8 |
+ "path" |
|
| 8 | 9 |
|
| 9 | 10 |
"github.com/docker/docker/api/types" |
| 10 | 11 |
"golang.org/x/net/context" |
| ... | ... |
@@ -18,8 +19,15 @@ func (cli *Client) VolumeInspect(ctx context.Context, volumeID string) (types.Vo |
| 18 | 18 |
|
| 19 | 19 |
// VolumeInspectWithRaw returns the information about a specific volume in the docker host and its raw representation |
| 20 | 20 |
func (cli *Client) VolumeInspectWithRaw(ctx context.Context, volumeID string) (types.Volume, []byte, error) {
|
| 21 |
+ // The empty ID needs to be handled here because with an empty ID the |
|
| 22 |
+ // request url will not contain a trailing / which calls the volume list API |
|
| 23 |
+ // instead of volume inspect |
|
| 24 |
+ if volumeID == "" {
|
|
| 25 |
+ return types.Volume{}, nil, volumeNotFoundError{volumeID}
|
|
| 26 |
+ } |
|
| 27 |
+ |
|
| 21 | 28 |
var volume types.Volume |
| 22 |
- resp, err := cli.get(ctx, "/volumes/"+volumeID, nil, nil) |
|
| 29 |
+ resp, err := cli.get(ctx, path.Join("/volumes", volumeID), nil, nil)
|
|
| 23 | 30 |
if err != nil {
|
| 24 | 31 |
if resp.statusCode == http.StatusNotFound {
|
| 25 | 32 |
return volume, nil, volumeNotFoundError{volumeID}
|
| ... | ... |
@@ -10,6 +10,9 @@ import ( |
| 10 | 10 |
"testing" |
| 11 | 11 |
|
| 12 | 12 |
"github.com/docker/docker/api/types" |
| 13 |
+ "github.com/docker/docker/internal/testutil" |
|
| 14 |
+ "github.com/stretchr/testify/assert" |
|
| 15 |
+ "github.com/stretchr/testify/require" |
|
| 13 | 16 |
"golang.org/x/net/context" |
| 14 | 17 |
) |
| 15 | 18 |
|
| ... | ... |
@@ -19,9 +22,7 @@ func TestVolumeInspectError(t *testing.T) {
|
| 19 | 19 |
} |
| 20 | 20 |
|
| 21 | 21 |
_, err := client.VolumeInspect(context.Background(), "nothing") |
| 22 |
- if err == nil || err.Error() != "Error response from daemon: Server error" {
|
|
| 23 |
- t.Fatalf("expected a Server Error, got %v", err)
|
|
| 24 |
- } |
|
| 22 |
+ testutil.ErrorContains(t, err, "Error response from daemon: Server error") |
|
| 25 | 23 |
} |
| 26 | 24 |
|
| 27 | 25 |
func TestVolumeInspectNotFound(t *testing.T) {
|
| ... | ... |
@@ -30,13 +31,34 @@ func TestVolumeInspectNotFound(t *testing.T) {
|
| 30 | 30 |
} |
| 31 | 31 |
|
| 32 | 32 |
_, err := client.VolumeInspect(context.Background(), "unknown") |
| 33 |
- if err == nil || !IsErrVolumeNotFound(err) {
|
|
| 34 |
- t.Fatalf("expected a volumeNotFound error, got %v", err)
|
|
| 33 |
+ assert.True(t, IsErrNotFound(err)) |
|
| 34 |
+} |
|
| 35 |
+ |
|
| 36 |
+func TestVolumeInspectWithEmptyID(t *testing.T) {
|
|
| 37 |
+ expectedURL := "/volumes/" |
|
| 38 |
+ |
|
| 39 |
+ client := &Client{
|
|
| 40 |
+ client: newMockClient(func(req *http.Request) (*http.Response, error) {
|
|
| 41 |
+ assert.Equal(t, req.URL.Path, expectedURL) |
|
| 42 |
+ return &http.Response{
|
|
| 43 |
+ StatusCode: http.StatusNotFound, |
|
| 44 |
+ Body: ioutil.NopCloser(bytes.NewReader(nil)), |
|
| 45 |
+ }, nil |
|
| 46 |
+ }), |
|
| 35 | 47 |
} |
| 48 |
+ _, err := client.VolumeInspect(context.Background(), "") |
|
| 49 |
+ testutil.ErrorContains(t, err, "No such volume: ") |
|
| 50 |
+ |
|
| 36 | 51 |
} |
| 37 | 52 |
|
| 38 | 53 |
func TestVolumeInspect(t *testing.T) {
|
| 39 | 54 |
expectedURL := "/volumes/volume_id" |
| 55 |
+ expected := types.Volume{
|
|
| 56 |
+ Name: "name", |
|
| 57 |
+ Driver: "driver", |
|
| 58 |
+ Mountpoint: "mountpoint", |
|
| 59 |
+ } |
|
| 60 |
+ |
|
| 40 | 61 |
client := &Client{
|
| 41 | 62 |
client: newMockClient(func(req *http.Request) (*http.Response, error) {
|
| 42 | 63 |
if !strings.HasPrefix(req.URL.Path, expectedURL) {
|
| ... | ... |
@@ -45,11 +67,7 @@ func TestVolumeInspect(t *testing.T) {
|
| 45 | 45 |
if req.Method != "GET" {
|
| 46 | 46 |
return nil, fmt.Errorf("expected GET method, got %s", req.Method)
|
| 47 | 47 |
} |
| 48 |
- content, err := json.Marshal(types.Volume{
|
|
| 49 |
- Name: "name", |
|
| 50 |
- Driver: "driver", |
|
| 51 |
- Mountpoint: "mountpoint", |
|
| 52 |
- }) |
|
| 48 |
+ content, err := json.Marshal(expected) |
|
| 53 | 49 |
if err != nil {
|
| 54 | 50 |
return nil, err |
| 55 | 51 |
} |
| ... | ... |
@@ -60,17 +78,7 @@ func TestVolumeInspect(t *testing.T) {
|
| 60 | 60 |
}), |
| 61 | 61 |
} |
| 62 | 62 |
|
| 63 |
- v, err := client.VolumeInspect(context.Background(), "volume_id") |
|
| 64 |
- if err != nil {
|
|
| 65 |
- t.Fatal(err) |
|
| 66 |
- } |
|
| 67 |
- if v.Name != "name" {
|
|
| 68 |
- t.Fatalf("expected `name`, got %s", v.Name)
|
|
| 69 |
- } |
|
| 70 |
- if v.Driver != "driver" {
|
|
| 71 |
- t.Fatalf("expected `driver`, got %s", v.Driver)
|
|
| 72 |
- } |
|
| 73 |
- if v.Mountpoint != "mountpoint" {
|
|
| 74 |
- t.Fatalf("expected `mountpoint`, got %s", v.Mountpoint)
|
|
| 75 |
- } |
|
| 63 |
+ volume, err := client.VolumeInspect(context.Background(), "volume_id") |
|
| 64 |
+ require.NoError(t, err) |
|
| 65 |
+ assert.Equal(t, expected, volume) |
|
| 76 | 66 |
} |