From 647124bf5e7c2c4860cb31910f40eaa44e258b96 Mon Sep 17 00:00:00 2001 From: Maciej Szulik Date: Tue, 17 May 2016 12:12:50 +0200 Subject: [PATCH] ScheduledJob client and storage tests --- pkg/client/unversioned/scheduledjobs_test.go | 277 +++++++++++++++++++ pkg/registry/scheduledjob/etcd/etcd.go | 10 +- pkg/registry/scheduledjob/etcd/etcd_test.go | 177 ++++++++++++ test/e2e/framework/framework.go | 2 +- 4 files changed, 464 insertions(+), 2 deletions(-) create mode 100644 pkg/client/unversioned/scheduledjobs_test.go create mode 100644 pkg/registry/scheduledjob/etcd/etcd_test.go diff --git a/pkg/client/unversioned/scheduledjobs_test.go b/pkg/client/unversioned/scheduledjobs_test.go new file mode 100644 index 00000000000..975d1503c30 --- /dev/null +++ b/pkg/client/unversioned/scheduledjobs_test.go @@ -0,0 +1,277 @@ +/* +Copyright 2016 The Kubernetes Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package unversioned_test + +import ( + "testing" + + "k8s.io/kubernetes/pkg/api" + "k8s.io/kubernetes/pkg/api/testapi" + "k8s.io/kubernetes/pkg/apis/batch" + "k8s.io/kubernetes/pkg/apis/batch/v2alpha1" + "k8s.io/kubernetes/pkg/client/unversioned/testclient/simple" +) + +func getScheduledJobsResource() string { + return "scheduledjobs" +} + +func TestListScheduledJob(t *testing.T) { + // scheduled jobs should be tested only when batch/v2alpha1 is enabled + if *testapi.Batch.GroupVersion() != v2alpha1.SchemeGroupVersion { + return + } + + ns := api.NamespaceAll + c := &simple.Client{ + Request: simple.Request{ + Method: "GET", + Path: testapi.Batch.ResourcePath(getScheduledJobsResource(), ns, ""), + }, + Response: simple.Response{StatusCode: 200, + Body: &batch.ScheduledJobList{ + Items: []batch.ScheduledJob{ + { + ObjectMeta: api.ObjectMeta{ + Name: "foo", + Labels: map[string]string{ + "foo": "bar", + "name": "baz", + }, + }, + Spec: batch.ScheduledJobSpec{ + JobTemplate: batch.JobTemplateSpec{ + Spec: batch.JobSpec{ + Template: api.PodTemplateSpec{}, + }, + }, + }, + }, + }, + }, + }, + ResourceGroup: batch.GroupName, + } + receivedScheduledJobList, err := c.Setup(t).Batch().ScheduledJobs(ns).List(api.ListOptions{}) + defer c.Close() + c.Validate(t, receivedScheduledJobList, err) +} + +func TestGetScheduledJob(t *testing.T) { + // scheduled jobs should be tested only when batch/v2alpha1 is enabled + if *testapi.Batch.GroupVersion() != v2alpha1.SchemeGroupVersion { + return + } + + ns := api.NamespaceDefault + c := &simple.Client{ + Request: simple.Request{ + Method: "GET", + Path: testapi.Batch.ResourcePath(getScheduledJobsResource(), ns, "foo"), + Query: simple.BuildQueryValues(nil), + }, + Response: simple.Response{ + StatusCode: 200, + Body: &batch.ScheduledJob{ + ObjectMeta: api.ObjectMeta{ + Name: "foo", + Labels: map[string]string{ + "foo": "bar", + "name": "baz", + }, + }, + Spec: batch.ScheduledJobSpec{ + JobTemplate: batch.JobTemplateSpec{ + Spec: batch.JobSpec{ + Template: api.PodTemplateSpec{}, + }, + }, + }, + }, + }, + ResourceGroup: batch.GroupName, + } + receivedScheduledJob, err := c.Setup(t).Batch().ScheduledJobs(ns).Get("foo") + defer c.Close() + c.Validate(t, receivedScheduledJob, err) +} + +func TestUpdateScheduledJob(t *testing.T) { + // scheduled jobs should be tested only when batch/v2alpha1 is enabled + if *testapi.Batch.GroupVersion() != v2alpha1.SchemeGroupVersion { + return + } + + ns := api.NamespaceDefault + requestScheduledJob := &batch.ScheduledJob{ + ObjectMeta: api.ObjectMeta{ + Name: "foo", + Namespace: ns, + ResourceVersion: "1", + }, + } + c := &simple.Client{ + Request: simple.Request{ + Method: "PUT", + Path: testapi.Batch.ResourcePath(getScheduledJobsResource(), ns, "foo"), + Query: simple.BuildQueryValues(nil), + }, + Response: simple.Response{ + StatusCode: 200, + Body: &batch.ScheduledJob{ + ObjectMeta: api.ObjectMeta{ + Name: "foo", + Labels: map[string]string{ + "foo": "bar", + "name": "baz", + }, + }, + Spec: batch.ScheduledJobSpec{ + JobTemplate: batch.JobTemplateSpec{ + Spec: batch.JobSpec{ + Template: api.PodTemplateSpec{}, + }, + }, + }, + }, + }, + ResourceGroup: batch.GroupName, + } + receivedScheduledJob, err := c.Setup(t).Batch().ScheduledJobs(ns).Update(requestScheduledJob) + defer c.Close() + c.Validate(t, receivedScheduledJob, err) +} + +func TestUpdateScheduledJobStatus(t *testing.T) { + // scheduled jobs should be tested only when batch/v2alpha1 is enabled + if *testapi.Batch.GroupVersion() != v2alpha1.SchemeGroupVersion { + return + } + + ns := api.NamespaceDefault + requestScheduledJob := &batch.ScheduledJob{ + ObjectMeta: api.ObjectMeta{ + Name: "foo", + Namespace: ns, + ResourceVersion: "1", + }, + } + c := &simple.Client{ + Request: simple.Request{ + Method: "PUT", + Path: testapi.Batch.ResourcePath(getScheduledJobsResource(), ns, "foo") + "/status", + Query: simple.BuildQueryValues(nil), + }, + Response: simple.Response{ + StatusCode: 200, + Body: &batch.ScheduledJob{ + ObjectMeta: api.ObjectMeta{ + Name: "foo", + Labels: map[string]string{ + "foo": "bar", + "name": "baz", + }, + }, + Spec: batch.ScheduledJobSpec{ + ConcurrencyPolicy: batch.AllowConcurrent, + JobTemplate: batch.JobTemplateSpec{ + Spec: batch.JobSpec{ + Template: api.PodTemplateSpec{}, + }, + }, + }, + Status: batch.ScheduledJobStatus{ + Active: []api.ObjectReference{{Name: "ref"}}, + }, + }, + }, + ResourceGroup: batch.GroupName, + } + receivedScheduledJob, err := c.Setup(t).Batch().ScheduledJobs(ns).UpdateStatus(requestScheduledJob) + defer c.Close() + c.Validate(t, receivedScheduledJob, err) +} + +func TestDeleteScheduledJob(t *testing.T) { + // scheduled jobs should be tested only when batch/v2alpha1 is enabled + if *testapi.Batch.GroupVersion() != v2alpha1.SchemeGroupVersion { + return + } + + ns := api.NamespaceDefault + c := &simple.Client{ + Request: simple.Request{ + Method: "DELETE", + Path: testapi.Batch.ResourcePath(getScheduledJobsResource(), ns, "foo"), + Query: simple.BuildQueryValues(nil), + }, + Response: simple.Response{StatusCode: 200}, + ResourceGroup: batch.GroupName, + } + err := c.Setup(t).Batch().ScheduledJobs(ns).Delete("foo", nil) + defer c.Close() + c.Validate(t, nil, err) +} + +func TestCreateScheduledJob(t *testing.T) { + // scheduled jobs should be tested only when batch/v2alpha1 is enabled + if *testapi.Batch.GroupVersion() != v2alpha1.SchemeGroupVersion { + return + } + + ns := api.NamespaceDefault + requestScheduledJob := &batch.ScheduledJob{ + ObjectMeta: api.ObjectMeta{ + Name: "foo", + Namespace: ns, + }, + } + c := &simple.Client{ + Request: simple.Request{ + Method: "POST", + Path: testapi.Batch.ResourcePath(getScheduledJobsResource(), ns, ""), + Body: requestScheduledJob, + Query: simple.BuildQueryValues(nil), + }, + Response: simple.Response{ + StatusCode: 200, + Body: &batch.ScheduledJob{ + ObjectMeta: api.ObjectMeta{ + Name: "foo", + Labels: map[string]string{ + "foo": "bar", + "name": "baz", + }, + }, + Spec: batch.ScheduledJobSpec{ + JobTemplate: batch.JobTemplateSpec{ + Spec: batch.JobSpec{ + Template: api.PodTemplateSpec{}, + }, + }, + }, + }, + }, + ResourceGroup: batch.GroupName, + } + receivedScheduledJob, err := c.Setup(t).Batch().ScheduledJobs(ns).Create(requestScheduledJob) + defer c.Close() + if err != nil { + t.Fatalf("unexpected error: %v", err) + } + c.Validate(t, receivedScheduledJob, err) +} diff --git a/pkg/registry/scheduledjob/etcd/etcd.go b/pkg/registry/scheduledjob/etcd/etcd.go index 5cb2365b344..4f6eb375394 100644 --- a/pkg/registry/scheduledjob/etcd/etcd.go +++ b/pkg/registry/scheduledjob/etcd/etcd.go @@ -25,6 +25,7 @@ import ( "k8s.io/kubernetes/pkg/registry/generic/registry" "k8s.io/kubernetes/pkg/registry/scheduledjob" "k8s.io/kubernetes/pkg/runtime" + "k8s.io/kubernetes/pkg/storage" ) // REST implements a RESTStorage for scheduled jobs against etcd @@ -38,7 +39,14 @@ func NewREST(opts generic.RESTOptions) (*REST, *StatusREST) { newListFunc := func() runtime.Object { return &batch.ScheduledJobList{} } storageInterface := opts.Decorator( - opts.Storage, cachesize.GetWatchCacheSizeByResource(cachesize.ScheduledJobs), &batch.ScheduledJob{}, prefix, scheduledjob.Strategy, newListFunc) + opts.Storage, + cachesize.GetWatchCacheSizeByResource(cachesize.ScheduledJobs), + &batch.ScheduledJob{}, + prefix, + scheduledjob.Strategy, + newListFunc, + storage.NoTriggerPublisher, + ) store := ®istry.Store{ NewFunc: func() runtime.Object { return &batch.ScheduledJob{} }, diff --git a/pkg/registry/scheduledjob/etcd/etcd_test.go b/pkg/registry/scheduledjob/etcd/etcd_test.go new file mode 100644 index 00000000000..d78462e4d24 --- /dev/null +++ b/pkg/registry/scheduledjob/etcd/etcd_test.go @@ -0,0 +1,177 @@ +/* +Copyright 2016 The Kubernetes Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package etcd + +import ( + "testing" + + "k8s.io/kubernetes/pkg/api" + "k8s.io/kubernetes/pkg/api/testapi" + "k8s.io/kubernetes/pkg/apis/batch" + "k8s.io/kubernetes/pkg/apis/batch/v2alpha1" + "k8s.io/kubernetes/pkg/fields" + "k8s.io/kubernetes/pkg/labels" + "k8s.io/kubernetes/pkg/registry/generic" + "k8s.io/kubernetes/pkg/registry/registrytest" + "k8s.io/kubernetes/pkg/runtime" + etcdtesting "k8s.io/kubernetes/pkg/storage/etcd/testing" +) + +func newStorage(t *testing.T) (*REST, *StatusREST, *etcdtesting.EtcdTestServer) { + etcdStorage, server := registrytest.NewEtcdStorage(t, batch.GroupName) + restOptions := generic.RESTOptions{Storage: etcdStorage, Decorator: generic.UndecoratedStorage, DeleteCollectionWorkers: 1} + storage, statusStorage := NewREST(restOptions) + return storage, statusStorage, server +} + +func validNewScheduledJob() *batch.ScheduledJob { + return &batch.ScheduledJob{ + ObjectMeta: api.ObjectMeta{ + Name: "foo", + Namespace: api.NamespaceDefault, + }, + Spec: batch.ScheduledJobSpec{ + Schedule: "* * * * * ?", + ConcurrencyPolicy: batch.AllowConcurrent, + JobTemplate: batch.JobTemplateSpec{ + Spec: batch.JobSpec{ + Template: api.PodTemplateSpec{ + Spec: api.PodSpec{ + RestartPolicy: api.RestartPolicyOnFailure, + DNSPolicy: api.DNSClusterFirst, + Containers: []api.Container{{Name: "abc", Image: "image", ImagePullPolicy: api.PullIfNotPresent}}, + }, + }, + }, + }, + }, + } +} + +func TestCreate(t *testing.T) { + // scheduled jobs should be tested only when batch/v2alpha1 is enabled + if *testapi.Batch.GroupVersion() != v2alpha1.SchemeGroupVersion { + return + } + + storage, _, server := newStorage(t) + defer server.Terminate(t) + test := registrytest.New(t, storage.Store) + validScheduledJob := validNewScheduledJob() + validScheduledJob.ObjectMeta = api.ObjectMeta{} + test.TestCreate( + // valid + validScheduledJob, + // invalid (empty spec) + &batch.ScheduledJob{ + Spec: batch.ScheduledJobSpec{}, + }, + ) +} + +func TestUpdate(t *testing.T) { + // scheduled jobs should be tested only when batch/v2alpha1 is enabled + if *testapi.Batch.GroupVersion() != v2alpha1.SchemeGroupVersion { + return + } + + storage, _, server := newStorage(t) + defer server.Terminate(t) + test := registrytest.New(t, storage.Store) + schedule := "1 1 1 1 1 ?" + test.TestUpdate( + // valid + validNewScheduledJob(), + // updateFunc + func(obj runtime.Object) runtime.Object { + object := obj.(*batch.ScheduledJob) + object.Spec.Schedule = schedule + return object + }, + // invalid updateFunc + func(obj runtime.Object) runtime.Object { + object := obj.(*batch.ScheduledJob) + object.Spec.Schedule = "* * *" + return object + }, + ) +} + +func TestDelete(t *testing.T) { + // scheduled jobs should be tested only when batch/v2alpha1 is enabled + if *testapi.Batch.GroupVersion() != v2alpha1.SchemeGroupVersion { + return + } + + storage, _, server := newStorage(t) + defer server.Terminate(t) + test := registrytest.New(t, storage.Store) + test.TestDelete(validNewScheduledJob()) +} + +func TestGet(t *testing.T) { + // scheduled jobs should be tested only when batch/v2alpha1 is enabled + if *testapi.Batch.GroupVersion() != v2alpha1.SchemeGroupVersion { + return + } + + storage, _, server := newStorage(t) + defer server.Terminate(t) + test := registrytest.New(t, storage.Store) + test.TestGet(validNewScheduledJob()) +} + +func TestList(t *testing.T) { + // scheduled jobs should be tested only when batch/v2alpha1 is enabled + if *testapi.Batch.GroupVersion() != v2alpha1.SchemeGroupVersion { + return + } + + storage, _, server := newStorage(t) + defer server.Terminate(t) + test := registrytest.New(t, storage.Store) + test.TestList(validNewScheduledJob()) +} + +func TestWatch(t *testing.T) { + // scheduled jobs should be tested only when batch/v2alpha1 is enabled + if *testapi.Batch.GroupVersion() != v2alpha1.SchemeGroupVersion { + return + } + + storage, _, server := newStorage(t) + defer server.Terminate(t) + test := registrytest.New(t, storage.Store) + test.TestWatch( + validNewScheduledJob(), + // matching labels + []labels.Set{}, + // not matching labels + []labels.Set{ + {"x": "y"}, + }, + // matching fields + []fields.Set{}, + // not matching fields + []fields.Set{ + {"metadata.name": "xyz"}, + {"name": "foo"}, + }, + ) +} + +// TODO: test update /status diff --git a/test/e2e/framework/framework.go b/test/e2e/framework/framework.go index a7649e7c77b..cf41ecffdd0 100644 --- a/test/e2e/framework/framework.go +++ b/test/e2e/framework/framework.go @@ -324,7 +324,7 @@ func (f *Framework) AfterEach() { case "json": for i := range summaries { typeName := reflect.TypeOf(summaries[i]).String() - Logf("%v JSON\n%v", typeName[strings.LastIndex(typeName, ".")+1:len(typeName)], summaries[i].PrintJSON()) + Logf("%v JSON\n%v", typeName[strings.LastIndex(typeName, ".")+1:], summaries[i].PrintJSON()) Logf("Finished") } default: