docs/cluster/engine_test.go

547 lines
23 KiB
Go

package cluster
import (
"bytes"
"errors"
"fmt"
"io"
"math"
"testing"
"time"
engineapi "github.com/docker/engine-api/client"
"github.com/docker/engine-api/types"
containertypes "github.com/docker/engine-api/types/container"
"github.com/docker/engine-api/types/events"
"github.com/docker/engine-api/types/filters"
networktypes "github.com/docker/engine-api/types/network"
engineapimock "github.com/docker/swarm/api/mockclient"
engineapinop "github.com/docker/swarm/api/nopclient"
"github.com/samalba/dockerclient"
"github.com/samalba/dockerclient/mockclient"
"github.com/samalba/dockerclient/nopclient"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/mock"
)
type infiniteRead struct{}
func (infiniteRead) Read(p []byte) (n int, err error) {
p = append(p, 1)
return 1, nil
}
var (
mockInfo = types.Info{
ID: "id",
Name: "name",
NCPU: 10,
MemTotal: 20,
Driver: "driver-test",
ExecutionDriver: "execution-driver-test",
KernelVersion: "1.2.3",
OperatingSystem: "golang",
Labels: []string{"foo=bar"},
}
mockVersion = types.Version{
Version: "1.6.2",
}
engOpts = &EngineOpts{
RefreshMinInterval: time.Duration(30) * time.Second,
RefreshMaxInterval: time.Duration(60) * time.Second,
FailureRetry: 3,
}
)
type nopCloser struct {
io.Reader
}
// Close
func (nopCloser) Close() error {
return nil
}
func TestSetEngineState(t *testing.T) {
engine := NewEngine("test", 0, engOpts)
assert.True(t, engine.state == statePending)
engine.setState(stateUnhealthy)
assert.True(t, engine.state == stateUnhealthy)
engine.setState(stateHealthy)
assert.True(t, engine.state == stateHealthy)
}
func TestErrMsg(t *testing.T) {
engine := NewEngine("test", 0, engOpts)
assert.True(t, len(engine.ErrMsg()) == 0)
message := "cannot connect"
engine.setErrMsg(message)
assert.True(t, engine.ErrMsg() == message)
}
func TestCheckConnectionErr(t *testing.T) {
engine := NewEngine("test", 0, engOpts)
engine.setState(stateHealthy)
assert.True(t, engine.failureCount == 0)
err := dockerclient.ErrConnectionRefused
engine.CheckConnectionErr(err)
assert.True(t, len(engine.ErrMsg()) > 0)
assert.True(t, engine.failureCount == 1)
err = engineapi.ErrConnectionFailed
engine.CheckConnectionErr(err)
assert.True(t, engine.failureCount == 2)
err = nil
engine.CheckConnectionErr(err)
assert.True(t, engine.failureCount == 0)
assert.True(t, len(engine.ErrMsg()) == 0)
// Do not accept random error
err = fmt.Errorf("random error")
engine.CheckConnectionErr(err)
assert.True(t, engine.failureCount == 0)
assert.True(t, len(engine.ErrMsg()) == 0)
}
func TestEngineFailureCount(t *testing.T) {
engine := NewEngine("test", 0, engOpts)
engine.setState(stateHealthy)
for i := 0; i < engine.opts.FailureRetry; i++ {
assert.True(t, engine.IsHealthy())
engine.incFailureCount()
}
assert.False(t, engine.IsHealthy())
assert.True(t, engine.failureCount == engine.opts.FailureRetry)
engine.resetFailureCount()
assert.True(t, engine.failureCount == 0)
}
func TestHealthINdicator(t *testing.T) {
engine := NewEngine("test", 0, engOpts)
assert.True(t, engine.state == statePending)
assert.True(t, engine.HealthIndicator() == 0)
engine.setState(stateUnhealthy)
assert.True(t, engine.HealthIndicator() == 0)
engine.setState(stateHealthy)
assert.True(t, engine.HealthIndicator() == 100)
engine.incFailureCount()
assert.True(t, engine.HealthIndicator() == (int64)(100-100/engine.opts.FailureRetry))
}
func TestEngineConnectionFailure(t *testing.T) {
engine := NewEngine("test", 0, engOpts)
assert.False(t, engine.isConnected())
// Always fail.
client := mockclient.NewMockClient()
apiClient := engineapimock.NewMockClient()
apiClient.On("Info", mock.Anything).Return(types.Info{}, errors.New("fail"))
// Connect() should fail
assert.Error(t, engine.ConnectWithClient(client, apiClient))
// isConnected() should return false
nop := nopclient.NewNopClient()
nopAPIClient := engineapinop.NewNopClient()
assert.Error(t, engine.ConnectWithClient(nop, nopAPIClient))
assert.False(t, engine.isConnected())
client.Mock.AssertExpectations(t)
apiClient.Mock.AssertExpectations(t)
}
func TestOutdatedEngine(t *testing.T) {
engine := NewEngine("test", 0, engOpts)
client := mockclient.NewMockClient()
apiClient := engineapimock.NewMockClient()
apiClient.On("Info", mock.Anything).Return(types.Info{}, nil)
assert.Error(t, engine.ConnectWithClient(client, apiClient))
nop := nopclient.NewNopClient()
nopAPIClient := engineapinop.NewNopClient()
assert.Error(t, engine.ConnectWithClient(nop, nopAPIClient))
assert.False(t, engine.isConnected())
client.Mock.AssertExpectations(t)
apiClient.Mock.AssertExpectations(t)
}
func TestEngineCpusMemory(t *testing.T) {
engine := NewEngine("test", 0, engOpts)
engine.setState(stateUnhealthy)
assert.False(t, engine.isConnected())
client := mockclient.NewMockClient()
apiClient := engineapimock.NewMockClient()
apiClient.On("Info", mock.Anything).Return(mockInfo, nil)
apiClient.On("ServerVersion", mock.Anything).Return(mockVersion, nil)
apiClient.On("NetworkList", mock.Anything,
mock.AnythingOfType("NetworkListOptions"),
).Return([]types.NetworkResource{}, nil)
apiClient.On("VolumeList", mock.Anything,
mock.AnythingOfType("Args"),
).Return(types.VolumesListResponse{}, nil)
apiClient.On("ImageList", mock.Anything, mock.AnythingOfType("ImageListOptions")).Return([]types.Image{}, nil)
apiClient.On("ContainerList", mock.Anything, types.ContainerListOptions{All: true, Size: false}).Return([]types.Container{}, nil)
apiClient.On("Events", mock.Anything, mock.AnythingOfType("EventsOptions")).Return(&nopCloser{infiniteRead{}}, nil)
assert.NoError(t, engine.ConnectWithClient(client, apiClient))
assert.True(t, engine.isConnected())
assert.True(t, engine.IsHealthy())
assert.Equal(t, engine.UsedCpus(), int64(0))
assert.Equal(t, engine.UsedMemory(), int64(0))
client.Mock.AssertExpectations(t)
apiClient.Mock.AssertExpectations(t)
}
func TestEngineSpecs(t *testing.T) {
engine := NewEngine("test", 0, engOpts)
engine.setState(stateUnhealthy)
assert.False(t, engine.isConnected())
client := mockclient.NewMockClient()
apiClient := engineapimock.NewMockClient()
apiClient.On("Info", mock.Anything).Return(mockInfo, nil)
apiClient.On("ServerVersion", mock.Anything).Return(mockVersion, nil)
apiClient.On("NetworkList", mock.Anything,
mock.AnythingOfType("NetworkListOptions"),
).Return([]types.NetworkResource{}, nil)
apiClient.On("VolumeList", mock.Anything,
mock.AnythingOfType("Args"),
).Return(types.VolumesListResponse{}, nil)
apiClient.On("ImageList", mock.Anything, mock.AnythingOfType("ImageListOptions")).Return([]types.Image{}, nil)
apiClient.On("ContainerList", mock.Anything, types.ContainerListOptions{All: true, Size: false}).Return([]types.Container{}, nil)
apiClient.On("Events", mock.Anything, mock.AnythingOfType("EventsOptions")).Return(&nopCloser{infiniteRead{}}, nil)
assert.NoError(t, engine.ConnectWithClient(client, apiClient))
assert.True(t, engine.isConnected())
assert.True(t, engine.IsHealthy())
assert.Equal(t, engine.Cpus, int64(mockInfo.NCPU))
assert.Equal(t, engine.Memory, mockInfo.MemTotal)
assert.Equal(t, engine.Labels["storagedriver"], mockInfo.Driver)
assert.Equal(t, engine.Labels["executiondriver"], mockInfo.ExecutionDriver)
assert.Equal(t, engine.Labels["kernelversion"], mockInfo.KernelVersion)
assert.Equal(t, engine.Labels["operatingsystem"], mockInfo.OperatingSystem)
assert.Equal(t, engine.Labels["foo"], "bar")
client.Mock.AssertExpectations(t)
apiClient.Mock.AssertExpectations(t)
}
func TestEngineState(t *testing.T) {
engine := NewEngine("test", 0, engOpts)
engine.setState(stateUnhealthy)
assert.False(t, engine.isConnected())
client := mockclient.NewMockClient()
apiClient := engineapimock.NewMockClient()
apiClient.On("Info", mock.Anything).Return(mockInfo, nil)
apiClient.On("ServerVersion", mock.Anything).Return(mockVersion, nil)
apiClient.On("NetworkList", mock.Anything,
mock.AnythingOfType("NetworkListOptions"),
).Return([]types.NetworkResource{}, nil)
apiClient.On("VolumeList", mock.Anything,
mock.AnythingOfType("Args"),
).Return(types.VolumesListResponse{}, nil)
apiClient.On("Events", mock.Anything, mock.AnythingOfType("EventsOptions")).Return(&nopCloser{infiniteRead{}}, nil)
// The client will return one container at first, then a second one will appear.
apiClient.On("ImageList", mock.Anything, mock.AnythingOfType("ImageListOptions")).Return([]types.Image{}, nil).Once()
apiClient.On("ContainerList", mock.Anything, types.ContainerListOptions{All: true, Size: false}).Return([]types.Container{{ID: "one"}}, nil).Once()
apiClient.On("ContainerInspect", mock.Anything, "one").Return(types.ContainerJSON{ContainerJSONBase: &types.ContainerJSONBase{HostConfig: &containertypes.HostConfig{Resources: containertypes.Resources{CPUShares: 100}}}, Config: &containertypes.Config{}, NetworkSettings: &types.NetworkSettings{Networks: nil}}, nil).Once()
filterArgs := filters.NewArgs()
filterArgs.Add("id", "two")
apiClient.On("ContainerList", mock.Anything, types.ContainerListOptions{All: true, Size: false, Filter: filterArgs}).Return([]types.Container{{ID: "two"}}, nil).Once()
apiClient.On("ContainerInspect", mock.Anything, "two").Return(types.ContainerJSON{ContainerJSONBase: &types.ContainerJSONBase{HostConfig: &containertypes.HostConfig{Resources: containertypes.Resources{CPUShares: 100}}}, Config: &containertypes.Config{}, NetworkSettings: &types.NetworkSettings{Networks: nil}}, nil).Once()
assert.NoError(t, engine.ConnectWithClient(client, apiClient))
assert.True(t, engine.isConnected())
// The engine should only have a single container at this point.
containers := engine.Containers()
assert.Len(t, containers, 1)
if containers[0].ID != "one" {
t.Fatalf("Missing container: one")
}
// Fake an event which will trigger a refresh. The second container will appear.
engine.handler(events.Message{ID: "two", Status: "created"})
containers = engine.Containers()
assert.Len(t, containers, 2)
if containers[0].ID != "one" && containers[1].ID != "one" {
t.Fatalf("Missing container: one")
}
if containers[0].ID != "two" && containers[1].ID != "two" {
t.Fatalf("Missing container: two")
}
client.Mock.AssertExpectations(t)
apiClient.Mock.AssertExpectations(t)
}
func TestCreateContainer(t *testing.T) {
var (
config = &ContainerConfig{containertypes.Config{
Image: "busybox",
Cmd: []string{"date"},
Tty: false,
}, containertypes.HostConfig{
Resources: containertypes.Resources{
CPUShares: 1,
},
}, networktypes.NetworkingConfig{}}
engine = NewEngine("test", 0, engOpts)
client = mockclient.NewMockClient()
apiClient = engineapimock.NewMockClient()
readCloser = nopCloser{bytes.NewBufferString("")}
)
engine.setState(stateUnhealthy)
apiClient.On("Info", mock.Anything).Return(mockInfo, nil)
apiClient.On("ServerVersion", mock.Anything).Return(mockVersion, nil)
apiClient.On("NetworkList", mock.Anything,
mock.AnythingOfType("NetworkListOptions"),
).Return([]types.NetworkResource{}, nil)
apiClient.On("VolumeList", mock.Anything,
mock.AnythingOfType("Args"),
).Return(types.VolumesListResponse{}, nil)
apiClient.On("Events", mock.Anything, mock.AnythingOfType("EventsOptions")).Return(&nopCloser{infiniteRead{}}, nil)
client.On("ListContainers", true, false, "").Return([]dockerclient.Container{}, nil).Once()
apiClient.On("ImageList", mock.Anything, mock.AnythingOfType("ImageListOptions")).Return([]types.Image{}, nil).Once()
// filterArgs1 := filters.NewArgs()
// filterArgs1.Add("id", id)
apiClient.On("ContainerList", mock.Anything, types.ContainerListOptions{All: true, Size: false}).Return([]types.Container{}, nil).Once()
assert.NoError(t, engine.ConnectWithClient(client, apiClient))
assert.True(t, engine.isConnected())
mockConfig := *config
mockConfig.HostConfig.CPUShares = int64(math.Ceil(float64(config.HostConfig.CPUShares*1024) / float64(mockInfo.NCPU)))
// Everything is ok
name := "test1"
id := "id1"
apiClient.On("ImageList", mock.Anything, mock.AnythingOfType("ImageListOptions")).Return([]types.Image{}, nil).Once()
var auth *types.AuthConfig
apiClient.On("ContainerCreate", mock.Anything, &mockConfig.Config, &mockConfig.HostConfig, &mockConfig.NetworkingConfig, name).Return(types.ContainerCreateResponse{ID: id}, nil).Once()
filterArgs := filters.NewArgs()
filterArgs.Add("id", id)
apiClient.On("ContainerList", mock.Anything, types.ContainerListOptions{All: true, Size: false, Filter: filterArgs}).Return([]types.Container{{ID: id}}, nil).Once()
apiClient.On("ContainerInspect", mock.Anything, id).Return(types.ContainerJSON{Config: &config.Config, ContainerJSONBase: &types.ContainerJSONBase{HostConfig: &config.HostConfig}, NetworkSettings: &types.NetworkSettings{Networks: nil}}, nil).Once()
container, err := engine.Create(config, name, false, auth)
assert.Nil(t, err)
assert.Equal(t, container.ID, id)
assert.Len(t, engine.Containers(), 1)
// Image not found, pullImage == false
name = "test2"
mockConfig.HostConfig.CPUShares = int64(math.Ceil(float64(config.HostConfig.CPUShares*1024) / float64(mockInfo.NCPU)))
// FIXMEENGINEAPI : below should return an engine-api error, or something custom
apiClient.On("ContainerCreate", mock.Anything, &mockConfig.Config, &mockConfig.HostConfig, &mockConfig.NetworkingConfig, name).Return(types.ContainerCreateResponse{}, dockerclient.ErrImageNotFound).Once()
container, err = engine.Create(config, name, false, auth)
assert.Equal(t, err, dockerclient.ErrImageNotFound)
assert.Nil(t, container)
// Image not found, pullImage == true, and the image can be pulled successfully
name = "test3"
id = "id3"
apiClient.On("ImageList", mock.Anything, mock.AnythingOfType("ImageListOptions")).Return([]types.Image{}, nil).Once()
mockConfig.HostConfig.CPUShares = int64(math.Ceil(float64(config.HostConfig.CPUShares*1024) / float64(mockInfo.NCPU)))
apiClient.On("ImagePull", mock.Anything, config.Image, mock.AnythingOfType("types.ImagePullOptions")).Return(readCloser, nil).Once()
// TODO(nishanttotla): below should return an engine-api error, or something custom, so that we can get rid of dockerclient
apiClient.On("ContainerCreate", mock.Anything, &mockConfig.Config, &mockConfig.HostConfig, &mockConfig.NetworkingConfig, name).Return(types.ContainerCreateResponse{}, dockerclient.ErrImageNotFound).Once()
// FIXMEENGINEAPI : below should return an engine-api error, or something custom
apiClient.On("ContainerCreate", mock.Anything, &mockConfig.Config, &mockConfig.HostConfig, &mockConfig.NetworkingConfig, name).Return(types.ContainerCreateResponse{ID: id}, nil).Once()
filterArgs = filters.NewArgs()
filterArgs.Add("id", id)
apiClient.On("ContainerList", mock.Anything, types.ContainerListOptions{All: true, Size: false, Filter: filterArgs}).Return([]types.Container{{ID: id}}, nil).Once()
apiClient.On("ContainerInspect", mock.Anything, id).Return(types.ContainerJSON{Config: &config.Config, ContainerJSONBase: &types.ContainerJSONBase{HostConfig: &config.HostConfig}, NetworkSettings: &types.NetworkSettings{Networks: nil}}, nil).Once()
container, err = engine.Create(config, name, true, auth)
assert.Nil(t, err)
assert.Equal(t, container.ID, id)
assert.Len(t, engine.Containers(), 2)
}
func TestImages(t *testing.T) {
engine := NewEngine("test", 0, engOpts)
engine.setState(stateHealthy)
engine.images = []*Image{
{types.Image{ID: "a"}, engine},
{types.Image{ID: "b"}, engine},
{types.Image{ID: "c"}, engine},
}
result := engine.Images()
assert.Equal(t, len(result), 3)
}
func TestTotalMemory(t *testing.T) {
engine := NewEngine("test", 0.05, engOpts)
engine.Memory = 1024
assert.Equal(t, engine.TotalMemory(), int64(1024+1024*5/100))
engine = NewEngine("test", 0, engOpts)
engine.Memory = 1024
assert.Equal(t, engine.TotalMemory(), int64(1024))
}
func TestTotalCpus(t *testing.T) {
engine := NewEngine("test", 0.05, engOpts)
engine.Cpus = 2
assert.Equal(t, engine.TotalCpus(), int64(2+2*5/100))
engine = NewEngine("test", 0, engOpts)
engine.Cpus = 2
assert.Equal(t, engine.TotalCpus(), int64(2))
}
func TestUsedCpus(t *testing.T) {
var (
containerNcpu = []int64{1, 2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41, 43, 47}
hostNcpu = []int64{1, 2, 4, 8, 10, 12, 16, 20, 32, 36, 40, 48}
)
engine := NewEngine("test", 0, engOpts)
engine.setState(stateHealthy)
client := mockclient.NewMockClient()
apiClient := engineapimock.NewMockClient()
for _, hn := range hostNcpu {
for _, cn := range containerNcpu {
if cn <= hn {
mockInfo.NCPU = int(hn)
cpuShares := int64(math.Ceil(float64(cn*1024) / float64(mockInfo.NCPU)))
apiClient.On("Info", mock.Anything).Return(mockInfo, nil).Once()
apiClient.On("ServerVersion", mock.Anything).Return(mockVersion, nil)
apiClient.On("NetworkList", mock.Anything,
mock.AnythingOfType("NetworkListOptions"),
).Return([]types.NetworkResource{}, nil)
apiClient.On("VolumeList", mock.Anything,
mock.AnythingOfType("Args"),
).Return(types.VolumesListResponse{}, nil)
apiClient.On("Events", mock.Anything, mock.AnythingOfType("EventsOptions")).Return(&nopCloser{infiniteRead{}}, nil)
apiClient.On("ImageList", mock.Anything, mock.AnythingOfType("ImageListOptions")).Return([]types.Image{}, nil).Once()
apiClient.On("ContainerList", mock.Anything, types.ContainerListOptions{All: true, Size: false}).Return([]types.Container{{ID: "test"}}, nil).Once()
apiClient.On("ContainerInspect", mock.Anything, "test").Return(types.ContainerJSON{ContainerJSONBase: &types.ContainerJSONBase{HostConfig: &containertypes.HostConfig{Resources: containertypes.Resources{CPUShares: cpuShares}}}, Config: &containertypes.Config{}, NetworkSettings: &types.NetworkSettings{Networks: nil}}, nil).Once()
engine.ConnectWithClient(client, apiClient)
assert.Equal(t, engine.Cpus, int64(mockInfo.NCPU))
assert.Equal(t, engine.UsedCpus(), cn)
}
}
}
}
func TestContainerRemovedDuringRefresh(t *testing.T) {
var (
container1 = types.Container{ID: "c1"}
container2 = types.Container{ID: "c2"}
info1 types.ContainerJSON
info2 = types.ContainerJSON{ContainerJSONBase: &types.ContainerJSONBase{HostConfig: &containertypes.HostConfig{Resources: containertypes.Resources{CPUShares: 100}}}, Config: &containertypes.Config{}, NetworkSettings: &types.NetworkSettings{Networks: nil}}
)
engine := NewEngine("test", 0, engOpts)
engine.setState(stateUnhealthy)
assert.False(t, engine.isConnected())
// A container is removed before it can be inspected.
client := mockclient.NewMockClient()
apiClient := engineapimock.NewMockClient()
apiClient.On("Info", mock.Anything).Return(mockInfo, nil)
apiClient.On("ServerVersion", mock.Anything).Return(mockVersion, nil)
apiClient.On("NetworkList", mock.Anything,
mock.AnythingOfType("NetworkListOptions"),
).Return([]types.NetworkResource{}, nil)
apiClient.On("VolumeList", mock.Anything,
mock.AnythingOfType("Args"),
).Return(types.VolumesListResponse{}, nil)
apiClient.On("ImageList", mock.Anything, mock.AnythingOfType("ImageListOptions")).Return([]types.Image{}, nil)
apiClient.On("Events", mock.Anything, mock.AnythingOfType("EventsOptions")).Return(&nopCloser{infiniteRead{}}, nil)
apiClient.On("ContainerList", mock.Anything, types.ContainerListOptions{All: true, Size: false}).Return([]types.Container{container1, container2}, nil)
apiClient.On("ContainerInspect", mock.Anything, "c1").Return(info1, errors.New("Not found"))
apiClient.On("ContainerInspect", mock.Anything, "c2").Return(info2, nil)
assert.NoError(t, engine.ConnectWithClient(client, apiClient))
assert.Nil(t, engine.RefreshContainers(true))
// List of containers is still valid
containers := engine.Containers()
assert.Len(t, containers, 1)
assert.Equal(t, containers[0].ID, "c2")
client.Mock.AssertExpectations(t)
apiClient.Mock.AssertExpectations(t)
}
func TestDisconnect(t *testing.T) {
engine := NewEngine("test", 0, engOpts)
client := mockclient.NewMockClient()
apiClient := engineapimock.NewMockClient()
apiClient.On("Info", mock.Anything).Return(mockInfo, nil)
apiClient.On("ServerVersion", mock.Anything).Return(mockVersion, nil)
apiClient.On("NetworkList", mock.Anything,
mock.AnythingOfType("NetworkListOptions"),
).Return([]types.NetworkResource{}, nil)
apiClient.On("VolumeList", mock.Anything,
mock.AnythingOfType("Args"),
).Return(types.VolumesListResponse{}, nil)
apiClient.On("Events", mock.Anything, mock.AnythingOfType("EventsOptions")).Return(&nopCloser{infiniteRead{}}, nil)
// The client will return one container at first, then a second one will appear.
apiClient.On("ImageList", mock.Anything, mock.AnythingOfType("ImageListOptions")).Return([]types.Image{}, nil)
apiClient.On("ContainerList", mock.Anything, types.ContainerListOptions{All: true, Size: false}).Return([]types.Container{{ID: "one"}}, nil).Once()
apiClient.On("ContainerInspect", mock.Anything, "one").Return(types.ContainerJSON{ContainerJSONBase: &types.ContainerJSONBase{HostConfig: &containertypes.HostConfig{Resources: containertypes.Resources{CPUShares: 100}}}, Config: &containertypes.Config{}, NetworkSettings: &types.NetworkSettings{Networks: nil}}, nil).Once()
filterArgs := filters.NewArgs()
filterArgs.Add("id", "two")
apiClient.On("ContainerList", mock.Anything, types.ContainerListOptions{All: true, Size: false, Filter: filterArgs}).Return([]types.Container{{ID: "two"}}, nil).Once()
apiClient.On("ContainerInspect", mock.Anything, "two").Return(types.ContainerJSON{ContainerJSONBase: &types.ContainerJSONBase{HostConfig: &containertypes.HostConfig{Resources: containertypes.Resources{CPUShares: 100}}}, Config: &containertypes.Config{}, NetworkSettings: &types.NetworkSettings{Networks: nil}}, nil).Once()
assert.NoError(t, engine.ConnectWithClient(client, apiClient))
assert.True(t, engine.isConnected())
defer func() {
if r := recover(); r != nil {
t.Errorf("TestDisconnect causes panic")
}
}()
engine.Disconnect()
assert.False(t, engine.isConnected())
assert.True(t, engine.state == stateDisconnected)
// Double disconnect shouldn't cause panic
engine.Disconnect()
}
func TestRemoveImage(t *testing.T) {
engine := NewEngine("test", 0, engOpts)
imageName := "test-image"
dIs := []types.ImageDelete{{Deleted: imageName}}
apiClient := engineapimock.NewMockClient()
apiClient.On("ImageList", mock.Anything, mock.AnythingOfType("ImageListOptions")).Return([]types.Image{}, nil)
apiClient.On("ImageRemove", mock.Anything, mock.Anything,
mock.AnythingOfType("ImageRemoveOptions")).Return(dIs, nil)
engine.apiClient = apiClient
deletedImages, err := engine.RemoveImage("test-image", true)
if err != nil {
t.Errorf("encountered an unexpected error")
}
if deletedImages[0].Deleted != imageName {
t.Errorf("didn't get the image we removed")
}
apiClient.Mock.AssertExpectations(t)
}