outputBuffer = gbytes.NewBuffer()
		terminalUI = terminal.NewUI(nil, outputBuffer, nil)
		fakeExitHandler = &fake_exit_handler.FakeExitHandler{}
		fakeSecureShell = &fake_secure_shell.FakeSecureShell{}
	})

	Describe("SSHCommand", func() {
		var sshCommand cli.Command

		BeforeEach(func() {
			commandFactory := command_factory.NewSSHCommandFactory(config, terminalUI, fakeExitHandler, fakeSecureShell)
			sshCommand = commandFactory.MakeSSHCommand()
		})

		It("should ssh to instance 0 given an app name", func() {
			test_helpers.ExecuteCommandWithArgs(sshCommand, []string{"app-name"})

			Expect(outputBuffer).To(test_helpers.SayLine("Connecting to app-name/0 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(0))
			Expect(command).To(BeEmpty())
			Expect(actualConfig).To(Equal(config))
		})

		It("should ssh to instance index specified", func() {
			test_helpers.ExecuteCommandWithArgs(sshCommand, []string{"--instance", "2", "app-name"})

			Expect(outputBuffer).To(test_helpers.SayLine("Connecting to app-name/2 at %s", config.Target()))
	})

	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(newConfig.Receptor()).To(Equal("http://*****:*****@receptor.oldtarget.com"))
		}

		BeforeEach(func() {
			commandFactory := command_factory.NewConfigCommandFactory(config, terminalUI, fakeTargetVerifier, fakeBlobStoreVerifier, fakeExitHandler)
			targetCommand = commandFactory.MakeTargetCommand()

			config.SetTarget("oldtarget.com")
			config.SetLogin("olduser", "oldpass")
			Expect(config.Save()).To(Succeed())
		})

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

			It("outputs the current user and target host", func() {
				Expect(outputBuffer).To(test_helpers.SayLine("Target:\t\[email protected]"))
			})

			Context("when no username is set", func() {
				BeforeEach(func() {
					config.SetLogin("", "")
					Expect(config.Save()).To(Succeed())
				})

				It("only prints the target", func() {
					Expect(outputBuffer).To(test_helpers.SayLine("Target:\t\toldtarget.com"))
				})
	var fakeClusterTestRunner *fake_cluster_test_runner.FakeClusterTestRunner

	BeforeEach(func() {
		fakeClusterTestRunner = &fake_cluster_test_runner.FakeClusterTestRunner{}
	})

	Describe("MakeClusterTestCommand", func() {
		var clusterTestCommand cli.Command

		BeforeEach(func() {
			commandFactory := command_factory.NewClusterTestCommandFactory(fakeClusterTestRunner)
			clusterTestCommand = commandFactory.MakeClusterTestCommand()
		})

		It("prints the integration test run output and args", func() {
			test_helpers.ExecuteCommandWithArgs(clusterTestCommand, []string{"--timeout=50s", "--verbose=true"})

			Expect(fakeClusterTestRunner.RunCallCount()).To(Equal(1))
			timeoutArg, verboseArg := fakeClusterTestRunner.GetArgsForRun()
			Expect(timeoutArg).To(Equal(time.Second * 50))
			Expect(verboseArg).To(BeTrue())
		})

		It("has sane defaults", func() {
			test_helpers.ExecuteCommandWithArgs(clusterTestCommand, []string{})

			Expect(fakeClusterTestRunner.RunCallCount()).To(Equal(1))
			timeoutArg, verboseArg := fakeClusterTestRunner.GetArgsForRun()
			Expect(timeoutArg).To(Equal(time.Minute * 2))
			Expect(verboseArg).To(BeFalse())
		})
				prevDir, err = os.Getwd()
				Expect(err).ToNot(HaveOccurred())
				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()
	)

	BeforeEach(func() {
		commandRan = false

		cliCommand = cli.Command{
			Name: "exec",
			Action: func(*cli.Context) {
				commandRan = true
			},
		}
	})

	Describe("ExecuteCommandWithArgs", func() {
		It("executes the command", func() {
			test_helpers.ExecuteCommandWithArgs(cliCommand, []string{})

			Expect(commandRan).To(BeTrue())
		})
	})

	Describe("AsyncExecuteCommandWithArgs", func() {
		It("executes the command", func() {
			doneChan := test_helpers.AsyncExecuteCommandWithArgs(cliCommand, []string{})

			Eventually(doneChan, 3).Should(BeClosed())
			Expect(commandRan).To(BeTrue())
		})
	})
})
		Context("when the archive path is a file and exists", func() {
			var (
				tmpFile *os.File
				err     error
			)
			BeforeEach(func() {
				tmpDir := os.TempDir()
				tmpFile, err = ioutil.TempFile(tmpDir, "tmp_file")
				Expect(err).ToNot(HaveOccurred())
			})
			AfterEach(func() {
				os.RemoveAll(tmpFile.Name())
			})

			It("checks the file exists and calls the droplet runner", func() {
				test_helpers.ExecuteCommandWithArgs(uploadBitsCommand, []string{"droplet-name", tmpFile.Name()})

				Expect(outputBuffer).To(test_helpers.Say("Successfully uploaded droplet-name"))
				Expect(fakeDropletRunner.UploadBitsCallCount()).To(Equal(1))
				dropletName, uploadPath := fakeDropletRunner.UploadBitsArgsForCall(0)
				Expect(dropletName).To(Equal("droplet-name"))
				Expect(uploadPath).To(Equal(tmpFile.Name()))
			})

			Context("when the droplet runner returns an error", func() {
				It("prints the error", func() {
					fakeDropletRunner.UploadBitsReturns(errors.New("uploading bits failed"))

					test_helpers.ExecuteCommandWithArgs(uploadBitsCommand, []string{"droplet-name", tmpFile.Name()})

					Expect(outputBuffer).To(test_helpers.Say("Error uploading to droplet-name: uploading bits failed"))
		})

		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))
		fakeAppExaminer = &fake_app_examiner.FakeAppExaminer{}
		fakeSecureShell = &fake_secure_shell.FakeSecureShell{}
	})

	Describe("SSHCommand", func() {
		var sshCommand cli.Command

		BeforeEach(func() {
			commandFactory := command_factory.NewSSHCommandFactory(config, terminalUI, fakeExitHandler, fakeAppExaminer, fakeSecureShell)
			sshCommand = commandFactory.MakeSSHCommand()
		})

		It("should ssh to instance 0 given an app name", func() {
			fakeAppExaminer.AppStatusReturns(app_examiner.AppInfo{ActualRunningInstances: 1}, nil)

			test_helpers.ExecuteCommandWithArgs(sshCommand, []string{"app-name"})

			Expect(outputBuffer).To(test_helpers.SayLine("Connecting to app-name/0 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(0))
			Expect(command).To(BeEmpty())
			Expect(actualConfig).To(Equal(config))

			Expect(fakeAppExaminer.AppStatusCallCount()).To(Equal(1))
			Expect(fakeAppExaminer.AppStatusArgsForCall(0)).To(Equal("app-name"))
		})

		It("should ssh to instance index specified", func() {
예제 #10
0
			logsCommand = commandFactory.MakeLogsCommand()
		})

		It("tails logs", func() {
			appExaminer.AppExistsReturns(true, nil)

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

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

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

		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..."))
	BeforeEach(func() {
		fakeIntegrationTestRunner = fake_integration_test_runner.NewFakeIntegrationTestRunner()
	})

	Describe("MakeIntegrationTestCommand", func() {

		var integrationTestCommand cli.Command

		BeforeEach(func() {
			commandFactory := command_factory.NewIntegrationTestCommandFactory(fakeIntegrationTestRunner)
			integrationTestCommand = commandFactory.MakeIntegrationTestCommand()
		})

		It("prints the integration test run output and args", func() {
			test_helpers.ExecuteCommandWithArgs(integrationTestCommand, []string{"--timeout=50s", "--verbose=true", "--cli-help"})

			Expect(fakeIntegrationTestRunner.RunCallCount()).To(Equal(1))
			timeoutArg, verboseArg, cliHelpArg := fakeIntegrationTestRunner.GetArgsForRun()
			Expect(timeoutArg).To(Equal(time.Second * 50))
			Expect(verboseArg).To(Equal(true))
			Expect(cliHelpArg).To(Equal(true))
		})

		It("has sane defaults", func() {
			test_helpers.ExecuteCommandWithArgs(integrationTestCommand, []string{})

			Expect(fakeIntegrationTestRunner.RunCallCount()).To(Equal(1))
			timeoutArg, verboseArg, cliHelpArg := fakeIntegrationTestRunner.GetArgsForRun()
			Expect(timeoutArg).To(Equal(time.Minute * 2))
			Expect(verboseArg).To(BeFalse())
			commandFactory := command_factory.NewTaskExaminerCommandFactory(fakeTaskExaminer, terminalUI, fakeExitHandler)
			taskCommand = commandFactory.MakeTaskCommand()
		})

		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() {
	BeforeEach(func() {
		fakeClusterTestRunner = &fake_cluster_test_runner.FakeClusterTestRunner{}
	})

	Describe("MakeClusterTestCommand", func() {
		var clusterTestCommand cli.Command

		BeforeEach(func() {
			commandFactory := command_factory.NewClusterTestCommandFactory(fakeClusterTestRunner)
			clusterTestCommand = commandFactory.MakeClusterTestCommand()
		})

		It("prints the integration test run output and args", func() {
			args := []string{"--timeout=50s", "--verbose=true"}
			test_helpers.ExecuteCommandWithArgs(clusterTestCommand, args)

			Expect(fakeClusterTestRunner.RunCallCount()).To(Equal(1))
			timeoutArg, verboseArg := fakeClusterTestRunner.GetArgsForRun()
			Expect(timeoutArg).To(Equal(time.Second * 50))
			Expect(verboseArg).To(BeTrue())
		})

		It("has sane defaults", func() {
			test_helpers.ExecuteCommandWithArgs(clusterTestCommand, []string{})

			Expect(fakeClusterTestRunner.RunCallCount()).To(Equal(1))
			timeoutArg, verboseArg := fakeClusterTestRunner.GetArgsForRun()
			Expect(timeoutArg).To(Equal(time.Minute * 2))
			Expect(verboseArg).To(BeFalse())
		})
			buildDropletCommand = commandFactory.MakeBuildDropletCommand()
			fakeBlobStoreVerifier.VerifyReturns(true, nil)
		})

		Context("when the archive path is a folder and exists", func() {
			BeforeEach(func() {
				fakeCFIgnore.ShouldIgnoreStub = func(path string) bool {
					return path == "some-ignored-file"
				}
			})

			It("zips up current working folder and uploads as the droplet name", func() {
				fakeZipper.IsZipFileReturns(false)
				fakeZipper.ZipReturns("xyz.zip", nil)

				test_helpers.ExecuteCommandWithArgs(buildDropletCommand, []string{"droplet-name", "http://some.url/for/buildpack"})

				Expect(outputBuffer).To(test_helpers.SayLine("Uploading application bits..."))
				Expect(outputBuffer).To(test_helpers.SayLine("Uploaded."))

				Expect(fakeBlobStoreVerifier.VerifyCallCount()).To(Equal(1))
				Expect(fakeBlobStoreVerifier.VerifyArgsForCall(0)).To(Equal(config))

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

				Expect(uploadPath).NotTo(BeNil())
				Expect(uploadPath).To(Equal("xyz.zip"))
					FailureReason: "No compatible container",
					Result:        "Finished",
					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")))
		Context("when the json file exists", func() {
			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))
				prevDir, err = os.Getwd()
				Expect(err).ToNot(HaveOccurred())
				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()
				"--run-as-root=true",
				"--instances=22",
				"--env=TIMEZONE=CST",
				`--env=LANG="Chicago English"`,
				`--env=JAVA_OPTS="-Djava.arg=/dev/urandom"`,
				"--env=COLOR",
				"--env=UNSET",
				"--timeout=28s",
				"cool-web-app",
				"superfun/app:mycooltag",
				"--",
				"/start-me-please",
				"AppArg0",
				`--appFlavor="purple"`,
			}
			test_helpers.ExecuteCommandWithArgs(createCommand, args)

			Expect(fakeDockerMetadataFetcher.FetchMetadataCallCount()).To(Equal(1))
			Expect(fakeDockerMetadataFetcher.FetchMetadataArgsForCall(0)).To(Equal("superfun/app:mycooltag"))

			Expect(fakeAppRunner.CreateAppCallCount()).To(Equal(1))
			createAppParams := fakeAppRunner.CreateAppArgsForCall(0)
			Expect(createAppParams.Name).To(Equal("cool-web-app"))
			Expect(createAppParams.StartCommand).To(Equal("/start-me-please"))
			Expect(createAppParams.RootFS).To(Equal("docker:///superfun/app#mycooltag"))
			Expect(createAppParams.AppArgs).To(Equal([]string{"AppArg0", "--appFlavor=\"purple\""}))
			Expect(createAppParams.Instances).To(Equal(22))
			Expect(createAppParams.EnvironmentVariables).To(Equal(map[string]string{
				"DOCKER":       "ME",
				"TIMEZONE":     "CST",
				"LANG":         `"Chicago English"`,
	})

	Describe("SSHCommand", func() {
		var sshCommand cli.Command

		BeforeEach(func() {
			commandFactory := command_factory.NewSSHCommandFactory(config, terminalUI, fakeExitHandler, fakeAppExaminer, fakeSSH)
			sshCommand = commandFactory.MakeSSHCommand()
		})

		Context("when connecting fails", func() {
			It("should print an error", func() {
				fakeAppExaminer.AppStatusReturns(app_examiner.AppInfo{ActualRunningInstances: 1}, nil)
				fakeSSH.ConnectReturns(errors.New("connection failed"))

				test_helpers.ExecuteCommandWithArgs(sshCommand, []string{"good-name"})

				Expect(outputBuffer).To(test_helpers.SayLine("Error connecting to good-name/0: connection failed"))

				Expect(fakeSSH.ConnectCallCount()).To(Equal(1))
				Expect(fakeSSH.ForwardCallCount()).To(Equal(0))
				Expect(fakeSSH.ShellCallCount()).To(Equal(0))
				Expect(fakeExitHandler.ExitCalledWith).To(Equal([]int{exit_codes.CommandFailed}))
			})
		})

		Describe("port forwarding", func() {
			It("should forward a local port to a remote host and port", func() {
				fakeAppExaminer.AppStatusReturns(app_examiner.AppInfo{ActualRunningInstances: 1}, nil)

				test_helpers.ExecuteCommandWithArgs(sshCommand, []string{"app-name", "-N", "-L", "mrlocalhost:1234:remotehost:5678"})