func roundTrip(t *testing.T, codec runtime.Codec, item runtime.Object) { printer := spew.ConfigState{DisableMethods: true} name := reflect.TypeOf(item).Elem().Name() data, err := codec.Encode(item) if err != nil { t.Errorf("%v: %v (%s)", name, err, printer.Sprintf("%#v", item)) return } obj2, err := codec.Decode(data) if err != nil { t.Errorf("0: %v: %v\nCodec: %v\nData: %s\nSource: %#v", name, err, codec, string(data), printer.Sprintf("%#v", item)) return } if !api.Semantic.DeepEqual(item, obj2) { t.Errorf("1: %v: diff: %v\nCodec: %v\nData: %s\nSource: %#v\nFinal: %#v", name, util.ObjectGoPrintDiff(item, obj2), codec, string(data), printer.Sprintf("%#v", item), printer.Sprintf("%#v", obj2)) return } obj3 := reflect.New(reflect.TypeOf(item).Elem()).Interface().(runtime.Object) err = codec.DecodeInto(data, obj3) if err != nil { t.Errorf("2: %v: %v", name, err) return } if !api.Semantic.DeepEqual(item, obj3) { t.Errorf("3: %v: diff: %v\nCodec: %v", name, util.ObjectDiff(item, obj3), codec) return } }
func validateEvent(actualEvent *api.Event, expectedEvent *api.Event, t *testing.T) (*api.Event, error) { expectCompression := expectedEvent.Count > 1 // Just check that the timestamp was set. if actualEvent.FirstTimestamp.IsZero() || actualEvent.LastTimestamp.IsZero() { t.Errorf("timestamp wasn't set: %#v", *actualEvent) } if actualEvent.FirstTimestamp.Equal(actualEvent.LastTimestamp) { if expectCompression { t.Errorf("FirstTimestamp (%q) and LastTimestamp (%q) must be equal to indicate only one occurrence of the event, but were different. Actual Event: %#v", actualEvent.FirstTimestamp, actualEvent.LastTimestamp, *actualEvent) } } else { if !expectCompression { t.Errorf("FirstTimestamp (%q) and LastTimestamp (%q) must be different to indicate event compression happened, but were the same. Actual Event: %#v", actualEvent.FirstTimestamp, actualEvent.LastTimestamp, *actualEvent) } } actualFirstTimestamp := actualEvent.FirstTimestamp actualLastTimestamp := actualEvent.LastTimestamp // Temp clear time stamps for comparison because actual values don't matter for comparison actualEvent.FirstTimestamp = expectedEvent.FirstTimestamp actualEvent.LastTimestamp = expectedEvent.LastTimestamp // Check that name has the right prefix. if n, en := actualEvent.Name, expectedEvent.Name; !strings.HasPrefix(n, en) { t.Errorf("Name '%v' does not contain prefix '%v'", n, en) } actualEvent.Name = expectedEvent.Name if e, a := expectedEvent, actualEvent; !reflect.DeepEqual(e, a) { t.Errorf("diff: %s", util.ObjectGoPrintDiff(e, a)) } actualEvent.FirstTimestamp = actualFirstTimestamp actualEvent.LastTimestamp = actualLastTimestamp return actualEvent, nil }
func (r *subjectAccessTest) runTest(t *testing.T) { storage := NewREST(subjectaccessreview.NewRegistry(subjectaccessreview.NewREST(r.authorizer))) expectedResponse := &authorizationapi.SubjectAccessReviewResponse{ Namespace: r.reviewRequest.Action.Namespace, Allowed: r.authorizer.allowed, Reason: r.authorizer.reason, } expectedAttributes := authorizer.ToDefaultAuthorizationAttributes(r.reviewRequest.Action) ctx := kapi.WithNamespace(kapi.NewContext(), r.reviewRequest.Action.Namespace) obj, err := storage.Create(ctx, r.reviewRequest) if err != nil && len(r.authorizer.err) == 0 { t.Fatalf("unexpected error: %v", err) } if len(r.authorizer.err) != 0 { if err == nil { t.Fatalf("unexpected non-error: %v", err) } if e, a := r.authorizer.err, err.Error(); e != a { t.Fatalf("expected %v, got %v", e, a) } return } switch obj.(type) { case *authorizationapi.SubjectAccessReviewResponse: if !reflect.DeepEqual(expectedResponse, obj) { t.Errorf("diff %v", util.ObjectGoPrintDiff(expectedResponse, obj)) } case nil: if len(r.authorizer.err) == 0 { t.Fatal("unexpected nil object") } default: t.Errorf("Unexpected obj type: %v", obj) } if !reflect.DeepEqual(expectedAttributes, r.authorizer.actualAttributes) { t.Errorf("diff %v", util.ObjectGoPrintDiff(expectedAttributes, r.authorizer.actualAttributes)) } }
func (r *subjectAccessTest) runTest(t *testing.T) { const namespace = "unittest" storage := REST{r.authorizer} expectedResponse := &authorizationapi.SubjectAccessReviewResponse{ Namespace: namespace, Allowed: r.authorizer.allowed, Reason: r.authorizer.reason, } expectedAttributes := &authorizer.DefaultAuthorizationAttributes{ Verb: r.reviewRequest.Verb, Resource: r.reviewRequest.Resource, } ctx := kapi.WithNamespace(kapi.NewContext(), namespace) obj, err := storage.Create(ctx, r.reviewRequest) if err != nil && len(r.authorizer.err) == 0 { t.Fatalf("unexpected error: %v", err) } if err == nil && len(r.authorizer.err) != 0 { t.Fatalf("unexpected non-error: %v", err) } switch obj.(type) { case *authorizationapi.SubjectAccessReviewResponse: if !reflect.DeepEqual(expectedResponse, obj) { t.Errorf("diff %v", util.ObjectGoPrintDiff(expectedResponse, obj)) } case nil: if len(r.authorizer.err) == 0 { t.Fatal("unexpected nil object") } default: t.Errorf("Unexpected obj type: %v", obj) } if !reflect.DeepEqual(expectedAttributes, r.authorizer.actualAttributes) { t.Errorf("diff %v", util.ObjectGoPrintDiff(expectedAttributes, r.authorizer.actualAttributes)) } }
func TestAPIServerDefaults(t *testing.T) { defaults := apiserveroptions.NewAPIServer() // This is a snapshot of the default config // If the default changes (new fields are added, or default values change), we want to know // Once we've reacted to the changes appropriately in BuildKubernetesMasterConfig(), update this expected default to match the new upstream defaults expectedDefaults := &apiserveroptions.APIServer{ ServerRunOptions: &genericapiserver.ServerRunOptions{ BindAddress: net.ParseIP("0.0.0.0"), CertDirectory: "/var/run/kubernetes", InsecureBindAddress: net.ParseIP("127.0.0.1"), InsecurePort: 8080, LongRunningRequestRE: "(/|^)((watch|proxy)(/|$)|(logs?|portforward|exec|attach)/?$)", MaxRequestsInFlight: 400, SecurePort: 6443, }, APIGroupPrefix: "/apis", APIPrefix: "/api", AdmissionControl: "AlwaysAdmit", AuthorizationMode: "AlwaysAllow", DeleteCollectionWorkers: 1, EnableLogsSupport: true, EnableProfiling: true, EnableWatchCache: true, EtcdConfig: etcdstorage.EtcdConfig{ Prefix: "/registry", }, EventTTL: 1 * time.Hour, MasterCount: 1, MasterServiceNamespace: "default", MinRequestTimeout: 1800, RuntimeConfig: util.ConfigurationMap{}, StorageVersions: registered.AllPreferredGroupVersions(), DefaultStorageVersions: registered.AllPreferredGroupVersions(), KubeletConfig: kubeletclient.KubeletClientConfig{ Port: 10250, EnableHttps: true, HTTPTimeout: time.Duration(5) * time.Second, }, } if !reflect.DeepEqual(defaults, expectedDefaults) { t.Logf("expected defaults, actual defaults: \n%s", util.ObjectGoPrintDiff(expectedDefaults, defaults)) t.Errorf("Got different defaults than expected, adjust in BuildKubernetesMasterConfig and update expectedDefaults") } }
func TestEventUpdate(t *testing.T) { eventA := &api.Event{ ObjectMeta: api.ObjectMeta{Name: "foo", Namespace: api.NamespaceDefault}, Reason: "forTesting", InvolvedObject: api.ObjectReference{Name: "foo", Namespace: api.NamespaceDefault}, } eventB := &api.Event{ ObjectMeta: api.ObjectMeta{Name: "foo", Namespace: api.NamespaceDefault}, Reason: "for testing again", InvolvedObject: api.ObjectReference{Name: "foo", Namespace: api.NamespaceDefault}, } eventC := &api.Event{ ObjectMeta: api.ObjectMeta{Name: "foo", Namespace: api.NamespaceDefault, ResourceVersion: "1"}, Reason: "for testing again something else", InvolvedObject: api.ObjectReference{Name: "foo", Namespace: api.NamespaceDefault}, } nodeWithEventA := tools.EtcdResponseWithError{ R: &etcd.Response{ Node: &etcd.Node{ Value: runtime.EncodeOrDie(testapi.Codec(), eventA), ModifiedIndex: 1, CreatedIndex: 1, TTL: int64(testTTL), }, }, E: nil, } nodeWithEventB := tools.EtcdResponseWithError{ R: &etcd.Response{ Node: &etcd.Node{ Value: runtime.EncodeOrDie(testapi.Codec(), eventB), ModifiedIndex: 1, CreatedIndex: 1, TTL: int64(testTTL), }, }, E: nil, } nodeWithEventC := tools.EtcdResponseWithError{ R: &etcd.Response{ Node: &etcd.Node{ Value: runtime.EncodeOrDie(testapi.Codec(), eventC), ModifiedIndex: 1, CreatedIndex: 1, TTL: int64(testTTL), }, }, E: nil, } emptyNode := tools.EtcdResponseWithError{ R: &etcd.Response{}, E: tools.EtcdErrorNotFound, } ctx := api.NewDefaultContext() key := "foo" path, err := etcdgeneric.NamespaceKeyFunc(ctx, "/events", key) path = etcdtest.AddPrefix(path) if err != nil { t.Errorf("Unexpected error: %v", err) } table := map[string]struct { existing tools.EtcdResponseWithError expect tools.EtcdResponseWithError toUpdate runtime.Object errOK func(error) bool }{ "doesNotExist": { existing: emptyNode, expect: nodeWithEventA, toUpdate: eventA, errOK: func(err error) bool { return err == nil }, }, "doesNotExist2": { existing: emptyNode, expect: nodeWithEventB, toUpdate: eventB, errOK: func(err error) bool { return err == nil }, }, "replaceExisting": { existing: nodeWithEventA, expect: nodeWithEventC, toUpdate: eventC, errOK: func(err error) bool { return err == nil }, }, } for name, item := range table { storage, fakeClient := newStorage(t) fakeClient.Data[path] = item.existing _, _, err := storage.Update(ctx, item.toUpdate) if !item.errOK(err) { t.Errorf("%v: unexpected error: %v", name, err) } // nullify fields set by infrastructure received := fakeClient.Data[path] var event api.Event if err := testapi.Codec().DecodeInto([]byte(received.R.Node.Value), &event); err != nil { t.Errorf("unexpected error: %v", err) } event.ObjectMeta.CreationTimestamp = util.Time{} event.ObjectMeta.UID = "" received.R.Node.Value = runtime.EncodeOrDie(testapi.Codec(), &event) if e, a := item.expect, received; !reflect.DeepEqual(e, a) { t.Errorf("%v:\n%s", name, util.ObjectGoPrintDiff(e, a)) } } }
func (tc *patchTestCase) Run(t *testing.T) { t.Logf("Starting test %s", tc.name) namespace := tc.startingPod.Namespace name := tc.startingPod.Name codec := testapi.Default.Codec() admit := tc.admit if admit == nil { admit = func(updatedObject runtime.Object) error { return nil } } testPatcher := &testPatcher{} testPatcher.startingPod = tc.startingPod testPatcher.updatePod = tc.updatePod ctx := api.NewDefaultContext() ctx = api.WithNamespace(ctx, namespace) namer := &testNamer{namespace, name} versionedObj, err := api.Scheme.ConvertToVersion(&api.Pod{}, "v1") if err != nil { t.Errorf("%s: unexpected error: %v", tc.name, err) return } for _, patchType := range []api.PatchType{api.JSONPatchType, api.MergePatchType, api.StrategicMergePatchType} { // TODO SUPPORT THIS! if patchType == api.JSONPatchType { continue } t.Logf("Working with patchType %v", patchType) originalObjJS, err := runtime.Encode(codec, tc.startingPod) if err != nil { t.Errorf("%s: unexpected error: %v", tc.name, err) return } changedJS, err := runtime.Encode(codec, tc.changedPod) if err != nil { t.Errorf("%s: unexpected error: %v", tc.name, err) return } patch := []byte{} switch patchType { case api.JSONPatchType: continue case api.StrategicMergePatchType: patch, err = strategicpatch.CreateStrategicMergePatch(originalObjJS, changedJS, versionedObj) if err != nil { t.Errorf("%s: unexpected error: %v", tc.name, err) return } case api.MergePatchType: patch, err = jsonpatch.CreateMergePatch(originalObjJS, changedJS) if err != nil { t.Errorf("%s: unexpected error: %v", tc.name, err) return } } resultObj, err := patchResource(ctx, admit, 1*time.Second, versionedObj, testPatcher, name, patchType, patch, namer, codec) if len(tc.expectedError) != 0 { if err == nil || err.Error() != tc.expectedError { t.Errorf("%s: expected error %v, but got %v", tc.name, tc.expectedError, err) return } } else { if err != nil { t.Errorf("%s: unexpected error: %v", tc.name, err) return } } if tc.expectedPod == nil { if resultObj != nil { t.Errorf("%s: unexpected result: %v", tc.name, resultObj) } return } resultPod := resultObj.(*api.Pod) // roundtrip to get defaulting expectedJS, err := runtime.Encode(codec, tc.expectedPod) if err != nil { t.Errorf("%s: unexpected error: %v", tc.name, err) return } expectedObj, err := runtime.Decode(codec, expectedJS) if err != nil { t.Errorf("%s: unexpected error: %v", tc.name, err) return } reallyExpectedPod := expectedObj.(*api.Pod) if !reflect.DeepEqual(*reallyExpectedPod, *resultPod) { t.Errorf("%s mismatch: %v\n", tc.name, util.ObjectGoPrintDiff(reallyExpectedPod, resultPod)) return } } }
func TestControllerStart(t *testing.T) { two := int64(2) testCases := []struct { stream *api.ImageStream run bool }{ { stream: &api.ImageStream{ ObjectMeta: kapi.ObjectMeta{ Annotations: map[string]string{api.DockerImageRepositoryCheckAnnotation: unversioned.Now().UTC().Format(time.RFC3339)}, Name: "test", Namespace: "other", }, }, }, { stream: &api.ImageStream{ ObjectMeta: kapi.ObjectMeta{ Annotations: map[string]string{api.DockerImageRepositoryCheckAnnotation: unversioned.Now().UTC().Format(time.RFC3339)}, Name: "test", Namespace: "other", }, Spec: api.ImageStreamSpec{ DockerImageRepository: "test/other", }, }, }, { stream: &api.ImageStream{ ObjectMeta: kapi.ObjectMeta{ Annotations: map[string]string{api.DockerImageRepositoryCheckAnnotation: "a random error"}, Name: "test", Namespace: "other", }, Spec: api.ImageStreamSpec{ DockerImageRepository: "test/other", }, }, }, // references are ignored { stream: &api.ImageStream{ ObjectMeta: kapi.ObjectMeta{Name: "test", Namespace: "other"}, Spec: api.ImageStreamSpec{ Tags: map[string]api.TagReference{ "latest": { From: &kapi.ObjectReference{Kind: "DockerImage", Name: "test/other:latest"}, Reference: true, }, }, }, }, }, { stream: &api.ImageStream{ ObjectMeta: kapi.ObjectMeta{Name: "test", Namespace: "other"}, Spec: api.ImageStreamSpec{ Tags: map[string]api.TagReference{ "latest": { From: &kapi.ObjectReference{Kind: "AnotherImage", Name: "test/other:latest"}, Reference: true, }, }, }, }, }, // spec tag will be imported { run: true, stream: &api.ImageStream{ ObjectMeta: kapi.ObjectMeta{Name: "test", Namespace: "other"}, Spec: api.ImageStreamSpec{ Tags: map[string]api.TagReference{ "latest": { From: &kapi.ObjectReference{Kind: "DockerImage", Name: "test/other:latest"}, }, }, }, }, }, // spec tag with generation with no pending status will be imported { run: true, stream: &api.ImageStream{ ObjectMeta: kapi.ObjectMeta{Name: "test", Namespace: "other"}, Spec: api.ImageStreamSpec{ Tags: map[string]api.TagReference{ "latest": { From: &kapi.ObjectReference{Kind: "DockerImage", Name: "test/other:latest"}, Generation: &two, }, }, }, }, }, // spec tag with generation with older status generation will be imported { run: true, stream: &api.ImageStream{ ObjectMeta: kapi.ObjectMeta{Name: "test", Namespace: "other"}, Spec: api.ImageStreamSpec{ Tags: map[string]api.TagReference{ "latest": { From: &kapi.ObjectReference{Kind: "DockerImage", Name: "test/other:latest"}, Generation: &two, }, }, }, Status: api.ImageStreamStatus{ Tags: map[string]api.TagEventList{"latest": {Items: []api.TagEvent{{Generation: 1}}}}, }, }, }, // spec tag with generation with status condition error and equal generation will not be imported { stream: &api.ImageStream{ ObjectMeta: kapi.ObjectMeta{ Annotations: map[string]string{api.DockerImageRepositoryCheckAnnotation: unversioned.Now().UTC().Format(time.RFC3339)}, Name: "test", Namespace: "other", }, Spec: api.ImageStreamSpec{ Tags: map[string]api.TagReference{ "latest": { From: &kapi.ObjectReference{Kind: "DockerImage", Name: "test/other:latest"}, Generation: &two, }, }, }, Status: api.ImageStreamStatus{ Tags: map[string]api.TagEventList{"latest": {Conditions: []api.TagEventCondition{ { Type: api.ImportSuccess, Status: kapi.ConditionFalse, Generation: 2, }, }}}, }, }, }, // spec tag with generation with status condition error and older generation will be imported { run: true, stream: &api.ImageStream{ ObjectMeta: kapi.ObjectMeta{ Annotations: map[string]string{api.DockerImageRepositoryCheckAnnotation: unversioned.Now().UTC().Format(time.RFC3339)}, Name: "test", Namespace: "other", }, Spec: api.ImageStreamSpec{ Tags: map[string]api.TagReference{ "latest": { From: &kapi.ObjectReference{Kind: "DockerImage", Name: "test/other:latest"}, Generation: &two, }, }, }, Status: api.ImageStreamStatus{ Tags: map[string]api.TagEventList{"latest": {Conditions: []api.TagEventCondition{ { Type: api.ImportSuccess, Status: kapi.ConditionFalse, Generation: 1, }, }}}, }, }, }, // spec tag with generation with older status generation will be imported { run: true, stream: &api.ImageStream{ ObjectMeta: kapi.ObjectMeta{ Annotations: map[string]string{api.DockerImageRepositoryCheckAnnotation: unversioned.Now().UTC().Format(time.RFC3339)}, Name: "test", Namespace: "other", }, Spec: api.ImageStreamSpec{ Tags: map[string]api.TagReference{ "latest": { From: &kapi.ObjectReference{Kind: "DockerImage", Name: "test/other:latest"}, Generation: &two, }, }, }, Status: api.ImageStreamStatus{ Tags: map[string]api.TagEventList{"latest": {Items: []api.TagEvent{{Generation: 1}}}}, }, }, }, } for i, test := range testCases { fake := &client.Fake{} c := ImportController{streams: fake} other, err := kapi.Scheme.DeepCopy(test.stream) if err != nil { t.Fatal(err) } if err := c.Next(test.stream); err != nil { t.Errorf("%d: unexpected error: %v", i, err) } if test.run { if len(fake.Actions()) == 0 { t.Errorf("%d: expected remote calls: %#v", i, fake) } } else { if !kapi.Semantic.DeepEqual(test.stream, other) { t.Errorf("%d: did not expect change to stream: %s", i, util.ObjectGoPrintDiff(test.stream, other)) } if len(fake.Actions()) != 0 { t.Errorf("%d: did not expect remote calls", i) } } } }
func TestWebhook(t *testing.T) { serv := new(recorderService) s, err := NewTestServer(serv, serverCert, serverKey, caCert) if err != nil { t.Fatal(err) } defer s.Close() wh, err := newAuthorizer(s.URL, clientCert, clientKey, caCert) if err != nil { t.Fatal(err) } expTypeMeta := unversioned.TypeMeta{ APIVersion: "authorization.k8s.io/v1beta1", Kind: "SubjectAccessReview", } tests := []struct { attr authorizer.Attributes want v1beta1.SubjectAccessReview }{ { attr: authorizer.AttributesRecord{User: &user.DefaultInfo{}}, want: v1beta1.SubjectAccessReview{ TypeMeta: expTypeMeta, Spec: v1beta1.SubjectAccessReviewSpec{ NonResourceAttributes: &v1beta1.NonResourceAttributes{}, }, }, }, { attr: authorizer.AttributesRecord{User: &user.DefaultInfo{Name: "jane"}}, want: v1beta1.SubjectAccessReview{ TypeMeta: expTypeMeta, Spec: v1beta1.SubjectAccessReviewSpec{ User: "******", NonResourceAttributes: &v1beta1.NonResourceAttributes{}, }, }, }, { attr: authorizer.AttributesRecord{ User: &user.DefaultInfo{ Name: "jane", UID: "1", Groups: []string{"group1", "group2"}, }, Verb: "GET", Namespace: "kittensandponies", APIGroup: "group3", Resource: "pods", ResourceRequest: true, Path: "/foo", }, want: v1beta1.SubjectAccessReview{ TypeMeta: expTypeMeta, Spec: v1beta1.SubjectAccessReviewSpec{ User: "******", Groups: []string{"group1", "group2"}, ResourceAttributes: &v1beta1.ResourceAttributes{ Verb: "GET", Namespace: "kittensandponies", Group: "group3", Resource: "pods", }, }, }, }, } for i, tt := range tests { if err := wh.Authorize(tt.attr); err != nil { t.Errorf("case %d: authorization failed: %v", i, err) continue } gotAttr, err := serv.Last() if err != nil { t.Errorf("case %d: failed to deserialize webhook request: %v", i, err) continue } if !reflect.DeepEqual(gotAttr, tt.want) { t.Errorf("case %d: got != want:\n%s", i, util.ObjectGoPrintDiff(gotAttr, tt.want)) } } }
func TestCMServerDefaults(t *testing.T) { defaults := cmapp.NewCMServer() // This is a snapshot of the default config // If the default changes (new fields are added, or default values change), we want to know // Once we've reacted to the changes appropriately in BuildKubernetesMasterConfig(), update this expected default to match the new upstream defaults expectedDefaults := &cmapp.CMServer{ KubeControllerManagerConfiguration: componentconfig.KubeControllerManagerConfiguration{ Port: 10252, // disabled Address: "0.0.0.0", ConcurrentEndpointSyncs: 5, ConcurrentRCSyncs: 5, ConcurrentRSSyncs: 5, ConcurrentDaemonSetSyncs: 2, ConcurrentJobSyncs: 5, ConcurrentResourceQuotaSyncs: 5, ConcurrentDeploymentSyncs: 5, ConcurrentNamespaceSyncs: 2, LookupCacheSizeForRC: 4096, LookupCacheSizeForRS: 4096, LookupCacheSizeForDaemonSet: 1024, ServiceSyncPeriod: unversioned.Duration{Duration: 5 * time.Minute}, NodeSyncPeriod: unversioned.Duration{Duration: 10 * time.Second}, ResourceQuotaSyncPeriod: unversioned.Duration{Duration: 5 * time.Minute}, NamespaceSyncPeriod: unversioned.Duration{Duration: 5 * time.Minute}, PVClaimBinderSyncPeriod: unversioned.Duration{Duration: 10 * time.Minute}, HorizontalPodAutoscalerSyncPeriod: unversioned.Duration{Duration: 30 * time.Second}, DeploymentControllerSyncPeriod: unversioned.Duration{Duration: 30 * time.Second}, MinResyncPeriod: unversioned.Duration{Duration: 12 * time.Hour}, RegisterRetryCount: 10, PodEvictionTimeout: unversioned.Duration{Duration: 5 * time.Minute}, NodeMonitorGracePeriod: unversioned.Duration{Duration: 40 * time.Second}, NodeStartupGracePeriod: unversioned.Duration{Duration: 60 * time.Second}, NodeMonitorPeriod: unversioned.Duration{Duration: 5 * time.Second}, ClusterName: "kubernetes", TerminatedPodGCThreshold: 12500, VolumeConfiguration: componentconfig.VolumeConfiguration{ EnableHostPathProvisioning: false, PersistentVolumeRecyclerConfiguration: componentconfig.PersistentVolumeRecyclerConfiguration{ MaximumRetry: 3, MinimumTimeoutNFS: 300, IncrementTimeoutNFS: 30, MinimumTimeoutHostPath: 60, IncrementTimeoutHostPath: 30, }, }, KubeAPIQPS: 20.0, KubeAPIBurst: 30, LeaderElection: componentconfig.LeaderElectionConfiguration{ LeaderElect: false, LeaseDuration: unversioned.Duration{Duration: 15 * time.Second}, RenewDeadline: unversioned.Duration{Duration: 10 * time.Second}, RetryPeriod: unversioned.Duration{Duration: 2 * time.Second}, }, }, } if !reflect.DeepEqual(defaults, expectedDefaults) { t.Logf("expected defaults, actual defaults: \n%s", util.ObjectGoPrintDiff(expectedDefaults, defaults)) t.Errorf("Got different defaults than expected, adjust in BuildKubernetesMasterConfig and update expectedDefaults") } }
func TestEventUpdate(t *testing.T) { eventA := &api.Event{ ObjectMeta: api.ObjectMeta{Name: "foo", Namespace: api.NamespaceDefault}, Reason: "forTesting", } eventB := &api.Event{ ObjectMeta: api.ObjectMeta{Name: "bar", Namespace: api.NamespaceDefault}, Reason: "for testing again", } eventC := &api.Event{ ObjectMeta: api.ObjectMeta{Name: "pan", Namespace: api.NamespaceDefault, ResourceVersion: "1"}, Reason: "for testing again something else", } nodeWithEventA := tools.EtcdResponseWithError{ R: &etcd.Response{ Node: &etcd.Node{ Value: runtime.EncodeOrDie(testapi.Codec(), eventA), ModifiedIndex: 1, CreatedIndex: 1, TTL: int64(testTTL), }, }, E: nil, } nodeWithEventB := tools.EtcdResponseWithError{ R: &etcd.Response{ Node: &etcd.Node{ Value: runtime.EncodeOrDie(testapi.Codec(), eventB), ModifiedIndex: 1, CreatedIndex: 1, TTL: int64(testTTL), }, }, E: nil, } nodeWithEventC := tools.EtcdResponseWithError{ R: &etcd.Response{ Node: &etcd.Node{ Value: runtime.EncodeOrDie(testapi.Codec(), eventC), ModifiedIndex: 1, CreatedIndex: 1, TTL: int64(testTTL), }, }, E: nil, } emptyNode := tools.EtcdResponseWithError{ R: &etcd.Response{}, E: tools.EtcdErrorNotFound, } ctx := api.NewDefaultContext() key := "foo" path, err := etcdgeneric.NamespaceKeyFunc(ctx, "/events", key) path = etcdtest.AddPrefix(path) if err != nil { t.Errorf("Unexpected error: %v", err) } table := map[string]struct { existing tools.EtcdResponseWithError expect tools.EtcdResponseWithError toUpdate runtime.Object errOK func(error) bool }{ "doesNotExist": { existing: emptyNode, expect: nodeWithEventA, toUpdate: eventA, errOK: func(err error) bool { return err == nil }, }, "doesNotExist2": { existing: emptyNode, expect: nodeWithEventB, toUpdate: eventB, errOK: func(err error) bool { return err == nil }, }, "replaceExisting": { existing: nodeWithEventA, expect: nodeWithEventC, toUpdate: eventC, errOK: func(err error) bool { return err == nil }, }, } for name, item := range table { fakeClient, registry := NewTestEventEtcdRegistry(t) fakeClient.Data[path] = item.existing err := registry.UpdateWithName(ctx, key, item.toUpdate) if !item.errOK(err) { t.Errorf("%v: unexpected error: %v", name, err) } if e, a := item.expect, fakeClient.Data[path]; !reflect.DeepEqual(e, a) { t.Errorf("%v:\n%s", name, util.ObjectGoPrintDiff(e, a)) } } }
// TestNestedParse tests that parsing the `go test` output in the test directory with a nested builder works as expected func TestNestedParse(t *testing.T) { var testCases = []struct { name string testFile string rootSuiteNames []string expectedSuites *api.TestSuites }{ { name: "basic", testFile: "1.txt", expectedSuites: &api.TestSuites{ Suites: []*api.TestSuite{ { Name: "package", NumTests: 2, Duration: 0.16, Children: []*api.TestSuite{ { Name: "package/name", NumTests: 2, Duration: 0.16, TestCases: []*api.TestCase{ { Name: "TestOne", Duration: 0.06, }, { Name: "TestTwo", Duration: 0.1, }, }, }, }, }, }, }, }, { name: "basic with restricted root", testFile: "1.txt", rootSuiteNames: []string{"package/name"}, expectedSuites: &api.TestSuites{ Suites: []*api.TestSuite{ { Name: "package/name", NumTests: 2, Duration: 0.16, TestCases: []*api.TestCase{ { Name: "TestOne", Duration: 0.06, }, { Name: "TestTwo", Duration: 0.1, }, }, }, }, }, }, { name: "failure", testFile: "2.txt", expectedSuites: &api.TestSuites{ Suites: []*api.TestSuite{ { Name: "package", NumTests: 2, NumFailed: 1, Duration: 0.15, Children: []*api.TestSuite{ { Name: "package/name", NumTests: 2, NumFailed: 1, Duration: 0.15, TestCases: []*api.TestCase{ { Name: "TestOne", Duration: 0.02, FailureOutput: &api.FailureOutput{ Output: `=== RUN TestOne --- FAIL: TestOne (0.02 seconds) file_test.go:11: Error message file_test.go:11: Longer error message.`, }, }, { Name: "TestTwo", Duration: 0.13, }, }, }, }, }, }, }, }, { name: "skip", testFile: "3.txt", expectedSuites: &api.TestSuites{ Suites: []*api.TestSuite{ { Name: "package", NumTests: 2, NumSkipped: 1, Duration: 0.15, Children: []*api.TestSuite{ { Name: "package/name", NumTests: 2, NumSkipped: 1, Duration: 0.15, TestCases: []*api.TestCase{ { Name: "TestOne", Duration: 0.02, SkipMessage: &api.SkipMessage{ Message: `=== RUN TestOne --- SKIP: TestOne (0.02 seconds) file_test.go:11: Skip message`, }, }, { Name: "TestTwo", Duration: 0.13, }, }, }, }, }, }, }, }, { name: "go 1.4", testFile: "4.txt", expectedSuites: &api.TestSuites{ Suites: []*api.TestSuite{ { Name: "package", NumTests: 2, Duration: 0.16, Children: []*api.TestSuite{ { Name: "package/name", NumTests: 2, Duration: 0.16, TestCases: []*api.TestCase{ { Name: "TestOne", Duration: 0.06, }, { Name: "TestTwo", Duration: 0.1, }, }, }, }, }, }, }, }, { name: "multiple suites", testFile: "5.txt", expectedSuites: &api.TestSuites{ Suites: []*api.TestSuite{ { Name: "package", NumTests: 4, NumFailed: 1, Duration: 0.31, Children: []*api.TestSuite{ { Name: "package/name1", NumTests: 2, Duration: 0.16, TestCases: []*api.TestCase{ { Name: "TestOne", Duration: 0.06, }, { Name: "TestTwo", Duration: 0.1, }, }, }, { Name: "package/name2", NumTests: 2, Duration: 0.15, NumFailed: 1, TestCases: []*api.TestCase{ { Name: "TestOne", Duration: 0.02, FailureOutput: &api.FailureOutput{ Output: `=== RUN TestOne --- FAIL: TestOne (0.02 seconds) file_test.go:11: Error message file_test.go:11: Longer error message.`, }, }, { Name: "TestTwo", Duration: 0.13, }, }, }, }, }, }, }, }, { name: "coverage statement", testFile: "6.txt", expectedSuites: &api.TestSuites{ Suites: []*api.TestSuite{ { Name: "package", NumTests: 2, Duration: 0.16, Children: []*api.TestSuite{ { Name: "package/name", NumTests: 2, Duration: 0.16, Properties: []*api.TestSuiteProperty{ { Name: "coverage.statements.pct", Value: "13.37", }, }, TestCases: []*api.TestCase{ { Name: "TestOne", Duration: 0.06, }, { Name: "TestTwo", Duration: 0.1, }, }, }, }, }, }, }, }, { name: "coverage statement in package result", testFile: "7.txt", expectedSuites: &api.TestSuites{ Suites: []*api.TestSuite{ { Name: "package", NumTests: 2, Duration: 0.16, Children: []*api.TestSuite{ { Name: "package/name", NumTests: 2, Duration: 0.16, Properties: []*api.TestSuiteProperty{ { Name: "coverage.statements.pct", Value: "10.0", }, }, TestCases: []*api.TestCase{ { Name: "TestOne", Duration: 0.06, }, { Name: "TestTwo", Duration: 0.1, }, }, }, }, }, }, }, }, { name: "go 1.5", testFile: "8.txt", expectedSuites: &api.TestSuites{ Suites: []*api.TestSuite{ { Name: "package", NumTests: 2, Duration: 0.05, Children: []*api.TestSuite{ { Name: "package/name", NumTests: 2, Duration: 0.05, TestCases: []*api.TestCase{ { Name: "TestOne", Duration: 0.02, }, { Name: "TestTwo", Duration: 0.03, }, }, }, }, }, }, }, }, { name: "nested ", testFile: "9.txt", expectedSuites: &api.TestSuites{ Suites: []*api.TestSuite{ { Name: "package", NumTests: 6, NumFailed: 1, NumSkipped: 1, Duration: 0.4, Children: []*api.TestSuite{ { Name: "package/name", NumTests: 4, NumFailed: 1, NumSkipped: 1, Duration: 0.1, TestCases: []*api.TestCase{ { Name: "TestOne", Duration: 0.02, }, { Name: "TestTwo", Duration: 0.03, }, }, Children: []*api.TestSuite{ { Name: "package/name/nested", NumTests: 2, NumFailed: 1, NumSkipped: 1, Duration: 0.05, TestCases: []*api.TestCase{ { Name: "TestOne", Duration: 0.02, FailureOutput: &api.FailureOutput{ Output: `=== RUN TestOne --- FAIL: TestOne (0.02 seconds) file_test.go:11: Error message file_test.go:11: Longer error message.`, }, }, { Name: "TestTwo", Duration: 0.03, SkipMessage: &api.SkipMessage{ Message: `=== RUN TestTwo --- SKIP: TestTwo (0.03 seconds) file_test.go:11: Skip message PASS`, // we include this line greedily even though it does not belong to the test }, }, }, }, }, }, { Name: "package/other", NumTests: 2, Duration: 0.3, Children: []*api.TestSuite{ { Name: "package/other/nested", NumTests: 2, Duration: 0.3, TestCases: []*api.TestCase{ { Name: "TestOne", Duration: 0.1, }, { Name: "TestTwo", Duration: 0.2, }, }, }, }, }, }, }, }, }, }, { name: "test case timing doesn't add to test suite timing", testFile: "10.txt", expectedSuites: &api.TestSuites{ Suites: []*api.TestSuite{ { Name: "package", NumTests: 2, Duration: 2.16, Children: []*api.TestSuite{ { Name: "package/name", NumTests: 2, Duration: 2.16, TestCases: []*api.TestCase{ { Name: "TestOne", Duration: 0.06, }, { Name: "TestTwo", Duration: 0.1, }, }, }, }, }, }, }, }, } for _, testCase := range testCases { parser := NewParser(nested.NewTestSuitesBuilder(testCase.rootSuiteNames)) testFile := "./../../../test/gotest/testdata/" + testCase.testFile reader, err := os.Open(testFile) if err != nil { t.Errorf("%s: unexpected error opening file %q: %v", testCase.name, testFile, err) continue } testSuites, err := parser.Parse(bufio.NewScanner(reader)) if err != nil { t.Errorf("%s: unexpected error parsing file: %v", testCase.name, err) continue } if !reflect.DeepEqual(testSuites, testCase.expectedSuites) { fmt.Println(util.ObjectGoPrintDiff(testSuites, testCase.expectedSuites)) t.Errorf("%s: did not produce the correct test suites from file:\n\texpected:\n\t%v,\n\tgot\n\t%v", testCase.name, testCase.expectedSuites, testSuites) } } }
func TestAnonymousConfig(t *testing.T) { f := fuzz.New().NilChance(0.0).NumElements(1, 1) f.Funcs( func(r *runtime.Codec, f fuzz.Continue) {}, func(r *http.RoundTripper, f fuzz.Continue) {}, func(fn *func(http.RoundTripper) http.RoundTripper, f fuzz.Continue) {}, ) for i := 0; i < 20; i++ { original := &restclient.Config{} f.Fuzz(original) actual := AnonymousClientConfig(original) expected := *original // this is the list of known security related fields, add to this list if a new field // is added to restclient.Config, update AnonymousClientConfig to preserve the field otherwise. expected.BearerToken = "" expected.Username = "" expected.Password = "" expected.TLSClientConfig.CertData = nil expected.TLSClientConfig.CertFile = "" expected.TLSClientConfig.KeyData = nil expected.TLSClientConfig.KeyFile = "" if !reflect.DeepEqual(actual, expected) { t.Fatalf("AnonymousClientConfig dropped unexpected fields, identify whether they are security related or not: %s", util.ObjectGoPrintDiff(expected, actual)) } } }
func roundTrip(t *testing.T, codec runtime.Codec, item runtime.Object) { printer := spew.ConfigState{DisableMethods: true} gvk, err := api.Scheme.ObjectKind(item) t.Logf("fully qualified kind for %v is %v with codec %v", reflect.TypeOf(item), gvk, codec) name := reflect.TypeOf(item).Elem().Name() data, err := runtime.Encode(codec, item) if err != nil { t.Errorf("%v: %v (%s)", name, err, printer.Sprintf("%#v", item)) return } obj2, err := runtime.Decode(codec, data) if err != nil { t.Errorf("0: %v: %v\nCodec: %v\nData: %s\nSource: %#v", name, err, codec, string(data), printer.Sprintf("%#v", item)) return } if !api.Semantic.DeepEqual(item, obj2) { t.Errorf("\n1: %v: diff: %v\nCodec: %v\nSource:\n\n%#v\n\nEncoded:\n\n%s\n\nFinal:\n\n%#v", name, util.ObjectGoPrintDiff(item, obj2), codec, printer.Sprintf("%#v", item), string(data), printer.Sprintf("%#v", obj2)) return } obj3 := reflect.New(reflect.TypeOf(item).Elem()).Interface().(runtime.Object) err = runtime.DecodeInto(codec, data, obj3) if err != nil { t.Errorf("2: %v: %v", name, err) return } if !api.Semantic.DeepEqual(item, obj3) { t.Errorf("3: %v: diff: %v\nCodec: %v", name, util.ObjectDiff(item, obj3), codec) return } }
func TestKubeletDefaults(t *testing.T) { defaults := kubeletoptions.NewKubeletServer() // This is a snapshot of the default config // If the default changes (new fields are added, or default values change), we want to know // Once we've reacted to the changes appropriately in BuildKubernetesNodeConfig(), update this expected default to match the new upstream defaults expectedDefaults := &kubeletoptions.KubeletServer{ AuthPath: util.NewStringFlag("/var/lib/kubelet/kubernetes_auth"), KubeConfig: util.NewStringFlag("/var/lib/kubelet/kubeconfig"), SystemReserved: util.ConfigurationMap{}, KubeReserved: util.ConfigurationMap{}, KubeletConfiguration: componentconfig.KubeletConfiguration{ Address: "0.0.0.0", // overridden AllowPrivileged: false, // overridden CAdvisorPort: 4194, // disabled VolumeStatsAggPeriod: unversioned.Duration{Duration: time.Minute}, CertDirectory: "/var/run/kubernetes", CgroupRoot: "", ClusterDNS: "", // overridden ClusterDomain: "", // overridden ConfigureCBR0: false, ContainerRuntime: "docker", Containerized: false, // overridden based on OPENSHIFT_CONTAINERIZED CPUCFSQuota: true, // forced to true DockerExecHandlerName: "native", EventBurst: 10, EventRecordQPS: 5.0, EnableCustomMetrics: false, EnableDebuggingHandlers: true, EnableServer: true, FileCheckFrequency: unversioned.Duration{Duration: 20 * time.Second}, // overridden HealthzBindAddress: "127.0.0.1", // disabled HealthzPort: 10248, // disabled HostNetworkSources: "*", // overridden HostPIDSources: "*", // overridden HostIPCSources: "*", // overridden HTTPCheckFrequency: unversioned.Duration{Duration: 20 * time.Second}, // disabled ImageMinimumGCAge: unversioned.Duration{Duration: 2 * time.Minute}, ImageGCHighThresholdPercent: 90, ImageGCLowThresholdPercent: 80, LowDiskSpaceThresholdMB: 256, MasterServiceNamespace: "default", MaxContainerCount: 240, MaxPerPodContainerCount: 2, MaxOpenFiles: 1000000, MaxPods: 110, // overridden MinimumGCAge: unversioned.Duration{Duration: 1 * time.Minute}, NetworkPluginDir: "/usr/libexec/kubernetes/kubelet-plugins/net/exec/", NetworkPluginName: "", // overridden NonMasqueradeCIDR: "10.0.0.0/8", VolumePluginDir: "/usr/libexec/kubernetes/kubelet-plugins/volume/exec/", NodeStatusUpdateFrequency: unversioned.Duration{Duration: 10 * time.Second}, NodeLabels: map[string]string{}, OOMScoreAdj: -999, LockFilePath: "", PodInfraContainerImage: kubetypes.PodInfraContainerImage, // overridden Port: 10250, // overridden ReadOnlyPort: 10255, // disabled RegisterNode: true, RegisterSchedulable: true, RegistryBurst: 10, RegistryPullQPS: 5.0, KubeletCgroups: "", RktPath: "", RktStage1Image: "", RootDirectory: "/var/lib/kubelet", // overridden RuntimeCgroups: "", SerializeImagePulls: true, StreamingConnectionIdleTimeout: unversioned.Duration{Duration: 4 * time.Hour}, SyncFrequency: unversioned.Duration{Duration: 1 * time.Minute}, SystemCgroups: "", TLSCertFile: "", // overridden to prevent cert generation TLSPrivateKeyFile: "", // overridden to prevent cert generation ReconcileCIDR: true, KubeAPIQPS: 5.0, KubeAPIBurst: 10, ExperimentalFlannelOverlay: false, OutOfDiskTransitionFrequency: unversioned.Duration{Duration: 5 * time.Minute}, HairpinMode: "promiscuous-bridge", BabysitDaemons: false, }, } if !reflect.DeepEqual(defaults, expectedDefaults) { t.Logf("expected defaults, actual defaults: \n%s", util.ObjectGoPrintDiff(expectedDefaults, defaults)) t.Errorf("Got different defaults than expected, adjust in BuildKubernetesNodeConfig and update expectedDefaults") } }