Files
virtual-kubelet/vkubelet/pod_test.go
Jeremy Rickard 87e72bf4df Light up UpdatePod (#613)
* Light up UpdatePod

This PR updates the vkublet/pod.go createOrUpdate(..) method to actually handle
updates. It gets the pod from the provider as before, but now if it exists the method
checks the hash of the spec against the spec of the new pod. If they've changed, it
calls UpdatePod(..).

Also makes a small change to the Server struct to swap from kuberentes.Clientset to kubernetes.Interface
to better facilitate testing with fake ClientSet.

Co-Authored-By: Brian Goff <cpuguy83@gmail.com>
2019-05-17 11:14:29 -07:00

287 lines
6.0 KiB
Go

package vkubelet
import (
"context"
"testing"
"github.com/virtual-kubelet/virtual-kubelet/providers/mock"
testutil "github.com/virtual-kubelet/virtual-kubelet/test/util"
"gotest.tools/assert"
is "gotest.tools/assert/cmp"
corev1 "k8s.io/api/core/v1"
"k8s.io/client-go/kubernetes/fake"
)
type FakeProvider struct {
*mock.MockProvider
createFn func()
updateFn func()
}
func (f *FakeProvider) CreatePod(ctx context.Context, pod *corev1.Pod) error {
f.createFn()
return f.MockProvider.CreatePod(ctx, pod)
}
func (f *FakeProvider) UpdatePod(ctx context.Context, pod *corev1.Pod) error {
f.updateFn()
return f.MockProvider.CreatePod(ctx, pod)
}
type TestServer struct {
*Server
mock *FakeProvider
client *fake.Clientset
}
func newMockProvider(t *testing.T) (*mock.MockProvider, error) {
return mock.NewMockProviderMockConfig(
mock.MockConfig{},
"vk123",
"linux",
"127.0.0.1",
443,
)
}
func newTestServer(t *testing.T) *TestServer {
mockProvider, err := newMockProvider(t)
assert.Check(t, is.Nil(err))
fk8s := fake.NewSimpleClientset()
fakeProvider := &FakeProvider{
MockProvider: mockProvider,
}
rm := testutil.FakeResourceManager()
tsvr := &TestServer{
Server: &Server{
namespace: "default",
nodeName: "vk123",
provider: fakeProvider,
resourceManager: rm,
k8sClient: fk8s,
},
mock: fakeProvider,
client: fk8s,
}
return tsvr
}
func TestPodHashingEqual(t *testing.T) {
p1 := corev1.PodSpec{
Containers: []corev1.Container{
corev1.Container{
Name: "nginx",
Image: "nginx:1.15.12-perl",
Ports: []corev1.ContainerPort{
corev1.ContainerPort{
ContainerPort: 443,
Protocol: "tcp",
},
},
},
},
}
h1 := hashPodSpec(p1)
p2 := corev1.PodSpec{
Containers: []corev1.Container{
corev1.Container{
Name: "nginx",
Image: "nginx:1.15.12-perl",
Ports: []corev1.ContainerPort{
corev1.ContainerPort{
ContainerPort: 443,
Protocol: "tcp",
},
},
},
},
}
h2 := hashPodSpec(p2)
assert.Check(t, is.Equal(h1, h2))
}
func TestPodHashingDifferent(t *testing.T) {
p1 := corev1.PodSpec{
Containers: []corev1.Container{
corev1.Container{
Name: "nginx",
Image: "nginx:1.15.12",
Ports: []corev1.ContainerPort{
corev1.ContainerPort{
ContainerPort: 443,
Protocol: "tcp",
},
},
},
},
}
h1 := hashPodSpec(p1)
p2 := corev1.PodSpec{
Containers: []corev1.Container{
corev1.Container{
Name: "nginx",
Image: "nginx:1.15.12-perl",
Ports: []corev1.ContainerPort{
corev1.ContainerPort{
ContainerPort: 443,
Protocol: "tcp",
},
},
},
},
}
h2 := hashPodSpec(p2)
assert.Check(t, h1 != h2)
}
func TestPodCreateNewPod(t *testing.T) {
svr := newTestServer(t)
pod := &corev1.Pod{}
pod.ObjectMeta.Namespace = "default"
pod.ObjectMeta.Name = "nginx"
pod.Spec = corev1.PodSpec{
Containers: []corev1.Container{
corev1.Container{
Name: "nginx",
Image: "nginx:1.15.12",
Ports: []corev1.ContainerPort{
corev1.ContainerPort{
ContainerPort: 443,
Protocol: "tcp",
},
},
},
},
}
created := false
updated := false
// The pod doesn't exist, we should invoke the CreatePod() method of the provider
svr.mock.createFn = func() {
created = true
}
svr.mock.updateFn = func() {
updated = true
}
er := testutil.FakeEventRecorder(5)
err := svr.createOrUpdatePod(context.Background(), pod, er)
assert.Check(t, is.Nil(err))
// createOrUpdate called CreatePod but did not call UpdatePod because the pod did not exist
assert.Check(t, created)
assert.Check(t, !updated)
}
func TestPodUpdateExisting(t *testing.T) {
svr := newTestServer(t)
pod := &corev1.Pod{}
pod.ObjectMeta.Namespace = "default"
pod.ObjectMeta.Name = "nginx"
pod.Spec = corev1.PodSpec{
Containers: []corev1.Container{
corev1.Container{
Name: "nginx",
Image: "nginx:1.15.12",
Ports: []corev1.ContainerPort{
corev1.ContainerPort{
ContainerPort: 443,
Protocol: "tcp",
},
},
},
},
}
err := svr.mock.MockProvider.CreatePod(context.Background(), pod)
assert.Check(t, is.Nil(err))
created := false
updated := false
// The pod doesn't exist, we should invoke the CreatePod() method of the provider
svr.mock.createFn = func() {
created = true
}
svr.mock.updateFn = func() {
updated = true
}
pod2 := &corev1.Pod{}
pod2.ObjectMeta.Namespace = "default"
pod2.ObjectMeta.Name = "nginx"
pod2.Spec = corev1.PodSpec{
Containers: []corev1.Container{
corev1.Container{
Name: "nginx",
Image: "nginx:1.15.12-perl",
Ports: []corev1.ContainerPort{
corev1.ContainerPort{
ContainerPort: 443,
Protocol: "tcp",
},
},
},
},
}
er := testutil.FakeEventRecorder(5)
err = svr.createOrUpdatePod(context.Background(), pod2, er)
assert.Check(t, is.Nil(err))
// createOrUpdate didn't call CreatePod but did call UpdatePod because the spec changed
assert.Check(t, !created)
assert.Check(t, updated)
}
func TestPodNoSpecChange(t *testing.T) {
svr := newTestServer(t)
pod := &corev1.Pod{}
pod.ObjectMeta.Namespace = "default"
pod.ObjectMeta.Name = "nginx"
pod.Spec = corev1.PodSpec{
Containers: []corev1.Container{
corev1.Container{
Name: "nginx",
Image: "nginx:1.15.12",
Ports: []corev1.ContainerPort{
corev1.ContainerPort{
ContainerPort: 443,
Protocol: "tcp",
},
},
},
},
}
err := svr.mock.MockProvider.CreatePod(context.Background(), pod)
assert.Check(t, is.Nil(err))
created := false
updated := false
// The pod doesn't exist, we should invoke the CreatePod() method of the provider
svr.mock.createFn = func() {
created = true
}
svr.mock.updateFn = func() {
updated = true
}
er := testutil.FakeEventRecorder(5)
err = svr.createOrUpdatePod(context.Background(), pod, er)
assert.Check(t, is.Nil(err))
// createOrUpdate didn't call CreatePod or UpdatePod, spec didn't change
assert.Check(t, !created)
assert.Check(t, !updated)
}