func verifyEvents(t *testing.T, expected, actual []*PodLifecycleEvent) { sort.Sort(sortableEvents(expected)) sort.Sort(sortableEvents(actual)) if !reflect.DeepEqual(expected, actual) { t.Errorf("Actual events differ from the expected; diff:\n %v", diff.ObjectDiff(expected, actual)) } }
func TestUpdateStatus(t *testing.T) { storage, statusStorage, server := newStorage(t) defer server.Terminate(t) ctx := api.NewContext() key, _ := storage.KeyFunc(ctx, "foo") key = etcdtest.AddPrefix(key) pvStart := validNewPersistentVolume("foo") err := storage.Storage.Create(ctx, key, pvStart, nil, 0) if err != nil { t.Errorf("unexpected error: %v", err) } pvIn := &api.PersistentVolume{ ObjectMeta: api.ObjectMeta{ Name: "foo", }, Status: api.PersistentVolumeStatus{ Phase: api.VolumeBound, }, } _, _, err = statusStorage.Update(ctx, pvIn.Name, rest.DefaultUpdatedObjectInfo(pvIn, api.Scheme)) if err != nil { t.Fatalf("Unexpected error: %v", err) } obj, err := storage.Get(ctx, "foo") if err != nil { t.Errorf("unexpected error: %v", err) } pvOut := obj.(*api.PersistentVolume) // only compare the relevant change b/c metadata will differ if !api.Semantic.DeepEqual(pvIn.Status, pvOut.Status) { t.Errorf("unexpected object: %s", diff.ObjectDiff(pvIn.Status, pvOut.Status)) } }
func TestEncode_Ptr(t *testing.T) { grace := int64(30) pod := &api.Pod{ ObjectMeta: api.ObjectMeta{ Labels: map[string]string{"name": "foo"}, }, Spec: api.PodSpec{ RestartPolicy: api.RestartPolicyAlways, DNSPolicy: api.DNSClusterFirst, TerminationGracePeriodSeconds: &grace, SecurityContext: &api.PodSecurityContext{}, }, } obj := runtime.Object(pod) data, err := runtime.Encode(testapi.Default.Codec(), obj) obj2, err2 := runtime.Decode(testapi.Default.Codec(), data) if err != nil || err2 != nil { t.Fatalf("Failure: '%v' '%v'", err, err2) } if _, ok := obj2.(*api.Pod); !ok { t.Fatalf("Got wrong type") } if !api.Semantic.DeepEqual(obj2, pod) { t.Errorf("\nExpected:\n\n %#v,\n\nGot:\n\n %#vDiff: %v\n\n", pod, obj2, diff.ObjectDiff(obj2, pod)) } }
func TestUpdateStatus(t *testing.T) { storage, status, server := newStorage(t) defer server.Terminate(t) ctx := api.NewDefaultContext() key, _ := storage.KeyFunc(ctx, "foo") key = etcdtest.AddPrefix(key) resourcequotaStart := validNewResourceQuota() err := storage.Storage.Create(ctx, key, resourcequotaStart, nil, 0) if err != nil { t.Fatalf("Unexpected error: %v", err) } resourcequotaIn := &api.ResourceQuota{ ObjectMeta: api.ObjectMeta{ Name: "foo", Namespace: api.NamespaceDefault, }, Status: api.ResourceQuotaStatus{ Used: api.ResourceList{ api.ResourceCPU: resource.MustParse("1"), api.ResourceMemory: resource.MustParse("1Gi"), api.ResourcePods: resource.MustParse("1"), api.ResourceServices: resource.MustParse("1"), api.ResourceReplicationControllers: resource.MustParse("1"), api.ResourceQuotas: resource.MustParse("1"), }, Hard: api.ResourceList{ api.ResourceCPU: resource.MustParse("100"), api.ResourceMemory: resource.MustParse("4Gi"), api.ResourcePods: resource.MustParse("10"), api.ResourceServices: resource.MustParse("10"), api.ResourceReplicationControllers: resource.MustParse("10"), api.ResourceQuotas: resource.MustParse("1"), }, }, } _, _, err = status.Update(ctx, resourcequotaIn.Name, rest.DefaultUpdatedObjectInfo(resourcequotaIn, api.Scheme)) if err != nil { t.Fatalf("Unexpected error: %v", err) } obj, err := storage.Get(ctx, "foo") rqOut := obj.(*api.ResourceQuota) // only compare the meaningful update b/c we can't compare due to metadata if !api.Semantic.DeepEqual(resourcequotaIn.Status, rqOut.Status) { t.Errorf("unexpected object: %s", diff.ObjectDiff(resourcequotaIn, rqOut)) } }
func TestGetMultipleTypeObjectsWithDirectReference(t *testing.T) { _, svc, _ := testData() node := &api.Node{ ObjectMeta: api.ObjectMeta{ Name: "foo", }, Spec: api.NodeSpec{ ExternalID: "ext", }, } f, tf, codec := NewAPIFactory() tf.Printer = &testPrinter{} tf.Client = &fake.RESTClient{ Codec: codec, Client: fake.CreateHTTPClient(func(req *http.Request) (*http.Response, error) { switch req.URL.Path { case "/nodes/foo": return &http.Response{StatusCode: 200, Header: defaultHeader(), Body: objBody(codec, node)}, nil case "/namespaces/test/services/bar": return &http.Response{StatusCode: 200, Header: defaultHeader(), Body: objBody(codec, &svc.Items[0])}, nil default: t.Fatalf("unexpected request: %#v\n%#v", req.URL, req) return nil, nil } }), } tf.Namespace = "test" buf := bytes.NewBuffer([]byte{}) cmd := NewCmdGet(f, buf) cmd.SetOutput(buf) cmd.Run(cmd, []string{"services/bar", "node/foo"}) expected := []runtime.Object{&svc.Items[0], node} actual := tf.Printer.(*testPrinter).Objects if !api.Semantic.DeepEqual(expected, actual) { t.Errorf("unexpected object: %s", diff.ObjectDiff(expected, actual)) } if len(buf.String()) == 0 { t.Errorf("unexpected empty output") } }
func TestUpdateStatus(t *testing.T) { storage, statusStorage, server := newStorage(t) defer server.Terminate(t) ctx := api.NewDefaultContext() key, _ := storage.KeyFunc(ctx, "foo") key = etcdtest.AddPrefix(key) pvcStart := validNewPersistentVolumeClaim("foo", api.NamespaceDefault) err := storage.Storage.Create(ctx, key, pvcStart, nil, 0) pvc := &api.PersistentVolumeClaim{ ObjectMeta: api.ObjectMeta{ Name: "foo", Namespace: api.NamespaceDefault, }, Spec: api.PersistentVolumeClaimSpec{ AccessModes: []api.PersistentVolumeAccessMode{api.ReadWriteOnce}, Resources: api.ResourceRequirements{ Requests: api.ResourceList{ api.ResourceName(api.ResourceStorage): resource.MustParse("3Gi"), }, }, }, Status: api.PersistentVolumeClaimStatus{ Phase: api.ClaimBound, }, } _, _, err = statusStorage.Update(ctx, pvc.Name, rest.DefaultUpdatedObjectInfo(pvc, api.Scheme)) if err != nil { t.Fatalf("Unexpected error: %v", err) } obj, err := storage.Get(ctx, "foo") if err != nil { t.Errorf("unexpected error: %v", err) } pvcOut := obj.(*api.PersistentVolumeClaim) // only compare relevant changes b/c of difference in metadata if !api.Semantic.DeepEqual(pvc.Status, pvcOut.Status) { t.Errorf("unexpected object: %s", diff.ObjectDiff(pvc.Status, pvcOut.Status)) } }
func (test configCommandTest) run(t *testing.T) string { out, actualConfig := testConfigCommand(test.args, test.startingConfig, t) testSetNilMapsToEmpties(reflect.ValueOf(&test.expectedConfig)) testSetNilMapsToEmpties(reflect.ValueOf(&actualConfig)) testClearLocationOfOrigin(&actualConfig) if !api.Semantic.DeepEqual(test.expectedConfig, actualConfig) { t.Errorf("diff: %v", diff.ObjectDiff(test.expectedConfig, actualConfig)) t.Errorf("expected: %#v\n actual: %#v", test.expectedConfig, actualConfig) } for _, expectedOutput := range test.expectedOutputs { if !strings.Contains(out, expectedOutput) { t.Errorf("expected '%s' in output, got '%s'", expectedOutput, out) } } return out }
func (test stepParserTest) run(t *testing.T) { actualSteps, err := newNavigationSteps(test.path) if len(test.expectedError) != 0 { if err == nil { t.Errorf("Did not get %v", test.expectedError) } else { if !strings.Contains(err.Error(), test.expectedError) { t.Errorf("Expected %v, but got %v", test.expectedError, err) } } return } if err != nil { t.Errorf("Unexpected error: %v", err) } if !reflect.DeepEqual(test.expectedNavigationSteps, *actualSteps) { t.Errorf("diff: %v", diff.ObjectDiff(test.expectedNavigationSteps, *actualSteps)) t.Errorf("expected: %#v\n actual: %#v", test.expectedNavigationSteps, *actualSteps) } }
func TestScaleGet(t *testing.T) { storage, server := newStorage(t) defer server.Terminate(t) name := "foo" var rs extensions.ReplicaSet ctx := api.WithNamespace(api.NewContext(), api.NamespaceDefault) key := etcdtest.AddPrefix("/replicasets/" + api.NamespaceDefault + "/" + name) if err := storage.ReplicaSet.Storage.Create(ctx, key, &validReplicaSet, &rs, 0); err != nil { t.Fatalf("error setting new replica set (key: %s) %v: %v", key, validReplicaSet, err) } want := &extensions.Scale{ ObjectMeta: api.ObjectMeta{ Name: name, Namespace: api.NamespaceDefault, UID: rs.UID, ResourceVersion: rs.ResourceVersion, CreationTimestamp: rs.CreationTimestamp, }, Spec: extensions.ScaleSpec{ Replicas: validReplicaSet.Spec.Replicas, }, Status: extensions.ScaleStatus{ Replicas: validReplicaSet.Status.Replicas, Selector: validReplicaSet.Spec.Selector, }, } obj, err := storage.Scale.Get(ctx, name) got := obj.(*extensions.Scale) if err != nil { t.Fatalf("error fetching scale for %s: %v", name, err) } if !api.Semantic.DeepEqual(got, want) { t.Errorf("unexpected scale: %s", diff.ObjectDiff(got, want)) } }
func TestMonitorNodeStatusUpdateStatus(t *testing.T) { fakeNow := unversioned.Date(2015, 1, 1, 12, 0, 0, 0, time.UTC) table := []struct { fakeNodeHandler *FakeNodeHandler timeToPass time.Duration newNodeStatus api.NodeStatus expectedEvictPods bool expectedRequestCount int expectedNodes []*api.Node }{ // Node created long time ago, without status: // Expect Unknown status posted from node controller. { fakeNodeHandler: &FakeNodeHandler{ Existing: []*api.Node{ { ObjectMeta: api.ObjectMeta{ Name: "node0", CreationTimestamp: unversioned.Date(2012, 1, 1, 0, 0, 0, 0, time.UTC), }, }, }, Clientset: fake.NewSimpleClientset(&api.PodList{Items: []api.Pod{*newPod("pod0", "node0")}}), }, expectedRequestCount: 2, // List+Update expectedNodes: []*api.Node{ { ObjectMeta: api.ObjectMeta{ Name: "node0", CreationTimestamp: unversioned.Date(2012, 1, 1, 0, 0, 0, 0, time.UTC), }, Status: api.NodeStatus{ Conditions: []api.NodeCondition{ { Type: api.NodeReady, Status: api.ConditionUnknown, Reason: "NodeStatusNeverUpdated", Message: "Kubelet never posted node status.", LastHeartbeatTime: unversioned.Date(2012, 1, 1, 0, 0, 0, 0, time.UTC), LastTransitionTime: fakeNow, }, { Type: api.NodeOutOfDisk, Status: api.ConditionUnknown, Reason: "NodeStatusNeverUpdated", Message: "Kubelet never posted node status.", LastHeartbeatTime: unversioned.Date(2012, 1, 1, 0, 0, 0, 0, time.UTC), LastTransitionTime: fakeNow, }, }, }, }, }, }, // Node created recently, without status. // Expect no action from node controller (within startup grace period). { fakeNodeHandler: &FakeNodeHandler{ Existing: []*api.Node{ { ObjectMeta: api.ObjectMeta{ Name: "node0", CreationTimestamp: fakeNow, }, }, }, Clientset: fake.NewSimpleClientset(&api.PodList{Items: []api.Pod{*newPod("pod0", "node0")}}), }, expectedRequestCount: 1, // List expectedNodes: nil, }, // Node created long time ago, with status updated by kubelet exceeds grace period. // Expect Unknown status posted from node controller. { fakeNodeHandler: &FakeNodeHandler{ Existing: []*api.Node{ { ObjectMeta: api.ObjectMeta{ Name: "node0", CreationTimestamp: unversioned.Date(2012, 1, 1, 0, 0, 0, 0, time.UTC), }, Status: api.NodeStatus{ Conditions: []api.NodeCondition{ { Type: api.NodeReady, Status: api.ConditionTrue, // Node status hasn't been updated for 1hr. LastHeartbeatTime: unversioned.Date(2015, 1, 1, 12, 0, 0, 0, time.UTC), LastTransitionTime: unversioned.Date(2015, 1, 1, 12, 0, 0, 0, time.UTC), }, { Type: api.NodeOutOfDisk, Status: api.ConditionFalse, // Node status hasn't been updated for 1hr. LastHeartbeatTime: unversioned.Date(2015, 1, 1, 12, 0, 0, 0, time.UTC), LastTransitionTime: unversioned.Date(2015, 1, 1, 12, 0, 0, 0, time.UTC), }, }, Capacity: api.ResourceList{ api.ResourceName(api.ResourceCPU): resource.MustParse("10"), api.ResourceName(api.ResourceMemory): resource.MustParse("10G"), }, }, Spec: api.NodeSpec{ ExternalID: "node0", }, }, }, Clientset: fake.NewSimpleClientset(&api.PodList{Items: []api.Pod{*newPod("pod0", "node0")}}), }, expectedRequestCount: 3, // (List+)List+Update timeToPass: time.Hour, newNodeStatus: api.NodeStatus{ Conditions: []api.NodeCondition{ { Type: api.NodeReady, Status: api.ConditionTrue, // Node status hasn't been updated for 1hr. LastHeartbeatTime: unversioned.Date(2015, 1, 1, 12, 0, 0, 0, time.UTC), LastTransitionTime: unversioned.Date(2015, 1, 1, 12, 0, 0, 0, time.UTC), }, { Type: api.NodeOutOfDisk, Status: api.ConditionFalse, // Node status hasn't been updated for 1hr. LastHeartbeatTime: unversioned.Date(2015, 1, 1, 12, 0, 0, 0, time.UTC), LastTransitionTime: unversioned.Date(2015, 1, 1, 12, 0, 0, 0, time.UTC), }, }, Capacity: api.ResourceList{ api.ResourceName(api.ResourceCPU): resource.MustParse("10"), api.ResourceName(api.ResourceMemory): resource.MustParse("10G"), }, }, expectedNodes: []*api.Node{ { ObjectMeta: api.ObjectMeta{ Name: "node0", CreationTimestamp: unversioned.Date(2012, 1, 1, 0, 0, 0, 0, time.UTC), }, Status: api.NodeStatus{ Conditions: []api.NodeCondition{ { Type: api.NodeReady, Status: api.ConditionUnknown, Reason: "NodeStatusUnknown", Message: "Kubelet stopped posting node status.", LastHeartbeatTime: unversioned.Date(2015, 1, 1, 12, 0, 0, 0, time.UTC), LastTransitionTime: unversioned.Time{Time: unversioned.Date(2015, 1, 1, 12, 0, 0, 0, time.UTC).Add(time.Hour)}, }, { Type: api.NodeOutOfDisk, Status: api.ConditionUnknown, Reason: "NodeStatusUnknown", Message: "Kubelet stopped posting node status.", LastHeartbeatTime: unversioned.Date(2015, 1, 1, 12, 0, 0, 0, time.UTC), LastTransitionTime: unversioned.Time{Time: unversioned.Date(2015, 1, 1, 12, 0, 0, 0, time.UTC).Add(time.Hour)}, }, }, Capacity: api.ResourceList{ api.ResourceName(api.ResourceCPU): resource.MustParse("10"), api.ResourceName(api.ResourceMemory): resource.MustParse("10G"), }, }, Spec: api.NodeSpec{ ExternalID: "node0", }, }, }, }, // Node created long time ago, with status updated recently. // Expect no action from node controller (within monitor grace period). { fakeNodeHandler: &FakeNodeHandler{ Existing: []*api.Node{ { ObjectMeta: api.ObjectMeta{ Name: "node0", CreationTimestamp: unversioned.Date(2012, 1, 1, 0, 0, 0, 0, time.UTC), }, Status: api.NodeStatus{ Conditions: []api.NodeCondition{ { Type: api.NodeReady, Status: api.ConditionTrue, // Node status has just been updated. LastHeartbeatTime: fakeNow, LastTransitionTime: fakeNow, }, }, Capacity: api.ResourceList{ api.ResourceName(api.ResourceCPU): resource.MustParse("10"), api.ResourceName(api.ResourceMemory): resource.MustParse("10G"), }, }, Spec: api.NodeSpec{ ExternalID: "node0", }, }, }, Clientset: fake.NewSimpleClientset(&api.PodList{Items: []api.Pod{*newPod("pod0", "node0")}}), }, expectedRequestCount: 1, // List expectedNodes: nil, }, } for i, item := range table { nodeController := NewNodeController(nil, item.fakeNodeHandler, 5*time.Minute, flowcontrol.NewFakeAlwaysRateLimiter(), flowcontrol.NewFakeAlwaysRateLimiter(), testNodeMonitorGracePeriod, testNodeStartupGracePeriod, testNodeMonitorPeriod, nil, nil, 0, false) nodeController.now = func() unversioned.Time { return fakeNow } if err := nodeController.monitorNodeStatus(); err != nil { t.Errorf("unexpected error: %v", err) } if item.timeToPass > 0 { nodeController.now = func() unversioned.Time { return unversioned.Time{Time: fakeNow.Add(item.timeToPass)} } item.fakeNodeHandler.Existing[0].Status = item.newNodeStatus if err := nodeController.monitorNodeStatus(); err != nil { t.Errorf("unexpected error: %v", err) } } if item.expectedRequestCount != item.fakeNodeHandler.RequestCount { t.Errorf("expected %v call, but got %v.", item.expectedRequestCount, item.fakeNodeHandler.RequestCount) } if len(item.fakeNodeHandler.UpdatedNodes) > 0 && !api.Semantic.DeepEqual(item.expectedNodes, item.fakeNodeHandler.UpdatedNodes) { t.Errorf("Case[%d] unexpected nodes: %s", i, diff.ObjectDiff(item.expectedNodes[0], item.fakeNodeHandler.UpdatedNodes[0])) } if len(item.fakeNodeHandler.UpdatedNodeStatuses) > 0 && !api.Semantic.DeepEqual(item.expectedNodes, item.fakeNodeHandler.UpdatedNodeStatuses) { t.Errorf("Case[%d] unexpected nodes: %s", i, diff.ObjectDiff(item.expectedNodes[0], item.fakeNodeHandler.UpdatedNodeStatuses[0])) } } }
func TestCreatePodSecurityContextNonmutating(t *testing.T) { // Create a pod with a security context that needs filling in createPod := func() *api.Pod { return &api.Pod{ Spec: api.PodSpec{ SecurityContext: &api.PodSecurityContext{}, }, } } // Create a PSP with strategies that will populate a blank psc createPSP := func() *extensions.PodSecurityPolicy { return &extensions.PodSecurityPolicy{ ObjectMeta: api.ObjectMeta{ Name: "psp-sa", }, Spec: extensions.PodSecurityPolicySpec{ DefaultAddCapabilities: []api.Capability{"foo"}, RequiredDropCapabilities: []api.Capability{"bar"}, RunAsUser: extensions.RunAsUserStrategyOptions{ Rule: extensions.RunAsUserStrategyRunAsAny, }, SELinux: extensions.SELinuxStrategyOptions{ Rule: extensions.SELinuxStrategyRunAsAny, }, // these are pod mutating strategies that are tested above FSGroup: extensions.FSGroupStrategyOptions{ Rule: extensions.FSGroupStrategyMustRunAs, Ranges: []extensions.IDRange{ {Min: 1, Max: 1}, }, }, SupplementalGroups: extensions.SupplementalGroupsStrategyOptions{ Rule: extensions.SupplementalGroupsStrategyMustRunAs, Ranges: []extensions.IDRange{ {Min: 1, Max: 1}, }, }, }, } } pod := createPod() psp := createPSP() provider, err := NewSimpleProvider(psp, "namespace", NewSimpleStrategyFactory()) if err != nil { t.Fatalf("unable to create provider %v", err) } sc, err := provider.CreatePodSecurityContext(pod) if err != nil { t.Fatalf("unable to create psc %v", err) } // The generated security context should have filled in missing options, so they should differ if reflect.DeepEqual(sc, &pod.Spec.SecurityContext) { t.Error("expected created security context to be different than container's, but they were identical") } // Creating the provider or the security context should not have mutated the psp or pod if !reflect.DeepEqual(createPod(), pod) { diffs := diff.ObjectDiff(createPod(), pod) t.Errorf("pod was mutated by CreatePodSecurityContext. diff:\n%s", diffs) } if !reflect.DeepEqual(createPSP(), psp) { t.Error("psp was mutated by CreatePodSecurityContext") } }
func TestDefaultRuleResolver(t *testing.T) { ruleReadPods := rbac.PolicyRule{ Verbs: []string{"GET", "WATCH"}, APIGroups: []string{"v1"}, Resources: []string{"pods"}, } ruleReadServices := rbac.PolicyRule{ Verbs: []string{"GET", "WATCH"}, APIGroups: []string{"v1"}, Resources: []string{"services"}, } ruleWriteNodes := rbac.PolicyRule{ Verbs: []string{"PUT", "CREATE", "UPDATE"}, APIGroups: []string{"v1"}, Resources: []string{"nodes"}, } ruleAdmin := rbac.PolicyRule{ Verbs: []string{"*"}, APIGroups: []string{"*"}, Resources: []string{"*"}, } staticRoles1 := staticRoles{ roles: []rbac.Role{ { ObjectMeta: api.ObjectMeta{Namespace: "namespace1", Name: "readthings"}, Rules: []rbac.PolicyRule{ruleReadPods, ruleReadServices}, }, }, clusterRoles: []rbac.ClusterRole{ { ObjectMeta: api.ObjectMeta{Name: "cluster-admin"}, Rules: []rbac.PolicyRule{ruleAdmin}, }, { ObjectMeta: api.ObjectMeta{Name: "write-nodes"}, Rules: []rbac.PolicyRule{ruleWriteNodes}, }, }, roleBindings: []rbac.RoleBinding{ { ObjectMeta: api.ObjectMeta{Namespace: "namespace1"}, Subjects: []rbac.Subject{ {Kind: rbac.UserKind, Name: "foobar"}, {Kind: rbac.GroupKind, Name: "group1"}, }, RoleRef: api.ObjectReference{Kind: "Role", Namespace: "namespace1", Name: "readthings"}, }, }, clusterRoleBindings: []rbac.ClusterRoleBinding{ { Subjects: []rbac.Subject{ {Kind: rbac.UserKind, Name: "admin"}, {Kind: rbac.GroupKind, Name: "admin"}, }, RoleRef: api.ObjectReference{Kind: "ClusterRole", Name: "cluster-admin"}, }, }, } tests := []struct { staticRoles // For a given context, what are the rules that apply? ctx api.Context effectiveRules []rbac.PolicyRule }{ { staticRoles: staticRoles1, ctx: api.WithNamespace( api.WithUser(api.NewContext(), &user.DefaultInfo{Name: "foobar"}), "namespace1", ), effectiveRules: []rbac.PolicyRule{ruleReadPods, ruleReadServices}, }, { staticRoles: staticRoles1, ctx: api.WithNamespace( // Same as above but diffrerent namespace. Should return no rules. api.WithUser(api.NewContext(), &user.DefaultInfo{Name: "foobar"}), "namespace2", ), effectiveRules: []rbac.PolicyRule{}, }, { staticRoles: staticRoles1, // GetEffectivePolicyRules only returns the policies for the namespace, not the master namespace. ctx: api.WithNamespace( api.WithUser(api.NewContext(), &user.DefaultInfo{ Name: "foobar", Groups: []string{"admin"}, }), "namespace1", ), effectiveRules: []rbac.PolicyRule{ruleReadPods, ruleReadServices}, }, { staticRoles: staticRoles1, // Same as above but without a namespace. Only cluster rules should apply. ctx: api.WithUser(api.NewContext(), &user.DefaultInfo{ Name: "foobar", Groups: []string{"admin"}, }), effectiveRules: []rbac.PolicyRule{ruleAdmin}, }, { staticRoles: staticRoles1, ctx: api.WithUser(api.NewContext(), &user.DefaultInfo{}), effectiveRules: []rbac.PolicyRule{}, }, } for i, tc := range tests { ruleResolver := newMockRuleResolver(&tc.staticRoles) rules, err := ruleResolver.GetEffectivePolicyRules(tc.ctx) if err != nil { t.Errorf("case %d: GetEffectivePolicyRules(context)=%v", i, err) continue } // Sort for deep equals sort.Sort(byHash(rules)) sort.Sort(byHash(tc.effectiveRules)) if !reflect.DeepEqual(rules, tc.effectiveRules) { ruleDiff := diff.ObjectDiff(rules, tc.effectiveRules) t.Errorf("case %d: %s", i, ruleDiff) } } }
func TestWatchRead(t *testing.T) { simpleStorage := &SimpleRESTStorage{} _ = rest.Watcher(simpleStorage) // Give compile error if this doesn't work. handler := handle(map[string]rest.Storage{"simples": simpleStorage}) server := httptest.NewServer(handler) defer server.Close() dest, _ := url.Parse(server.URL) dest.Path = "/" + prefix + "/" + testGroupVersion.Group + "/" + testGroupVersion.Version + "/simples" dest.RawQuery = "watch=1" connectHTTP := func(accept string) (io.ReadCloser, string) { client := http.Client{} request, err := http.NewRequest("GET", dest.String(), nil) if err != nil { t.Fatalf("unexpected error: %v", err) } request.Header.Add("Accept", accept) response, err := client.Do(request) if err != nil { t.Fatalf("unexpected error: %v", err) } if response.StatusCode != http.StatusOK { t.Fatalf("Unexpected response %#v", response) } return response.Body, response.Header.Get("Content-Type") } connectWebSocket := func(accept string) (io.ReadCloser, string) { dest := *dest dest.Scheme = "ws" // Required by websocket, though the server never sees it. config, err := websocket.NewConfig(dest.String(), "http://localhost") if err != nil { t.Fatalf("unexpected error: %v", err) } config.Header.Add("Accept", accept) ws, err := websocket.DialConfig(config) if err != nil { t.Fatalf("unexpected error: %v", err) } return ws, "__default__" } testCases := []struct { Accept string ExpectedContentType string MediaType string }{ { Accept: "application/json", ExpectedContentType: "application/json", MediaType: "application/json", }, // TODO: yaml stream serialization requires that RawExtension.MarshalJSON // be able to understand nested encoding (since yaml calls json.Marshal // rather than yaml.Marshal, which results in the raw bytes being in yaml). // Same problem as thirdparty object. /*{ Accept: "application/yaml", ExpectedContentType: "application/yaml;stream=watch", MediaType: "application/yaml", },*/ { Accept: "application/vnd.kubernetes.protobuf", ExpectedContentType: "application/vnd.kubernetes.protobuf;stream=watch", MediaType: "application/vnd.kubernetes.protobuf", }, { Accept: "application/vnd.kubernetes.protobuf;stream=watch", ExpectedContentType: "application/vnd.kubernetes.protobuf;stream=watch", MediaType: "application/vnd.kubernetes.protobuf", }, } protocols := []struct { name string selfFraming bool fn func(string) (io.ReadCloser, string) }{ {name: "http", fn: connectHTTP}, {name: "websocket", selfFraming: true, fn: connectWebSocket}, } for _, protocol := range protocols { for _, test := range testCases { serializer, ok := api.Codecs.StreamingSerializerForMediaType(test.MediaType, nil) if !ok { t.Fatal(serializer) } r, contentType := protocol.fn(test.Accept) defer r.Close() if contentType != "__default__" && contentType != test.ExpectedContentType { t.Errorf("Unexpected content type: %#v", contentType) } objectSerializer, ok := api.Codecs.SerializerForMediaType(test.MediaType, nil) if !ok { t.Fatal(objectSerializer) } objectCodec := api.Codecs.DecoderToVersion(objectSerializer, testInternalGroupVersion) var fr io.ReadCloser = r if !protocol.selfFraming { fr = serializer.Framer.NewFrameReader(r) } d := streaming.NewDecoder(fr, serializer) var w *watch.FakeWatcher for w == nil { w = simpleStorage.Watcher() time.Sleep(time.Millisecond) } for i, item := range podWatchTestTable { action, object := item.t, item.obj name := fmt.Sprintf("%s-%s-%d", protocol.name, test.MediaType, i) // Send w.Action(action, object) // Test receive var got versioned.Event _, _, err := d.Decode(nil, &got) if err != nil { t.Fatalf("%s: Unexpected error: %v", name, err) } if got.Type != string(action) { t.Errorf("%s: Unexpected type: %v", name, got.Type) } gotObj, err := runtime.Decode(objectCodec, got.Object.Raw) if err != nil { t.Fatalf("%s: Decode error: %v", name, err) } if _, err := api.GetReference(gotObj); err != nil { t.Errorf("%s: Unable to construct reference: %v", name, err) } if e, a := object, gotObj; !api.Semantic.DeepEqual(e, a) { t.Errorf("%s: different: %s", name, diff.ObjectDiff(e, a)) } } w.Stop() var got versioned.Event _, _, err := d.Decode(nil, &got) if err == nil { t.Errorf("Unexpected non-error") } r.Close() } } }