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 `