2021-08-18 11:37:46 +08:00
|
|
|
/*
|
|
|
|
Copyright 2021 The KubeVela 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 cli
|
|
|
|
|
|
|
|
import (
|
|
|
|
"context"
|
|
|
|
"fmt"
|
|
|
|
"os"
|
|
|
|
"testing"
|
|
|
|
|
|
|
|
"github.com/stretchr/testify/require"
|
2021-10-19 17:34:30 +08:00
|
|
|
corev1 "k8s.io/api/core/v1"
|
2021-08-18 11:37:46 +08:00
|
|
|
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
|
|
|
"k8s.io/apimachinery/pkg/runtime"
|
|
|
|
"k8s.io/apimachinery/pkg/types"
|
|
|
|
|
2022-09-02 12:55:03 +08:00
|
|
|
workflowv1alpha1 "github.com/kubevela/workflow/api/v1alpha1"
|
|
|
|
wfTypes "github.com/kubevela/workflow/pkg/types"
|
|
|
|
|
2021-08-18 11:37:46 +08:00
|
|
|
"github.com/oam-dev/kubevela/apis/core.oam.dev/common"
|
|
|
|
"github.com/oam-dev/kubevela/apis/core.oam.dev/v1beta1"
|
|
|
|
cmdutil "github.com/oam-dev/kubevela/pkg/utils/util"
|
|
|
|
)
|
|
|
|
|
2021-08-20 20:45:09 +08:00
|
|
|
var workflowSpec = v1beta1.ApplicationSpec{
|
|
|
|
Components: []common.ApplicationComponent{{
|
|
|
|
Name: "test-component",
|
|
|
|
Type: "worker",
|
2021-10-13 16:16:53 +08:00
|
|
|
Properties: &runtime.RawExtension{Raw: []byte(`{"cmd":["sleep","1000"],"image":"busybox"}`)},
|
2021-08-20 20:45:09 +08:00
|
|
|
}},
|
|
|
|
Workflow: &v1beta1.Workflow{
|
2022-09-02 12:55:03 +08:00
|
|
|
Steps: []workflowv1alpha1.WorkflowStep{{
|
|
|
|
WorkflowStepBase: workflowv1alpha1.WorkflowStepBase{
|
|
|
|
Name: "test-wf1",
|
|
|
|
Type: "foowf",
|
|
|
|
Properties: &runtime.RawExtension{Raw: []byte(`{"namespace":"default"}`)},
|
|
|
|
},
|
2021-08-20 20:45:09 +08:00
|
|
|
}},
|
|
|
|
},
|
|
|
|
}
|
|
|
|
|
2021-08-18 11:37:46 +08:00
|
|
|
func TestWorkflowSuspend(t *testing.T) {
|
|
|
|
c := initArgs()
|
|
|
|
ioStream := cmdutil.IOStreams{In: os.Stdin, Out: os.Stdout, ErrOut: os.Stderr}
|
|
|
|
ctx := context.TODO()
|
|
|
|
|
|
|
|
testCases := map[string]struct {
|
|
|
|
app *v1beta1.Application
|
2023-03-01 10:59:31 +08:00
|
|
|
expected *v1beta1.Application
|
|
|
|
step string
|
|
|
|
expectedErr string
|
2021-08-18 11:37:46 +08:00
|
|
|
}{
|
|
|
|
"no app name specified": {
|
2023-03-01 10:59:31 +08:00
|
|
|
expectedErr: "please specify the name of application/workflow",
|
2021-08-18 11:37:46 +08:00
|
|
|
},
|
2021-08-20 20:45:09 +08:00
|
|
|
"workflow not running": {
|
|
|
|
app: &v1beta1.Application{
|
|
|
|
ObjectMeta: metav1.ObjectMeta{
|
|
|
|
Name: "workflow-not-running",
|
|
|
|
Namespace: "default",
|
|
|
|
},
|
|
|
|
Spec: workflowSpec,
|
|
|
|
Status: common.AppStatus{},
|
|
|
|
},
|
2023-03-01 10:59:31 +08:00
|
|
|
expectedErr: "the workflow in application workflow-not-running is not start",
|
2021-08-20 20:45:09 +08:00
|
|
|
},
|
2021-08-18 11:37:46 +08:00
|
|
|
"suspend successfully": {
|
|
|
|
app: &v1beta1.Application{
|
|
|
|
ObjectMeta: metav1.ObjectMeta{
|
|
|
|
Name: "workflow",
|
2021-10-19 17:34:30 +08:00
|
|
|
Namespace: "test",
|
2021-08-18 11:37:46 +08:00
|
|
|
},
|
2021-08-20 20:45:09 +08:00
|
|
|
Spec: workflowSpec,
|
2021-08-18 11:37:46 +08:00
|
|
|
Status: common.AppStatus{
|
|
|
|
Workflow: &common.WorkflowStatus{
|
|
|
|
Suspend: false,
|
|
|
|
},
|
|
|
|
},
|
|
|
|
},
|
2023-03-01 10:59:31 +08:00
|
|
|
expected: &v1beta1.Application{
|
|
|
|
ObjectMeta: metav1.ObjectMeta{
|
|
|
|
Name: "workflow",
|
|
|
|
Namespace: "test",
|
|
|
|
},
|
|
|
|
Spec: workflowSpec,
|
|
|
|
Status: common.AppStatus{
|
|
|
|
Workflow: &common.WorkflowStatus{
|
|
|
|
Suspend: true,
|
|
|
|
},
|
|
|
|
},
|
|
|
|
},
|
|
|
|
},
|
|
|
|
"step not found": {
|
|
|
|
app: &v1beta1.Application{
|
|
|
|
ObjectMeta: metav1.ObjectMeta{
|
|
|
|
Name: "step-not-found",
|
|
|
|
Namespace: "default",
|
|
|
|
},
|
|
|
|
Spec: workflowSpec,
|
|
|
|
Status: common.AppStatus{
|
|
|
|
Workflow: &common.WorkflowStatus{
|
|
|
|
Suspend: false,
|
|
|
|
},
|
|
|
|
},
|
|
|
|
},
|
|
|
|
step: "not-found",
|
|
|
|
expectedErr: "can not find",
|
|
|
|
},
|
|
|
|
"suspend all": {
|
|
|
|
app: &v1beta1.Application{
|
|
|
|
ObjectMeta: metav1.ObjectMeta{
|
|
|
|
Name: "suspend-all",
|
|
|
|
Namespace: "default",
|
|
|
|
},
|
|
|
|
Spec: workflowSpec,
|
|
|
|
Status: common.AppStatus{
|
|
|
|
Workflow: &common.WorkflowStatus{
|
|
|
|
Steps: []workflowv1alpha1.WorkflowStepStatus{
|
|
|
|
{
|
|
|
|
StepStatus: workflowv1alpha1.StepStatus{
|
|
|
|
Name: "step1",
|
|
|
|
Phase: workflowv1alpha1.WorkflowStepPhaseRunning,
|
|
|
|
},
|
|
|
|
SubStepsStatus: []workflowv1alpha1.StepStatus{
|
|
|
|
{
|
|
|
|
Name: "sub1",
|
|
|
|
Phase: workflowv1alpha1.WorkflowStepPhaseRunning,
|
|
|
|
},
|
|
|
|
},
|
|
|
|
},
|
|
|
|
{
|
|
|
|
StepStatus: workflowv1alpha1.StepStatus{
|
|
|
|
Name: "step2",
|
|
|
|
Phase: workflowv1alpha1.WorkflowStepPhaseRunning,
|
|
|
|
},
|
|
|
|
SubStepsStatus: []workflowv1alpha1.StepStatus{
|
|
|
|
{
|
|
|
|
Name: "sub2",
|
|
|
|
Phase: workflowv1alpha1.WorkflowStepPhaseSucceeded,
|
|
|
|
},
|
|
|
|
},
|
|
|
|
},
|
|
|
|
},
|
|
|
|
},
|
|
|
|
},
|
|
|
|
},
|
|
|
|
expected: &v1beta1.Application{
|
|
|
|
Status: common.AppStatus{
|
|
|
|
Workflow: &common.WorkflowStatus{
|
|
|
|
Suspend: true,
|
|
|
|
Steps: []workflowv1alpha1.WorkflowStepStatus{
|
|
|
|
{
|
|
|
|
StepStatus: workflowv1alpha1.StepStatus{
|
|
|
|
Name: "step1",
|
|
|
|
Phase: workflowv1alpha1.WorkflowStepPhaseSuspending,
|
|
|
|
},
|
|
|
|
SubStepsStatus: []workflowv1alpha1.StepStatus{
|
|
|
|
{
|
|
|
|
Name: "sub1",
|
|
|
|
Phase: workflowv1alpha1.WorkflowStepPhaseSuspending,
|
|
|
|
},
|
|
|
|
},
|
|
|
|
},
|
|
|
|
{
|
|
|
|
StepStatus: workflowv1alpha1.StepStatus{
|
|
|
|
Name: "step2",
|
|
|
|
Phase: workflowv1alpha1.WorkflowStepPhaseSuspending,
|
|
|
|
},
|
|
|
|
SubStepsStatus: []workflowv1alpha1.StepStatus{
|
|
|
|
{
|
|
|
|
Name: "sub2",
|
|
|
|
Phase: workflowv1alpha1.WorkflowStepPhaseSucceeded,
|
|
|
|
},
|
|
|
|
},
|
|
|
|
},
|
|
|
|
},
|
|
|
|
},
|
|
|
|
},
|
|
|
|
},
|
|
|
|
},
|
|
|
|
"suspend specific step": {
|
|
|
|
app: &v1beta1.Application{
|
|
|
|
ObjectMeta: metav1.ObjectMeta{
|
|
|
|
Name: "suspend-step",
|
|
|
|
Namespace: "default",
|
|
|
|
},
|
|
|
|
Spec: workflowSpec,
|
|
|
|
Status: common.AppStatus{
|
|
|
|
Workflow: &common.WorkflowStatus{
|
|
|
|
Steps: []workflowv1alpha1.WorkflowStepStatus{
|
|
|
|
{
|
|
|
|
StepStatus: workflowv1alpha1.StepStatus{
|
|
|
|
Name: "step1",
|
|
|
|
Phase: workflowv1alpha1.WorkflowStepPhaseRunning,
|
|
|
|
},
|
|
|
|
SubStepsStatus: []workflowv1alpha1.StepStatus{
|
|
|
|
{
|
|
|
|
Name: "sub1",
|
|
|
|
Phase: workflowv1alpha1.WorkflowStepPhaseRunning,
|
|
|
|
},
|
|
|
|
},
|
|
|
|
},
|
|
|
|
},
|
|
|
|
},
|
|
|
|
},
|
|
|
|
},
|
|
|
|
expected: &v1beta1.Application{
|
|
|
|
Status: common.AppStatus{
|
|
|
|
Workflow: &common.WorkflowStatus{
|
|
|
|
Suspend: true,
|
|
|
|
Steps: []workflowv1alpha1.WorkflowStepStatus{
|
|
|
|
{
|
|
|
|
StepStatus: workflowv1alpha1.StepStatus{
|
|
|
|
Name: "step1",
|
|
|
|
Phase: workflowv1alpha1.WorkflowStepPhaseSuspending,
|
|
|
|
},
|
|
|
|
SubStepsStatus: []workflowv1alpha1.StepStatus{
|
|
|
|
{
|
|
|
|
Name: "sub1",
|
|
|
|
Phase: workflowv1alpha1.WorkflowStepPhaseSuspending,
|
|
|
|
},
|
|
|
|
},
|
|
|
|
},
|
|
|
|
},
|
|
|
|
},
|
|
|
|
},
|
|
|
|
},
|
|
|
|
step: "step1",
|
|
|
|
},
|
|
|
|
"suspend specific sub step": {
|
|
|
|
app: &v1beta1.Application{
|
|
|
|
ObjectMeta: metav1.ObjectMeta{
|
|
|
|
Name: "suspend-sub-step",
|
|
|
|
Namespace: "default",
|
|
|
|
},
|
|
|
|
Spec: workflowSpec,
|
|
|
|
Status: common.AppStatus{
|
|
|
|
Workflow: &common.WorkflowStatus{
|
|
|
|
Steps: []workflowv1alpha1.WorkflowStepStatus{
|
|
|
|
{
|
|
|
|
StepStatus: workflowv1alpha1.StepStatus{
|
|
|
|
Name: "step1",
|
|
|
|
Phase: workflowv1alpha1.WorkflowStepPhaseRunning,
|
|
|
|
},
|
|
|
|
SubStepsStatus: []workflowv1alpha1.StepStatus{
|
|
|
|
{
|
|
|
|
Name: "sub1",
|
|
|
|
Phase: workflowv1alpha1.WorkflowStepPhaseRunning,
|
|
|
|
},
|
|
|
|
},
|
|
|
|
},
|
|
|
|
},
|
|
|
|
},
|
|
|
|
},
|
|
|
|
},
|
|
|
|
expected: &v1beta1.Application{
|
|
|
|
Status: common.AppStatus{
|
|
|
|
Workflow: &common.WorkflowStatus{
|
|
|
|
Suspend: true,
|
|
|
|
Steps: []workflowv1alpha1.WorkflowStepStatus{
|
|
|
|
{
|
|
|
|
StepStatus: workflowv1alpha1.StepStatus{
|
|
|
|
Name: "step1",
|
|
|
|
Phase: workflowv1alpha1.WorkflowStepPhaseRunning,
|
|
|
|
},
|
|
|
|
SubStepsStatus: []workflowv1alpha1.StepStatus{
|
|
|
|
{
|
|
|
|
Name: "sub1",
|
|
|
|
Phase: workflowv1alpha1.WorkflowStepPhaseSuspending,
|
|
|
|
},
|
|
|
|
},
|
|
|
|
},
|
|
|
|
},
|
|
|
|
},
|
|
|
|
},
|
|
|
|
},
|
|
|
|
step: "sub1",
|
2021-08-18 11:37:46 +08:00
|
|
|
},
|
|
|
|
}
|
|
|
|
|
|
|
|
for name, tc := range testCases {
|
|
|
|
t.Run(name, func(t *testing.T) {
|
|
|
|
r := require.New(t)
|
2022-10-26 16:04:34 +08:00
|
|
|
cmd := NewWorkflowSuspendCommand(c, ioStream, &WorkflowArgs{Args: c, Writer: ioStream.Out})
|
2021-08-18 17:04:21 +08:00
|
|
|
initCommand(cmd)
|
2021-12-25 10:36:54 +08:00
|
|
|
// clean up the arguments before start
|
|
|
|
cmd.SetArgs([]string{})
|
2022-01-07 15:49:27 +08:00
|
|
|
client, err := c.GetClient()
|
|
|
|
r.NoError(err)
|
2021-08-18 11:37:46 +08:00
|
|
|
if tc.app != nil {
|
2022-01-07 15:49:27 +08:00
|
|
|
err := client.Create(ctx, tc.app)
|
2021-08-18 11:37:46 +08:00
|
|
|
r.NoError(err)
|
2023-03-01 10:59:31 +08:00
|
|
|
cmdArgs := []string{tc.app.Name}
|
2021-10-19 17:34:30 +08:00
|
|
|
if tc.app.Namespace != corev1.NamespaceDefault {
|
2022-01-07 15:49:27 +08:00
|
|
|
err := client.Create(ctx, &corev1.Namespace{
|
2021-10-19 17:34:30 +08:00
|
|
|
ObjectMeta: metav1.ObjectMeta{
|
|
|
|
Name: tc.app.Namespace,
|
|
|
|
},
|
|
|
|
})
|
|
|
|
r.NoError(err)
|
2023-03-01 10:59:31 +08:00
|
|
|
cmdArgs = append(cmdArgs, "-n", tc.app.Namespace)
|
2021-10-19 17:34:30 +08:00
|
|
|
cmd.SetArgs([]string{tc.app.Name, "-n", tc.app.Namespace})
|
|
|
|
}
|
2023-03-01 10:59:31 +08:00
|
|
|
if tc.step != "" {
|
|
|
|
cmdArgs = append(cmdArgs, "--step", tc.step)
|
|
|
|
}
|
|
|
|
cmd.SetArgs(cmdArgs)
|
2021-08-18 11:37:46 +08:00
|
|
|
}
|
2022-01-07 15:49:27 +08:00
|
|
|
err = cmd.Execute()
|
2023-03-01 10:59:31 +08:00
|
|
|
if tc.expectedErr != "" {
|
|
|
|
r.Contains(err.Error(), tc.expectedErr)
|
2021-08-18 11:37:46 +08:00
|
|
|
return
|
|
|
|
}
|
|
|
|
r.NoError(err)
|
|
|
|
|
|
|
|
wf := &v1beta1.Application{}
|
2022-01-07 15:49:27 +08:00
|
|
|
err = client.Get(ctx, types.NamespacedName{
|
2021-08-18 11:37:46 +08:00
|
|
|
Namespace: tc.app.Namespace,
|
|
|
|
Name: tc.app.Name,
|
|
|
|
}, wf)
|
|
|
|
r.NoError(err)
|
|
|
|
r.Equal(true, wf.Status.Workflow.Suspend)
|
2023-03-01 10:59:31 +08:00
|
|
|
r.Equal(tc.expected.Status, wf.Status)
|
2021-08-18 11:37:46 +08:00
|
|
|
})
|
|
|
|
}
|
|
|
|
}
|
2021-08-18 17:04:21 +08:00
|
|
|
|
|
|
|
func TestWorkflowResume(t *testing.T) {
|
|
|
|
c := initArgs()
|
|
|
|
ioStream := cmdutil.IOStreams{In: os.Stdin, Out: os.Stdout, ErrOut: os.Stderr}
|
|
|
|
ctx := context.TODO()
|
|
|
|
|
|
|
|
testCases := map[string]struct {
|
|
|
|
app *v1beta1.Application
|
|
|
|
expectedErr error
|
|
|
|
}{
|
|
|
|
"no app name specified": {
|
2022-10-26 16:04:34 +08:00
|
|
|
expectedErr: fmt.Errorf("please specify the name of application/workflow"),
|
2021-08-18 17:04:21 +08:00
|
|
|
},
|
|
|
|
"workflow not suspended": {
|
|
|
|
app: &v1beta1.Application{
|
|
|
|
ObjectMeta: metav1.ObjectMeta{
|
|
|
|
Name: "workflow-not-suspended",
|
|
|
|
Namespace: "default",
|
|
|
|
},
|
2021-08-20 20:45:09 +08:00
|
|
|
Spec: workflowSpec,
|
|
|
|
Status: common.AppStatus{
|
|
|
|
Workflow: &common.WorkflowStatus{
|
|
|
|
Suspend: false,
|
2021-08-18 17:04:21 +08:00
|
|
|
},
|
|
|
|
},
|
2021-08-20 20:45:09 +08:00
|
|
|
},
|
|
|
|
},
|
|
|
|
"workflow not running": {
|
|
|
|
app: &v1beta1.Application{
|
|
|
|
ObjectMeta: metav1.ObjectMeta{
|
|
|
|
Name: "workflow-not-running",
|
|
|
|
Namespace: "default",
|
|
|
|
},
|
|
|
|
Spec: workflowSpec,
|
|
|
|
Status: common.AppStatus{},
|
|
|
|
},
|
2022-10-26 16:04:34 +08:00
|
|
|
expectedErr: fmt.Errorf("the workflow in application workflow-not-running is not start"),
|
2021-08-20 20:45:09 +08:00
|
|
|
},
|
|
|
|
"workflow terminated": {
|
|
|
|
app: &v1beta1.Application{
|
|
|
|
ObjectMeta: metav1.ObjectMeta{
|
|
|
|
Name: "workflow-terminated",
|
|
|
|
Namespace: "default",
|
|
|
|
},
|
|
|
|
Spec: workflowSpec,
|
2021-08-18 17:04:21 +08:00
|
|
|
Status: common.AppStatus{
|
|
|
|
Workflow: &common.WorkflowStatus{
|
2021-08-20 20:45:09 +08:00
|
|
|
Terminated: true,
|
2021-08-18 17:04:21 +08:00
|
|
|
},
|
|
|
|
},
|
|
|
|
},
|
2021-08-20 20:45:09 +08:00
|
|
|
expectedErr: fmt.Errorf("can not resume a terminated workflow"),
|
2021-08-18 17:04:21 +08:00
|
|
|
},
|
|
|
|
"resume successfully": {
|
|
|
|
app: &v1beta1.Application{
|
|
|
|
ObjectMeta: metav1.ObjectMeta{
|
|
|
|
Name: "workflow",
|
2021-10-19 17:34:30 +08:00
|
|
|
Namespace: "test",
|
2021-08-18 17:04:21 +08:00
|
|
|
},
|
2021-08-20 20:45:09 +08:00
|
|
|
Spec: workflowSpec,
|
2021-08-18 17:04:21 +08:00
|
|
|
Status: common.AppStatus{
|
|
|
|
Workflow: &common.WorkflowStatus{
|
|
|
|
Suspend: true,
|
2022-09-02 12:55:03 +08:00
|
|
|
Steps: []workflowv1alpha1.WorkflowStepStatus{
|
2022-06-13 14:30:52 +08:00
|
|
|
{
|
2022-09-02 12:55:03 +08:00
|
|
|
StepStatus: workflowv1alpha1.StepStatus{
|
2022-06-13 14:30:52 +08:00
|
|
|
Type: "suspend",
|
|
|
|
Phase: "running",
|
|
|
|
},
|
|
|
|
},
|
|
|
|
{
|
2022-09-02 12:55:03 +08:00
|
|
|
StepStatus: workflowv1alpha1.StepStatus{
|
2022-06-13 14:30:52 +08:00
|
|
|
Type: "step-group",
|
|
|
|
},
|
2022-09-02 12:55:03 +08:00
|
|
|
SubStepsStatus: []workflowv1alpha1.StepStatus{
|
2022-06-13 14:30:52 +08:00
|
|
|
{
|
2022-09-02 12:55:03 +08:00
|
|
|
Type: "suspend",
|
|
|
|
Phase: "running",
|
2022-06-13 14:30:52 +08:00
|
|
|
},
|
|
|
|
},
|
|
|
|
},
|
|
|
|
},
|
2021-08-18 17:04:21 +08:00
|
|
|
},
|
|
|
|
},
|
|
|
|
},
|
|
|
|
},
|
|
|
|
}
|
|
|
|
|
|
|
|
for name, tc := range testCases {
|
|
|
|
t.Run(name, func(t *testing.T) {
|
|
|
|
r := require.New(t)
|
2022-10-26 16:04:34 +08:00
|
|
|
cmd := NewWorkflowResumeCommand(c, ioStream, &WorkflowArgs{Args: c, Writer: ioStream.Out})
|
2021-08-18 17:04:21 +08:00
|
|
|
initCommand(cmd)
|
2022-06-24 18:03:04 +08:00
|
|
|
// clean up the arguments before start
|
|
|
|
cmd.SetArgs([]string{})
|
2022-01-07 15:49:27 +08:00
|
|
|
client, err := c.GetClient()
|
|
|
|
r.NoError(err)
|
2021-08-18 17:04:21 +08:00
|
|
|
if tc.app != nil {
|
2022-01-07 15:49:27 +08:00
|
|
|
err := client.Create(ctx, tc.app)
|
2021-08-18 17:04:21 +08:00
|
|
|
r.NoError(err)
|
|
|
|
|
2021-10-19 17:34:30 +08:00
|
|
|
if tc.app.Namespace != corev1.NamespaceDefault {
|
2022-01-07 15:49:27 +08:00
|
|
|
err := client.Create(ctx, &corev1.Namespace{
|
2021-10-19 17:34:30 +08:00
|
|
|
ObjectMeta: metav1.ObjectMeta{
|
|
|
|
Name: tc.app.Namespace,
|
|
|
|
},
|
|
|
|
})
|
|
|
|
r.NoError(err)
|
|
|
|
cmd.SetArgs([]string{tc.app.Name, "-n", tc.app.Namespace})
|
|
|
|
} else {
|
|
|
|
cmd.SetArgs([]string{tc.app.Name})
|
|
|
|
}
|
2021-08-18 17:04:21 +08:00
|
|
|
}
|
2022-01-07 15:49:27 +08:00
|
|
|
err = cmd.Execute()
|
2021-08-18 17:04:21 +08:00
|
|
|
if tc.expectedErr != nil {
|
|
|
|
r.Equal(tc.expectedErr, err)
|
|
|
|
return
|
|
|
|
}
|
|
|
|
r.NoError(err)
|
|
|
|
|
|
|
|
wf := &v1beta1.Application{}
|
2022-01-07 15:49:27 +08:00
|
|
|
err = client.Get(ctx, types.NamespacedName{
|
2021-08-18 17:04:21 +08:00
|
|
|
Namespace: tc.app.Namespace,
|
|
|
|
Name: tc.app.Name,
|
|
|
|
}, wf)
|
|
|
|
r.NoError(err)
|
|
|
|
r.Equal(false, wf.Status.Workflow.Suspend)
|
2022-06-13 14:30:52 +08:00
|
|
|
for _, step := range wf.Status.Workflow.Steps {
|
|
|
|
if step.Type == "suspend" {
|
2023-03-01 10:59:31 +08:00
|
|
|
r.Equal(step.Phase, workflowv1alpha1.WorkflowStepPhaseRunning)
|
2022-06-13 14:30:52 +08:00
|
|
|
}
|
|
|
|
for _, sub := range step.SubStepsStatus {
|
|
|
|
if sub.Type == "suspend" {
|
2023-03-01 10:59:31 +08:00
|
|
|
r.Equal(sub.Phase, workflowv1alpha1.WorkflowStepPhaseRunning)
|
2022-06-13 14:30:52 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2021-08-18 17:04:21 +08:00
|
|
|
})
|
|
|
|
}
|
|
|
|
}
|
2021-08-20 20:45:09 +08:00
|
|
|
|
|
|
|
func TestWorkflowTerminate(t *testing.T) {
|
|
|
|
c := initArgs()
|
|
|
|
ioStream := cmdutil.IOStreams{In: os.Stdin, Out: os.Stdout, ErrOut: os.Stderr}
|
|
|
|
ctx := context.TODO()
|
|
|
|
|
|
|
|
testCases := map[string]struct {
|
|
|
|
app *v1beta1.Application
|
|
|
|
expectedErr error
|
|
|
|
}{
|
|
|
|
"no app name specified": {
|
2022-10-26 16:04:34 +08:00
|
|
|
expectedErr: fmt.Errorf("please specify the name of application/workflow"),
|
2021-08-20 20:45:09 +08:00
|
|
|
},
|
|
|
|
"workflow not running": {
|
|
|
|
app: &v1beta1.Application{
|
|
|
|
ObjectMeta: metav1.ObjectMeta{
|
|
|
|
Name: "workflow-not-running",
|
|
|
|
Namespace: "default",
|
|
|
|
},
|
|
|
|
Spec: workflowSpec,
|
|
|
|
Status: common.AppStatus{},
|
|
|
|
},
|
2022-10-26 16:04:34 +08:00
|
|
|
expectedErr: fmt.Errorf("the workflow in application workflow-not-running is not start"),
|
2021-08-20 20:45:09 +08:00
|
|
|
},
|
|
|
|
"terminate successfully": {
|
|
|
|
app: &v1beta1.Application{
|
|
|
|
ObjectMeta: metav1.ObjectMeta{
|
|
|
|
Name: "workflow",
|
2021-10-19 17:34:30 +08:00
|
|
|
Namespace: "test",
|
2021-08-20 20:45:09 +08:00
|
|
|
},
|
|
|
|
Spec: workflowSpec,
|
|
|
|
Status: common.AppStatus{
|
|
|
|
Workflow: &common.WorkflowStatus{
|
|
|
|
Terminated: false,
|
2022-09-02 12:55:03 +08:00
|
|
|
Steps: []workflowv1alpha1.WorkflowStepStatus{
|
2022-06-13 14:30:52 +08:00
|
|
|
{
|
2022-09-02 12:55:03 +08:00
|
|
|
StepStatus: workflowv1alpha1.StepStatus{
|
2022-06-13 14:30:52 +08:00
|
|
|
Name: "1",
|
|
|
|
Type: "suspend",
|
|
|
|
Phase: "succeeded",
|
|
|
|
},
|
|
|
|
},
|
|
|
|
{
|
2022-09-02 12:55:03 +08:00
|
|
|
StepStatus: workflowv1alpha1.StepStatus{
|
2022-06-13 14:30:52 +08:00
|
|
|
Name: "2",
|
|
|
|
Type: "suspend",
|
|
|
|
Phase: "running",
|
|
|
|
},
|
|
|
|
},
|
|
|
|
{
|
2022-09-02 12:55:03 +08:00
|
|
|
StepStatus: workflowv1alpha1.StepStatus{
|
2022-06-13 14:30:52 +08:00
|
|
|
Name: "3",
|
|
|
|
Type: "step-group",
|
|
|
|
Phase: "running",
|
|
|
|
},
|
2022-09-02 12:55:03 +08:00
|
|
|
SubStepsStatus: []workflowv1alpha1.StepStatus{
|
2022-06-13 14:30:52 +08:00
|
|
|
{
|
2022-09-02 12:55:03 +08:00
|
|
|
Type: "suspend",
|
|
|
|
Phase: "running",
|
2022-06-13 14:30:52 +08:00
|
|
|
},
|
|
|
|
{
|
2022-09-02 12:55:03 +08:00
|
|
|
Type: "suspend",
|
|
|
|
Phase: "succeeded",
|
2022-06-13 14:30:52 +08:00
|
|
|
},
|
|
|
|
},
|
|
|
|
},
|
|
|
|
},
|
2021-08-20 20:45:09 +08:00
|
|
|
},
|
|
|
|
},
|
|
|
|
},
|
|
|
|
},
|
|
|
|
}
|
|
|
|
|
|
|
|
for name, tc := range testCases {
|
|
|
|
t.Run(name, func(t *testing.T) {
|
|
|
|
r := require.New(t)
|
2022-10-26 16:04:34 +08:00
|
|
|
cmd := NewWorkflowTerminateCommand(c, ioStream, &WorkflowArgs{Args: c, Writer: ioStream.Out})
|
2021-08-20 20:45:09 +08:00
|
|
|
initCommand(cmd)
|
2022-06-24 18:03:04 +08:00
|
|
|
// clean up the arguments before start
|
|
|
|
cmd.SetArgs([]string{})
|
2022-01-07 15:49:27 +08:00
|
|
|
client, err := c.GetClient()
|
|
|
|
r.NoError(err)
|
2021-08-20 20:45:09 +08:00
|
|
|
if tc.app != nil {
|
2022-01-07 15:49:27 +08:00
|
|
|
err := client.Create(ctx, tc.app)
|
2021-08-20 20:45:09 +08:00
|
|
|
r.NoError(err)
|
|
|
|
|
2021-10-19 17:34:30 +08:00
|
|
|
if tc.app.Namespace != corev1.NamespaceDefault {
|
2022-01-07 15:49:27 +08:00
|
|
|
err := client.Create(ctx, &corev1.Namespace{
|
2021-10-19 17:34:30 +08:00
|
|
|
ObjectMeta: metav1.ObjectMeta{
|
|
|
|
Name: tc.app.Namespace,
|
|
|
|
},
|
|
|
|
})
|
|
|
|
r.NoError(err)
|
|
|
|
cmd.SetArgs([]string{tc.app.Name, "-n", tc.app.Namespace})
|
|
|
|
} else {
|
|
|
|
cmd.SetArgs([]string{tc.app.Name})
|
|
|
|
}
|
2021-08-20 20:45:09 +08:00
|
|
|
}
|
2022-01-07 15:49:27 +08:00
|
|
|
err = cmd.Execute()
|
2021-08-20 20:45:09 +08:00
|
|
|
if tc.expectedErr != nil {
|
|
|
|
r.Equal(tc.expectedErr, err)
|
|
|
|
return
|
|
|
|
}
|
|
|
|
r.NoError(err)
|
|
|
|
|
|
|
|
wf := &v1beta1.Application{}
|
2022-01-07 15:49:27 +08:00
|
|
|
err = client.Get(ctx, types.NamespacedName{
|
2021-08-20 20:45:09 +08:00
|
|
|
Namespace: tc.app.Namespace,
|
|
|
|
Name: tc.app.Name,
|
|
|
|
}, wf)
|
|
|
|
r.NoError(err)
|
|
|
|
r.Equal(true, wf.Status.Workflow.Terminated)
|
2022-06-13 14:30:52 +08:00
|
|
|
for _, step := range wf.Status.Workflow.Steps {
|
2022-09-02 12:55:03 +08:00
|
|
|
if step.Phase != workflowv1alpha1.WorkflowStepPhaseSucceeded {
|
|
|
|
r.Equal(step.Phase, workflowv1alpha1.WorkflowStepPhaseFailed)
|
2022-06-22 14:51:23 +08:00
|
|
|
r.Equal(step.Reason, wfTypes.StatusReasonTerminate)
|
2022-06-13 14:30:52 +08:00
|
|
|
}
|
|
|
|
for _, sub := range step.SubStepsStatus {
|
2022-09-02 12:55:03 +08:00
|
|
|
if sub.Phase != workflowv1alpha1.WorkflowStepPhaseSucceeded {
|
|
|
|
r.Equal(sub.Phase, workflowv1alpha1.WorkflowStepPhaseFailed)
|
2022-06-22 14:51:23 +08:00
|
|
|
r.Equal(sub.Reason, wfTypes.StatusReasonTerminate)
|
2022-06-13 14:30:52 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2021-08-20 20:45:09 +08:00
|
|
|
})
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
func TestWorkflowRestart(t *testing.T) {
|
|
|
|
c := initArgs()
|
|
|
|
ioStream := cmdutil.IOStreams{In: os.Stdin, Out: os.Stdout, ErrOut: os.Stderr}
|
|
|
|
ctx := context.TODO()
|
|
|
|
|
|
|
|
testCases := map[string]struct {
|
|
|
|
app *v1beta1.Application
|
|
|
|
expectedErr error
|
|
|
|
}{
|
|
|
|
"no app name specified": {
|
2022-10-26 16:04:34 +08:00
|
|
|
expectedErr: fmt.Errorf("please specify the name of application/workflow"),
|
2021-08-20 20:45:09 +08:00
|
|
|
},
|
|
|
|
"workflow not running": {
|
|
|
|
app: &v1beta1.Application{
|
|
|
|
ObjectMeta: metav1.ObjectMeta{
|
|
|
|
Name: "workflow-not-running",
|
|
|
|
Namespace: "default",
|
|
|
|
},
|
|
|
|
Spec: workflowSpec,
|
|
|
|
Status: common.AppStatus{},
|
|
|
|
},
|
2022-10-26 16:04:34 +08:00
|
|
|
expectedErr: fmt.Errorf("the workflow in application workflow-not-running is not start"),
|
2021-08-20 20:45:09 +08:00
|
|
|
},
|
|
|
|
"restart successfully": {
|
|
|
|
app: &v1beta1.Application{
|
|
|
|
ObjectMeta: metav1.ObjectMeta{
|
|
|
|
Name: "workflow",
|
2021-10-19 17:34:30 +08:00
|
|
|
Namespace: "test",
|
2021-08-20 20:45:09 +08:00
|
|
|
},
|
|
|
|
Spec: workflowSpec,
|
|
|
|
Status: common.AppStatus{
|
|
|
|
Workflow: &common.WorkflowStatus{
|
|
|
|
Terminated: true,
|
|
|
|
},
|
|
|
|
},
|
|
|
|
},
|
|
|
|
},
|
|
|
|
}
|
|
|
|
|
|
|
|
for name, tc := range testCases {
|
|
|
|
t.Run(name, func(t *testing.T) {
|
|
|
|
r := require.New(t)
|
2022-10-26 16:04:34 +08:00
|
|
|
cmd := NewWorkflowRestartCommand(c, ioStream, &WorkflowArgs{Args: c, Writer: ioStream.Out})
|
2021-08-20 20:45:09 +08:00
|
|
|
initCommand(cmd)
|
2022-06-24 18:03:04 +08:00
|
|
|
// clean up the arguments before start
|
|
|
|
cmd.SetArgs([]string{})
|
2022-01-07 15:49:27 +08:00
|
|
|
client, err := c.GetClient()
|
|
|
|
r.NoError(err)
|
2021-08-20 20:45:09 +08:00
|
|
|
if tc.app != nil {
|
2022-01-07 15:49:27 +08:00
|
|
|
err := client.Create(ctx, tc.app)
|
2021-08-20 20:45:09 +08:00
|
|
|
r.NoError(err)
|
|
|
|
|
2021-10-19 17:34:30 +08:00
|
|
|
if tc.app.Namespace != corev1.NamespaceDefault {
|
2022-01-07 15:49:27 +08:00
|
|
|
err := client.Create(ctx, &corev1.Namespace{
|
2021-10-19 17:34:30 +08:00
|
|
|
ObjectMeta: metav1.ObjectMeta{
|
|
|
|
Name: tc.app.Namespace,
|
|
|
|
},
|
|
|
|
})
|
|
|
|
r.NoError(err)
|
|
|
|
cmd.SetArgs([]string{tc.app.Name, "-n", tc.app.Namespace})
|
|
|
|
} else {
|
|
|
|
cmd.SetArgs([]string{tc.app.Name})
|
|
|
|
}
|
2021-08-20 20:45:09 +08:00
|
|
|
}
|
2022-01-07 15:49:27 +08:00
|
|
|
err = cmd.Execute()
|
2021-08-20 20:45:09 +08:00
|
|
|
if tc.expectedErr != nil {
|
|
|
|
r.Equal(tc.expectedErr, err)
|
|
|
|
return
|
|
|
|
}
|
|
|
|
r.NoError(err)
|
|
|
|
|
|
|
|
wf := &v1beta1.Application{}
|
2022-01-07 15:49:27 +08:00
|
|
|
err = client.Get(ctx, types.NamespacedName{
|
2021-08-20 20:45:09 +08:00
|
|
|
Namespace: tc.app.Namespace,
|
|
|
|
Name: tc.app.Name,
|
|
|
|
}, wf)
|
|
|
|
r.NoError(err)
|
|
|
|
var nilStatus *common.WorkflowStatus = nil
|
|
|
|
r.Equal(nilStatus, wf.Status.Workflow)
|
|
|
|
})
|
|
|
|
}
|
|
|
|
}
|
2021-11-24 21:34:44 +08:00
|
|
|
|
|
|
|
func TestWorkflowRollback(t *testing.T) {
|
|
|
|
c := initArgs()
|
|
|
|
ioStream := cmdutil.IOStreams{In: os.Stdin, Out: os.Stdout, ErrOut: os.Stderr}
|
|
|
|
ctx := context.TODO()
|
|
|
|
|
|
|
|
testCases := map[string]struct {
|
|
|
|
app *v1beta1.Application
|
|
|
|
revision *v1beta1.ApplicationRevision
|
|
|
|
expectedErr error
|
|
|
|
}{
|
|
|
|
"no app name specified": {
|
2022-10-26 16:04:34 +08:00
|
|
|
expectedErr: fmt.Errorf("please specify the name of application/workflow"),
|
2021-11-24 21:34:44 +08:00
|
|
|
},
|
|
|
|
"workflow running": {
|
|
|
|
app: &v1beta1.Application{
|
|
|
|
ObjectMeta: metav1.ObjectMeta{
|
2022-10-26 16:04:34 +08:00
|
|
|
Name: "workflow-running",
|
2021-11-24 21:34:44 +08:00
|
|
|
Namespace: "default",
|
|
|
|
},
|
|
|
|
Spec: workflowSpec,
|
|
|
|
Status: common.AppStatus{
|
|
|
|
Workflow: &common.WorkflowStatus{
|
|
|
|
Suspend: false,
|
|
|
|
Terminated: false,
|
|
|
|
Finished: false,
|
|
|
|
},
|
|
|
|
},
|
|
|
|
},
|
|
|
|
expectedErr: fmt.Errorf("can not rollback a running workflow"),
|
|
|
|
},
|
|
|
|
"invalid revision": {
|
|
|
|
app: &v1beta1.Application{
|
|
|
|
ObjectMeta: metav1.ObjectMeta{
|
|
|
|
Name: "invalid-revision",
|
|
|
|
Namespace: "default",
|
|
|
|
},
|
|
|
|
Spec: workflowSpec,
|
|
|
|
Status: common.AppStatus{
|
|
|
|
Workflow: &common.WorkflowStatus{
|
|
|
|
Suspend: true,
|
|
|
|
},
|
|
|
|
},
|
|
|
|
},
|
|
|
|
expectedErr: fmt.Errorf("the latest revision is not set: invalid-revision"),
|
|
|
|
},
|
|
|
|
"rollback successfully": {
|
|
|
|
app: &v1beta1.Application{
|
|
|
|
ObjectMeta: metav1.ObjectMeta{
|
|
|
|
Name: "workflow",
|
|
|
|
Namespace: "test",
|
|
|
|
},
|
|
|
|
Spec: workflowSpec,
|
|
|
|
Status: common.AppStatus{
|
|
|
|
LatestRevision: &common.Revision{
|
|
|
|
Name: "revision-v1",
|
|
|
|
},
|
|
|
|
Workflow: &common.WorkflowStatus{
|
|
|
|
Terminated: true,
|
|
|
|
},
|
|
|
|
},
|
|
|
|
},
|
|
|
|
revision: &v1beta1.ApplicationRevision{
|
|
|
|
ObjectMeta: metav1.ObjectMeta{
|
|
|
|
Name: "revision-v1",
|
|
|
|
Namespace: "test",
|
|
|
|
},
|
|
|
|
Spec: v1beta1.ApplicationRevisionSpec{
|
2022-11-24 10:27:13 +08:00
|
|
|
ApplicationRevisionCompressibleFields: v1beta1.ApplicationRevisionCompressibleFields{
|
|
|
|
Application: v1beta1.Application{
|
|
|
|
Spec: v1beta1.ApplicationSpec{
|
|
|
|
Components: []common.ApplicationComponent{{
|
|
|
|
Name: "revision-component",
|
|
|
|
Type: "worker",
|
|
|
|
Properties: &runtime.RawExtension{Raw: []byte(`{"cmd":["sleep","1000"],"image":"busybox"}`)},
|
|
|
|
}},
|
|
|
|
},
|
2021-11-24 21:34:44 +08:00
|
|
|
},
|
|
|
|
},
|
|
|
|
},
|
|
|
|
},
|
|
|
|
},
|
|
|
|
}
|
|
|
|
|
|
|
|
for name, tc := range testCases {
|
|
|
|
t.Run(name, func(t *testing.T) {
|
|
|
|
r := require.New(t)
|
2022-10-26 16:04:34 +08:00
|
|
|
cmd := NewWorkflowRollbackCommand(c, ioStream, &WorkflowArgs{Args: c, Writer: ioStream.Out})
|
2021-11-24 21:34:44 +08:00
|
|
|
initCommand(cmd)
|
2022-06-24 18:03:04 +08:00
|
|
|
// clean up the arguments before start
|
|
|
|
cmd.SetArgs([]string{})
|
2022-01-07 15:49:27 +08:00
|
|
|
client, err := c.GetClient()
|
|
|
|
r.NoError(err)
|
2021-11-24 21:34:44 +08:00
|
|
|
if tc.app != nil {
|
2022-01-07 15:49:27 +08:00
|
|
|
err := client.Create(ctx, tc.app)
|
2021-11-24 21:34:44 +08:00
|
|
|
r.NoError(err)
|
|
|
|
|
|
|
|
if tc.app.Namespace != corev1.NamespaceDefault {
|
2022-01-07 15:49:27 +08:00
|
|
|
err := client.Create(ctx, &corev1.Namespace{
|
2021-11-24 21:34:44 +08:00
|
|
|
ObjectMeta: metav1.ObjectMeta{
|
|
|
|
Name: tc.app.Namespace,
|
|
|
|
},
|
|
|
|
})
|
|
|
|
r.NoError(err)
|
|
|
|
cmd.SetArgs([]string{tc.app.Name, "-n", tc.app.Namespace})
|
|
|
|
} else {
|
|
|
|
cmd.SetArgs([]string{tc.app.Name})
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if tc.revision != nil {
|
2022-01-07 15:49:27 +08:00
|
|
|
err := client.Create(ctx, tc.revision)
|
2021-11-24 21:34:44 +08:00
|
|
|
r.NoError(err)
|
|
|
|
}
|
2022-01-07 15:49:27 +08:00
|
|
|
err = cmd.Execute()
|
2021-11-24 21:34:44 +08:00
|
|
|
if tc.expectedErr != nil {
|
|
|
|
r.Equal(tc.expectedErr, err)
|
|
|
|
return
|
|
|
|
}
|
|
|
|
r.NoError(err)
|
|
|
|
|
|
|
|
wf := &v1beta1.Application{}
|
2022-01-07 15:49:27 +08:00
|
|
|
err = client.Get(ctx, types.NamespacedName{
|
2021-11-24 21:34:44 +08:00
|
|
|
Namespace: tc.app.Namespace,
|
|
|
|
Name: tc.app.Name,
|
|
|
|
}, wf)
|
|
|
|
r.NoError(err)
|
|
|
|
r.Equal(wf.Spec.Components[0].Name, "revision-component")
|
|
|
|
})
|
|
|
|
}
|
|
|
|
}
|