github.com/spinnaker/spin@v1.30.0/cmd/application/save_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 // limitations under the License. 14 15 package application 16 17 import ( 18 "bytes" 19 "fmt" 20 "io" 21 "io/ioutil" 22 "net/http" 23 "net/http/httptest" 24 "os" 25 "strings" 26 "testing" 27 28 "github.com/spinnaker/spin/cmd" 29 "github.com/spinnaker/spin/util" 30 ) 31 32 const ( 33 NAME = "app" 34 EMAIL = "appowner@spinnaker-test.net" 35 ) 36 37 func TestApplicationSave_basic(t *testing.T) { 38 saveBuffer := new(bytes.Buffer) 39 ts := testGateAppSaveSuccess(saveBuffer) 40 defer ts.Close() 41 42 rootCmd, options := cmd.NewCmdRoot(ioutil.Discard, ioutil.Discard) 43 rootCmd.AddCommand(NewApplicationCmd(options)) 44 45 args := []string{ 46 "application", "save", 47 "--gate-endpoint=" + ts.URL, 48 "--application-name", NAME, 49 "--owner-email", EMAIL, 50 "--cloud-providers", "gce,kubernetes", 51 } 52 rootCmd.SetArgs(args) 53 err := rootCmd.Execute() 54 if err != nil { 55 t.Fatalf("Command failed with: %s", err) 56 } 57 58 expected := strings.TrimSpace(testAppTaskJsonStr) 59 recieved := saveBuffer.Bytes() 60 util.TestPrettyJsonDiff(t, "save request body", expected, recieved) 61 } 62 63 func TestApplicationSave_fail(t *testing.T) { 64 ts := testGateFail() 65 defer ts.Close() 66 67 rootCmd, options := cmd.NewCmdRoot(ioutil.Discard, ioutil.Discard) 68 rootCmd.AddCommand(NewApplicationCmd(options)) 69 70 args := []string{ 71 "application", "save", 72 "--application-name", NAME, 73 "--owner-email", EMAIL, 74 "--cloud-providers", "gce,kubernetes", 75 "--gate-endpoint=" + ts.URL, 76 } 77 rootCmd.SetArgs(args) 78 err := rootCmd.Execute() 79 if err == nil { 80 t.Fatalf("Command failed with: %s", err) 81 } 82 } 83 84 func TestApplicationSave_flags(t *testing.T) { 85 saveBuffer := new(bytes.Buffer) 86 ts := testGateAppSaveSuccess(saveBuffer) 87 defer ts.Close() 88 89 rootCmd, options := cmd.NewCmdRoot(ioutil.Discard, ioutil.Discard) 90 rootCmd.AddCommand(NewApplicationCmd(options)) 91 92 args := []string{ 93 "application", "save", 94 "--gate-endpoint=" + ts.URL, 95 } 96 rootCmd.SetArgs(args) 97 err := rootCmd.Execute() 98 if err == nil { 99 t.Fatalf("Command failed with: %s", err) 100 } 101 102 expected := "" 103 recieved := strings.TrimSpace(saveBuffer.String()) 104 if expected != recieved { 105 t.Fatalf("Unexpected save request body:\n%s", recieved) 106 } 107 } 108 109 func TestApplicationSave_missingname(t *testing.T) { 110 saveBuffer := new(bytes.Buffer) 111 ts := testGateAppSaveSuccess(saveBuffer) 112 defer ts.Close() 113 114 rootCmd, options := cmd.NewCmdRoot(ioutil.Discard, ioutil.Discard) 115 rootCmd.AddCommand(NewApplicationCmd(options)) 116 117 args := []string{ 118 "application", "save", 119 "--owner-email", EMAIL, 120 "--cloud-providers", "gce,kubernetes", 121 "--gate-endpoint=" + ts.URL, 122 } 123 rootCmd.SetArgs(args) 124 err := rootCmd.Execute() 125 if err == nil { 126 t.Fatalf("Command failed with: %s", err) 127 } 128 129 expected := "" 130 recieved := strings.TrimSpace(saveBuffer.String()) 131 if expected != recieved { 132 t.Fatalf("Unexpected save request body:\n%s", recieved) 133 } 134 } 135 136 func TestApplicationSave_missingemail(t *testing.T) { 137 saveBuffer := new(bytes.Buffer) 138 ts := testGateAppSaveSuccess(saveBuffer) 139 defer ts.Close() 140 141 rootCmd, options := cmd.NewCmdRoot(ioutil.Discard, ioutil.Discard) 142 rootCmd.AddCommand(NewApplicationCmd(options)) 143 144 args := []string{ 145 "application", "save", 146 "--application-name", NAME, 147 "--cloud-providers", "gce,kubernetes", 148 "--gate-endpoint", ts.URL, 149 } 150 rootCmd.SetArgs(args) 151 err := rootCmd.Execute() 152 if err == nil { 153 t.Fatalf("Command failed with: %s", err) 154 } 155 156 expected := "" 157 recieved := strings.TrimSpace(saveBuffer.String()) 158 if expected != recieved { 159 t.Fatalf("Unexpected save request body:\n%s", recieved) 160 } 161 } 162 163 func TestApplicationSave_missingproviders(t *testing.T) { 164 saveBuffer := new(bytes.Buffer) 165 ts := testGateAppSaveSuccess(saveBuffer) 166 defer ts.Close() 167 168 rootCmd, options := cmd.NewCmdRoot(ioutil.Discard, ioutil.Discard) 169 rootCmd.AddCommand(NewApplicationCmd(options)) 170 171 args := []string{ 172 "application", "save", 173 "--application-name", NAME, 174 "--owner-email", EMAIL, 175 "--gate-endpoint", ts.URL, 176 } 177 rootCmd.SetArgs(args) 178 err := rootCmd.Execute() 179 if err == nil { 180 t.Fatalf("Command failed with: %s", err) 181 } 182 183 expected := "" 184 recieved := strings.TrimSpace(saveBuffer.String()) 185 if expected != recieved { 186 t.Fatalf("Unexpected save request body:\n%s", recieved) 187 } 188 } 189 190 func TestApplicationSave_filejson(t *testing.T) { 191 saveBuffer := new(bytes.Buffer) 192 ts := testGateAppSaveSuccess(saveBuffer) 193 defer ts.Close() 194 195 tempFile := tempAppFile(testAppJsonStr) 196 if tempFile == nil { 197 t.Fatal("Could not create temp app file.") 198 } 199 defer os.Remove(tempFile.Name()) 200 201 rootCmd, options := cmd.NewCmdRoot(ioutil.Discard, ioutil.Discard) 202 rootCmd.AddCommand(NewApplicationCmd(options)) 203 204 args := []string{ 205 "application", "save", 206 "--file", tempFile.Name(), 207 "--gate-endpoint", ts.URL, 208 } 209 rootCmd.SetArgs(args) 210 err := rootCmd.Execute() 211 if err != nil { 212 t.Fatalf("Command failed with: %s", err) 213 } 214 215 expected := strings.TrimSpace(testAppTaskJsonStr) 216 recieved := saveBuffer.Bytes() 217 util.TestPrettyJsonDiff(t, "save request body", expected, recieved) 218 } 219 220 func TestApplicationSave_fileyaml(t *testing.T) { 221 saveBuffer := new(bytes.Buffer) 222 ts := testGateAppSaveSuccess(saveBuffer) 223 defer ts.Close() 224 225 tempFile := tempAppFile(testAppYamlStr) 226 if tempFile == nil { 227 t.Fatal("Could not create temp app file.") 228 } 229 defer os.Remove(tempFile.Name()) 230 231 rootCmd, options := cmd.NewCmdRoot(ioutil.Discard, ioutil.Discard) 232 rootCmd.AddCommand(NewApplicationCmd(options)) 233 234 args := []string{ 235 "application", "save", 236 "--file", tempFile.Name(), 237 "--gate-endpoint", ts.URL, 238 } 239 rootCmd.SetArgs(args) 240 err := rootCmd.Execute() 241 if err != nil { 242 t.Fatalf("Command failed with: %s", err) 243 } 244 245 expected := strings.TrimSpace(testAppTaskJsonStr) 246 recieved := saveBuffer.Bytes() 247 util.TestPrettyJsonDiff(t, "save request body", expected, recieved) 248 } 249 250 func TestApplicationSave_stdinjson(t *testing.T) { 251 saveBuffer := new(bytes.Buffer) 252 ts := testGateAppSaveSuccess(saveBuffer) 253 defer ts.Close() 254 255 tempFile := tempAppFile(testAppJsonStr) 256 if tempFile == nil { 257 t.Fatal("Could not create temp app file.") 258 } 259 defer os.Remove(tempFile.Name()) 260 261 // Prepare Stdin for test reading. 262 tempFile.Seek(0, 0) 263 oldStdin := os.Stdin 264 defer func() { os.Stdin = oldStdin }() 265 os.Stdin = tempFile 266 267 rootCmd, options := cmd.NewCmdRoot(ioutil.Discard, ioutil.Discard) 268 rootCmd.AddCommand(NewApplicationCmd(options)) 269 270 args := []string{ 271 "application", "save", 272 "--gate-endpoint", ts.URL, 273 } 274 rootCmd.SetArgs(args) 275 err := rootCmd.Execute() 276 if err != nil { 277 t.Fatalf("Command failed with: %s", err) 278 } 279 280 expected := strings.TrimSpace(testAppTaskJsonStr) 281 recieved := saveBuffer.Bytes() 282 util.TestPrettyJsonDiff(t, "save request body", expected, recieved) 283 } 284 285 func TestApplicationSave_stdinyaml(t *testing.T) { 286 saveBuffer := new(bytes.Buffer) 287 ts := testGateAppSaveSuccess(saveBuffer) 288 defer ts.Close() 289 290 tempFile := tempAppFile(testAppYamlStr) 291 if tempFile == nil { 292 t.Fatal("Could not create temp app file.") 293 } 294 defer os.Remove(tempFile.Name()) 295 296 // Prepare Stdin for test reading. 297 tempFile.Seek(0, 0) 298 oldStdin := os.Stdin 299 defer func() { os.Stdin = oldStdin }() 300 os.Stdin = tempFile 301 302 rootCmd, options := cmd.NewCmdRoot(ioutil.Discard, ioutil.Discard) 303 rootCmd.AddCommand(NewApplicationCmd(options)) 304 305 args := []string{ 306 "application", "save", 307 "--gate-endpoint", ts.URL, 308 } 309 rootCmd.SetArgs(args) 310 err := rootCmd.Execute() 311 if err != nil { 312 t.Fatalf("Command failed with: %s", err) 313 } 314 315 expected := strings.TrimSpace(testAppTaskJsonStr) 316 recieved := saveBuffer.Bytes() 317 util.TestPrettyJsonDiff(t, "save request body", expected, recieved) 318 } 319 320 // testGateFail spins up a local http server that we will configure the GateClient 321 // to direct requests to. Responds with a 500 InternalServerError. 322 func testGateFail() *httptest.Server { 323 return httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { 324 // TODO(jacobkiefer): Mock more robust errors once implemented upstream. 325 http.Error(w, "Internal Server Error", http.StatusInternalServerError) 326 })) 327 } 328 329 // testGateAppSaveSuccess spins up a local http server that we will configure the GateClient 330 // to direct requests to. Responds with successful responses to pipeline execute API calls. 331 // Writes request body to buffer for testing. 332 func testGateAppSaveSuccess(buffer io.Writer) *httptest.Server { 333 mux := util.TestGateMuxWithVersionHandler() 334 mux.Handle( 335 "/tasks", 336 util.NewTestBufferHandlerFunc(http.MethodPost, buffer, http.StatusOK, strings.TrimSpace(testAppTaskRefJsonStr)), 337 ) 338 mux.Handle("/tasks/id", http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { 339 w.Header().Add("content-type", "application/json") 340 fmt.Fprintln(w, strings.TrimSpace(testAppTaskStatusJsonStr)) 341 })) 342 return httptest.NewServer(mux) 343 } 344 345 func tempAppFile(appContent string) *os.File { 346 tempFile, _ := ioutil.TempFile("" /* /tmp dir. */, "app-spec") 347 bytes, err := tempFile.Write([]byte(appContent)) 348 if err != nil || bytes == 0 { 349 fmt.Println("Could not write temp file.") 350 return nil 351 } 352 return tempFile 353 } 354 355 const testAppTaskRefJsonStr = ` 356 { 357 "ref": "/tasks/id" 358 } 359 ` 360 361 const testAppTaskStatusJsonStr = ` 362 { 363 "status": "SUCCEEDED" 364 } 365 ` 366 367 const testAppJsonStr = ` 368 { 369 "email" : "appowner@spinnaker-test.net", 370 "cloudProviders" : "gce,kubernetes", 371 "name" : "app", 372 "instancePort": 80 373 } 374 ` 375 376 const testAppYamlStr = ` 377 email: appowner@spinnaker-test.net 378 cloudProviders: gce,kubernetes 379 name: app 380 instancePort: 80 381 ` 382 383 const testAppTaskJsonStr = ` 384 { 385 "application": "app", 386 "description": "Create Application: app", 387 "job": [ 388 { 389 "application": { 390 "cloudProviders": "gce,kubernetes", 391 "email": "appowner@spinnaker-test.net", 392 "instancePort": 80, 393 "name": "app" 394 }, 395 "type": "createApplication" 396 } 397 ] 398 } 399 `