mirror of
https://github.com/moby/moby.git
synced 2026-01-11 18:51:37 +00:00
The WithMockClient option was explicitly resetting the client's API version (see [1]), which differs from the regular client, which is initialized with the current API version used by the client (see [2]). This patch: - reduces the `WithMockClient` to only set the custom HTTP client, leaving other fields un-touched. - adds a test utility and updates tests to handle the API-version prefix - removes redundant uses of `WithVersion()` in tests; for most test-cases it was used to make sure a current API version is used that supports the feature being tested, but there was no test to verify the behavior for lower API versions, so we may as well test against "latest". [1]:5a582729d8/client/client_mock_test.go (L22-L36)[2]:5a582729d8/client/client.go (L167-L190)Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
187 lines
5.7 KiB
Go
187 lines
5.7 KiB
Go
package client
|
|
|
|
import (
|
|
"bytes"
|
|
"context"
|
|
"encoding/json"
|
|
"fmt"
|
|
"io"
|
|
"net/http"
|
|
"testing"
|
|
|
|
cerrdefs "github.com/containerd/errdefs"
|
|
"github.com/moby/moby/api/types/container"
|
|
"gotest.tools/v3/assert"
|
|
is "gotest.tools/v3/assert/cmp"
|
|
)
|
|
|
|
func TestContainerCreateError(t *testing.T) {
|
|
client, err := NewClientWithOpts(
|
|
WithMockClient(errorMock(http.StatusInternalServerError, "Server error")),
|
|
)
|
|
assert.NilError(t, err)
|
|
|
|
_, err = client.ContainerCreate(context.Background(), nil, nil, nil, nil, "nothing")
|
|
assert.Error(t, err, "config is nil")
|
|
assert.Check(t, is.ErrorType(err, cerrdefs.IsInvalidArgument))
|
|
|
|
_, err = client.ContainerCreate(context.Background(), &container.Config{}, nil, nil, nil, "nothing")
|
|
assert.Check(t, is.ErrorType(err, cerrdefs.IsInternal))
|
|
|
|
// 404 doesn't automatically means an unknown image
|
|
client, err = NewClientWithOpts(
|
|
WithMockClient(errorMock(http.StatusNotFound, "Server error")),
|
|
)
|
|
assert.NilError(t, err)
|
|
|
|
_, err = client.ContainerCreate(context.Background(), &container.Config{}, nil, nil, nil, "nothing")
|
|
assert.Check(t, is.ErrorType(err, cerrdefs.IsNotFound))
|
|
}
|
|
|
|
func TestContainerCreateImageNotFound(t *testing.T) {
|
|
client, err := NewClientWithOpts(
|
|
WithMockClient(errorMock(http.StatusNotFound, "No such image")),
|
|
)
|
|
assert.NilError(t, err)
|
|
|
|
_, err = client.ContainerCreate(context.Background(), &container.Config{Image: "unknown_image"}, nil, nil, nil, "unknown")
|
|
assert.Check(t, is.ErrorType(err, cerrdefs.IsNotFound))
|
|
}
|
|
|
|
func TestContainerCreateWithName(t *testing.T) {
|
|
const expectedURL = "/containers/create"
|
|
client, err := NewClientWithOpts(
|
|
WithMockClient(func(req *http.Request) (*http.Response, error) {
|
|
if err := assertRequest(req, http.MethodPost, expectedURL); err != nil {
|
|
return nil, err
|
|
}
|
|
name := req.URL.Query().Get("name")
|
|
if name != "container_name" {
|
|
return nil, fmt.Errorf("container name not set in URL query properly. Expected `container_name`, got %s", name)
|
|
}
|
|
b, err := json.Marshal(container.CreateResponse{
|
|
ID: "container_id",
|
|
})
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
return &http.Response{
|
|
StatusCode: http.StatusOK,
|
|
Body: io.NopCloser(bytes.NewReader(b)),
|
|
}, nil
|
|
}),
|
|
)
|
|
assert.NilError(t, err)
|
|
|
|
r, err := client.ContainerCreate(context.Background(), &container.Config{}, nil, nil, nil, "container_name")
|
|
assert.NilError(t, err)
|
|
assert.Check(t, is.Equal(r.ID, "container_id"))
|
|
}
|
|
|
|
// TestContainerCreateAutoRemove validates that a client using API 1.24 always disables AutoRemove. When using API 1.25
|
|
// or up, AutoRemove should not be disabled.
|
|
func TestContainerCreateAutoRemove(t *testing.T) {
|
|
autoRemoveValidator := func(expectedValue bool) func(req *http.Request) (*http.Response, error) {
|
|
return func(req *http.Request) (*http.Response, error) {
|
|
var config container.CreateRequest
|
|
|
|
if err := json.NewDecoder(req.Body).Decode(&config); err != nil {
|
|
return nil, err
|
|
}
|
|
if config.HostConfig.AutoRemove != expectedValue {
|
|
return nil, fmt.Errorf("expected AutoRemove to be %v, got %v", expectedValue, config.HostConfig.AutoRemove)
|
|
}
|
|
b, err := json.Marshal(container.CreateResponse{
|
|
ID: "container_id",
|
|
})
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
return &http.Response{
|
|
StatusCode: http.StatusOK,
|
|
Body: io.NopCloser(bytes.NewReader(b)),
|
|
}, nil
|
|
}
|
|
}
|
|
testCases := []struct {
|
|
version string
|
|
expectedAutoRemove bool
|
|
}{
|
|
{version: "1.24", expectedAutoRemove: false},
|
|
{version: "1.25", expectedAutoRemove: true},
|
|
}
|
|
for _, tc := range testCases {
|
|
t.Run(tc.version, func(t *testing.T) {
|
|
client, err := NewClientWithOpts(
|
|
WithMockClient(autoRemoveValidator(tc.expectedAutoRemove)),
|
|
WithVersion(tc.version),
|
|
)
|
|
assert.NilError(t, err)
|
|
|
|
_, err = client.ContainerCreate(context.Background(), &container.Config{}, &container.HostConfig{AutoRemove: true}, nil, nil, "")
|
|
assert.NilError(t, err)
|
|
})
|
|
}
|
|
}
|
|
|
|
// TestContainerCreateConnectionError verifies that connection errors occurring
|
|
// during API-version negotiation are not shadowed by API-version errors.
|
|
//
|
|
// Regression test for https://github.com/docker/cli/issues/4890
|
|
func TestContainerCreateConnectionError(t *testing.T) {
|
|
client, err := NewClientWithOpts(WithAPIVersionNegotiation(), WithHost("tcp://no-such-host.invalid"))
|
|
assert.NilError(t, err)
|
|
|
|
_, err = client.ContainerCreate(context.Background(), &container.Config{}, nil, nil, nil, "")
|
|
assert.Check(t, is.ErrorType(err, IsErrConnectionFailed))
|
|
}
|
|
|
|
// TestContainerCreateCapabilities verifies that CapAdd and CapDrop capabilities
|
|
// are normalized to their canonical form.
|
|
func TestContainerCreateCapabilities(t *testing.T) {
|
|
inputCaps := []string{
|
|
"all",
|
|
"ALL",
|
|
"capability_b",
|
|
"capability_a",
|
|
"capability_c",
|
|
"CAPABILITY_D",
|
|
"CAP_CAPABILITY_D",
|
|
}
|
|
|
|
expectedCaps := []string{
|
|
"ALL",
|
|
"CAP_CAPABILITY_A",
|
|
"CAP_CAPABILITY_B",
|
|
"CAP_CAPABILITY_C",
|
|
"CAP_CAPABILITY_D",
|
|
}
|
|
|
|
client, err := NewClientWithOpts(
|
|
WithMockClient(func(req *http.Request) (*http.Response, error) {
|
|
var config container.CreateRequest
|
|
|
|
if err := json.NewDecoder(req.Body).Decode(&config); err != nil {
|
|
return nil, err
|
|
}
|
|
assert.Check(t, is.DeepEqual(config.HostConfig.CapAdd, expectedCaps))
|
|
assert.Check(t, is.DeepEqual(config.HostConfig.CapDrop, expectedCaps))
|
|
|
|
b, err := json.Marshal(container.CreateResponse{
|
|
ID: "container_id",
|
|
})
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
return &http.Response{
|
|
StatusCode: http.StatusOK,
|
|
Body: io.NopCloser(bytes.NewReader(b)),
|
|
}, nil
|
|
}),
|
|
)
|
|
assert.NilError(t, err)
|
|
|
|
_, err = client.ContainerCreate(context.Background(), &container.Config{}, &container.HostConfig{CapAdd: inputCaps, CapDrop: inputCaps}, nil, nil, "")
|
|
assert.NilError(t, err)
|
|
}
|