Repository: furiko-io/furiko
Pull request #89 (2022-06-03 20:53:43)

feat(cli): Add enable/disable subcommands
Adds two new subcommands:

```
Usage:
  furiko [command]

Available Commands:
  ...
  disable     Disable automatic scheduling for a JobConfig.
  enable      Enable automatic scheduling for a JobConfig.
  ...
```

Detailed subcommand help:

```
Disables automatic scheduling for a JobConfig.

If the specified JobConfig does not have a schedule, then an error will be thrown.
If the specified JobConfig is already disabled, then this is a no-op.

Usage:
  furiko disable [flags]

Examples:
  # Disable scheduling for the JobConfig.
  furiko disable send-weekly-report
```

```
Enables automatic scheduling for a JobConfig.

If the specified JobConfig does not have a schedule, then an error will be thrown.
If the specified JobConfig is already enabled, then this is a no-op.

Usage:
  furiko enable [flags]

Examples:
  # Enable scheduling for the JobConfig.
  furiko enable send-weekly-report
```

codecov[bot]: # [Codecov](https://codecov.io/gh/furiko-io/furiko/pull/89?src=pr&el=h1&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=furiko-io) Report
> Merging [#89](https://codecov.io/gh/furiko-io/furiko/pull/89?src=pr&el=desc&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=furiko-io) (d2aff72) into [main](https://codecov.io/gh/furiko-io/furiko/commit/25d2757df2e1a5a814580da20ef1b8e1097613fa?el=desc&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=furiko-io) (25d2757) will **increase** coverage by `0.13%`.
> The diff coverage is `73.68%`.

```diff
@@            Coverage Diff             @@
##             main      #89      +/-   ##
==========================================
+ Coverage   62.87%   63.00%   +0.13%     
==========================================
  Files         200      202       +2     
  Lines       10334    10448     +114     
==========================================
+ Hits         6497     6583      +86     
- Misses       3489     3507      +18     
- Partials      348      358      +10     
```


| [Impacted Files](https://codecov.io/gh/furiko-io/furiko/pull/89?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=furiko-io) | Coverage Δ | |
|---|---|---|
| [pkg/cli/cmd/cmd\_disable.go](https://codecov.io/gh/furiko-io/furiko/pull/89/diff?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=furiko-io#diff-cGtnL2NsaS9jbWQvY21kX2Rpc2FibGUuZ28=) | `73.21% <73.21%> (ø)` | |
| [pkg/cli/cmd/cmd\_enable.go](https://codecov.io/gh/furiko-io/furiko/pull/89/diff?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=furiko-io#diff-cGtnL2NsaS9jbWQvY21kX2VuYWJsZS5nbw==) | `73.21% <73.21%> (ø)` | |
| [pkg/cli/cmd/cmd.go](https://codecov.io/gh/furiko-io/furiko/pull/89/diff?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=furiko-io#diff-cGtnL2NsaS9jbWQvY21kLmdv) | `92.68% <100.00%> (+0.37%)` | :arrow_up: |
| [pkg/runtime/testing/action.go](https://codecov.io/gh/furiko-io/furiko/pull/89/diff?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=furiko-io#diff-cGtnL3J1bnRpbWUvdGVzdGluZy9hY3Rpb24uZ28=) | `75.86% <0.00%> (+3.44%)` | :arrow_up: |

------

[Continue to review full report at Codecov](https://codecov.io/gh/furiko-io/furiko/pull/89?src=pr&el=continue&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=furiko-io).
> **Legend** - [Click here to learn more](https://docs.codecov.io/docs/codecov-delta?utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=furiko-io)
> `Δ = absolute <relative> (impact)`, `ø = not affected`, `? = missing data`
> Powered by [Codecov](https://codecov.io/gh/furiko-io/furiko/pull/89?src=pr&el=footer&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=furiko-io). Last update [25d2757...d2aff72](https://codecov.io/gh/furiko-io/furiko/pull/89?src=pr&el=lastupdated&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=furiko-io). Read the [comment docs](https://docs.codecov.io/docs/pull-request-comments?utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=furiko-io).


Patch:
diff --git a/pkg/cli/cmd/cmd.go b/pkg/cli/cmd/cmd.go
index 820dc97..9339d1f 100644
--- a/pkg/cli/cmd/cmd.go
+++ b/pkg/cli/cmd/cmd.go
@@ -73,6 +73,8 @@ func NewRootCommand(streams *streams.Streams) *cobra.Command {
 	cmd.AddCommand(NewListCommand(streams))
 	cmd.AddCommand(NewRunCommand(streams))
 	cmd.AddCommand(NewKillCommand(streams))
+	cmd.AddCommand(NewEnableCommand(streams))
+	cmd.AddCommand(NewDisableCommand(streams))
 
 	return cmd
 }
diff --git a/pkg/cli/cmd/cmd_disable.go b/pkg/cli/cmd/cmd_disable.go
new file mode 100644
index 0000000..a3032de
--- /dev/null
+++ b/pkg/cli/cmd/cmd_disable.go
@@ -0,0 +1,104 @@
+/*
+ * Copyright 2022 The Furiko 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 cmd
+
+import (
+	"fmt"
+
+	"github.com/pkg/errors"
+	"github.com/spf13/cobra"
+	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
+	"k8s.io/client-go/tools/cache"
+	"k8s.io/klog/v2"
+
+	"github.com/furiko-io/furiko/pkg/cli/streams"
+)
+
+var (
+	DisableExample = PrepareExample(`
+# Disable scheduling for the JobConfig.
+{{.CommandName}} disable send-weekly-report`)
+)
+
+type DisableCommand struct {
+	streams *streams.Streams
+	name    string
+}
+
+func NewDisableCommand(streams *streams.Streams) *cobra.Command {
+	c := &DisableCommand{
+		streams: streams,
+	}
+
+	cmd := &cobra.Command{
+		Use:   "disable",
+		Short: "Disable automatic scheduling for a JobConfig.",
+		Long: `Disables automatic scheduling for a JobConfig.
+
+If the specified JobConfig does not have a schedule, then an error will be thrown.
+If the specified JobConfig is already disabled, then this is a no-op.`,
+		Example: DisableExample,
+		Args:    cobra.ExactArgs(1),
+		PreRunE: PrerunWithKubeconfig,
+		RunE:    c.Run,
+	}
+
+	return cmd
+}
+
+func (c *DisableCommand) Run(cmd *cobra.Command, args []string) error {
+	ctx := cmd.Context()
+	client := ctrlContext.Clientsets().Furiko().ExecutionV1alpha1()
+	namespace, err := GetNamespace(cmd)
+	if err != nil {
+		return err
+	}
+
+	if len(args) == 0 {
+		return errors.New("job config name must be specified")
+	}
+	name := args[0]
+
+	jobConfig, err := client.JobConfigs(namespace).Get(ctx, name, metav1.GetOptions{})
+	if err != nil {
+		return errors.Wrapf(err, "cannot get job config")
+	}
+
+	key, err := cache.MetaNamespaceKeyFunc(jobConfig)
+	if err != nil {
+		return errors.Wrapf(err, "key func error")
+	}
+
+	if jobConfig.Spec.Schedule == nil {
+		return fmt.Errorf("job config has no schedule specified")
+	}
+	if jobConfig.Spec.Schedule.Disabled {
+		c.streams.Printf("Job config %v is already disabled", key)
+		return nil
+	}
+
+	newJobConfig := jobConfig.DeepCopy()
+	newJobConfig.Spec.Schedule.Disabled = true
+	updatedJobConfig, err := client.JobConfigs(namespace).Update(ctx, newJobConfig, metav1.UpdateOptions{})
+	if err != nil {
+		return errors.Wrapf(err, "cannot update job config")
+	}
+	klog.V(1).InfoS("updated job config", "namespace", updatedJobConfig.Namespace, "name", updatedJobConfig.Name)
+
+	c.streams.Printf("Successfully disabled automatic scheduling for job config %v\n", key)
+	return nil
+}
diff --git a/pkg/cli/cmd/cmd_enable.go b/pkg/cli/cmd/cmd_enable.go
new file mode 100644
index 0000000..74cfacf
--- /dev/null
+++ b/pkg/cli/cmd/cmd_enable.go
@@ -0,0 +1,104 @@
+/*
+ * Copyright 2022 The Furiko 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 cmd
+
+import (
+	"fmt"
+
+	"github.com/pkg/errors"
+	"github.com/spf13/cobra"
+	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
+	"k8s.io/client-go/tools/cache"
+	"k8s.io/klog/v2"
+
+	"github.com/furiko-io/furiko/pkg/cli/streams"
+)
+
+var (
+	EnableExample = PrepareExample(`
+# Enable scheduling for the JobConfig.
+{{.CommandName}} enable send-weekly-report`)
+)
+
+type EnableCommand struct {
+	streams *streams.Streams
+	name    string
+}
+
+func NewEnableCommand(streams *streams.Streams) *cobra.Command {
+	c := &EnableCommand{
+		streams: streams,
+	}
+
+	cmd := &cobra.Command{
+		Use:   "enable",
+		Short: "Enable automatic scheduling for a JobConfig.",
+		Long: `Enables automatic scheduling for a JobConfig.
+
+If the specified JobConfig does not have a schedule, then an error will be thrown.
+If the specified JobConfig is already enabled, then this is a no-op.`,
+		Example: EnableExample,
+		Args:    cobra.ExactArgs(1),
+		PreRunE: PrerunWithKubeconfig,
+		RunE:    c.Run,
+	}
+
+	return cmd
+}
+
+func (c *EnableCommand) Run(cmd *cobra.Command, args []string) error {
+	ctx := cmd.Context()
+	client := ctrlContext.Clientsets().Furiko().ExecutionV1alpha1()
+	namespace, err := GetNamespace(cmd)
+	if err != nil {
+		return err
+	}
+
+	if len(args) == 0 {
+		return errors.New("job config name must be specified")
+	}
+	name := args[0]
+
+	jobConfig, err := client.JobConfigs(namespace).Get(ctx, name, metav1.GetOptions{})
+	if err != nil {
+		return errors.Wrapf(err, "cannot get job config")
+	}
+
+	key, err := cache.MetaNamespaceKeyFunc(jobConfig)
+	if err != nil {
+		return errors.Wrapf(err, "key func error")
+	}
+
+	if jobConfig.Spec.Schedule == nil {
+		return fmt.Errorf("job config has no schedule specified")
+	}
+	if !jobConfig.Spec.Schedule.Disabled {
+		c.streams.Printf("Job config %v is already enabled", key)
+		return nil
+	}
+
+	newJobConfig := jobConfig.DeepCopy()
+	newJobConfig.Spec.Schedule.Disabled = false
+	updatedJobConfig, err := client.JobConfigs(namespace).Update(ctx, newJobConfig, metav1.UpdateOptions{})
+	if err != nil {
+		return errors.Wrapf(err, "cannot update job config")
+	}
+	klog.V(1).InfoS("updated job config", "namespace", updatedJobConfig.Namespace, "name", updatedJobConfig.Name)
+
+	c.streams.Printf("Successfully enabled automatic scheduling for job config %v\n", key)
+	return nil
+}
diff --git a/pkg/execution/mutation/mutation.go b/pkg/execution/mutation/mutation.go
index 55b1a50..d9bc7a8 100644
--- a/pkg/execution/mutation/mutation.go
+++ b/pkg/execution/mutation/mutation.go
@@ -67,11 +67,6 @@ func (m *Mutator) MutateJobConfig(rjc *v1alpha1.JobConfig) *webhook.Result {
 		rjc.Spec.Option = options.MutateDefaultingOptionSpec(spec)
 	}
 
-	// Mutate JobTemplate, but don't add taskTemplate fields, because they should be
-	// added only when the Job is created.
-	result.Merge(m.MutateJobTemplateSpec(&rjc.Spec.Template.Spec, false,
-		field.NewPath("spec", "template", "spec")))
-
 	return result
 }
 
@@ -134,7 +129,7 @@ func (m *Mutator) MutateJob(rj *v1alpha1.Job) *webhook.Result {
 	if rj.Spec.Template == nil {
 		rj.Spec.Template = &v1alpha1.JobTemplate{}
 	}
-	result.Merge(m.MutateJobTemplateSpec(rj.Spec.Template, true, field.NewPath("spec", "template")))
+	result.Merge(m.MutateJobTemplateSpec(rj.Spec.Template, field.NewPath("spec", "template")))
 
 	return result
 }
@@ -297,35 +292,24 @@ func (m *Mutator) evaluateOptionValues(rj *v1alpha1.Job, rjc *v1alpha1.JobConfig
 }
 
 // MutateJobTemplateSpec mutates a JobTemplate in-place.
-func (m *Mutator) MutateJobTemplateSpec(
-	spec *v1alpha1.JobTemplate,
-	taskTemplate bool,
-	fldPath *field.Path,
-) *webhook.Result {
+func (m *Mutator) MutateJobTemplateSpec(spec *v1alpha1.JobTemplate, fldPath *field.Path) *webhook.Result {
 	result := webhook.NewResult()
 
+	// Add MaxAttempts if not specified.
 	if spec.MaxAttempts == nil {
 		spec.MaxAttempts = pointer.Int64(1)
 	}
+
 	if spec.Parallelism != nil {
 		result.Merge(m.MutateParallelismSpec(spec.Parallelism, fldPath.Child("parallelism")))
 	}
-	if taskTemplate {
-		result.Merge(m.MutateTaskTemplate(&spec.TaskTemplate, fldPath.Child("taskTemplate")))
+	if spec.TaskTemplate.Pod != nil {
+		result.Merge(m.MutatePodTemplateSpec(spec.TaskTemplate.Pod, fldPath.Child("taskTemplate", "pod")))
 	}
 
 	return result
 }
 
-// MutateTaskTemplate mutates a TaskTemplate in-place.
-func (m *Mutator) MutateTaskTemplate(spec *v1alpha1.TaskTemplate, fldPath *field.Path) *webhook.Result {
-	result := webhook.NewResult()
-	if spec.Pod != nil {
-		result.Merge(m.MutatePodTemplateSpec(spec.Pod, fldPath.Child("pod")))
-	}
-	return result
-}
-
 // MutateParallelismSpec mutates ParallelismSpec in-place.
 func (m *Mutator) MutateParallelismSpec(spec *v1alpha1.ParallelismSpec, fldPath *field.Path) *webhook.Result {
 	result := webhook.NewResult()


Test patch:
diff --git a/pkg/cli/cmd/cmd_disable_test.go b/pkg/cli/cmd/cmd_disable_test.go
new file mode 100644
index 0000000..0902f4e
--- /dev/null
+++ b/pkg/cli/cmd/cmd_disable_test.go
@@ -0,0 +1,78 @@
+/*
+ * Copyright 2022 The Furiko 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 cmd_test
+
+import (
+	"testing"
+
+	"github.com/stretchr/testify/assert"
+	"k8s.io/apimachinery/pkg/runtime"
+
+	"github.com/furiko-io/furiko/pkg/cli/cmd"
+	runtimetesting "github.com/furiko-io/furiko/pkg/runtime/testing"
+)
+
+func TestDisableCommand(t *testing.T) {
+	runtimetesting.RunCommandTests(t, []runtimetesting.CommandTest{
+		{
+			Name: "display help",
+			Args: []string{"disable", "--help"},
+			Stdout: runtimetesting.Output{
+				Contains: cmd.DisableExample,
+			},
+		},
+		{
+			Name:      "need an argument",
+			Args:      []string{"disable"},
+			WantError: assert.Error,
+		},
+		{
+			Name:      "job config does not exist",
+			Args:      []string{"run", "periodic-jobconfig"},
+			WantError: runtimetesting.AssertErrorIsNotFound(),
+		},
+		{
+			Name:     "already disabled",
+			Args:     []string{"disable", "periodic-jobconfig"},
+			Fixtures: []runtime.Object{disabledJobConfig},
+			Stdout: runtimetesting.Output{
+				Contains: "is already disabled",
+			},
+		},
+		{
+			Name:      "job config has no schedule",
+			Args:      []string{"disable", "adhoc-jobconfig"},
+			Fixtures:  []runtime.Object{adhocJobConfig},
+			WantError: assert.Error,
+		},
+		{
+			Name:     "successfully disabled",
+			Args:     []string{"disable", "periodic-jobconfig"},
+			Fixtures: []runtime.Object{periodicJobConfig},
+			Stdout: runtimetesting.Output{
+				Contains: "Successfully disabled automatic scheduling",
+			},
+			WantActions: runtimetesting.CombinedActions{
+				Furiko: runtimetesting.ActionTest{
+					Actions: []runtimetesting.Action{
+						runtimetesting.NewUpdateJobConfigAction(DefaultNamespace, disabledJobConfig),
+					},
+				},
+			},
+		},
+	})
+}
diff --git a/pkg/cli/cmd/cmd_enable_test.go b/pkg/cli/cmd/cmd_enable_test.go
new file mode 100644
index 0000000..8f01623
--- /dev/null
+++ b/pkg/cli/cmd/cmd_enable_test.go
@@ -0,0 +1,78 @@
+/*
+ * Copyright 2022 The Furiko 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 cmd_test
+
+import (
+	"testing"
+
+	"github.com/stretchr/testify/assert"
+	"k8s.io/apimachinery/pkg/runtime"
+
+	"github.com/furiko-io/furiko/pkg/cli/cmd"
+	runtimetesting "github.com/furiko-io/furiko/pkg/runtime/testing"
+)
+
+func TestEnableCommand(t *testing.T) {
+	runtimetesting.RunCommandTests(t, []runtimetesting.CommandTest{
+		{
+			Name: "display help",
+			Args: []string{"enable", "--help"},
+			Stdout: runtimetesting.Output{
+				Contains: cmd.EnableExample,
+			},
+		},
+		{
+			Name:      "need an argument",
+			Args:      []string{"enable"},
+			WantError: assert.Error,
+		},
+		{
+			Name:      "job config does not exist",
+			Args:      []string{"run", "periodic-jobconfig"},
+			WantError: runtimetesting.AssertErrorIsNotFound(),
+		},
+		{
+			Name:     "successfully enabled",
+			Args:     []string{"enable", "periodic-jobconfig"},
+			Fixtures: []runtime.Object{disabledJobConfig},
+			Stdout: runtimetesting.Output{
+				Contains: "Successfully enabled automatic scheduling",
+			},
+			WantActions: runtimetesting.CombinedActions{
+				Furiko: runtimetesting.ActionTest{
+					Actions: []runtimetesting.Action{
+						runtimetesting.NewUpdateJobConfigAction(DefaultNamespace, periodicJobConfig),
+					},
+				},
+			},
+		},
+		{
+			Name:     "already enabled",
+			Args:     []string{"enable", "periodic-jobconfig"},
+			Fixtures: []runtime.Object{periodicJobConfig},
+			Stdout: runtimetesting.Output{
+				Contains: "is already enabled",
+			},
+		},
+		{
+			Name:      "job config has no schedule",
+			Args:      []string{"enable", "adhoc-jobconfig"},
+			Fixtures:  []runtime.Object{adhocJobConfig},
+			WantError: assert.Error,
+		},
+	})
+}
diff --git a/pkg/cli/cmd/cmd_get_jobconfig_test.go b/pkg/cli/cmd/cmd_get_jobconfig_test.go
index 7c7c07c..77a2c3c 100644
--- a/pkg/cli/cmd/cmd_get_jobconfig_test.go
+++ b/pkg/cli/cmd/cmd_get_jobconfig_test.go
@@ -50,6 +50,28 @@ var (
 		},
 	}
 
+	disabledJobConfig = &execution.JobConfig{
+		ObjectMeta: metav1.ObjectMeta{
+			Name:      "periodic-jobconfig",
+			Namespace: DefaultNamespace,
+		},
+		Spec: execution.JobConfigSpec{
+			Concurrency: execution.ConcurrencySpec{
+				Policy: execution.ConcurrencyPolicyForbid,
+			},
+			Schedule: &execution.ScheduleSpec{
+				Cron: &execution.CronSchedule{
+					Expression: "H/5 * * * *",
+					Timezone:   "Asia/Singapore",
+				},
+				Disabled: true,
+			},
+		},
+		Status: execution.JobConfigStatus{
+			State: execution.JobConfigReadyEnabled,
+		},
+	}
+
 	adhocJobConfig = &execution.JobConfig{
 		ObjectMeta: metav1.ObjectMeta{
 			Name:      "adhoc-jobconfig",
diff --git a/pkg/execution/mutation/mutation_test.go b/pkg/execution/mutation/mutation_test.go
index b289130..4a130dd 100644
--- a/pkg/execution/mutation/mutation_test.go
+++ b/pkg/execution/mutation/mutation_test.go
@@ -163,15 +163,6 @@ var (
 		},
 	}
 
-	jobConfigJobTemplateSpecBasic = v1alpha1.JobTemplateSpec{
-		Spec: v1alpha1.JobTemplate{
-			TaskTemplate: v1alpha1.TaskTemplate{
-				Pod: &podTemplateSpecBasic,
-			},
-			MaxAttempts: pointer.Int64(1),
-		},
-	}
-
 	jobTemplateSpecBasic2 = v1alpha1.JobTemplateSpec{
 		Spec: v1alpha1.JobTemplate{
 			TaskTemplate: v1alpha1.TaskTemplate{
@@ -232,7 +223,7 @@ func TestMutator_MutateJobConfig(t *testing.T) {
 			rjc: &v1alpha1.JobConfig{
 				ObjectMeta: objectMetaJobConfig,
 				Spec: v1alpha1.JobConfigSpec{
-					Template: jobConfigJobTemplateSpecBasic,
+					Template: jobTemplateSpecBasic,
 				},
 			},
 		},
@@ -246,42 +237,6 @@ func TestMutator_MutateJobConfig(t *testing.T) {
 							TaskTemplate: v1alpha1.TaskTemplate{
 								Pod: &podTemplateSpecBare,
 							},
-							MaxAttempts: pointer.Int64(1),
-						},
-					},
-				},
-			},
-		},
-		{
-			name: "add default JobTemplate values",
-			rjc: &v1alpha1.JobConfig{
-				ObjectMeta: objectMetaJobConfig,
-				Spec: v1alpha1.JobConfigSpec{
-					Template: v1alpha1.JobTemplateSpec{
-						Spec: v1alpha1.JobTemplate{
-							TaskTemplate: v1alpha1.TaskTemplate{
-								Pod: &podTemplateSpecBare,
-							},
-							Parallelism: &v1alpha1.ParallelismSpec{
-								WithCount: pointer.Int64(3),
-							},
-						},
-					},
-				},
-			},
-			want: &v1alpha1.JobConfig{
-				ObjectMeta: objectMetaJobConfig,
-				Spec: v1alpha1.JobConfigSpec{
-					Template: v1alpha1.JobTemplateSpec{
-						Spec: v1alpha1.JobTemplate{
-							TaskTemplate: v1alpha1.TaskTemplate{
-								Pod: &podTemplateSpecBare,
-							},
-							MaxAttempts: pointer.Int64(1),
-							Parallelism: &v1alpha1.ParallelismSpec{
-								WithCount:          pointer.Int64(3),
-								CompletionStrategy: v1alpha1.AllSuccessful,
-							},
 						},
 					},
 				},
@@ -292,7 +247,7 @@ func TestMutator_MutateJobConfig(t *testing.T) {
 			rjc: &v1alpha1.JobConfig{
 				ObjectMeta: objectMetaJobConfig,
 				Spec: v1alpha1.JobConfigSpec{
-					Template: jobConfigJobTemplateSpecBasic,
+					Template: jobTemplateSpecBasic,
 					Option: &v1alpha1.OptionSpec{
 						Options: []v1alpha1.Option{
 							{
@@ -306,7 +261,7 @@ func TestMutator_MutateJobConfig(t *testing.T) {
 			want: &v1alpha1.JobConfig{
 				ObjectMeta: objectMetaJobConfig,
 				Spec: v1alpha1.JobConfigSpec{
-					Template: jobConfigJobTemplateSpecBasic,
+					Template: jobTemplateSpecBasic,
 					Option: &v1alpha1.OptionSpec{
 						Options: []v1alpha1.Option{
 							{