Update go dependencies

This commit is contained in:
Manuel de Brito Fontes 2018-05-26 11:27:53 -04:00 committed by Manuel Alejandro de Brito Fontes
parent 15ffb51394
commit bb4d483837
No known key found for this signature in database
GPG key ID: 786136016A8BA02A
1621 changed files with 86368 additions and 284392 deletions

View file

@ -1,95 +0,0 @@
/*
Copyright 2016 The Kubernetes Authors.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package kubelet
import (
"testing"
"time"
"k8s.io/api/core/v1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/types"
"k8s.io/apimachinery/pkg/util/clock"
"k8s.io/client-go/tools/record"
)
// mockPodStatusProvider returns the status on the specified pod
type mockPodStatusProvider struct {
pods []*v1.Pod
}
// GetPodStatus returns the status on the associated pod with matching uid (if found)
func (m *mockPodStatusProvider) GetPodStatus(uid types.UID) (v1.PodStatus, bool) {
for _, pod := range m.pods {
if pod.UID == uid {
return pod.Status, true
}
}
return v1.PodStatus{}, false
}
// TestActiveDeadlineHandler verifies the active deadline handler functions as expected.
func TestActiveDeadlineHandler(t *testing.T) {
pods := newTestPods(4)
fakeClock := clock.NewFakeClock(time.Now())
podStatusProvider := &mockPodStatusProvider{pods: pods}
fakeRecorder := &record.FakeRecorder{}
handler, err := newActiveDeadlineHandler(podStatusProvider, fakeRecorder, fakeClock)
if err != nil {
t.Fatalf("unexpected error: %v", err)
}
now := metav1.Now()
startTime := metav1.NewTime(now.Time.Add(-1 * time.Minute))
// this pod has exceeded its active deadline
exceededActiveDeadlineSeconds := int64(30)
pods[0].Status.StartTime = &startTime
pods[0].Spec.ActiveDeadlineSeconds = &exceededActiveDeadlineSeconds
// this pod has not exceeded its active deadline
notYetActiveDeadlineSeconds := int64(120)
pods[1].Status.StartTime = &startTime
pods[1].Spec.ActiveDeadlineSeconds = &notYetActiveDeadlineSeconds
// this pod has no deadline
pods[2].Status.StartTime = &startTime
pods[2].Spec.ActiveDeadlineSeconds = nil
testCases := []struct {
pod *v1.Pod
expected bool
}{{pods[0], true}, {pods[1], false}, {pods[2], false}, {pods[3], false}}
for i, testCase := range testCases {
if actual := handler.ShouldSync(testCase.pod); actual != testCase.expected {
t.Errorf("[%d] ShouldSync expected %#v, got %#v", i, testCase.expected, actual)
}
actual := handler.ShouldEvict(testCase.pod)
if actual.Evict != testCase.expected {
t.Errorf("[%d] ShouldEvict.Evict expected %#v, got %#v", i, testCase.expected, actual.Evict)
}
if testCase.expected {
if actual.Reason != reason {
t.Errorf("[%d] ShouldEvict.Reason expected %#v, got %#v", i, message, actual.Reason)
}
if actual.Message != message {
t.Errorf("[%d] ShouldEvict.Message expected %#v, got %#v", i, message, actual.Message)
}
}
}
}

View file

@ -1,210 +0,0 @@
/*
Copyright 2015 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 container
import (
"fmt"
"strconv"
"testing"
"time"
"github.com/stretchr/testify/assert"
"k8s.io/apimachinery/pkg/types"
)
func newTestCache() *cache {
c := NewCache()
return c.(*cache)
}
func TestCacheNotInitialized(t *testing.T) {
cache := newTestCache()
// If the global timestamp is not set, always return nil.
d := cache.getIfNewerThan(types.UID("1234"), time.Time{})
assert.True(t, d == nil, "should return nil since cache is not initialized")
}
func getTestPodIDAndStatus(numContainers int) (types.UID, *PodStatus) {
id := types.UID(strconv.FormatInt(time.Now().UnixNano(), 10))
name := fmt.Sprintf("cache-foo-%s", string(id))
namespace := "ns"
var status *PodStatus
if numContainers > 0 {
status = &PodStatus{ID: id, Name: name, Namespace: namespace}
} else {
status = &PodStatus{ID: id}
}
for i := 0; i < numContainers; i++ {
status.ContainerStatuses = append(status.ContainerStatuses, &ContainerStatus{Name: string(i)})
}
return id, status
}
func TestGetIfNewerThanWhenPodExists(t *testing.T) {
cache := newTestCache()
timestamp := time.Now()
cases := []struct {
cacheTime time.Time
modified time.Time
expected bool
}{
{
// Both the global cache timestamp and the modified time are newer
// than the timestamp.
cacheTime: timestamp.Add(time.Second),
modified: timestamp,
expected: true,
},
{
// Global cache timestamp is newer, but the pod entry modified
// time is older than the given timestamp. This means that the
// entry is up-to-date even though it hasn't changed for a while.
cacheTime: timestamp.Add(time.Second),
modified: timestamp.Add(-time.Second * 10),
expected: true,
},
{
// Global cache timestamp is older, but the pod entry modified
// time is newer than the given timestamp. This means that the
// entry is up-to-date but the rest of the cache are still being
// updated.
cacheTime: timestamp.Add(-time.Second),
modified: timestamp.Add(time.Second * 3),
expected: true,
},
{
// Both the global cache timestamp and the modified time are older
// than the given timestamp.
cacheTime: timestamp.Add(-time.Second),
modified: timestamp.Add(-time.Second),
expected: false,
},
}
for i, c := range cases {
podID, status := getTestPodIDAndStatus(2)
cache.UpdateTime(c.cacheTime)
cache.Set(podID, status, nil, c.modified)
d := cache.getIfNewerThan(podID, timestamp)
assert.Equal(t, c.expected, d != nil, "test[%d]", i)
}
}
func TestGetPodNewerThanWhenPodDoesNotExist(t *testing.T) {
cache := newTestCache()
cacheTime := time.Now()
cache.UpdateTime(cacheTime)
podID := types.UID("1234")
cases := []struct {
timestamp time.Time
expected bool
}{
{
timestamp: cacheTime.Add(-time.Second),
expected: true,
},
{
timestamp: cacheTime.Add(time.Second),
expected: false,
},
}
for i, c := range cases {
d := cache.getIfNewerThan(podID, c.timestamp)
assert.Equal(t, c.expected, d != nil, "test[%d]", i)
}
}
func TestCacheSetAndGet(t *testing.T) {
cache := NewCache()
cases := []struct {
numContainers int
error error
}{
{numContainers: 3, error: nil},
{numContainers: 2, error: fmt.Errorf("unable to get status")},
{numContainers: 0, error: nil},
}
for i, c := range cases {
podID, status := getTestPodIDAndStatus(c.numContainers)
cache.Set(podID, status, c.error, time.Time{})
// Read back the status and error stored in cache and make sure they
// match the original ones.
actualStatus, actualErr := cache.Get(podID)
assert.Equal(t, status, actualStatus, "test[%d]", i)
assert.Equal(t, c.error, actualErr, "test[%d]", i)
}
}
func TestCacheGetPodDoesNotExist(t *testing.T) {
cache := NewCache()
podID, status := getTestPodIDAndStatus(0)
// If the pod does not exist in cache, cache should return an status
// object with id filled.
actualStatus, actualErr := cache.Get(podID)
assert.Equal(t, status, actualStatus)
assert.Equal(t, nil, actualErr)
}
func TestDelete(t *testing.T) {
cache := &cache{pods: map[types.UID]*data{}}
// Write a new pod status into the cache.
podID, status := getTestPodIDAndStatus(3)
cache.Set(podID, status, nil, time.Time{})
actualStatus, actualErr := cache.Get(podID)
assert.Equal(t, status, actualStatus)
assert.Equal(t, nil, actualErr)
// Delete the pod from cache, and verify that we get an empty status.
cache.Delete(podID)
expectedStatus := &PodStatus{ID: podID}
actualStatus, actualErr = cache.Get(podID)
assert.Equal(t, expectedStatus, actualStatus)
assert.Equal(t, nil, actualErr)
}
func verifyNotification(t *testing.T, ch chan *data, expectNotification bool) {
if expectNotification {
assert.True(t, len(ch) > 0, "Did not receive notification")
} else {
assert.True(t, len(ch) < 1, "Should not have triggered the notification")
}
// Drain the channel.
for i := 0; i < len(ch); i++ {
<-ch
}
}
func TestRegisterNotification(t *testing.T) {
cache := newTestCache()
cacheTime := time.Now()
cache.UpdateTime(cacheTime)
podID, status := getTestPodIDAndStatus(1)
ch := cache.subscribe(podID, cacheTime.Add(time.Second))
verifyNotification(t, ch, false)
cache.Set(podID, status, nil, cacheTime.Add(time.Second))
// The Set operation should've triggered the notification.
verifyNotification(t, ch, true)
podID, _ = getTestPodIDAndStatus(1)
ch = cache.subscribe(podID, cacheTime.Add(time.Second))
verifyNotification(t, ch, false)
cache.UpdateTime(cacheTime.Add(time.Second * 2))
// The advance of cache timestamp should've triggered the notification.
verifyNotification(t, ch, true)
}

View file

@ -1,322 +0,0 @@
/*
Copyright 2015 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 container
import (
"reflect"
"testing"
"github.com/stretchr/testify/assert"
"k8s.io/api/core/v1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
)
func TestEnvVarsToMap(t *testing.T) {
vars := []EnvVar{
{
Name: "foo",
Value: "bar",
},
{
Name: "zoo",
Value: "baz",
},
}
varMap := EnvVarsToMap(vars)
if e, a := len(vars), len(varMap); e != a {
t.Errorf("Unexpected map length; expected: %d, got %d", e, a)
}
if a := varMap["foo"]; a != "bar" {
t.Errorf("Unexpected value of key 'foo': %v", a)
}
if a := varMap["zoo"]; a != "baz" {
t.Errorf("Unexpected value of key 'zoo': %v", a)
}
}
func TestExpandCommandAndArgs(t *testing.T) {
cases := []struct {
name string
container *v1.Container
envs []EnvVar
expectedCommand []string
expectedArgs []string
}{
{
name: "none",
container: &v1.Container{},
},
{
name: "command expanded",
container: &v1.Container{
Command: []string{"foo", "$(VAR_TEST)", "$(VAR_TEST2)"},
},
envs: []EnvVar{
{
Name: "VAR_TEST",
Value: "zoo",
},
{
Name: "VAR_TEST2",
Value: "boo",
},
},
expectedCommand: []string{"foo", "zoo", "boo"},
},
{
name: "args expanded",
container: &v1.Container{
Args: []string{"zap", "$(VAR_TEST)", "$(VAR_TEST2)"},
},
envs: []EnvVar{
{
Name: "VAR_TEST",
Value: "hap",
},
{
Name: "VAR_TEST2",
Value: "trap",
},
},
expectedArgs: []string{"zap", "hap", "trap"},
},
{
name: "both expanded",
container: &v1.Container{
Command: []string{"$(VAR_TEST2)--$(VAR_TEST)", "foo", "$(VAR_TEST3)"},
Args: []string{"foo", "$(VAR_TEST)", "$(VAR_TEST2)"},
},
envs: []EnvVar{
{
Name: "VAR_TEST",
Value: "zoo",
},
{
Name: "VAR_TEST2",
Value: "boo",
},
{
Name: "VAR_TEST3",
Value: "roo",
},
},
expectedCommand: []string{"boo--zoo", "foo", "roo"},
expectedArgs: []string{"foo", "zoo", "boo"},
},
}
for _, tc := range cases {
actualCommand, actualArgs := ExpandContainerCommandAndArgs(tc.container, tc.envs)
if e, a := tc.expectedCommand, actualCommand; !reflect.DeepEqual(e, a) {
t.Errorf("%v: unexpected command; expected %v, got %v", tc.name, e, a)
}
if e, a := tc.expectedArgs, actualArgs; !reflect.DeepEqual(e, a) {
t.Errorf("%v: unexpected args; expected %v, got %v", tc.name, e, a)
}
}
}
func TestShouldContainerBeRestarted(t *testing.T) {
pod := &v1.Pod{
ObjectMeta: metav1.ObjectMeta{
UID: "12345678",
Name: "foo",
Namespace: "new",
},
Spec: v1.PodSpec{
Containers: []v1.Container{
{Name: "no-history"},
{Name: "alive"},
{Name: "succeed"},
{Name: "failed"},
{Name: "unknown"},
},
},
}
podStatus := &PodStatus{
ID: pod.UID,
Name: pod.Name,
Namespace: pod.Namespace,
ContainerStatuses: []*ContainerStatus{
{
Name: "alive",
State: ContainerStateRunning,
},
{
Name: "succeed",
State: ContainerStateExited,
ExitCode: 0,
},
{
Name: "failed",
State: ContainerStateExited,
ExitCode: 1,
},
{
Name: "alive",
State: ContainerStateExited,
ExitCode: 2,
},
{
Name: "unknown",
State: ContainerStateUnknown,
},
{
Name: "failed",
State: ContainerStateExited,
ExitCode: 3,
},
},
}
policies := []v1.RestartPolicy{
v1.RestartPolicyNever,
v1.RestartPolicyOnFailure,
v1.RestartPolicyAlways,
}
expected := map[string][]bool{
"no-history": {true, true, true},
"alive": {false, false, false},
"succeed": {false, false, true},
"failed": {false, true, true},
"unknown": {true, true, true},
}
for _, c := range pod.Spec.Containers {
for i, policy := range policies {
pod.Spec.RestartPolicy = policy
e := expected[c.Name][i]
r := ShouldContainerBeRestarted(&c, pod, podStatus)
if r != e {
t.Errorf("Restart for container %q with restart policy %q expected %t, got %t",
c.Name, policy, e, r)
}
}
}
}
func TestHasPrivilegedContainer(t *testing.T) {
newBoolPtr := func(b bool) *bool {
return &b
}
tests := map[string]struct {
securityContext *v1.SecurityContext
expected bool
}{
"nil security context": {
securityContext: nil,
expected: false,
},
"nil privileged": {
securityContext: &v1.SecurityContext{},
expected: false,
},
"false privileged": {
securityContext: &v1.SecurityContext{Privileged: newBoolPtr(false)},
expected: false,
},
"true privileged": {
securityContext: &v1.SecurityContext{Privileged: newBoolPtr(true)},
expected: true,
},
}
for k, v := range tests {
pod := &v1.Pod{
Spec: v1.PodSpec{
Containers: []v1.Container{
{SecurityContext: v.securityContext},
},
},
}
actual := HasPrivilegedContainer(pod)
if actual != v.expected {
t.Errorf("%s expected %t but got %t", k, v.expected, actual)
}
}
// Test init containers as well.
for k, v := range tests {
pod := &v1.Pod{
Spec: v1.PodSpec{
InitContainers: []v1.Container{
{SecurityContext: v.securityContext},
},
},
}
actual := HasPrivilegedContainer(pod)
if actual != v.expected {
t.Errorf("%s expected %t but got %t", k, v.expected, actual)
}
}
}
func TestMakePortMappings(t *testing.T) {
port := func(name string, protocol v1.Protocol, containerPort, hostPort int32, ip string) v1.ContainerPort {
return v1.ContainerPort{
Name: name,
Protocol: protocol,
ContainerPort: containerPort,
HostPort: hostPort,
HostIP: ip,
}
}
portMapping := func(name string, protocol v1.Protocol, containerPort, hostPort int, ip string) PortMapping {
return PortMapping{
Name: name,
Protocol: protocol,
ContainerPort: containerPort,
HostPort: hostPort,
HostIP: ip,
}
}
tests := []struct {
container *v1.Container
expectedPortMappings []PortMapping
}{
{
&v1.Container{
Name: "fooContainer",
Ports: []v1.ContainerPort{
port("", v1.ProtocolTCP, 80, 8080, "127.0.0.1"),
port("", v1.ProtocolTCP, 443, 4343, "192.168.0.1"),
port("foo", v1.ProtocolUDP, 555, 5555, ""),
// Duplicated, should be ignored.
port("foo", v1.ProtocolUDP, 888, 8888, ""),
// Duplicated, should be ignored.
port("", v1.ProtocolTCP, 80, 8888, ""),
},
},
[]PortMapping{
portMapping("fooContainer-TCP:80", v1.ProtocolTCP, 80, 8080, "127.0.0.1"),
portMapping("fooContainer-TCP:443", v1.ProtocolTCP, 443, 4343, "192.168.0.1"),
portMapping("fooContainer-foo", v1.ProtocolUDP, 555, 5555, ""),
},
},
}
for i, tt := range tests {
actual := MakePortMappings(tt.container)
assert.Equal(t, tt.expectedPortMappings, actual, "[%d]", i)
}
}

View file

@ -1,213 +0,0 @@
/*
Copyright 2015 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 container
import (
"testing"
"k8s.io/api/core/v1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/kubernetes/pkg/api/legacyscheme"
_ "k8s.io/kubernetes/pkg/apis/core/install"
)
func TestFieldPath(t *testing.T) {
pod := &v1.Pod{Spec: v1.PodSpec{Containers: []v1.Container{
{Name: "foo"},
{Name: "bar"},
{Name: ""},
{Name: "baz"},
}}}
table := map[string]struct {
pod *v1.Pod
container *v1.Container
path string
success bool
}{
"basic": {pod, &v1.Container{Name: "foo"}, "spec.containers{foo}", true},
"basic2": {pod, &v1.Container{Name: "baz"}, "spec.containers{baz}", true},
"emptyName": {pod, &v1.Container{Name: ""}, "spec.containers[2]", true},
"basicSamePointer": {pod, &pod.Spec.Containers[0], "spec.containers{foo}", true},
"missing": {pod, &v1.Container{Name: "qux"}, "", false},
}
for name, item := range table {
res, err := fieldPath(item.pod, item.container)
if item.success == false {
if err == nil {
t.Errorf("%v: unexpected non-error", name)
}
continue
}
if err != nil {
t.Errorf("%v: unexpected error: %v", name, err)
continue
}
if e, a := item.path, res; e != a {
t.Errorf("%v: wanted %v, got %v", name, e, a)
}
}
}
func TestGenerateContainerRef(t *testing.T) {
var (
okPod = v1.Pod{
TypeMeta: metav1.TypeMeta{
Kind: "Pod",
APIVersion: legacyscheme.Registry.GroupOrDie(v1.GroupName).GroupVersion.String(),
},
ObjectMeta: metav1.ObjectMeta{
Name: "ok",
Namespace: "test-ns",
UID: "bar",
ResourceVersion: "42",
SelfLink: "/api/" + legacyscheme.Registry.GroupOrDie(v1.GroupName).GroupVersion.String() + "/pods/foo",
},
Spec: v1.PodSpec{
Containers: []v1.Container{
{
Name: "by-name",
},
{},
},
},
}
noSelfLinkPod = okPod
defaultedSelfLinkPod = okPod
)
noSelfLinkPod.Kind = ""
noSelfLinkPod.APIVersion = ""
noSelfLinkPod.ObjectMeta.SelfLink = ""
defaultedSelfLinkPod.ObjectMeta.SelfLink = "/api/" + legacyscheme.Registry.GroupOrDie(v1.GroupName).GroupVersion.String() + "/pods/ok"
cases := []struct {
name string
pod *v1.Pod
container *v1.Container
expected *v1.ObjectReference
success bool
}{
{
name: "by-name",
pod: &okPod,
container: &v1.Container{
Name: "by-name",
},
expected: &v1.ObjectReference{
Kind: "Pod",
APIVersion: legacyscheme.Registry.GroupOrDie(v1.GroupName).GroupVersion.String(),
Name: "ok",
Namespace: "test-ns",
UID: "bar",
ResourceVersion: "42",
FieldPath: ".spec.containers{by-name}",
},
success: true,
},
{
name: "no-name",
pod: &okPod,
container: &v1.Container{},
expected: &v1.ObjectReference{
Kind: "Pod",
APIVersion: legacyscheme.Registry.GroupOrDie(v1.GroupName).GroupVersion.String(),
Name: "ok",
Namespace: "test-ns",
UID: "bar",
ResourceVersion: "42",
FieldPath: ".spec.containers[1]",
},
success: true,
},
{
name: "no-selflink",
pod: &noSelfLinkPod,
container: &v1.Container{},
expected: nil,
success: false,
},
{
name: "defaulted-selflink",
pod: &defaultedSelfLinkPod,
container: &v1.Container{
Name: "by-name",
},
expected: &v1.ObjectReference{
Kind: "Pod",
APIVersion: legacyscheme.Registry.GroupOrDie(v1.GroupName).GroupVersion.String(),
Name: "ok",
Namespace: "test-ns",
UID: "bar",
ResourceVersion: "42",
FieldPath: ".spec.containers{by-name}",
},
success: true,
},
{
name: "implicitly-required",
pod: &okPod,
container: &v1.Container{
Name: "net",
},
expected: &v1.ObjectReference{
Kind: "Pod",
APIVersion: legacyscheme.Registry.GroupOrDie(v1.GroupName).GroupVersion.String(),
Name: "ok",
Namespace: "test-ns",
UID: "bar",
ResourceVersion: "42",
FieldPath: "implicitly required container net",
},
success: true,
},
}
for _, tc := range cases {
actual, err := GenerateContainerRef(tc.pod, tc.container)
if err != nil {
if tc.success {
t.Errorf("%v: unexpected error: %v", tc.name, err)
}
continue
}
if !tc.success {
t.Errorf("%v: unexpected success", tc.name)
continue
}
if e, a := tc.expected.Kind, actual.Kind; e != a {
t.Errorf("%v: kind: expected %v, got %v", tc.name, e, a)
}
if e, a := tc.expected.APIVersion, actual.APIVersion; e != a {
t.Errorf("%v: apiVersion: expected %v, got %v", tc.name, e, a)
}
if e, a := tc.expected.Name, actual.Name; e != a {
t.Errorf("%v: name: expected %v, got %v", tc.name, e, a)
}
if e, a := tc.expected.Namespace, actual.Namespace; e != a {
t.Errorf("%v: namespace: expected %v, got %v", tc.name, e, a)
}
if e, a := tc.expected.UID, actual.UID; e != a {
t.Errorf("%v: uid: expected %v, got %v", tc.name, e, a)
}
if e, a := tc.expected.ResourceVersion, actual.ResourceVersion; e != a {
t.Errorf("%v: kind: expected %v, got %v", tc.name, e, a)
}
}
}

View file

@ -1,74 +0,0 @@
/*
Copyright 2015 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 container_test
import (
"reflect"
"testing"
"time"
. "k8s.io/kubernetes/pkg/kubelet/container"
ctest "k8s.io/kubernetes/pkg/kubelet/container/testing"
)
func comparePods(t *testing.T, expected []*ctest.FakePod, actual []*Pod) {
if len(expected) != len(actual) {
t.Errorf("expected %d pods, got %d instead", len(expected), len(actual))
}
for i := range expected {
if !reflect.DeepEqual(expected[i].Pod, actual[i]) {
t.Errorf("expected %#v, got %#v", expected[i].Pod, actual[i])
}
}
}
func TestGetPods(t *testing.T) {
runtime := &ctest.FakeRuntime{}
expected := []*ctest.FakePod{{Pod: &Pod{ID: "1111"}}, {Pod: &Pod{ID: "2222"}}, {Pod: &Pod{ID: "3333"}}}
runtime.PodList = expected
cache := NewTestRuntimeCache(runtime)
actual, err := cache.GetPods()
if err != nil {
t.Errorf("unexpected error %v", err)
}
comparePods(t, expected, actual)
}
func TestForceUpdateIfOlder(t *testing.T) {
runtime := &ctest.FakeRuntime{}
cache := NewTestRuntimeCache(runtime)
// Cache old pods.
oldpods := []*ctest.FakePod{{Pod: &Pod{ID: "1111"}}}
runtime.PodList = oldpods
cache.UpdateCacheWithLock()
// Update the runtime to new pods.
newpods := []*ctest.FakePod{{Pod: &Pod{ID: "1111"}}, {Pod: &Pod{ID: "2222"}}, {Pod: &Pod{ID: "3333"}}}
runtime.PodList = newpods
// An older timestamp should not force an update.
cache.ForceUpdateIfOlder(time.Now().Add(-20 * time.Minute))
actual := cache.GetCachedPods()
comparePods(t, oldpods, actual)
// A newer timestamp should force an update.
cache.ForceUpdateIfOlder(time.Now().Add(20 * time.Second))
actual = cache.GetCachedPods()
comparePods(t, newpods, actual)
}

View file

@ -1,68 +0,0 @@
/*
Copyright 2015 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 container
import (
"errors"
"testing"
)
func TestPodSyncResult(t *testing.T) {
okResults := []*SyncResult{
NewSyncResult(StartContainer, "container_0"),
NewSyncResult(SetupNetwork, "pod"),
}
errResults := []*SyncResult{
NewSyncResult(KillContainer, "container_1"),
NewSyncResult(TeardownNetwork, "pod"),
}
errResults[0].Fail(errors.New("error_0"), "message_0")
errResults[1].Fail(errors.New("error_1"), "message_1")
// If the PodSyncResult doesn't contain error result, it should not be error
result := PodSyncResult{}
result.AddSyncResult(okResults...)
if result.Error() != nil {
t.Errorf("PodSyncResult should not be error: %v", result)
}
// If the PodSyncResult contains error result, it should be error
result = PodSyncResult{}
result.AddSyncResult(okResults...)
result.AddSyncResult(errResults...)
if result.Error() == nil {
t.Errorf("PodSyncResult should be error: %q", result)
}
// If the PodSyncResult is failed, it should be error
result = PodSyncResult{}
result.AddSyncResult(okResults...)
result.Fail(errors.New("error"))
if result.Error() == nil {
t.Errorf("PodSyncResult should be error: %q", result)
}
// If the PodSyncResult is added an error PodSyncResult, it should be error
errResult := PodSyncResult{}
errResult.AddSyncResult(errResults...)
result = PodSyncResult{}
result.AddSyncResult(okResults...)
result.AddPodSyncResult(errResult)
if result.Error() == nil {
t.Errorf("PodSyncResult should be error: %q", result)
}
}

View file

@ -237,6 +237,7 @@ type Dependencies struct {
DockerClientConfig *dockershim.ClientConfig
EventClient v1core.EventsGetter
HeartbeatClient v1core.CoreV1Interface
OnHeartbeatFailure func()
KubeClient clientset.Interface
ExternalKubeClient clientset.Interface
Mounter mount.Interface
@ -493,6 +494,7 @@ func NewMainKubelet(kubeCfg *kubeletconfiginternal.KubeletConfiguration,
nodeName: nodeName,
kubeClient: kubeDeps.KubeClient,
heartbeatClient: kubeDeps.HeartbeatClient,
onRepeatedHeartbeatFailure: kubeDeps.OnHeartbeatFailure,
rootDirectory: rootDirectory,
resyncInterval: kubeCfg.SyncFrequency.Duration,
sourcesReady: config.NewSourcesReady(kubeDeps.PodConfig.SeenAllSources),
@ -935,6 +937,9 @@ type Kubelet struct {
iptClient utilipt.Interface
rootDirectory string
// onRepeatedHeartbeatFailure is called when a heartbeat operation fails more than once. optional.
onRepeatedHeartbeatFailure func()
// podWorkers handle syncing Pods in response to events.
podWorkers PodWorkers

View file

@ -1,69 +0,0 @@
/*
Copyright 2016 The Kubernetes Authors.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package kubelet
import (
"path/filepath"
"testing"
"github.com/stretchr/testify/assert"
)
func TestKubeletDirs(t *testing.T) {
testKubelet := newTestKubelet(t, false /* controllerAttachDetachEnabled */)
defer testKubelet.Cleanup()
kubelet := testKubelet.kubelet
root := kubelet.rootDirectory
var exp, got string
got = kubelet.getPodsDir()
exp = filepath.Join(root, "pods")
assert.Equal(t, exp, got)
got = kubelet.getPluginsDir()
exp = filepath.Join(root, "plugins")
assert.Equal(t, exp, got)
got = kubelet.getPluginDir("foobar")
exp = filepath.Join(root, "plugins/foobar")
assert.Equal(t, exp, got)
got = kubelet.getPodDir("abc123")
exp = filepath.Join(root, "pods/abc123")
assert.Equal(t, exp, got)
got = kubelet.getPodVolumesDir("abc123")
exp = filepath.Join(root, "pods/abc123/volumes")
assert.Equal(t, exp, got)
got = kubelet.getPodVolumeDir("abc123", "plugin", "foobar")
exp = filepath.Join(root, "pods/abc123/volumes/plugin/foobar")
assert.Equal(t, exp, got)
got = kubelet.getPodPluginsDir("abc123")
exp = filepath.Join(root, "pods/abc123/plugins")
assert.Equal(t, exp, got)
got = kubelet.getPodPluginDir("abc123", "foobar")
exp = filepath.Join(root, "pods/abc123/plugins/foobar")
assert.Equal(t, exp, got)
got = kubelet.getPodContainerDir("abc123", "def456")
exp = filepath.Join(root, "pods/abc123/containers/def456")
assert.Equal(t, exp, got)
}

View file

@ -1,206 +0,0 @@
/*
Copyright 2016 The Kubernetes Authors.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package kubelet
import (
"fmt"
"net"
"testing"
"github.com/stretchr/testify/assert"
)
func TestNetworkHostGetsPodNotFound(t *testing.T) {
testKubelet := newTestKubelet(t, true)
defer testKubelet.Cleanup()
nh := networkHost{testKubelet.kubelet}
actualPod, _ := nh.GetPodByName("", "")
if actualPod != nil {
t.Fatalf("Was expected nil, received %v instead", actualPod)
}
}
func TestNetworkHostGetsKubeClient(t *testing.T) {
testKubelet := newTestKubelet(t, true)
defer testKubelet.Cleanup()
nh := networkHost{testKubelet.kubelet}
if nh.GetKubeClient() != testKubelet.fakeKubeClient {
t.Fatalf("NetworkHost client does not match testKubelet's client")
}
}
func TestNetworkHostGetsRuntime(t *testing.T) {
testKubelet := newTestKubelet(t, true)
defer testKubelet.Cleanup()
nh := networkHost{testKubelet.kubelet}
if nh.GetRuntime() != testKubelet.fakeRuntime {
t.Fatalf("NetworkHost runtime does not match testKubelet's runtime")
}
}
func TestNetworkHostSupportsLegacyFeatures(t *testing.T) {
testKubelet := newTestKubelet(t, true)
defer testKubelet.Cleanup()
nh := networkHost{testKubelet.kubelet}
if nh.SupportsLegacyFeatures() == false {
t.Fatalf("SupportsLegacyFeatures should not be false")
}
}
func TestNoOpHostGetsName(t *testing.T) {
nh := NoOpLegacyHost{}
pod, err := nh.GetPodByName("", "")
if pod != nil && err != true {
t.Fatalf("noOpLegacyHost getpodbyname expected to be nil and true")
}
}
func TestNoOpHostGetsKubeClient(t *testing.T) {
nh := NoOpLegacyHost{}
if nh.GetKubeClient() != nil {
t.Fatalf("noOpLegacyHost client expected to be nil")
}
}
func TestNoOpHostGetsRuntime(t *testing.T) {
nh := NoOpLegacyHost{}
if nh.GetRuntime() != nil {
t.Fatalf("noOpLegacyHost runtime expected to be nil")
}
}
func TestNoOpHostSupportsLegacyFeatures(t *testing.T) {
nh := NoOpLegacyHost{}
if nh.SupportsLegacyFeatures() != false {
t.Fatalf("noOpLegacyHost legacy features expected to be false")
}
}
func TestNodeIPParam(t *testing.T) {
type test struct {
nodeIP string
success bool
testName string
}
tests := []test{
{
nodeIP: "",
success: false,
testName: "IP not set",
},
{
nodeIP: "127.0.0.1",
success: false,
testName: "IPv4 loopback address",
},
{
nodeIP: "::1",
success: false,
testName: "IPv6 loopback address",
},
{
nodeIP: "224.0.0.1",
success: false,
testName: "multicast IPv4 address",
},
{
nodeIP: "ff00::1",
success: false,
testName: "multicast IPv6 address",
},
{
nodeIP: "169.254.0.1",
success: false,
testName: "IPv4 link-local unicast address",
},
{
nodeIP: "fe80::0202:b3ff:fe1e:8329",
success: false,
testName: "IPv6 link-local unicast address",
},
{
nodeIP: "0.0.0.0",
success: false,
testName: "Unspecified IPv4 address",
},
{
nodeIP: "::",
success: false,
testName: "Unspecified IPv6 address",
},
{
nodeIP: "1.2.3.4",
success: false,
testName: "IPv4 address that doesn't belong to host",
},
}
addrs, err := net.InterfaceAddrs()
if err != nil {
assert.Error(t, err, fmt.Sprintf(
"Unable to obtain a list of the node's unicast interface addresses."))
}
for _, addr := range addrs {
var ip net.IP
switch v := addr.(type) {
case *net.IPNet:
ip = v.IP
case *net.IPAddr:
ip = v.IP
}
if ip.IsLoopback() || ip.IsLinkLocalUnicast() {
break
}
successTest := test{
nodeIP: ip.String(),
success: true,
testName: fmt.Sprintf("Success test case for address %s", ip.String()),
}
tests = append(tests, successTest)
}
for _, test := range tests {
err := validateNodeIP(net.ParseIP(test.nodeIP))
if test.success {
assert.NoError(t, err, "test %s", test.testName)
} else {
assert.Error(t, err, fmt.Sprintf("test %s", test.testName))
}
}
}
func TestGetIPTablesMark(t *testing.T) {
tests := []struct {
bit int
expect string
}{
{
14,
"0x00004000/0x00004000",
},
{
15,
"0x00008000/0x00008000",
},
}
for _, tc := range tests {
res := getIPTablesMark(tc.bit)
assert.Equal(t, tc.expect, res, "input %d", tc.bit)
}
}

View file

@ -371,6 +371,9 @@ func (kl *Kubelet) syncNodeStatus() {
func (kl *Kubelet) updateNodeStatus() error {
for i := 0; i < nodeStatusUpdateRetry; i++ {
if err := kl.tryUpdateNodeStatus(i); err != nil {
if i > 0 && kl.onRepeatedHeartbeatFailure != nil {
kl.onRepeatedHeartbeatFailure()
}
glog.Errorf("Error updating node status, will retry: %v", err)
} else {
return nil

File diff suppressed because it is too large Load diff

View file

@ -110,23 +110,6 @@ func (kl *Kubelet) makeGPUDevices(pod *v1.Pod, container *v1.Container) ([]kubec
return devices, nil
}
func makeAbsolutePath(goos, path string) string {
if goos != "windows" {
return "/" + path
}
// These are all for windows
// If there is a colon, give up.
if strings.Contains(path, ":") {
return path
}
// If there is a slash, but no drive, add 'c:'
if strings.HasPrefix(path, "/") || strings.HasPrefix(path, "\\") {
return "c:" + path
}
// Otherwise, add 'c:\'
return "c:\\" + path
}
// makeBlockVolumes maps the raw block devices specified in the path of the container
// Experimental
func (kl *Kubelet) makeBlockVolumes(pod *v1.Pod, container *v1.Container, podVolumes kubecontainer.VolumeMap, blkutil volumepathhandler.BlockVolumePathHandler) ([]kubecontainer.DeviceInfo, error) {
@ -239,6 +222,7 @@ func makeMounts(pod *v1.Pod, podDir string, container *v1.Container, hostName, h
VolumePath: volumePath,
PodDir: podDir,
ContainerName: container.Name,
ReadOnly: mount.ReadOnly || vol.Mounter.GetAttributes().ReadOnly,
})
if err != nil {
// Don't pass detailed error back to the user because it could give information about host filesystem
@ -255,7 +239,7 @@ func makeMounts(pod *v1.Pod, podDir string, container *v1.Container, hostName, h
}
}
if !filepath.IsAbs(containerPath) {
containerPath = makeAbsolutePath(runtime.GOOS, containerPath)
containerPath = volumeutil.MakeAbsolutePath(runtime.GOOS, containerPath)
}
propagation, err := translateMountPropagation(mount.MountPropagation)
@ -301,12 +285,14 @@ func translateMountPropagation(mountMode *v1.MountPropagationMode) (runtimeapi.M
}
switch {
case mountMode == nil:
// HostToContainer is the default
return runtimeapi.MountPropagation_PROPAGATION_HOST_TO_CONTAINER, nil
// PRIVATE is the default
return runtimeapi.MountPropagation_PROPAGATION_PRIVATE, nil
case *mountMode == v1.MountPropagationHostToContainer:
return runtimeapi.MountPropagation_PROPAGATION_HOST_TO_CONTAINER, nil
case *mountMode == v1.MountPropagationBidirectional:
return runtimeapi.MountPropagation_PROPAGATION_BIDIRECTIONAL, nil
case *mountMode == v1.MountPropagationNone:
return runtimeapi.MountPropagation_PROPAGATION_PRIVATE, nil
default:
return 0, fmt.Errorf("invalid MountPropagation mode: %q", mountMode)
}

File diff suppressed because it is too large Load diff

View file

@ -1,102 +0,0 @@
// +build windows
/*
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 kubelet
import (
"testing"
"github.com/stretchr/testify/assert"
"k8s.io/api/core/v1"
kubecontainer "k8s.io/kubernetes/pkg/kubelet/container"
"k8s.io/kubernetes/pkg/util/mount"
)
func TestMakeMountsWindows(t *testing.T) {
container := v1.Container{
VolumeMounts: []v1.VolumeMount{
{
MountPath: "c:/etc/hosts",
Name: "disk",
ReadOnly: false,
},
{
MountPath: "c:/mnt/path3",
Name: "disk",
ReadOnly: true,
},
{
MountPath: "c:/mnt/path4",
Name: "disk4",
ReadOnly: false,
},
{
MountPath: "c:/mnt/path5",
Name: "disk5",
ReadOnly: false,
},
},
}
podVolumes := kubecontainer.VolumeMap{
"disk": kubecontainer.VolumeInfo{Mounter: &stubVolume{path: "c:/mnt/disk"}},
"disk4": kubecontainer.VolumeInfo{Mounter: &stubVolume{path: "c:/mnt/host"}},
"disk5": kubecontainer.VolumeInfo{Mounter: &stubVolume{path: "c:/var/lib/kubelet/podID/volumes/empty/disk5"}},
}
pod := v1.Pod{
Spec: v1.PodSpec{
HostNetwork: true,
},
}
fm := &mount.FakeMounter{}
mounts, _, _ := makeMounts(&pod, "/pod", &container, "fakepodname", "", "", podVolumes, fm)
expectedMounts := []kubecontainer.Mount{
{
Name: "disk",
ContainerPath: "c:/etc/hosts",
HostPath: "c:/mnt/disk",
ReadOnly: false,
SELinuxRelabel: false,
},
{
Name: "disk",
ContainerPath: "c:/mnt/path3",
HostPath: "c:/mnt/disk",
ReadOnly: true,
SELinuxRelabel: false,
},
{
Name: "disk4",
ContainerPath: "c:/mnt/path4",
HostPath: "c:/mnt/host",
ReadOnly: false,
SELinuxRelabel: false,
},
{
Name: "disk5",
ContainerPath: "c:/mnt/path5",
HostPath: "c:/var/lib/kubelet/podID/volumes/empty/disk5",
ReadOnly: false,
SELinuxRelabel: false,
},
}
assert.Equal(t, expectedMounts, mounts, "mounts of container %+v", container)
}

View file

@ -1,111 +0,0 @@
/*
Copyright 2016 The Kubernetes Authors.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package kubelet
import (
"testing"
"github.com/stretchr/testify/assert"
cadvisorapi "github.com/google/cadvisor/info/v1"
cadvisorapiv2 "github.com/google/cadvisor/info/v2"
"k8s.io/api/core/v1"
apiequality "k8s.io/apimachinery/pkg/api/equality"
"k8s.io/apimachinery/pkg/api/resource"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
)
func TestPodResourceLimitsDefaulting(t *testing.T) {
cpuCores := resource.MustParse("10")
memoryCapacity := resource.MustParse("10Gi")
tk := newTestKubelet(t, true)
defer tk.Cleanup()
tk.fakeCadvisor.On("VersionInfo").Return(&cadvisorapi.VersionInfo{}, nil)
tk.fakeCadvisor.On("MachineInfo").Return(&cadvisorapi.MachineInfo{
NumCores: int(cpuCores.Value()),
MemoryCapacity: uint64(memoryCapacity.Value()),
}, nil)
tk.fakeCadvisor.On("ImagesFsInfo").Return(cadvisorapiv2.FsInfo{}, nil)
tk.fakeCadvisor.On("RootFsInfo").Return(cadvisorapiv2.FsInfo{}, nil)
tk.kubelet.nodeInfo = &testNodeInfo{
nodes: []*v1.Node{
{
ObjectMeta: metav1.ObjectMeta{
Name: string(tk.kubelet.nodeName),
},
Status: v1.NodeStatus{
Allocatable: v1.ResourceList{
v1.ResourceCPU: resource.MustParse("6"),
v1.ResourceMemory: resource.MustParse("4Gi"),
},
},
},
},
}
cases := []struct {
pod *v1.Pod
expected *v1.Pod
}{
{
pod: getPod("0", "0"),
expected: getPod("6", "4Gi"),
},
{
pod: getPod("1", "0"),
expected: getPod("1", "4Gi"),
},
{
pod: getPod("", ""),
expected: getPod("6", "4Gi"),
},
{
pod: getPod("0", "1Mi"),
expected: getPod("6", "1Mi"),
},
}
as := assert.New(t)
for idx, tc := range cases {
actual, _, err := tk.kubelet.defaultPodLimitsForDownwardAPI(tc.pod, nil)
as.Nil(err, "failed to default pod limits: %v", err)
if !apiequality.Semantic.DeepEqual(tc.expected, actual) {
as.Fail("test case [%d] failed. Expected: %+v, Got: %+v", idx, tc.expected, actual)
}
}
}
func getPod(cpuLimit, memoryLimit string) *v1.Pod {
resources := v1.ResourceRequirements{}
if cpuLimit != "" || memoryLimit != "" {
resources.Limits = make(v1.ResourceList)
}
if cpuLimit != "" {
resources.Limits[v1.ResourceCPU] = resource.MustParse(cpuLimit)
}
if memoryLimit != "" {
resources.Limits[v1.ResourceMemory] = resource.MustParse(memoryLimit)
}
return &v1.Pod{
Spec: v1.PodSpec{
Containers: []v1.Container{
{
Name: "foo",
Resources: resources,
},
},
},
}
}

File diff suppressed because it is too large Load diff

View file

@ -1,470 +0,0 @@
/*
Copyright 2016 The Kubernetes Authors.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package kubelet
import (
"fmt"
"testing"
"github.com/stretchr/testify/assert"
"k8s.io/api/core/v1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/runtime"
"k8s.io/apimachinery/pkg/types"
core "k8s.io/client-go/testing"
"k8s.io/kubernetes/pkg/volume"
volumetest "k8s.io/kubernetes/pkg/volume/testing"
"k8s.io/kubernetes/pkg/volume/util"
)
func TestListVolumesForPod(t *testing.T) {
testKubelet := newTestKubelet(t, false /* controllerAttachDetachEnabled */)
defer testKubelet.Cleanup()
kubelet := testKubelet.kubelet
pod := podWithUIDNameNsSpec("12345678", "foo", "test", v1.PodSpec{
Volumes: []v1.Volume{
{
Name: "vol1",
VolumeSource: v1.VolumeSource{
GCEPersistentDisk: &v1.GCEPersistentDiskVolumeSource{
PDName: "fake-device1",
},
},
},
{
Name: "vol2",
VolumeSource: v1.VolumeSource{
GCEPersistentDisk: &v1.GCEPersistentDiskVolumeSource{
PDName: "fake-device2",
},
},
},
},
})
stopCh := runVolumeManager(kubelet)
defer close(stopCh)
kubelet.podManager.SetPods([]*v1.Pod{pod})
err := kubelet.volumeManager.WaitForAttachAndMount(pod)
assert.NoError(t, err)
podName := util.GetUniquePodName(pod)
volumesToReturn, volumeExsit := kubelet.ListVolumesForPod(types.UID(podName))
assert.True(t, volumeExsit, "expected to find volumes for pod %q", podName)
outerVolumeSpecName1 := "vol1"
assert.NotNil(t, volumesToReturn[outerVolumeSpecName1], "key %s", outerVolumeSpecName1)
outerVolumeSpecName2 := "vol2"
assert.NotNil(t, volumesToReturn[outerVolumeSpecName2], "key %s", outerVolumeSpecName2)
}
func TestPodVolumesExist(t *testing.T) {
testKubelet := newTestKubelet(t, false /* controllerAttachDetachEnabled */)
defer testKubelet.Cleanup()
kubelet := testKubelet.kubelet
pods := []*v1.Pod{
{
ObjectMeta: metav1.ObjectMeta{
Name: "pod1",
UID: "pod1uid",
},
Spec: v1.PodSpec{
Volumes: []v1.Volume{
{
Name: "vol1",
VolumeSource: v1.VolumeSource{
GCEPersistentDisk: &v1.GCEPersistentDiskVolumeSource{
PDName: "fake-device1",
},
},
},
},
},
},
{
ObjectMeta: metav1.ObjectMeta{
Name: "pod2",
UID: "pod2uid",
},
Spec: v1.PodSpec{
Volumes: []v1.Volume{
{
Name: "vol2",
VolumeSource: v1.VolumeSource{
GCEPersistentDisk: &v1.GCEPersistentDiskVolumeSource{
PDName: "fake-device2",
},
},
},
},
},
},
{
ObjectMeta: metav1.ObjectMeta{
Name: "pod3",
UID: "pod3uid",
},
Spec: v1.PodSpec{
Volumes: []v1.Volume{
{
Name: "vol3",
VolumeSource: v1.VolumeSource{
GCEPersistentDisk: &v1.GCEPersistentDiskVolumeSource{
PDName: "fake-device3",
},
},
},
},
},
},
}
stopCh := runVolumeManager(kubelet)
defer close(stopCh)
kubelet.podManager.SetPods(pods)
for _, pod := range pods {
err := kubelet.volumeManager.WaitForAttachAndMount(pod)
assert.NoError(t, err)
}
for _, pod := range pods {
podVolumesExist := kubelet.podVolumesExist(pod.UID)
assert.True(t, podVolumesExist, "pod %q", pod.UID)
}
}
func TestVolumeAttachAndMountControllerDisabled(t *testing.T) {
testKubelet := newTestKubelet(t, false /* controllerAttachDetachEnabled */)
defer testKubelet.Cleanup()
kubelet := testKubelet.kubelet
pod := podWithUIDNameNsSpec("12345678", "foo", "test", v1.PodSpec{
Volumes: []v1.Volume{
{
Name: "vol1",
VolumeSource: v1.VolumeSource{
GCEPersistentDisk: &v1.GCEPersistentDiskVolumeSource{
PDName: "fake-device",
},
},
},
},
})
stopCh := runVolumeManager(kubelet)
defer close(stopCh)
kubelet.podManager.SetPods([]*v1.Pod{pod})
err := kubelet.volumeManager.WaitForAttachAndMount(pod)
assert.NoError(t, err)
podVolumes := kubelet.volumeManager.GetMountedVolumesForPod(
util.GetUniquePodName(pod))
expectedPodVolumes := []string{"vol1"}
assert.Len(t, podVolumes, len(expectedPodVolumes), "Volumes for pod %+v", pod)
for _, name := range expectedPodVolumes {
assert.Contains(t, podVolumes, name, "Volumes for pod %+v", pod)
}
assert.True(t, testKubelet.volumePlugin.GetNewAttacherCallCount() >= 1, "Expected plugin NewAttacher to be called at least once")
assert.NoError(t, volumetest.VerifyWaitForAttachCallCount(
1 /* expectedWaitForAttachCallCount */, testKubelet.volumePlugin))
assert.NoError(t, volumetest.VerifyAttachCallCount(
1 /* expectedAttachCallCount */, testKubelet.volumePlugin))
assert.NoError(t, volumetest.VerifyMountDeviceCallCount(
1 /* expectedMountDeviceCallCount */, testKubelet.volumePlugin))
assert.NoError(t, volumetest.VerifySetUpCallCount(
1 /* expectedSetUpCallCount */, testKubelet.volumePlugin))
}
func TestVolumeUnmountAndDetachControllerDisabled(t *testing.T) {
testKubelet := newTestKubelet(t, false /* controllerAttachDetachEnabled */)
defer testKubelet.Cleanup()
kubelet := testKubelet.kubelet
pod := podWithUIDNameNsSpec("12345678", "foo", "test", v1.PodSpec{
Volumes: []v1.Volume{
{
Name: "vol1",
VolumeSource: v1.VolumeSource{
GCEPersistentDisk: &v1.GCEPersistentDiskVolumeSource{
PDName: "fake-device",
},
},
},
},
})
stopCh := runVolumeManager(kubelet)
defer close(stopCh)
// Add pod
kubelet.podManager.SetPods([]*v1.Pod{pod})
// Verify volumes attached
err := kubelet.volumeManager.WaitForAttachAndMount(pod)
assert.NoError(t, err)
podVolumes := kubelet.volumeManager.GetMountedVolumesForPod(
util.GetUniquePodName(pod))
expectedPodVolumes := []string{"vol1"}
assert.Len(t, podVolumes, len(expectedPodVolumes), "Volumes for pod %+v", pod)
for _, name := range expectedPodVolumes {
assert.Contains(t, podVolumes, name, "Volumes for pod %+v", pod)
}
assert.True(t, testKubelet.volumePlugin.GetNewAttacherCallCount() >= 1, "Expected plugin NewAttacher to be called at least once")
assert.NoError(t, volumetest.VerifyWaitForAttachCallCount(
1 /* expectedWaitForAttachCallCount */, testKubelet.volumePlugin))
assert.NoError(t, volumetest.VerifyAttachCallCount(
1 /* expectedAttachCallCount */, testKubelet.volumePlugin))
assert.NoError(t, volumetest.VerifyMountDeviceCallCount(
1 /* expectedMountDeviceCallCount */, testKubelet.volumePlugin))
assert.NoError(t, volumetest.VerifySetUpCallCount(
1 /* expectedSetUpCallCount */, testKubelet.volumePlugin))
// Remove pod
kubelet.podManager.SetPods([]*v1.Pod{})
assert.NoError(t, waitForVolumeUnmount(kubelet.volumeManager, pod))
// Verify volumes unmounted
podVolumes = kubelet.volumeManager.GetMountedVolumesForPod(
util.GetUniquePodName(pod))
assert.Len(t, podVolumes, 0,
"Expected volumes to be unmounted and detached. But some volumes are still mounted: %#v", podVolumes)
assert.NoError(t, volumetest.VerifyTearDownCallCount(
1 /* expectedTearDownCallCount */, testKubelet.volumePlugin))
// Verify volumes detached and no longer reported as in use
assert.NoError(t, waitForVolumeDetach(v1.UniqueVolumeName("fake/vol1"), kubelet.volumeManager))
assert.True(t, testKubelet.volumePlugin.GetNewAttacherCallCount() >= 1, "Expected plugin NewAttacher to be called at least once")
assert.NoError(t, volumetest.VerifyDetachCallCount(
1 /* expectedDetachCallCount */, testKubelet.volumePlugin))
}
func TestVolumeAttachAndMountControllerEnabled(t *testing.T) {
testKubelet := newTestKubelet(t, true /* controllerAttachDetachEnabled */)
defer testKubelet.Cleanup()
kubelet := testKubelet.kubelet
kubeClient := testKubelet.fakeKubeClient
kubeClient.AddReactor("get", "nodes",
func(action core.Action) (bool, runtime.Object, error) {
return true, &v1.Node{
ObjectMeta: metav1.ObjectMeta{Name: testKubeletHostname},
Status: v1.NodeStatus{
VolumesAttached: []v1.AttachedVolume{
{
Name: "fake/vol1",
DevicePath: "fake/path",
},
}},
Spec: v1.NodeSpec{ExternalID: testKubeletHostname},
}, nil
})
kubeClient.AddReactor("*", "*", func(action core.Action) (bool, runtime.Object, error) {
return true, nil, fmt.Errorf("no reaction implemented for %s", action)
})
pod := podWithUIDNameNsSpec("12345678", "foo", "test", v1.PodSpec{
Volumes: []v1.Volume{
{
Name: "vol1",
VolumeSource: v1.VolumeSource{
GCEPersistentDisk: &v1.GCEPersistentDiskVolumeSource{
PDName: "fake-device",
},
},
},
},
})
stopCh := runVolumeManager(kubelet)
defer close(stopCh)
kubelet.podManager.SetPods([]*v1.Pod{pod})
// Fake node status update
go simulateVolumeInUseUpdate(
v1.UniqueVolumeName("fake/vol1"),
stopCh,
kubelet.volumeManager)
assert.NoError(t, kubelet.volumeManager.WaitForAttachAndMount(pod))
podVolumes := kubelet.volumeManager.GetMountedVolumesForPod(
util.GetUniquePodName(pod))
expectedPodVolumes := []string{"vol1"}
assert.Len(t, podVolumes, len(expectedPodVolumes), "Volumes for pod %+v", pod)
for _, name := range expectedPodVolumes {
assert.Contains(t, podVolumes, name, "Volumes for pod %+v", pod)
}
assert.True(t, testKubelet.volumePlugin.GetNewAttacherCallCount() >= 1, "Expected plugin NewAttacher to be called at least once")
assert.NoError(t, volumetest.VerifyWaitForAttachCallCount(
1 /* expectedWaitForAttachCallCount */, testKubelet.volumePlugin))
assert.NoError(t, volumetest.VerifyZeroAttachCalls(testKubelet.volumePlugin))
assert.NoError(t, volumetest.VerifyMountDeviceCallCount(
1 /* expectedMountDeviceCallCount */, testKubelet.volumePlugin))
assert.NoError(t, volumetest.VerifySetUpCallCount(
1 /* expectedSetUpCallCount */, testKubelet.volumePlugin))
}
func TestVolumeUnmountAndDetachControllerEnabled(t *testing.T) {
testKubelet := newTestKubelet(t, true /* controllerAttachDetachEnabled */)
defer testKubelet.Cleanup()
kubelet := testKubelet.kubelet
kubeClient := testKubelet.fakeKubeClient
kubeClient.AddReactor("get", "nodes",
func(action core.Action) (bool, runtime.Object, error) {
return true, &v1.Node{
ObjectMeta: metav1.ObjectMeta{Name: testKubeletHostname},
Status: v1.NodeStatus{
VolumesAttached: []v1.AttachedVolume{
{
Name: "fake/vol1",
DevicePath: "fake/path",
},
}},
Spec: v1.NodeSpec{ExternalID: testKubeletHostname},
}, nil
})
kubeClient.AddReactor("*", "*", func(action core.Action) (bool, runtime.Object, error) {
return true, nil, fmt.Errorf("no reaction implemented for %s", action)
})
pod := podWithUIDNameNsSpec("12345678", "foo", "test", v1.PodSpec{
Volumes: []v1.Volume{
{
Name: "vol1",
VolumeSource: v1.VolumeSource{
GCEPersistentDisk: &v1.GCEPersistentDiskVolumeSource{
PDName: "fake-device",
},
},
},
},
})
stopCh := runVolumeManager(kubelet)
defer close(stopCh)
// Add pod
kubelet.podManager.SetPods([]*v1.Pod{pod})
// Fake node status update
go simulateVolumeInUseUpdate(
v1.UniqueVolumeName("fake/vol1"),
stopCh,
kubelet.volumeManager)
// Verify volumes attached
assert.NoError(t, kubelet.volumeManager.WaitForAttachAndMount(pod))
podVolumes := kubelet.volumeManager.GetMountedVolumesForPod(
util.GetUniquePodName(pod))
expectedPodVolumes := []string{"vol1"}
assert.Len(t, podVolumes, len(expectedPodVolumes), "Volumes for pod %+v", pod)
for _, name := range expectedPodVolumes {
assert.Contains(t, podVolumes, name, "Volumes for pod %+v", pod)
}
assert.True(t, testKubelet.volumePlugin.GetNewAttacherCallCount() >= 1, "Expected plugin NewAttacher to be called at least once")
assert.NoError(t, volumetest.VerifyWaitForAttachCallCount(
1 /* expectedWaitForAttachCallCount */, testKubelet.volumePlugin))
assert.NoError(t, volumetest.VerifyZeroAttachCalls(testKubelet.volumePlugin))
assert.NoError(t, volumetest.VerifyMountDeviceCallCount(
1 /* expectedMountDeviceCallCount */, testKubelet.volumePlugin))
assert.NoError(t, volumetest.VerifySetUpCallCount(
1 /* expectedSetUpCallCount */, testKubelet.volumePlugin))
// Remove pod
kubelet.podManager.SetPods([]*v1.Pod{})
assert.NoError(t, waitForVolumeUnmount(kubelet.volumeManager, pod))
// Verify volumes unmounted
podVolumes = kubelet.volumeManager.GetMountedVolumesForPod(
util.GetUniquePodName(pod))
assert.Len(t, podVolumes, 0,
"Expected volumes to be unmounted and detached. But some volumes are still mounted: %#v", podVolumes)
assert.NoError(t, volumetest.VerifyTearDownCallCount(
1 /* expectedTearDownCallCount */, testKubelet.volumePlugin))
// Verify volumes detached and no longer reported as in use
assert.NoError(t, waitForVolumeDetach(v1.UniqueVolumeName("fake/vol1"), kubelet.volumeManager))
assert.True(t, testKubelet.volumePlugin.GetNewAttacherCallCount() >= 1, "Expected plugin NewAttacher to be called at least once")
assert.NoError(t, volumetest.VerifyZeroDetachCallCount(testKubelet.volumePlugin))
}
type stubVolume struct {
path string
volume.MetricsNil
}
func (f *stubVolume) GetPath() string {
return f.path
}
func (f *stubVolume) GetAttributes() volume.Attributes {
return volume.Attributes{}
}
func (f *stubVolume) CanMount() error {
return nil
}
func (f *stubVolume) SetUp(fsGroup *int64) error {
return nil
}
func (f *stubVolume) SetUpAt(dir string, fsGroup *int64) error {
return nil
}
type stubBlockVolume struct {
dirPath string
volName string
}
func (f *stubBlockVolume) GetGlobalMapPath(spec *volume.Spec) (string, error) {
return "", nil
}
func (f *stubBlockVolume) GetPodDeviceMapPath() (string, string) {
return f.dirPath, f.volName
}
func (f *stubBlockVolume) SetUpDevice() (string, error) {
return "", nil
}
func (f *stubBlockVolume) TearDownDevice(mapPath string, devicePath string) error {
return nil
}

View file

@ -1,38 +0,0 @@
/*
Copyright 2015 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 kubelet
import (
"testing"
"github.com/stretchr/testify/assert"
"k8s.io/api/core/v1"
"k8s.io/client-go/tools/record"
cadvisortest "k8s.io/kubernetes/pkg/kubelet/cadvisor/testing"
)
func TestBasic(t *testing.T) {
fakeRecorder := &record.FakeRecorder{}
mockCadvisor := &cadvisortest.Fake{}
node := &v1.ObjectReference{}
oomWatcher := NewOOMWatcher(mockCadvisor, fakeRecorder)
assert.NoError(t, oomWatcher.Start(node))
// TODO: Improve this test once cadvisor exports events.EventChannel as an interface
// and thereby allow using a mock version of cadvisor.
}

View file

@ -1,203 +0,0 @@
/*
Copyright 2016 The Kubernetes Authors.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package kubelet
import (
"reflect"
"testing"
"time"
kubecontainer "k8s.io/kubernetes/pkg/kubelet/container"
)
func TestGetContainersToDeleteInPodWithFilter(t *testing.T) {
pod := kubecontainer.PodStatus{
ContainerStatuses: []*kubecontainer.ContainerStatus{
{
ID: kubecontainer.ContainerID{Type: "test", ID: "1"},
Name: "foo",
CreatedAt: time.Now(),
State: kubecontainer.ContainerStateExited,
},
{
ID: kubecontainer.ContainerID{Type: "test", ID: "2"},
Name: "bar",
CreatedAt: time.Now().Add(time.Second),
State: kubecontainer.ContainerStateExited,
},
{
ID: kubecontainer.ContainerID{Type: "test", ID: "3"},
Name: "bar",
CreatedAt: time.Now().Add(2 * time.Second),
State: kubecontainer.ContainerStateExited,
},
{
ID: kubecontainer.ContainerID{Type: "test", ID: "4"},
Name: "bar",
CreatedAt: time.Now().Add(3 * time.Second),
State: kubecontainer.ContainerStateExited,
},
{
ID: kubecontainer.ContainerID{Type: "test", ID: "5"},
Name: "bar",
CreatedAt: time.Now().Add(4 * time.Second),
State: kubecontainer.ContainerStateRunning,
},
},
}
testCases := []struct {
containersToKeep int
expectedContainersToDelete containerStatusbyCreatedList
}{
{
0,
[]*kubecontainer.ContainerStatus{pod.ContainerStatuses[3], pod.ContainerStatuses[2], pod.ContainerStatuses[1]},
},
{
1,
[]*kubecontainer.ContainerStatus{pod.ContainerStatuses[2], pod.ContainerStatuses[1]},
},
{
2,
[]*kubecontainer.ContainerStatus{pod.ContainerStatuses[1]},
},
}
for _, test := range testCases {
candidates := getContainersToDeleteInPod("4", &pod, test.containersToKeep)
if !reflect.DeepEqual(candidates, test.expectedContainersToDelete) {
t.Errorf("expected %v got %v", test.expectedContainersToDelete, candidates)
}
}
}
func TestGetContainersToDeleteInPod(t *testing.T) {
pod := kubecontainer.PodStatus{
ContainerStatuses: []*kubecontainer.ContainerStatus{
{
ID: kubecontainer.ContainerID{Type: "test", ID: "1"},
Name: "foo",
CreatedAt: time.Now(),
State: kubecontainer.ContainerStateExited,
},
{
ID: kubecontainer.ContainerID{Type: "test", ID: "2"},
Name: "bar",
CreatedAt: time.Now().Add(time.Second),
State: kubecontainer.ContainerStateExited,
},
{
ID: kubecontainer.ContainerID{Type: "test", ID: "3"},
Name: "bar",
CreatedAt: time.Now().Add(2 * time.Second),
State: kubecontainer.ContainerStateExited,
},
{
ID: kubecontainer.ContainerID{Type: "test", ID: "4"},
Name: "bar",
CreatedAt: time.Now().Add(3 * time.Second),
State: kubecontainer.ContainerStateExited,
},
{
ID: kubecontainer.ContainerID{Type: "test", ID: "5"},
Name: "bar",
CreatedAt: time.Now().Add(4 * time.Second),
State: kubecontainer.ContainerStateRunning,
},
},
}
testCases := []struct {
containersToKeep int
expectedContainersToDelete containerStatusbyCreatedList
}{
{
0,
[]*kubecontainer.ContainerStatus{pod.ContainerStatuses[3], pod.ContainerStatuses[2], pod.ContainerStatuses[1], pod.ContainerStatuses[0]},
},
{
1,
[]*kubecontainer.ContainerStatus{pod.ContainerStatuses[2], pod.ContainerStatuses[1], pod.ContainerStatuses[0]},
},
{
2,
[]*kubecontainer.ContainerStatus{pod.ContainerStatuses[1], pod.ContainerStatuses[0]},
},
}
for _, test := range testCases {
candidates := getContainersToDeleteInPod("", &pod, test.containersToKeep)
if !reflect.DeepEqual(candidates, test.expectedContainersToDelete) {
t.Errorf("expected %v got %v", test.expectedContainersToDelete, candidates)
}
}
}
func TestGetContainersToDeleteInPodWithNoMatch(t *testing.T) {
pod := kubecontainer.PodStatus{
ContainerStatuses: []*kubecontainer.ContainerStatus{
{
ID: kubecontainer.ContainerID{Type: "test", ID: "1"},
Name: "foo",
CreatedAt: time.Now(),
State: kubecontainer.ContainerStateExited,
},
{
ID: kubecontainer.ContainerID{Type: "test", ID: "2"},
Name: "bar",
CreatedAt: time.Now().Add(time.Second),
State: kubecontainer.ContainerStateExited,
},
{
ID: kubecontainer.ContainerID{Type: "test", ID: "3"},
Name: "bar",
CreatedAt: time.Now().Add(2 * time.Second),
State: kubecontainer.ContainerStateExited,
},
{
ID: kubecontainer.ContainerID{Type: "test", ID: "4"},
Name: "bar",
CreatedAt: time.Now().Add(3 * time.Second),
State: kubecontainer.ContainerStateExited,
},
{
ID: kubecontainer.ContainerID{Type: "test", ID: "5"},
Name: "bar",
CreatedAt: time.Now().Add(4 * time.Second),
State: kubecontainer.ContainerStateRunning,
},
},
}
testCases := []struct {
filterID string
expectedContainersToDelete containerStatusbyCreatedList
}{
{
"abc",
[]*kubecontainer.ContainerStatus{},
},
}
for _, test := range testCases {
candidates := getContainersToDeleteInPod(test.filterID, &pod, len(pod.ContainerStatuses))
if !reflect.DeepEqual(candidates, test.expectedContainersToDelete) {
t.Errorf("expected %v got %v", test.expectedContainersToDelete, candidates)
}
}
}

View file

@ -1,355 +0,0 @@
/*
Copyright 2014 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 kubelet
import (
"reflect"
"sync"
"testing"
"time"
"k8s.io/api/core/v1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/types"
"k8s.io/apimachinery/pkg/util/clock"
"k8s.io/client-go/tools/record"
kubecontainer "k8s.io/kubernetes/pkg/kubelet/container"
containertest "k8s.io/kubernetes/pkg/kubelet/container/testing"
kubetypes "k8s.io/kubernetes/pkg/kubelet/types"
"k8s.io/kubernetes/pkg/kubelet/util/queue"
)
// fakePodWorkers runs sync pod function in serial, so we can have
// deterministic behaviour in testing.
type fakePodWorkers struct {
syncPodFn syncPodFnType
cache kubecontainer.Cache
t TestingInterface
}
func (f *fakePodWorkers) UpdatePod(options *UpdatePodOptions) {
status, err := f.cache.Get(options.Pod.UID)
if err != nil {
f.t.Errorf("Unexpected error: %v", err)
}
if err := f.syncPodFn(syncPodOptions{
mirrorPod: options.MirrorPod,
pod: options.Pod,
podStatus: status,
updateType: options.UpdateType,
killPodOptions: options.KillPodOptions,
}); err != nil {
f.t.Errorf("Unexpected error: %v", err)
}
}
func (f *fakePodWorkers) ForgetNonExistingPodWorkers(desiredPods map[types.UID]empty) {}
func (f *fakePodWorkers) ForgetWorker(uid types.UID) {}
type TestingInterface interface {
Errorf(format string, args ...interface{})
}
func newPod(uid, name string) *v1.Pod {
return &v1.Pod{
ObjectMeta: metav1.ObjectMeta{
UID: types.UID(uid),
Name: name,
},
}
}
// syncPodRecord is a record of a sync pod call
type syncPodRecord struct {
name string
updateType kubetypes.SyncPodType
}
func createPodWorkers() (*podWorkers, map[types.UID][]syncPodRecord) {
lock := sync.Mutex{}
processed := make(map[types.UID][]syncPodRecord)
fakeRecorder := &record.FakeRecorder{}
fakeRuntime := &containertest.FakeRuntime{}
fakeCache := containertest.NewFakeCache(fakeRuntime)
podWorkers := newPodWorkers(
func(options syncPodOptions) error {
func() {
lock.Lock()
defer lock.Unlock()
pod := options.pod
processed[pod.UID] = append(processed[pod.UID], syncPodRecord{
name: pod.Name,
updateType: options.updateType,
})
}()
return nil
},
fakeRecorder,
queue.NewBasicWorkQueue(&clock.RealClock{}),
time.Second,
time.Second,
fakeCache,
)
return podWorkers, processed
}
func drainWorkers(podWorkers *podWorkers, numPods int) {
for {
stillWorking := false
podWorkers.podLock.Lock()
for i := 0; i < numPods; i++ {
if podWorkers.isWorking[types.UID(string(i))] {
stillWorking = true
}
}
podWorkers.podLock.Unlock()
if !stillWorking {
break
}
time.Sleep(50 * time.Millisecond)
}
}
func TestUpdatePod(t *testing.T) {
podWorkers, processed := createPodWorkers()
numPods := 20
for i := 0; i < numPods; i++ {
for j := i; j < numPods; j++ {
podWorkers.UpdatePod(&UpdatePodOptions{
Pod: newPod(string(j), string(i)),
UpdateType: kubetypes.SyncPodCreate,
})
}
}
drainWorkers(podWorkers, numPods)
if len(processed) != numPods {
t.Errorf("Not all pods processed: %v", len(processed))
return
}
for i := 0; i < numPods; i++ {
uid := types.UID(i)
if len(processed[uid]) < 1 || len(processed[uid]) > i+1 {
t.Errorf("Pod %v processed %v times", i, len(processed[uid]))
continue
}
// PodWorker guarantees the first and the last event will be processed
first := 0
last := len(processed[uid]) - 1
if processed[uid][first].name != string(0) {
t.Errorf("Pod %v: incorrect order %v, %v", i, first, processed[uid][first])
}
if processed[uid][last].name != string(i) {
t.Errorf("Pod %v: incorrect order %v, %v", i, last, processed[uid][last])
}
}
}
func TestUpdatePodDoesNotForgetSyncPodKill(t *testing.T) {
podWorkers, processed := createPodWorkers()
numPods := 20
for i := 0; i < numPods; i++ {
pod := newPod(string(i), string(i))
podWorkers.UpdatePod(&UpdatePodOptions{
Pod: pod,
UpdateType: kubetypes.SyncPodCreate,
})
podWorkers.UpdatePod(&UpdatePodOptions{
Pod: pod,
UpdateType: kubetypes.SyncPodKill,
})
podWorkers.UpdatePod(&UpdatePodOptions{
Pod: pod,
UpdateType: kubetypes.SyncPodUpdate,
})
}
drainWorkers(podWorkers, numPods)
if len(processed) != numPods {
t.Errorf("Not all pods processed: %v", len(processed))
return
}
for i := 0; i < numPods; i++ {
uid := types.UID(i)
// each pod should be processed two times (create, kill, but not update)
syncPodRecords := processed[uid]
if len(syncPodRecords) < 2 {
t.Errorf("Pod %v processed %v times, but expected at least 2", i, len(syncPodRecords))
continue
}
if syncPodRecords[0].updateType != kubetypes.SyncPodCreate {
t.Errorf("Pod %v event was %v, but expected %v", i, syncPodRecords[0].updateType, kubetypes.SyncPodCreate)
}
if syncPodRecords[1].updateType != kubetypes.SyncPodKill {
t.Errorf("Pod %v event was %v, but expected %v", i, syncPodRecords[1].updateType, kubetypes.SyncPodKill)
}
}
}
func TestForgetNonExistingPodWorkers(t *testing.T) {
podWorkers, _ := createPodWorkers()
numPods := 20
for i := 0; i < numPods; i++ {
podWorkers.UpdatePod(&UpdatePodOptions{
Pod: newPod(string(i), "name"),
UpdateType: kubetypes.SyncPodUpdate,
})
}
drainWorkers(podWorkers, numPods)
if len(podWorkers.podUpdates) != numPods {
t.Errorf("Incorrect number of open channels %v", len(podWorkers.podUpdates))
}
desiredPods := map[types.UID]empty{}
desiredPods[types.UID(2)] = empty{}
desiredPods[types.UID(14)] = empty{}
podWorkers.ForgetNonExistingPodWorkers(desiredPods)
if len(podWorkers.podUpdates) != 2 {
t.Errorf("Incorrect number of open channels %v", len(podWorkers.podUpdates))
}
if _, exists := podWorkers.podUpdates[types.UID(2)]; !exists {
t.Errorf("No updates channel for pod 2")
}
if _, exists := podWorkers.podUpdates[types.UID(14)]; !exists {
t.Errorf("No updates channel for pod 14")
}
podWorkers.ForgetNonExistingPodWorkers(map[types.UID]empty{})
if len(podWorkers.podUpdates) != 0 {
t.Errorf("Incorrect number of open channels %v", len(podWorkers.podUpdates))
}
}
type simpleFakeKubelet struct {
pod *v1.Pod
mirrorPod *v1.Pod
podStatus *kubecontainer.PodStatus
wg sync.WaitGroup
}
func (kl *simpleFakeKubelet) syncPod(options syncPodOptions) error {
kl.pod, kl.mirrorPod, kl.podStatus = options.pod, options.mirrorPod, options.podStatus
return nil
}
func (kl *simpleFakeKubelet) syncPodWithWaitGroup(options syncPodOptions) error {
kl.pod, kl.mirrorPod, kl.podStatus = options.pod, options.mirrorPod, options.podStatus
kl.wg.Done()
return nil
}
// byContainerName sort the containers in a running pod by their names.
type byContainerName kubecontainer.Pod
func (b byContainerName) Len() int { return len(b.Containers) }
func (b byContainerName) Swap(i, j int) {
b.Containers[i], b.Containers[j] = b.Containers[j], b.Containers[i]
}
func (b byContainerName) Less(i, j int) bool {
return b.Containers[i].Name < b.Containers[j].Name
}
// TestFakePodWorkers verifies that the fakePodWorkers behaves the same way as the real podWorkers
// for their invocation of the syncPodFn.
func TestFakePodWorkers(t *testing.T) {
fakeRecorder := &record.FakeRecorder{}
fakeRuntime := &containertest.FakeRuntime{}
fakeCache := containertest.NewFakeCache(fakeRuntime)
kubeletForRealWorkers := &simpleFakeKubelet{}
kubeletForFakeWorkers := &simpleFakeKubelet{}
realPodWorkers := newPodWorkers(kubeletForRealWorkers.syncPodWithWaitGroup, fakeRecorder, queue.NewBasicWorkQueue(&clock.RealClock{}), time.Second, time.Second, fakeCache)
fakePodWorkers := &fakePodWorkers{kubeletForFakeWorkers.syncPod, fakeCache, t}
tests := []struct {
pod *v1.Pod
mirrorPod *v1.Pod
}{
{
&v1.Pod{},
&v1.Pod{},
},
{
podWithUIDNameNs("12345678", "foo", "new"),
podWithUIDNameNs("12345678", "fooMirror", "new"),
},
{
podWithUIDNameNs("98765", "bar", "new"),
podWithUIDNameNs("98765", "barMirror", "new"),
},
}
for i, tt := range tests {
kubeletForRealWorkers.wg.Add(1)
realPodWorkers.UpdatePod(&UpdatePodOptions{
Pod: tt.pod,
MirrorPod: tt.mirrorPod,
UpdateType: kubetypes.SyncPodUpdate,
})
fakePodWorkers.UpdatePod(&UpdatePodOptions{
Pod: tt.pod,
MirrorPod: tt.mirrorPod,
UpdateType: kubetypes.SyncPodUpdate,
})
kubeletForRealWorkers.wg.Wait()
if !reflect.DeepEqual(kubeletForRealWorkers.pod, kubeletForFakeWorkers.pod) {
t.Errorf("%d: Expected: %#v, Actual: %#v", i, kubeletForRealWorkers.pod, kubeletForFakeWorkers.pod)
}
if !reflect.DeepEqual(kubeletForRealWorkers.mirrorPod, kubeletForFakeWorkers.mirrorPod) {
t.Errorf("%d: Expected: %#v, Actual: %#v", i, kubeletForRealWorkers.mirrorPod, kubeletForFakeWorkers.mirrorPod)
}
if !reflect.DeepEqual(kubeletForRealWorkers.podStatus, kubeletForFakeWorkers.podStatus) {
t.Errorf("%d: Expected: %#v, Actual: %#v", i, kubeletForRealWorkers.podStatus, kubeletForFakeWorkers.podStatus)
}
}
}
// TestKillPodNowFunc tests the blocking kill pod function works with pod workers as expected.
func TestKillPodNowFunc(t *testing.T) {
fakeRecorder := &record.FakeRecorder{}
podWorkers, processed := createPodWorkers()
killPodFunc := killPodNow(podWorkers, fakeRecorder)
pod := newPod("test", "test")
gracePeriodOverride := int64(0)
err := killPodFunc(pod, v1.PodStatus{Phase: v1.PodFailed, Reason: "reason", Message: "message"}, &gracePeriodOverride)
if err != nil {
t.Errorf("Unexpected error: %v", err)
}
if len(processed) != 1 {
t.Errorf("len(processed) expected: %v, actual: %v", 1, len(processed))
return
}
syncPodRecords := processed[pod.UID]
if len(syncPodRecords) != 1 {
t.Errorf("Pod processed %v times, but expected %v", len(syncPodRecords), 1)
}
if syncPodRecords[0].updateType != kubetypes.SyncPodKill {
t.Errorf("Pod update type was %v, but expected %v", syncPodRecords[0].updateType, kubetypes.SyncPodKill)
}
}

View file

@ -1,69 +0,0 @@
/*
Copyright 2016 The Kubernetes Authors.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package kubelet
import (
"testing"
"k8s.io/apimachinery/pkg/types"
kubecontainer "k8s.io/kubernetes/pkg/kubelet/container"
)
func TestReasonCache(t *testing.T) {
// Create test sync result
syncResult := kubecontainer.PodSyncResult{}
results := []*kubecontainer.SyncResult{
// reason cache should be set for SyncResult with StartContainer action and error
kubecontainer.NewSyncResult(kubecontainer.StartContainer, "container_1"),
// reason cache should not be set for SyncResult with StartContainer action but without error
kubecontainer.NewSyncResult(kubecontainer.StartContainer, "container_2"),
// reason cache should not be set for SyncResult with other actions
kubecontainer.NewSyncResult(kubecontainer.KillContainer, "container_3"),
}
results[0].Fail(kubecontainer.ErrRunContainer, "message_1")
results[2].Fail(kubecontainer.ErrKillContainer, "message_3")
syncResult.AddSyncResult(results...)
uid := types.UID("pod_1")
reasonCache := NewReasonCache()
reasonCache.Update(uid, syncResult)
assertReasonInfo(t, reasonCache, uid, results[0], true)
assertReasonInfo(t, reasonCache, uid, results[1], false)
assertReasonInfo(t, reasonCache, uid, results[2], false)
reasonCache.Remove(uid, results[0].Target.(string))
assertReasonInfo(t, reasonCache, uid, results[0], false)
}
func assertReasonInfo(t *testing.T, cache *ReasonCache, uid types.UID, result *kubecontainer.SyncResult, found bool) {
name := result.Target.(string)
actualReason, ok := cache.Get(uid, name)
if ok && !found {
t.Fatalf("unexpected cache hit: %v, %q", actualReason.Err, actualReason.Message)
}
if !ok && found {
t.Fatalf("corresponding reason info not found")
}
if !found {
return
}
reason := result.Error
message := result.Message
if actualReason.Err != reason || actualReason.Message != message {
t.Errorf("expected %v %q, got %v %q", reason, message, actualReason.Err, actualReason.Message)
}
}

View file

@ -1,175 +0,0 @@
/*
Copyright 2014 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 kubelet
import (
"os"
"testing"
"time"
cadvisorapi "github.com/google/cadvisor/info/v1"
cadvisorapiv2 "github.com/google/cadvisor/info/v2"
"k8s.io/api/core/v1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/types"
"k8s.io/apimachinery/pkg/util/clock"
"k8s.io/client-go/kubernetes/fake"
"k8s.io/client-go/tools/record"
utiltesting "k8s.io/client-go/util/testing"
"k8s.io/kubernetes/pkg/kubelet/apis/kubeletconfig"
cadvisortest "k8s.io/kubernetes/pkg/kubelet/cadvisor/testing"
"k8s.io/kubernetes/pkg/kubelet/cm"
"k8s.io/kubernetes/pkg/kubelet/configmap"
kubecontainer "k8s.io/kubernetes/pkg/kubelet/container"
containertest "k8s.io/kubernetes/pkg/kubelet/container/testing"
"k8s.io/kubernetes/pkg/kubelet/eviction"
"k8s.io/kubernetes/pkg/kubelet/network"
nettest "k8s.io/kubernetes/pkg/kubelet/network/testing"
kubepod "k8s.io/kubernetes/pkg/kubelet/pod"
podtest "k8s.io/kubernetes/pkg/kubelet/pod/testing"
"k8s.io/kubernetes/pkg/kubelet/secret"
"k8s.io/kubernetes/pkg/kubelet/server/stats"
"k8s.io/kubernetes/pkg/kubelet/status"
statustest "k8s.io/kubernetes/pkg/kubelet/status/testing"
"k8s.io/kubernetes/pkg/kubelet/volumemanager"
"k8s.io/kubernetes/pkg/util/mount"
"k8s.io/kubernetes/pkg/volume"
volumetest "k8s.io/kubernetes/pkg/volume/testing"
)
func TestRunOnce(t *testing.T) {
cadvisor := &cadvisortest.Mock{}
cadvisor.On("MachineInfo").Return(&cadvisorapi.MachineInfo{}, nil)
cadvisor.On("ImagesFsInfo").Return(cadvisorapiv2.FsInfo{
Usage: 400,
Capacity: 1000,
Available: 600,
}, nil)
cadvisor.On("RootFsInfo").Return(cadvisorapiv2.FsInfo{
Usage: 9,
Capacity: 10,
}, nil)
fakeSecretManager := secret.NewFakeManager()
fakeConfigMapManager := configmap.NewFakeManager()
podManager := kubepod.NewBasicPodManager(
podtest.NewFakeMirrorClient(), fakeSecretManager, fakeConfigMapManager)
fakeRuntime := &containertest.FakeRuntime{}
basePath, err := utiltesting.MkTmpdir("kubelet")
if err != nil {
t.Fatalf("can't make a temp rootdir %v", err)
}
defer os.RemoveAll(basePath)
kb := &Kubelet{
rootDirectory: basePath,
recorder: &record.FakeRecorder{},
cadvisor: cadvisor,
nodeInfo: testNodeInfo{},
statusManager: status.NewManager(nil, podManager, &statustest.FakePodDeletionSafetyProvider{}),
podManager: podManager,
os: &containertest.FakeOS{},
containerRuntime: fakeRuntime,
reasonCache: NewReasonCache(),
clock: clock.RealClock{},
kubeClient: &fake.Clientset{},
hostname: testKubeletHostname,
nodeName: testKubeletHostname,
runtimeState: newRuntimeState(time.Second),
}
kb.containerManager = cm.NewStubContainerManager()
plug := &volumetest.FakeVolumePlugin{PluginName: "fake", Host: nil}
kb.volumePluginMgr, err =
NewInitializedVolumePluginMgr(kb, fakeSecretManager, fakeConfigMapManager, []volume.VolumePlugin{plug}, nil /* prober */)
if err != nil {
t.Fatalf("failed to initialize VolumePluginMgr: %v", err)
}
kb.volumeManager = volumemanager.NewVolumeManager(
true,
kb.nodeName,
kb.podManager,
kb.statusManager,
kb.kubeClient,
kb.volumePluginMgr,
fakeRuntime,
kb.mounter,
kb.getPodsDir(),
kb.recorder,
false, /* experimentalCheckNodeCapabilitiesBeforeMount */
false /* keepTerminatedPodVolumes */)
kb.networkPlugin, _ = network.InitNetworkPlugin([]network.NetworkPlugin{}, "", nettest.NewFakeHost(nil), kubeletconfig.HairpinNone, "", network.UseDefaultMTU)
// TODO: Factor out "StatsProvider" from Kubelet so we don't have a cyclic dependency
volumeStatsAggPeriod := time.Second * 10
kb.resourceAnalyzer = stats.NewResourceAnalyzer(kb, volumeStatsAggPeriod)
nodeRef := &v1.ObjectReference{
Kind: "Node",
Name: string(kb.nodeName),
UID: types.UID(kb.nodeName),
Namespace: "",
}
fakeKillPodFunc := func(pod *v1.Pod, podStatus v1.PodStatus, gracePeriodOverride *int64) error {
return nil
}
evictionManager, evictionAdmitHandler := eviction.NewManager(kb.resourceAnalyzer, eviction.Config{}, fakeKillPodFunc, nil, nil, kb.recorder, nodeRef, kb.clock)
kb.evictionManager = evictionManager
kb.admitHandlers.AddPodAdmitHandler(evictionAdmitHandler)
kb.mounter = &mount.FakeMounter{}
if err := kb.setupDataDirs(); err != nil {
t.Errorf("Failed to init data dirs: %v", err)
}
pods := []*v1.Pod{
{
ObjectMeta: metav1.ObjectMeta{
UID: "12345678",
Name: "foo",
Namespace: "new",
},
Spec: v1.PodSpec{
Containers: []v1.Container{
{Name: "bar"},
},
},
},
}
podManager.SetPods(pods)
// The original test here is totally meaningless, because fakeruntime will always return an empty podStatus. While
// the original logic of isPodRunning happens to return true when podstatus is empty, so the test can always pass.
// Now the logic in isPodRunning is changed, to let the test pass, we set the podstatus directly in fake runtime.
// This is also a meaningless test, because the isPodRunning will also always return true after setting this. However,
// because runonce is never used in kubernetes now, we should deprioritize the cleanup work.
// TODO(random-liu) Fix the test, make it meaningful.
fakeRuntime.PodStatus = kubecontainer.PodStatus{
ContainerStatuses: []*kubecontainer.ContainerStatus{
{
Name: "bar",
State: kubecontainer.ContainerStateRunning,
},
},
}
results, err := kb.runOnce(pods, time.Millisecond)
if err != nil {
t.Errorf("unexpected error: %v", err)
}
if results[0].Err != nil {
t.Errorf("unexpected run pod error: %v", results[0].Err)
}
if results[0].Pod.Name != "foo" {
t.Errorf("unexpected pod: %q", results[0].Pod.Name)
}
}

View file

@ -1,119 +0,0 @@
/*
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 types
import (
"testing"
"github.com/stretchr/testify/assert"
)
func TestGetContainerName(t *testing.T) {
var cases = []struct {
labels map[string]string
containerName string
}{
{
labels: map[string]string{
"io.kubernetes.container.name": "c1",
},
containerName: "c1",
},
{
labels: map[string]string{
"io.kubernetes.container.name": "c2",
},
containerName: "c2",
},
}
for _, data := range cases {
containerName := GetContainerName(data.labels)
assert.Equal(t, data.containerName, containerName)
}
}
func TestGetPodName(t *testing.T) {
var cases = []struct {
labels map[string]string
podName string
}{
{
labels: map[string]string{
"io.kubernetes.pod.name": "p1",
},
podName: "p1",
},
{
labels: map[string]string{
"io.kubernetes.pod.name": "p2",
},
podName: "p2",
},
}
for _, data := range cases {
podName := GetPodName(data.labels)
assert.Equal(t, data.podName, podName)
}
}
func TestGetPodUID(t *testing.T) {
var cases = []struct {
labels map[string]string
podUID string
}{
{
labels: map[string]string{
"io.kubernetes.pod.uid": "uid1",
},
podUID: "uid1",
},
{
labels: map[string]string{
"io.kubernetes.pod.uid": "uid2",
},
podUID: "uid2",
},
}
for _, data := range cases {
podUID := GetPodUID(data.labels)
assert.Equal(t, data.podUID, podUID)
}
}
func TestGetPodNamespace(t *testing.T) {
var cases = []struct {
labels map[string]string
podNamespace string
}{
{
labels: map[string]string{
"io.kubernetes.pod.namespace": "ns1",
},
podNamespace: "ns1",
},
{
labels: map[string]string{
"io.kubernetes.pod.namespace": "ns2",
},
podNamespace: "ns2",
},
}
for _, data := range cases {
podNamespace := GetPodNamespace(data.labels)
assert.Equal(t, data.podNamespace, podNamespace)
}
}

View file

@ -1,178 +0,0 @@
/*
Copyright 2014 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 types
import (
"testing"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
"k8s.io/api/core/v1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
)
func TestGetValidatedSources(t *testing.T) {
// Empty.
sources, err := GetValidatedSources([]string{""})
require.NoError(t, err)
require.Len(t, sources, 0)
// Success.
sources, err = GetValidatedSources([]string{FileSource, ApiserverSource})
require.NoError(t, err)
require.Len(t, sources, 2)
// All.
sources, err = GetValidatedSources([]string{AllSource})
require.NoError(t, err)
require.Len(t, sources, 3)
// Unknown source.
sources, err = GetValidatedSources([]string{"taco"})
require.Error(t, err)
}
func TestGetPodSource(t *testing.T) {
cases := []struct {
pod v1.Pod
expected string
errExpected bool
}{
{
pod: v1.Pod{},
expected: "",
errExpected: true,
},
{
pod: v1.Pod{
ObjectMeta: metav1.ObjectMeta{
Annotations: map[string]string{
"kubernetes.io/config.source": "host-ipc-sources",
},
},
},
expected: "host-ipc-sources",
errExpected: false,
},
}
for i, data := range cases {
source, err := GetPodSource(&data.pod)
if data.errExpected {
assert.Error(t, err)
} else {
assert.NoError(t, err)
}
assert.Equal(t, data.expected, source, "test[%d]", i)
t.Logf("Test case [%d]", i)
}
}
func TestString(t *testing.T) {
cases := []struct {
sp SyncPodType
expected string
}{
{
sp: SyncPodCreate,
expected: "create",
},
{
sp: SyncPodUpdate,
expected: "update",
},
{
sp: SyncPodSync,
expected: "sync",
},
{
sp: SyncPodKill,
expected: "kill",
},
{
sp: 50,
expected: "unknown",
},
}
for i, data := range cases {
syncPodString := data.sp.String()
assert.Equal(t, data.expected, syncPodString, "test[%d]", i)
t.Logf("Test case [%d]", i)
}
}
func TestIsCriticalPod(t *testing.T) {
cases := []struct {
pod v1.Pod
expected bool
}{
{
pod: v1.Pod{
ObjectMeta: metav1.ObjectMeta{
Name: "pod1",
Namespace: "ns",
Annotations: map[string]string{
"scheduler.alpha.kubernetes.io/critical-pod": "",
},
},
},
expected: false,
},
{
pod: v1.Pod{
ObjectMeta: metav1.ObjectMeta{
Name: "pod2",
Namespace: "ns",
Annotations: map[string]string{
"scheduler.alpha.kubernetes.io/critical-pod": "abc",
},
},
},
expected: false,
},
{
pod: v1.Pod{
ObjectMeta: metav1.ObjectMeta{
Name: "pod3",
Namespace: "kube-system",
Annotations: map[string]string{
"scheduler.alpha.kubernetes.io/critical-pod": "abc",
},
},
},
expected: false,
},
{
pod: v1.Pod{
ObjectMeta: metav1.ObjectMeta{
Name: "pod4",
Namespace: "kube-system",
Annotations: map[string]string{
"scheduler.alpha.kubernetes.io/critical-pod": "",
},
},
},
expected: true,
},
}
for i, data := range cases {
actual := IsCriticalPod(&data.pod)
if actual != data.expected {
t.Errorf("IsCriticalPod result wrong:\nexpected: %v\nactual: %v for test[%d] with Annotations: %v",
data.expected, actual, i, data.pod.Annotations)
}
}
}

View file

@ -1,138 +0,0 @@
/*
Copyright 2016 The Kubernetes Authors.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package types
import (
"reflect"
"testing"
"github.com/stretchr/testify/assert"
"k8s.io/api/core/v1"
)
func TestConvertToTimestamp(t *testing.T) {
timestamp := "2017-02-17T15:34:49.830882016+08:00"
convertedTimeStamp := ConvertToTimestamp(timestamp).GetString()
assert.Equal(t, timestamp, convertedTimeStamp)
}
func TestLen(t *testing.T) {
var cases = []struct {
statuses SortedContainerStatuses
expected int
}{
{
statuses: SortedContainerStatuses{{Name: "first"}},
expected: 1,
},
{
statuses: SortedContainerStatuses{{Name: "first"}, {Name: "second"}},
expected: 2,
},
}
for _, data := range cases {
assert.Equal(t, data.expected, data.statuses.Len())
}
}
func TestSwap(t *testing.T) {
var cases = []struct {
statuses SortedContainerStatuses
expected SortedContainerStatuses
}{
{
statuses: SortedContainerStatuses{{Name: "first"}, {Name: "second"}},
expected: SortedContainerStatuses{{Name: "second"}, {Name: "first"}},
},
}
for _, data := range cases {
data.statuses.Swap(0, 1)
if !reflect.DeepEqual(data.statuses, data.expected) {
t.Errorf(
"failed Swap:\n\texpected: %v\n\t actual: %v",
data.expected,
data.statuses,
)
}
}
}
func TestLess(t *testing.T) {
var cases = []struct {
statuses SortedContainerStatuses
expected bool
}{
{
statuses: SortedContainerStatuses{{Name: "first"}, {Name: "second"}},
expected: true,
},
{
statuses: SortedContainerStatuses{{Name: "second"}, {Name: "first"}},
expected: false,
},
}
for _, data := range cases {
actual := data.statuses.Less(0, 1)
if actual != data.expected {
t.Errorf(
"failed Less:\n\texpected: %t\n\t actual: %t",
data.expected,
actual,
)
}
}
}
func TestSortInitContainerStatuses(t *testing.T) {
pod := v1.Pod{
Spec: v1.PodSpec{},
}
var cases = []struct {
containers []v1.Container
statuses []v1.ContainerStatus
sortedStatuses []v1.ContainerStatus
}{
{
containers: []v1.Container{{Name: "first"}, {Name: "second"}, {Name: "third"}, {Name: "fourth"}},
statuses: []v1.ContainerStatus{{Name: "first"}, {Name: "second"}, {Name: "third"}, {Name: "fourth"}},
sortedStatuses: []v1.ContainerStatus{{Name: "first"}, {Name: "second"}, {Name: "third"}, {Name: "fourth"}},
},
{
containers: []v1.Container{{Name: "first"}, {Name: "second"}, {Name: "third"}, {Name: "fourth"}},
statuses: []v1.ContainerStatus{{Name: "second"}, {Name: "first"}, {Name: "fourth"}, {Name: "third"}},
sortedStatuses: []v1.ContainerStatus{{Name: "first"}, {Name: "second"}, {Name: "third"}, {Name: "fourth"}},
},
{
containers: []v1.Container{{Name: "first"}, {Name: "second"}, {Name: "third"}, {Name: "fourth"}},
statuses: []v1.ContainerStatus{{Name: "fourth"}, {Name: "first"}},
sortedStatuses: []v1.ContainerStatus{{Name: "first"}, {Name: "fourth"}},
},
{
containers: []v1.Container{{Name: "first"}, {Name: "second"}, {Name: "third"}, {Name: "fourth"}},
statuses: []v1.ContainerStatus{{Name: "first"}, {Name: "third"}},
sortedStatuses: []v1.ContainerStatus{{Name: "first"}, {Name: "third"}},
},
}
for _, data := range cases {
pod.Spec.InitContainers = data.containers
SortInitContainerStatuses(&pod, data.statuses)
if !reflect.DeepEqual(data.statuses, data.sortedStatuses) {
t.Errorf("SortInitContainerStatuses result wrong:\nContainers order: %v\nExpected order: %v\nReturne order: %v",
data.containers, data.sortedStatuses, data.statuses)
}
}
}

View file

@ -1,35 +0,0 @@
/*
Copyright 2016 The Kubernetes Authors.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package format
import (
"testing"
"k8s.io/api/core/v1"
"k8s.io/apimachinery/pkg/api/resource"
)
func TestResourceList(t *testing.T) {
resourceList := v1.ResourceList{}
resourceList[v1.ResourceCPU] = resource.MustParse("100m")
resourceList[v1.ResourceMemory] = resource.MustParse("5Gi")
actual := ResourceList(resourceList)
expected := "cpu=100m,memory=5Gi"
if actual != expected {
t.Errorf("Unexpected result, actual: %v, expected: %v", actual, expected)
}
}

View file

@ -1,222 +0,0 @@
/*
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 sliceutils
import (
"testing"
"k8s.io/api/core/v1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
kubecontainer "k8s.io/kubernetes/pkg/kubelet/container"
"time"
)
func TestStringInSlice(t *testing.T) {
fooTests := []struct {
s string
list []string
er bool
}{
{"first", []string{"first", "second"}, true},
{"FIRST", []string{"first", "second"}, false},
{"third", []string{"first", "second"}, false},
{"first", nil, false},
{"", []string{"first", "second"}, false},
{"", []string{"first", "second", ""}, true},
{"", nil, false},
}
for _, fooTest := range fooTests {
r := StringInSlice(fooTest.s, fooTest.list)
if r != fooTest.er {
t.Errorf("returned %t but expected %t for s=%s & list=%s", r, fooTest.er, fooTest.s, fooTest.list)
}
}
}
func buildPodsByCreationTime() PodsByCreationTime {
return []*v1.Pod{
{
ObjectMeta: metav1.ObjectMeta{
Name: "foo1",
Namespace: v1.NamespaceDefault,
CreationTimestamp: metav1.Time{
Time: time.Now(),
},
},
},
{
ObjectMeta: metav1.ObjectMeta{
Name: "foo2",
Namespace: v1.NamespaceDefault,
CreationTimestamp: metav1.Time{
Time: time.Now().Add(time.Hour * 1),
},
},
},
{
ObjectMeta: metav1.ObjectMeta{
Name: "foo3",
Namespace: v1.NamespaceDefault,
CreationTimestamp: metav1.Time{
Time: time.Now().Add(time.Hour * 2),
},
},
},
}
}
func TestPodsByCreationTimeLen(t *testing.T) {
fooTests := []struct {
pods PodsByCreationTime
el int
}{
{[]*v1.Pod{}, 0},
{buildPodsByCreationTime(), 3},
{[]*v1.Pod{nil, {}}, 2},
{nil, 0},
}
for _, fooTest := range fooTests {
r := fooTest.pods.Len()
if r != fooTest.el {
t.Errorf("returned %d but expected %d for the len of PodsByCreationTime=%s", r, fooTest.el, fooTest.pods)
}
}
}
func TestPodsByCreationTimeSwap(t *testing.T) {
fooTests := []struct {
pods PodsByCreationTime
i int
j int
}{
{buildPodsByCreationTime(), 0, 1},
{buildPodsByCreationTime(), 2, 1},
}
for _, fooTest := range fooTests {
fooi := fooTest.pods[fooTest.i]
fooj := fooTest.pods[fooTest.j]
fooTest.pods.Swap(fooTest.i, fooTest.j)
if fooi.GetName() != fooTest.pods[fooTest.j].GetName() || fooj.GetName() != fooTest.pods[fooTest.i].GetName() {
t.Errorf("failed to swap for %v", fooTest)
}
}
}
func TestPodsByCreationTimeLess(t *testing.T) {
fooTests := []struct {
pods PodsByCreationTime
i int
j int
er bool
}{
// ascending order
{buildPodsByCreationTime(), 0, 2, true},
{buildPodsByCreationTime(), 1, 0, false},
}
for _, fooTest := range fooTests {
r := fooTest.pods.Less(fooTest.i, fooTest.j)
if r != fooTest.er {
t.Errorf("returned %t but expected %t for the foo=%s", r, fooTest.er, fooTest.pods)
}
}
}
func buildByImageSize() ByImageSize {
return []kubecontainer.Image{
{
ID: "1",
RepoTags: []string{"foo-tag11", "foo-tag12"},
RepoDigests: []string{"foo-rd11", "foo-rd12"},
Size: 1,
},
{
ID: "2",
RepoTags: []string{"foo-tag21", "foo-tag22"},
RepoDigests: []string{"foo-rd21", "foo-rd22"},
Size: 2,
},
{
ID: "3",
RepoTags: []string{"foo-tag31", "foo-tag32"},
RepoDigests: []string{"foo-rd31", "foo-rd32"},
Size: 3,
},
}
}
func TestByImageSizeLen(t *testing.T) {
fooTests := []struct {
images ByImageSize
el int
}{
{[]kubecontainer.Image{}, 0},
{buildByImageSize(), 3},
{nil, 0},
}
for _, fooTest := range fooTests {
r := fooTest.images.Len()
if r != fooTest.el {
t.Errorf("returned %d but expected %d for the len of ByImageSize=%v", r, fooTest.el, fooTest.images)
}
}
}
func TestByImageSizeSwap(t *testing.T) {
fooTests := []struct {
images ByImageSize
i int
j int
}{
{buildByImageSize(), 0, 1},
{buildByImageSize(), 2, 1},
}
for _, fooTest := range fooTests {
fooi := fooTest.images[fooTest.i]
fooj := fooTest.images[fooTest.j]
fooTest.images.Swap(fooTest.i, fooTest.j)
if fooi.ID != fooTest.images[fooTest.j].ID || fooj.ID != fooTest.images[fooTest.i].ID {
t.Errorf("failed to swap for %v", fooTest)
}
}
}
func TestByImageSizeLess(t *testing.T) {
fooTests := []struct {
images ByImageSize
i int
j int
er bool
}{
// descending order
{buildByImageSize(), 0, 2, false},
{buildByImageSize(), 1, 0, true},
}
for _, fooTest := range fooTests {
r := fooTest.images.Less(fooTest.i, fooTest.j)
if r != fooTest.er {
t.Errorf("returned %t but expected %t for the foo=%v", r, fooTest.er, fooTest.images)
}
}
}

View file

@ -1,64 +0,0 @@
/*
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 util
import (
"testing"
"github.com/stretchr/testify/assert"
)
func TestParseEndpoint(t *testing.T) {
tests := []struct {
endpoint string
expectError bool
expectedProtocol string
expectedAddr string
}{
{
endpoint: "unix:///tmp/s1.sock",
expectedProtocol: "unix",
expectedAddr: "/tmp/s1.sock",
},
{
endpoint: "tcp://localhost:15880",
expectedProtocol: "tcp",
expectedAddr: "localhost:15880",
},
{
endpoint: "tcp1://abc",
expectedProtocol: "tcp1",
expectError: true,
},
{
endpoint: "a b c",
expectError: true,
},
}
for _, test := range tests {
protocol, addr, err := parseEndpoint(test.endpoint)
assert.Equal(t, test.expectedProtocol, protocol)
if test.expectError {
assert.NotNil(t, err, "Expect error during parsing %q", test.endpoint)
continue
}
assert.Nil(t, err, "Expect no error during parsing %q", test.endpoint)
assert.Equal(t, test.expectedAddr, addr)
}
}