diff --git a/hack/test-cmd.sh b/hack/test-cmd.sh index 565fafb3c6c..46207d88783 100755 --- a/hack/test-cmd.sh +++ b/hack/test-cmd.sh @@ -178,7 +178,7 @@ kube::log::status "Starting kube-apiserver" # Admission Controllers to invoke prior to persisting objects in cluster ADMISSION_CONTROL="NamespaceLifecycle,LimitRanger,ResourceQuota" -KUBE_API_VERSIONS="v1,autoscaling/v1,extensions/v1beta1" "${KUBE_OUTPUT_HOSTBIN}/kube-apiserver" \ +KUBE_API_VERSIONS="v1,autoscaling/v1,batch/v1,extensions/v1beta1" "${KUBE_OUTPUT_HOSTBIN}/kube-apiserver" \ --address="127.0.0.1" \ --public-address-override="127.0.0.1" \ --port="${API_PORT}" \ @@ -1601,7 +1601,7 @@ kube_api_versions=( v1 ) for version in "${kube_api_versions[@]}"; do - KUBE_API_VERSIONS="v1,autoscaling/v1,extensions/v1beta1" runTests "${version}" + KUBE_API_VERSIONS="v1,autoscaling/v1,batch/v1,extensions/v1beta1" runTests "${version}" done kube::log::status "TEST PASSED" diff --git a/hack/test-go.sh b/hack/test-go.sh index 7f55d71b6be..5d3c5124c16 100755 --- a/hack/test-go.sh +++ b/hack/test-go.sh @@ -58,7 +58,7 @@ KUBE_GOVERALLS_BIN=${KUBE_GOVERALLS_BIN:-} # Lists of API Versions of each groups that should be tested, groups are # separated by comma, lists are separated by semicolon. e.g., # "v1,compute/v1alpha1,experimental/v1alpha2;v1,compute/v2,experimental/v1alpha3" -KUBE_TEST_API_VERSIONS=${KUBE_TEST_API_VERSIONS:-"v1,extensions/v1beta1,metrics/v1alpha1;v1,autoscaling/v1,extensions/v1beta1,metrics/v1alpha1"} +KUBE_TEST_API_VERSIONS=${KUBE_TEST_API_VERSIONS:-"v1,extensions/v1beta1,metrics/v1alpha1;v1,autoscaling/v1,batch/v1,extensions/v1beta1,metrics/v1alpha1"} # once we have multiple group supports # Run tests with the standard (registry) and a custom etcd prefix # (kubernetes.io/registry). @@ -315,7 +315,7 @@ for (( i=0, j=0; ; )); do # KUBE_TEST_API sets the version of each group to be tested. KUBE_API_VERSIONS # register the groups/versions as supported by k8s. So KUBE_API_VERSIONS # needs to be the superset of KUBE_TEST_API. - KUBE_TEST_API="${apiVersion}" KUBE_API_VERSIONS="v1,autoscaling/v1,extensions/v1beta1,componentconfig/v1alpha1,metrics/v1alpha1" ETCD_PREFIX=${etcdPrefix} runTests "$@" + KUBE_TEST_API="${apiVersion}" KUBE_API_VERSIONS="v1,autoscaling/v1,batch/v1,extensions/v1beta1,componentconfig/v1alpha1,metrics/v1alpha1" ETCD_PREFIX=${etcdPrefix} runTests "$@" i=${i}+1 j=${j}+1 if [[ i -eq ${apiVersionsCount} ]] && [[ j -eq ${etcdPrefixesCount} ]]; then diff --git a/hack/test-integration.sh b/hack/test-integration.sh index 75266a344d9..d97980287e9 100755 --- a/hack/test-integration.sh +++ b/hack/test-integration.sh @@ -29,7 +29,7 @@ source "${KUBE_ROOT}/hack/lib/init.sh" # "v1,compute/v1alpha1,experimental/v1alpha2;v1,compute/v2,experimental/v1alpha3" # TODO: It's going to be: # KUBE_TEST_API_VERSIONS=${KUBE_TEST_API_VERSIONS:-"v1,extensions/v1beta1"} -KUBE_TEST_API_VERSIONS=${KUBE_TEST_API_VERSIONS:-"v1,extensions/v1beta1;v1,autoscaling/v1,extensions/v1beta1"} +KUBE_TEST_API_VERSIONS=${KUBE_TEST_API_VERSIONS:-"v1,extensions/v1beta1;v1,autoscaling/v1,batch/v1,extensions/v1beta1"} # Give integration tests longer to run KUBE_TIMEOUT=${KUBE_TIMEOUT:--timeout 240s} @@ -52,21 +52,21 @@ runTests() { KUBE_RACE="" \ KUBE_TIMEOUT="${KUBE_TIMEOUT}" \ KUBE_TEST_API_VERSIONS="$1" \ - KUBE_API_VERSIONS="v1,autoscaling/v1,extensions/v1beta1" \ + KUBE_API_VERSIONS="v1,autoscaling/v1,batch/v1,extensions/v1beta1" \ "${KUBE_ROOT}/hack/test-go.sh" test/integration kube::log::status "Running integration test scenario with watch cache on" - KUBE_API_VERSIONS="v1,autoscaling/v1,extensions/v1beta1" KUBE_TEST_API_VERSIONS="$1" "${KUBE_OUTPUT_HOSTBIN}/integration" --v=${LOG_LEVEL} \ + KUBE_API_VERSIONS="v1,autoscaling/v1,batch/v1,extensions/v1beta1" KUBE_TEST_API_VERSIONS="$1" "${KUBE_OUTPUT_HOSTBIN}/integration" --v=${LOG_LEVEL} \ --max-concurrency="${KUBE_INTEGRATION_TEST_MAX_CONCURRENCY}" --watch-cache=true kube::log::status "Running integration test scenario with watch cache off" - KUBE_API_VERSIONS="v1,autoscaling/v1,extensions/v1beta1" KUBE_TEST_API_VERSIONS="$1" "${KUBE_OUTPUT_HOSTBIN}/integration" --v=${LOG_LEVEL} \ + KUBE_API_VERSIONS="v1,autoscaling/v1,batch/v1,extensions/v1beta1" KUBE_TEST_API_VERSIONS="$1" "${KUBE_OUTPUT_HOSTBIN}/integration" --v=${LOG_LEVEL} \ --max-concurrency="${KUBE_INTEGRATION_TEST_MAX_CONCURRENCY}" --watch-cache=false cleanup } -KUBE_API_VERSIONS="v1,autoscaling/v1,extensions/v1beta1" "${KUBE_ROOT}/hack/build-go.sh" "$@" cmd/integration +KUBE_API_VERSIONS="v1,autoscaling/v1,batch/v1,extensions/v1beta1" "${KUBE_ROOT}/hack/build-go.sh" "$@" cmd/integration # Run cleanup to stop etcd on interrupt or other kill signal. trap cleanup EXIT diff --git a/pkg/api/testapi/testapi.go b/pkg/api/testapi/testapi.go index f6f75e87972..965e6f3dee3 100644 --- a/pkg/api/testapi/testapi.go +++ b/pkg/api/testapi/testapi.go @@ -27,6 +27,7 @@ import ( "k8s.io/kubernetes/pkg/api/unversioned" "k8s.io/kubernetes/pkg/apimachinery/registered" "k8s.io/kubernetes/pkg/apis/autoscaling" + "k8s.io/kubernetes/pkg/apis/batch" "k8s.io/kubernetes/pkg/apis/extensions" "k8s.io/kubernetes/pkg/runtime" @@ -41,6 +42,7 @@ var ( Groups = make(map[string]TestGroup) Default TestGroup Autoscaling TestGroup + Batch TestGroup Extensions TestGroup ) @@ -78,6 +80,12 @@ func init() { internalGroupVersion: extensions.SchemeGroupVersion, } } + if _, ok := Groups[batch.GroupName]; !ok { + Groups[batch.GroupName] = TestGroup{ + externalGroupVersion: unversioned.GroupVersion{Group: batch.GroupName, Version: registered.GroupOrDie(batch.GroupName).GroupVersion.Version}, + internalGroupVersion: extensions.SchemeGroupVersion, + } + } if _, ok := Groups[extensions.GroupName]; !ok { Groups[extensions.GroupName] = TestGroup{ externalGroupVersion: unversioned.GroupVersion{Group: extensions.GroupName, Version: registered.GroupOrDie(extensions.GroupName).GroupVersion.Version}, @@ -87,6 +95,7 @@ func init() { Default = Groups[api.GroupName] Autoscaling = Groups[autoscaling.GroupName] + Batch = Groups[batch.GroupName] Extensions = Groups[extensions.GroupName] } diff --git a/pkg/api/testapi/testapi_test.go b/pkg/api/testapi/testapi_test.go index 7d9ad0ec0d9..aa049f91d86 100644 --- a/pkg/api/testapi/testapi_test.go +++ b/pkg/api/testapi/testapi_test.go @@ -128,6 +128,10 @@ func TestAutoscalingEncodeDecodeStatus(t *testing.T) { testEncodeDecodeStatus(t, Autoscaling.Codec()) } +func TestBatchEncodeDecodeStatus(t *testing.T) { + testEncodeDecodeStatus(t, Batch.Codec()) +} + func TestExperimentalEncodeDecodeStatus(t *testing.T) { testEncodeDecodeStatus(t, Extensions.Codec()) } diff --git a/pkg/client/unversioned/jobs_test.go b/pkg/client/unversioned/jobs_test.go index 76a87eab004..b65f5339c9b 100644 --- a/pkg/client/unversioned/jobs_test.go +++ b/pkg/client/unversioned/jobs_test.go @@ -33,7 +33,7 @@ func getJobResourceName() string { return "jobs" } -func TestListJobs(t *testing.T) { +func TestListJobsViaExtensions(t *testing.T) { ns := api.NamespaceAll c := &simple.Client{ Request: simple.Request{ @@ -64,7 +64,7 @@ func TestListJobs(t *testing.T) { c.Validate(t, receivedJobList, err) } -func TestGetJob(t *testing.T) { +func TestGetJobViaExtensions(t *testing.T) { ns := api.NamespaceDefault c := &simple.Client{ Request: simple.Request{ @@ -93,7 +93,7 @@ func TestGetJob(t *testing.T) { c.Validate(t, receivedJob, err) } -func TestGetJobWithNoName(t *testing.T) { +func TestGetJobWithNoNameViaExtensions(t *testing.T) { ns := api.NamespaceDefault c := &simple.Client{Error: true} receivedJob, err := c.Setup(t).Extensions().Jobs(ns).Get("") @@ -105,7 +105,7 @@ func TestGetJobWithNoName(t *testing.T) { c.Validate(t, receivedJob, err) } -func TestUpdateJob(t *testing.T) { +func TestUpdateJobViaExtensions(t *testing.T) { ns := api.NamespaceDefault requestJob := &extensions.Job{ ObjectMeta: api.ObjectMeta{ @@ -141,7 +141,7 @@ func TestUpdateJob(t *testing.T) { c.Validate(t, receivedJob, err) } -func TestUpdateJobStatus(t *testing.T) { +func TestUpdateJobStatusViaExtensions(t *testing.T) { ns := api.NamespaceDefault requestJob := &extensions.Job{ ObjectMeta: api.ObjectMeta{ @@ -180,7 +180,7 @@ func TestUpdateJobStatus(t *testing.T) { c.Validate(t, receivedJob, err) } -func TestDeleteJob(t *testing.T) { +func TestDeleteJobViaExtensions(t *testing.T) { ns := api.NamespaceDefault c := &simple.Client{ Request: simple.Request{ @@ -195,7 +195,7 @@ func TestDeleteJob(t *testing.T) { c.Validate(t, nil, err) } -func TestCreateJob(t *testing.T) { +func TestCreateJobViaExtensions(t *testing.T) { ns := api.NamespaceDefault requestJob := &extensions.Job{ ObjectMeta: api.ObjectMeta{ @@ -230,3 +230,203 @@ func TestCreateJob(t *testing.T) { defer c.Close() c.Validate(t, receivedJob, err) } + +// Tests below are a copy of the above tests. Once job is removed from extensions, above test cases can be deleted. + +func TestListJobsViaBatch(t *testing.T) { + ns := api.NamespaceAll + c := &simple.Client{ + Request: simple.Request{ + Method: "GET", + Path: testapi.Batch.ResourcePath(getJobResourceName(), ns, ""), + }, + Response: simple.Response{StatusCode: 200, + Body: &extensions.JobList{ + Items: []extensions.Job{ + { + ObjectMeta: api.ObjectMeta{ + Name: "foo", + Labels: map[string]string{ + "foo": "bar", + "name": "baz", + }, + }, + Spec: extensions.JobSpec{ + Template: api.PodTemplateSpec{}, + }, + }, + }, + }, + }, + } + receivedJobList, err := c.Setup(t).Batch().Jobs(ns).List(api.ListOptions{}) + defer c.Close() + c.Validate(t, receivedJobList, err) +} + +func TestGetJobViaBatch(t *testing.T) { + ns := api.NamespaceDefault + c := &simple.Client{ + Request: simple.Request{ + Method: "GET", + Path: testapi.Batch.ResourcePath(getJobResourceName(), ns, "foo"), + Query: simple.BuildQueryValues(nil), + }, + Response: simple.Response{ + StatusCode: 200, + Body: &extensions.Job{ + ObjectMeta: api.ObjectMeta{ + Name: "foo", + Labels: map[string]string{ + "foo": "bar", + "name": "baz", + }, + }, + Spec: extensions.JobSpec{ + Template: api.PodTemplateSpec{}, + }, + }, + }, + } + receivedJob, err := c.Setup(t).Batch().Jobs(ns).Get("foo") + defer c.Close() + c.Validate(t, receivedJob, err) +} + +func TestGetJobWithNoNameViaBatch(t *testing.T) { + ns := api.NamespaceDefault + c := &simple.Client{Error: true} + receivedJob, err := c.Setup(t).Batch().Jobs(ns).Get("") + defer c.Close() + if (err != nil) && (err.Error() != simple.NameRequiredError) { + t.Errorf("Expected error: %v, but got %v", simple.NameRequiredError, err) + } + + c.Validate(t, receivedJob, err) +} + +func TestUpdateJobViaBatch(t *testing.T) { + ns := api.NamespaceDefault + requestJob := &extensions.Job{ + ObjectMeta: api.ObjectMeta{ + Name: "foo", + Namespace: ns, + ResourceVersion: "1", + }, + } + c := &simple.Client{ + Request: simple.Request{ + Method: "PUT", + Path: testapi.Batch.ResourcePath(getJobResourceName(), ns, "foo"), + Query: simple.BuildQueryValues(nil), + }, + Response: simple.Response{ + StatusCode: 200, + Body: &extensions.Job{ + ObjectMeta: api.ObjectMeta{ + Name: "foo", + Labels: map[string]string{ + "foo": "bar", + "name": "baz", + }, + }, + Spec: extensions.JobSpec{ + Template: api.PodTemplateSpec{}, + }, + }, + }, + } + receivedJob, err := c.Setup(t).Batch().Jobs(ns).Update(requestJob) + defer c.Close() + c.Validate(t, receivedJob, err) +} + +func TestUpdateJobStatusViaBatch(t *testing.T) { + ns := api.NamespaceDefault + requestJob := &extensions.Job{ + ObjectMeta: api.ObjectMeta{ + Name: "foo", + Namespace: ns, + ResourceVersion: "1", + }, + } + c := &simple.Client{ + Request: simple.Request{ + Method: "PUT", + Path: testapi.Batch.ResourcePath(getJobResourceName(), ns, "foo") + "/status", + Query: simple.BuildQueryValues(nil), + }, + Response: simple.Response{ + StatusCode: 200, + Body: &extensions.Job{ + ObjectMeta: api.ObjectMeta{ + Name: "foo", + Labels: map[string]string{ + "foo": "bar", + "name": "baz", + }, + }, + Spec: extensions.JobSpec{ + Template: api.PodTemplateSpec{}, + }, + Status: extensions.JobStatus{ + Active: 1, + }, + }, + }, + } + receivedJob, err := c.Setup(t).Batch().Jobs(ns).UpdateStatus(requestJob) + defer c.Close() + c.Validate(t, receivedJob, err) +} + +func TestDeleteJobViaBatch(t *testing.T) { + ns := api.NamespaceDefault + c := &simple.Client{ + Request: simple.Request{ + Method: "DELETE", + Path: testapi.Batch.ResourcePath(getJobResourceName(), ns, "foo"), + Query: simple.BuildQueryValues(nil), + }, + Response: simple.Response{StatusCode: 200}, + } + err := c.Setup(t).Batch().Jobs(ns).Delete("foo", nil) + defer c.Close() + c.Validate(t, nil, err) +} + +func TestCreateJobViaBatch(t *testing.T) { + ns := api.NamespaceDefault + requestJob := &extensions.Job{ + ObjectMeta: api.ObjectMeta{ + Name: "foo", + Namespace: ns, + }, + } + c := &simple.Client{ + Request: simple.Request{ + Method: "POST", + Path: testapi.Batch.ResourcePath(getJobResourceName(), ns, ""), + Body: requestJob, + Query: simple.BuildQueryValues(nil), + }, + Response: simple.Response{ + StatusCode: 200, + Body: &extensions.Job{ + ObjectMeta: api.ObjectMeta{ + Name: "foo", + Labels: map[string]string{ + "foo": "bar", + "name": "baz", + }, + }, + Spec: extensions.JobSpec{ + Template: api.PodTemplateSpec{}, + }, + }, + }, + } + receivedJob, err := c.Setup(t).Batch().Jobs(ns).Create(requestJob) + defer c.Close() + c.Validate(t, receivedJob, err) +} diff --git a/pkg/master/master_test.go b/pkg/master/master_test.go index f108c75d48d..94265abd08c 100644 --- a/pkg/master/master_test.go +++ b/pkg/master/master_test.go @@ -36,6 +36,7 @@ import ( utilnet "k8s.io/kubernetes/pkg/util/net" "k8s.io/kubernetes/pkg/apis/autoscaling" + "k8s.io/kubernetes/pkg/apis/batch" "k8s.io/kubernetes/pkg/apis/extensions" "k8s.io/kubernetes/pkg/genericapiserver" "k8s.io/kubernetes/pkg/kubelet/client" @@ -69,12 +70,15 @@ func setUp(t *testing.T) (Master, *etcdtesting.EtcdTestServer, Config, *assert.A api.GroupName, etcdstorage.NewEtcdStorage(server.Client, testapi.Default.Codec(), etcdtest.PathPrefix(), false)) storageDestinations.AddAPIGroup( autoscaling.GroupName, etcdstorage.NewEtcdStorage(server.Client, testapi.Autoscaling.Codec(), etcdtest.PathPrefix(), false)) + storageDestinations.AddAPIGroup( + batch.GroupName, etcdstorage.NewEtcdStorage(server.Client, testapi.Batch.Codec(), etcdtest.PathPrefix(), false)) storageDestinations.AddAPIGroup( extensions.GroupName, etcdstorage.NewEtcdStorage(server.Client, testapi.Extensions.Codec(), etcdtest.PathPrefix(), false)) config.StorageDestinations = storageDestinations storageVersions[api.GroupName] = testapi.Default.GroupVersion().String() storageVersions[autoscaling.GroupName] = testapi.Autoscaling.GroupVersion().String() + storageVersions[batch.GroupName] = testapi.Batch.GroupVersion().String() storageVersions[extensions.GroupName] = testapi.Extensions.GroupVersion().String() config.StorageVersions = storageVersions config.PublicAddress = net.ParseIP("192.168.10.4") @@ -278,7 +282,7 @@ func TestDiscoveryAtAPIS(t *testing.T) { t.Fatalf("unexpected error: %v", err) } - expectGroupNames := []string{autoscaling.GroupName, extensions.GroupName} + expectGroupNames := []string{autoscaling.GroupName, batch.GroupName, extensions.GroupName} expectVersions := [][]unversioned.GroupVersionForDiscovery{ { { @@ -286,6 +290,12 @@ func TestDiscoveryAtAPIS(t *testing.T) { Version: testapi.Autoscaling.GroupVersion().Version, }, }, + { + { + GroupVersion: testapi.Batch.GroupVersion().String(), + Version: testapi.Batch.GroupVersion().Version, + }, + }, { { GroupVersion: testapi.Extensions.GroupVersion().String(), @@ -298,6 +308,10 @@ func TestDiscoveryAtAPIS(t *testing.T) { GroupVersion: config.StorageVersions[autoscaling.GroupName], Version: apiutil.GetVersion(config.StorageVersions[autoscaling.GroupName]), }, + { + GroupVersion: config.StorageVersions[batch.GroupName], + Version: apiutil.GetVersion(config.StorageVersions[batch.GroupName]), + }, { GroupVersion: config.StorageVersions[extensions.GroupName], Version: apiutil.GetVersion(config.StorageVersions[extensions.GroupName]), @@ -337,19 +351,23 @@ func TestDiscoveryAtAPIS(t *testing.T) { thirdPartyGroupName := "company.com" thirdPartyExpectVersions := []unversioned.GroupVersionForDiscovery{thirdPartyGV} - assert.Equal(3, len(groupList.Groups)) + assert.Equal(4, len(groupList.Groups)) // autoscaling group assert.Equal(expectGroupNames[0], groupList.Groups[0].Name) assert.Equal(expectVersions[0], groupList.Groups[0].Versions) assert.Equal(expectPreferredVersion[0], groupList.Groups[0].PreferredVersion) + // batch group + assert.Equal(expectGroupNames[1], groupList.Groups[1].Name) + assert.Equal(expectVersions[1], groupList.Groups[1].Versions) + assert.Equal(expectPreferredVersion[1], groupList.Groups[1].PreferredVersion) // third party - assert.Equal(thirdPartyGroupName, groupList.Groups[1].Name) - assert.Equal(thirdPartyExpectVersions, groupList.Groups[1].Versions) - assert.Equal(thirdPartyGV, groupList.Groups[1].PreferredVersion) + assert.Equal(thirdPartyGroupName, groupList.Groups[2].Name) + assert.Equal(thirdPartyExpectVersions, groupList.Groups[2].Versions) + assert.Equal(thirdPartyGV, groupList.Groups[2].PreferredVersion) // extensions group - assert.Equal(expectGroupNames[1], groupList.Groups[2].Name) - assert.Equal(expectVersions[1], groupList.Groups[2].Versions) - assert.Equal(expectPreferredVersion[1], groupList.Groups[2].PreferredVersion) + assert.Equal(expectGroupNames[2], groupList.Groups[3].Name) + assert.Equal(expectVersions[2], groupList.Groups[3].Versions) + assert.Equal(expectPreferredVersion[2], groupList.Groups[3].PreferredVersion) } var versionsToTest = []string{"v1", "v3"} diff --git a/test/integration/framework/etcd_utils.go b/test/integration/framework/etcd_utils.go index 8270e423268..cdd7fbdc80b 100644 --- a/test/integration/framework/etcd_utils.go +++ b/test/integration/framework/etcd_utils.go @@ -59,6 +59,13 @@ func NewAutoscalingEtcdStorage(client etcd.Client) storage.Interface { return etcdstorage.NewEtcdStorage(client, testapi.Autoscaling.Codec(), etcdtest.PathPrefix(), false) } +func NewBatchEtcdStorage(client etcd.Client) storage.Interface { + if client == nil { + client = NewEtcdClient() + } + return etcdstorage.NewEtcdStorage(client, testapi.Batch.Codec(), etcdtest.PathPrefix(), false) +} + func NewExtensionsEtcdStorage(client etcd.Client) storage.Interface { if client == nil { client = NewEtcdClient() diff --git a/test/integration/framework/master_utils.go b/test/integration/framework/master_utils.go index 2fb7a6e80f2..edef5355472 100644 --- a/test/integration/framework/master_utils.go +++ b/test/integration/framework/master_utils.go @@ -30,6 +30,7 @@ import ( "k8s.io/kubernetes/pkg/api" "k8s.io/kubernetes/pkg/api/testapi" "k8s.io/kubernetes/pkg/apis/autoscaling" + "k8s.io/kubernetes/pkg/apis/batch" "k8s.io/kubernetes/pkg/apis/extensions" "k8s.io/kubernetes/pkg/apiserver" clientset "k8s.io/kubernetes/pkg/client/clientset_generated/internalclientset" @@ -153,12 +154,15 @@ func NewMasterConfig() *master.Config { storageVersions[api.GroupName] = testapi.Default.GroupVersion().String() autoscalingEtcdStorage := NewAutoscalingEtcdStorage(etcdClient) storageVersions[autoscaling.GroupName] = testapi.Autoscaling.GroupVersion().String() + batchEtcdStorage := NewBatchEtcdStorage(etcdClient) + storageVersions[batch.GroupName] = testapi.Batch.GroupVersion().String() expEtcdStorage := NewExtensionsEtcdStorage(etcdClient) storageVersions[extensions.GroupName] = testapi.Extensions.GroupVersion().String() storageDestinations := genericapiserver.NewStorageDestinations() storageDestinations.AddAPIGroup(api.GroupName, etcdStorage) storageDestinations.AddAPIGroup(autoscaling.GroupName, autoscalingEtcdStorage) + storageDestinations.AddAPIGroup(batch.GroupName, batchEtcdStorage) storageDestinations.AddAPIGroup(extensions.GroupName, expEtcdStorage) return &master.Config{ diff --git a/test/integration/master_test.go b/test/integration/master_test.go index 15b6a43fde8..0fd68feaf85 100644 --- a/test/integration/master_test.go +++ b/test/integration/master_test.go @@ -51,6 +51,10 @@ func TestAutoscalingPrefix(t *testing.T) { testPrefix(t, "/apis/autoscaling/") } +func TestBatchPrefix(t *testing.T) { + testPrefix(t, "/apis/batch/") +} + func TestExtensionsPrefix(t *testing.T) { testPrefix(t, "/apis/extensions/") } @@ -95,6 +99,10 @@ func autoscalingPath(resource, namespace, name string) string { return testapi.Autoscaling.ResourcePath(resource, namespace, name) } +func batchPath(resource, namespace, name string) string { + return testapi.Batch.ResourcePath(resource, namespace, name) +} + func extensionsPath(resource, namespace, name string) string { return testapi.Extensions.ResourcePath(resource, namespace, name) } @@ -145,6 +153,152 @@ func TestAutoscalingGroupBackwardCompatibility(t *testing.T) { } } +var jobV1beta1 string = ` +{ + "kind": "Job", + "apiVersion": "extensions/v1beta1", + "metadata": { + "name": "pi", + "labels": { + "app": "pi" + } + }, + "spec": { + "parallelism": 1, + "completions": 1, + "selector": { + "matchLabels": { + "app": "pi" + } + }, + "template": { + "metadata": { + "name": "pi", + "creationTimestamp": null, + "labels": { + "app": "pi" + } + }, + "spec": { + "containers": [ + { + "name": "pi", + "image": "perl", + "command": [ + "perl", + "-Mbignum=bpi", + "-wle", + "print bpi(2000)" + ] + } + ], + "restartPolicy": "Never" + } + } + } +} +` + +var jobV1 string = ` +{ + "kind": "Job", + "apiVersion": "batch/v1", + "metadata": { + "name": "pi", + "labels": { + "app": "pi" + } + }, + "spec": { + "parallelism": 1, + "completions": 1, + "selector": { + "matchLabels": { + "app": "pi" + } + }, + "template": { + "metadata": { + "name": "pi", + "creationTimestamp": null, + "labels": { + "app": "pi" + } + }, + "spec": { + "containers": [ + { + "name": "pi", + "image": "perl", + "command": [ + "perl", + "-Mbignum=bpi", + "-wle", + "print bpi(2000)" + ] + } + ], + "restartPolicy": "Never" + } + } + } +} +` + +// TestBatchGroupBackwardCompatibility is testing that batch/v1 and ext/v1beta1 +// Job share storage. This test can be deleted when Jobs is removed from ext/v1beta1, +// (expected to happen in 1.4). +func TestBatchGroupBackwardCompatibility(t *testing.T) { + _, s := framework.RunAMaster(t) + defer s.Close() + transport := http.DefaultTransport + + requests := []struct { + verb string + URL string + body string + expectedStatusCodes map[int]bool + expectedVersion string + }{ + // Post a v1 and get back both as v1beta1 and as v1. + {"POST", batchPath("jobs", api.NamespaceDefault, ""), jobV1, code201, ""}, + {"GET", batchPath("jobs", api.NamespaceDefault, ""), "", code200, testapi.Batch.GroupVersion().String()}, + {"GET", extensionsPath("jobs", api.NamespaceDefault, ""), "", code200, testapi.Extensions.GroupVersion().String()}, + // Post a v1beta1 and get back both as v1beta1 and as v1. + {"POST", extensionsPath("jobs", api.NamespaceDefault, ""), jobV1beta1, code201, ""}, + {"GET", batchPath("jobs", api.NamespaceDefault, ""), "", code200, testapi.Batch.GroupVersion().String()}, + {"GET", extensionsPath("jobs", api.NamespaceDefault, ""), "", code200, testapi.Extensions.GroupVersion().String()}, + } + + for _, r := range requests { + bodyBytes := bytes.NewReader([]byte(r.body)) + req, err := http.NewRequest(r.verb, s.URL+r.URL, bodyBytes) + if err != nil { + t.Logf("case %v", r) + t.Fatalf("unexpected error: %v", err) + } + func() { + resp, err := transport.RoundTrip(req) + defer resp.Body.Close() + if err != nil { + t.Logf("case %v", r) + t.Fatalf("unexpected error: %v", err) + } + b, _ := ioutil.ReadAll(resp.Body) + body := string(b) + if _, ok := r.expectedStatusCodes[resp.StatusCode]; !ok { + t.Logf("case %v", r) + t.Errorf("Expected status one of %v, but got %v", r.expectedStatusCodes, resp.StatusCode) + t.Errorf("Body: %v", body) + } + if !strings.Contains(body, "\"apiVersion\":\""+r.expectedVersion) { + t.Logf("case %v", r) + t.Errorf("Expected version %v, got body %v", r.expectedVersion, body) + } + }() + } +} + func TestAccept(t *testing.T) { _, s := framework.RunAMaster(t) // TODO: Uncomment when fix #19254