istio.io/istio@v0.0.0-20240520182934-d79c90f27776/istioctl/pkg/internaldebug/internal-debug_test.go (about) 1 // Copyright Istio 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 package internaldebug 16 17 import ( 18 "bytes" 19 "context" 20 "fmt" 21 "net/http" 22 "strings" 23 "testing" 24 25 discovery "github.com/envoyproxy/go-control-plane/envoy/service/discovery/v3" 26 "github.com/spf13/cobra" 27 "google.golang.org/grpc" 28 corev1 "k8s.io/api/core/v1" 29 metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" 30 "k8s.io/cli-runtime/pkg/resource" 31 "k8s.io/client-go/rest/fake" 32 cmdtesting "k8s.io/kubectl/pkg/cmd/testing" 33 cmdutil "k8s.io/kubectl/pkg/cmd/util" 34 35 "istio.io/api/label" 36 "istio.io/istio/istioctl/pkg/cli" 37 "istio.io/istio/istioctl/pkg/clioptions" 38 "istio.io/istio/istioctl/pkg/multixds" 39 "istio.io/istio/istioctl/pkg/xds" 40 "istio.io/istio/pkg/kube" 41 "istio.io/istio/pkg/test/util/assert" 42 ) 43 44 type execTestCase struct { 45 args []string 46 revision string 47 noIstiod bool 48 49 // Typically use one of the three 50 expectedOutput string // Expected constant output 51 expectedString string // String output is expected to contain 52 53 wantException bool 54 } 55 56 func TestInternalDebug(t *testing.T) { 57 cases := []execTestCase{ 58 { // case 0, no args 59 args: []string{}, 60 noIstiod: true, 61 expectedOutput: "Error: debug type is required\n", 62 wantException: true, 63 }, 64 { // case 1, no istiod 65 args: []string{"adsz"}, 66 noIstiod: true, 67 expectedOutput: "Error: no running Istio pods in \"istio-system\"\n", 68 wantException: true, 69 }, 70 { // case 2, with Istiod instance 71 args: []string{"adsz"}, 72 expectedString: "", 73 }, 74 } 75 multixds.GetXdsResponse = func(_ *discovery.DiscoveryRequest, _ string, _ string, _ clioptions.CentralControlPlaneOptions, _ []grpc.DialOption, 76 ) (*discovery.DiscoveryResponse, error) { 77 return &discovery.DiscoveryResponse{}, nil 78 } 79 t.Cleanup(func() { 80 multixds.GetXdsResponse = xds.GetXdsResponse 81 }) 82 83 for i, c := range cases { 84 t.Run(fmt.Sprintf("case %d %s", i, strings.Join(c.args, " ")), func(t *testing.T) { 85 ctx := cli.NewFakeContext(&cli.NewFakeContextOption{ 86 IstioNamespace: "istio-system", 87 }) 88 if !c.noIstiod { 89 client, err := ctx.CLIClientWithRevision(c.revision) 90 assert.NoError(t, err) 91 _, err = client.Kube().CoreV1().Pods("istio-system").Create(context.TODO(), &corev1.Pod{ 92 ObjectMeta: metav1.ObjectMeta{ 93 Name: "istiod-test", 94 Namespace: "istio-system", 95 Labels: map[string]string{ 96 "app": "istiod", 97 label.IoIstioRev.Name: c.revision, 98 }, 99 }, 100 Status: corev1.PodStatus{ 101 Phase: corev1.PodRunning, 102 }, 103 }, metav1.CreateOptions{}) 104 assert.NoError(t, err) 105 } 106 verifyExecTestOutput(t, DebugCommand(ctx), c) 107 }) 108 } 109 } 110 111 func verifyExecTestOutput(t *testing.T, cmd *cobra.Command, c execTestCase) { 112 t.Helper() 113 114 var out bytes.Buffer 115 cmd.SetArgs(c.args) 116 cmd.SilenceUsage = true 117 cmd.SetOut(&out) 118 cmd.SetErr(&out) 119 120 fErr := cmd.Execute() 121 output := out.String() 122 123 if c.expectedOutput != "" && c.expectedOutput != output { 124 t.Fatalf("Unexpected output for 'istioctl %s'\n got: %q\nwant: %q", strings.Join(c.args, " "), output, c.expectedOutput) 125 } 126 127 if c.expectedString != "" && !strings.Contains(output, c.expectedString) { 128 t.Fatalf("Output didn't match for '%s %s'\n got %v\nwant: %v", cmd.Name(), strings.Join(c.args, " "), output, c.expectedString) 129 } 130 131 if c.wantException { 132 if fErr == nil { 133 t.Fatalf("Wanted an exception for 'istioctl %s', didn't get one, output was %q", 134 strings.Join(c.args, " "), output) 135 } 136 } else { 137 if fErr != nil { 138 t.Fatalf("Unwanted exception for 'istioctl %s': %v", strings.Join(c.args, " "), fErr) 139 } 140 } 141 } 142 143 func init() { 144 cli.MakeKubeFactory = func(k kube.CLIClient) cmdutil.Factory { 145 tf := cmdtesting.NewTestFactory() 146 _, _, codec := cmdtesting.NewExternalScheme() 147 tf.UnstructuredClient = &fake.RESTClient{ 148 NegotiatedSerializer: resource.UnstructuredPlusDefaultContentConfig().NegotiatedSerializer, 149 Resp: &http.Response{ 150 StatusCode: http.StatusOK, 151 Header: cmdtesting.DefaultHeader(), 152 Body: cmdtesting.ObjBody(codec, 153 cmdtesting.NewInternalType("", "", "foo")), 154 }, 155 } 156 return tf 157 } 158 }