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  }