github.com/spinnaker/spin@v1.30.0/cmd/pipeline-template/get_test.go (about) 1 // Copyright (c) 2018, Google, Inc. 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 14 package pipeline_template 15 16 import ( 17 "bytes" 18 "fmt" 19 "io/ioutil" 20 "net/http" 21 "net/http/httptest" 22 "strings" 23 "testing" 24 25 "github.com/andreyvit/diff" 26 27 "github.com/spinnaker/spin/cmd" 28 "github.com/spinnaker/spin/util" 29 ) 30 31 func TestPipelineGet_json(t *testing.T) { 32 ts := testGatePipelineTemplateGetSuccess() 33 defer ts.Close() 34 35 buffer := new(bytes.Buffer) 36 rootCmd, rootOpts := cmd.NewCmdRoot(buffer, buffer) 37 rootCmd.AddCommand(NewPipelineTemplateCmd(rootOpts)) 38 39 args := []string{"pipeline-template", "get", "--id", "newSpelTemplate", "--gate-endpoint", ts.URL} 40 rootCmd.SetArgs(args) 41 42 err := rootCmd.Execute() 43 if err != nil { 44 t.Fatalf("Command failed with: %s", err) 45 } 46 47 expected := strings.TrimSpace(pipelineTemplateGetJson) 48 recieved := strings.TrimSpace(buffer.String()) 49 if expected != recieved { 50 t.Fatalf("Unexpected command output:\n%s", diff.LineDiff(expected, recieved)) 51 } 52 } 53 54 func TestPipelineGet_yaml(t *testing.T) { 55 ts := testGatePipelineTemplateGetSuccess() 56 defer ts.Close() 57 58 buffer := new(bytes.Buffer) 59 rootCmd, rootOpts := cmd.NewCmdRoot(buffer, buffer) 60 rootCmd.AddCommand(NewPipelineTemplateCmd(rootOpts)) 61 62 args := []string{"pipeline-template", "get", "--id", "newSpelTemplate", "--output", "yaml", "--gate-endpoint", ts.URL} 63 rootCmd.SetArgs(args) 64 65 err := rootCmd.Execute() 66 if err != nil { 67 t.Fatalf("Command failed with: %s", err) 68 } 69 70 expected := strings.TrimSpace(pipelineTemplateGetYaml) 71 recieved := strings.TrimSpace(buffer.String()) 72 if expected != recieved { 73 t.Fatalf("Unexpected command output:\n%s", diff.LineDiff(expected, recieved)) 74 } 75 } 76 77 func TestPipelineGet_args(t *testing.T) { 78 ts := testGatePipelineTemplateGetSuccess() 79 defer ts.Close() 80 81 rootCmd, rootOpts := cmd.NewCmdRoot(ioutil.Discard, ioutil.Discard) 82 rootCmd.AddCommand(NewPipelineTemplateCmd(rootOpts)) 83 84 args := []string{"pipeline-template", "get", "newSpelTemplate", "--gate-endpoint", ts.URL} 85 rootCmd.SetArgs(args) 86 87 err := rootCmd.Execute() 88 if err != nil { 89 t.Fatalf("Command failed with: %s", err) 90 } 91 } 92 93 func TestPipelineGet_tag(t *testing.T) { 94 ts := testGatePipelineTemplateGetSuccess() 95 defer ts.Close() 96 97 rootCmd, rootOpts := cmd.NewCmdRoot(ioutil.Discard, ioutil.Discard) 98 rootCmd.AddCommand(NewPipelineTemplateCmd(rootOpts)) 99 100 args := []string{"pipeline-template", "get", "newSpelTemplate", "--tag", "stable", "--gate-endpoint", ts.URL} 101 rootCmd.SetArgs(args) 102 103 err := rootCmd.Execute() 104 if err != nil { 105 t.Fatalf("Command failed with: %s", err) 106 } 107 } 108 109 func TestPipelineGet_flags(t *testing.T) { 110 ts := testGatePipelineTemplateGetSuccess() 111 defer ts.Close() 112 113 rootCmd, rootOpts := cmd.NewCmdRoot(ioutil.Discard, ioutil.Discard) 114 rootCmd.AddCommand(NewPipelineTemplateCmd(rootOpts)) 115 116 args := []string{"pipeline-template", "get", "--gate-endpoint", ts.URL} // missing id flag and no args 117 rootCmd.SetArgs(args) 118 119 err := rootCmd.Execute() 120 if err == nil { 121 t.Fatalf("Command failed with: %s", err) 122 } 123 } 124 125 func TestPipelineGet_fail(t *testing.T) { 126 ts := testGateFail() 127 defer ts.Close() 128 129 rootCmd, rootOpts := cmd.NewCmdRoot(ioutil.Discard, ioutil.Discard) 130 rootCmd.AddCommand(NewPipelineTemplateCmd(rootOpts)) 131 132 args := []string{"pipeline-template", "get", "--id", "newSpelTemplate", "--gate-endpoint", ts.URL} 133 rootCmd.SetArgs(args) 134 135 err := rootCmd.Execute() 136 if err == nil { 137 t.Fatalf("Command failed with: %s", err) 138 } 139 } 140 141 func TestPipelineGet_notfound(t *testing.T) { 142 ts := testGatePipelineTemplateGetMissing() 143 defer ts.Close() 144 145 rootCmd, rootOpts := cmd.NewCmdRoot(ioutil.Discard, ioutil.Discard) 146 rootCmd.AddCommand(NewPipelineTemplateCmd(rootOpts)) 147 148 args := []string{"pipeline-template", "get", "--application", "app", "--name", "two", "--gate-endpoint", ts.URL} 149 rootCmd.SetArgs(args) 150 151 err := rootCmd.Execute() 152 if err == nil { 153 t.Fatalf("Command failed with: %s", err) 154 } 155 } 156 157 // testGatePipelineGetSuccess spins up a local http server that we will configure the GateClient 158 // to direct requests to. Responds with a 200 and a well-formed pipeline get response. 159 func testGatePipelineTemplateGetSuccess() *httptest.Server { 160 mux := util.TestGateMuxWithVersionHandler() 161 mux.Handle("/v2/pipelineTemplates/", http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { 162 w.Header().Add("content-type", "application/json") 163 fmt.Fprintln(w, strings.TrimSpace(pipelineTemplateGetJson)) 164 })) 165 return httptest.NewServer(mux) 166 } 167 168 // testGatePipelineGetMissing returns a 404 Not Found for an errant pipeline name|application pair. 169 func testGatePipelineTemplateGetMissing() *httptest.Server { 170 mux := util.TestGateMuxWithVersionHandler() 171 mux.Handle("/v2/pipelineTemplates/", http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { 172 http.NotFound(w, r) 173 })) 174 return httptest.NewServer(mux) 175 } 176 177 // testGateFail spins up a local http server that we will configure the GateClient 178 // to direct requests to. Responds with a 500 InternalServerError. 179 func testGateFail() *httptest.Server { 180 return httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { 181 // TODO(jacobkiefer): Mock more robust errors once implemented upstream. 182 http.Error(w, "Internal Server Error", http.StatusInternalServerError) 183 })) 184 } 185 186 const pipelineTemplateGetJson = ` 187 { 188 "id": "newSpelTemplate", 189 "lastModifiedBy": "anonymous", 190 "metadata": { 191 "description": "A generic application bake and tag pipeline.", 192 "name": "Default Bake and Tag", 193 "owner": "example@example.com", 194 "scopes": [ 195 "global" 196 ] 197 }, 198 "pipeline": { 199 "description": "", 200 "keepWaitingPipelines": false, 201 "lastModifiedBy": "anonymous", 202 "limitConcurrent": true, 203 "notifications": [], 204 "parameterConfig": [], 205 "stages": [ 206 { 207 "name": "My Wait Stage", 208 "refId": "wait1", 209 "requisiteStageRefIds": [], 210 "type": "wait", 211 "waitTime": "${ templateVariables.waitTime }" 212 } 213 ], 214 "triggers": [ 215 { 216 "attributeConstraints": {}, 217 "enabled": true, 218 "payloadConstraints": {}, 219 "pubsubSystem": "google", 220 "source": "jtk54", 221 "subscription": "super-pub", 222 "subscriptionName": "super-pub", 223 "type": "pubsub" 224 } 225 ], 226 "updateTs": "1543509523663" 227 }, 228 "protect": false, 229 "schema": "v2", 230 "updateTs": "1543860678988", 231 "variables": [ 232 { 233 "defaultValue": 42, 234 "description": "The time a wait stage shall pauseth", 235 "name": "waitTime", 236 "type": "int" 237 } 238 ] 239 } 240 ` 241 242 const pipelineTemplateGetYaml = ` 243 id: newSpelTemplate 244 lastModifiedBy: anonymous 245 metadata: 246 description: A generic application bake and tag pipeline. 247 name: Default Bake and Tag 248 owner: example@example.com 249 scopes: 250 - global 251 pipeline: 252 description: "" 253 keepWaitingPipelines: false 254 lastModifiedBy: anonymous 255 limitConcurrent: true 256 notifications: [] 257 parameterConfig: [] 258 stages: 259 - name: My Wait Stage 260 refId: wait1 261 requisiteStageRefIds: [] 262 type: wait 263 waitTime: ${ templateVariables.waitTime } 264 triggers: 265 - attributeConstraints: {} 266 enabled: true 267 payloadConstraints: {} 268 pubsubSystem: google 269 source: jtk54 270 subscription: super-pub 271 subscriptionName: super-pub 272 type: pubsub 273 updateTs: "1543509523663" 274 protect: false 275 schema: v2 276 updateTs: "1543860678988" 277 variables: 278 - defaultValue: 42 279 description: The time a wait stage shall pauseth 280 name: waitTime 281 type: int 282 `