github.com/verrazzano/verrazzano@v1.7.1/tools/vz/test/helpers/fake_cmd_context.go (about) 1 // Copyright (c) 2022, 2024, Oracle and/or its affiliates. 2 // Licensed under the Universal Permissive License v 1.0 as shown at https://oss.oracle.com/licenses/upl. 3 4 package helpers 5 6 import ( 7 "bytes" 8 "encoding/json" 9 "errors" 10 "fmt" 11 "github.com/stretchr/testify/assert" 12 "io" 13 "k8s.io/client-go/discovery" 14 discoveryFake "k8s.io/client-go/discovery/fake" 15 "testing" 16 17 "net/http" 18 "os" 19 "strings" 20 "time" 21 22 "github.com/spf13/cobra" 23 "github.com/verrazzano/verrazzano/tools/vz/pkg/github" 24 "k8s.io/cli-runtime/pkg/genericclioptions" 25 "k8s.io/client-go/dynamic" 26 "k8s.io/client-go/kubernetes" 27 "k8s.io/client-go/kubernetes/fake" 28 "sigs.k8s.io/controller-runtime/pkg/client" 29 ) 30 31 type FakeRootCmdContext struct { 32 client client.Client 33 kubeClient kubernetes.Interface 34 dynamicClient dynamic.Interface 35 genericclioptions.IOStreams 36 } 37 38 type FakeRootCmdContextWithFiles struct { 39 FakeRootCmdContext 40 Out *os.File 41 ErrOut *os.File 42 } 43 44 // GetOutputStream - return the output stream 45 func (rc *FakeRootCmdContext) GetOutputStream() io.Writer { 46 return rc.IOStreams.Out 47 } 48 49 // GetErrorStream - return the error stream 50 func (rc *FakeRootCmdContext) GetErrorStream() io.Writer { 51 return rc.IOStreams.ErrOut 52 } 53 54 // GetInputStream - return the input stream 55 func (rc *FakeRootCmdContext) GetInputStream() io.Reader { 56 return rc.IOStreams.In 57 } 58 59 // GetClient - return a controller runtime client that supports the schemes used by the CLI 60 func (rc *FakeRootCmdContext) GetClient(cmd *cobra.Command) (client.Client, error) { 61 return rc.client, nil 62 } 63 64 // GetKubeClient - return a Kubernetes clientset for use with the fake go-client 65 func (rc *FakeRootCmdContext) GetKubeClient(cmd *cobra.Command) (kubernetes.Interface, error) { 66 return rc.kubeClient, nil 67 } 68 69 // SetClient - set the client 70 func (rc *FakeRootCmdContext) SetClient(client client.Client) { 71 rc.client = client 72 } 73 74 // SetKubeClient - set the kubeclient 75 func (rc *FakeRootCmdContext) SetKubeClient(kubeClient kubernetes.Interface) { 76 rc.kubeClient = kubeClient 77 } 78 79 // RoundTripFunc - define the type for the Transport function 80 type RoundTripFunc func(req *http.Request) *http.Response 81 82 // RoundTrip - define the implementation for the Transport function 83 func (f RoundTripFunc) RoundTrip(req *http.Request) (*http.Response, error) { 84 return f(req), nil 85 } 86 87 // GetHTTPClient - return an HTTP client for testing that always responds with a 200 88 // and a pre-defined list of releases 89 func (rc *FakeRootCmdContext) GetHTTPClient() *http.Client { 90 // Predefined response for the list of releases 91 releaseResponse := []github.ReleaseAsset{ 92 { 93 TagName: "v1.3.0", 94 }, 95 { 96 TagName: "v1.2.0", 97 }, 98 { 99 TagName: "v1.3.1", 100 }, 101 } 102 jsonResp, _ := json.Marshal(releaseResponse) 103 104 // Predefined response for getting operator.yaml 105 jsonOperResp, err := os.ReadFile("../../test/testdata/operator-file-fake.yaml") 106 if err != nil { 107 panic(err) 108 } 109 110 return &http.Client{ 111 Timeout: time.Second * 30, 112 Transport: RoundTripFunc(func(req *http.Request) *http.Response { 113 if strings.Contains(req.URL.Path, "/releases/download") { 114 return &http.Response{ 115 StatusCode: http.StatusOK, 116 Body: io.NopCloser(bytes.NewBuffer(jsonOperResp)), 117 Header: http.Header{"Content-Type": {"application/octet-stream"}}, 118 } 119 } 120 return &http.Response{ 121 StatusCode: http.StatusOK, 122 Body: io.NopCloser(bytes.NewBuffer(jsonResp)), 123 Header: http.Header{"Content-Type": {"application/json"}}, 124 } 125 }), 126 } 127 } 128 129 // GetDynamicClient - return a dynamic client for use with the fake go-client 130 func (rc *FakeRootCmdContext) GetDynamicClient(cmd *cobra.Command) (dynamic.Interface, error) { 131 return rc.dynamicClient, nil 132 } 133 134 // SetDynamicClient - set a dynamic client for use with the fake go-client (used for testing) 135 func (rc *FakeRootCmdContext) SetDynamicClient(dynClient dynamic.Interface) { 136 rc.dynamicClient = dynClient 137 } 138 139 func NewFakeRootCmdContext(streams genericclioptions.IOStreams) *FakeRootCmdContext { 140 return &FakeRootCmdContext{ 141 IOStreams: streams, 142 kubeClient: fake.NewSimpleClientset(), 143 } 144 } 145 146 // NewFakeRootCmdContextWithFiles creates a newFakeRootCmdContext with the out stream and the error stream set to two separate files 147 func NewFakeRootCmdContextWithFiles(t *testing.T) *FakeRootCmdContextWithFiles { 148 stdOutFile, stdErrfile, err := createStdTempFiles() 149 assert.Nil(t, err) 150 return &FakeRootCmdContextWithFiles{ 151 FakeRootCmdContext: FakeRootCmdContext{ 152 IOStreams: genericclioptions.IOStreams{In: os.Stdin, Out: stdOutFile, ErrOut: stdErrfile}, 153 kubeClient: fake.NewSimpleClientset(), 154 }, 155 Out: stdOutFile, 156 ErrOut: stdErrfile, 157 } 158 } 159 160 // CleanUpFakeRootCmdContextWithFiles removes the standard out and standard error files from the local file system 161 func CleanUpNewFakeRootCmdContextWithFiles(context *FakeRootCmdContextWithFiles) { 162 _, err := os.Stat(context.Out.Name()) 163 if !(errors.Is(err, os.ErrNotExist)) { 164 os.Remove(context.Out.Name()) 165 } 166 _, err = os.Stat(context.ErrOut.Name()) 167 if !(errors.Is(err, os.ErrNotExist)) { 168 os.Remove(context.ErrOut.Name()) 169 } 170 } 171 172 // createStdTempFiles creates temporary files for stdout and stderr. 173 func createStdTempFiles() (*os.File, *os.File, error) { 174 stdoutFile, err := os.CreateTemp("", "tmpstdout") 175 if err != nil { 176 return nil, nil, err 177 } 178 179 stderrFile, err := os.CreateTemp("", "tmpstderr") 180 if err != nil { 181 return nil, nil, err 182 } 183 184 return stdoutFile, stderrFile, nil 185 } 186 187 func (rc *FakeRootCmdContext) GetDiscoveryClient(cmd *cobra.Command) (discovery.DiscoveryInterface, error) { 188 client := rc.kubeClient 189 discoveryClient, ok := client.Discovery().(*discoveryFake.FakeDiscovery) 190 if !ok { 191 return nil, fmt.Errorf("DiscoveryClient was not successfully created") 192 } 193 return discoveryClient, nil 194 } 195 196 func (rc *FakeRootCmdContext) VerifyCLIArgsNil(cmd *cobra.Command) error { 197 cmd.Args = func(cmd *cobra.Command, args []string) error { 198 // In unit-tests the TestName is an arg. So to avoid tests failing because of the TestName 199 // we're now checking that the arg list is greater than 1. 200 if len(args) > 1 { 201 return fmt.Errorf("invalid arguments specified: %s", args) 202 } 203 return nil 204 } 205 return nil 206 }