func (runner *clusterTestRunner) cloneRepo(timeout time.Duration, repoURL string) string { tmpDir, err := ioutil.TempDir("", "repo") Expect(err).NotTo(HaveOccurred()) fmt.Fprintln(getStyledWriter("test"), colors.PurpleUnderline(fmt.Sprintf("Attempting to clone %s to %s", repoURL, tmpDir))) command := exec.Command("git", "clone", repoURL, tmpDir) session, err := gexec.Start(command, getStyledWriter("git-clone"), getStyledWriter("git-clone")) Expect(err).NotTo(HaveOccurred()) expectExitInBuffer(timeout, session, session.Err) Eventually(session.Err).Should(test_helpers.Say(fmt.Sprintf("Cloning into '%s'...", tmpDir))) fmt.Fprintf(getStyledWriter("test"), "Cloned %s into %s\n", repoURL, tmpDir) return tmpDir }
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"))
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() {
test_helpers.ExecuteCommandWithArgs(sshCommand, []string{"-t", "app-name", "/bin/ls"}) Expect(fakeSSH.ShellCallCount()).To(Equal(1)) _, ptyDesired := fakeSSH.ShellArgsForCall(0) Expect(ptyDesired).To(BeTrue()) }) Context("when a command is provided", func() { It("should run a command remotely instead of the login shell", func() { fakeAppExaminer.AppStatusReturns(app_examiner.AppInfo{ActualRunningInstances: 1}, nil) doneChan := test_helpers.AsyncExecuteCommandWithArgs(sshCommand, []string{"app-name", "echo", "1", "2", "3"}) Eventually(doneChan, 3).Should(BeClosed()) Expect(outputBuffer).NotTo(test_helpers.Say("Connecting to app-name")) Expect(fakeSSH.ShellCallCount()).To(Equal(1)) command, _ := fakeSSH.ShellArgsForCall(0) Expect(command).To(Equal("echo 1 2 3")) }) It("should support -- delimiter for args", func() { fakeAppExaminer.AppStatusReturns(app_examiner.AppInfo{ActualRunningInstances: 1}, nil) test_helpers.ExecuteCommandWithArgs(sshCommand, []string{"app-name", "--", "/bin/ls", "-l"}) Expect(fakeSSH.ShellCallCount()).To(Equal(1)) command, _ := fakeSSH.ShellArgsForCall(0) Expect(command).To(Equal("/bin/ls -l")) })
It("is an error when no path is passed in", func() { test_helpers.ExecuteCommandWithArgs(submitTaskCommand, []string{}) Expect(outputBuffer).To(test_helpers.SayLine("Path to JSON is required")) Expect(fakeTaskRunner.SubmitTaskCallCount()).To(BeZero()) Expect(fakeExitHandler.ExitCalledWith).To(Equal([]int{exit_codes.InvalidSyntax})) }) Context("when the file cannot be read", func() { It("prints an error", func() { args := []string{filepath.Join(os.TempDir(), "file-no-existy")} test_helpers.ExecuteCommandWithArgs(submitTaskCommand, args) Expect(outputBuffer).To(test_helpers.Say("Error reading file")) Expect(fakeTaskRunner.SubmitTaskCallCount()).To(Equal(0)) Expect(fakeExitHandler.ExitCalledWith).To(Equal([]int{exit_codes.FileSystemError})) }) }) }) Describe("DeleteTaskCommand", func() { var deleteTaskCommand cli.Command BeforeEach(func() { commandFactory := command_factory.NewTaskRunnerCommandFactory(fakeTaskRunner, terminalUI, fakeExitHandler) deleteTaskCommand = commandFactory.MakeDeleteTaskCommand() })
}) Describe("Instantiation", func() { It("instantiates a terminal", func() { Expect(terminalUI).NotTo(BeNil()) _, readWriterOk := terminalUI.(io.ReadWriter) Expect(readWriterOk).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")) }) Context("when printf-style syntax is used", func() { It("says the formatted message to the terminal", func() { terminalUI.Say("delim %s what %d", "put-this-in", 44) Expect(outputBuffer).To(test_helpers.Say("delim put-this-in what 44")) }) }) }) 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")) })
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})) }) }) })
}) 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 GUID")) 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(outputBuffer).To(test_helpers.SayNewLine()) 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{
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",
}) It("is an error when no path is passed in", func() { test_helpers.ExecuteCommandWithArgs(submitLrpCommand, []string{}) Expect(outputBuffer).To(test_helpers.SayLine("Path to JSON is required")) Expect(fakeAppRunner.SubmitLrpCallCount()).To(BeZero()) Expect(fakeExitHandler.ExitCalledWith).To(Equal([]int{exit_codes.InvalidSyntax})) }) Context("when the file cannot be read", func() { It("prints an error", func() { args := []string{"file-no-existy"} test_helpers.ExecuteCommandWithArgs(submitLrpCommand, args) Expect(outputBuffer).To(test_helpers.Say("Error reading file: open file-no-existy:")) Expect(fakeAppRunner.SubmitLrpCallCount()).To(Equal(0)) Expect(fakeExitHandler.ExitCalledWith).To(Equal([]int{exit_codes.FileSystemError})) }) }) }) Describe("ScaleAppCommand", func() { var scaleCommand cli.Command BeforeEach(func() { appRunnerCommandFactoryConfig = command_factory.AppRunnerCommandFactoryConfig{ AppRunner: fakeAppRunner, AppExaminer: fakeAppExaminer, UI: terminalUI, Clock: fakeClock,
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(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"))
State: "COMPLETED", }, { 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")))
"github.com/cloudfoundry-incubator/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")) })