github.com/chenbh/concourse/v6@v6.4.2/fly/integration/execute_with_outputs_test.go (about) 1 package integration_test 2 3 import ( 4 "archive/tar" 5 "compress/gzip" 6 "encoding/json" 7 "fmt" 8 "io/ioutil" 9 "net/http" 10 "os" 11 "os/exec" 12 "path/filepath" 13 "time" 14 15 "github.com/chenbh/concourse/v6/atc" 16 "github.com/chenbh/concourse/v6/atc/event" 17 . "github.com/onsi/ginkgo" 18 . "github.com/onsi/gomega" 19 "github.com/onsi/gomega/gbytes" 20 "github.com/onsi/gomega/gexec" 21 "github.com/onsi/gomega/ghttp" 22 "github.com/vito/go-sse/sse" 23 ) 24 25 var _ = Describe("Fly CLI", func() { 26 var tmpdir string 27 var buildDir string 28 var taskConfigPath string 29 30 var streaming chan struct{} 31 var events chan atc.Event 32 var outputDir string 33 34 var expectedPlan atc.Plan 35 var workerArtifact = atc.WorkerArtifact{ 36 ID: 125, 37 Name: "some-dir", 38 } 39 40 BeforeEach(func() { 41 var err error 42 tmpdir, err = ioutil.TempDir("", "fly-build-dir") 43 Expect(err).NotTo(HaveOccurred()) 44 45 outputDir, err = ioutil.TempDir("", "fly-task-output") 46 Expect(err).NotTo(HaveOccurred()) 47 48 buildDir = filepath.Join(tmpdir, "fixture") 49 50 err = os.Mkdir(buildDir, 0755) 51 Expect(err).NotTo(HaveOccurred()) 52 53 taskConfigPath = filepath.Join(buildDir, "task.yml") 54 55 err = ioutil.WriteFile( 56 taskConfigPath, 57 []byte(`--- 58 platform: some-platform 59 60 image_resource: 61 type: registry-image 62 source: 63 repository: ubuntu 64 65 inputs: 66 - name: fixture 67 68 outputs: 69 - name: some-dir 70 71 params: 72 FOO: bar 73 BAZ: buzz 74 X: 1 75 76 run: 77 path: /bin/sh 78 args: 79 - -c 80 - echo some-content > some-dir/a-file 81 82 `), 83 0644, 84 ) 85 Expect(err).NotTo(HaveOccurred()) 86 87 streaming = make(chan struct{}) 88 events = make(chan atc.Event) 89 90 planFactory := atc.NewPlanFactory(0) 91 92 expectedPlan = planFactory.NewPlan(atc.EnsurePlan{ 93 Step: planFactory.NewPlan(atc.DoPlan{ 94 planFactory.NewPlan(atc.AggregatePlan{ 95 planFactory.NewPlan(atc.ArtifactInputPlan{ 96 Name: filepath.Base(buildDir), 97 ArtifactID: 125, 98 }), 99 }), 100 planFactory.NewPlan(atc.TaskPlan{ 101 Name: "one-off", 102 Config: &atc.TaskConfig{ 103 Platform: "some-platform", 104 ImageResource: &atc.ImageResource{ 105 Type: "registry-image", 106 Source: atc.Source{ 107 "repository": "ubuntu", 108 }, 109 }, 110 Inputs: []atc.TaskInputConfig{ 111 {Name: "fixture"}, 112 }, 113 Outputs: []atc.TaskOutputConfig{ 114 {Name: "some-dir"}, 115 }, 116 Params: map[string]string{ 117 "FOO": "bar", 118 "BAZ": "buzz", 119 "X": "1", 120 }, 121 Run: atc.TaskRunConfig{ 122 Path: "/bin/sh", 123 Args: []string{"-c", "echo some-content > some-dir/a-file"}, 124 }, 125 }, 126 }), 127 }), 128 Next: planFactory.NewPlan(atc.AggregatePlan{ 129 planFactory.NewPlan(atc.ArtifactOutputPlan{ 130 Name: "some-dir", 131 }), 132 }), 133 }) 134 }) 135 136 AfterEach(func() { 137 err := os.RemoveAll(tmpdir) 138 Expect(err).NotTo(HaveOccurred()) 139 140 err = os.RemoveAll(outputDir) 141 Expect(err).NotTo(HaveOccurred()) 142 }) 143 144 JustBeforeEach(func() { 145 atcServer.RouteToHandler("POST", "/api/v1/teams/main/artifacts", 146 ghttp.CombineHandlers( 147 func(w http.ResponseWriter, req *http.Request) { 148 Expect(req.FormValue("platform")).To(Equal("some-platform")) 149 150 gr, err := gzip.NewReader(req.Body) 151 Expect(err).NotTo(HaveOccurred()) 152 153 tr := tar.NewReader(gr) 154 155 hdr, err := tr.Next() 156 Expect(err).NotTo(HaveOccurred()) 157 158 Expect(hdr.Name).To(Equal("./")) 159 160 hdr, err = tr.Next() 161 Expect(err).NotTo(HaveOccurred()) 162 163 Expect(hdr.Name).To(MatchRegexp("(./)?task.yml$")) 164 }, 165 ghttp.RespondWithJSONEncoded(201, workerArtifact), 166 ), 167 ) 168 atcServer.RouteToHandler("POST", "/api/v1/teams/main/builds", 169 ghttp.CombineHandlers( 170 ghttp.VerifyRequest("POST", "/api/v1/teams/main/builds"), 171 VerifyPlan(expectedPlan), 172 func(w http.ResponseWriter, r *http.Request) { 173 http.SetCookie(w, &http.Cookie{ 174 Name: "Some-Cookie", 175 Value: "some-cookie-data", 176 Path: "/", 177 Expires: time.Now().Add(1 * time.Minute), 178 }) 179 }, 180 ghttp.RespondWith(201, `{"id":128}`), 181 ), 182 ) 183 atcServer.RouteToHandler("GET", "/api/v1/builds/128/events", 184 ghttp.CombineHandlers( 185 ghttp.VerifyRequest("GET", "/api/v1/builds/128/events"), 186 func(w http.ResponseWriter, r *http.Request) { 187 flusher := w.(http.Flusher) 188 189 w.Header().Add("Content-Type", "text/event-stream; charset=utf-8") 190 w.Header().Add("Cache-Control", "no-cache, no-store, must-revalidate") 191 w.Header().Add("Connection", "keep-alive") 192 193 w.WriteHeader(http.StatusOK) 194 195 flusher.Flush() 196 197 close(streaming) 198 199 id := 0 200 201 for e := range events { 202 payload, err := json.Marshal(event.Message{Event: e}) 203 Expect(err).NotTo(HaveOccurred()) 204 205 event := sse.Event{ 206 ID: fmt.Sprintf("%d", id), 207 Name: "event", 208 Data: payload, 209 } 210 211 err = event.Write(w) 212 Expect(err).NotTo(HaveOccurred()) 213 214 flusher.Flush() 215 216 id++ 217 } 218 219 err := sse.Event{ 220 Name: "end", 221 }.Write(w) 222 Expect(err).NotTo(HaveOccurred()) 223 }, 224 ), 225 ) 226 atcServer.RouteToHandler("GET", "/api/v1/builds/128/artifacts", 227 ghttp.RespondWithJSONEncoded(200, []atc.WorkerArtifact{workerArtifact}), 228 ) 229 230 atcServer.RouteToHandler("GET", "/api/v1/teams/main/artifacts/125", tarHandler) 231 }) 232 233 Context("when running with --output", func() { 234 Context("when the task specifies those outputs", func() { 235 It("downloads the tasks output to the directory provided", func() { 236 flyCmd := exec.Command(flyPath, "-t", targetName, "e", "-c", taskConfigPath, "--output", "some-dir="+outputDir) 237 flyCmd.Dir = buildDir 238 239 sess, err := gexec.Start(flyCmd, GinkgoWriter, GinkgoWriter) 240 Expect(err).NotTo(HaveOccurred()) 241 242 // sync with after create 243 Eventually(streaming).Should(BeClosed()) 244 245 close(events) 246 247 <-sess.Exited 248 Expect(sess.ExitCode()).To(Equal(0)) 249 250 outputFiles, err := ioutil.ReadDir(outputDir) 251 Expect(err).NotTo(HaveOccurred()) 252 253 Expect(outputFiles).To(HaveLen(1)) 254 Expect(outputFiles[0].Name()).To(Equal("some-file")) 255 256 data, err := ioutil.ReadFile(filepath.Join(outputDir, outputFiles[0].Name())) 257 Expect(err).NotTo(HaveOccurred()) 258 Expect(data).To(Equal([]byte("tar-contents"))) 259 }) 260 }) 261 262 Context("when the task does not specify those outputs", func() { 263 It("exits 1", func() { 264 flyCmd := exec.Command(flyPath, "-t", targetName, "e", "-c", taskConfigPath, "-o", "wrong-output=wrong-path") 265 flyCmd.Dir = buildDir 266 267 sess, err := gexec.Start(flyCmd, GinkgoWriter, GinkgoWriter) 268 Expect(err).NotTo(HaveOccurred()) 269 270 Eventually(sess.Err).Should(gbytes.Say("error: unknown output 'wrong-output'")) 271 272 <-sess.Exited 273 Expect(sess.ExitCode()).To(Equal(1)) 274 }) 275 }) 276 }) 277 }) 278 279 func tarHandler(w http.ResponseWriter, req *http.Request) { 280 gw := gzip.NewWriter(w) 281 tw := tar.NewWriter(gw) 282 283 tarContents := []byte("tar-contents") 284 285 err := tw.WriteHeader(&tar.Header{ 286 Name: "some-file", 287 Mode: 0644, 288 Size: int64(len(tarContents)), 289 }) 290 Expect(err).NotTo(HaveOccurred()) 291 292 _, err = tw.Write(tarContents) 293 Expect(err).NotTo(HaveOccurred()) 294 295 err = tw.Close() 296 Expect(err).NotTo(HaveOccurred()) 297 298 err = gw.Close() 299 Expect(err).NotTo(HaveOccurred()) 300 }