diff --git a/pkg/kubelet/config/file_test.go b/pkg/kubelet/config/file_test.go index eebbcb1576228..44d1f9279f3e5 100644 --- a/pkg/kubelet/config/file_test.go +++ b/pkg/kubelet/config/file_test.go @@ -32,60 +32,6 @@ import ( "github.com/GoogleCloudPlatform/kubernetes/pkg/types" ) -// TODO(wojtek-t): Most of the test cases are pretty similar and introduce -// the same boilerplate. Refactor them similarly to what is done in http_test.go - -func ExampleManifestAndPod(id string) (v1beta1.ContainerManifest, api.Pod) { - hostname, _ := os.Hostname() - hostname = strings.ToLower(hostname) - - manifest := v1beta1.ContainerManifest{ - Version: "v1beta1", - ID: id, - UUID: types.UID(id), - Containers: []v1beta1.Container{ - { - Name: "c" + id, - Image: "foo", - TerminationMessagePath: "/somepath", - }, - }, - Volumes: []v1beta1.Volume{ - { - Name: "host-dir", - Source: v1beta1.VolumeSource{ - HostDir: &v1beta1.HostPathVolumeSource{"/dir/path"}, - }, - }, - }, - } - expectedPod := api.Pod{ - ObjectMeta: api.ObjectMeta{ - Name: id + "-" + hostname, - UID: types.UID(id), - Namespace: kubelet.NamespaceDefault, - SelfLink: "/api/v1beta2/pods/" + id + "-" + hostname + "?namespace=default", - }, - Spec: api.PodSpec{ - Containers: []api.Container{ - { - Name: "c" + id, - Image: "foo", - }, - }, - Volumes: []api.Volume{ - { - Name: "host-dir", - VolumeSource: api.VolumeSource{ - HostPath: &api.HostPathVolumeSource{"/dir/path"}, - }, - }, - }, - }, - } - return manifest, expectedPod -} - func TestExtractFromNonExistentFile(t *testing.T) { ch := make(chan interface{}, 1) c := sourceFile{"/some/fake/file", ch} @@ -123,113 +69,209 @@ func writeTestFile(t *testing.T, dir, name string, contents string) *os.File { return file } -func TestReadManifestFromFile(t *testing.T) { +func TestReadFromFile(t *testing.T) { hostname, _ := os.Hostname() hostname = strings.ToLower(hostname) - file := writeTestFile(t, os.TempDir(), "test_pod_config", - `{ - "version": "v1beta1", - "uuid": "12345", - "id": "test", - "containers": [{ "name": "image", "image": "test/image", imagePullPolicy: "PullAlways"}] - }`) - defer os.Remove(file.Name()) - - ch := make(chan interface{}) - NewSourceFile(file.Name(), time.Millisecond, ch) - select { - case got := <-ch: - update := got.(kubelet.PodUpdate) - expected := CreatePodUpdate(kubelet.SET, kubelet.FileSource, api.Pod{ - ObjectMeta: api.ObjectMeta{ - Name: "test-" + hostname, - UID: "12345", - Namespace: kubelet.NamespaceDefault, - SelfLink: "/api/v1beta2/pods/test-" + hostname + "?namespace=default", - }, - Spec: api.PodSpec{Containers: []api.Container{{Image: "test/image"}}}, - }) - - if !api.Semantic.DeepDerivative(expected, update) { - t.Fatalf("Expected %#v, Got %#v", expected, update) - } - - case <-time.After(time.Second): - t.Errorf("Expected update, timeout instead") + var testCases = []struct { + desc string + fileContents string + expected kubelet.PodUpdate + }{ + { + desc: "Manifest", + fileContents: `{ + "version": "v1beta1", + "uuid": "12345", + "id": "test", + "containers": [{ "name": "image", "image": "test/image", "imagePullPolicy": "PullAlways"}] + }`, + expected: CreatePodUpdate(kubelet.SET, kubelet.FileSource, api.Pod{ + ObjectMeta: api.ObjectMeta{ + Name: "test-" + hostname, + UID: "12345", + Namespace: kubelet.NamespaceDefault, + SelfLink: "/api/v1beta2/pods/test-" + hostname + "?namespace=default", + }, + Spec: api.PodSpec{ + RestartPolicy: api.RestartPolicyAlways, + DNSPolicy: api.DNSClusterFirst, + Containers: []api.Container{{ + Name: "image", + Image: "test/image", + TerminationMessagePath: "/dev/termination-log", + ImagePullPolicy: "Always"}}, + }, + }), + }, + { + desc: "Manifest without ID", + fileContents: `{ + "version": "v1beta1", + "uuid": "12345", + "containers": [{ "name": "image", "image": "test/image", "imagePullPolicy": "PullAlways"}] + }`, + expected: CreatePodUpdate(kubelet.SET, kubelet.FileSource, api.Pod{ + ObjectMeta: api.ObjectMeta{ + Name: "12345-" + hostname, + UID: "12345", + Namespace: kubelet.NamespaceDefault, + SelfLink: "/api/v1beta2/pods/12345-" + hostname + "?namespace=default", + }, + Spec: api.PodSpec{ + RestartPolicy: api.RestartPolicyAlways, + DNSPolicy: api.DNSClusterFirst, + Containers: []api.Container{{ + Name: "image", + Image: "test/image", + TerminationMessagePath: "/dev/termination-log", + ImagePullPolicy: "Always"}}, + }, + }), + }, + { + desc: "Manifest v1beta2", + fileContents: `{ + "version": "v1beta2", + "uuid": "12345", + "id": "test", + "containers": [{ "name": "image", "image": "test/image", "imagePullPolicy": "PullAlways"}] + }`, + expected: CreatePodUpdate(kubelet.SET, kubelet.FileSource, api.Pod{ + ObjectMeta: api.ObjectMeta{ + Name: "test-" + hostname, + UID: "12345", + Namespace: kubelet.NamespaceDefault, + SelfLink: "/api/v1beta2/pods/test-" + hostname + "?namespace=default", + }, + Spec: api.PodSpec{ + RestartPolicy: api.RestartPolicyAlways, + DNSPolicy: api.DNSClusterFirst, + Containers: []api.Container{{ + Name: "image", + Image: "test/image", + TerminationMessagePath: "/dev/termination-log", + ImagePullPolicy: "Always"}}, + }, + }), + }, + { + desc: "Simple pod", + fileContents: `{ + "kind": "Pod", + "apiVersion": "v1beta1", + "uid": "12345", + "id": "test", + "namespace": "mynamespace", + "desiredState": { + "manifest": { + "containers": [{ "name": "image", "image": "test/image" }], + }, + }, + }`, + expected: CreatePodUpdate(kubelet.SET, kubelet.FileSource, api.Pod{ + ObjectMeta: api.ObjectMeta{ + Name: "test-" + hostname, + UID: "12345", + Namespace: "mynamespace", + SelfLink: "/api/v1beta2/pods/test-" + hostname + "?namespace=mynamespace", + }, + Spec: api.PodSpec{ + RestartPolicy: api.RestartPolicyAlways, + DNSPolicy: api.DNSClusterFirst, + Containers: []api.Container{{ + Name: "image", + Image: "test/image", + TerminationMessagePath: "/dev/termination-log", + ImagePullPolicy: "IfNotPresent"}}, + }, + }), + }, + { + desc: "Pod without ID", + fileContents: `{ + "kind": "Pod", + "apiversion": "v1beta1", + "uid": "12345", + "desiredState": { + "manifest": { + "containers": [{ "name": "image", "image": "test/image" }], + }, + }, + }`, + expected: CreatePodUpdate(kubelet.SET, kubelet.FileSource, api.Pod{ + ObjectMeta: api.ObjectMeta{ + Name: "12345-" + hostname, + UID: "12345", + Namespace: kubelet.NamespaceDefault, + SelfLink: "/api/v1beta2/pods/12345-" + hostname + "?namespace=default", + }, + Spec: api.PodSpec{ + RestartPolicy: api.RestartPolicyAlways, + DNSPolicy: api.DNSClusterFirst, + Containers: []api.Container{{ + Name: "image", + Image: "test/image", + TerminationMessagePath: "/dev/termination-log", + ImagePullPolicy: "IfNotPresent"}}, + }, + }), + }, + { + desc: "Pod v1beta3", + fileContents: `{ + "kind": "Pod", + "apiversion": "v1beta3", + "metadata": { + "uid": "12345", + "name": "test", + }, + "spec": { + "containers": [{ "name": "image", "image": "test/image" }], + }, + }`, + expected: CreatePodUpdate(kubelet.SET, kubelet.FileSource, api.Pod{ + ObjectMeta: api.ObjectMeta{ + Name: "test-" + hostname, + UID: "12345", + Namespace: kubelet.NamespaceDefault, + SelfLink: "/api/v1beta2/pods/test-" + hostname + "?namespace=default", + }, + Spec: api.PodSpec{ + RestartPolicy: api.RestartPolicyAlways, + DNSPolicy: api.DNSClusterFirst, + Containers: []api.Container{{ + Name: "image", + Image: "test/image", + TerminationMessagePath: "/dev/termination-log", + ImagePullPolicy: "IfNotPresent"}}, + }, + }), + }, } -} - -func TestReadManifestFromFileWithoutID(t *testing.T) { - hostname, _ := os.Hostname() - hostname = strings.ToLower(hostname) - - file := writeTestFile(t, os.TempDir(), "test_pod_config", - `{ - "version": "v1beta1", - "uuid": "12345", - "containers": [{ "name": "image", "image": "test/image", imagePullPolicy: "PullAlways"}] - }`) - defer os.Remove(file.Name()) - ch := make(chan interface{}) - NewSourceFile(file.Name(), time.Millisecond, ch) - select { - case got := <-ch: - update := got.(kubelet.PodUpdate) - expected := CreatePodUpdate(kubelet.SET, kubelet.FileSource, api.Pod{ - ObjectMeta: api.ObjectMeta{ - Name: "12345-" + hostname, - UID: "12345", - Namespace: kubelet.NamespaceDefault, - SelfLink: "/api/v1beta2/pods/12345-" + hostname + "?namespace=default", - }, - Spec: api.PodSpec{Containers: []api.Container{{Image: "test/image"}}}, - }) - - if !api.Semantic.DeepDerivative(expected, update) { - t.Fatalf("Expected %#v, Got %#v", expected, update) - } - - case <-time.After(time.Second): - t.Errorf("Expected update, timeout instead") - } -} - -func TestReadManifestV1Beta2FromFile(t *testing.T) { - hostname, _ := os.Hostname() - hostname = strings.ToLower(hostname) - - file := writeTestFile(t, os.TempDir(), "test_pod_config", - `{ - "version": "v1beta2", - "uuid": "12345", - "id": "test", - "containers": [{ "name": "image", "image": "test/image", imagePullPolicy: "PullAlways"}] - }`) - defer os.Remove(file.Name()) - - ch := make(chan interface{}) - NewSourceFile(file.Name(), time.Millisecond, ch) - select { - case got := <-ch: - update := got.(kubelet.PodUpdate) - expected := CreatePodUpdate(kubelet.SET, kubelet.FileSource, api.Pod{ - ObjectMeta: api.ObjectMeta{ - Name: "test-" + hostname, - UID: "12345", - Namespace: kubelet.NamespaceDefault, - SelfLink: "/api/v1beta2/pods/test-" + hostname + "?namespace=default", - }, - Spec: api.PodSpec{Containers: []api.Container{{Image: "test/image"}}}, - }) - - if !api.Semantic.DeepDerivative(expected, update) { - t.Fatalf("Expected %#v, Got %#v", expected, update) - } - - case <-time.After(time.Second): - t.Errorf("Expected update, timeout instead") + for _, testCase := range testCases { + func() { + file := writeTestFile(t, os.TempDir(), "test_pod_config", testCase.fileContents) + defer os.Remove(file.Name()) + + ch := make(chan interface{}) + NewSourceFile(file.Name(), time.Millisecond, ch) + select { + case got := <-ch: + update := got.(kubelet.PodUpdate) + for _, pod := range update.Pods { + if errs := validation.ValidatePod(&pod); len(errs) > 0 { + t.Errorf("%s: Invalid pod %#v, %#v", testCase.desc, pod, errs) + } + } + if !api.Semantic.DeepEqual(testCase.expected, update) { + t.Errorf("%s: Expected %#v, Got %#v", testCase.desc, testCase.expected, update) + } + case <-time.After(time.Second): + t.Errorf("%s: Expected update, timeout instead", testCase.desc) + } + }() } } @@ -256,132 +298,6 @@ func TestReadManifestFromFileWithDefaults(t *testing.T) { } } -func TestReadPodFromFile(t *testing.T) { - hostname, _ := os.Hostname() - hostname = strings.ToLower(hostname) - - file := writeTestFile(t, os.TempDir(), "test_pod_config", - `{ - "kind": "Pod", - "apiVersion": "v1beta1", - "uid": "12345", - "id": "test", - "namespace": "mynamespace", - "desiredState": { - "manifest": { - "containers": [{ "name": "image", "image": "test/image" }], - }, - }, - }`) - defer os.Remove(file.Name()) - - ch := make(chan interface{}) - NewSourceFile(file.Name(), time.Millisecond, ch) - select { - case got := <-ch: - update := got.(kubelet.PodUpdate) - expected := CreatePodUpdate(kubelet.SET, kubelet.FileSource, api.Pod{ - ObjectMeta: api.ObjectMeta{ - Name: "test-" + hostname, - UID: "12345", - Namespace: "mynamespace", - SelfLink: "/api/v1beta2/pods/test-" + hostname + "?namespace=mynamespace", - }, - Spec: api.PodSpec{Containers: []api.Container{{Image: "test/image"}}}, - }) - - if !api.Semantic.DeepDerivative(expected, update) { - t.Fatalf("Expected %#v, Got %#v", expected, update) - } - - case <-time.After(time.Second): - t.Errorf("Expected update, timeout instead") - } -} - -func TestReadPodV1Beta3FromFile(t *testing.T) { - hostname, _ := os.Hostname() - hostname = strings.ToLower(hostname) - - file := writeTestFile(t, os.TempDir(), "test_pod_config", - `{ - "kind": "Pod", - "apiversion": "v1beta3", - "metadata": { - "uid": "12345", - "name": "test", - }, - "spec": { - "containers": [{ "name": "image", "image": "test/image" }], - }, - }`) - defer os.Remove(file.Name()) - - ch := make(chan interface{}) - NewSourceFile(file.Name(), time.Millisecond, ch) - select { - case got := <-ch: - update := got.(kubelet.PodUpdate) - expected := CreatePodUpdate(kubelet.SET, kubelet.FileSource, api.Pod{ - ObjectMeta: api.ObjectMeta{ - Name: "test-" + hostname, - UID: "12345", - Namespace: kubelet.NamespaceDefault, - SelfLink: "/api/v1beta2/pods/test-" + hostname + "?namespace=default", - }, - Spec: api.PodSpec{Containers: []api.Container{{Image: "test/image"}}}, - }) - - if !api.Semantic.DeepDerivative(expected, update) { - t.Fatalf("Expected %#v, Got %#v", expected, update) - } - - case <-time.After(time.Second): - t.Errorf("Expected update, timeout instead") - } -} - -func TestReadPodFromFileWithoutID(t *testing.T) { - hostname, _ := os.Hostname() - hostname = strings.ToLower(hostname) - - file := writeTestFile(t, os.TempDir(), "test_pod_config", - `{ - "kind": "Pod", - "apiversion": "v1beta1", - "uid": "12345", - "DesiredState": { - "Manifest": { - "containers": [{ "name": "image", "image": "test/image" }], - }, - }, - }`) - defer os.Remove(file.Name()) - - ch := make(chan interface{}) - NewSourceFile(file.Name(), time.Millisecond, ch) - select { - case got := <-ch: - update := got.(kubelet.PodUpdate) - expected := CreatePodUpdate(kubelet.SET, kubelet.FileSource, api.Pod{ - ObjectMeta: api.ObjectMeta{ - Name: "12345-" + hostname, - UID: "12345", - Namespace: kubelet.NamespaceDefault, - SelfLink: "/api/v1beta2/pods/12345-" + hostname + "?namespace=default", - }, - Spec: api.PodSpec{Containers: []api.Container{{Image: "test/image"}}}, - }) - - if !api.Semantic.DeepDerivative(expected, update) { - t.Fatalf("Expected %#v, Got %#v", expected, update) - } - - case <-time.After(time.Second): - t.Errorf("Expected update, timeout instead") - } -} - func TestExtractFromBadDataFile(t *testing.T) { file := writeTestFile(t, os.TempDir(), "test_pod_config", string([]byte{1, 2, 3})) defer os.Remove(file.Name()) @@ -411,11 +327,62 @@ func TestExtractFromEmptyDir(t *testing.T) { update := (<-ch).(kubelet.PodUpdate) expected := CreatePodUpdate(kubelet.SET, kubelet.FileSource) - if !api.Semantic.DeepDerivative(expected, update) { + if !api.Semantic.DeepEqual(expected, update) { t.Errorf("Expected %#v, Got %#v", expected, update) } } +func ExampleManifestAndPod(id string) (v1beta1.ContainerManifest, api.Pod) { + hostname, _ := os.Hostname() + hostname = strings.ToLower(hostname) + + manifest := v1beta1.ContainerManifest{ + Version: "v1beta1", + ID: id, + UUID: types.UID(id), + Containers: []v1beta1.Container{ + { + Name: "c" + id, + Image: "foo", + TerminationMessagePath: "/somepath", + }, + }, + Volumes: []v1beta1.Volume{ + { + Name: "host-dir", + Source: v1beta1.VolumeSource{ + HostDir: &v1beta1.HostPathVolumeSource{"/dir/path"}, + }, + }, + }, + } + expectedPod := api.Pod{ + ObjectMeta: api.ObjectMeta{ + Name: id + "-" + hostname, + UID: types.UID(id), + Namespace: kubelet.NamespaceDefault, + SelfLink: "/api/v1beta2/pods/" + id + "-" + hostname + "?namespace=default", + }, + Spec: api.PodSpec{ + Containers: []api.Container{ + { + Name: "c" + id, + Image: "foo", + }, + }, + Volumes: []api.Volume{ + { + Name: "host-dir", + VolumeSource: api.VolumeSource{ + HostPath: &api.HostPathVolumeSource{"/dir/path"}, + }, + }, + }, + }, + } + return manifest, expectedPod +} + func TestExtractFromDir(t *testing.T) { manifest, expectedPod := ExampleManifestAndPod("1") manifest2, expectedPod2 := ExampleManifestAndPod("2")