github.com/oam-dev/kubevela@v1.9.11/references/cli/ls_test.go (about) 1 /* 2 Copyright 2021 The KubeVela Authors. 3 4 Licensed under the Apache License, Version 2.0 (the "License"); 5 you may not use this file except in compliance with the License. 6 You may obtain a copy of the License at 7 8 http://www.apache.org/licenses/LICENSE-2.0 9 10 Unless required by applicable law or agreed to in writing, software 11 distributed under the License is distributed on an "AS IS" BASIS, 12 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 See the License for the specific language governing permissions and 14 limitations under the License. 15 */ 16 17 package cli 18 19 import ( 20 "context" 21 "fmt" 22 "testing" 23 24 "github.com/stretchr/testify/require" 25 metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" 26 "k8s.io/apimachinery/pkg/runtime" 27 "sigs.k8s.io/controller-runtime/pkg/client/fake" 28 29 "github.com/oam-dev/kubevela/apis/core.oam.dev/common" 30 "github.com/oam-dev/kubevela/apis/core.oam.dev/v1beta1" 31 common2 "github.com/oam-dev/kubevela/pkg/utils/common" 32 ) 33 34 var componentOrderSpec = v1beta1.ApplicationSpec{ 35 Components: []common.ApplicationComponent{{ 36 Name: "test-component1", 37 Type: "worker", 38 Properties: &runtime.RawExtension{Raw: []byte(`{"cmd":["sleep","1000"],"image":"busybox"}`)}, 39 }, { 40 Name: "test-component2", 41 Type: "worker", 42 Properties: &runtime.RawExtension{Raw: []byte(`{"cmd":["sleep","1000"],"image":"busybox"}`)}, 43 }, { 44 Name: "test-component3", 45 Type: "worker", 46 Properties: &runtime.RawExtension{Raw: []byte(`{"cmd":["sleep","1000"],"image":"busybox"}`)}, 47 }, 48 }, 49 } 50 51 var componentOrderStatus = common.AppStatus{ 52 Services: []common.ApplicationComponentStatus{{ 53 Name: "test-component2", 54 Message: "test-component2 applied", 55 Healthy: true, 56 }, { 57 Name: "test-component1", 58 Message: "test-component1 applied", 59 Healthy: false, 60 }, { 61 Name: "test-component3", 62 Message: "", 63 Healthy: true, 64 }}, 65 66 Phase: common.ApplicationRunning, 67 } 68 69 var componentSpec = v1beta1.ApplicationSpec{ 70 Components: []common.ApplicationComponent{ 71 { 72 Name: "test1-component", 73 Type: "worker", 74 Properties: &runtime.RawExtension{Raw: []byte(`{"cmd":["sleep","1000"],"image":"busybox"}`)}, 75 }, 76 }, 77 } 78 79 var componentStatus = common.AppStatus{ 80 Services: []common.ApplicationComponentStatus{ 81 { 82 Name: "test1-component", 83 Message: "test1-component applied", 84 Healthy: true, 85 }, 86 }, 87 Phase: common.ApplicationRunning, 88 } 89 90 func TestBuildApplicationListTable(t *testing.T) { 91 ctx := context.TODO() 92 testCases := map[string]struct { 93 apps []*v1beta1.Application 94 expectedErr error 95 namespace string 96 labelSelector string 97 fieldSelector string 98 expectAppListSize int 99 }{ 100 "specified component order different from applied": { 101 apps: []*v1beta1.Application{ 102 { 103 ObjectMeta: metav1.ObjectMeta{ 104 Name: "dependency", 105 Namespace: "test", 106 }, 107 Spec: componentOrderSpec, 108 Status: componentOrderStatus, 109 }, 110 }, 111 expectedErr: nil, 112 namespace: "test", 113 expectAppListSize: 1, 114 }, 115 "specified label selector": { 116 apps: []*v1beta1.Application{ 117 { 118 ObjectMeta: metav1.ObjectMeta{ 119 Name: "app1", 120 Namespace: "test1", 121 }, 122 Spec: componentSpec, 123 Status: componentStatus, 124 }, 125 { 126 ObjectMeta: metav1.ObjectMeta{ 127 Name: "app2", 128 Namespace: "test1", 129 Labels: map[string]string{ 130 "app.kubernetes.io/name": "busybox", 131 "app.kubernetes.io/version": "v1", 132 }, 133 }, 134 Spec: componentSpec, 135 Status: componentStatus, 136 }, 137 }, 138 expectedErr: nil, 139 namespace: "test1", 140 labelSelector: "app.kubernetes.io/name=busybox,app.kubernetes.io/version=v1", 141 expectAppListSize: 1, 142 }, 143 "specified field selector": { 144 apps: []*v1beta1.Application{ 145 { 146 ObjectMeta: metav1.ObjectMeta{ 147 Name: "app1", 148 Namespace: "test2", 149 }, 150 Spec: componentSpec, 151 Status: componentStatus, 152 }, 153 { 154 ObjectMeta: metav1.ObjectMeta{ 155 Name: "app2", 156 Namespace: "test2", 157 }, 158 Spec: componentSpec, 159 Status: componentStatus, 160 }, 161 }, 162 expectedErr: nil, 163 namespace: "test2", 164 fieldSelector: "metadata.name=app2,metadata.namespace=test2", 165 expectAppListSize: 1, 166 }, 167 } 168 169 client := fake.NewClientBuilder().WithScheme(common2.Scheme).Build() 170 171 for name, tc := range testCases { 172 t.Run(name, func(t *testing.T) { 173 r := require.New(t) 174 175 if tc.apps != nil && len(tc.apps) > 0 { 176 for _, app := range tc.apps { 177 err := client.Create(ctx, app) 178 r.NoError(err) 179 } 180 } 181 service := map[string]common.ApplicationComponentStatus{} 182 for _, app := range tc.apps { 183 for _, s := range app.Status.Services { 184 service[s.Name] = s 185 } 186 } 187 188 LabelSelector = tc.labelSelector 189 FieldSelector = tc.fieldSelector 190 tb, err := buildApplicationListTable(ctx, client, tc.namespace) 191 r.Equal(tc.expectedErr, err) 192 for _, app := range tc.apps { 193 for i, component := range app.Spec.Components { 194 row := tb.Rows[i+1] 195 compName := fmt.Sprintf("%s", row.Cells[1].Data) 196 r.Equal(component.Name, compName) 197 r.Equal(component.Type, fmt.Sprintf("%s", row.Cells[2].Data)) 198 r.Equal(string(app.Status.Phase), fmt.Sprintf("%s", row.Cells[4].Data)) 199 r.Equal(getHealthString(service[compName].Healthy), fmt.Sprintf("%s", row.Cells[5].Data)) 200 r.Equal(service[compName].Message, fmt.Sprintf("%s", row.Cells[6].Data)) 201 } 202 } 203 // filter header, "├─" and "└─" to get actual appList size 204 var actualAppListSize int 205 for _, row := range tb.Rows { 206 if row.Cells[0].Data != "APP" && row.Cells[0].Data != "├─" && row.Cells[0].Data != "└─" { 207 actualAppListSize = actualAppListSize + 1 208 } 209 } 210 r.Equal(tc.expectAppListSize, actualAppListSize) 211 }) 212 } 213 }