Add unit test.
Signed-off-by: Random-Liu <lantaol@google.com>
This commit is contained in:
parent
bf28c7fc75
commit
e4e9f30c5d
54
pkg/registrar/registrar_test.go
Normal file
54
pkg/registrar/registrar_test.go
Normal file
@ -0,0 +1,54 @@
|
|||||||
|
/*
|
||||||
|
Copyright 2017 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 registrar
|
||||||
|
|
||||||
|
import (
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
assertlib "github.com/stretchr/testify/assert"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestRegistrar(t *testing.T) {
|
||||||
|
r := NewRegistrar()
|
||||||
|
assert := assertlib.New(t)
|
||||||
|
|
||||||
|
t.Logf("should be able to reserve a name<->key mapping")
|
||||||
|
assert.NoError(r.Reserve("test-name-1", "test-id-1"))
|
||||||
|
|
||||||
|
t.Logf("should be able to reserve a new name<->key mapping")
|
||||||
|
assert.NoError(r.Reserve("test-name-2", "test-id-2"))
|
||||||
|
|
||||||
|
t.Logf("should be able to reserve the same name<->key mapping")
|
||||||
|
assert.NoError(r.Reserve("test-name-1", "test-id-1"))
|
||||||
|
|
||||||
|
t.Logf("should not be able to reserve conflict name<->key mapping")
|
||||||
|
assert.Error(r.Reserve("test-name-1", "test-id-conflict"))
|
||||||
|
assert.Error(r.Reserve("test-name-conflict", "test-id-2"))
|
||||||
|
|
||||||
|
t.Logf("should be able to release name<->key mapping by key")
|
||||||
|
r.ReleaseByKey("test-id-1")
|
||||||
|
|
||||||
|
t.Logf("should be able to release name<->key mapping by name")
|
||||||
|
r.ReleaseByName("test-name-2")
|
||||||
|
|
||||||
|
t.Logf("should be able to reserve new name<->key mapping after release")
|
||||||
|
assert.NoError(r.Reserve("test-name-1", "test-id-new"))
|
||||||
|
assert.NoError(r.Reserve("test-name-new", "test-id-2"))
|
||||||
|
|
||||||
|
t.Logf("should be able to reserve same name/key name<->key")
|
||||||
|
assert.NoError(r.Reserve("same-name-id", "same-name-id"))
|
||||||
|
}
|
59
pkg/server/helpers_test.go
Normal file
59
pkg/server/helpers_test.go
Normal file
@ -0,0 +1,59 @@
|
|||||||
|
/*
|
||||||
|
Copyright 2017 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 server
|
||||||
|
|
||||||
|
import (
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"github.com/stretchr/testify/assert"
|
||||||
|
|
||||||
|
"github.com/kubernetes-incubator/cri-containerd/pkg/metadata"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestGetSandbox(t *testing.T) {
|
||||||
|
c := newTestCRIContainerdService()
|
||||||
|
testID := "abcdefg"
|
||||||
|
testSandbox := metadata.SandboxMetadata{
|
||||||
|
ID: testID,
|
||||||
|
Name: "test-name",
|
||||||
|
}
|
||||||
|
assert.NoError(t, c.sandboxStore.Create(testSandbox))
|
||||||
|
assert.NoError(t, c.sandboxIDIndex.Add(testID))
|
||||||
|
|
||||||
|
for desc, test := range map[string]struct {
|
||||||
|
id string
|
||||||
|
expected *metadata.SandboxMetadata
|
||||||
|
}{
|
||||||
|
"full id": {
|
||||||
|
id: testID,
|
||||||
|
expected: &testSandbox,
|
||||||
|
},
|
||||||
|
"partial id": {
|
||||||
|
id: testID[:3],
|
||||||
|
expected: &testSandbox,
|
||||||
|
},
|
||||||
|
"non-exist id": {
|
||||||
|
id: "gfedcba",
|
||||||
|
expected: nil,
|
||||||
|
},
|
||||||
|
} {
|
||||||
|
t.Logf("TestCase %q", desc)
|
||||||
|
sb, err := c.getSandbox(test.id)
|
||||||
|
assert.NoError(t, err)
|
||||||
|
assert.Equal(t, test.expected, sb)
|
||||||
|
}
|
||||||
|
}
|
210
pkg/server/sandbox_list_test.go
Normal file
210
pkg/server/sandbox_list_test.go
Normal file
@ -0,0 +1,210 @@
|
|||||||
|
/*
|
||||||
|
Copyright 2017 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 server
|
||||||
|
|
||||||
|
import (
|
||||||
|
"testing"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/stretchr/testify/assert"
|
||||||
|
"golang.org/x/net/context"
|
||||||
|
|
||||||
|
"github.com/containerd/containerd/api/types/container"
|
||||||
|
|
||||||
|
"k8s.io/kubernetes/pkg/kubelet/api/v1alpha1/runtime"
|
||||||
|
|
||||||
|
"github.com/kubernetes-incubator/cri-containerd/pkg/metadata"
|
||||||
|
servertesting "github.com/kubernetes-incubator/cri-containerd/pkg/server/testing"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestToCRISandbox(t *testing.T) {
|
||||||
|
config := &runtime.PodSandboxConfig{
|
||||||
|
Metadata: &runtime.PodSandboxMetadata{
|
||||||
|
Name: "test-name",
|
||||||
|
Uid: "test-uid",
|
||||||
|
Namespace: "test-ns",
|
||||||
|
Attempt: 1,
|
||||||
|
},
|
||||||
|
Labels: map[string]string{"a": "b"},
|
||||||
|
Annotations: map[string]string{"c": "d"},
|
||||||
|
}
|
||||||
|
createdAt := time.Now().UnixNano()
|
||||||
|
meta := &metadata.SandboxMetadata{
|
||||||
|
ID: "test-id",
|
||||||
|
Name: "test-name",
|
||||||
|
Config: config,
|
||||||
|
CreatedAt: createdAt,
|
||||||
|
NetNS: "test-netns",
|
||||||
|
}
|
||||||
|
state := runtime.PodSandboxState_SANDBOX_READY
|
||||||
|
expect := &runtime.PodSandbox{
|
||||||
|
Id: "test-id",
|
||||||
|
Metadata: config.GetMetadata(),
|
||||||
|
State: state,
|
||||||
|
CreatedAt: createdAt,
|
||||||
|
Labels: config.GetLabels(),
|
||||||
|
Annotations: config.GetAnnotations(),
|
||||||
|
}
|
||||||
|
s := toCRISandbox(meta, state)
|
||||||
|
assert.Equal(t, expect, s)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestFilterSandboxes(t *testing.T) {
|
||||||
|
c := newTestCRIContainerdService()
|
||||||
|
|
||||||
|
testSandboxes := []*runtime.PodSandbox{
|
||||||
|
{
|
||||||
|
Id: "1",
|
||||||
|
Metadata: &runtime.PodSandboxMetadata{Name: "name-1", Uid: "uid-1", Namespace: "ns-1", Attempt: 1},
|
||||||
|
State: runtime.PodSandboxState_SANDBOX_READY,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Id: "2",
|
||||||
|
Metadata: &runtime.PodSandboxMetadata{Name: "name-2", Uid: "uid-2", Namespace: "ns-2", Attempt: 2},
|
||||||
|
State: runtime.PodSandboxState_SANDBOX_NOTREADY,
|
||||||
|
Labels: map[string]string{"a": "b"},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Id: "3",
|
||||||
|
Metadata: &runtime.PodSandboxMetadata{Name: "name-2", Uid: "uid-2", Namespace: "ns-2", Attempt: 2},
|
||||||
|
State: runtime.PodSandboxState_SANDBOX_READY,
|
||||||
|
Labels: map[string]string{"c": "d"},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
for desc, test := range map[string]struct {
|
||||||
|
filter *runtime.PodSandboxFilter
|
||||||
|
expect []*runtime.PodSandbox
|
||||||
|
}{
|
||||||
|
"no filter": {
|
||||||
|
expect: testSandboxes,
|
||||||
|
},
|
||||||
|
"id filter": {
|
||||||
|
filter: &runtime.PodSandboxFilter{Id: "2"},
|
||||||
|
expect: []*runtime.PodSandbox{testSandboxes[1]},
|
||||||
|
},
|
||||||
|
"state filter": {
|
||||||
|
filter: &runtime.PodSandboxFilter{
|
||||||
|
State: &runtime.PodSandboxStateValue{
|
||||||
|
State: runtime.PodSandboxState_SANDBOX_READY,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
expect: []*runtime.PodSandbox{testSandboxes[0], testSandboxes[2]},
|
||||||
|
},
|
||||||
|
"label filter": {
|
||||||
|
filter: &runtime.PodSandboxFilter{
|
||||||
|
LabelSelector: map[string]string{"a": "b"},
|
||||||
|
},
|
||||||
|
expect: []*runtime.PodSandbox{testSandboxes[1]},
|
||||||
|
},
|
||||||
|
"mixed filter not matched": {
|
||||||
|
filter: &runtime.PodSandboxFilter{
|
||||||
|
Id: "1",
|
||||||
|
LabelSelector: map[string]string{"a": "b"},
|
||||||
|
},
|
||||||
|
expect: []*runtime.PodSandbox{},
|
||||||
|
},
|
||||||
|
"mixed filter matched": {
|
||||||
|
filter: &runtime.PodSandboxFilter{
|
||||||
|
State: &runtime.PodSandboxStateValue{
|
||||||
|
State: runtime.PodSandboxState_SANDBOX_READY,
|
||||||
|
},
|
||||||
|
LabelSelector: map[string]string{"c": "d"},
|
||||||
|
},
|
||||||
|
expect: []*runtime.PodSandbox{testSandboxes[2]},
|
||||||
|
},
|
||||||
|
} {
|
||||||
|
filtered := c.filterCRISandboxes(testSandboxes, test.filter)
|
||||||
|
assert.Equal(t, test.expect, filtered, desc)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestListPodSandbox(t *testing.T) {
|
||||||
|
c := newTestCRIContainerdService()
|
||||||
|
|
||||||
|
fake := c.containerService.(*servertesting.FakeExecutionClient)
|
||||||
|
|
||||||
|
sandboxesInStore := []metadata.SandboxMetadata{
|
||||||
|
{
|
||||||
|
ID: "1",
|
||||||
|
Name: "name-1",
|
||||||
|
Config: &runtime.PodSandboxConfig{Metadata: &runtime.PodSandboxMetadata{Name: "name-1"}},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
ID: "2",
|
||||||
|
Name: "name-2",
|
||||||
|
Config: &runtime.PodSandboxConfig{Metadata: &runtime.PodSandboxMetadata{Name: "name-2"}},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
ID: "3",
|
||||||
|
Name: "name-3",
|
||||||
|
Config: &runtime.PodSandboxConfig{Metadata: &runtime.PodSandboxMetadata{Name: "name-3"}},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
sandboxesInContainerd := []container.Container{
|
||||||
|
// Running container with corresponding metadata
|
||||||
|
{
|
||||||
|
ID: "1",
|
||||||
|
Pid: 1,
|
||||||
|
Status: container.Status_RUNNING,
|
||||||
|
},
|
||||||
|
// Stopped container with corresponding metadata
|
||||||
|
{
|
||||||
|
ID: "2",
|
||||||
|
Pid: 2,
|
||||||
|
Status: container.Status_STOPPED,
|
||||||
|
},
|
||||||
|
// Container without corresponding metadata
|
||||||
|
{
|
||||||
|
ID: "4",
|
||||||
|
Pid: 4,
|
||||||
|
Status: container.Status_STOPPED,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
expect := []*runtime.PodSandbox{
|
||||||
|
{
|
||||||
|
Id: "1",
|
||||||
|
Metadata: &runtime.PodSandboxMetadata{Name: "name-1"},
|
||||||
|
State: runtime.PodSandboxState_SANDBOX_READY,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Id: "2",
|
||||||
|
Metadata: &runtime.PodSandboxMetadata{Name: "name-2"},
|
||||||
|
State: runtime.PodSandboxState_SANDBOX_NOTREADY,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Id: "3",
|
||||||
|
Metadata: &runtime.PodSandboxMetadata{Name: "name-3"},
|
||||||
|
State: runtime.PodSandboxState_SANDBOX_NOTREADY,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
// Inject test metadata
|
||||||
|
for _, s := range sandboxesInStore {
|
||||||
|
c.sandboxStore.Create(s)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Inject fake containerd containers
|
||||||
|
fake.SetFakeContainers(sandboxesInContainerd)
|
||||||
|
|
||||||
|
resp, err := c.ListPodSandbox(context.Background(), &runtime.ListPodSandboxRequest{})
|
||||||
|
assert.NoError(t, err)
|
||||||
|
sandboxes := resp.GetItems()
|
||||||
|
assert.Len(t, sandboxes, len(expect))
|
||||||
|
for _, s := range expect {
|
||||||
|
assert.Contains(t, sandboxes, s)
|
||||||
|
}
|
||||||
|
}
|
122
pkg/server/sandbox_remove_test.go
Normal file
122
pkg/server/sandbox_remove_test.go
Normal file
@ -0,0 +1,122 @@
|
|||||||
|
/*
|
||||||
|
Copyright 2017 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 server
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"github.com/stretchr/testify/assert"
|
||||||
|
"golang.org/x/net/context"
|
||||||
|
|
||||||
|
"github.com/containerd/containerd/api/types/container"
|
||||||
|
|
||||||
|
"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"
|
||||||
|
|
||||||
|
"k8s.io/kubernetes/pkg/kubelet/api/v1alpha1/runtime"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestRemovePodSandbox(t *testing.T) {
|
||||||
|
testID := "test-id"
|
||||||
|
testName := "test-name"
|
||||||
|
testMetadata := metadata.SandboxMetadata{
|
||||||
|
ID: testID,
|
||||||
|
Name: testName,
|
||||||
|
}
|
||||||
|
for desc, test := range map[string]struct {
|
||||||
|
sandboxContainers []container.Container
|
||||||
|
injectMetadata bool
|
||||||
|
injectContainerdErr error
|
||||||
|
injectFSErr error
|
||||||
|
expectErr bool
|
||||||
|
expectRemoved string
|
||||||
|
expectCalls []string
|
||||||
|
}{
|
||||||
|
"should not return error if sandbox does not exist": {
|
||||||
|
injectMetadata: false,
|
||||||
|
expectErr: false,
|
||||||
|
expectCalls: []string{},
|
||||||
|
},
|
||||||
|
"should return error when sandbox container is not deleted": {
|
||||||
|
injectMetadata: true,
|
||||||
|
sandboxContainers: []container.Container{{ID: testID}},
|
||||||
|
expectErr: true,
|
||||||
|
expectCalls: []string{"info"},
|
||||||
|
},
|
||||||
|
"should return error when arbitrary containerd error is injected": {
|
||||||
|
injectMetadata: true,
|
||||||
|
injectContainerdErr: fmt.Errorf("arbitrary error"),
|
||||||
|
expectErr: true,
|
||||||
|
expectCalls: []string{"info"},
|
||||||
|
},
|
||||||
|
"should return error when error fs error is injected": {
|
||||||
|
injectMetadata: true,
|
||||||
|
injectFSErr: fmt.Errorf("fs error"),
|
||||||
|
expectRemoved: getSandboxRootDir(testRootDir, testID),
|
||||||
|
expectErr: true,
|
||||||
|
expectCalls: []string{"info"},
|
||||||
|
},
|
||||||
|
"should be able to successfully delete": {
|
||||||
|
injectMetadata: true,
|
||||||
|
expectRemoved: getSandboxRootDir(testRootDir, testID),
|
||||||
|
expectCalls: []string{"info"},
|
||||||
|
},
|
||||||
|
} {
|
||||||
|
t.Logf("TestCase %q", desc)
|
||||||
|
c := newTestCRIContainerdService()
|
||||||
|
fake := c.containerService.(*servertesting.FakeExecutionClient)
|
||||||
|
fakeOS := c.os.(*ostesting.FakeOS)
|
||||||
|
fake.SetFakeContainers(test.sandboxContainers)
|
||||||
|
if test.injectMetadata {
|
||||||
|
c.sandboxNameIndex.Reserve(testName, testID)
|
||||||
|
c.sandboxIDIndex.Add(testID)
|
||||||
|
c.sandboxStore.Create(testMetadata)
|
||||||
|
}
|
||||||
|
if test.injectContainerdErr != nil {
|
||||||
|
fake.InjectError("info", test.injectContainerdErr)
|
||||||
|
}
|
||||||
|
fakeOS.RemoveAllFn = func(path string) error {
|
||||||
|
assert.Equal(t, test.expectRemoved, path)
|
||||||
|
return test.injectFSErr
|
||||||
|
}
|
||||||
|
res, err := c.RemovePodSandbox(context.Background(), &runtime.RemovePodSandboxRequest{
|
||||||
|
PodSandboxId: testID,
|
||||||
|
})
|
||||||
|
assert.Equal(t, test.expectCalls, fake.GetCalledNames())
|
||||||
|
if test.expectErr {
|
||||||
|
assert.Error(t, err)
|
||||||
|
assert.Nil(t, res)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
assert.NoError(t, err)
|
||||||
|
assert.NotNil(t, res)
|
||||||
|
assert.NoError(t, c.sandboxNameIndex.Reserve(testName, testID),
|
||||||
|
"sandbox name should be released")
|
||||||
|
_, err = c.sandboxIDIndex.Get(testID)
|
||||||
|
assert.Error(t, err, "sandbox id should be removed")
|
||||||
|
meta, err := c.sandboxStore.Get(testID)
|
||||||
|
assert.NoError(t, err)
|
||||||
|
assert.Nil(t, meta, "sandbox metadata should be removed")
|
||||||
|
res, err = c.RemovePodSandbox(context.Background(), &runtime.RemovePodSandboxRequest{
|
||||||
|
PodSandboxId: testID,
|
||||||
|
})
|
||||||
|
assert.NoError(t, err)
|
||||||
|
assert.NotNil(t, res, "remove should be idempotent")
|
||||||
|
}
|
||||||
|
}
|
191
pkg/server/sandbox_run_test.go
Normal file
191
pkg/server/sandbox_run_test.go
Normal file
@ -0,0 +1,191 @@
|
|||||||
|
/*
|
||||||
|
Copyright 2017 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 server
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/json"
|
||||||
|
"io"
|
||||||
|
"os"
|
||||||
|
"syscall"
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"github.com/stretchr/testify/assert"
|
||||||
|
"github.com/stretchr/testify/require"
|
||||||
|
"golang.org/x/net/context"
|
||||||
|
|
||||||
|
"github.com/containerd/containerd/api/services/execution"
|
||||||
|
runtimespec "github.com/opencontainers/runtime-spec/specs-go"
|
||||||
|
|
||||||
|
ostesting "github.com/kubernetes-incubator/cri-containerd/pkg/os/testing"
|
||||||
|
servertesting "github.com/kubernetes-incubator/cri-containerd/pkg/server/testing"
|
||||||
|
|
||||||
|
"k8s.io/kubernetes/pkg/kubelet/api/v1alpha1/runtime"
|
||||||
|
)
|
||||||
|
|
||||||
|
func getRunPodSandboxTestData() (*runtime.PodSandboxConfig, func(*testing.T, string, *runtimespec.Spec)) {
|
||||||
|
config := &runtime.PodSandboxConfig{
|
||||||
|
Metadata: &runtime.PodSandboxMetadata{
|
||||||
|
Name: "test-name",
|
||||||
|
Uid: "test-uid",
|
||||||
|
Namespace: "test-ns",
|
||||||
|
Attempt: 1,
|
||||||
|
},
|
||||||
|
Hostname: "test-hostname",
|
||||||
|
LogDirectory: "test-log-directory",
|
||||||
|
Labels: map[string]string{"a": "b"},
|
||||||
|
Annotations: map[string]string{"c": "d"},
|
||||||
|
Linux: &runtime.LinuxPodSandboxConfig{
|
||||||
|
CgroupParent: "/test/cgroup/parent",
|
||||||
|
},
|
||||||
|
}
|
||||||
|
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)
|
||||||
|
}
|
||||||
|
return config, 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)
|
||||||
|
}{
|
||||||
|
"spec should reflect original config": {
|
||||||
|
specCheck: func(t *testing.T, spec *runtimespec.Spec) {
|
||||||
|
// runtime spec should have expected namespaces enabled by default.
|
||||||
|
require.NotNil(t, spec.Linux)
|
||||||
|
assert.Contains(t, spec.Linux.Namespaces, runtimespec.LinuxNamespace{
|
||||||
|
Type: runtimespec.NetworkNamespace,
|
||||||
|
})
|
||||||
|
assert.Contains(t, spec.Linux.Namespaces, runtimespec.LinuxNamespace{
|
||||||
|
Type: runtimespec.PIDNamespace,
|
||||||
|
})
|
||||||
|
assert.Contains(t, spec.Linux.Namespaces, runtimespec.LinuxNamespace{
|
||||||
|
Type: runtimespec.IPCNamespace,
|
||||||
|
})
|
||||||
|
},
|
||||||
|
},
|
||||||
|
"host namespace": {
|
||||||
|
configChange: func(c *runtime.PodSandboxConfig) {
|
||||||
|
c.Linux.SecurityContext = &runtime.LinuxSandboxSecurityContext{
|
||||||
|
NamespaceOptions: &runtime.NamespaceOption{
|
||||||
|
HostNetwork: true,
|
||||||
|
HostPid: true,
|
||||||
|
HostIpc: true,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
},
|
||||||
|
specCheck: func(t *testing.T, spec *runtimespec.Spec) {
|
||||||
|
// runtime spec should disable expected namespaces in host mode.
|
||||||
|
require.NotNil(t, spec.Linux)
|
||||||
|
assert.NotContains(t, spec.Linux.Namespaces, runtimespec.LinuxNamespace{
|
||||||
|
Type: runtimespec.NetworkNamespace,
|
||||||
|
})
|
||||||
|
assert.NotContains(t, spec.Linux.Namespaces, runtimespec.LinuxNamespace{
|
||||||
|
Type: runtimespec.PIDNamespace,
|
||||||
|
})
|
||||||
|
assert.NotContains(t, spec.Linux.Namespaces, runtimespec.LinuxNamespace{
|
||||||
|
Type: runtimespec.IPCNamespace,
|
||||||
|
})
|
||||||
|
},
|
||||||
|
},
|
||||||
|
} {
|
||||||
|
t.Logf("TestCase %q", desc)
|
||||||
|
c := newTestCRIContainerdService()
|
||||||
|
config, specCheck := getRunPodSandboxTestData()
|
||||||
|
if test.configChange != nil {
|
||||||
|
test.configChange(config)
|
||||||
|
}
|
||||||
|
spec := c.generateSandboxContainerSpec(testID, config)
|
||||||
|
specCheck(t, testID, spec)
|
||||||
|
if test.specCheck != nil {
|
||||||
|
test.specCheck(t, spec)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestRunPodSandbox(t *testing.T) {
|
||||||
|
config, specCheck := getRunPodSandboxTestData()
|
||||||
|
c := newTestCRIContainerdService()
|
||||||
|
fake := c.containerService.(*servertesting.FakeExecutionClient)
|
||||||
|
fakeOS := c.os.(*ostesting.FakeOS)
|
||||||
|
var dirs []string
|
||||||
|
var pipes []string
|
||||||
|
fakeOS.MkdirAllFn = func(path string, perm os.FileMode) error {
|
||||||
|
dirs = append(dirs, path)
|
||||||
|
assert.Equal(t, os.FileMode(0755), perm)
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
fakeOS.OpenFifoFn = func(ctx context.Context, fn string, flag int, perm os.FileMode) (io.ReadWriteCloser, error) {
|
||||||
|
pipes = append(pipes, fn)
|
||||||
|
assert.Equal(t, syscall.O_RDONLY|syscall.O_CREAT|syscall.O_NONBLOCK, flag)
|
||||||
|
assert.Equal(t, os.FileMode(0700), perm)
|
||||||
|
return nopReadWriteCloser{}, nil
|
||||||
|
}
|
||||||
|
expectCalls := []string{"create", "start"}
|
||||||
|
|
||||||
|
res, err := c.RunPodSandbox(context.Background(), &runtime.RunPodSandboxRequest{Config: config})
|
||||||
|
assert.NoError(t, err)
|
||||||
|
require.NotNil(t, res)
|
||||||
|
id := res.GetPodSandboxId()
|
||||||
|
|
||||||
|
assert.Len(t, dirs, 1)
|
||||||
|
assert.Equal(t, getSandboxRootDir(c.rootDir, id), dirs[0], "sandbox root directory should be created")
|
||||||
|
|
||||||
|
assert.Len(t, pipes, 2)
|
||||||
|
_, stdout, stderr := getStreamingPipes(getSandboxRootDir(c.rootDir, id))
|
||||||
|
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, expectCalls, fake.GetCalledNames(), "expect containerd functions should be called")
|
||||||
|
calls := fake.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")
|
||||||
|
spec := &runtimespec.Spec{}
|
||||||
|
assert.NoError(t, json.Unmarshal(createOpts.Spec.Value, spec))
|
||||||
|
t.Logf("oci spec check")
|
||||||
|
specCheck(t, id, spec)
|
||||||
|
|
||||||
|
startID := calls[1].Argument.(*execution.StartRequest).ID
|
||||||
|
assert.Equal(t, id, startID, "start id should be correct")
|
||||||
|
|
||||||
|
meta, err := c.sandboxStore.Get(id)
|
||||||
|
assert.NoError(t, err)
|
||||||
|
assert.Equal(t, id, meta.ID, "metadata id should be correct")
|
||||||
|
err = c.sandboxNameIndex.Reserve(meta.Name, "random-id")
|
||||||
|
assert.Error(t, err, "metadata name should be reserved")
|
||||||
|
assert.Equal(t, config, meta.Config, "metadata config should be correct")
|
||||||
|
// TODO(random-liu): [P2] Add clock interface and use fake clock.
|
||||||
|
assert.NotZero(t, meta.CreatedAt, "metadata CreatedAt should be set")
|
||||||
|
info, err := fake.Info(context.Background(), &execution.InfoRequest{ID: id})
|
||||||
|
assert.NoError(t, err)
|
||||||
|
pid := info.Pid
|
||||||
|
assert.Equal(t, meta.NetNS, getNetworkNamespace(pid), "metadata network namespace should be correct")
|
||||||
|
|
||||||
|
gotID, err := c.sandboxIDIndex.Get(id)
|
||||||
|
assert.NoError(t, err)
|
||||||
|
assert.Equal(t, id, gotID, "sandbox id should be indexed")
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO(random-liu): [P1] Add unit test for different error cases to make sure
|
||||||
|
// the function cleans up on error properly.
|
192
pkg/server/sandbox_status_test.go
Normal file
192
pkg/server/sandbox_status_test.go
Normal file
@ -0,0 +1,192 @@
|
|||||||
|
/*
|
||||||
|
Copyright 2017 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 server
|
||||||
|
|
||||||
|
import (
|
||||||
|
"errors"
|
||||||
|
"testing"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/stretchr/testify/assert"
|
||||||
|
"github.com/stretchr/testify/require"
|
||||||
|
"golang.org/x/net/context"
|
||||||
|
|
||||||
|
"github.com/containerd/containerd/api/types/container"
|
||||||
|
|
||||||
|
"k8s.io/kubernetes/pkg/kubelet/api/v1alpha1/runtime"
|
||||||
|
|
||||||
|
"github.com/kubernetes-incubator/cri-containerd/pkg/metadata"
|
||||||
|
servertesting "github.com/kubernetes-incubator/cri-containerd/pkg/server/testing"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Variables used in the following test.
|
||||||
|
|
||||||
|
const sandboxStatusTestID = "test-id"
|
||||||
|
|
||||||
|
func getSandboxStatusTestData() (*metadata.SandboxMetadata, *runtime.PodSandboxStatus) {
|
||||||
|
config := &runtime.PodSandboxConfig{
|
||||||
|
Metadata: &runtime.PodSandboxMetadata{
|
||||||
|
Name: "test-name",
|
||||||
|
Uid: "test-uid",
|
||||||
|
Namespace: "test-ns",
|
||||||
|
Attempt: 1,
|
||||||
|
},
|
||||||
|
Linux: &runtime.LinuxPodSandboxConfig{
|
||||||
|
SecurityContext: &runtime.LinuxSandboxSecurityContext{
|
||||||
|
NamespaceOptions: &runtime.NamespaceOption{
|
||||||
|
HostNetwork: true,
|
||||||
|
HostPid: false,
|
||||||
|
HostIpc: true,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
Labels: map[string]string{"a": "b"},
|
||||||
|
Annotations: map[string]string{"c": "d"},
|
||||||
|
}
|
||||||
|
|
||||||
|
createdAt := time.Now().UnixNano()
|
||||||
|
|
||||||
|
metadata := &metadata.SandboxMetadata{
|
||||||
|
ID: sandboxStatusTestID,
|
||||||
|
Name: "test-name",
|
||||||
|
Config: config,
|
||||||
|
CreatedAt: createdAt,
|
||||||
|
}
|
||||||
|
|
||||||
|
expectedStatus := &runtime.PodSandboxStatus{
|
||||||
|
Id: sandboxStatusTestID,
|
||||||
|
Metadata: config.GetMetadata(),
|
||||||
|
CreatedAt: createdAt,
|
||||||
|
Network: &runtime.PodSandboxNetworkStatus{},
|
||||||
|
Linux: &runtime.LinuxPodSandboxStatus{
|
||||||
|
Namespaces: &runtime.Namespace{
|
||||||
|
Options: &runtime.NamespaceOption{
|
||||||
|
HostNetwork: true,
|
||||||
|
HostPid: false,
|
||||||
|
HostIpc: true,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
Labels: config.GetLabels(),
|
||||||
|
Annotations: config.GetAnnotations(),
|
||||||
|
}
|
||||||
|
|
||||||
|
return metadata, expectedStatus
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestToCRISandboxStatus(t *testing.T) {
|
||||||
|
for desc, test := range map[string]struct {
|
||||||
|
state runtime.PodSandboxState
|
||||||
|
expectNetNS string
|
||||||
|
}{
|
||||||
|
"ready sandbox should have network namespace": {
|
||||||
|
state: runtime.PodSandboxState_SANDBOX_READY,
|
||||||
|
expectNetNS: "test-netns",
|
||||||
|
},
|
||||||
|
"not ready sandbox should not have network namespace": {
|
||||||
|
state: runtime.PodSandboxState_SANDBOX_NOTREADY,
|
||||||
|
expectNetNS: "",
|
||||||
|
},
|
||||||
|
} {
|
||||||
|
metadata, expect := getSandboxStatusTestData()
|
||||||
|
metadata.NetNS = "test-netns"
|
||||||
|
status := toCRISandboxStatus(metadata, test.state)
|
||||||
|
expect.Linux.Namespaces.Network = test.expectNetNS
|
||||||
|
expect.State = test.state
|
||||||
|
assert.Equal(t, expect, status, desc)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestPodSandboxStatus(t *testing.T) {
|
||||||
|
for desc, test := range map[string]struct {
|
||||||
|
sandboxContainers []container.Container
|
||||||
|
injectMetadata bool
|
||||||
|
injectErr error
|
||||||
|
expectState runtime.PodSandboxState
|
||||||
|
expectErr bool
|
||||||
|
expectCalls []string
|
||||||
|
}{
|
||||||
|
"sandbox status without metadata": {
|
||||||
|
injectMetadata: false,
|
||||||
|
expectErr: true,
|
||||||
|
expectCalls: []string{},
|
||||||
|
},
|
||||||
|
"sandbox status with running sandbox container": {
|
||||||
|
sandboxContainers: []container.Container{{
|
||||||
|
ID: sandboxStatusTestID,
|
||||||
|
Pid: 1,
|
||||||
|
Status: container.Status_RUNNING,
|
||||||
|
}},
|
||||||
|
injectMetadata: true,
|
||||||
|
expectState: runtime.PodSandboxState_SANDBOX_READY,
|
||||||
|
expectCalls: []string{"info"},
|
||||||
|
},
|
||||||
|
"sandbox status with stopped sandbox container": {
|
||||||
|
sandboxContainers: []container.Container{{
|
||||||
|
ID: sandboxStatusTestID,
|
||||||
|
Pid: 1,
|
||||||
|
Status: container.Status_STOPPED,
|
||||||
|
}},
|
||||||
|
injectMetadata: true,
|
||||||
|
expectState: runtime.PodSandboxState_SANDBOX_NOTREADY,
|
||||||
|
expectCalls: []string{"info"},
|
||||||
|
},
|
||||||
|
"sandbox status with non-existing sandbox container": {
|
||||||
|
sandboxContainers: []container.Container{},
|
||||||
|
injectMetadata: true,
|
||||||
|
expectState: runtime.PodSandboxState_SANDBOX_NOTREADY,
|
||||||
|
expectCalls: []string{"info"},
|
||||||
|
},
|
||||||
|
"sandbox status with arbitrary error": {
|
||||||
|
sandboxContainers: []container.Container{{
|
||||||
|
ID: sandboxStatusTestID,
|
||||||
|
Pid: 1,
|
||||||
|
Status: container.Status_RUNNING,
|
||||||
|
}},
|
||||||
|
injectMetadata: true,
|
||||||
|
injectErr: errors.New("arbitrary error"),
|
||||||
|
expectErr: true,
|
||||||
|
expectCalls: []string{"info"},
|
||||||
|
},
|
||||||
|
} {
|
||||||
|
t.Logf("TestCase %q", desc)
|
||||||
|
metadata, expect := getSandboxStatusTestData()
|
||||||
|
c := newTestCRIContainerdService()
|
||||||
|
fake := c.containerService.(*servertesting.FakeExecutionClient)
|
||||||
|
fake.SetFakeContainers(test.sandboxContainers)
|
||||||
|
if test.injectMetadata {
|
||||||
|
assert.NoError(t, c.sandboxIDIndex.Add(metadata.ID))
|
||||||
|
assert.NoError(t, c.sandboxStore.Create(*metadata))
|
||||||
|
}
|
||||||
|
if test.injectErr != nil {
|
||||||
|
fake.InjectError("info", test.injectErr)
|
||||||
|
}
|
||||||
|
res, err := c.PodSandboxStatus(context.Background(), &runtime.PodSandboxStatusRequest{
|
||||||
|
PodSandboxId: sandboxStatusTestID,
|
||||||
|
})
|
||||||
|
assert.Equal(t, test.expectCalls, fake.GetCalledNames())
|
||||||
|
if test.expectErr {
|
||||||
|
assert.Error(t, err)
|
||||||
|
assert.Nil(t, res)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
assert.NoError(t, err)
|
||||||
|
require.NotNil(t, res)
|
||||||
|
expect.State = test.expectState
|
||||||
|
assert.Equal(t, expect, res.GetStatus())
|
||||||
|
}
|
||||||
|
}
|
106
pkg/server/sandbox_stop_test.go
Normal file
106
pkg/server/sandbox_stop_test.go
Normal file
@ -0,0 +1,106 @@
|
|||||||
|
/*
|
||||||
|
Copyright 2017 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 server
|
||||||
|
|
||||||
|
import (
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"github.com/stretchr/testify/assert"
|
||||||
|
"golang.org/x/net/context"
|
||||||
|
"google.golang.org/grpc"
|
||||||
|
"google.golang.org/grpc/codes"
|
||||||
|
|
||||||
|
"github.com/containerd/containerd"
|
||||||
|
"github.com/containerd/containerd/api/types/container"
|
||||||
|
|
||||||
|
"k8s.io/kubernetes/pkg/kubelet/api/v1alpha1/runtime"
|
||||||
|
|
||||||
|
"github.com/kubernetes-incubator/cri-containerd/pkg/metadata"
|
||||||
|
servertesting "github.com/kubernetes-incubator/cri-containerd/pkg/server/testing"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestStopPodSandbox(t *testing.T) {
|
||||||
|
testID := "test-id"
|
||||||
|
testSandbox := metadata.SandboxMetadata{
|
||||||
|
ID: testID,
|
||||||
|
Name: "test-name",
|
||||||
|
}
|
||||||
|
testContainer := container.Container{
|
||||||
|
ID: testID,
|
||||||
|
Pid: 1,
|
||||||
|
Status: container.Status_RUNNING,
|
||||||
|
}
|
||||||
|
|
||||||
|
for desc, test := range map[string]struct {
|
||||||
|
sandboxContainers []container.Container
|
||||||
|
injectSandbox bool
|
||||||
|
injectErr error
|
||||||
|
expectErr bool
|
||||||
|
expectCalls []string
|
||||||
|
}{
|
||||||
|
"stop non-existing sandbox": {
|
||||||
|
injectSandbox: false,
|
||||||
|
expectErr: true,
|
||||||
|
expectCalls: []string{},
|
||||||
|
},
|
||||||
|
"stop sandbox with sandbox container": {
|
||||||
|
sandboxContainers: []container.Container{testContainer},
|
||||||
|
injectSandbox: true,
|
||||||
|
expectErr: false,
|
||||||
|
expectCalls: []string{"delete"},
|
||||||
|
},
|
||||||
|
"stop sandbox with sandbox container not exist error": {
|
||||||
|
sandboxContainers: []container.Container{},
|
||||||
|
injectSandbox: true,
|
||||||
|
// Inject error to make sure fake execution client returns error.
|
||||||
|
injectErr: grpc.Errorf(codes.Unknown, containerd.ErrContainerNotExist.Error()),
|
||||||
|
expectErr: false,
|
||||||
|
expectCalls: []string{"delete"},
|
||||||
|
},
|
||||||
|
"stop sandbox with with arbitrary error": {
|
||||||
|
injectSandbox: true,
|
||||||
|
injectErr: grpc.Errorf(codes.Unknown, "arbitrary error"),
|
||||||
|
expectErr: true,
|
||||||
|
expectCalls: []string{"delete"},
|
||||||
|
},
|
||||||
|
} {
|
||||||
|
t.Logf("TestCase %q", desc)
|
||||||
|
c := newTestCRIContainerdService()
|
||||||
|
fake := c.containerService.(*servertesting.FakeExecutionClient)
|
||||||
|
fake.SetFakeContainers(test.sandboxContainers)
|
||||||
|
|
||||||
|
if test.injectSandbox {
|
||||||
|
assert.NoError(t, c.sandboxStore.Create(testSandbox))
|
||||||
|
c.sandboxIDIndex.Add(testID)
|
||||||
|
}
|
||||||
|
if test.injectErr != nil {
|
||||||
|
fake.InjectError("delete", test.injectErr)
|
||||||
|
}
|
||||||
|
|
||||||
|
res, err := c.StopPodSandbox(context.Background(), &runtime.StopPodSandboxRequest{
|
||||||
|
PodSandboxId: testID,
|
||||||
|
})
|
||||||
|
if test.expectErr {
|
||||||
|
assert.Error(t, err)
|
||||||
|
assert.Nil(t, res)
|
||||||
|
} else {
|
||||||
|
assert.NoError(t, err)
|
||||||
|
assert.NotNil(t, res)
|
||||||
|
}
|
||||||
|
assert.Equal(t, test.expectCalls, fake.GetCalledNames())
|
||||||
|
}
|
||||||
|
}
|
162
pkg/server/service_test.go
Normal file
162
pkg/server/service_test.go
Normal file
@ -0,0 +1,162 @@
|
|||||||
|
/*
|
||||||
|
Copyright 2017 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 server
|
||||||
|
|
||||||
|
import (
|
||||||
|
"io"
|
||||||
|
"os"
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"github.com/docker/docker/pkg/truncindex"
|
||||||
|
"github.com/stretchr/testify/assert"
|
||||||
|
"github.com/stretchr/testify/require"
|
||||||
|
"golang.org/x/net/context"
|
||||||
|
|
||||||
|
"github.com/kubernetes-incubator/cri-containerd/pkg/metadata"
|
||||||
|
"github.com/kubernetes-incubator/cri-containerd/pkg/metadata/store"
|
||||||
|
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"
|
||||||
|
|
||||||
|
"github.com/containerd/containerd/api/services/execution"
|
||||||
|
|
||||||
|
"k8s.io/kubernetes/pkg/kubelet/api/v1alpha1/runtime"
|
||||||
|
)
|
||||||
|
|
||||||
|
type nopReadWriteCloser struct{}
|
||||||
|
|
||||||
|
func (nopReadWriteCloser) Read(p []byte) (n int, err error) { return len(p), nil }
|
||||||
|
func (nopReadWriteCloser) Write(p []byte) (n int, err error) { return len(p), nil }
|
||||||
|
func (nopReadWriteCloser) Close() error { return nil }
|
||||||
|
|
||||||
|
const testRootDir = "/test/rootfs"
|
||||||
|
|
||||||
|
// newTestCRIContainerdService creates a fake criContainerdService for test.
|
||||||
|
func newTestCRIContainerdService() *criContainerdService {
|
||||||
|
return &criContainerdService{
|
||||||
|
os: ostesting.NewFakeOS(),
|
||||||
|
rootDir: testRootDir,
|
||||||
|
containerService: servertesting.NewFakeExecutionClient(),
|
||||||
|
sandboxStore: metadata.NewSandboxStore(store.NewMetadataStore()),
|
||||||
|
sandboxNameIndex: registrar.NewRegistrar(),
|
||||||
|
sandboxIDIndex: truncindex.NewTruncIndex(nil),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Test all sandbox operations.
|
||||||
|
func TestSandboxOperations(t *testing.T) {
|
||||||
|
c := newTestCRIContainerdService()
|
||||||
|
fake := c.containerService.(*servertesting.FakeExecutionClient)
|
||||||
|
fakeOS := c.os.(*ostesting.FakeOS)
|
||||||
|
fakeOS.OpenFifoFn = func(ctx context.Context, fn string, flag int, perm os.FileMode) (io.ReadWriteCloser, error) {
|
||||||
|
return nopReadWriteCloser{}, nil
|
||||||
|
}
|
||||||
|
config := &runtime.PodSandboxConfig{
|
||||||
|
Metadata: &runtime.PodSandboxMetadata{
|
||||||
|
Name: "test-name",
|
||||||
|
Uid: "test-uid",
|
||||||
|
Namespace: "test-ns",
|
||||||
|
Attempt: 1,
|
||||||
|
},
|
||||||
|
Hostname: "test-hostname",
|
||||||
|
LogDirectory: "test-log-directory",
|
||||||
|
Labels: map[string]string{"a": "b"},
|
||||||
|
Annotations: map[string]string{"c": "d"},
|
||||||
|
}
|
||||||
|
|
||||||
|
t.Logf("should be able to run a pod sandbox")
|
||||||
|
runRes, err := c.RunPodSandbox(context.Background(), &runtime.RunPodSandboxRequest{Config: config})
|
||||||
|
assert.NoError(t, err)
|
||||||
|
require.NotNil(t, runRes)
|
||||||
|
id := runRes.GetPodSandboxId()
|
||||||
|
|
||||||
|
t.Logf("should be able to get pod sandbox status")
|
||||||
|
info, err := fake.Info(context.Background(), &execution.InfoRequest{ID: id})
|
||||||
|
assert.NoError(t, err)
|
||||||
|
expectSandboxStatus := &runtime.PodSandboxStatus{
|
||||||
|
Id: id,
|
||||||
|
Metadata: config.GetMetadata(),
|
||||||
|
// TODO(random-liu): [P2] Use fake clock for CreatedAt.
|
||||||
|
Network: &runtime.PodSandboxNetworkStatus{},
|
||||||
|
Linux: &runtime.LinuxPodSandboxStatus{
|
||||||
|
Namespaces: &runtime.Namespace{
|
||||||
|
Network: getNetworkNamespace(info.Pid),
|
||||||
|
Options: &runtime.NamespaceOption{
|
||||||
|
HostNetwork: false,
|
||||||
|
HostPid: false,
|
||||||
|
HostIpc: false,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
Labels: config.GetLabels(),
|
||||||
|
Annotations: config.GetAnnotations(),
|
||||||
|
}
|
||||||
|
statusRes, err := c.PodSandboxStatus(context.Background(), &runtime.PodSandboxStatusRequest{PodSandboxId: id})
|
||||||
|
assert.NoError(t, err)
|
||||||
|
require.NotNil(t, statusRes)
|
||||||
|
status := statusRes.GetStatus()
|
||||||
|
expectSandboxStatus.CreatedAt = status.GetCreatedAt()
|
||||||
|
assert.Equal(t, expectSandboxStatus, status)
|
||||||
|
|
||||||
|
t.Logf("should be able to list pod sandboxes")
|
||||||
|
expectSandbox := &runtime.PodSandbox{
|
||||||
|
Id: id,
|
||||||
|
Metadata: config.GetMetadata(),
|
||||||
|
State: runtime.PodSandboxState_SANDBOX_READY,
|
||||||
|
Labels: config.GetLabels(),
|
||||||
|
Annotations: config.GetAnnotations(),
|
||||||
|
}
|
||||||
|
listRes, err := c.ListPodSandbox(context.Background(), &runtime.ListPodSandboxRequest{})
|
||||||
|
assert.NoError(t, err)
|
||||||
|
require.NotNil(t, listRes)
|
||||||
|
sandboxes := listRes.GetItems()
|
||||||
|
assert.Len(t, sandboxes, 1)
|
||||||
|
expectSandbox.CreatedAt = sandboxes[0].CreatedAt
|
||||||
|
assert.Equal(t, expectSandbox, sandboxes[0])
|
||||||
|
|
||||||
|
t.Logf("should be able to stop a pod sandbox")
|
||||||
|
stopRes, err := c.StopPodSandbox(context.Background(), &runtime.StopPodSandboxRequest{PodSandboxId: id})
|
||||||
|
assert.NoError(t, err)
|
||||||
|
require.NotNil(t, stopRes)
|
||||||
|
statusRes, err = c.PodSandboxStatus(context.Background(), &runtime.PodSandboxStatusRequest{PodSandboxId: id})
|
||||||
|
assert.NoError(t, err)
|
||||||
|
require.NotNil(t, statusRes)
|
||||||
|
assert.Equal(t, runtime.PodSandboxState_SANDBOX_NOTREADY, statusRes.GetStatus().GetState(),
|
||||||
|
"sandbox status should be NOTREADY after stopped")
|
||||||
|
listRes, err = c.ListPodSandbox(context.Background(), &runtime.ListPodSandboxRequest{})
|
||||||
|
assert.NoError(t, err)
|
||||||
|
require.NotNil(t, listRes)
|
||||||
|
assert.Len(t, listRes.GetItems(), 1)
|
||||||
|
assert.Equal(t, runtime.PodSandboxState_SANDBOX_NOTREADY, listRes.GetItems()[0].State,
|
||||||
|
"sandbox in list should be NOTREADY after stopped")
|
||||||
|
|
||||||
|
t.Logf("should be able to remove a pod sandbox")
|
||||||
|
removeRes, err := c.RemovePodSandbox(context.Background(), &runtime.RemovePodSandboxRequest{PodSandboxId: id})
|
||||||
|
assert.NoError(t, err)
|
||||||
|
require.NotNil(t, removeRes)
|
||||||
|
_, err = c.PodSandboxStatus(context.Background(), &runtime.PodSandboxStatusRequest{PodSandboxId: id})
|
||||||
|
assert.Error(t, err, "should not be able to get sandbox status after removed")
|
||||||
|
listRes, err = c.ListPodSandbox(context.Background(), &runtime.ListPodSandboxRequest{})
|
||||||
|
assert.NoError(t, err)
|
||||||
|
require.NotNil(t, listRes)
|
||||||
|
assert.Empty(t, listRes.GetItems(), "should not be able to list the sandbox after removed")
|
||||||
|
|
||||||
|
t.Logf("should be able to create the sandbox again")
|
||||||
|
runRes, err = c.RunPodSandbox(context.Background(), &runtime.RunPodSandboxRequest{Config: config})
|
||||||
|
assert.NoError(t, err)
|
||||||
|
require.NotNil(t, runRes)
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user