Expect(os.Chdir(tmpDir)).To(Succeed())

				fakeCFIgnore.ShouldIgnoreStub = func(path string) bool {
					return path == "some-ignored-file"
				}
			})

			AfterEach(func() {
				Expect(os.Chdir(prevDir)).To(Succeed())
				Expect(os.RemoveAll(tmpDir)).To(Succeed())
			})

			It("tars up current working folder and uploads as the droplet name", func() {
				test_helpers.ExecuteCommandWithArgs(buildDropletCommand, []string{"droplet-name", "http://some.url/for/buildpack"})

				Expect(outputBuffer).To(test_helpers.Say("Submitted build of droplet-name"))
				Expect(fakeDropletRunner.UploadBitsCallCount()).To(Equal(1))
				dropletName, uploadPath := fakeDropletRunner.UploadBitsArgsForCall(0)
				Expect(dropletName).To(Equal("droplet-name"))

				Expect(uploadPath).ToNot(BeNil())
				Expect(uploadPath).To(HaveSuffix(".tar"))

				buffer := make([]byte, 12)
				file, err := os.Open(uploadPath)
				Expect(err).ToNot(HaveOccurred())
				tarReader := tar.NewReader(file)

				h, err := tarReader.Next()
				Expect(err).NotTo(HaveOccurred())
				Expect(h.FileInfo().Name()).To(Equal("aaa"))
Beispiel #2
0
		It("instantiates a terminal", func() {
			Expect(terminalUI).ToNot(BeNil())

			_, readWriterOk := terminalUI.(io.ReadWriter)
			Expect(readWriterOk).To(BeTrue())

			_, passwordReaderOk := terminalUI.(password_reader.PasswordReader)
			Expect(passwordReaderOk).To(BeTrue())
		})
	})

	Describe("Output methods", func() {
		Describe("Say", func() {
			It("says the message to the terminal", func() {
				terminalUI.Say("Cloudy with a chance of meatballs")
				Expect(outputBuffer).To(test_helpers.Say("Cloudy with a chance of meatballs"))
			})
		})

		Describe("SayLine", func() {
			It("says the message to the terminal with a newline", func() {
				terminalUI.SayLine("Strange Clouds")
				Expect(outputBuffer).To(test_helpers.Say("Strange Clouds\n"))
			})
		})

		Describe("SayIncorrectUsage", func() {
			Context("when no message is passed", func() {
				It("outputs incorrect usage", func() {
					terminalUI.SayIncorrectUsage("")
					Expect(outputBuffer).To(test_helpers.SayIncorrectUsage())
					State:         "COMPLETED",
				},
				task_examiner.TaskInfo{
					TaskGuid:      "task-guid-3",
					CellID:        "",
					Failed:        true,
					FailureReason: "",
					Result:        "",
					State:         "COMPLETED",
				},
			}
			fakeTaskExaminer.ListTasksReturns(listTasks, nil)

			test_helpers.ExecuteCommandWithArgs(listAppsCommand, []string{})

			Expect(outputBuffer).To(test_helpers.Say(colors.Bold("App Name")))
			Expect(outputBuffer).To(test_helpers.Say(colors.Bold("Instances")))
			Expect(outputBuffer).To(test_helpers.Say(colors.Bold("DiskMB")))
			Expect(outputBuffer).To(test_helpers.Say(colors.Bold("MemoryMB")))
			Expect(outputBuffer).To(test_helpers.Say(colors.Bold("Route")))

			Expect(outputBuffer).To(test_helpers.Say(colors.Bold("process1")))
			Expect(outputBuffer).To(test_helpers.Say(colors.Red("0/21")))
			Expect(outputBuffer).To(test_helpers.Say(colors.NoColor("100")))
			Expect(outputBuffer).To(test_helpers.Say(colors.NoColor("50")))
			Expect(outputBuffer).To(test_helpers.Say("alldaylong.com => 54321"))

			Expect(outputBuffer).To(test_helpers.Say(colors.Bold("process2")))
			Expect(outputBuffer).To(test_helpers.Say(colors.Yellow("9/8")))
			Expect(outputBuffer).To(test_helpers.Say(colors.NoColor("400")))
			Expect(outputBuffer).To(test_helpers.Say(colors.NoColor("30")))
		Context("when the json file exists", func() {
			BeforeEach(func() {
				tmpDir = os.TempDir()
				tmpFile, err = ioutil.TempFile(tmpDir, "tmp_json")
				Expect(err).ToNot(HaveOccurred())

				Expect(ioutil.WriteFile(tmpFile.Name(), []byte(`{"Value":"test value"}`), 0700)).To(Succeed())
			})

			It("creates an app from json", func() {
				fakeAppRunner.SubmitLrpReturns("my-json-app", nil)
				args := []string{tmpFile.Name()}

				test_helpers.ExecuteCommandWithArgs(submitLrpCommand, args)

				Expect(outputBuffer).To(test_helpers.Say(colors.Green("Successfully submitted my-json-app.")))
				Expect(outputBuffer).To(test_helpers.Say("To view the status of your application: ltc status my-json-app"))
				Expect(fakeAppRunner.SubmitLrpCallCount()).To(Equal(1))
				Expect(fakeAppRunner.SubmitLrpArgsForCall(0)).To(Equal([]byte(`{"Value":"test value"}`)))
			})

			It("prints an error returned by the app_runner", func() {
				fakeAppRunner.SubmitLrpReturns("app-that-broke", errors.New("some error"))
				args := []string{tmpFile.Name()}

				test_helpers.ExecuteCommandWithArgs(submitLrpCommand, args)

				Expect(outputBuffer).To(test_helpers.Say("Error creating app-that-broke: some error"))
				Expect(fakeAppRunner.SubmitLrpCallCount()).To(Equal(1))
				Expect(fakeExitHandler.ExitCalledWith).To(Equal([]int{exit_codes.CommandFailed}))
			})
		It("polls until the required number of instances are running", func() {
			fakeAppExaminer.RunningAppInstancesInfoReturns(1, false, nil)

			args := []string{
				"cool-web-app",
				"22",
			}
			doneChan := test_helpers.AsyncExecuteCommandWithArgs(scaleCommand, args)

			Eventually(outputBuffer).Should(test_helpers.SayLine("Scaling cool-web-app to 22 instances"))

			Expect(fakeAppExaminer.RunningAppInstancesInfoCallCount()).To(Equal(1))
			Expect(fakeAppExaminer.RunningAppInstancesInfoArgsForCall(0)).To(Equal("cool-web-app"))

			fakeClock.IncrementBySeconds(1)
			Eventually(outputBuffer).Should(test_helpers.Say("."))
			fakeClock.IncrementBySeconds(1)
			Eventually(outputBuffer).Should(test_helpers.Say("."))

			fakeAppExaminer.RunningAppInstancesInfoReturns(22, false, nil)
			fakeClock.IncrementBySeconds(1)

			Eventually(doneChan, 3).Should(BeClosed())

			Expect(outputBuffer).To(test_helpers.SayLine(colors.Green("App Scaled Successfully")))
		})

		Context("when the app does not scale before the timeout elapses", func() {
			It("alerts the user the app took too long to scale", func() {
				fakeAppExaminer.RunningAppInstancesInfoReturns(1, false, nil)
			Expect(outputBuffer).To(test_helpers.SayLine("Connecting to app-name/2 at %s", config.Target()))

			Expect(fakeSecureShell.ConnectToShellCallCount()).To(Equal(1))
			appName, instanceIndex, command, actualConfig := fakeSecureShell.ConnectToShellArgsForCall(0)
			Expect(appName).To(Equal("app-name"))
			Expect(instanceIndex).To(Equal(2))
			Expect(command).To(BeEmpty())
			Expect(actualConfig).To(Equal(config))
		})

		It("should run a command remotely instead of the login shell", func() {
			doneChan := test_helpers.AsyncExecuteCommandWithArgs(sshCommand, []string{"app-name", "echo", "1", "2", "3"})

			Eventually(doneChan).Should(BeClosed())
			Expect(outputBuffer).NotTo(test_helpers.Say("Connecting to app-name"))

			Expect(fakeSecureShell.ConnectToShellCallCount()).To(Equal(1))
			appName, instanceIndex, command, actualConfig := fakeSecureShell.ConnectToShellArgsForCall(0)
			Expect(appName).To(Equal("app-name"))
			Expect(instanceIndex).To(Equal(0))
			Expect(command).To(Equal("echo 1 2 3"))
			Expect(actualConfig).To(Equal(config))
		})

		It("should support -- delimiter for args", func() {
			doneChan := test_helpers.AsyncExecuteCommandWithArgs(sshCommand, []string{"app-name", "--", "/bin/ls", "-l"})

			Eventually(doneChan).Should(BeClosed())
			Expect(outputBuffer).NotTo(test_helpers.Say("Connecting to app-name"))
				Expect(uploadPath).NotTo(BeNil())
				Expect(uploadPath).To(Equal("xyz.zip"))
			})

			It("passes through environment variables from the command-line", func() {
				args := []string{
					"-e",
					"AAAA",
					"-e",
					"BBBB=2",
					"droplet-name",
					"http://some.url/for/buildpack",
				}
				test_helpers.ExecuteCommandWithArgs(buildDropletCommand, args)

				Expect(outputBuffer).To(test_helpers.Say("Submitted build of droplet-name"))

				_, _, _, envVars, _, _, _ := fakeDropletRunner.BuildDropletArgsForCall(0)

				aaaaVar, found := envVars["AAAA"]
				Expect(found).To(BeTrue())
				Expect(aaaaVar).To(Equal("xyz"))
				bbbbVar, found := envVars["BBBB"]
				Expect(found).To(BeTrue())
				Expect(bbbbVar).To(Equal("2"))
			})

			It("allows specifying resource parameters on the command-line", func() {
				args := []string{
					"-c",
					"75",
	"github.com/cloudfoundry-incubator/lattice/ltc/test_helpers"
)

var _ = Describe("RegexSafeSay", func() {
	var outputBuffer *gbytes.Buffer

	BeforeEach(func() {
		outputBuffer = gbytes.NewBuffer()
	})

	Describe("Say", func() {
		BeforeEach(func() {
			outputBuffer.Write([]byte(`match this \|?-^$.(){}`))
		})
		It("matches with regex-escaped characters", func() {
			Expect(outputBuffer).To(test_helpers.Say(`match this \|?-^$.(){}`))
		})
		It("negated match", func() {
			Expect(outputBuffer).NotTo(test_helpers.Say("match that"))
		})
		Context("when format string is passed with arguments", func() {
			It("matches with regex-escaped characters", func() {
				Expect(outputBuffer).To(test_helpers.Say(`match %s \|?-^$.(){}`, "this"))
			})
		})
	})

	Describe("SayLine", func() {
		BeforeEach(func() {
			outputBuffer.Write([]byte(`match this \|?-^$.(){}` + "\n"))
		})
				Expect(os.Chdir(tmpDir)).To(Succeed())

				fakeCFIgnore.ShouldIgnoreStub = func(path string) bool {
					return path == "some-ignored-file"
				}
			})

			AfterEach(func() {
				Expect(os.Chdir(prevDir)).To(Succeed())
				Expect(os.RemoveAll(tmpDir)).To(Succeed())
			})

			It("zips up current working folder and uploads as the droplet name", func() {
				test_helpers.ExecuteCommandWithArgs(buildDropletCommand, []string{"droplet-name", "http://some.url/for/buildpack"})

				Expect(outputBuffer).To(test_helpers.Say("Submitted build of droplet-name"))
				Expect(fakeDropletRunner.UploadBitsCallCount()).To(Equal(1))
				dropletName, uploadPath := fakeDropletRunner.UploadBitsArgsForCall(0)
				Expect(dropletName).To(Equal("droplet-name"))

				Expect(uploadPath).ToNot(BeNil())
				Expect(uploadPath).To(HaveSuffix(".zip"))

				zipReader, err := zip.OpenReader(uploadPath)
				Expect(err).NotTo(HaveOccurred())

				Expect(zipReader.File).To(HaveLen(6))

				buffer := make([]byte, 12)
				h := zipReader.File[0].FileHeader
				f, err := zipReader.File[0].Open()
				})
			})

			Context("when the blob store target is offline", func() {
				It("exits", func() {
					fakeBlobStoreVerifier.VerifyReturns(false, errors.New("some error"))

					test_helpers.ExecuteCommandWithArgs(targetCommand, []string{"myapi.com"})

					Expect(fakeBlobStoreVerifier.VerifyCallCount()).To(Equal(1))
					Expect(fakeBlobStoreVerifier.VerifyArgsForCall(0)).To(Equal(dav_blob_store.Config{
						Host: "myapi.com",
						Port: "8444",
					}))

					Expect(outputBuffer).To(test_helpers.Say("Could not connect to the droplet store."))
					verifyOldTargetStillSet()
					Expect(fakeExitHandler.ExitCalledWith).To(Equal([]int{exit_codes.BadTarget}))
				})
			})

			Context("when the persister returns errors", func() {
				BeforeEach(func() {
					commandFactory := command_factory.NewConfigCommandFactory(config_package.New(errorPersister("some error")), terminalUI, fakeTargetVerifier, fakeBlobStoreVerifier, fakeExitHandler)
					targetCommand = commandFactory.MakeTargetCommand()
				})

				It("exits", func() {
					test_helpers.ExecuteCommandWithArgs(targetCommand, []string{"myapi.com"})

					Eventually(outputBuffer).Should(test_helpers.SayLine("some error"))
		})

		It("displays info for a pending task", func() {
			taskInfo := task_examiner.TaskInfo{
				TaskGuid:      "boop",
				State:         "PENDING",
				CellID:        "cell-01",
				Failed:        false,
				FailureReason: "",
				Result:        "",
			}
			fakeTaskExaminer.TaskStatusReturns(taskInfo, nil)

			test_helpers.ExecuteCommandWithArgs(taskCommand, []string{"boop"})

			Expect(outputBuffer).To(test_helpers.Say("Task Name"))
			Expect(outputBuffer).To(test_helpers.Say("boop"))
			Expect(outputBuffer).To(test_helpers.Say("Cell ID"))
			Expect(outputBuffer).To(test_helpers.Say("cell-01"))
			Expect(outputBuffer).To(test_helpers.Say("Status"))
			Expect(outputBuffer).To(test_helpers.Say(colors.Yellow("PENDING")))
			Expect(outputBuffer).NotTo(test_helpers.Say("Result"))
			Expect(outputBuffer).NotTo(test_helpers.Say("Failure Reason"))

			Expect(fakeTaskExaminer.TaskStatusCallCount()).To(Equal(1))
			Expect(fakeTaskExaminer.TaskStatusArgsForCall(0)).To(Equal("boop"))
		})

		It("displays result for a non-failed completed task", func() {
			taskInfo := task_examiner.TaskInfo{
				TaskGuid:      "boop",
			}

			fakeTargetVerifier.VerifyTargetReturns(true, true, nil)
			cliConfig.SetTarget("my-lattice.example.com")
			cliConfig.Save()
		})

		It("informs user for any incorrect provided flags", func() {
			cliAppArgs := []string{"ltc", "print-a-unicorn", "--bad-flag=10"}
			flags := main.GetCommandFlags(cliApp, cliAppArgs[1])
			badFlags := main.MatchArgAndFlags(flags, cliAppArgs[2:])
			main.InjectHelpTemplate(badFlags)
			err := cliApp.Run(cliAppArgs)
			Expect(err).To(HaveOccurred())

			Expect(outputBuffer).To(test_helpers.Say("Incorrect Usage."))
			Expect(outputBuffer).To(test_helpers.Say("Unknown flag \"--bad-flag\""))
		})

		It("checks flags with prefix '--'", func() {
			cliAppArgs := []string{"ltc", "print-a-unicorn", "not-a-flag", "--invalid-flag"}
			flags := main.GetCommandFlags(cliApp, cliAppArgs[1])
			badFlags := main.MatchArgAndFlags(flags, cliAppArgs[2:])
			main.InjectHelpTemplate(badFlags)
			err := cliApp.Run(cliAppArgs)
			Expect(err).To(HaveOccurred())

			Expect(outputBuffer).To(test_helpers.Say("Incorrect Usage."))
			Expect(outputBuffer).To(test_helpers.Say("Unknown flag \"--invalid-flag\""))
			Expect(outputBuffer).NotTo(test_helpers.Say("Unknown flag \"not-a-flag\""))
		})
		logReader = fake_log_reader.NewFakeLogReader()
		consoleTailedLogsOutputter = console_tailed_logs_outputter.NewConsoleTailedLogsOutputter(terminalUI, logReader)
	})

	Describe("OutputTailedLogs", func() {
		It("Tails logs", func() {
			now := time.Now()
			logReader.AddLog(buildLogMessage("RTR", "1", now, []byte("First log")))
			logReader.AddError(errors.New("First Error"))

			go consoleTailedLogsOutputter.OutputTailedLogs("my-app-guid")

			Eventually(logReader.GetAppGuid).Should(Equal("my-app-guid"))

			logOutputBufferString := fmt.Sprintf("%s [%s|%s] First log\n", colors.Cyan(now.Format("01/02 15:04:05.00")), colors.Yellow("RTR"), colors.Yellow("1"))
			Eventually(outputBuffer).Should(test_helpers.Say(logOutputBufferString))
			Eventually(outputBuffer).Should(test_helpers.Say("First Error\n"))
		})
	})

	Describe("OutputDebugLogs", func() {
		It("tails logs with pretty formatting", func() {
			now := time.Now()
			logReader.AddLog(buildLogMessage("rep", "cell-1", now, []byte("First log")))
			logReader.AddError(errors.New("First Error"))

			go consoleTailedLogsOutputter.OutputDebugLogs(true)

			Eventually(logReader.GetAppGuid).Should(Equal(reserved_app_ids.LatticeDebugLogStreamAppId))

			Eventually(outputBuffer).Should(test_helpers.Say("rep"))
				app_examiner.AppInfo{ProcessGuid: "process2", DesiredInstances: 8, ActualRunningInstances: 9, DiskMB: 400, MemoryMB: 30, Ports: []uint16{1234}, Routes: route_helpers.AppRoutes{route_helpers.AppRoute{Hostnames: []string{"never.io"}, Port: 1234}}},
				app_examiner.AppInfo{ProcessGuid: "process3", DesiredInstances: 5, ActualRunningInstances: 5, DiskMB: 600, MemoryMB: 90, Ports: []uint16{1234}, Routes: route_helpers.AppRoutes{route_helpers.AppRoute{Hostnames: []string{"allthetime.com", "herewego.org"}, Port: 1234}}},
				app_examiner.AppInfo{ProcessGuid: "process4", DesiredInstances: 0, ActualRunningInstances: 0, DiskMB: 10, MemoryMB: 10, Routes: route_helpers.AppRoutes{}},
			}

			listTasks := []task_examiner.TaskInfo{
				task_examiner.TaskInfo{TaskGuid: "task-guid-1", CellID: "cell-01", Failed: false, FailureReason: "", Result: "Finished", State: "COMPLETED"},
				task_examiner.TaskInfo{TaskGuid: "task-guid-2", CellID: "cell-02", Failed: true, FailureReason: "No compatible container", Result: "Finished", State: "COMPLETED"},
				task_examiner.TaskInfo{TaskGuid: "task-guid-3", CellID: "", Failed: true, FailureReason: "", Result: "", State: "COMPLETED"},
			}
			fakeAppExaminer.ListAppsReturns(listApps, nil)
			fakeTaskExaminer.ListTasksReturns(listTasks, nil)

			test_helpers.ExecuteCommandWithArgs(listAppsCommand, []string{})

			Expect(outputBuffer).To(test_helpers.Say(colors.Bold("App Name")))
			Expect(outputBuffer).To(test_helpers.Say(colors.Bold("Instances")))
			Expect(outputBuffer).To(test_helpers.Say(colors.Bold("DiskMB")))
			Expect(outputBuffer).To(test_helpers.Say(colors.Bold("MemoryMB")))
			Expect(outputBuffer).To(test_helpers.Say(colors.Bold("Route")))

			Expect(outputBuffer).To(test_helpers.Say(colors.Bold("process1")))
			Expect(outputBuffer).To(test_helpers.Say(colors.Red("0/21")))
			Expect(outputBuffer).To(test_helpers.Say(colors.NoColor("100")))
			Expect(outputBuffer).To(test_helpers.Say(colors.NoColor("50")))
			Expect(outputBuffer).To(test_helpers.Say("alldaylong.com => 54321"))

			Expect(outputBuffer).To(test_helpers.Say(colors.Bold("process2")))
			Expect(outputBuffer).To(test_helpers.Say(colors.Yellow("9/8")))
			Expect(outputBuffer).To(test_helpers.Say(colors.NoColor("400")))
			Expect(outputBuffer).To(test_helpers.Say(colors.NoColor("30")))
					Expect(fakeExitHandler.ExitCalledWith).To(Equal([]int{exit_codes.FileSystemError}))
				})
			})
		})

		Context("when the receptor requires authentication", func() {
			BeforeEach(func() {
				fakeTargetVerifier.VerifyTargetReturns(true, false, nil)
				fakeBlobStoreVerifier.VerifyReturns(true, nil)
				fakePasswordReader.PromptForPasswordReturns("testpassword")
			})

			It("prompts for credentials and stores them in the config", func() {
				doneChan := test_helpers.AsyncExecuteCommandWithArgs(targetCommand, []string{"myapi.com"})

				Eventually(outputBuffer).Should(test_helpers.Say("Username: "******"testusername\n"))

				Eventually(doneChan, 3).Should(BeClosed())

				Expect(config.Target()).To(Equal("myapi.com"))
				Expect(config.Receptor()).To(Equal("http://*****:*****@receptor.myapi.com"))
				Expect(outputBuffer).To(test_helpers.SayLine("API location set."))

				Expect(fakePasswordReader.PromptForPasswordCallCount()).To(Equal(1))
				Expect(fakePasswordReader.PromptForPasswordArgsForCall(0)).To(Equal("Password"))

				Expect(fakeTargetVerifier.VerifyTargetCallCount()).To(Equal(2))
				Expect(fakeTargetVerifier.VerifyTargetArgsForCall(0)).To(Equal("http://receptor.myapi.com"))
				Expect(fakeTargetVerifier.VerifyTargetArgsForCall(1)).To(Equal("http://*****:*****@receptor.myapi.com"))
	Describe("MakeCliApp", func() {
		It("makes an app", func() {
			Expect(cliApp).ToNot(BeNil())
			Expect(cliApp.Name).To(Equal("ltc"))
			Expect(cliApp.Author).To(Equal("Pivotal"))
			Expect(cliApp.Version).To(Equal("v0.2.Test (diego 0.12345.0)"))
			Expect(cliApp.Email).To(Equal("*****@*****.**"))
			Expect(cliApp.Usage).To(Equal(cli_app_factory.LtcUsage))
			Expect(cliApp.Commands).NotTo(BeEmpty())
			Expect(cliApp.Action).ToNot(BeNil())
			Expect(cliApp.CommandNotFound).ToNot(BeNil())

			By("writing to the App.Writer", func() {
				cliApp.Writer.Write([]byte("write_sample"))
				Expect(outputBuffer).To(test_helpers.Say("write_sample"))
			})

		})

		Context("when targeted at a dav blob store", func() {
			BeforeEach(func() {
				cliConfig.SetBlobStore("http://test.com", "9999", "username", "password")
			})

			It("instantiates a new dav blob store object", func() {

			})
		})

		Context("when invoked without latticeVersion set", func() {
Beispiel #17
0
	Describe("MakeCliApp", func() {
		It("makes an app", func() {
			Expect(cliApp).ToNot(BeNil())
			Expect(cliApp.Name).To(Equal("ltc"))
			Expect(cliApp.Author).To(Equal("Pivotal"))
			Expect(cliApp.Version).To(Equal("v0.2.Test (diego 0.12345.0)"))
			Expect(cliApp.Email).To(Equal("*****@*****.**"))
			Expect(cliApp.Usage).To(Equal(cli_app_factory.LtcUsage))
			Expect(cliApp.Commands).NotTo(BeEmpty())
			Expect(cliApp.Action).ToNot(BeNil())
			Expect(cliApp.CommandNotFound).ToNot(BeNil())

			By("writing to the App.Writer", func() {
				cliApp.Writer.Write([]byte("write_sample"))
				Expect(outputBuffer).To(test_helpers.Say("write_sample"))
			})

		})

		Context("when invoked without latticeVersion set", func() {
			BeforeEach(func() {
				diegoVersion = ""
				latticeVersion = ""
			})

			It("defaults the version", func() {
				Expect(cliApp).NotTo(BeNil())
				Expect(cliApp.Version).To(Equal("development (not versioned) (diego unknown)"))
			})
		})
		It("handles invalid appguids", func() {
			test_helpers.ExecuteCommandWithArgs(logsCommand, []string{})

			Expect(outputBuffer).To(test_helpers.SayIncorrectUsage())
			Expect(fakeExitHandler.ExitCalledWith).To(Equal([]int{exit_codes.InvalidSyntax}))
		})

		It("handles non existent application", func() {
			appExaminer.AppExistsReturns(false, nil)
			taskExaminer.TaskStatusReturns(task_examiner.TaskInfo{}, errors.New("task not found"))

			doneChan := test_helpers.AsyncExecuteCommandWithArgs(logsCommand, []string{"non_existent_app"})

			Eventually(fakeTailedLogsOutputter.OutputTailedLogsCallCount).Should(Equal(1))
			Expect(fakeTailedLogsOutputter.OutputTailedLogsArgsForCall(0)).To(Equal("non_existent_app"))
			Expect(outputBuffer).To(test_helpers.Say("Application or task non_existent_app not found."))
			Expect(outputBuffer).To(test_helpers.Say("Tailing logs and waiting for non_existent_app to appear..."))

			Consistently(doneChan).ShouldNot(BeClosed())
		})

		It("handles tasks", func() {
			appExaminer.AppExistsReturns(false, nil)
			taskExaminer.TaskStatusReturns(task_examiner.TaskInfo{}, nil)

			doneChan := test_helpers.AsyncExecuteCommandWithArgs(logsCommand, []string{"task-guid"})

			Eventually(fakeTailedLogsOutputter.OutputTailedLogsCallCount).Should(Equal(1))
			Expect(fakeTailedLogsOutputter.OutputTailedLogsArgsForCall(0)).To(Equal("task-guid"))

			Consistently(doneChan).ShouldNot(BeClosed())
	Describe("TargetBlobCommand", func() {
		var targetBlobCommand cli.Command

		BeforeEach(func() {
			commandFactory := command_factory.NewConfigCommandFactory(config, terminalUI, fakeTargetVerifier, fakeExitHandler)
			targetBlobCommand = commandFactory.MakeTargetBlobCommand()
		})

		Context("displaying the blob target", func() {
			It("outputs the current target", func() {
				config.SetBlobTarget("192.168.11.11", 8980, "datkeyyo", "supersecretJKJK", "bucket")
				config.Save()

				test_helpers.ExecuteCommandWithArgs(targetBlobCommand, []string{})

				Expect(outputBuffer).To(test_helpers.Say("Blob Target:\t192.168.11.11:8980\n"))
				Expect(outputBuffer).To(test_helpers.Say("Access Key:\tdatkeyyo"))
				Expect(outputBuffer).To(test_helpers.Say("Secret Key:\tsupersecretJKJK"))
				Expect(outputBuffer).To(test_helpers.Say("Bucket Name:\tbucket"))
			})

			It("alerts the user if no target is set", func() {
				config.SetBlobTarget("", 0, "", "", "")
				config.Save()

				test_helpers.ExecuteCommandWithArgs(targetBlobCommand, []string{})

				Expect(outputBuffer).To(test_helpers.SayLine("Blob target not set"))
			})
		})
			Expect(createAppParams.RouteOverrides).To(ContainExactly(app_runner.RouteOverrides{
				app_runner.RouteOverride{HostnamePrefix: "route-3000-yay", Port: 3000},
				app_runner.RouteOverride{HostnamePrefix: "route-1111-wahoo", Port: 1111},
				app_runner.RouteOverride{HostnamePrefix: "route-1111-me-too", Port: 1111},
			}))
			Expect(createAppParams.NoRoutes).To(BeFalse())
			Expect(createAppParams.WorkingDir).To(Equal("/applications"))

			Expect(createAppParams.Setup).To(BeAssignableToTypeOf(&models.DownloadAction{}))
			reqSetup, ok := createAppParams.Setup.(*models.DownloadAction)
			Expect(ok).To(BeTrue())
			Expect(reqSetup.From).To(Equal("http://file_server.service.dc1.consul:8080/v1/static/healthcheck.tgz"))
			Expect(reqSetup.To).To(Equal("/tmp"))
			Expect(reqSetup.User).To(Equal("vcap"))

			Expect(outputBuffer).To(test_helpers.Say("Creating App: cool-web-app\n"))
			Expect(outputBuffer).To(test_helpers.Say(colors.Green("cool-web-app is now running.\n")))
			Expect(outputBuffer).To(test_helpers.Say("App is reachable at:\n"))
			Expect(outputBuffer).To(test_helpers.Say(colors.Green("http://route-3000-yay.192.168.11.11.xip.io\n")))
			Expect(outputBuffer).To(test_helpers.Say(colors.Green("http://route-1111-wahoo.192.168.11.11.xip.io\n")))
			Expect(outputBuffer).To(test_helpers.Say(colors.Green("http://route-1111-me-too.192.168.11.11.xip.io\n")))
		})

		Context("when the PROCESS_GUID is passed in as --env", func() {
			It("sets the PROCESS_GUID to the value passed in", func() {
				fakeDockerMetadataFetcher.FetchMetadataReturns(&docker_metadata_fetcher.ImageMetadata{StartCommand: []string{""}}, nil)
				fakeAppExaminer.RunningAppInstancesInfoReturns(1, false, nil)
				args := []string{
					"app-to-start",
					"fun-org/app",
					"--env=PROCESS_GUID=MyHappyGuid",
			BeforeEach(func() {
				tmpDir = os.TempDir()
				tmpFile, err = ioutil.TempFile(tmpDir, "tmp_json")

				Expect(err).ToNot(HaveOccurred())
			})

			It("submits a task from json", func() {
				jsonContents := []byte(`{"Value":"test value"}`)
				ioutil.WriteFile(tmpFile.Name(), jsonContents, 0700)
				args := []string{tmpFile.Name()}
				fakeTaskRunner.SubmitTaskReturns("some-task", nil)

				test_helpers.ExecuteCommandWithArgs(submitTaskCommand, args)

				Expect(outputBuffer).To(test_helpers.Say(colors.Green("Successfully submitted some-task")))
				Expect(fakeTaskRunner.SubmitTaskCallCount()).To(Equal(1))
				Expect(fakeTaskRunner.SubmitTaskArgsForCall(0)).To(Equal(jsonContents))
			})

			It("prints an error returned by the task_runner", func() {
				jsonContents := []byte(`{"Value":"test value"}`)
				ioutil.WriteFile(tmpFile.Name(), jsonContents, 0700)
				args := []string{tmpFile.Name()}
				fakeTaskRunner.SubmitTaskReturns("some-task", errors.New("taskypoo"))

				test_helpers.ExecuteCommandWithArgs(submitTaskCommand, args)

				Expect(fakeTaskRunner.SubmitTaskCallCount()).To(Equal(1))
				Expect(fakeTaskRunner.SubmitTaskArgsForCall(0)).To(Equal(jsonContents))
		BeforeEach(func() {
			commandFactory := command_factory.NewConfigCommandFactory(config, terminalUI, fakeTargetVerifier, fakeExitHandler)
			targetCommand = commandFactory.MakeTargetCommand()
		})

		JustBeforeEach(func() {
			config.SetTarget("oldtarget.com")
			config.SetLogin("olduser", "oldpass")
			config.Save()
		})

		Context("displaying the target", func() {
			It("outputs the current target", func() {
				test_helpers.ExecuteCommandWithArgs(targetCommand, []string{})

				Expect(outputBuffer).To(test_helpers.Say("Target:\t\toldtarget.com\n"))
				Expect(outputBuffer).To(test_helpers.Say("Username:\tolduser"))
			})

			It("does not show the username if no username is set", func() {
				config.SetLogin("", "")

				test_helpers.ExecuteCommandWithArgs(targetCommand, []string{})

				Expect(outputBuffer).ToNot(test_helpers.Say("Username:"******"alerts the user if no target is set", func() {
				config.SetTarget("")
				test_helpers.ExecuteCommandWithArgs(targetCommand, []string{})
				Expect(fakeDockerMetadataFetcher.FetchMetadataArgsForCall(0)).To(Equal("fun-org/app"))

				Expect(fakeAppRunner.CreateAppCallCount()).To(Equal(1))
				createAppParams := fakeAppRunner.CreateAppArgsForCall(0)
				Expect(createAppParams.StartCommand).To(Equal("/fetch-start"))
				Expect(createAppParams.AppArgs).To(Equal([]string{"arg1", "arg2"}))
				Expect(createAppParams.RootFS).To(Equal("docker:///fun-org/app#latest"))
				Expect(createAppParams.WorkingDir).To(Equal("/this/directory/right/here"))
			})

			It("does not output the working directory if it is not set", func() {
				fakeDockerMetadataFetcher.FetchMetadataReturns(&docker_metadata_fetcher.ImageMetadata{StartCommand: []string{"/fetch-start"}}, nil)

				test_helpers.ExecuteCommandWithArgs(createCommand, args)

				Expect(outputBuffer).NotTo(test_helpers.Say("Working directory is:"))
				Expect(fakeAppRunner.CreateAppCallCount()).To(Equal(1))
			})

			Context("when the metadata also has no start command", func() {
				It("outputs an error message and exits", func() {
					fakeDockerMetadataFetcher.FetchMetadataReturns(&docker_metadata_fetcher.ImageMetadata{}, nil)

					test_helpers.ExecuteCommandWithArgs(createCommand, args)

					Expect(outputBuffer).To(test_helpers.SayLine("Unable to determine start command from image metadata."))
					Expect(fakeAppRunner.CreateAppCallCount()).To(Equal(0))
					Expect(fakeExitHandler.ExitCalledWith).To(Equal([]int{exit_codes.BadDocker}))
				})
			})
		})
	"github.com/cloudfoundry-incubator/lattice/ltc/test_helpers"
)

var _ = Describe("RegexSafeSay", func() {

	var gbytesBuffer *gbytes.Buffer

	BeforeEach(func() {
		gbytesBuffer = gbytes.NewBuffer()
	})

	Describe("Say", func() {
		It("matches with regex-escaped characters", func() {
			gbytesBuffer.Write([]byte(`match this \|?-^$.(){}`))

			Expect(gbytesBuffer).To(test_helpers.Say(`match this \|?-^$.(){}`))
		})

		It("negated match", func() {
			gbytesBuffer.Write([]byte("say that"))

			Expect(gbytesBuffer).ToNot(test_helpers.Say("different"))
		})
	})

	Describe("SayLine", func() {
		It("matches with regex-escaped characters", func() {
			gbytesBuffer.Write([]byte("sample\n"))

			Expect(gbytesBuffer).To(test_helpers.SayLine("sample"))
		})