Add integration test
Signed-off-by: Lantao Liu <lantaol@google.com>
This commit is contained in:
parent
db68300a5a
commit
6905460b85
148
integration/containerd_image_test.go
Normal file
148
integration/containerd_image_test.go
Normal file
@ -0,0 +1,148 @@
|
|||||||
|
/*
|
||||||
|
Copyright 2018 The containerd 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 integration
|
||||||
|
|
||||||
|
import (
|
||||||
|
"golang.org/x/net/context"
|
||||||
|
"testing"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/containerd/containerd"
|
||||||
|
"github.com/containerd/containerd/errdefs"
|
||||||
|
"github.com/pkg/errors"
|
||||||
|
"github.com/stretchr/testify/assert"
|
||||||
|
"github.com/stretchr/testify/require"
|
||||||
|
runtime "k8s.io/kubernetes/pkg/kubelet/apis/cri/runtime/v1alpha2"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Test to test the CRI plugin should see image pulled into containerd directly.
|
||||||
|
func TestContainerdImage(t *testing.T) {
|
||||||
|
testImage := "docker.io/library/busybox:latest"
|
||||||
|
ctx := context.Background()
|
||||||
|
|
||||||
|
t.Logf("make sure the test image doesn't exist in the cri plugin")
|
||||||
|
i, err := imageService.ImageStatus(&runtime.ImageSpec{Image: testImage})
|
||||||
|
require.NoError(t, err)
|
||||||
|
if i != nil {
|
||||||
|
require.NoError(t, imageService.RemoveImage(&runtime.ImageSpec{Image: testImage}))
|
||||||
|
}
|
||||||
|
|
||||||
|
t.Logf("pull the image into containerd")
|
||||||
|
_, err = containerdClient.Pull(ctx, testImage, containerd.WithPullUnpack)
|
||||||
|
assert.NoError(t, err)
|
||||||
|
defer func() {
|
||||||
|
// Make sure the image is cleaned up in any case.
|
||||||
|
if err := containerdClient.ImageService().Delete(ctx, testImage); err != nil {
|
||||||
|
assert.True(t, errdefs.IsNotFound(err), err)
|
||||||
|
}
|
||||||
|
assert.NoError(t, imageService.RemoveImage(&runtime.ImageSpec{Image: testImage}))
|
||||||
|
}()
|
||||||
|
|
||||||
|
t.Logf("the image should be seen by the cri plugin")
|
||||||
|
var id string
|
||||||
|
checkImage := func() (bool, error) {
|
||||||
|
img, err := imageService.ImageStatus(&runtime.ImageSpec{Image: testImage})
|
||||||
|
if err != nil {
|
||||||
|
return false, err
|
||||||
|
}
|
||||||
|
if img == nil {
|
||||||
|
t.Logf("Image %q not show up in the cri plugin yet", testImage)
|
||||||
|
return false, nil
|
||||||
|
}
|
||||||
|
id = img.Id
|
||||||
|
img, err = imageService.ImageStatus(&runtime.ImageSpec{Image: id})
|
||||||
|
if err != nil {
|
||||||
|
return false, err
|
||||||
|
}
|
||||||
|
if img == nil {
|
||||||
|
// We always generate image id as a reference first, it must
|
||||||
|
// be ready here.
|
||||||
|
return false, errors.New("can't reference image by id")
|
||||||
|
}
|
||||||
|
if len(img.RepoTags) != 1 {
|
||||||
|
// RepoTags must have been populated correctly.
|
||||||
|
return false, errors.Errorf("unexpected repotags: %+v", img.RepoTags)
|
||||||
|
}
|
||||||
|
if img.RepoTags[0] != testImage {
|
||||||
|
return false, errors.Errorf("unexpected repotag %q", img.RepoTags[0])
|
||||||
|
}
|
||||||
|
return true, nil
|
||||||
|
}
|
||||||
|
require.NoError(t, Eventually(checkImage, 100*time.Millisecond, 10*time.Second))
|
||||||
|
require.NoError(t, Consistently(checkImage, 100*time.Millisecond, time.Second))
|
||||||
|
defer func() {
|
||||||
|
t.Logf("image should still be seen by id if only tag get deleted")
|
||||||
|
if err := containerdClient.ImageService().Delete(ctx, testImage); err != nil {
|
||||||
|
assert.True(t, errdefs.IsNotFound(err), err)
|
||||||
|
}
|
||||||
|
assert.NoError(t, Consistently(func() (bool, error) {
|
||||||
|
img, err := imageService.ImageStatus(&runtime.ImageSpec{Image: id})
|
||||||
|
if err != nil {
|
||||||
|
return false, err
|
||||||
|
}
|
||||||
|
return img != nil, nil
|
||||||
|
}, 100*time.Millisecond, time.Second))
|
||||||
|
t.Logf("image should be removed from the cri plugin if all references get deleted")
|
||||||
|
if err := containerdClient.ImageService().Delete(ctx, id); err != nil {
|
||||||
|
assert.True(t, errdefs.IsNotFound(err), err)
|
||||||
|
}
|
||||||
|
assert.NoError(t, Eventually(func() (bool, error) {
|
||||||
|
img, err := imageService.ImageStatus(&runtime.ImageSpec{Image: id})
|
||||||
|
if err != nil {
|
||||||
|
return false, err
|
||||||
|
}
|
||||||
|
return img == nil, nil
|
||||||
|
}, 100*time.Millisecond, 10*time.Second))
|
||||||
|
}()
|
||||||
|
|
||||||
|
t.Logf("the image should be marked as managed")
|
||||||
|
imgByRef, err := containerdClient.GetImage(ctx, testImage)
|
||||||
|
assert.NoError(t, err)
|
||||||
|
assert.Equal(t, imgByRef.Labels()["io.cri-containerd.image"], "managed")
|
||||||
|
|
||||||
|
t.Logf("the image id should be created and managed")
|
||||||
|
imgByID, err := containerdClient.GetImage(ctx, id)
|
||||||
|
assert.NoError(t, err)
|
||||||
|
assert.Equal(t, imgByID.Labels()["io.cri-containerd.image"], "managed")
|
||||||
|
|
||||||
|
t.Logf("should be able to start container with the image")
|
||||||
|
sbConfig := PodSandboxConfig("sandbox", "containerd-image")
|
||||||
|
sb, err := runtimeService.RunPodSandbox(sbConfig)
|
||||||
|
require.NoError(t, err)
|
||||||
|
defer func() {
|
||||||
|
assert.NoError(t, runtimeService.StopPodSandbox(sb))
|
||||||
|
assert.NoError(t, runtimeService.RemovePodSandbox(sb))
|
||||||
|
}()
|
||||||
|
|
||||||
|
cnConfig := ContainerConfig(
|
||||||
|
"test-container",
|
||||||
|
id,
|
||||||
|
WithCommand("top"),
|
||||||
|
)
|
||||||
|
cn, err := runtimeService.CreateContainer(sb, cnConfig, sbConfig)
|
||||||
|
require.NoError(t, err)
|
||||||
|
require.NoError(t, runtimeService.StartContainer(cn))
|
||||||
|
checkContainer := func() (bool, error) {
|
||||||
|
s, err := runtimeService.ContainerStatus(cn)
|
||||||
|
if err != nil {
|
||||||
|
return false, err
|
||||||
|
}
|
||||||
|
return s.GetState() == runtime.ContainerState_CONTAINER_RUNNING, nil
|
||||||
|
}
|
||||||
|
require.NoError(t, Eventually(checkContainer, 100*time.Millisecond, 10*time.Second))
|
||||||
|
require.NoError(t, Consistently(checkContainer, 100*time.Millisecond, time.Second))
|
||||||
|
}
|
@ -17,6 +17,7 @@ limitations under the License.
|
|||||||
package integration
|
package integration
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"sort"
|
||||||
"testing"
|
"testing"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
@ -128,6 +129,17 @@ func TestContainerdRestart(t *testing.T) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
t.Logf("Pull test images")
|
||||||
|
for _, image := range []string{"busybox", "alpine"} {
|
||||||
|
img, err := imageService.PullImage(&runtime.ImageSpec{image}, nil)
|
||||||
|
require.NoError(t, err)
|
||||||
|
defer func() {
|
||||||
|
assert.NoError(t, imageService.RemoveImage(&runtime.ImageSpec{Image: img}))
|
||||||
|
}()
|
||||||
|
}
|
||||||
|
imagesBeforeRestart, err := imageService.ListImages(nil)
|
||||||
|
assert.NoError(t, err)
|
||||||
|
|
||||||
t.Logf("Kill containerd")
|
t.Logf("Kill containerd")
|
||||||
require.NoError(t, KillProcess("containerd"))
|
require.NoError(t, KillProcess("containerd"))
|
||||||
defer func() {
|
defer func() {
|
||||||
@ -179,4 +191,24 @@ func TestContainerdRestart(t *testing.T) {
|
|||||||
assert.NoError(t, runtimeService.StopPodSandbox(s.id))
|
assert.NoError(t, runtimeService.StopPodSandbox(s.id))
|
||||||
assert.NoError(t, runtimeService.RemovePodSandbox(s.id))
|
assert.NoError(t, runtimeService.RemovePodSandbox(s.id))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
t.Logf("Should recover all images")
|
||||||
|
imagesAfterRestart, err := imageService.ListImages(nil)
|
||||||
|
assert.NoError(t, err)
|
||||||
|
assert.Equal(t, len(imagesBeforeRestart), len(imagesAfterRestart))
|
||||||
|
for _, i1 := range imagesBeforeRestart {
|
||||||
|
found := false
|
||||||
|
for _, i2 := range imagesAfterRestart {
|
||||||
|
if i1.Id == i2.Id {
|
||||||
|
sort.Strings(i1.RepoTags)
|
||||||
|
sort.Strings(i1.RepoDigests)
|
||||||
|
sort.Strings(i2.RepoTags)
|
||||||
|
sort.Strings(i2.RepoDigests)
|
||||||
|
assert.Equal(t, i1, i2)
|
||||||
|
found = true
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
assert.True(t, found, "should find image %+v", i1)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -260,6 +260,26 @@ func Eventually(f CheckFunc, period, timeout time.Duration) error {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Consistently makes sure that f consistently returns true without
|
||||||
|
// error before timeout exceeds. If f returns error, Consistently
|
||||||
|
// will return the same error immediately.
|
||||||
|
func Consistently(f CheckFunc, period, timeout time.Duration) error {
|
||||||
|
start := time.Now()
|
||||||
|
for {
|
||||||
|
ok, err := f()
|
||||||
|
if !ok {
|
||||||
|
return errors.New("get false")
|
||||||
|
}
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if time.Since(start) >= timeout {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
time.Sleep(period)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Randomize adds uuid after a string.
|
// Randomize adds uuid after a string.
|
||||||
func Randomize(str string) string {
|
func Randomize(str string) string {
|
||||||
return str + "-" + util.GenerateID()
|
return str + "-" + util.GenerateID()
|
||||||
|
Loading…
Reference in New Issue
Block a user