github.com/cloudfoundry-attic/ltc@v0.0.0-20151123212628-098adc7919fc/droplet_runner/droplet_runner_test.go (about) 1 package droplet_runner_test 2 3 import ( 4 "errors" 5 "fmt" 6 "io" 7 "io/ioutil" 8 "os" 9 "path/filepath" 10 "reflect" 11 "strings" 12 "time" 13 14 . "github.com/onsi/ginkgo" 15 . "github.com/onsi/gomega" 16 17 "github.com/cloudfoundry-incubator/bbs/models" 18 "github.com/cloudfoundry-incubator/ltc/app_examiner" 19 "github.com/cloudfoundry-incubator/ltc/app_examiner/fake_app_examiner" 20 "github.com/cloudfoundry-incubator/ltc/app_runner" 21 "github.com/cloudfoundry-incubator/ltc/app_runner/fake_app_runner" 22 "github.com/cloudfoundry-incubator/ltc/blob_store/blob" 23 "github.com/cloudfoundry-incubator/ltc/config/persister" 24 "github.com/cloudfoundry-incubator/ltc/droplet_runner" 25 "github.com/cloudfoundry-incubator/ltc/droplet_runner/fake_blob_store" 26 "github.com/cloudfoundry-incubator/ltc/droplet_runner/fake_proxyconf_reader" 27 "github.com/cloudfoundry-incubator/ltc/task_runner/fake_task_runner" 28 "github.com/cloudfoundry-incubator/ltc/test_helpers/matchers" 29 30 config_package "github.com/cloudfoundry-incubator/ltc/config" 31 ) 32 33 var _ = Describe("DropletRunner", func() { 34 var ( 35 fakeAppRunner *fake_app_runner.FakeAppRunner 36 fakeTaskRunner *fake_task_runner.FakeTaskRunner 37 config *config_package.Config 38 fakeBlobStore *fake_blob_store.FakeBlobStore 39 fakeAppExaminer *fake_app_examiner.FakeAppExaminer 40 fakeProxyConfReader *fake_proxyconf_reader.FakeProxyConfReader 41 dropletRunner droplet_runner.DropletRunner 42 ) 43 44 BeforeEach(func() { 45 fakeAppRunner = &fake_app_runner.FakeAppRunner{} 46 fakeTaskRunner = &fake_task_runner.FakeTaskRunner{} 47 config = config_package.New(persister.NewMemPersister()) 48 fakeBlobStore = &fake_blob_store.FakeBlobStore{} 49 fakeAppExaminer = &fake_app_examiner.FakeAppExaminer{} 50 fakeProxyConfReader = &fake_proxyconf_reader.FakeProxyConfReader{} 51 dropletRunner = droplet_runner.New(fakeAppRunner, fakeTaskRunner, config, fakeBlobStore, fakeAppExaminer, fakeProxyConfReader) 52 }) 53 54 Describe("ListDroplets", func() { 55 It("returns a list of droplets in the blob store", func() { 56 fakeBlobStore.ListReturns([]blob.Blob{ 57 {Path: "X-bits.zip", Created: time.Unix(1000, 0), Size: 100}, 58 {Path: "X-droplet.tgz", Created: time.Unix(2000, 0), Size: 200}, 59 {Path: "Y-bits.zip"}, 60 {Path: "droplet.tgz"}, 61 }, nil) 62 63 Expect(dropletRunner.ListDroplets()).To(Equal([]droplet_runner.Droplet{ 64 {Name: "X", Created: time.Unix(2000, 0), Size: 200}, 65 })) 66 }) 67 68 It("returns an error when querying the blob store fails", func() { 69 fakeBlobStore.ListReturns(nil, errors.New("some error")) 70 71 _, err := dropletRunner.ListDroplets() 72 Expect(err).To(MatchError("some error")) 73 }) 74 }) 75 76 Describe("UploadBits", func() { 77 Context("when the archive path is a file and exists", func() { 78 var tmpFile *os.File 79 80 BeforeEach(func() { 81 tmpDir := os.TempDir() 82 var err error 83 tmpFile, err = ioutil.TempFile(tmpDir, "tmp_file") 84 Expect(err).NotTo(HaveOccurred()) 85 86 Expect(ioutil.WriteFile(tmpFile.Name(), []byte("some contents"), 0600)).To(Succeed()) 87 }) 88 89 AfterEach(func() { 90 tmpFile.Close() 91 Expect(os.Remove(tmpFile.Name())).To(Succeed()) 92 }) 93 94 It("uploads the file to the bucket", func() { 95 Expect(dropletRunner.UploadBits("droplet-name", tmpFile.Name())).To(Succeed()) 96 97 Expect(fakeBlobStore.UploadCallCount()).To(Equal(1)) 98 path, _ := fakeBlobStore.UploadArgsForCall(0) 99 Expect(path).To(Equal("droplet-name-bits.zip")) 100 }) 101 102 It("returns an error when we fail to open the droplet bits", func() { 103 err := dropletRunner.UploadBits("droplet-name", "some non-existent file") 104 Expect(reflect.TypeOf(err).String()).To(Equal("*os.PathError")) 105 }) 106 107 It("returns an error when the upload fails", func() { 108 fakeBlobStore.UploadReturns(errors.New("some error")) 109 110 err := dropletRunner.UploadBits("droplet-name", tmpFile.Name()) 111 Expect(err).To(MatchError("some error")) 112 }) 113 }) 114 }) 115 116 Describe("BuildDroplet", func() { 117 It("does the build droplet task", func() { 118 config.SetBlobStore("blob-host", "7474", "dav-user", "dav-pass") 119 Expect(config.Save()).To(Succeed()) 120 121 blobURL := fmt.Sprintf("http://%s:%s@%s:%s%s", 122 config.BlobStore().Username, 123 config.BlobStore().Password, 124 config.BlobStore().Host, 125 config.BlobStore().Port, 126 "/blobs/droplet-name") 127 128 fakeBlobStore.DownloadAppBitsActionReturns(models.WrapAction(&models.DownloadAction{ 129 From: blobURL + "-bits.zip", 130 To: "/tmp/app", 131 User: "vcap", 132 })) 133 134 fakeBlobStore.DeleteAppBitsActionReturns(models.WrapAction(&models.RunAction{ 135 Path: "/tmp/davtool", 136 Dir: "/", 137 Args: []string{"delete", blobURL + "-bits.zip"}, 138 User: "vcap", 139 })) 140 141 fakeBlobStore.UploadDropletActionReturns(models.WrapAction(&models.RunAction{ 142 Path: "/tmp/davtool", 143 Dir: "/", 144 Args: []string{"put", blobURL + "-droplet.tgz", "/tmp/droplet"}, 145 User: "vcap", 146 })) 147 err := dropletRunner.BuildDroplet("task-name", "droplet-name", "buildpack", map[string]string{}, 128, 100, 800) 148 Expect(err).NotTo(HaveOccurred()) 149 150 Expect(fakeTaskRunner.CreateTaskCallCount()).To(Equal(1)) 151 createTaskParams := fakeTaskRunner.CreateTaskArgsForCall(0) 152 Expect(createTaskParams).ToNot(BeNil()) 153 receptorRequest := createTaskParams.GetReceptorRequest() 154 155 expectedActions := models.WrapAction(&models.SerialAction{ 156 Actions: []*models.Action{ 157 models.WrapAction(&models.DownloadAction{ 158 From: "http://file-server.service.cf.internal:8080/v1/static/cell-helpers/cell-helpers.tgz", 159 To: "/tmp", 160 User: "vcap", 161 }), 162 models.WrapAction(&models.DownloadAction{ 163 From: "http://file-server.service.cf.internal:8080/v1/static/buildpack_app_lifecycle/buildpack_app_lifecycle.tgz", 164 To: "/tmp", 165 User: "vcap", 166 }), 167 models.WrapAction(&models.DownloadAction{ 168 From: blobURL + "-bits.zip", 169 To: "/tmp/app", 170 User: "vcap", 171 }), 172 models.WrapAction(&models.RunAction{ 173 Path: "/tmp/davtool", 174 Dir: "/", 175 Args: []string{"delete", blobURL + "-bits.zip"}, 176 User: "vcap", 177 }), 178 models.WrapAction(&models.RunAction{ 179 Path: "/bin/chmod", 180 Dir: "/tmp/app", 181 Args: []string{"-R", "a+X", "."}, 182 User: "vcap", 183 }), 184 models.WrapAction(&models.RunAction{ 185 Path: "/tmp/builder", 186 Dir: "/", 187 Args: []string{ 188 "-buildArtifactsCacheDir=/tmp/cache", 189 "-buildDir=/tmp/app", 190 "-buildpackOrder=buildpack", 191 "-buildpacksDir=/tmp/buildpacks", 192 "-outputBuildArtifactsCache=/tmp/output-cache", 193 "-outputDroplet=/tmp/droplet", 194 "-outputMetadata=/tmp/result.json", 195 "-skipCertVerify=false", 196 "-skipDetect=true", 197 }, 198 User: "vcap", 199 }), 200 models.WrapAction(&models.RunAction{ 201 Path: "/tmp/davtool", 202 Dir: "/", 203 Args: []string{"put", blobURL + "-droplet.tgz", "/tmp/droplet"}, 204 User: "vcap", 205 }), 206 }, 207 }) 208 Expect(receptorRequest.Action).To(Equal(expectedActions)) 209 Expect(receptorRequest.TaskGuid).To(Equal("task-name")) 210 Expect(receptorRequest.LogGuid).To(Equal("task-name")) 211 Expect(receptorRequest.MetricsGuid).To(Equal("task-name")) 212 Expect(receptorRequest.RootFS).To(Equal("preloaded:cflinuxfs2")) 213 Expect(receptorRequest.EnvironmentVariables).To(matchers.ContainExactly([]*models.EnvironmentVariable{ 214 {Name: "CF_STACK", Value: "cflinuxfs2"}, 215 {Name: "MEMORY_LIMIT", Value: "128M"}, 216 {Name: "http_proxy", Value: ""}, 217 {Name: "https_proxy", Value: ""}, 218 {Name: "no_proxy", Value: ""}, 219 })) 220 Expect(receptorRequest.LogSource).To(Equal("BUILD")) 221 Expect(receptorRequest.Domain).To(Equal("lattice")) 222 Expect(receptorRequest.Privileged).To(BeTrue()) 223 Expect(receptorRequest.EgressRules).ToNot(BeNil()) 224 Expect(receptorRequest.EgressRules).To(BeEmpty()) 225 Expect(receptorRequest.MemoryMB).To(Equal(128)) 226 }) 227 228 It("passes through user environment variables", func() { 229 config.SetBlobStore("blob-host", "7474", "dav-user", "dav-pass") 230 Expect(config.Save()).To(Succeed()) 231 232 env := map[string]string{ 233 "ENV_VAR": "stuff", 234 "OTHER_VAR": "same", 235 } 236 237 err := dropletRunner.BuildDroplet("task-name", "droplet-name", "buildpack", env, 128, 100, 800) 238 Expect(err).NotTo(HaveOccurred()) 239 240 Expect(fakeTaskRunner.CreateTaskCallCount()).To(Equal(1)) 241 createTaskParams := fakeTaskRunner.CreateTaskArgsForCall(0) 242 Expect(createTaskParams).ToNot(BeNil()) 243 receptorRequest := createTaskParams.GetReceptorRequest() 244 245 Expect(receptorRequest.EnvironmentVariables).To(matchers.ContainExactly([]*models.EnvironmentVariable{ 246 {Name: "CF_STACK", Value: "cflinuxfs2"}, 247 {Name: "MEMORY_LIMIT", Value: "128M"}, 248 {Name: "ENV_VAR", Value: "stuff"}, 249 {Name: "OTHER_VAR", Value: "same"}, 250 {Name: "http_proxy", Value: ""}, 251 {Name: "https_proxy", Value: ""}, 252 {Name: "no_proxy", Value: ""}, 253 })) 254 }) 255 256 It("sets proxy environment variables if a proxyconf exists", func() { 257 config.SetBlobStore("blob-host", "7474", "dav-user", "dav-pass") 258 Expect(config.Save()).To(Succeed()) 259 260 env := map[string]string{} 261 262 fakeProxyConfReader.ProxyConfReturns(droplet_runner.ProxyConf{ 263 HTTPProxy: "http://proxy", 264 HTTPSProxy: "https://proxy", 265 NoProxy: "no-proxy", 266 }, nil) 267 268 err := dropletRunner.BuildDroplet("task-name", "droplet-name", "buildpack", env, 128, 100, 800) 269 Expect(err).NotTo(HaveOccurred()) 270 271 Expect(fakeTaskRunner.CreateTaskCallCount()).To(Equal(1)) 272 createTaskParams := fakeTaskRunner.CreateTaskArgsForCall(0) 273 Expect(createTaskParams).ToNot(BeNil()) 274 receptorRequest := createTaskParams.GetReceptorRequest() 275 276 Expect(receptorRequest.EnvironmentVariables).To(matchers.ContainExactly([]*models.EnvironmentVariable{ 277 {Name: "CF_STACK", Value: "cflinuxfs2"}, 278 {Name: "MEMORY_LIMIT", Value: "128M"}, 279 {Name: "http_proxy", Value: "http://proxy"}, 280 {Name: "https_proxy", Value: "https://proxy"}, 281 {Name: "no_proxy", Value: "no-proxy"}, 282 })) 283 }) 284 285 It("passes through cpuWeight, memoryMB and diskMB", func() { 286 config.SetBlobStore("blob-host", "7474", "dav-user", "dav-pass") 287 Expect(config.Save()).To(Succeed()) 288 289 err := dropletRunner.BuildDroplet("task-name", "droplet-name", "buildpack", map[string]string{}, 1, 2, 3) 290 Expect(err).NotTo(HaveOccurred()) 291 292 Expect(fakeTaskRunner.CreateTaskCallCount()).To(Equal(1)) 293 createTaskParams := fakeTaskRunner.CreateTaskArgsForCall(0) 294 receptorRequest := createTaskParams.GetReceptorRequest() 295 Expect(receptorRequest.MemoryMB).To(Equal(1)) 296 Expect(receptorRequest.CPUWeight).To(Equal(uint(2))) 297 Expect(receptorRequest.DiskMB).To(Equal(3)) 298 }) 299 300 It("returns an error when ProxyConfReader fails", func() { 301 fakeProxyConfReader.ProxyConfReturns(droplet_runner.ProxyConf{}, errors.New("can't proxy")) 302 303 err := dropletRunner.BuildDroplet("task-name", "droplet-name", "buildpack", map[string]string{}, 0, 0, 0) 304 Expect(err).To(MatchError("can't proxy")) 305 306 Expect(fakeTaskRunner.CreateTaskCallCount()).To(Equal(0)) 307 }) 308 309 It("returns an error when create task fails", func() { 310 fakeTaskRunner.CreateTaskReturns(errors.New("creating task failed")) 311 312 err := dropletRunner.BuildDroplet("task-name", "droplet-name", "buildpack", map[string]string{}, 0, 0, 0) 313 Expect(err).To(MatchError("creating task failed")) 314 315 Expect(fakeTaskRunner.CreateTaskCallCount()).To(Equal(1)) 316 }) 317 }) 318 319 Describe("LaunchDroplet", func() { 320 BeforeEach(func() { 321 config.SetBlobStore("blob-host", "7474", "dav-user", "dav-pass") 322 Expect(config.Save()).To(Succeed()) 323 }) 324 325 It("launches the droplet lrp task with a start command from buildpack results", func() { 326 fakeBlobStore.DownloadDropletActionReturns(models.WrapAction(&models.DownloadAction{ 327 From: "http://dav-user:dav-pass@blob-host:7474/blobs/droplet-name-droplet.tgz", 328 To: "/home/vcap", 329 User: "vcap", 330 })) 331 332 err := dropletRunner.LaunchDroplet("app-name", "droplet-name", "", []string{}, app_runner.AppEnvironmentParams{}) 333 Expect(err).NotTo(HaveOccurred()) 334 335 Expect(fakeAppRunner.CreateAppCallCount()).To(Equal(1)) 336 createAppParams := fakeAppRunner.CreateAppArgsForCall(0) 337 Expect(createAppParams.Name).To(Equal("app-name")) 338 Expect(createAppParams.RootFS).To(Equal(droplet_runner.DropletRootFS)) 339 Expect(createAppParams.StartCommand).To(Equal("/tmp/launcher")) 340 Expect(createAppParams.AppArgs).To(Equal([]string{"/home/vcap/app", "", "{}"})) 341 Expect(createAppParams.WorkingDir).To(Equal("/home/vcap")) 342 Expect(createAppParams.AppEnvironmentParams.EnvironmentVariables).To(matchers.ContainExactly(map[string]string{ 343 "PWD": "/home/vcap", 344 "TMPDIR": "/home/vcap/tmp", 345 "http_proxy": "", 346 "https_proxy": "", 347 "no_proxy": "", 348 })) 349 Expect(createAppParams.Annotation).To(MatchJSON(`{ 350 "droplet_source": { 351 "droplet_name": "droplet-name" 352 } 353 }`)) 354 355 Expect(createAppParams.Setup).To(Equal(models.WrapAction(&models.SerialAction{ 356 LogSource: "app-name", 357 Actions: []*models.Action{ 358 models.WrapAction(&models.DownloadAction{ 359 From: "http://file-server.service.cf.internal:8080/v1/static/cell-helpers/cell-helpers.tgz", 360 To: "/tmp", 361 User: "vcap", 362 }), 363 models.WrapAction(&models.DownloadAction{ 364 From: "http://dav-user:dav-pass@blob-host:7474/blobs/droplet-name-droplet.tgz", 365 To: "/home/vcap", 366 User: "vcap", 367 }), 368 }, 369 }))) 370 }) 371 372 It("launches the droplet lrp task with proxy environment variables", func() { 373 fakeBlobStore.DownloadReturns(ioutil.NopCloser(strings.NewReader("{}")), nil) 374 fakeBlobStore.DownloadDropletActionReturns(models.WrapAction(&models.DownloadAction{})) 375 376 fakeProxyConfReader.ProxyConfReturns(droplet_runner.ProxyConf{ 377 HTTPProxy: "http://proxy", 378 HTTPSProxy: "https://proxy", 379 NoProxy: "no-proxy", 380 }, nil) 381 382 err := dropletRunner.LaunchDroplet("app-name", "droplet-name", "", []string{}, app_runner.AppEnvironmentParams{}) 383 Expect(err).NotTo(HaveOccurred()) 384 385 Expect(fakeAppRunner.CreateAppCallCount()).To(Equal(1)) 386 createAppParams := fakeAppRunner.CreateAppArgsForCall(0) 387 Expect(createAppParams.AppEnvironmentParams.EnvironmentVariables).To(matchers.ContainExactly(map[string]string{ 388 "PWD": "/home/vcap", 389 "TMPDIR": "/home/vcap/tmp", 390 "http_proxy": "http://proxy", 391 "https_proxy": "https://proxy", 392 "no_proxy": "no-proxy", 393 })) 394 }) 395 396 It("launches the droplet lrp task with a custom start command", func() { 397 err := dropletRunner.LaunchDroplet("app-name", "droplet-name", "start-r-up", []string{"-yeah!"}, app_runner.AppEnvironmentParams{}) 398 Expect(err).NotTo(HaveOccurred()) 399 400 Expect(fakeAppRunner.CreateAppCallCount()).To(Equal(1)) 401 createAppParams := fakeAppRunner.CreateAppArgsForCall(0) 402 Expect(createAppParams.Name).To(Equal("app-name")) 403 Expect(createAppParams.StartCommand).To(Equal("/tmp/launcher")) 404 Expect(createAppParams.AppArgs).To(Equal([]string{"/home/vcap/app", "start-r-up -yeah!", "{}"})) 405 }) 406 407 It("returns an error when proxyConf reader fails", func() { 408 fakeBlobStore.DownloadReturns(ioutil.NopCloser(strings.NewReader("{}")), nil) 409 fakeBlobStore.DownloadDropletActionReturns(models.WrapAction(&models.DownloadAction{})) 410 fakeProxyConfReader.ProxyConfReturns(droplet_runner.ProxyConf{}, errors.New("proxyConf has failed")) 411 412 err := dropletRunner.LaunchDroplet("app-name", "droplet-name", "", []string{}, app_runner.AppEnvironmentParams{}) 413 Expect(err).To(MatchError("proxyConf has failed")) 414 }) 415 416 It("returns an error when create app fails", func() { 417 fakeBlobStore.DownloadReturns(ioutil.NopCloser(strings.NewReader(`{}`)), nil) 418 fakeAppRunner.CreateAppReturns(errors.New("nope")) 419 420 err := dropletRunner.LaunchDroplet("app-name", "droplet-name", "", []string{}, app_runner.AppEnvironmentParams{}) 421 Expect(err).To(MatchError("nope")) 422 }) 423 }) 424 425 Describe("RemoveDroplet", func() { 426 It("recursively removes a droplets from the blob store", func() { 427 config.SetBlobStore("blob-host", "7474", "dav-user", "dav-pass") 428 Expect(config.Save()).To(Succeed()) 429 430 fakeBlobStore.ListReturns([]blob.Blob{ 431 {Path: "drippy-bits.zip"}, 432 {Path: "drippy-droplet.tgz"}, 433 }, nil) 434 435 appInfos := []app_examiner.AppInfo{ 436 { 437 Annotation: "", 438 }, 439 { 440 Annotation: "junk", 441 }, 442 { 443 Annotation: `{ 444 "droplet_source": { 445 "droplet_name": "other-drippy" 446 } 447 }`, 448 }, 449 } 450 fakeAppExaminer.ListAppsReturns(appInfos, nil) 451 452 Expect(dropletRunner.RemoveDroplet("drippy")).To(Succeed()) 453 454 Expect(fakeBlobStore.ListCallCount()).To(Equal(1)) 455 456 Expect(fakeBlobStore.DeleteCallCount()).To(Equal(2)) 457 Expect(fakeBlobStore.DeleteArgsForCall(0)).To(Equal("drippy-bits.zip")) 458 Expect(fakeBlobStore.DeleteArgsForCall(1)).To(Equal("drippy-droplet.tgz")) 459 }) 460 461 It("returns an error when querying the blob store fails", func() { 462 fakeBlobStore.ListReturns(nil, errors.New("some error")) 463 464 err := dropletRunner.RemoveDroplet("drippy") 465 Expect(err).To(MatchError("some error")) 466 }) 467 468 It("returns an error when the app specifies that the droplet is in use", func() { 469 config.SetBlobStore("blob-host", "7474", "dav-user", "dav-pass") 470 Expect(config.Save()).To(Succeed()) 471 472 appInfos := []app_examiner.AppInfo{{ 473 ProcessGuid: "dripapp", 474 Annotation: `{ 475 "droplet_source": { 476 "droplet_name": "drippy" 477 } 478 }`, 479 }} 480 fakeAppExaminer.ListAppsReturns(appInfos, nil) 481 482 err := dropletRunner.RemoveDroplet("drippy") 483 Expect(err).To(MatchError("app dripapp was launched from droplet")) 484 }) 485 486 It("returns an error when listing the running applications fails", func() { 487 fakeAppExaminer.ListAppsReturns(nil, errors.New("some error")) 488 489 err := dropletRunner.RemoveDroplet("drippy") 490 Expect(err).To(MatchError("some error")) 491 }) 492 493 It("returns an error when the droplet doesn't exist", func() { 494 fakeBlobStore.ListReturns([]blob.Blob{ 495 {Path: "drippy-bits.zip"}, 496 {Path: "drippy-droplet.tgz"}, 497 }, nil) 498 499 err := dropletRunner.RemoveDroplet("droopy") 500 Expect(err).To(MatchError("droplet not found")) 501 }) 502 }) 503 504 Describe("ExportDroplet", func() { 505 BeforeEach(func() { 506 fakeDropletReader := ioutil.NopCloser(strings.NewReader("some droplet reader")) 507 508 fakeBlobStore.DownloadStub = func(path string) (io.ReadCloser, error) { 509 switch path { 510 case "drippy-droplet.tgz": 511 return fakeDropletReader, nil 512 case "no-such-droplet-droplet.tgz": 513 return nil, errors.New("some missing droplet error") 514 default: 515 return nil, errors.New("fake GetReader called with invalid arguments") 516 } 517 } 518 }) 519 520 It("returns IO readers for the droplet", func() { 521 dropletReader, err := dropletRunner.ExportDroplet("drippy") 522 defer dropletReader.Close() 523 Expect(err).NotTo(HaveOccurred()) 524 Expect(ioutil.ReadAll(dropletReader)).To(BeEquivalentTo("some droplet reader")) 525 }) 526 527 Context("when the droplet name does not have an associated droplet", func() { 528 It("returns an error", func() { 529 _, err := dropletRunner.ExportDroplet("no-such-droplet") 530 Expect(err).To(MatchError("droplet not found: some missing droplet error")) 531 }) 532 }) 533 }) 534 535 Describe("ImportDroplet", func() { 536 var tmpDir, dropletPathArg string 537 538 BeforeEach(func() { 539 var err error 540 tmpDir, err = ioutil.TempDir(os.TempDir(), "droplet") 541 Expect(err).NotTo(HaveOccurred()) 542 543 dropletPathArg = filepath.Join(tmpDir, "totally-drippy.tgz") 544 Expect(ioutil.WriteFile(dropletPathArg, []byte("droplet contents"), 0644)).To(Succeed()) 545 }) 546 547 AfterEach(func() { 548 Expect(os.RemoveAll(tmpDir)).To(Succeed()) 549 }) 550 551 Context("when the droplet files exist", func() { 552 It("uploads the droplet files to the blob store", func() { 553 err := dropletRunner.ImportDroplet("drippy", dropletPathArg) 554 Expect(err).NotTo(HaveOccurred()) 555 556 Expect(fakeBlobStore.UploadCallCount()).To(Equal(1)) 557 558 path, _ := fakeBlobStore.UploadArgsForCall(0) 559 Expect(path).To(Equal("drippy-droplet.tgz")) 560 }) 561 562 Context("when the blob bucket returns error(s)", func() { 563 It("returns an error uploading the droplet file", func() { 564 fakeBlobStore.UploadReturns(errors.New("some error")) 565 566 err := dropletRunner.ImportDroplet("drippy", dropletPathArg) 567 Expect(err).To(MatchError("some error")) 568 }) 569 }) 570 }) 571 572 Context("when the droplet files do not exist", func() { 573 It("returns an error opening the droplet file", func() { 574 err := dropletRunner.ImportDroplet("drippy", "some/missing/droplet/path") 575 Expect(reflect.TypeOf(err).String()).To(Equal("*os.PathError")) 576 }) 577 }) 578 }) 579 })