...

Source file src/github.com/chaos-mesh/chaos-mesh/pkg/dashboard/core/workflow_test.go

Documentation: github.com/chaos-mesh/chaos-mesh/pkg/dashboard/core

     1  // Copyright 2021 Chaos Mesh Authors.
     2  //
     3  // Licensed under the Apache License, Version 2.0 (the "License");
     4  // you may not use this file except in compliance with the License.
     5  // You may obtain a copy of the License at
     6  //
     7  // http://www.apache.org/licenses/LICENSE-2.0
     8  //
     9  // Unless required by applicable law or agreed to in writing, software
    10  // distributed under the License is distributed on an "AS IS" BASIS,
    11  // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    12  // See the License for the specific language governing permissions and
    13  // limitations under the License.
    14  //
    15  
    16  package core
    17  
    18  import (
    19  	"reflect"
    20  	"testing"
    21  
    22  	corev1 "k8s.io/api/core/v1"
    23  	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
    24  
    25  	"github.com/chaos-mesh/chaos-mesh/api/v1alpha1"
    26  )
    27  
    28  func Test_convertWorkflow(t *testing.T) {
    29  	type args struct {
    30  		kubeWorkflow v1alpha1.Workflow
    31  	}
    32  	tests := []struct {
    33  		name string
    34  		args args
    35  		want WorkflowMeta
    36  	}{
    37  		{
    38  			name: "simple workflow",
    39  			args: args{
    40  				v1alpha1.Workflow{
    41  					TypeMeta: metav1.TypeMeta{},
    42  					ObjectMeta: metav1.ObjectMeta{
    43  						Namespace: "fake-namespace",
    44  						Name:      "fake-workflow-0",
    45  					},
    46  					Spec: v1alpha1.WorkflowSpec{
    47  						Entry: "an-entry",
    48  					},
    49  					Status: v1alpha1.WorkflowStatus{},
    50  				},
    51  			},
    52  			want: WorkflowMeta{
    53  				Namespace: "fake-namespace",
    54  				Name:      "fake-workflow-0",
    55  				Entry:     "an-entry",
    56  				Status:    WorkflowUnknown,
    57  			},
    58  		}, {
    59  			name: "running workflow",
    60  			args: args{
    61  				v1alpha1.Workflow{
    62  					TypeMeta: metav1.TypeMeta{},
    63  					ObjectMeta: metav1.ObjectMeta{
    64  						Namespace: "fake-namespace",
    65  						Name:      "fake-workflow-0",
    66  					},
    67  					Spec: v1alpha1.WorkflowSpec{
    68  						Entry: "an-entry",
    69  					},
    70  					Status: v1alpha1.WorkflowStatus{
    71  						Conditions: []v1alpha1.WorkflowCondition{
    72  							{
    73  								Type:   v1alpha1.WorkflowConditionScheduled,
    74  								Status: corev1.ConditionTrue,
    75  								Reason: "",
    76  							},
    77  						},
    78  					},
    79  				},
    80  			},
    81  			want: WorkflowMeta{
    82  				Namespace: "fake-namespace",
    83  				Name:      "fake-workflow-0",
    84  				Entry:     "an-entry",
    85  				Status:    WorkflowRunning,
    86  			},
    87  		}, {
    88  			name: "running workflow",
    89  			args: args{
    90  				v1alpha1.Workflow{
    91  					TypeMeta: metav1.TypeMeta{},
    92  					ObjectMeta: metav1.ObjectMeta{
    93  						Namespace: "fake-namespace",
    94  						Name:      "fake-workflow-0",
    95  					},
    96  					Spec: v1alpha1.WorkflowSpec{
    97  						Entry: "an-entry",
    98  					},
    99  					Status: v1alpha1.WorkflowStatus{
   100  						Conditions: []v1alpha1.WorkflowCondition{
   101  							{
   102  								Type:   v1alpha1.WorkflowConditionAccomplished,
   103  								Status: corev1.ConditionUnknown,
   104  								Reason: "",
   105  							},
   106  							{
   107  								Type:   v1alpha1.WorkflowConditionScheduled,
   108  								Status: corev1.ConditionTrue,
   109  								Reason: "",
   110  							},
   111  						},
   112  					},
   113  				},
   114  			},
   115  			want: WorkflowMeta{
   116  				Namespace: "fake-namespace",
   117  				Name:      "fake-workflow-0",
   118  				Entry:     "an-entry",
   119  				Status:    WorkflowRunning,
   120  			},
   121  		}, {
   122  			name: "running workflow",
   123  			args: args{
   124  				v1alpha1.Workflow{
   125  					TypeMeta: metav1.TypeMeta{},
   126  					ObjectMeta: metav1.ObjectMeta{
   127  						Namespace: "fake-namespace",
   128  						Name:      "fake-workflow-0",
   129  					},
   130  					Spec: v1alpha1.WorkflowSpec{
   131  						Entry: "an-entry",
   132  					},
   133  					Status: v1alpha1.WorkflowStatus{
   134  						Conditions: []v1alpha1.WorkflowCondition{
   135  							{
   136  								Type:   v1alpha1.WorkflowConditionAccomplished,
   137  								Status: corev1.ConditionFalse,
   138  								Reason: "",
   139  							},
   140  							{
   141  								Type:   v1alpha1.WorkflowConditionScheduled,
   142  								Status: corev1.ConditionTrue,
   143  								Reason: "",
   144  							},
   145  						},
   146  					},
   147  				},
   148  			},
   149  			want: WorkflowMeta{
   150  				Namespace: "fake-namespace",
   151  				Name:      "fake-workflow-0",
   152  				Entry:     "an-entry",
   153  				Status:    WorkflowRunning,
   154  			},
   155  		}, {
   156  			name: "succeed workflow",
   157  			args: args{
   158  				v1alpha1.Workflow{
   159  					TypeMeta: metav1.TypeMeta{},
   160  					ObjectMeta: metav1.ObjectMeta{
   161  						Namespace: "fake-namespace",
   162  						Name:      "fake-workflow-0",
   163  					},
   164  					Spec: v1alpha1.WorkflowSpec{
   165  						Entry: "an-entry",
   166  					},
   167  					Status: v1alpha1.WorkflowStatus{
   168  						Conditions: []v1alpha1.WorkflowCondition{
   169  							{
   170  								Type:   v1alpha1.WorkflowConditionAccomplished,
   171  								Status: corev1.ConditionTrue,
   172  								Reason: "",
   173  							},
   174  							{
   175  								Type:   v1alpha1.WorkflowConditionScheduled,
   176  								Status: corev1.ConditionTrue,
   177  								Reason: "",
   178  							},
   179  						},
   180  					},
   181  				},
   182  			},
   183  			want: WorkflowMeta{
   184  				Namespace: "fake-namespace",
   185  				Name:      "fake-workflow-0",
   186  				Entry:     "an-entry",
   187  				Status:    WorkflowSucceed,
   188  			},
   189  		}, {
   190  			name: "converting UID",
   191  			args: args{
   192  				v1alpha1.Workflow{
   193  					TypeMeta: metav1.TypeMeta{},
   194  					ObjectMeta: metav1.ObjectMeta{
   195  						Namespace: "fake-namespace",
   196  						Name:      "fake-workflow-0",
   197  						UID:       "uid-of-workflow",
   198  					},
   199  					Spec: v1alpha1.WorkflowSpec{
   200  						Entry: "an-entry",
   201  					},
   202  					Status: v1alpha1.WorkflowStatus{
   203  						Conditions: []v1alpha1.WorkflowCondition{
   204  							{
   205  								Type:   v1alpha1.WorkflowConditionAccomplished,
   206  								Status: corev1.ConditionTrue,
   207  								Reason: "",
   208  							},
   209  							{
   210  								Type:   v1alpha1.WorkflowConditionScheduled,
   211  								Status: corev1.ConditionTrue,
   212  								Reason: "",
   213  							},
   214  						},
   215  					},
   216  				},
   217  			},
   218  			want: WorkflowMeta{
   219  				Namespace: "fake-namespace",
   220  				Name:      "fake-workflow-0",
   221  				Entry:     "an-entry",
   222  				Status:    WorkflowSucceed,
   223  				UID:       "uid-of-workflow",
   224  			},
   225  		},
   226  	}
   227  	for _, tt := range tests {
   228  		t.Run(tt.name, func(t *testing.T) {
   229  			if got := convertWorkflow(tt.args.kubeWorkflow); !reflect.DeepEqual(got, tt.want) {
   230  				t.Errorf("convertWorkflow() = %v, want %v", got, tt.want)
   231  			}
   232  		})
   233  	}
   234  }
   235  
   236  func Test_convertWorkflowDetail(t *testing.T) {
   237  	type args struct {
   238  		kubeWorkflow v1alpha1.Workflow
   239  		kubeNodes    []v1alpha1.WorkflowNode
   240  	}
   241  	tests := []struct {
   242  		name    string
   243  		args    args
   244  		want    WorkflowDetail
   245  		wantErr bool
   246  	}{
   247  		{
   248  			name: "simple workflow detail with no nodes",
   249  			args: args{
   250  				kubeWorkflow: v1alpha1.Workflow{
   251  					TypeMeta: metav1.TypeMeta{},
   252  					ObjectMeta: metav1.ObjectMeta{
   253  						Namespace: "another-namespace",
   254  						Name:      "another-fake-workflow",
   255  					},
   256  					Spec: v1alpha1.WorkflowSpec{
   257  						Entry:     "another-entry",
   258  						Templates: nil,
   259  					},
   260  					Status: v1alpha1.WorkflowStatus{},
   261  				},
   262  				kubeNodes: nil,
   263  			},
   264  			want: WorkflowDetail{
   265  				WorkflowMeta: WorkflowMeta{
   266  					Namespace: "another-namespace",
   267  					Name:      "another-fake-workflow",
   268  					Entry:     "another-entry",
   269  					Status:    WorkflowUnknown,
   270  				},
   271  				Topology: Topology{
   272  					Nodes: []Node{},
   273  				},
   274  				KubeObject: KubeObjectDesc{
   275  					Meta: KubeObjectMeta{
   276  						Name:      "another-fake-workflow",
   277  						Namespace: "another-namespace",
   278  					},
   279  					Spec: v1alpha1.WorkflowSpec{
   280  						Entry: "another-entry",
   281  					},
   282  				},
   283  			},
   284  		},
   285  		// TODO: Add test cases.
   286  	}
   287  	for _, tt := range tests {
   288  		t.Run(tt.name, func(t *testing.T) {
   289  			got, err := convertWorkflowDetail(tt.args.kubeWorkflow, tt.args.kubeNodes)
   290  			if (err != nil) != tt.wantErr {
   291  				t.Errorf("convertWorkflowDetail() error = %v, wantErr %v", err, tt.wantErr)
   292  				return
   293  			}
   294  			if !reflect.DeepEqual(got, tt.want) {
   295  				t.Errorf("convertWorkflowDetail() got = %v, want %v", got, tt.want)
   296  			}
   297  		})
   298  	}
   299  }
   300  
   301  func Test_convertWorkflowNode(t *testing.T) {
   302  	type args struct {
   303  		kubeWorkflowNode v1alpha1.WorkflowNode
   304  	}
   305  	tests := []struct {
   306  		name    string
   307  		args    args
   308  		want    Node
   309  		wantErr bool
   310  	}{
   311  		{
   312  			name: "simple node",
   313  			args: args{kubeWorkflowNode: v1alpha1.WorkflowNode{
   314  				TypeMeta: metav1.TypeMeta{},
   315  				ObjectMeta: metav1.ObjectMeta{
   316  					Namespace: "fake-namespace",
   317  					Name:      "fake-node-0",
   318  				},
   319  				Spec: v1alpha1.WorkflowNodeSpec{
   320  					WorkflowName: "fake-workflow-0",
   321  					TemplateName: "fake-template-0",
   322  					Type:         v1alpha1.TypeJVMChaos,
   323  				},
   324  				Status: v1alpha1.WorkflowNodeStatus{},
   325  			}},
   326  			want: Node{
   327  				Name:     "fake-node-0",
   328  				Type:     ChaosNode,
   329  				Serial:   nil,
   330  				Parallel: nil,
   331  				Template: "fake-template-0",
   332  				State:    NodeRunning,
   333  			},
   334  		}, {
   335  			name: "serial node",
   336  			args: args{
   337  				kubeWorkflowNode: v1alpha1.WorkflowNode{
   338  					TypeMeta: metav1.TypeMeta{},
   339  					ObjectMeta: metav1.ObjectMeta{
   340  						Namespace: "fake-namespace",
   341  						Name:      "fake-serial-node-0",
   342  					},
   343  					Spec: v1alpha1.WorkflowNodeSpec{
   344  						TemplateName: "fake-serial-node",
   345  						WorkflowName: "fake-workflow-0",
   346  						Type:         v1alpha1.TypeSerial,
   347  						Children:     []string{"child-0", "child-1"},
   348  					},
   349  					Status: v1alpha1.WorkflowNodeStatus{},
   350  				},
   351  			},
   352  			want: Node{
   353  				Name: "fake-serial-node-0",
   354  				Type: SerialNode,
   355  				Serial: []NodeNameWithTemplate{
   356  					{Name: "", Template: "child-0"},
   357  					{Name: "", Template: "child-1"},
   358  				},
   359  				Parallel: nil,
   360  				Template: "fake-serial-node",
   361  				State:    NodeRunning,
   362  			},
   363  		},
   364  		{
   365  			name: "parallel node",
   366  			args: args{
   367  				kubeWorkflowNode: v1alpha1.WorkflowNode{
   368  					TypeMeta: metav1.TypeMeta{},
   369  					ObjectMeta: metav1.ObjectMeta{
   370  						Namespace: "fake-namespace",
   371  						Name:      "parallel-node-0",
   372  					},
   373  					Spec: v1alpha1.WorkflowNodeSpec{
   374  						TemplateName: "parallel-node",
   375  						WorkflowName: "another-fake-workflow",
   376  						Type:         v1alpha1.TypeParallel,
   377  						Children:     []string{"child-1", "child-0"},
   378  					},
   379  					Status: v1alpha1.WorkflowNodeStatus{},
   380  				},
   381  			},
   382  			want: Node{
   383  				Name:   "parallel-node-0",
   384  				Type:   ParallelNode,
   385  				Serial: nil,
   386  				Parallel: []NodeNameWithTemplate{
   387  					{Name: "", Template: "child-1"},
   388  					{Name: "", Template: "child-0"},
   389  				},
   390  				Template: "parallel-node",
   391  				State:    NodeRunning,
   392  			},
   393  		},
   394  		{
   395  			name: "some chaos",
   396  			args: args{
   397  				kubeWorkflowNode: v1alpha1.WorkflowNode{
   398  					TypeMeta: metav1.TypeMeta{},
   399  					ObjectMeta: metav1.ObjectMeta{
   400  						Namespace: "fake-namespace",
   401  						Name:      "io-chaos-0",
   402  					},
   403  					Spec: v1alpha1.WorkflowNodeSpec{
   404  						TemplateName: "io-chaos",
   405  						WorkflowName: "another-workflow-0",
   406  						Type:         v1alpha1.TypeIOChaos,
   407  						EmbedChaos: &v1alpha1.EmbedChaos{
   408  							IOChaos: &v1alpha1.IOChaosSpec{
   409  								ContainerSelector: v1alpha1.ContainerSelector{
   410  									PodSelector: v1alpha1.PodSelector{
   411  										Mode: v1alpha1.OneMode,
   412  									},
   413  								},
   414  								Action:     "delay",
   415  								Delay:      "100ms",
   416  								Path:       "/fake/path",
   417  								Percent:    100,
   418  								VolumePath: "/fake/path",
   419  							},
   420  						},
   421  					},
   422  					Status: v1alpha1.WorkflowNodeStatus{},
   423  				},
   424  			},
   425  			want: Node{
   426  				Name:     "io-chaos-0",
   427  				Type:     ChaosNode,
   428  				Serial:   nil,
   429  				Parallel: nil,
   430  				Template: "io-chaos",
   431  				State:    NodeRunning,
   432  			},
   433  		},
   434  		{
   435  			name: "accomplished node",
   436  			args: args{
   437  				kubeWorkflowNode: v1alpha1.WorkflowNode{
   438  					TypeMeta: metav1.TypeMeta{},
   439  					ObjectMeta: metav1.ObjectMeta{
   440  						Namespace: "fake-namespace",
   441  						Name:      "the-entry-0",
   442  					},
   443  					Spec: v1alpha1.WorkflowNodeSpec{
   444  						TemplateName: "the-entry",
   445  						WorkflowName: "fake-workflow-0",
   446  						Type:         v1alpha1.TypeSerial,
   447  						Children:     []string{"unimportant-task-0"},
   448  					},
   449  					Status: v1alpha1.WorkflowNodeStatus{
   450  						Conditions: []v1alpha1.WorkflowNodeCondition{
   451  							{
   452  								Type:   v1alpha1.ConditionAccomplished,
   453  								Status: corev1.ConditionTrue,
   454  								Reason: "unit test mocked true",
   455  							},
   456  						},
   457  					},
   458  				},
   459  			},
   460  			want: Node{
   461  				Name:  "the-entry-0",
   462  				Type:  SerialNode,
   463  				State: NodeSucceed,
   464  				Serial: []NodeNameWithTemplate{
   465  					{Name: "", Template: "unimportant-task-0"},
   466  				},
   467  				Parallel: nil,
   468  				Template: "the-entry",
   469  			},
   470  		},
   471  		{
   472  			name: "deadline exceed node",
   473  			args: args{kubeWorkflowNode: v1alpha1.WorkflowNode{
   474  				TypeMeta: metav1.TypeMeta{},
   475  				ObjectMeta: metav1.ObjectMeta{
   476  					Namespace: "fake-namespace",
   477  					Name:      "deadline-exceed-node-0",
   478  				},
   479  				Spec: v1alpha1.WorkflowNodeSpec{
   480  					TemplateName: "deadline-exceed-node",
   481  					WorkflowName: "some-workflow",
   482  					Type:         v1alpha1.TypePodChaos,
   483  				},
   484  				Status: v1alpha1.WorkflowNodeStatus{
   485  					Conditions: []v1alpha1.WorkflowNodeCondition{
   486  						{
   487  							Type:   v1alpha1.ConditionDeadlineExceed,
   488  							Status: corev1.ConditionTrue,
   489  							Reason: "unit test mocked true",
   490  						},
   491  					},
   492  				},
   493  			}},
   494  			want: Node{
   495  				Name:     "deadline-exceed-node-0",
   496  				Type:     ChaosNode,
   497  				State:    NodeSucceed,
   498  				Serial:   nil,
   499  				Parallel: nil,
   500  				Template: "deadline-exceed-node",
   501  			},
   502  		},
   503  		{
   504  			name: "appending uid",
   505  			args: args{
   506  				kubeWorkflowNode: v1alpha1.WorkflowNode{
   507  					TypeMeta: metav1.TypeMeta{},
   508  					ObjectMeta: metav1.ObjectMeta{
   509  						Namespace: "fake-namespace",
   510  						Name:      "the-entry-0",
   511  						UID:       "uid-of-workflow-node",
   512  					},
   513  					Spec: v1alpha1.WorkflowNodeSpec{
   514  						TemplateName: "the-entry",
   515  						WorkflowName: "fake-workflow-0",
   516  						Type:         v1alpha1.TypeSerial,
   517  						Children:     []string{"unimportant-task-0"},
   518  					},
   519  					Status: v1alpha1.WorkflowNodeStatus{
   520  						Conditions: []v1alpha1.WorkflowNodeCondition{
   521  							{
   522  								Type:   v1alpha1.ConditionAccomplished,
   523  								Status: corev1.ConditionTrue,
   524  								Reason: "unit test mocked true",
   525  							},
   526  						},
   527  					},
   528  				},
   529  			},
   530  			want: Node{
   531  				Name:  "the-entry-0",
   532  				Type:  SerialNode,
   533  				State: NodeSucceed,
   534  				Serial: []NodeNameWithTemplate{
   535  					{Name: "", Template: "unimportant-task-0"},
   536  				},
   537  				Parallel: nil,
   538  				Template: "the-entry",
   539  				UID:      "uid-of-workflow-node",
   540  			},
   541  		},
   542  		{
   543  			name: "task node",
   544  			args: args{
   545  				kubeWorkflowNode: v1alpha1.WorkflowNode{
   546  					ObjectMeta: metav1.ObjectMeta{
   547  						Name:      "mocking-task-node-0",
   548  						Namespace: "mocked-namespace",
   549  					},
   550  					Spec: v1alpha1.WorkflowNodeSpec{
   551  						TemplateName: "mocking-task-node",
   552  						WorkflowName: "fake-workflow-0",
   553  						Type:         v1alpha1.TypeTask,
   554  						ConditionalBranches: []v1alpha1.ConditionalBranch{
   555  							{
   556  								Target:     "one-node",
   557  								Expression: "exitCode == 0",
   558  							},
   559  							{
   560  								Target:     "another-node",
   561  								Expression: "exitCode != 0",
   562  							},
   563  						},
   564  					},
   565  					Status: v1alpha1.WorkflowNodeStatus{
   566  						ConditionalBranchesStatus: &v1alpha1.ConditionalBranchesStatus{
   567  							Branches: []v1alpha1.ConditionalBranchStatus{
   568  								{
   569  									Target:           "one-node",
   570  									EvaluationResult: corev1.ConditionFalse,
   571  								},
   572  								{
   573  									Target:           "another-node",
   574  									EvaluationResult: corev1.ConditionTrue,
   575  								},
   576  							},
   577  							Context: nil,
   578  						},
   579  						ActiveChildren: []corev1.LocalObjectReference{
   580  							{
   581  								Name: "another-node-0",
   582  							},
   583  						},
   584  					},
   585  				},
   586  			},
   587  			want: Node{
   588  				Name:  "mocking-task-node-0",
   589  				Type:  TaskNode,
   590  				State: NodeRunning,
   591  				ConditionalBranches: []ConditionalBranch{
   592  					{
   593  						NodeNameWithTemplate: NodeNameWithTemplate{
   594  							Template: "one-node",
   595  							Name:     "",
   596  						},
   597  						Expression: "exitCode == 0",
   598  					},
   599  					{
   600  						NodeNameWithTemplate: NodeNameWithTemplate{
   601  							Template: "another-node",
   602  							Name:     "another-node-0",
   603  						},
   604  						Expression: "exitCode != 0",
   605  					},
   606  				},
   607  				Template: "mocking-task-node",
   608  			},
   609  			wantErr: false,
   610  		},
   611  	}
   612  	for _, tt := range tests {
   613  		t.Run(tt.name, func(t *testing.T) {
   614  			got, err := convertWorkflowNode(tt.args.kubeWorkflowNode)
   615  			if (err != nil) != tt.wantErr {
   616  				t.Errorf("convertWorkflowNode() error = %v, wantErr %v", err, tt.wantErr)
   617  				return
   618  			}
   619  			if !reflect.DeepEqual(got, tt.want) {
   620  				t.Errorf("convertWorkflowNode() got = %v, want %v", got, tt.want)
   621  			}
   622  		})
   623  	}
   624  }
   625  
   626  func Test_composeTaskAndNodes(t *testing.T) {
   627  	type args struct {
   628  		children []string
   629  		nodes    []string
   630  	}
   631  	tests := []struct {
   632  		name string
   633  		args args
   634  		want []NodeNameWithTemplate
   635  	}{
   636  		{
   637  			name: "ordered with serial",
   638  			args: args{
   639  				children: []string{"node-0", "node-1", "node-0", "node-2", "node-3"},
   640  				nodes:    []string{"node-0-instance", "node-1-instance", "node-0-another_instance"},
   641  			},
   642  			want: []NodeNameWithTemplate{
   643  				{
   644  					Name:     "node-0-instance",
   645  					Template: "node-0",
   646  				}, {
   647  					Name:     "node-1-instance",
   648  					Template: "node-1",
   649  				}, {
   650  					Name:     "node-0-another_instance",
   651  					Template: "node-0",
   652  				}, {
   653  					Name:     "",
   654  					Template: "node-2",
   655  				}, {
   656  					Name:     "",
   657  					Template: "node-3",
   658  				},
   659  			},
   660  		},
   661  	}
   662  	for _, tt := range tests {
   663  		t.Run(tt.name, func(t *testing.T) {
   664  			if got := composeSerialTaskAndNodes(tt.args.children, tt.args.nodes); !reflect.DeepEqual(got, tt.want) {
   665  				t.Errorf("composeSerialTaskAndNodes() = %v, want %v", got, tt.want)
   666  			}
   667  		})
   668  	}
   669  }
   670  
   671  func Test_composeParallelTaskAndNodes(t *testing.T) {
   672  	type args struct {
   673  		children []string
   674  		nodes    []string
   675  	}
   676  	tests := []struct {
   677  		name string
   678  		args args
   679  		want []NodeNameWithTemplate
   680  	}{
   681  		{
   682  			name: "parallel",
   683  			args: args{
   684  				children: []string{"node-a", "node-b", "node-a", "node-c", "node-d"},
   685  				nodes:    []string{"node-a-instance", "node-a-another_instance", "node-d-instance"},
   686  			},
   687  			want: []NodeNameWithTemplate{
   688  				{
   689  					Name:     "node-a-instance",
   690  					Template: "node-a",
   691  				}, {
   692  					Name:     "",
   693  					Template: "node-b",
   694  				}, {
   695  					Name:     "node-a-another_instance",
   696  					Template: "node-a",
   697  				}, {
   698  					Name:     "",
   699  					Template: "node-c",
   700  				}, {
   701  					Name:     "node-d-instance",
   702  					Template: "node-d",
   703  				},
   704  			},
   705  		},
   706  	}
   707  	for _, tt := range tests {
   708  		t.Run(tt.name, func(t *testing.T) {
   709  			if got := composeParallelTaskAndNodes(tt.args.children, tt.args.nodes); !reflect.DeepEqual(got, tt.want) {
   710  				t.Errorf("composeParallelTaskAndNodes() = %v, want %v", got, tt.want)
   711  			}
   712  		})
   713  	}
   714  }
   715  
   716  func Test_composeTaskConditionalBranches(t *testing.T) {
   717  	type args struct {
   718  		conditionalBranches []v1alpha1.ConditionalBranch
   719  		nodes               []string
   720  	}
   721  	tests := []struct {
   722  		name string
   723  		args args
   724  		want []ConditionalBranch
   725  	}{
   726  		{
   727  			name: "task node all of the branch is selected",
   728  			args: args{
   729  				conditionalBranches: []v1alpha1.ConditionalBranch{
   730  					{
   731  						Target:     "template-a",
   732  						Expression: "a: whatever valid or not",
   733  					},
   734  					{
   735  						Target:     "template-b",
   736  						Expression: "b: whatever valid or not",
   737  					},
   738  					{
   739  						Target:     "template-c",
   740  						Expression: "c: whatever valid or not",
   741  					},
   742  				},
   743  				nodes: []string{
   744  					"template-a-0",
   745  					"template-b-0",
   746  					"template-c-0",
   747  				},
   748  			},
   749  			want: []ConditionalBranch{
   750  				{
   751  					NodeNameWithTemplate: NodeNameWithTemplate{
   752  						Name:     "template-a-0",
   753  						Template: "template-a",
   754  					},
   755  					Expression: "a: whatever valid or not",
   756  				},
   757  				{
   758  					NodeNameWithTemplate: NodeNameWithTemplate{
   759  						Name:     "template-b-0",
   760  						Template: "template-b",
   761  					},
   762  					Expression: "b: whatever valid or not",
   763  				},
   764  				{
   765  					NodeNameWithTemplate: NodeNameWithTemplate{
   766  						Name:     "template-c-0",
   767  						Template: "template-c",
   768  					},
   769  					Expression: "c: whatever valid or not",
   770  				},
   771  			},
   772  		},
   773  		{
   774  			name: "none of the branch is selected",
   775  			args: args{
   776  				conditionalBranches: []v1alpha1.ConditionalBranch{
   777  					{
   778  						Target:     "template-a",
   779  						Expression: "a: whatever valid or not",
   780  					},
   781  					{
   782  						Target:     "template-b",
   783  						Expression: "b: whatever valid or not",
   784  					},
   785  					{
   786  						Target:     "template-c",
   787  						Expression: "c: whatever valid or not",
   788  					},
   789  				},
   790  				nodes: []string{},
   791  			},
   792  			want: []ConditionalBranch{
   793  				{
   794  					NodeNameWithTemplate: NodeNameWithTemplate{
   795  						Name:     "",
   796  						Template: "template-a",
   797  					},
   798  					Expression: "a: whatever valid or not",
   799  				},
   800  				{
   801  					NodeNameWithTemplate: NodeNameWithTemplate{
   802  						Name:     "",
   803  						Template: "template-b",
   804  					},
   805  					Expression: "b: whatever valid or not",
   806  				},
   807  				{
   808  					NodeNameWithTemplate: NodeNameWithTemplate{
   809  						Name:     "",
   810  						Template: "template-c",
   811  					},
   812  					Expression: "c: whatever valid or not",
   813  				},
   814  			},
   815  		},
   816  		{
   817  			name: "part of the branch is selected",
   818  			args: args{
   819  				conditionalBranches: []v1alpha1.ConditionalBranch{
   820  					{
   821  						Target:     "template-a",
   822  						Expression: "a: whatever valid or not",
   823  					},
   824  					{
   825  						Target:     "template-b",
   826  						Expression: "b: whatever valid or not",
   827  					},
   828  					{
   829  						Target:     "template-c",
   830  						Expression: "c: whatever valid or not",
   831  					},
   832  				},
   833  				nodes: []string{
   834  					"template-a-0",
   835  				},
   836  			},
   837  			want: []ConditionalBranch{
   838  				{
   839  					NodeNameWithTemplate: NodeNameWithTemplate{
   840  						Name:     "template-a-0",
   841  						Template: "template-a",
   842  					},
   843  					Expression: "a: whatever valid or not",
   844  				},
   845  				{
   846  					NodeNameWithTemplate: NodeNameWithTemplate{
   847  						Name:     "",
   848  						Template: "template-b",
   849  					},
   850  					Expression: "b: whatever valid or not",
   851  				},
   852  				{
   853  					NodeNameWithTemplate: NodeNameWithTemplate{
   854  						Name:     "",
   855  						Template: "template-c",
   856  					},
   857  					Expression: "c: whatever valid or not",
   858  				},
   859  			},
   860  		},
   861  	}
   862  	for _, tt := range tests {
   863  		t.Run(tt.name, func(t *testing.T) {
   864  			if got := composeTaskConditionalBranches(tt.args.conditionalBranches, tt.args.nodes); !reflect.DeepEqual(got, tt.want) {
   865  				t.Errorf("composeTaskConditionalBranches() = %v, want %v", got, tt.want)
   866  			}
   867  		})
   868  	}
   869  }
   870