mirror of https://github.com/k3s-io/k3s
Merge pull request #31804 from yujuhong/shim_test2
Automatic merge from submit-queue dockershim: add unit tests for sandbox/container status Part of #31459pull/6/head
commit
d66fde7e4f
|
@ -0,0 +1,154 @@
|
|||
/*
|
||||
Copyright 2016 The Kubernetes Authors.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package dockershim
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
|
||||
runtimeApi "k8s.io/kubernetes/pkg/kubelet/api/v1alpha1/runtime"
|
||||
)
|
||||
|
||||
// A helper to create a basic config.
|
||||
func makeContainerConfig(sConfig *runtimeApi.PodSandboxConfig, name, image string, attempt uint32) *runtimeApi.ContainerConfig {
|
||||
return &runtimeApi.ContainerConfig{
|
||||
Metadata: &runtimeApi.ContainerMetadata{
|
||||
Name: &name,
|
||||
Attempt: &attempt,
|
||||
},
|
||||
Image: &runtimeApi.ImageSpec{Image: &image},
|
||||
}
|
||||
}
|
||||
|
||||
// TestListContainers creates several containers and then list them to check
|
||||
// whether the correct metadatas, states, and labels are returned.
|
||||
func TestListContainers(t *testing.T) {
|
||||
ds, _ := newTestDockerSevice()
|
||||
podName, namespace := "foo", "bar"
|
||||
containerName, image := "sidecar", "logger"
|
||||
|
||||
configs := []*runtimeApi.ContainerConfig{}
|
||||
sConfigs := []*runtimeApi.PodSandboxConfig{}
|
||||
for i := 0; i < 3; i++ {
|
||||
s := makeSandboxConfig(fmt.Sprintf("%s%d", podName, i),
|
||||
fmt.Sprintf("%s%d", namespace, i), fmt.Sprintf("%d", i), 0)
|
||||
c := makeContainerConfig(s, fmt.Sprintf("%s%d", containerName, i),
|
||||
fmt.Sprintf("%s:v%d", image, i), uint32(i))
|
||||
sConfigs = append(sConfigs, s)
|
||||
configs = append(configs, c)
|
||||
}
|
||||
|
||||
expected := []*runtimeApi.Container{}
|
||||
state := runtimeApi.ContainerState_RUNNING
|
||||
for i := range configs {
|
||||
// We don't care about the sandbox id; pass a bogus one.
|
||||
sandboxID := fmt.Sprintf("sandboxid%d", i)
|
||||
id, err := ds.CreateContainer(sandboxID, configs[i], sConfigs[i])
|
||||
assert.NoError(t, err)
|
||||
err = ds.StartContainer(id)
|
||||
assert.NoError(t, err)
|
||||
|
||||
imageRef := "" // FakeDockerClient doesn't populate ImageRef yet.
|
||||
// Prepend to the expected list because ListContainers returns
|
||||
// the most recent containers first.
|
||||
expected = append([]*runtimeApi.Container{{
|
||||
Metadata: configs[i].Metadata,
|
||||
Id: &id,
|
||||
State: &state,
|
||||
Image: configs[i].Image,
|
||||
ImageRef: &imageRef,
|
||||
Labels: map[string]string{containerTypeLabelKey: containerTypeLabelContainer},
|
||||
}}, expected...)
|
||||
}
|
||||
containers, err := ds.ListContainers(nil)
|
||||
assert.NoError(t, err)
|
||||
assert.Len(t, containers, len(expected))
|
||||
assert.Equal(t, expected, containers)
|
||||
}
|
||||
|
||||
// TestContainerStatus tests the basic lifecycle operations and verify that
|
||||
// the status returned reflects the operations performed.
|
||||
func TestContainerStatus(t *testing.T) {
|
||||
ds, fakeDocker := newTestDockerSevice()
|
||||
sConfig := makeSandboxConfig("foo", "bar", "1", 0)
|
||||
config := makeContainerConfig(sConfig, "pause", "iamimage", 0)
|
||||
fClock := fakeDocker.Clock
|
||||
|
||||
var defaultTime time.Time
|
||||
dt := defaultTime.Unix()
|
||||
ct, st, ft := dt, dt, dt
|
||||
state := runtimeApi.ContainerState_CREATED
|
||||
// The following variables are not set in FakeDockerClient.
|
||||
imageRef := ""
|
||||
exitCode := int32(0)
|
||||
reason := ""
|
||||
|
||||
expected := &runtimeApi.ContainerStatus{
|
||||
State: &state,
|
||||
CreatedAt: &ct,
|
||||
StartedAt: &st,
|
||||
FinishedAt: &ft,
|
||||
Metadata: config.Metadata,
|
||||
Image: config.Image,
|
||||
ImageRef: &imageRef,
|
||||
ExitCode: &exitCode,
|
||||
Reason: &reason,
|
||||
Mounts: []*runtimeApi.Mount{},
|
||||
Labels: map[string]string{containerTypeLabelKey: containerTypeLabelContainer},
|
||||
}
|
||||
|
||||
// Create the container.
|
||||
fClock.SetTime(time.Now())
|
||||
*expected.CreatedAt = fClock.Now().Unix()
|
||||
id, err := ds.CreateContainer("sandboxid", config, sConfig)
|
||||
// Set the id manually since we don't know the id until it's created.
|
||||
expected.Id = &id
|
||||
assert.NoError(t, err)
|
||||
status, err := ds.ContainerStatus(id)
|
||||
assert.NoError(t, err)
|
||||
assert.Equal(t, expected, status)
|
||||
|
||||
// Advance the clock and start the container.
|
||||
fClock.SetTime(time.Now())
|
||||
*expected.StartedAt = fClock.Now().Unix()
|
||||
*expected.State = runtimeApi.ContainerState_RUNNING
|
||||
|
||||
err = ds.StartContainer(id)
|
||||
assert.NoError(t, err)
|
||||
status, err = ds.ContainerStatus(id)
|
||||
assert.Equal(t, expected, status)
|
||||
|
||||
// Advance the clock and stop the container.
|
||||
fClock.SetTime(time.Now())
|
||||
*expected.FinishedAt = fClock.Now().Unix()
|
||||
*expected.State = runtimeApi.ContainerState_EXITED
|
||||
*expected.Reason = "Completed"
|
||||
|
||||
err = ds.StopContainer(id, 0)
|
||||
assert.NoError(t, err)
|
||||
status, err = ds.ContainerStatus(id)
|
||||
assert.Equal(t, expected, status)
|
||||
|
||||
// Remove the container.
|
||||
err = ds.RemoveContainer(id)
|
||||
assert.NoError(t, err)
|
||||
status, err = ds.ContainerStatus(id)
|
||||
assert.Error(t, err, fmt.Sprintf("status of container: %+v", status))
|
||||
}
|
|
@ -18,9 +18,10 @@ package dockershim
|
|||
|
||||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
dockertypes "github.com/docker/engine-api/types"
|
||||
"github.com/stretchr/testify/assert"
|
||||
|
||||
runtimeApi "k8s.io/kubernetes/pkg/kubelet/api/v1alpha1/runtime"
|
||||
|
@ -38,23 +39,6 @@ func makeSandboxConfig(name, namespace, uid string, attempt uint32) *runtimeApi.
|
|||
}
|
||||
}
|
||||
|
||||
// TestRunSandbox tests that RunSandbox creates and starts a container
|
||||
// acting a the sandbox for the pod.
|
||||
func TestRunSandbox(t *testing.T) {
|
||||
ds, fakeDocker := newTestDockerSevice()
|
||||
config := makeSandboxConfig("foo", "bar", "1", 0)
|
||||
id, err := ds.RunPodSandbox(config)
|
||||
assert.NoError(t, err)
|
||||
assert.NoError(t, fakeDocker.AssertStarted([]string{id}))
|
||||
|
||||
// List running containers and verify that there is one (and only one)
|
||||
// running container that we just created.
|
||||
containers, err := fakeDocker.ListContainers(dockertypes.ContainerListOptions{All: false})
|
||||
assert.NoError(t, err)
|
||||
assert.Len(t, containers, 1)
|
||||
assert.Equal(t, id, containers[0].ID)
|
||||
}
|
||||
|
||||
// TestListSandboxes creates several sandboxes and then list them to check
|
||||
// whether the correct metadatas, states, and labels are returned.
|
||||
func TestListSandboxes(t *testing.T) {
|
||||
|
@ -88,3 +72,49 @@ func TestListSandboxes(t *testing.T) {
|
|||
assert.Len(t, sandboxes, len(expected))
|
||||
assert.Equal(t, expected, sandboxes)
|
||||
}
|
||||
|
||||
// TestSandboxStatus tests the basic lifecycle operations and verify that
|
||||
// the status returned reflects the operations performed.
|
||||
func TestSandboxStatus(t *testing.T) {
|
||||
ds, fakeDocker := newTestDockerSevice()
|
||||
fClock := fakeDocker.Clock
|
||||
config := makeSandboxConfig("foo", "bar", "1", 0)
|
||||
|
||||
// TODO: The following variables depend on the internal
|
||||
// implementation of FakeDockerClient, and should be fixed.
|
||||
fakeIP := "2.3.4.5"
|
||||
fakeNS := fmt.Sprintf("/proc/%d/ns/net", os.Getpid())
|
||||
|
||||
state := runtimeApi.PodSandBoxState_READY
|
||||
ct := int64(0)
|
||||
expected := &runtimeApi.PodSandboxStatus{
|
||||
State: &state,
|
||||
CreatedAt: &ct,
|
||||
Metadata: config.Metadata,
|
||||
Labels: map[string]string{containerTypeLabelKey: containerTypeLabelSandbox},
|
||||
Network: &runtimeApi.PodSandboxNetworkStatus{Ip: &fakeIP},
|
||||
Linux: &runtimeApi.LinuxPodSandboxStatus{Namespaces: &runtimeApi.Namespace{Network: &fakeNS}},
|
||||
}
|
||||
|
||||
// Create the sandbox.
|
||||
fClock.SetTime(time.Now())
|
||||
*expected.CreatedAt = fClock.Now().Unix()
|
||||
id, err := ds.RunPodSandbox(config)
|
||||
expected.Id = &id // ID is only known after the creation.
|
||||
status, err := ds.PodSandboxStatus(id)
|
||||
assert.NoError(t, err)
|
||||
assert.Equal(t, expected, status)
|
||||
|
||||
// Stop the sandbox.
|
||||
*expected.State = runtimeApi.PodSandBoxState_NOTREADY
|
||||
err = ds.StopPodSandbox(id)
|
||||
assert.NoError(t, err)
|
||||
status, err = ds.PodSandboxStatus(id)
|
||||
assert.Equal(t, expected, status)
|
||||
|
||||
// Remove the container.
|
||||
err = ds.RemovePodSandbox(id)
|
||||
assert.NoError(t, err)
|
||||
status, err = ds.PodSandboxStatus(id)
|
||||
assert.Error(t, err, fmt.Sprintf("status of sandbox: %+v", status))
|
||||
}
|
||||
|
|
|
@ -28,6 +28,7 @@ import (
|
|||
|
||||
dockertypes "github.com/docker/engine-api/types"
|
||||
dockercontainer "github.com/docker/engine-api/types/container"
|
||||
"k8s.io/kubernetes/pkg/util/clock"
|
||||
|
||||
"k8s.io/kubernetes/pkg/api"
|
||||
)
|
||||
|
@ -40,6 +41,7 @@ type calledDetail struct {
|
|||
// FakeDockerClient is a simple fake docker client, so that kubelet can be run for testing without requiring a real docker setup.
|
||||
type FakeDockerClient struct {
|
||||
sync.Mutex
|
||||
Clock *clock.FakeClock
|
||||
RunningContainerList []dockertypes.Container
|
||||
ExitedContainerList []dockertypes.Container
|
||||
ContainerMap map[string]*dockertypes.ContainerJSON
|
||||
|
@ -75,6 +77,7 @@ func NewFakeDockerClientWithVersion(version, apiVersion string) *FakeDockerClien
|
|||
VersionInfo: dockertypes.Version{Version: version, APIVersion: apiVersion},
|
||||
Errors: make(map[string]error),
|
||||
ContainerMap: make(map[string]*dockertypes.ContainerJSON),
|
||||
Clock: clock.NewFakeClock(time.Time{}),
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -292,7 +295,11 @@ func (f *FakeDockerClient) InspectContainer(id string) (*dockertypes.ContainerJS
|
|||
if container, ok := f.ContainerMap[id]; ok {
|
||||
return container, err
|
||||
}
|
||||
return nil, err
|
||||
if err != nil {
|
||||
// Use the custom error if it exists.
|
||||
return nil, err
|
||||
}
|
||||
return nil, fmt.Errorf("container %q not found", id)
|
||||
}
|
||||
|
||||
// InspectImage is a test-spy implementation of DockerInterface.InspectImage.
|
||||
|
@ -337,7 +344,8 @@ func (f *FakeDockerClient) CreateContainer(c dockertypes.ContainerCreateConfig)
|
|||
f.RunningContainerList = append([]dockertypes.Container{
|
||||
{ID: name, Names: []string{name}, Image: c.Config.Image, Labels: c.Config.Labels},
|
||||
}, f.RunningContainerList...)
|
||||
f.ContainerMap[name] = convertFakeContainer(&FakeContainer{ID: id, Name: name, Config: c.Config, HostConfig: c.HostConfig})
|
||||
f.ContainerMap[name] = convertFakeContainer(&FakeContainer{
|
||||
ID: id, Name: name, Config: c.Config, HostConfig: c.HostConfig, CreatedAt: f.Clock.Now()})
|
||||
f.normalSleep(100, 25, 25)
|
||||
return &dockertypes.ContainerCreateResponse{ID: id}, nil
|
||||
}
|
||||
|
@ -358,7 +366,7 @@ func (f *FakeDockerClient) StartContainer(id string) error {
|
|||
}
|
||||
container.State.Running = true
|
||||
container.State.Pid = os.Getpid()
|
||||
container.State.StartedAt = dockerTimestampToString(time.Now())
|
||||
container.State.StartedAt = dockerTimestampToString(f.Clock.Now())
|
||||
container.NetworkSettings.IPAddress = "2.3.4.5"
|
||||
f.ContainerMap[id] = container
|
||||
f.updateContainerStatus(id, statusRunningPrefix)
|
||||
|
@ -398,7 +406,7 @@ func (f *FakeDockerClient) StopContainer(id string, timeout int) error {
|
|||
FinishedAt: time.Now(),
|
||||
})
|
||||
} else {
|
||||
container.State.FinishedAt = dockerTimestampToString(time.Now())
|
||||
container.State.FinishedAt = dockerTimestampToString(f.Clock.Now())
|
||||
container.State.Running = false
|
||||
}
|
||||
f.ContainerMap[id] = container
|
||||
|
|
Loading…
Reference in New Issue