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) | ||||||
|  | } | ||||||
		Reference in New Issue
	
	Block a user
	 Random-Liu
					Random-Liu