func TestReadManifestFromFileWithDefaults(t *testing.T) {
	if !api.PreV1Beta3(testapi.Version()) {
		return
	}
	file := writeTestFile(t, os.TempDir(), "test_pod_config",
		fmt.Sprintf(`{
			"version": "%s",
			"id": "test",
			"containers": [{ "name": "image", "image": "test/image" }]
		}`, testapi.Version()))
	defer os.Remove(file.Name())

	ch := make(chan interface{})
	NewSourceFile(file.Name(), "localhost", time.Millisecond, ch)
	select {
	case got := <-ch:
		update := got.(kubelet.PodUpdate)
		if update.Pods[0].UID == "" {
			t.Errorf("Unexpected UID: %s", update.Pods[0].UID)
		}

	case <-time.After(time.Second):
		t.Errorf("Expected update, timeout instead")
	}
}
Example #2
0
func TestPodTemplateList(t *testing.T) {
	if api.PreV1Beta3(testapi.Version()) {
		return
	}

	ns := api.NamespaceDefault
	podTemplateList := &api.PodTemplateList{
		Items: []api.PodTemplate{
			{
				ObjectMeta: api.ObjectMeta{
					Name:      "foo",
					Namespace: ns,
				},
			},
		},
	}
	c := &testClient{
		Request: testRequest{
			Method: "GET",
			Path:   testapi.ResourcePath(getPodTemplatesResoureName(), ns, ""),
			Query:  buildQueryValues(ns, nil),
			Body:   nil,
		},
		Response: Response{StatusCode: 200, Body: podTemplateList},
	}
	response, err := c.Setup().PodTemplates(ns).List(labels.Everything(), fields.Everything())
	c.Validate(t, response, err)
}
func makeTestServer(t *testing.T, namespace, name string, podResponse, controllerResponse, updateResponse serverResponse) (*httptest.Server, *util.FakeHandler) {
	fakePodHandler := util.FakeHandler{
		StatusCode:   podResponse.statusCode,
		ResponseBody: runtime.EncodeOrDie(testapi.Codec(), podResponse.obj.(runtime.Object)),
	}
	fakeControllerHandler := util.FakeHandler{
		StatusCode:   controllerResponse.statusCode,
		ResponseBody: runtime.EncodeOrDie(testapi.Codec(), controllerResponse.obj.(runtime.Object)),
	}
	fakeUpdateHandler := util.FakeHandler{
		StatusCode:   updateResponse.statusCode,
		ResponseBody: runtime.EncodeOrDie(testapi.Codec(), updateResponse.obj.(runtime.Object)),
	}
	mux := http.NewServeMux()
	mux.Handle(testapi.ResourcePath("pods", namespace, ""), &fakePodHandler)
	mux.Handle(testapi.ResourcePath(replicationControllerResourceName(), "", ""), &fakeControllerHandler)
	if !api.PreV1Beta3(testapi.Version()) && namespace != "" {
		mux.Handle(testapi.ResourcePath(replicationControllerResourceName(), namespace, ""), &fakeControllerHandler)
	}
	if name != "" {
		mux.Handle(testapi.ResourcePath(replicationControllerResourceName(), namespace, name), &fakeUpdateHandler)
	}
	mux.HandleFunc("/", func(res http.ResponseWriter, req *http.Request) {
		t.Errorf("unexpected request: %v", req.RequestURI)
		res.WriteHeader(http.StatusNotFound)
	})
	return httptest.NewServer(mux), &fakeUpdateHandler
}
Example #4
0
func init() {
	if api.PreV1Beta3(testapi.Version()) {
		nodeResourceName = "minions"
	} else {
		nodeResourceName = "nodes"
	}
}
Example #5
0
func TestPodTemplateGet(t *testing.T) {
	if api.PreV1Beta3(testapi.Version()) {
		return
	}

	ns := api.NamespaceDefault
	podTemplate := &api.PodTemplate{
		ObjectMeta: api.ObjectMeta{
			Name:      "abc",
			Namespace: ns,
		},
		Template: api.PodTemplateSpec{},
	}
	c := &testClient{
		Request: testRequest{
			Method: "GET",
			Path:   testapi.ResourcePath(getPodTemplatesResoureName(), ns, "abc"),
			Query:  buildQueryValues(ns, nil),
			Body:   nil,
		},
		Response: Response{StatusCode: 200, Body: podTemplate},
	}

	response, err := c.Setup().PodTemplates(ns).Get("abc")
	c.Validate(t, response, err)
}
Example #6
0
func ResourcePathWithPrefixAndNamespaceQuery(prefix, resource, namespace, name string) string {
	path := ResourcePathWithPrefix(prefix, resource, namespace, name)
	// Add namespace as query param for pre v1beta3.
	if api.PreV1Beta3(Version()) && namespace != "" {
		path = path + "?namespace=" + namespace
	}
	return path
}
Example #7
0
// Delete deletes an existing service.
func (c *services) Delete(name string) error {
	// v1beta3 does not allow DELETE without a namespace.
	needNamespace := !api.PreV1Beta3(c.r.APIVersion())
	namespace := c.ns
	if needNamespace && len(namespace) == 0 {
		namespace = api.NamespaceDefault
	}
	return c.r.Delete().Namespace(c.ns).Resource("services").Name(name).Do().Error()
}
func TestExtractFromDir(t *testing.T) {
	if !api.PreV1Beta3(testapi.Version()) {
		return
	}
	manifest, expectedPod := exampleManifestAndPod("1")
	manifest2, expectedPod2 := exampleManifestAndPod("2")

	manifests := []v1beta1.ContainerManifest{manifest, manifest2}
	pods := []*api.Pod{expectedPod, expectedPod2}
	files := make([]*os.File, len(manifests))

	dirName, err := ioutil.TempDir("", "foo")
	if err != nil {
		t.Fatalf("Unexpected error: %v", err)
	}

	for i, manifest := range manifests {
		data, err := json.Marshal(manifest)
		if err != nil {
			t.Errorf("Unexpected error: %v", err)
			continue
		}
		file, err := ioutil.TempFile(dirName, manifest.ID)
		if err != nil {
			t.Errorf("Unexpected error: %v", err)
			continue
		}
		name := file.Name()
		if err := file.Close(); err != nil {
			t.Errorf("Unexpected error: %v", err)
			continue
		}
		ioutil.WriteFile(name, data, 0755)
		files[i] = file
	}

	ch := make(chan interface{}, 1)
	c := sourceFile{dirName, "an-example-host", ch}
	err = c.extractFromPath()
	if err != nil {
		t.Fatalf("Unexpected error: %v", err)
	}

	update := (<-ch).(kubelet.PodUpdate)
	expected := CreatePodUpdate(kubelet.SET, kubelet.FileSource, pods...)
	sort.Sort(sortedPods(update.Pods))
	sort.Sort(sortedPods(expected.Pods))
	if !api.Semantic.DeepDerivative(expected, update) {
		t.Fatalf("Expected %#v, Got %#v", expected, update)
	}
	for _, pod := range update.Pods {
		if errs := validation.ValidatePod(pod); len(errs) != 0 {
			t.Errorf("Expected no validation errors on %#v, Got %q", pod, errs)
		}
	}
}
Example #9
0
// Create creates a new service.
func (c *services) Create(svc *api.Service) (result *api.Service, err error) {
	result = &api.Service{}
	// v1beta3 does not allow POST without a namespace.
	needNamespace := !api.PreV1Beta3(c.r.APIVersion())
	namespace := c.ns
	if needNamespace && len(namespace) == 0 {
		namespace = api.NamespaceDefault
	}
	err = c.r.Post().Namespace(namespace).Resource("services").Body(svc).Do().Into(result)
	return
}
Example #10
0
func getSelfLink(name, namespace string) string {
	var selfLink string
	if api.PreV1Beta3(latest.Version) {
		selfLink = fmt.Sprintf("/api/"+latest.Version+"/pods/%s?namespace=%s", name, namespace)
	} else {
		if len(namespace) == 0 {
			namespace = api.NamespaceDefault
		}
		selfLink = fmt.Sprintf("/api/"+latest.Version+"/pods/namespaces/%s/%s", name, namespace)
	}
	return selfLink
}
Example #11
0
func TestPodTemplateDelete(t *testing.T) {
	if api.PreV1Beta3(testapi.Version()) {
		return
	}

	ns := api.NamespaceDefault
	c := &testClient{
		Request:  testRequest{Method: "DELETE", Path: testapi.ResourcePath(getPodTemplatesResoureName(), ns, "foo"), Query: buildQueryValues(ns, nil)},
		Response: Response{StatusCode: 200},
	}
	err := c.Setup().PodTemplates(ns).Delete("foo", nil)
	c.Validate(t, nil, err)
}
func parseResourceVersion(response []byte) (string, float64, error) {
	var resultBodyMap map[string]interface{}
	err := json.Unmarshal(response, &resultBodyMap)
	if err != nil {
		return "", 0, fmt.Errorf("unexpected error unmarshaling resultBody: %v", err)
	}
	apiVersion, ok := resultBodyMap["apiVersion"].(string)
	if !ok {
		return "", 0, fmt.Errorf("unexpected error, apiVersion not found in JSON response: %v", string(response))
	}
	if api.PreV1Beta3(apiVersion) {
		return parsePreV1Beta3ResourceVersion(resultBodyMap, response)
	}
	return parseV1Beta3ResourceVersion(resultBodyMap, response)
}
Example #13
0
func TestPodTemplateWatch(t *testing.T) {
	if api.PreV1Beta3(testapi.Version()) {
		return
	}

	c := &testClient{
		Request: testRequest{
			Method: "GET",
			Path:   "/api/" + testapi.Version() + "/watch/" + getPodTemplatesResoureName(),
			Query:  url.Values{"resourceVersion": []string{}}},
		Response: Response{StatusCode: 200},
	}
	_, err := c.Setup().PodTemplates(api.NamespaceAll).Watch(labels.Everything(), fields.Everything(), "")
	c.Validate(t, nil, err)
}
Example #14
0
// Update updates an existing service.
func (c *services) Update(svc *api.Service) (result *api.Service, err error) {
	result = &api.Service{}
	if len(svc.ResourceVersion) == 0 {
		err = fmt.Errorf("invalid update object, missing resource version: %v", svc)
		return
	}
	// v1beta3 does not allow PUT without a namespace.
	needNamespace := !api.PreV1Beta3(c.r.APIVersion())
	namespace := c.ns
	if needNamespace && len(namespace) == 0 {
		namespace = api.NamespaceDefault
	}
	err = c.r.Put().Namespace(namespace).Resource("services").Name(svc.Name).Body(svc).Do().Into(result)
	return
}
Example #15
0
// buildQueryValues is a convenience function for knowing if a namespace should be in a query param or not
func buildQueryValues(namespace string, query url.Values) url.Values {
	v := url.Values{}
	if query != nil {
		for key, values := range query {
			for _, value := range values {
				v.Add(key, value)
			}
		}
	}
	if len(namespace) > 0 {
		if api.PreV1Beta3(testapi.Version()) {
			v.Set("namespace", namespace)
		}
	}
	return v
}
func getFakeClient(t *testing.T, validURLs []string) (ClientPosterFunc, *httptest.Server) {
	handlerFunc := func(w http.ResponseWriter, r *http.Request) {
		for _, u := range validURLs {
			if u == r.RequestURI {
				return
			}
		}
		t.Errorf("Unexpected HTTP request: %s, expected %v", r.RequestURI, validURLs)
	}
	server := httptest.NewServer(http.HandlerFunc(handlerFunc))
	return func(mapping *meta.RESTMapping) (RESTClientPoster, error) {
		fakeCodec := testapi.Codec()
		fakeUri, _ := url.Parse(server.URL + "/api/" + testapi.Version())
		legacyBehavior := api.PreV1Beta3(testapi.Version())
		return client.NewRESTClient(fakeUri, testapi.Version(), fakeCodec, legacyBehavior, 5, 10), nil
	}, server
}
Example #17
0
// Returns the appropriate path for the given prefix (watch, proxy, redirect, etc), resource, namespace and name.
// For ex, this is of the form:
// /api/v1beta1/watch/pods/pod0 for v1beta1 and
// /api/v1beta3/watch/namespaces/foo/pods/pod0 for v1beta3.
func ResourcePathWithPrefix(prefix, resource, namespace, name string) string {
	path := "/api/" + Version()
	if prefix != "" {
		path = path + "/" + prefix
	}
	if !api.PreV1Beta3(Version()) {
		if namespace != "" {
			path = path + "/namespaces/" + namespace
		}
		// Resource names in v1beta3 are lower case.
		resource = strings.ToLower(resource)
	}
	if resource != "" {
		path = path + "/" + resource
	}
	if name != "" {
		path = path + "/" + name
	}
	return path
}
// WebHookURL returns the URL for the provided build config name and trigger policy, or ErrTriggerIsNotAWebHook
// if the trigger is not a webhook type.
func (c *buildConfigs) WebHookURL(name string, trigger *buildapi.BuildTriggerPolicy) (*url.URL, error) {
	if kapi.PreV1Beta3(c.r.APIVersion()) {
		switch {
		case trigger.GenericWebHook != nil:
			return c.r.Get().Namespace(c.ns).Resource("buildConfigHooks").Name(name).Suffix(trigger.GenericWebHook.Secret, "generic").URL(), nil
		case trigger.GitHubWebHook != nil:
			return c.r.Get().Namespace(c.ns).Resource("buildConfigHooks").Name(name).Suffix(trigger.GitHubWebHook.Secret, "github").URL(), nil
		default:
			return nil, ErrTriggerIsNotAWebHook
		}
	}
	switch {
	case trigger.GenericWebHook != nil:
		return c.r.Get().Namespace(c.ns).Resource("buildConfigs").Name(name).SubResource("webhooks").Suffix(trigger.GenericWebHook.Secret, "generic").URL(), nil
	case trigger.GitHubWebHook != nil:
		return c.r.Get().Namespace(c.ns).Resource("buildConfigs").Name(name).SubResource("webhooks").Suffix(trigger.GitHubWebHook.Secret, "github").URL(), nil
	default:
		return nil, ErrTriggerIsNotAWebHook
	}
}
func getSCCResoureName() string {
	if api.PreV1Beta3(testapi.Version()) {
		return "securityContextConstraints"
	}
	return "securitycontextconstraints"
}
func getPersistentVolumeClaimsResoureName() string {
	if api.PreV1Beta3(testapi.Version()) {
		return "persistentVolumeClaims"
	}
	return "persistentvolumeclaims"
}
Example #21
0
func getLimitRangesResourceName() string {
	if api.PreV1Beta3(testapi.Version()) {
		return "limitRanges"
	}
	return "limitranges"
}
Example #22
0
func getNodesResourceName() string {
	if api.PreV1Beta3(testapi.Version()) {
		return "minions"
	}
	return "nodes"
}
Example #23
0
func TestTemplateStrings(t *testing.T) {
	// This unit tests the "exists" function as well as the template from update.sh
	table := map[string]struct {
		pod    api.Pod
		expect string
	}{
		"nilInfo":   {api.Pod{}, "false"},
		"emptyInfo": {api.Pod{Status: api.PodStatus{ContainerStatuses: []api.ContainerStatus{}}}, "false"},
		"fooExists": {
			api.Pod{
				Status: api.PodStatus{
					ContainerStatuses: []api.ContainerStatus{
						{
							Name: "foo",
						},
					},
				},
			},
			"false",
		},
		"barExists": {
			api.Pod{
				Status: api.PodStatus{
					ContainerStatuses: []api.ContainerStatus{
						{
							Name: "bar",
						},
					},
				},
			},
			"false",
		},
		"bothExist": {
			api.Pod{
				Status: api.PodStatus{
					ContainerStatuses: []api.ContainerStatus{
						{
							Name: "foo",
						},
						{
							Name: "bar",
						},
					},
				},
			},
			"false",
		},
		"barValid": {
			api.Pod{
				Status: api.PodStatus{
					ContainerStatuses: []api.ContainerStatus{
						{
							Name: "foo",
						},
						{
							Name: "bar",
							State: api.ContainerState{
								Running: &api.ContainerStateRunning{
									StartedAt: util.Time{},
								},
							},
						},
					},
				},
			},
			"false",
		},
		"bothValid": {
			api.Pod{
				Status: api.PodStatus{
					ContainerStatuses: []api.ContainerStatus{
						{
							Name: "foo",
							State: api.ContainerState{
								Running: &api.ContainerStateRunning{
									StartedAt: util.Time{},
								},
							},
						},
						{
							Name: "bar",
							State: api.ContainerState{
								Running: &api.ContainerStateRunning{
									StartedAt: util.Time{},
								},
							},
						},
					},
				},
			},
			"true",
		},
	}
	// The point of this test is to verify that the below template works. If you change this
	// template, you need to update hack/e2e-suite/update.sh.
	tmpl := ``
	if api.PreV1Beta3(testapi.Version()) {
		tmpl = `{{exists . "currentState" "info" "foo" "state" "running"}}`
		useThisToDebug := `
a: {{exists . "currentState"}}
b: {{exists . "currentState" "info"}}
c: {{exists . "currentState" "info" "foo"}}
d: {{exists . "currentState" "info" "foo" "state"}}
e: {{exists . "currentState" "info" "foo" "state" "running"}}
f: {{exists . "currentState" "info" "foo" "state" "running" "startedAt"}}`
		_ = useThisToDebug // don't complain about unused var
	} else {
		tmpl = `{{if (exists . "status" "containerStatuses")}}{{range .status.containerStatuses}}{{if (and (eq .name "foo") (exists . "state" "running"))}}true{{end}}{{end}}{{end}}`
	}
	p, err := NewTemplatePrinter([]byte(tmpl))
	if err != nil {
		t.Fatalf("tmpl fail: %v", err)
	}

	printer := NewVersionedPrinter(p, api.Scheme, testapi.Version())

	for name, item := range table {
		buffer := &bytes.Buffer{}
		err = printer.PrintObj(&item.pod, buffer)
		if err != nil {
			t.Errorf("%v: unexpected err: %v", name, err)
			continue
		}
		actual := buffer.String()
		if len(actual) == 0 {
			actual = "false"
		}
		if e := item.expect; e != actual {
			t.Errorf("%v: expected %v, got %v", name, e, actual)
		}
	}
}
Example #24
0
// Returns the appropriate field label to use for name of the involved object as per the given API version.
func getInvolvedObjectNameFieldLabel(version string) string {
	if api.PreV1Beta3(version) {
		return "involvedObject.id"
	}
	return "involvedObject.name"
}
func TestExtractManifestFromHTTP(t *testing.T) {
	hostname := "random-hostname"
	// ContainerManifests are not supported v1beta3 onwards.
	if api.PreV1Beta3(testapi.Version()) {
		return
	}

	var testCases = []struct {
		desc      string
		manifests interface{}
		expected  kubelet.PodUpdate
	}{
		{
			desc: "Single manifest",
			manifests: v1beta1.ContainerManifest{Version: "v1beta1", ID: "foo", UUID: "111",
				Containers: []v1beta1.Container{{Name: "1", Image: "foo", ImagePullPolicy: v1beta1.PullAlways}}},
			expected: CreatePodUpdate(kubelet.SET,
				kubelet.HTTPSource,
				&api.Pod{
					ObjectMeta: api.ObjectMeta{
						UID:       "111",
						Name:      "foo" + "-" + hostname,
						Namespace: "foobar",

						SelfLink: getSelfLink("foo-"+hostname, kubelet.NamespaceDefault),
					},
					Spec: api.PodSpec{
						Host:          hostname,
						RestartPolicy: api.RestartPolicyAlways,
						DNSPolicy:     api.DNSClusterFirst,
						Containers: []api.Container{{
							Name:  "1",
							Image: "foo",
							TerminationMessagePath: "/dev/termination-log",
							ImagePullPolicy:        "Always"}},
					},
				}),
		},
		{
			desc: "Single manifest without ID",
			manifests: v1beta1.ContainerManifest{Version: "v1beta1", UUID: "111",
				Containers: []v1beta1.Container{{Name: "ctr", Image: "image", ImagePullPolicy: "IfNotPresent"}}},
			expected: CreatePodUpdate(kubelet.SET,
				kubelet.HTTPSource,
				&api.Pod{
					ObjectMeta: api.ObjectMeta{
						UID:       "111",
						Name:      "111" + "-" + hostname,
						Namespace: "foobar",

						SelfLink: getSelfLink("111-"+hostname, kubelet.NamespaceDefault),
					},
					Spec: api.PodSpec{
						Host:          hostname,
						RestartPolicy: api.RestartPolicyAlways,
						DNSPolicy:     api.DNSClusterFirst,
						Containers: []api.Container{{
							Name:  "ctr",
							Image: "image",
							TerminationMessagePath: "/dev/termination-log",
							ImagePullPolicy:        "IfNotPresent"}},
					},
				}),
		},
		{
			desc: "Single manifest with v1beta2",
			manifests: v1beta1.ContainerManifest{Version: "v1beta2", ID: "foo", UUID: "111",
				Containers: []v1beta1.Container{{Name: "1", Image: "foo", ImagePullPolicy: v1beta1.PullAlways}}},
			expected: CreatePodUpdate(kubelet.SET,
				kubelet.HTTPSource,
				&api.Pod{
					ObjectMeta: api.ObjectMeta{
						UID:       "111",
						Name:      "foo" + "-" + hostname,
						Namespace: "foobar",

						SelfLink: getSelfLink("foo-"+hostname, kubelet.NamespaceDefault),
					},
					Spec: api.PodSpec{
						Host:          hostname,
						RestartPolicy: api.RestartPolicyAlways,
						DNSPolicy:     api.DNSClusterFirst,
						Containers: []api.Container{{
							Name:  "1",
							Image: "foo",
							TerminationMessagePath: "/dev/termination-log",
							ImagePullPolicy:        "Always"}},
					},
				}),
		},
		{
			desc: "Multiple manifests",
			manifests: []v1beta1.ContainerManifest{
				{Version: "v1beta1", ID: "foo", UUID: "111",
					Containers: []v1beta1.Container{{Name: "1", Image: "foo", ImagePullPolicy: v1beta1.PullAlways}}},
				{Version: "v1beta1", ID: "bar", UUID: "222",
					Containers: []v1beta1.Container{{Name: "1", Image: "foo", ImagePullPolicy: ""}}},
			},
			expected: CreatePodUpdate(kubelet.SET,
				kubelet.HTTPSource,
				&api.Pod{
					ObjectMeta: api.ObjectMeta{
						UID:       "111",
						Name:      "foo" + "-" + hostname,
						Namespace: "foobar",

						SelfLink: getSelfLink("foo-"+hostname, kubelet.NamespaceDefault),
					},
					Spec: api.PodSpec{
						Host:          hostname,
						RestartPolicy: api.RestartPolicyAlways,
						DNSPolicy:     api.DNSClusterFirst,
						Containers: []api.Container{{
							Name:  "1",
							Image: "foo",
							TerminationMessagePath: "/dev/termination-log",
							ImagePullPolicy:        "Always"}},
					},
				},
				&api.Pod{
					ObjectMeta: api.ObjectMeta{
						UID:       "222",
						Name:      "bar" + "-" + hostname,
						Namespace: "foobar",

						SelfLink: getSelfLink("bar-"+hostname, kubelet.NamespaceDefault),
					},
					Spec: api.PodSpec{
						Host:          hostname,
						RestartPolicy: api.RestartPolicyAlways,
						DNSPolicy:     api.DNSClusterFirst,
						Containers: []api.Container{{
							Name:  "1",
							Image: "foo",
							TerminationMessagePath: "/dev/termination-log",
							ImagePullPolicy:        "IfNotPresent"}},
					},
				}),
		},
		{
			desc:      "Empty Array",
			manifests: []v1beta1.ContainerManifest{},
			expected:  CreatePodUpdate(kubelet.SET, kubelet.HTTPSource),
		},
	}

	for _, testCase := range testCases {
		data, err := json.Marshal(testCase.manifests)
		if err != nil {
			t.Fatalf("%s: Some weird json problem: %v", testCase.desc, err)
		}
		fakeHandler := util.FakeHandler{
			StatusCode:   200,
			ResponseBody: string(data),
		}
		testServer := httptest.NewServer(&fakeHandler)
		defer testServer.Close()
		ch := make(chan interface{}, 1)
		c := sourceURL{testServer.URL, hostname, ch, nil}
		if err := c.extractFromURL(); err != nil {
			t.Errorf("%s: Unexpected error: %v", testCase.desc, err)
			continue
		}
		update := (<-ch).(kubelet.PodUpdate)

		for i := range update.Pods {
			// There's no way to provide namespace in ContainerManifest, so
			// it will be defaulted.
			if update.Pods[i].Namespace != kubelet.NamespaceDefault {
				t.Errorf("Unexpected namespace: %s", update.Pods[0].Namespace)
			}
			update.Pods[i].ObjectMeta.Namespace = "foobar"
		}
		if !api.Semantic.DeepEqual(testCase.expected, update) {
			t.Errorf("%s: Expected: %#v, Got: %#v", testCase.desc, testCase.expected, update)
		}
		for _, pod := range update.Pods {
			if errs := validation.ValidatePod(pod); len(errs) != 0 {
				t.Errorf("%s: Expected no validation errors on %#v, Got %v", testCase.desc, pod, errors.NewAggregate(errs))
			}
		}
	}
}
// resourceName returns node's URL resource name based on resource version.
// Uses "minions" as the URL resource name for v1beta1 and v1beta2.
func (c *nodes) resourceName() string {
	if api.PreV1Beta3(c.r.APIVersion()) {
		return "minions"
	}
	return "nodes"
}
func getResourceQuotasResoureName() string {
	if api.PreV1Beta3(testapi.Version()) {
		return "resourceQuotas"
	}
	return "resourcequotas"
}
func replicationControllerResourceName() string {
	if api.PreV1Beta3(testapi.Version()) {
		return "replicationControllers"
	}
	return "replicationcontrollers"
}
func TestReadContainerManifestFromFile(t *testing.T) {
	// ContainerManifest is supported only for pre v1beta3 versions.
	if !api.PreV1Beta3(testapi.Version()) {
		return
	}
	hostname := "random-test-hostname"
	var testCases = []struct {
		desc         string
		fileContents string
		expected     kubelet.PodUpdate
	}{
		{
			desc: "Manifest",
			fileContents: fmt.Sprintf(`{
					"version": "%s",
					"uuid": "12345",
					"id": "test",
					"containers": [{ "name": "image", "image": "test/image", "imagePullPolicy": "PullAlways"}]
				}`, testapi.Version()),
			expected: CreatePodUpdate(kubelet.SET, kubelet.FileSource, &api.Pod{
				ObjectMeta: api.ObjectMeta{
					Name:      "test-" + hostname,
					UID:       "12345",
					Namespace: kubelet.NamespaceDefault,
					SelfLink:  getSelfLink("test-"+hostname, kubelet.NamespaceDefault),
				},
				Spec: api.PodSpec{
					Host:          hostname,
					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: fmt.Sprintf(`{
						"version": "%s",
						"uuid": "12345",
						"containers": [{ "name": "image", "image": "test/image", "imagePullPolicy": "PullAlways"}]
					}`, testapi.Version()),
			expected: CreatePodUpdate(kubelet.SET, kubelet.FileSource, &api.Pod{
				ObjectMeta: api.ObjectMeta{
					Name:      "12345-" + hostname,
					UID:       "12345",
					Namespace: kubelet.NamespaceDefault,
					SelfLink:  getSelfLink("12345-"+hostname, kubelet.NamespaceDefault),
				},
				Spec: api.PodSpec{
					Host:          hostname,
					RestartPolicy: api.RestartPolicyAlways,
					DNSPolicy:     api.DNSClusterFirst,
					Containers: []api.Container{{
						Name:  "image",
						Image: "test/image",
						TerminationMessagePath: "/dev/termination-log",
						ImagePullPolicy:        "Always"}},
				},
			}),
		},
	}

	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(), hostname, 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)
			}
		}()
	}
}