github.com/spinnaker/spin@v1.30.0/cmd/pipeline-template/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 pipeline_template 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 func TestPipelineTemplateSave_createjson(t *testing.T) { 33 saveBuffer := new(bytes.Buffer) 34 ts := testGatePipelineTemplateCreateSuccess(saveBuffer) 35 defer ts.Close() 36 37 tempFile := tempPipelineTemplateFile(testPipelineTemplateJsonStr) 38 if tempFile == nil { 39 t.Fatal("Could not create temp pipeline template file.") 40 } 41 defer os.Remove(tempFile.Name()) 42 43 rootCmd, rootOpts := cmd.NewCmdRoot(ioutil.Discard, ioutil.Discard) 44 rootCmd.AddCommand(NewPipelineTemplateCmd(rootOpts)) 45 46 args := []string{"pipeline-template", "save", "--file", tempFile.Name(), "--gate-endpoint", ts.URL} 47 rootCmd.SetArgs(args) 48 err := rootCmd.Execute() 49 if err != nil { 50 t.Fatalf("Command failed with: %s", err) 51 } 52 53 expected := strings.TrimSpace(testPipelineTemplateJsonStr) 54 recieved := saveBuffer.Bytes() 55 util.TestPrettyJsonDiff(t, "save request body", expected, recieved) 56 } 57 58 func TestPipelineTemplateSave_createyaml(t *testing.T) { 59 saveBuffer := new(bytes.Buffer) 60 ts := testGatePipelineTemplateCreateSuccess(saveBuffer) 61 defer ts.Close() 62 63 tempFile := tempPipelineTemplateFile(testPipelineTemplateYamlStr) 64 if tempFile == nil { 65 t.Fatal("Could not create temp pipeline template file.") 66 } 67 defer os.Remove(tempFile.Name()) 68 69 rootCmd, rootOpts := cmd.NewCmdRoot(ioutil.Discard, ioutil.Discard) 70 rootCmd.AddCommand(NewPipelineTemplateCmd(rootOpts)) 71 72 args := []string{"pipeline-template", "save", "--file", tempFile.Name(), "--gate-endpoint", ts.URL} 73 rootCmd.SetArgs(args) 74 err := rootCmd.Execute() 75 if err != nil { 76 t.Fatalf("Command failed with: %s", err) 77 } 78 79 expected := strings.TrimSpace(testPipelineTemplateJsonStr) 80 recieved := saveBuffer.Bytes() 81 util.TestPrettyJsonDiff(t, "save request body", expected, recieved) 82 } 83 84 func TestPipelineTemplateSave_createtag(t *testing.T) { 85 saveBuffer := new(bytes.Buffer) 86 ts := testGatePipelineTemplateCreateSuccess(saveBuffer) 87 defer ts.Close() 88 89 tempFile := tempPipelineTemplateFile(testPipelineTemplateJsonStr) 90 if tempFile == nil { 91 t.Fatal("Could not create temp pipeline template file.") 92 } 93 defer os.Remove(tempFile.Name()) 94 95 rootCmd, rootOpts := cmd.NewCmdRoot(ioutil.Discard, ioutil.Discard) 96 rootCmd.AddCommand(NewPipelineTemplateCmd(rootOpts)) 97 98 args := []string{"pipeline-template", "save", "--file", tempFile.Name(), "--tag", "stable", "--gate-endpoint", ts.URL} 99 rootCmd.SetArgs(args) 100 err := rootCmd.Execute() 101 if err != nil { 102 t.Fatalf("Command failed with: %s", err) 103 } 104 105 expected := strings.TrimSpace(testPipelineTemplateJsonStr) 106 recieved := saveBuffer.Bytes() 107 util.TestPrettyJsonDiff(t, "save request body", expected, recieved) 108 } 109 110 func TestPipelineTemplateSave_update(t *testing.T) { 111 saveBuffer := new(bytes.Buffer) 112 ts := testGatePipelineTemplateUpdateSuccess(saveBuffer) 113 defer ts.Close() 114 115 tempFile := tempPipelineTemplateFile(testPipelineTemplateJsonStr) 116 if tempFile == nil { 117 t.Fatal("Could not create temp pipeline template file.") 118 } 119 defer os.Remove(tempFile.Name()) 120 121 rootCmd, rootOpts := cmd.NewCmdRoot(ioutil.Discard, ioutil.Discard) 122 rootCmd.AddCommand(NewPipelineTemplateCmd(rootOpts)) 123 124 args := []string{"pipeline-template", "save", "--file", tempFile.Name(), "--gate-endpoint", ts.URL} 125 rootCmd.SetArgs(args) 126 err := rootCmd.Execute() 127 if err != nil { 128 t.Fatalf("Command failed with: %s", err) 129 } 130 131 expected := strings.TrimSpace(testPipelineTemplateJsonStr) 132 recieved := saveBuffer.Bytes() 133 util.TestPrettyJsonDiff(t, "save request body", expected, recieved) 134 } 135 136 func TestPipelineTemplateSave_updatetagfromfile(t *testing.T) { 137 saveBuffer := new(bytes.Buffer) 138 method := new(string) 139 ts := testGatePipelineTemplateUpdateTagSuccess(saveBuffer, method, "stable") 140 defer ts.Close() 141 142 tempFile := tempPipelineTemplateFile(testPipelineTemplateWithTagJsonStr) 143 if tempFile == nil { 144 t.Fatal("Could not create temp pipeline template file.") 145 } 146 defer os.Remove(tempFile.Name()) 147 148 rootCmd, rootOpts := cmd.NewCmdRoot(ioutil.Discard, ioutil.Discard) 149 rootCmd.AddCommand(NewPipelineTemplateCmd(rootOpts)) 150 151 args := []string{"pipeline-template", "save", "--file", tempFile.Name(), "--gate-endpoint", ts.URL} 152 rootCmd.SetArgs(args) 153 err := rootCmd.Execute() 154 if err != nil { 155 t.Fatalf("Command failed with: %s", err) 156 } 157 158 expected := strings.TrimSpace(testPipelineTemplateWithTagJsonStr) 159 recieved := saveBuffer.Bytes() 160 util.TestPrettyJsonDiff(t, "save request body", expected, recieved) 161 162 // Verify that the commad used the tag from the file 163 if *method != "update" { 164 t.Fatalf("Expected 'update' request, got %s", *method) 165 } 166 } 167 168 func TestPipelineTemplateSave_taginargumentsandfile(t *testing.T) { 169 saveBuffer := new(bytes.Buffer) 170 method := new(string) 171 ts := testGatePipelineTemplateUpdateTagSuccess(saveBuffer, method, "test") 172 defer ts.Close() 173 174 tempFile := tempPipelineTemplateFile(testPipelineTemplateWithTagJsonStr) 175 if tempFile == nil { 176 t.Fatal("Could not create temp pipeline template file.") 177 } 178 defer os.Remove(tempFile.Name()) 179 180 rootCmd, rootOpts := cmd.NewCmdRoot(ioutil.Discard, ioutil.Discard) 181 rootCmd.AddCommand(NewPipelineTemplateCmd(rootOpts)) 182 183 args := []string{"pipeline-template", "save", "--file", tempFile.Name(), "--tag", "test", "--gate-endpoint", ts.URL} 184 rootCmd.SetArgs(args) 185 err := rootCmd.Execute() 186 if err != nil { 187 t.Fatalf("Command failed with: %s", err) 188 } 189 190 expected := strings.TrimSpace(testPipelineTemplateWithTagJsonStr) 191 recieved := saveBuffer.Bytes() 192 util.TestPrettyJsonDiff(t, "save request body", expected, recieved) 193 194 // Tag in arguments should take precedence over tag in file 195 if *method != "update" { 196 t.Fatalf("Expected 'update' request, got %s", *method) 197 } 198 } 199 200 func TestPipelineTemplateSave_updatetag(t *testing.T) { 201 saveBuffer := new(bytes.Buffer) 202 ts := testGatePipelineTemplateUpdateSuccess(saveBuffer) 203 defer ts.Close() 204 205 tempFile := tempPipelineTemplateFile(testPipelineTemplateJsonStr) 206 if tempFile == nil { 207 t.Fatal("Could not create temp pipeline template file.") 208 } 209 defer os.Remove(tempFile.Name()) 210 211 rootCmd, rootOpts := cmd.NewCmdRoot(ioutil.Discard, ioutil.Discard) 212 rootCmd.AddCommand(NewPipelineTemplateCmd(rootOpts)) 213 214 args := []string{"pipeline-template", "save", "--file", tempFile.Name(), "--tag", "stable", "--gate-endpoint", ts.URL} 215 rootCmd.SetArgs(args) 216 err := rootCmd.Execute() 217 if err != nil { 218 t.Fatalf("Command failed with: %s", err) 219 } 220 221 expected := strings.TrimSpace(testPipelineTemplateJsonStr) 222 recieved := saveBuffer.Bytes() 223 util.TestPrettyJsonDiff(t, "save request body", expected, recieved) 224 } 225 226 func TestPipelineTemplateSave_stdin(t *testing.T) { 227 saveBuffer := new(bytes.Buffer) 228 ts := testGatePipelineTemplateUpdateSuccess(saveBuffer) 229 defer ts.Close() 230 231 tempFile := tempPipelineTemplateFile(testPipelineTemplateJsonStr) 232 if tempFile == nil { 233 t.Fatal("Could not create temp pipeline template file.") 234 } 235 defer os.Remove(tempFile.Name()) 236 237 // Prepare Stdin for test reading. 238 tempFile.Seek(0, 0) 239 oldStdin := os.Stdin 240 defer func() { os.Stdin = oldStdin }() 241 os.Stdin = tempFile 242 243 rootCmd, rootOpts := cmd.NewCmdRoot(ioutil.Discard, ioutil.Discard) 244 rootCmd.AddCommand(NewPipelineTemplateCmd(rootOpts)) 245 246 args := []string{"pipeline-template", "save", "--gate-endpoint", ts.URL} 247 rootCmd.SetArgs(args) 248 err := rootCmd.Execute() 249 if err != nil { 250 t.Fatalf("Command failed with: %s", err) 251 } 252 253 expected := strings.TrimSpace(testPipelineTemplateJsonStr) 254 recieved := saveBuffer.Bytes() 255 util.TestPrettyJsonDiff(t, "save request body", expected, recieved) 256 } 257 258 func TestPipelineTemplateSave_fail(t *testing.T) { 259 ts := testGateFail() 260 defer ts.Close() 261 262 tempFile := tempPipelineTemplateFile(testPipelineTemplateJsonStr) 263 if tempFile == nil { 264 t.Fatal("Could not create temp pipeline template file.") 265 } 266 defer os.Remove(tempFile.Name()) 267 268 rootCmd, rootOpts := cmd.NewCmdRoot(ioutil.Discard, ioutil.Discard) 269 rootCmd.AddCommand(NewPipelineTemplateCmd(rootOpts)) 270 271 args := []string{"pipeline-template", "save", "--file", tempFile.Name(), "--gate-endpoint", ts.URL} 272 273 rootCmd.SetArgs(args) 274 err := rootCmd.Execute() 275 if err == nil { 276 t.Fatalf("Command failed with: %s", err) 277 } 278 } 279 280 func TestPipelineTemplateSave_flags(t *testing.T) { 281 saveBuffer := new(bytes.Buffer) 282 ts := testGatePipelineTemplateUpdateSuccess(saveBuffer) 283 defer ts.Close() 284 285 rootCmd, rootOpts := cmd.NewCmdRoot(ioutil.Discard, ioutil.Discard) 286 rootCmd.AddCommand(NewPipelineTemplateCmd(rootOpts)) 287 288 args := []string{"pipeline-template", "save", "--gate-endpoint", ts.URL} // Missing pipeline spec file and stdin. 289 rootCmd.SetArgs(args) 290 err := rootCmd.Execute() 291 if err == nil { 292 t.Fatalf("Command failed with: %s", err) 293 } 294 295 expected := "" 296 recieved := strings.TrimSpace(saveBuffer.String()) 297 if expected != recieved { 298 t.Fatalf("Unexpected save request body:\n%s", recieved) 299 } 300 } 301 302 func TestPipelineTemplateSave_missingid(t *testing.T) { 303 saveBuffer := new(bytes.Buffer) 304 ts := testGatePipelineTemplateUpdateSuccess(saveBuffer) 305 defer ts.Close() 306 307 tempFile := tempPipelineTemplateFile(missingIdJsonStr) 308 if tempFile == nil { 309 t.Fatal("Could not create temp pipeline file.") 310 } 311 defer os.Remove(tempFile.Name()) 312 313 rootCmd, rootOpts := cmd.NewCmdRoot(ioutil.Discard, ioutil.Discard) 314 rootCmd.AddCommand(NewPipelineTemplateCmd(rootOpts)) 315 316 args := []string{"pipeline-template", "save", "--file", tempFile.Name(), "--gate-endpoint", ts.URL} 317 rootCmd.SetArgs(args) 318 err := rootCmd.Execute() 319 if err == nil { 320 t.Fatalf("Command failed with: %s", err) 321 } 322 323 expected := "" 324 recieved := strings.TrimSpace(saveBuffer.String()) 325 if expected != recieved { 326 t.Fatalf("Unexpected save request body:\n%s", recieved) 327 } 328 } 329 330 func TestPipelineTemplateSave_missingschema(t *testing.T) { 331 saveBuffer := new(bytes.Buffer) 332 ts := testGatePipelineTemplateUpdateSuccess(saveBuffer) 333 defer ts.Close() 334 335 tempFile := tempPipelineTemplateFile(missingSchemaJsonStr) 336 if tempFile == nil { 337 t.Fatal("Could not create temp pipeline file.") 338 } 339 defer os.Remove(tempFile.Name()) 340 341 rootCmd, rootOpts := cmd.NewCmdRoot(ioutil.Discard, ioutil.Discard) 342 rootCmd.AddCommand(NewPipelineTemplateCmd(rootOpts)) 343 344 args := []string{"pipeline-template", "save", "--file", tempFile.Name(), "--gate-endpoint", ts.URL} 345 rootCmd.SetArgs(args) 346 err := rootCmd.Execute() 347 if err == nil { 348 t.Fatalf("Command failed with: %s", err) 349 } 350 351 expected := "" 352 recieved := strings.TrimSpace(saveBuffer.String()) 353 if expected != recieved { 354 t.Fatalf("Unexpected save request body:\n%s", recieved) 355 } 356 } 357 358 func tempPipelineTemplateFile(pipelineContent string) *os.File { 359 tempFile, _ := ioutil.TempFile("" /* /tmp dir. */, "pipeline-spec") 360 bytes, err := tempFile.Write([]byte(pipelineContent)) 361 if err != nil || bytes == 0 { 362 fmt.Println("Could not write temp file.") 363 return nil 364 } 365 return tempFile 366 } 367 368 // testGatePipelineTemplateUpdateTagSuccess spins up a local http server that we will configure the GateClient 369 // to direct requests to. 370 // Responds with OK to indicate a pipeline template with an expected tag exists. 371 // Responds with 404 NotFound to indicate a pipeline template with an expected tag doesn't exist. 372 // Accepts POST calls for create and update requests. 373 // Writes used method and request body to buffer for testing. 374 func testGatePipelineTemplateUpdateTagSuccess(buffer io.Writer, method *string, expectedTag string) *httptest.Server { 375 mux := util.TestGateMuxWithVersionHandler() 376 mux.Handle( 377 "/v2/pipelineTemplates/update/testSpelTemplate", 378 http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { 379 *method = "update" 380 util.NewTestBufferHandlerFunc(http.MethodPost, buffer, http.StatusOK, "").ServeHTTP(w, r) 381 }), 382 ) 383 mux.Handle( 384 "/v2/pipelineTemplates/create", 385 http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { 386 *method = "create" 387 util.NewTestBufferHandlerFunc(http.MethodPost, buffer, http.StatusAccepted, "").ServeHTTP(w, r) 388 }), 389 ) 390 // Return that we found an MPT if a tag from the request equals to expectedTag. 391 mux.Handle("/v2/pipelineTemplates/testSpelTemplate", http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { 392 if r.URL.Query().Get("tag") == expectedTag { 393 w.WriteHeader(http.StatusOK) 394 } else { 395 w.WriteHeader(http.StatusNotFound) 396 } 397 })) 398 return httptest.NewServer(mux) 399 } 400 401 // testGatePipelineTemplateUpdateSuccess spins up a local http server that we will configure the GateClient 402 // to direct requests to. Responds with OK to indicate a pipeline template exists, 403 // and Accepts POST calls. 404 // Writes request body to buffer for testing. 405 func testGatePipelineTemplateUpdateSuccess(buffer io.Writer) *httptest.Server { 406 mux := util.TestGateMuxWithVersionHandler() 407 mux.Handle( 408 "/v2/pipelineTemplates/update/testSpelTemplate", 409 util.NewTestBufferHandlerFunc(http.MethodPost, buffer, http.StatusOK, ""), 410 ) 411 // Return that we found an MPT to signal that we should update. 412 mux.Handle("/v2/pipelineTemplates/testSpelTemplate", http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { 413 w.WriteHeader(http.StatusOK) 414 })) 415 return httptest.NewServer(mux) 416 } 417 418 // testGatePipelineTemplateCreateSuccess spins up a local http server that we will configure the GateClient 419 // to direct requests to. Responds with 404 NotFound to indicate a pipeline template doesn't exist, 420 // and Accepts POST calls. 421 // Writes request body to buffer for testing. 422 func testGatePipelineTemplateCreateSuccess(buffer io.Writer) *httptest.Server { 423 mux := util.TestGateMuxWithVersionHandler() 424 mux.Handle( 425 "/v2/pipelineTemplates/create", 426 util.NewTestBufferHandlerFunc(http.MethodPost, buffer, http.StatusAccepted, ""), 427 ) 428 // Return that there are no existing MPTs. 429 mux.Handle("/v2/pipelineTemplates/testSpelTemplate", http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { 430 w.WriteHeader(http.StatusNotFound) 431 })) 432 return httptest.NewServer(mux) 433 } 434 435 const missingSchemaJsonStr = ` 436 { 437 "id": "testSpelTemplate", 438 "lastModifiedBy": "anonymous", 439 "metadata": { 440 "description": "A generic application bake and tag pipeline.", 441 "name": "Default Bake and Tag", 442 "owner": "example@example.com", 443 "scopes": [ 444 "global" 445 ] 446 }, 447 "pipeline": { 448 "description": "", 449 "keepWaitingPipelines": false, 450 "lastModifiedBy": "anonymous", 451 "limitConcurrent": true, 452 "notifications": [], 453 "parameterConfig": [], 454 "stages": [ 455 { 456 "name": "My Wait Stage", 457 "refId": "wait1", 458 "requisiteStageRefIds": [], 459 "type": "wait", 460 "waitTime": "${ templateVariables.waitTime }" 461 } 462 ], 463 "triggers": [ 464 { 465 "attributeConstraints": {}, 466 "enabled": true, 467 "payloadConstraints": {}, 468 "pubsubSystem": "google", 469 "source": "jake", 470 "subscription": "super-why", 471 "subscriptionName": "super-why", 472 "type": "pubsub" 473 } 474 ], 475 "updateTs": "1543509523663" 476 }, 477 "protect": false, 478 "updateTs": "1544475186050", 479 "variables": [ 480 { 481 "defaultValue": 42, 482 "description": "The time a wait stage shall pauseth", 483 "name": "waitTime", 484 "type": "int" 485 } 486 ] 487 } 488 ` 489 490 const missingIdJsonStr = ` 491 { 492 "lastModifiedBy": "anonymous", 493 "metadata": { 494 "description": "A generic application bake and tag pipeline.", 495 "name": "Default Bake and Tag", 496 "owner": "example@example.com", 497 "scopes": [ 498 "global" 499 ] 500 }, 501 "pipeline": { 502 "description": "", 503 "keepWaitingPipelines": false, 504 "lastModifiedBy": "anonymous", 505 "limitConcurrent": true, 506 "notifications": [], 507 "parameterConfig": [], 508 "stages": [ 509 { 510 "name": "My Wait Stage", 511 "refId": "wait1", 512 "requisiteStageRefIds": [], 513 "type": "wait", 514 "waitTime": "${ templateVariables.waitTime }" 515 } 516 ], 517 "triggers": [ 518 { 519 "attributeConstraints": {}, 520 "enabled": true, 521 "payloadConstraints": {}, 522 "pubsubSystem": "google", 523 "source": "jake", 524 "subscription": "super-why", 525 "subscriptionName": "super-why", 526 "type": "pubsub" 527 } 528 ], 529 "updateTs": "1543509523663" 530 }, 531 "protect": false, 532 "schema": "v2", 533 "updateTs": "1544475186050", 534 "variables": [ 535 { 536 "defaultValue": 42, 537 "description": "The time a wait stage shall pauseth", 538 "name": "waitTime", 539 "type": "int" 540 } 541 ] 542 } 543 ` 544 545 const testPipelineTemplateJsonStr = ` 546 { 547 "id": "testSpelTemplate", 548 "lastModifiedBy": "anonymous", 549 "metadata": { 550 "description": "A generic application bake and tag pipeline.", 551 "name": "Default Bake and Tag", 552 "owner": "example@example.com", 553 "scopes": [ 554 "global" 555 ] 556 }, 557 "pipeline": { 558 "description": "", 559 "keepWaitingPipelines": false, 560 "lastModifiedBy": "anonymous", 561 "limitConcurrent": true, 562 "notifications": [], 563 "parameterConfig": [], 564 "stages": [ 565 { 566 "name": "My Wait Stage", 567 "refId": "wait1", 568 "requisiteStageRefIds": [], 569 "type": "wait", 570 "waitTime": "${ templateVariables.waitTime }" 571 } 572 ], 573 "triggers": [ 574 { 575 "attributeConstraints": {}, 576 "enabled": true, 577 "payloadConstraints": {}, 578 "pubsubSystem": "google", 579 "source": "jake", 580 "subscription": "super-why", 581 "subscriptionName": "super-why", 582 "type": "pubsub" 583 } 584 ], 585 "updateTs": "1543509523663" 586 }, 587 "protect": false, 588 "schema": "v2", 589 "updateTs": "1544475186050", 590 "variables": [ 591 { 592 "defaultValue": 42, 593 "description": "The time a wait stage shall pauseth", 594 "name": "waitTime", 595 "type": "int" 596 } 597 ] 598 } 599 ` 600 601 const testPipelineTemplateWithTagJsonStr = ` 602 { 603 "id": "testSpelTemplate", 604 "lastModifiedBy": "anonymous", 605 "metadata": { 606 "description": "A generic application bake and tag pipeline.", 607 "name": "Default Bake and Tag", 608 "owner": "example@example.com", 609 "scopes": [ 610 "global" 611 ] 612 }, 613 "pipeline": { 614 "description": "", 615 "keepWaitingPipelines": false, 616 "lastModifiedBy": "anonymous", 617 "limitConcurrent": true, 618 "notifications": [], 619 "parameterConfig": [], 620 "stages": [ 621 { 622 "name": "My Wait Stage", 623 "refId": "wait1", 624 "requisiteStageRefIds": [], 625 "type": "wait", 626 "waitTime": "${ templateVariables.waitTime }" 627 } 628 ], 629 "triggers": [ 630 { 631 "attributeConstraints": {}, 632 "enabled": true, 633 "payloadConstraints": {}, 634 "pubsubSystem": "google", 635 "source": "jake", 636 "subscription": "super-why", 637 "subscriptionName": "super-why", 638 "type": "pubsub" 639 } 640 ], 641 "updateTs": "1543509523663" 642 }, 643 "protect": false, 644 "schema": "v2", 645 "tag": "stable", 646 "updateTs": "1544475186050", 647 "variables": [ 648 { 649 "defaultValue": 42, 650 "description": "The time a wait stage shall pauseth", 651 "name": "waitTime", 652 "type": "int" 653 } 654 ] 655 } 656 ` 657 658 const testPipelineTemplateYamlStr = ` 659 id: testSpelTemplate 660 lastModifiedBy: anonymous 661 metadata: 662 description: A generic application bake and tag pipeline. 663 name: Default Bake and Tag 664 owner: example@example.com 665 scopes: 666 - global 667 pipeline: 668 description: '' 669 keepWaitingPipelines: false 670 lastModifiedBy: anonymous 671 limitConcurrent: true 672 notifications: [] 673 parameterConfig: [] 674 stages: 675 - name: My Wait Stage 676 refId: wait1 677 requisiteStageRefIds: [] 678 type: wait 679 waitTime: "${ templateVariables.waitTime }" 680 triggers: 681 - attributeConstraints: {} 682 enabled: true 683 payloadConstraints: {} 684 pubsubSystem: google 685 source: jake 686 subscription: super-why 687 subscriptionName: super-why 688 type: pubsub 689 updateTs: '1543509523663' 690 protect: false 691 schema: v2 692 updateTs: '1544475186050' 693 variables: 694 - defaultValue: 42 695 description: The time a wait stage shall pauseth 696 name: waitTime 697 type: int 698 `