github.com/spinnaker/spin@v1.30.0/cmd/pipeline-template/plan_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  	"fmt"
    19  	"io/ioutil"
    20  	"net/http"
    21  	"net/http/httptest"
    22  	"os"
    23  	"strings"
    24  	"testing"
    25  
    26  	"github.com/spinnaker/spin/cmd"
    27  	"github.com/spinnaker/spin/util"
    28  )
    29  
    30  func TestPipelineTemplatePlan_basic(t *testing.T) {
    31  	ts := testGatePlanSuccess()
    32  	defer ts.Close()
    33  
    34  	tempFile := tempPipelineTemplateFile(testPlanConfig)
    35  	if tempFile == nil {
    36  		t.Fatal("Could not create temp pipeline template file.")
    37  	}
    38  	defer os.Remove(tempFile.Name())
    39  
    40  	rootCmd, rootOpts := cmd.NewCmdRoot(ioutil.Discard, ioutil.Discard)
    41  	rootCmd.AddCommand(NewPipelineTemplateCmd(rootOpts))
    42  
    43  	args := []string{"pipeline-template", "plan", "--file", tempFile.Name(), "--gate-endpoint", ts.URL}
    44  	rootCmd.SetArgs(args)
    45  	err := rootCmd.Execute()
    46  	if err != nil {
    47  		t.Fatalf("Command failed with: %s", err)
    48  	}
    49  }
    50  
    51  func TestPipelineTemplatePlan_stdin(t *testing.T) {
    52  	ts := testGatePlanSuccess()
    53  	defer ts.Close()
    54  
    55  	tempFile := tempPipelineTemplateFile(testPlanConfig)
    56  	if tempFile == nil {
    57  		t.Fatal("Could not create temp pipeline template file.")
    58  	}
    59  	defer os.Remove(tempFile.Name())
    60  
    61  	// Prepare Stdin for test reading.
    62  	tempFile.Seek(0, 0)
    63  	oldStdin := os.Stdin
    64  	defer func() { os.Stdin = oldStdin }()
    65  	os.Stdin = tempFile
    66  
    67  	rootCmd, rootOpts := cmd.NewCmdRoot(ioutil.Discard, ioutil.Discard)
    68  	rootCmd.AddCommand(NewPipelineTemplateCmd(rootOpts))
    69  
    70  	args := []string{"pipeline-template", "plan", "--gate-endpoint", ts.URL}
    71  	rootCmd.SetArgs(args)
    72  	err := rootCmd.Execute()
    73  	if err != nil {
    74  		t.Fatalf("Command failed with: %s", err)
    75  	}
    76  }
    77  
    78  func TestPipelineTemplatePlan_fail(t *testing.T) {
    79  	ts := testGateFail()
    80  	defer ts.Close()
    81  
    82  	tempFile := tempPipelineTemplateFile(testPlanConfig)
    83  	if tempFile == nil {
    84  		t.Fatal("Could not create temp pipeline template file.")
    85  	}
    86  	defer os.Remove(tempFile.Name())
    87  
    88  	rootCmd, rootOpts := cmd.NewCmdRoot(ioutil.Discard, ioutil.Discard)
    89  	rootCmd.AddCommand(NewPipelineTemplateCmd(rootOpts))
    90  
    91  	args := []string{"pipeline-template", "plan", "--file", tempFile.Name(), "--gate-endpoint", ts.URL}
    92  	rootCmd.SetArgs(args)
    93  	err := rootCmd.Execute()
    94  	if err == nil {
    95  		t.Fatalf("Expected failure but command succeeded")
    96  	}
    97  }
    98  
    99  func TestPipelineTemplatePlan_flags(t *testing.T) {
   100  	ts := testGatePlanSuccess()
   101  	defer ts.Close()
   102  
   103  	rootCmd, rootOpts := cmd.NewCmdRoot(ioutil.Discard, ioutil.Discard)
   104  	rootCmd.AddCommand(NewPipelineTemplateCmd(rootOpts))
   105  
   106  	args := []string{"pipeline-template", "plan", "--gate-endpoint", ts.URL} // Missing pipeline config file and stdin.
   107  	rootCmd.SetArgs(args)
   108  	err := rootCmd.Execute()
   109  	if err == nil {
   110  		t.Fatalf("Expected failure but command succeeded")
   111  	}
   112  }
   113  
   114  // testGatePlanSuccess spins up a local http server that we will configure the GateClient
   115  // to direct requests to. Responds with 404 NotFound to indicate a pipeline template doesn't exist,
   116  // and Accepts POST calls.
   117  func testGatePlanSuccess() *httptest.Server {
   118  	mux := util.TestGateMuxWithVersionHandler()
   119  	mux.Handle("/v2/pipelineTemplates/plan", http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
   120  		if r.Method == http.MethodPost {
   121  			fmt.Fprintln(w, strings.TrimSpace(testPipelineTemplatePlanResp))
   122  		} else {
   123  			w.WriteHeader(http.StatusNotFound)
   124  		}
   125  	}))
   126  	return httptest.NewServer(mux)
   127  }
   128  
   129  const testPipelineTemplatePlanResp = `
   130  {
   131     "triggers" : [
   132        {
   133           "source" : "jack",
   134           "enabled" : true,
   135           "type" : "pubsub",
   136           "subscription" : "super-derp",
   137           "subscriptionName" : "super-derp",
   138           "payloadConstraints" : {},
   139           "pubsubSystem" : "google",
   140           "attributeConstraints" : {}
   141        }
   142     ],
   143     "trigger" : {
   144        "artifacts" : [],
   145        "type" : "manual",
   146        "user" : "anonymous",
   147        "parameters" : {}
   148     },
   149     "parameterConfig" : [],
   150     "keepWaitingPipelines" : false,
   151     "description" : "",
   152     "stages" : [
   153        {
   154           "refId" : "wait0",
   155           "notifications" : [],
   156           "waitTime" : 2,
   157           "inject" : {
   158              "last" : false,
   159              "first" : true
   160           },
   161           "type" : "wait",
   162           "requisiteStageRefIds" : []
   163        },
   164        {
   165           "requisiteStageRefIds" : [
   166              "wait0"
   167           ],
   168           "type" : "wait",
   169           "waitTime" : 6,
   170           "refId" : "wait1",
   171           "name" : "My Wait Stage",
   172           "notifications" : []
   173        },
   174        {
   175           "waitTime" : 67,
   176           "refId" : "wait2",
   177           "notifications" : [],
   178           "requisiteStageRefIds" : [
   179              "wait1"
   180           ],
   181           "type" : "wait"
   182        }
   183     ],
   184     "limitConcurrent" : true,
   185     "application" : "waze",
   186     "lastModifiedBy" : "anonymous",
   187     "updateTs" : "1543509523663",
   188     "expectedArtifacts" : [],
   189     "templateVariables" : {
   190        "waitTime" : 6
   191     },
   192     "id" : "unknown",
   193     "name" : "My First SpEL Pipeline",
   194     "notifications" : []
   195  }
   196  `
   197  
   198  const testPlanConfig = `
   199  {
   200      "schema": "v2",
   201      "application": "app",
   202      "name": "My First SpEL Pipeline",
   203      "template": {
   204          "source": "spinnaker://newSpelTemplate"
   205      },
   206      "variables": {
   207          "waitTime": 6
   208      },
   209      "inherit": [],
   210      "triggers": [
   211          {
   212              "type": "pubsub",
   213              "enabled": true,
   214              "pubsubSystem": "google",
   215              "subscription": "super-derp",
   216              "subscriptionName": "super-derp",
   217              "source": "jack",
   218              "attributeConstraints": {},
   219              "payloadConstraints": {},
   220  						"invalid-key": "whatever"
   221          }
   222      ],
   223      "parameters": [],
   224      "notifications": [],
   225      "description": "",
   226      "stages": [
   227          {
   228              "refId": "wait2",
   229              "requisiteStageRefIds": ["wait1"],
   230              "type": "wait",
   231              "waitTime": 67
   232          },
   233          {
   234              "refId": "wait0",
   235              "inject": {
   236                  "first": true
   237              },
   238              "type": "wait",
   239              "waitTime": 2
   240          }
   241      ]
   242  }
   243  `