github.com/1aal/kubeblocks@v0.0.0-20231107070852-e1c03e598921/pkg/cli/cmd/cluster/list_ops_test.go (about)

     1  /*
     2  Copyright (C) 2022-2023 ApeCloud Co., Ltd
     3  
     4  This file is part of KubeBlocks project
     5  
     6  This program is free software: you can redistribute it and/or modify
     7  it under the terms of the GNU Affero General Public License as published by
     8  the Free Software Foundation, either version 3 of the License, or
     9  (at your option) any later version.
    10  
    11  This program is distributed in the hope that it will be useful
    12  but WITHOUT ANY WARRANTY; without even the implied warranty of
    13  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    14  GNU Affero General Public License for more details.
    15  
    16  You should have received a copy of the GNU Affero General Public License
    17  along with this program.  If not, see <http://www.gnu.org/licenses/>.
    18  */
    19  
    20  package cluster
    21  
    22  import (
    23  	"bytes"
    24  	"io"
    25  	"strings"
    26  
    27  	. "github.com/onsi/ginkgo/v2"
    28  	. "github.com/onsi/gomega"
    29  	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
    30  	"k8s.io/apimachinery/pkg/runtime"
    31  	"k8s.io/cli-runtime/pkg/genericiooptions"
    32  	cmdtesting "k8s.io/kubectl/pkg/cmd/testing"
    33  
    34  	appsv1alpha1 "github.com/1aal/kubeblocks/apis/apps/v1alpha1"
    35  	"github.com/1aal/kubeblocks/pkg/cli/list"
    36  	clitesting "github.com/1aal/kubeblocks/pkg/cli/testing"
    37  	"github.com/1aal/kubeblocks/pkg/cli/types"
    38  )
    39  
    40  var _ = Describe("Expose", func() {
    41  	const (
    42  		namespace         = "test"
    43  		pending           = "pending"
    44  		running           = "running"
    45  		failed            = "failed"
    46  		succeed           = "succeed"
    47  		all               = "all"
    48  		statelessCompName = "stateless"
    49  		statefulCompName  = "stateful"
    50  	)
    51  
    52  	var (
    53  		streams genericiooptions.IOStreams
    54  		tf      *cmdtesting.TestFactory
    55  		opsName string
    56  	)
    57  
    58  	BeforeEach(func() {
    59  		streams, _, _, _ = genericiooptions.NewTestIOStreams()
    60  		tf = clitesting.NewTestFactory(namespace)
    61  	})
    62  
    63  	AfterEach(func() {
    64  		tf.Cleanup()
    65  	})
    66  
    67  	generateOpsObject := func(opsType appsv1alpha1.OpsType, phase appsv1alpha1.OpsPhase) *appsv1alpha1.OpsRequest {
    68  		ops := &appsv1alpha1.OpsRequest{
    69  			ObjectMeta: metav1.ObjectMeta{
    70  				Name:      "list-ops-" + clitesting.GetRandomStr(),
    71  				Namespace: namespace,
    72  			},
    73  			Spec: appsv1alpha1.OpsRequestSpec{
    74  				ClusterRef: "test-cluster",
    75  				Type:       opsType,
    76  			},
    77  			Status: appsv1alpha1.OpsRequestStatus{
    78  				Phase: phase,
    79  			},
    80  		}
    81  		ops.Status.Components = map[string]appsv1alpha1.OpsRequestComponentStatus{
    82  			statelessCompName: {},
    83  			statefulCompName:  {},
    84  		}
    85  		return ops
    86  	}
    87  
    88  	initOpsRequests := func() {
    89  		opsKeys := []struct {
    90  			opsType appsv1alpha1.OpsType
    91  			phase   appsv1alpha1.OpsPhase
    92  		}{
    93  			{appsv1alpha1.UpgradeType, appsv1alpha1.OpsPendingPhase},
    94  			{appsv1alpha1.HorizontalScalingType, appsv1alpha1.OpsFailedPhase},
    95  			{appsv1alpha1.HorizontalScalingType, appsv1alpha1.OpsSucceedPhase},
    96  			{appsv1alpha1.RestartType, appsv1alpha1.OpsSucceedPhase},
    97  			{appsv1alpha1.VerticalScalingType, appsv1alpha1.OpsRunningPhase},
    98  			{appsv1alpha1.VerticalScalingType, appsv1alpha1.OpsFailedPhase},
    99  			{appsv1alpha1.VerticalScalingType, appsv1alpha1.OpsRunningPhase},
   100  		}
   101  		opsList := make([]runtime.Object, len(opsKeys))
   102  		for i := range opsKeys {
   103  			opsList[i] = generateOpsObject(opsKeys[i].opsType, opsKeys[i].phase)
   104  		}
   105  		opsName = opsList[0].(*appsv1alpha1.OpsRequest).Name
   106  		tf.FakeDynamicClient = clitesting.FakeDynamicClient(opsList...)
   107  	}
   108  
   109  	getStdoutLinesCount := func(out io.Writer) int {
   110  		b := out.(*bytes.Buffer).String()
   111  		b = strings.Trim(b, "\n")
   112  		return len(strings.Split(b, "\n"))
   113  	}
   114  
   115  	initOpsOption := func(status []string, opsTypes []string) *opsListOptions {
   116  		streams, _, _, _ = genericiooptions.NewTestIOStreams()
   117  		return &opsListOptions{
   118  			ListOptions: list.NewListOptions(tf, streams, types.OpsGVR()),
   119  			status:      status,
   120  			opsType:     opsTypes,
   121  		}
   122  	}
   123  
   124  	It("list ops", func() {
   125  		By("new list ops command")
   126  		cmd := NewListOpsCmd(tf, streams)
   127  		Expect(cmd).ShouldNot(BeNil())
   128  
   129  		By("init opsRequests for testing")
   130  		initOpsRequests()
   131  
   132  		By("test run cmd")
   133  		cmd.Run(cmd, nil)
   134  
   135  		By("test status flag with default values")
   136  		o := initOpsOption([]string{pending, running, failed}, nil)
   137  		Expect(o.printOpsList()).Should(Succeed())
   138  		// title + filter ops
   139  		Expect(getStdoutLinesCount(o.Out)).Should(Equal(6))
   140  
   141  		By("test status flag with `all` keyword")
   142  		o = initOpsOption([]string{all}, nil)
   143  		Expect(o.printOpsList()).Should(Succeed())
   144  		// title + filter ops
   145  		Expect(getStdoutLinesCount(o.Out)).Should(Equal(8))
   146  
   147  		By("test status flag with custom inputs")
   148  		o = initOpsOption([]string{succeed}, nil)
   149  		Expect(o.printOpsList()).Should(Succeed())
   150  		// title + filter ops
   151  		Expect(getStdoutLinesCount(o.Out)).Should(Equal(3))
   152  
   153  		o = initOpsOption([]string{failed}, nil)
   154  		Expect(o.printOpsList()).Should(Succeed())
   155  		// title + filter ops
   156  		Expect(getStdoutLinesCount(o.Out)).Should(Equal(3))
   157  
   158  		By("test type flag")
   159  		o = initOpsOption([]string{all}, []string{string(appsv1alpha1.RestartType)})
   160  		Expect(o.printOpsList()).Should(Succeed())
   161  		// title + filter ops
   162  		Expect(getStdoutLinesCount(o.Out)).Should(Equal(2))
   163  
   164  		o = initOpsOption([]string{all}, []string{string(appsv1alpha1.RestartType), string(appsv1alpha1.VerticalScalingType)})
   165  		Expect(o.printOpsList()).Should(Succeed())
   166  		// title + filter ops
   167  		Expect(getStdoutLinesCount(o.Out)).Should(Equal(5))
   168  
   169  		By("test component for upgrade ops")
   170  		o = initOpsOption([]string{all}, []string{string(appsv1alpha1.UpgradeType)})
   171  		Expect(o.printOpsList()).Should(Succeed())
   172  		Expect(o.Out).Should(ContainSubstring(statefulCompName + "," + statelessCompName))
   173  
   174  		By("list-ops with specified name")
   175  		o = initOpsOption(nil, nil)
   176  		o.opsRequestName = opsName
   177  		Expect(o.printOpsList()).Should(Succeed())
   178  		Expect(getStdoutLinesCount(o.Out)).Should(Equal(2))
   179  
   180  		By("list-ops with not exist ops")
   181  		o = initOpsOption(nil, nil)
   182  		o.opsRequestName = "not-exist-ops"
   183  		done := clitesting.Capture()
   184  		Expect(o.printOpsList()).Should(Succeed())
   185  		capturedOutput, _ := done()
   186  		Expect(clitesting.ContainExpectStrings(capturedOutput, "No opsRequests found")).Should(BeTrue())
   187  
   188  		By("list-ops with not exist ops")
   189  		o = initOpsOption([]string{pending}, []string{string(appsv1alpha1.RestartType)})
   190  		done = clitesting.Capture()
   191  		Expect(o.printOpsList()).Should(Succeed())
   192  		capturedOutput, _ = done()
   193  		Expect(clitesting.ContainExpectStrings(capturedOutput, "kbcli cluster list-ops --status all")).Should(BeTrue())
   194  	})
   195  
   196  })