Add unit test.

Signed-off-by: Lantao Liu <lantaol@google.com>
This commit is contained in:
Lantao Liu 2017-05-27 00:32:07 +00:00
parent eb20601c08
commit 6eb1ddb1f8
3 changed files with 99 additions and 17 deletions

View File

@ -23,20 +23,22 @@ import (
"syscall"
"testing"
"github.com/containerd/containerd/api/services/execution"
rootfsapi "github.com/containerd/containerd/api/services/rootfs"
imagedigest "github.com/opencontainers/go-digest"
imagespec "github.com/opencontainers/image-spec/specs-go/v1"
runtimespec "github.com/opencontainers/runtime-spec/specs-go"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
"golang.org/x/net/context"
runtime "k8s.io/kubernetes/pkg/kubelet/apis/cri/v1alpha1"
"github.com/containerd/containerd/api/services/execution"
runtimespec "github.com/opencontainers/runtime-spec/specs-go"
"github.com/kubernetes-incubator/cri-containerd/pkg/metadata"
ostesting "github.com/kubernetes-incubator/cri-containerd/pkg/os/testing"
servertesting "github.com/kubernetes-incubator/cri-containerd/pkg/server/testing"
runtime "k8s.io/kubernetes/pkg/kubelet/apis/cri/v1alpha1"
)
func getRunPodSandboxTestData() (*runtime.PodSandboxConfig, func(*testing.T, string, *runtimespec.Spec)) {
func getRunPodSandboxTestData() (*runtime.PodSandboxConfig, *imagespec.ImageConfig, func(*testing.T, string, *runtimespec.Spec)) {
config := &runtime.PodSandboxConfig{
Metadata: &runtime.PodSandboxMetadata{
Name: "test-name",
@ -52,20 +54,31 @@ func getRunPodSandboxTestData() (*runtime.PodSandboxConfig, func(*testing.T, str
CgroupParent: "/test/cgroup/parent",
},
}
imageConfig := &imagespec.ImageConfig{
Env: []string{"a=b", "c=d"},
Entrypoint: []string{"/pause"},
Cmd: []string{"forever"},
WorkingDir: "/workspace",
}
specCheck := func(t *testing.T, id string, spec *runtimespec.Spec) {
assert.Equal(t, "test-hostname", spec.Hostname)
assert.Equal(t, getCgroupsPath("/test/cgroup/parent", id), spec.Linux.CgroupsPath)
assert.Equal(t, relativeRootfsPath, spec.Root.Path)
assert.Equal(t, true, spec.Root.Readonly)
assert.Contains(t, spec.Process.Env, "a=b", "c=d")
assert.Equal(t, []string{"/pause", "forever"}, spec.Process.Args)
assert.Equal(t, "/workspace", spec.Process.Cwd)
}
return config, specCheck
return config, imageConfig, specCheck
}
func TestGenerateSandboxContainerSpec(t *testing.T) {
testID := "test-id"
for desc, test := range map[string]struct {
configChange func(*runtime.PodSandboxConfig)
specCheck func(*testing.T, *runtimespec.Spec)
configChange func(*runtime.PodSandboxConfig)
imageConfigChange func(*imagespec.ImageConfig)
specCheck func(*testing.T, *runtimespec.Spec)
expectErr bool
}{
"spec should reflect original config": {
specCheck: func(t *testing.T, spec *runtimespec.Spec) {
@ -106,14 +119,36 @@ func TestGenerateSandboxContainerSpec(t *testing.T) {
})
},
},
"should return error when entrypoint is empty": {
imageConfigChange: func(c *imagespec.ImageConfig) {
c.Entrypoint = nil
},
expectErr: true,
},
"should return error when env is invalid ": {
imageConfigChange: func(c *imagespec.ImageConfig) {
c.Env = []string{"a"}
},
expectErr: true,
},
} {
t.Logf("TestCase %q", desc)
c := newTestCRIContainerdService()
config, specCheck := getRunPodSandboxTestData()
config, imageConfig, specCheck := getRunPodSandboxTestData()
if test.configChange != nil {
test.configChange(config)
}
spec := c.generateSandboxContainerSpec(testID, config)
if test.imageConfigChange != nil {
test.imageConfigChange(imageConfig)
}
spec, err := c.generateSandboxContainerSpec(testID, config, imageConfig)
if test.expectErr {
assert.Error(t, err)
assert.Nil(t, spec)
continue
}
assert.NoError(t, err)
assert.NotNil(t, spec)
specCheck(t, testID, spec)
if test.specCheck != nil {
test.specCheck(t, spec)
@ -122,8 +157,9 @@ func TestGenerateSandboxContainerSpec(t *testing.T) {
}
func TestRunPodSandbox(t *testing.T) {
config, specCheck := getRunPodSandboxTestData()
config, imageConfig, specCheck := getRunPodSandboxTestData()
c := newTestCRIContainerdService()
fakeRootfsClient := c.rootfsService.(*servertesting.FakeRootfsClient)
fakeExecutionClient := c.containerService.(*servertesting.FakeExecutionClient)
fakeCNIPlugin := c.netPlugin.(*servertesting.FakeCNIPlugin)
fakeOS := c.os.(*ostesting.FakeOS)
@ -140,6 +176,17 @@ func TestRunPodSandbox(t *testing.T) {
assert.Equal(t, os.FileMode(0700), perm)
return nopReadWriteCloser{}, nil
}
testChainID := imagedigest.Digest("test-sandbox-chain-id")
imageMetadata := metadata.ImageMetadata{
ID: testSandboxImage,
ChainID: testChainID.String(),
Config: imageConfig,
}
// Insert sandbox image metadata.
assert.NoError(t, c.imageMetadataStore.Create(imageMetadata))
// Insert fake chainID
fakeRootfsClient.SetFakeChainIDs([]imagedigest.Digest{testChainID})
expectRootfsClientCalls := []string{"prepare"}
expectExecutionClientCalls := []string{"create", "start"}
res, err := c.RunPodSandbox(context.Background(), &runtime.RunPodSandboxRequest{Config: config})
@ -155,13 +202,24 @@ func TestRunPodSandbox(t *testing.T) {
assert.Contains(t, pipes, stdout, "sandbox stdout pipe should be created")
assert.Contains(t, pipes, stderr, "sandbox stderr pipe should be created")
assert.Equal(t, expectRootfsClientCalls, fakeRootfsClient.GetCalledNames(), "expect rootfs functions should be called")
calls := fakeRootfsClient.GetCalledDetails()
prepareOpts := calls[0].Argument.(*rootfsapi.PrepareRequest)
assert.Equal(t, &rootfsapi.PrepareRequest{
Name: id,
ChainID: testChainID,
Readonly: true,
}, prepareOpts, "prepare request should be correct")
assert.Equal(t, expectExecutionClientCalls, fakeExecutionClient.GetCalledNames(), "expect containerd functions should be called")
calls := fakeExecutionClient.GetCalledDetails()
calls = fakeExecutionClient.GetCalledDetails()
createOpts := calls[0].Argument.(*execution.CreateRequest)
assert.Equal(t, id, createOpts.ID, "create id should be correct")
// TODO(random-liu): Test rootfs mount when image management part is integrated.
assert.Equal(t, stdout, createOpts.Stdout, "stdout pipe should be passed to containerd")
assert.Equal(t, stderr, createOpts.Stderr, "stderr pipe should be passed to containerd")
mountsResp, err := fakeRootfsClient.Mounts(context.Background(), &rootfsapi.MountsRequest{Name: id})
assert.NoError(t, err)
assert.Equal(t, mountsResp.Mounts, createOpts.Rootfs, "rootfs mount should be correct")
spec := &runtimespec.Spec{}
assert.NoError(t, json.Unmarshal(createOpts.Spec.Value, spec))
t.Logf("oci spec check")

View File

@ -32,6 +32,8 @@ import (
ostesting "github.com/kubernetes-incubator/cri-containerd/pkg/os/testing"
"github.com/kubernetes-incubator/cri-containerd/pkg/registrar"
servertesting "github.com/kubernetes-incubator/cri-containerd/pkg/server/testing"
imagedigest "github.com/opencontainers/go-digest"
imagespec "github.com/opencontainers/image-spec/specs-go/v1"
runtime "k8s.io/kubernetes/pkg/kubelet/apis/cri/v1alpha1"
)
@ -43,20 +45,28 @@ func (nopReadWriteCloser) Read(p []byte) (n int, err error) { return 0, io.EOF
func (nopReadWriteCloser) Write(p []byte) (n int, err error) { return 0, io.ErrShortWrite }
func (nopReadWriteCloser) Close() error { return nil }
const testRootDir = "/test/rootfs"
const (
testRootDir = "/test/rootfs"
// Use an image id as test sandbox image to avoid image name resolve.
// TODO(random-liu): Change this to image name after we have complete image
// management unit test framework.
testSandboxImage = "sha256:c75bebcdd211f41b3a460c7bf82970ed6c75acaab9cd4c9a4e125b03ca113798"
)
// newTestCRIContainerdService creates a fake criContainerdService for test.
func newTestCRIContainerdService() *criContainerdService {
return &criContainerdService{
os: ostesting.NewFakeOS(),
rootDir: testRootDir,
containerService: servertesting.NewFakeExecutionClient(),
sandboxImage: testSandboxImage,
sandboxStore: metadata.NewSandboxStore(store.NewMetadataStore()),
imageMetadataStore: metadata.NewImageMetadataStore(store.NewMetadataStore()),
sandboxNameIndex: registrar.NewRegistrar(),
sandboxIDIndex: truncindex.NewTruncIndex(nil),
containerStore: metadata.NewContainerStore(store.NewMetadataStore()),
containerNameIndex: registrar.NewRegistrar(),
containerService: servertesting.NewFakeExecutionClient(),
rootfsService: servertesting.NewFakeRootfsClient(),
netPlugin: servertesting.NewFakeCNIPlugin(),
}
}
@ -65,11 +75,21 @@ func newTestCRIContainerdService() *criContainerdService {
func TestSandboxOperations(t *testing.T) {
c := newTestCRIContainerdService()
fake := c.containerService.(*servertesting.FakeExecutionClient)
fakeRootfsClient := c.rootfsService.(*servertesting.FakeRootfsClient)
fakeOS := c.os.(*ostesting.FakeOS)
fakeCNIPlugin := c.netPlugin.(*servertesting.FakeCNIPlugin)
fakeOS.OpenFifoFn = func(ctx context.Context, fn string, flag int, perm os.FileMode) (io.ReadWriteCloser, error) {
return nopReadWriteCloser{}, nil
}
// Insert sandbox image metadata.
assert.NoError(t, c.imageMetadataStore.Create(metadata.ImageMetadata{
ID: testSandboxImage,
ChainID: "test-chain-id",
Config: &imagespec.ImageConfig{Entrypoint: []string{"/pause"}},
}))
// Insert fake chainID
fakeRootfsClient.SetFakeChainIDs([]imagedigest.Digest{imagedigest.Digest("test-chain-id")})
config := &runtime.PodSandboxConfig{
Metadata: &runtime.PodSandboxMetadata{
Name: "test-name",

View File

@ -169,7 +169,11 @@ func (f *FakeRootfsClient) Prepare(ctx context.Context, prepareOpts *rootfs.Prep
if ok {
return nil, fmt.Errorf("mounts already exist")
}
f.MountList[prepareOpts.Name] = []*mount.Mount{}
f.MountList[prepareOpts.Name] = []*mount.Mount{{
Type: "bind",
Source: prepareOpts.Name,
// TODO(random-liu): Fake options based on Readonly option.
}}
return &rootfs.MountResponse{
Mounts: f.MountList[prepareOpts.Name],
}, nil