github.com/wanddynosios/cli/v8@v8.7.9-0.20240221182337-1a92e3a7017f/command/v7/login_command_test.go (about)

     1  package v7_test
     2  
     3  import (
     4  	"errors"
     5  	"fmt"
     6  	"io"
     7  
     8  	"code.cloudfoundry.org/cli/actor/actionerror"
     9  	"code.cloudfoundry.org/cli/actor/v7action"
    10  	"code.cloudfoundry.org/cli/api/cloudcontroller/ccerror"
    11  	"code.cloudfoundry.org/cli/api/uaa"
    12  	"code.cloudfoundry.org/cli/api/uaa/constant"
    13  	"code.cloudfoundry.org/cli/cf/configuration/coreconfig"
    14  	"code.cloudfoundry.org/cli/command/commandfakes"
    15  	"code.cloudfoundry.org/cli/command/translatableerror"
    16  	. "code.cloudfoundry.org/cli/command/v7"
    17  	"code.cloudfoundry.org/cli/command/v7/v7fakes"
    18  	"code.cloudfoundry.org/cli/resources"
    19  	"code.cloudfoundry.org/cli/util/configv3"
    20  	"code.cloudfoundry.org/cli/util/ui"
    21  	. "github.com/onsi/ginkgo"
    22  	. "github.com/onsi/gomega"
    23  	. "github.com/onsi/gomega/gbytes"
    24  )
    25  
    26  var _ = Describe("login Command", func() {
    27  	var (
    28  		binaryName        string
    29  		cmd               LoginCommand
    30  		testUI            *ui.UI
    31  		fakeActor         *v7fakes.FakeActor
    32  		fakeConfig        *commandfakes.FakeConfig
    33  		fakeActorReloader *v7fakes.FakeActorReloader
    34  		executeErr        error
    35  		input             *Buffer
    36  	)
    37  
    38  	BeforeEach(func() {
    39  		input = NewBuffer()
    40  		testUI = ui.NewTestUI(input, NewBuffer(), NewBuffer())
    41  		fakeConfig = new(commandfakes.FakeConfig)
    42  		fakeActor = new(v7fakes.FakeActor)
    43  		fakeActorReloader = new(v7fakes.FakeActorReloader)
    44  
    45  		binaryName = "some-executable"
    46  		fakeConfig.BinaryNameReturns(binaryName)
    47  
    48  		fakeConfig.UAAOAuthClientReturns("cf")
    49  
    50  		cmd = LoginCommand{
    51  			UI:            testUI,
    52  			Actor:         fakeActor,
    53  			Config:        fakeConfig,
    54  			ActorReloader: fakeActorReloader,
    55  		}
    56  		cmd.APIEndpoint = ""
    57  
    58  		fakeActorReloader.ReloadReturns(fakeActor, nil)
    59  		fakeConfig.APIVersionReturns("3.99.0")
    60  	})
    61  
    62  	JustBeforeEach(func() {
    63  		executeErr = cmd.Execute(nil)
    64  	})
    65  
    66  	Describe("Validations", func() {
    67  		When("the --sso and the --origin flag are used together", func() {
    68  			BeforeEach(func() {
    69  				cmd.SSO = true
    70  				cmd.Origin = "some-origin"
    71  			})
    72  
    73  			It("returns an error", func() {
    74  				Expect(executeErr).To(MatchError(translatableerror.ArgumentCombinationError{
    75  					Args: []string{"--sso", "--origin"},
    76  				}))
    77  			})
    78  		})
    79  
    80  		When("the --sso-passcode and the --origin flag are used together", func() {
    81  			BeforeEach(func() {
    82  				cmd.SSOPasscode = "some-passcode"
    83  				cmd.Origin = "some-origin"
    84  			})
    85  
    86  			It("returns an error", func() {
    87  				Expect(executeErr).To(MatchError(translatableerror.ArgumentCombinationError{
    88  					Args: []string{"--sso-passcode", "--origin"},
    89  				}))
    90  			})
    91  		})
    92  
    93  		When("the --sso and the --sso-passcode flag are used together", func() {
    94  			BeforeEach(func() {
    95  				cmd.SSO = true
    96  				cmd.SSOPasscode = "some-passcode"
    97  			})
    98  
    99  			It("returns an error", func() {
   100  				Expect(executeErr).To(MatchError(translatableerror.ArgumentCombinationError{
   101  					Args: []string{"--sso-passcode", "--sso"},
   102  				}))
   103  			})
   104  		})
   105  
   106  		When("the user has manually added their client credentials", func() {
   107  			BeforeEach(func() {
   108  				fakeConfig.UAAOAuthClientReturns("some-other-client-id")
   109  				fakeConfig.UAAOAuthClientSecretReturns("some-secret")
   110  			})
   111  
   112  			It("returns an unsupported error", func() {
   113  				Expect(executeErr).To(MatchError(translatableerror.ManualClientCredentialsError{}))
   114  			})
   115  		})
   116  
   117  		When("the current grant type is client credentials", func() {
   118  			BeforeEach(func() {
   119  				fakeConfig.UAAGrantTypeReturns(string(constant.GrantTypeClientCredentials))
   120  			})
   121  
   122  			It("returns an error", func() {
   123  				Expect(executeErr).To(MatchError(translatableerror.PasswordGrantTypeLogoutRequiredError{}))
   124  			})
   125  		})
   126  
   127  		When("running against cf-on-k8s API", func() {
   128  			BeforeEach(func() {
   129  				fakeConfig.IsCFOnK8sReturns(true)
   130  				fakeConfig.TargetReturns("https://foo.bar")
   131  			})
   132  
   133  			When("sso flag is provided", func() {
   134  				BeforeEach(func() {
   135  					cmd.SSO = true
   136  				})
   137  
   138  				It("returns unsupported flag error", func() {
   139  					Expect(executeErr).To(Equal(translatableerror.NotSupportedOnKubernetesArgumentError{Arg: "--sso"}))
   140  				})
   141  			})
   142  
   143  			When("sso passcode flag is provided", func() {
   144  				BeforeEach(func() {
   145  					cmd.SSOPasscode = "sso-pass"
   146  				})
   147  
   148  				It("returns unsupported flag error", func() {
   149  					Expect(executeErr).To(Equal(translatableerror.NotSupportedOnKubernetesArgumentError{Arg: "--sso-passcode"}))
   150  				})
   151  			})
   152  
   153  			When("origin flag is provided", func() {
   154  				BeforeEach(func() {
   155  					cmd.Origin = "my-origin"
   156  				})
   157  
   158  				It("returns unsupported flag error", func() {
   159  					Expect(executeErr).To(Equal(translatableerror.NotSupportedOnKubernetesArgumentError{Arg: "--origin"}))
   160  				})
   161  			})
   162  		})
   163  	})
   164  
   165  	Describe("API Endpoint", func() {
   166  		When("user provides the api endpoint using the -a flag", func() {
   167  			BeforeEach(func() {
   168  				fakeActor.SetTargetReturns(v7action.Warnings{"some-warning-1", "some-warning-2"}, nil)
   169  				cmd.APIEndpoint = "api.example.com"
   170  			})
   171  
   172  			It("targets the provided api endpoint and prints all warnings", func() {
   173  				Expect(executeErr).ToNot(HaveOccurred())
   174  				Expect(fakeActor.SetTargetCallCount()).To(Equal(1))
   175  
   176  				actualSettings := fakeActor.SetTargetArgsForCall(0)
   177  				Expect(actualSettings.URL).To(Equal("https://api.example.com"))
   178  				Expect(actualSettings.SkipSSLValidation).To(Equal(false))
   179  
   180  				Expect(testUI.Err).To(Say("some-warning-1"))
   181  				Expect(testUI.Err).To(Say("some-warning-2"))
   182  			})
   183  
   184  			When("the user specifies --skip-ssl-validation", func() {
   185  				BeforeEach(func() {
   186  					cmd.SkipSSLValidation = true
   187  				})
   188  
   189  				It("targets the provided api endpoint", func() {
   190  					Expect(executeErr).ToNot(HaveOccurred())
   191  
   192  					actualSettings := fakeActor.SetTargetArgsForCall(0)
   193  					Expect(actualSettings.URL).To(Equal("https://api.example.com"))
   194  					Expect(actualSettings.SkipSSLValidation).To(Equal(true))
   195  				})
   196  			})
   197  
   198  			When("targeting the API fails", func() {
   199  				BeforeEach(func() {
   200  					fakeActor.SetTargetReturns(
   201  						v7action.Warnings{"some-warning-1", "some-warning-2"},
   202  						errors.New("some error"))
   203  				})
   204  
   205  				It("errors and prints all warnings", func() {
   206  					Expect(executeErr).To(MatchError("some error"))
   207  					Expect(testUI.Err).To(Say("some-warning-1"))
   208  					Expect(testUI.Err).To(Say("some-warning-2"))
   209  				})
   210  			})
   211  		})
   212  
   213  		When("user does not provide the api endpoint using the -a flag", func() {
   214  			When("config has API endpoint already set", func() {
   215  				BeforeEach(func() {
   216  					fakeConfig.TargetReturns("api.fake.com")
   217  				})
   218  
   219  				It("uses the API endpoint from the config", func() {
   220  					Expect(executeErr).ToNot(HaveOccurred())
   221  					Expect(fakeActor.SetTargetCallCount()).To(Equal(1))
   222  
   223  					actualSettings := fakeActor.SetTargetArgsForCall(0)
   224  					Expect(actualSettings.URL).To(Equal("https://api.fake.com"))
   225  				})
   226  
   227  				When("the API version is older than the minimum supported API version for the v7 CLI", func() {
   228  					BeforeEach(func() {
   229  						fakeConfig.APIVersionReturns("3.83.0")
   230  					})
   231  					It("warns that the user is targeting an unsupported API version and that things may not work correctly", func() {
   232  						Expect(testUI.Err).To(Say("Warning: Your targeted API's version \\(3.83.0\\) is less than the minimum supported API version \\(3.99.0\\). Some commands may not function correctly."))
   233  					})
   234  				})
   235  
   236  				When("the API version is empty", func() {
   237  					BeforeEach(func() {
   238  						fakeConfig.APIVersionReturns("")
   239  					})
   240  					It("prints a warning message", func() {
   241  						Expect(executeErr).ToNot(HaveOccurred())
   242  						Expect(testUI.Err).To(Say("Warning: unable to determine whether targeted API's version meets minimum supported."))
   243  					})
   244  				})
   245  
   246  				It("should NOT warn that the user is targeting an unsupported API version", func() {
   247  					Expect(testUI.Err).ToNot(Say("is less than the minimum supported API version"))
   248  				})
   249  
   250  				When("the config has SkipSSLValidation false and the --skip-ssl-validation flag is passed", func() {
   251  					BeforeEach(func() {
   252  						fakeConfig.SkipSSLValidationReturns(false)
   253  						cmd.SkipSSLValidation = true
   254  					})
   255  
   256  					It("sets the target with SkipSSLValidation is true", func() {
   257  						Expect(executeErr).ToNot(HaveOccurred())
   258  						Expect(fakeActor.SetTargetCallCount()).To(Equal(1))
   259  						targetSettings := fakeActor.SetTargetArgsForCall(0)
   260  						Expect(targetSettings.SkipSSLValidation).To(BeTrue())
   261  					})
   262  				})
   263  			})
   264  
   265  			When("config does not have an API endpoint set and the user enters the endpoint at the prompt", func() {
   266  				BeforeEach(func() {
   267  					cmd.APIEndpoint = ""
   268  					_, err := input.Write([]byte("api.example.com\n"))
   269  					Expect(err).ToNot(HaveOccurred())
   270  					fakeConfig.TargetReturnsOnCall(0, "")
   271  					fakeConfig.TargetReturnsOnCall(1, "https://api.example.com")
   272  				})
   273  
   274  				It("targets the API that the user inputted", func() {
   275  					Expect(executeErr).ToNot(HaveOccurred())
   276  					Expect(fakeActor.SetTargetCallCount()).To(Equal(1))
   277  					actualSettings := fakeActor.SetTargetArgsForCall(0)
   278  					Expect(actualSettings.URL).To(Equal("https://api.example.com"))
   279  					Expect(actualSettings.SkipSSLValidation).To(Equal(false))
   280  					Expect(fakeConfig.TargetCallCount()).To(Equal(2))
   281  				})
   282  
   283  				When("the user specifies --skip-ssl-validation", func() {
   284  					BeforeEach(func() {
   285  						cmd.SkipSSLValidation = true
   286  					})
   287  
   288  					It("targets the API that the user inputted", func() {
   289  						Expect(executeErr).ToNot(HaveOccurred())
   290  
   291  						actualSettings := fakeActor.SetTargetArgsForCall(0)
   292  						Expect(actualSettings.SkipSSLValidation).To(Equal(true))
   293  					})
   294  				})
   295  			})
   296  		})
   297  
   298  		When("the endpoint has trailing slashes", func() {
   299  			BeforeEach(func() {
   300  				cmd.APIEndpoint = "api.example.com////"
   301  				fakeConfig.TargetReturns("https://api.example.com///")
   302  			})
   303  
   304  			It("strips the backslashes before using the endpoint", func() {
   305  				Expect(executeErr).ToNot(HaveOccurred())
   306  				Expect(fakeActor.SetTargetCallCount()).To(Equal(1))
   307  				actualSettings := fakeActor.SetTargetArgsForCall(0)
   308  				Expect(actualSettings.URL).To(Equal("https://api.example.com"))
   309  			})
   310  		})
   311  
   312  		When("targeting the API fails due to an invalid certificate", func() {
   313  			BeforeEach(func() {
   314  				cmd.APIEndpoint = "api.example.com"
   315  				fakeActor.SetTargetReturns(nil, ccerror.UnverifiedServerError{URL: "https://api.example.com"})
   316  			})
   317  
   318  			It("returns an error mentioning the login command", func() {
   319  				Expect(executeErr).To(MatchError(
   320  					translatableerror.InvalidSSLCertError{URL: "https://api.example.com", SuggestedCommand: "login"}))
   321  			})
   322  		})
   323  	})
   324  
   325  	Describe("username and password", func() {
   326  		BeforeEach(func() {
   327  			fakeConfig.TargetReturns("https://some.random.endpoint")
   328  		})
   329  
   330  		When("the current grant type is password", func() {
   331  			BeforeEach(func() {
   332  				fakeConfig.UAAGrantTypeReturns(string(constant.GrantTypePassword))
   333  			})
   334  
   335  			It("fetches prompts from the UAA", func() {
   336  				Expect(executeErr).ToNot(HaveOccurred())
   337  				Expect(fakeActor.GetLoginPromptsCallCount()).To(Equal(1))
   338  			})
   339  
   340  			When("one of the prompts has a username key and is text type", func() {
   341  				BeforeEach(func() {
   342  					fakeActor.GetLoginPromptsReturns(map[string]coreconfig.AuthPrompt{
   343  						"username": {
   344  							DisplayName: "Username",
   345  							Type:        coreconfig.AuthPromptTypeText,
   346  						},
   347  					}, nil)
   348  				})
   349  
   350  				When("the username flag is set", func() {
   351  					BeforeEach(func() {
   352  						cmd.Username = "potatoface"
   353  					})
   354  
   355  					It("uses the provided value for the username", func() {
   356  						Expect(executeErr).ToNot(HaveOccurred())
   357  						Expect(fakeActor.AuthenticateCallCount()).To(Equal(1))
   358  						credentials, _, _ := fakeActor.AuthenticateArgsForCall(0)
   359  						Expect(credentials["username"]).To(Equal("potatoface"))
   360  					})
   361  
   362  					When("the --origin flag is set", func() {
   363  						BeforeEach(func() {
   364  							cmd.Origin = "picklebike"
   365  						})
   366  
   367  						It("authenticates with the specified origin", func() {
   368  							Expect(executeErr).NotTo(HaveOccurred())
   369  							Expect(fakeActor.AuthenticateCallCount()).To(Equal(1))
   370  							credentials, origin, _ := fakeActor.AuthenticateArgsForCall(0)
   371  							Expect(credentials["username"]).To(Equal("potatoface"))
   372  							Expect(origin).To(Equal("picklebike"))
   373  						})
   374  					})
   375  				})
   376  			})
   377  
   378  			When("one of the prompts has password key and is password type", func() {
   379  				BeforeEach(func() {
   380  					fakeActor.GetLoginPromptsReturns(map[string]coreconfig.AuthPrompt{
   381  						"password": {
   382  							DisplayName: "Your Password",
   383  							Type:        coreconfig.AuthPromptTypePassword,
   384  						},
   385  					}, nil)
   386  				})
   387  
   388  				When("the password flag is set", func() {
   389  					BeforeEach(func() {
   390  						cmd.Password = "noprompto"
   391  					})
   392  
   393  					It("uses the provided value", func() {
   394  						Expect(executeErr).ToNot(HaveOccurred())
   395  						Expect(fakeActor.AuthenticateCallCount()).To(Equal(1))
   396  						credentials, _, _ := fakeActor.AuthenticateArgsForCall(0)
   397  						Expect(credentials["password"]).To(Equal("noprompto"))
   398  					})
   399  
   400  					When("the password is incorrect", func() {
   401  						BeforeEach(func() {
   402  							_, err := input.Write([]byte("other-password\n"))
   403  							Expect(err).ToNot(HaveOccurred())
   404  							fakeActor.AuthenticateReturnsOnCall(0, errors.New("bad creds"))
   405  							fakeActor.AuthenticateReturnsOnCall(1, nil)
   406  						})
   407  
   408  						It("does not reuse the flag value for subsequent attempts", func() {
   409  							credentials, _, _ := fakeActor.AuthenticateArgsForCall(1)
   410  							Expect(credentials["password"]).To(Equal("other-password"))
   411  						})
   412  					})
   413  
   414  					When("there have been too many failed login attempts", func() {
   415  						BeforeEach(func() {
   416  							_, err := input.Write([]byte("other-password\n"))
   417  							Expect(err).ToNot(HaveOccurred())
   418  							fakeActor.AuthenticateReturns(
   419  								uaa.AccountLockedError{
   420  									Message: "Your account has been locked because of too many failed attempts to login.",
   421  								},
   422  							)
   423  						})
   424  
   425  						It("does not reuse the flag value for subsequent attempts", func() {
   426  							Expect(fakeActor.AuthenticateCallCount()).To(Equal(1), "called Authenticate again after lockout")
   427  							Expect(testUI.Err).To(Say("Your account has been locked because of too many failed attempts to login."))
   428  						})
   429  					})
   430  				})
   431  			})
   432  
   433  			When("UAA prompts for the SSO passcode during non-SSO flow", func() {
   434  				BeforeEach(func() {
   435  					cmd.SSO = false
   436  					cmd.Password = "some-password"
   437  					fakeActor.GetLoginPromptsReturns(map[string]coreconfig.AuthPrompt{
   438  						"password": {
   439  							DisplayName: "Your Password",
   440  							Type:        coreconfig.AuthPromptTypePassword,
   441  						},
   442  						"passcode": {
   443  							DisplayName: "gimme your passcode",
   444  							Type:        coreconfig.AuthPromptTypePassword,
   445  						},
   446  					}, nil)
   447  				})
   448  
   449  				It("does not prompt for the passcode, only the password", func() {
   450  					Expect(executeErr).ToNot(HaveOccurred())
   451  					Expect(testUI.Out).NotTo(Say("gimme your passcode"))
   452  					credentials, _, _ := fakeActor.AuthenticateArgsForCall(0)
   453  					Expect(credentials).To(HaveKeyWithValue("password", "some-password"))
   454  					Expect(credentials).NotTo(HaveKey("passcode"))
   455  				})
   456  			})
   457  
   458  			When("multiple prompts of text and password type are returned", func() {
   459  				BeforeEach(func() {
   460  					fakeActor.GetLoginPromptsReturns(map[string]coreconfig.AuthPrompt{
   461  						"account_number": {
   462  							DisplayName: "Account Number",
   463  							Type:        coreconfig.AuthPromptTypeText,
   464  						},
   465  						"username": {
   466  							DisplayName: "Username",
   467  							Type:        coreconfig.AuthPromptTypeText,
   468  						},
   469  						"passcode": {
   470  							DisplayName: "It's a passcode, what you want it to be???",
   471  							Type:        coreconfig.AuthPromptTypePassword,
   472  						},
   473  						"password": {
   474  							DisplayName: "Your Password",
   475  							Type:        coreconfig.AuthPromptTypePassword,
   476  						},
   477  						"supersecret": {
   478  							DisplayName: "MFA Code",
   479  							Type:        coreconfig.AuthPromptTypePassword,
   480  						},
   481  					}, nil)
   482  				})
   483  
   484  				When("all authentication information is coming from prompts, not flags", func() {
   485  					BeforeEach(func() {
   486  						_, err := input.Write([]byte("faker\nsomeaccount\nsomepassword\ngarbage\n"))
   487  						Expect(err).ToNot(HaveOccurred())
   488  					})
   489  
   490  					It("displays text prompts, starting with username, then password prompts, starting with password", func() {
   491  						Expect(executeErr).ToNot(HaveOccurred())
   492  
   493  						Expect(testUI.Out).To(Say("\n"))
   494  						Expect(testUI.Out).To(Say("Username:"))
   495  						Expect(testUI.Out).To(Say("faker"))
   496  
   497  						Expect(testUI.Out).To(Say("\n"))
   498  						Expect(testUI.Out).To(Say("Account Number:"))
   499  						Expect(testUI.Out).To(Say("someaccount"))
   500  
   501  						Expect(testUI.Out).To(Say("\n"))
   502  						Expect(testUI.Out).To(Say("Your Password:"))
   503  						Expect(testUI.Out).NotTo(Say("somepassword"))
   504  
   505  						Expect(testUI.Out).To(Say("\n"))
   506  						Expect(testUI.Out).To(Say("MFA Code:"))
   507  						Expect(testUI.Out).NotTo(Say("garbage"))
   508  					})
   509  
   510  					It("authenticates with the responses", func() {
   511  						Expect(fakeActor.AuthenticateCallCount()).To(Equal(1))
   512  						credentials, _, grantType := fakeActor.AuthenticateArgsForCall(0)
   513  						Expect(credentials["username"]).To(Equal("faker"))
   514  						Expect(credentials["password"]).To(Equal("somepassword"))
   515  						Expect(credentials["supersecret"]).To(Equal("garbage"))
   516  						Expect(grantType).To(Equal(constant.GrantTypePassword))
   517  					})
   518  				})
   519  
   520  				When("an error occurs prompting for the username", func() {
   521  					var fakeUI *commandfakes.FakeUI
   522  
   523  					BeforeEach(func() {
   524  						fakeUI = new(commandfakes.FakeUI)
   525  						fakeUI.DisplayTextPromptReturns("", errors.New("some-error"))
   526  						cmd = LoginCommand{
   527  							UI:            fakeUI,
   528  							Actor:         fakeActor,
   529  							Config:        fakeConfig,
   530  							ActorReloader: fakeActorReloader,
   531  						}
   532  					})
   533  
   534  					It("stops prompting after the first prompt and errors", func() {
   535  						Expect(fakeUI.DisplayTextPromptCallCount()).To(Equal(1))
   536  						Expect(executeErr).To(MatchError("Unable to authenticate."))
   537  					})
   538  				})
   539  
   540  				When("an error occurs in an additional text prompt after username", func() {
   541  					var fakeUI *commandfakes.FakeUI
   542  
   543  					BeforeEach(func() {
   544  						fakeUI = new(commandfakes.FakeUI)
   545  						fakeUI.DisplayTextPromptReturnsOnCall(0, "some-name", nil)
   546  						fakeUI.DisplayTextPromptReturnsOnCall(1, "", errors.New("some-error"))
   547  						cmd = LoginCommand{
   548  							UI:            fakeUI,
   549  							Actor:         fakeActor,
   550  							Config:        fakeConfig,
   551  							ActorReloader: fakeActorReloader,
   552  						}
   553  					})
   554  
   555  					It("returns the error", func() {
   556  						Expect(executeErr).To(MatchError("Unable to authenticate."))
   557  					})
   558  				})
   559  
   560  				When("an error occurs prompting for the password", func() {
   561  					var fakeUI *commandfakes.FakeUI
   562  
   563  					BeforeEach(func() {
   564  						fakeUI = new(commandfakes.FakeUI)
   565  						fakeUI.DisplayPasswordPromptReturns("", errors.New("some-error"))
   566  						cmd = LoginCommand{
   567  							UI:            fakeUI,
   568  							Actor:         fakeActor,
   569  							Config:        fakeConfig,
   570  							ActorReloader: fakeActorReloader,
   571  						}
   572  					})
   573  
   574  					It("stops prompting after the first prompt and errors", func() {
   575  						Expect(fakeUI.DisplayPasswordPromptCallCount()).To(Equal(1))
   576  						Expect(executeErr).To(MatchError("Unable to authenticate."))
   577  					})
   578  				})
   579  
   580  				When("an error occurs prompting for prompts of type password that are not the 'password'", func() {
   581  					var fakeUI *commandfakes.FakeUI
   582  
   583  					BeforeEach(func() {
   584  						fakeUI = new(commandfakes.FakeUI)
   585  						fakeUI.DisplayPasswordPromptReturnsOnCall(0, "some-password", nil)
   586  						fakeUI.DisplayPasswordPromptReturnsOnCall(1, "", errors.New("some-error"))
   587  
   588  						cmd = LoginCommand{
   589  							UI:            fakeUI,
   590  							Actor:         fakeActor,
   591  							Config:        fakeConfig,
   592  							ActorReloader: fakeActorReloader,
   593  						}
   594  					})
   595  
   596  					It("stops prompting after the second prompt and errors", func() {
   597  						Expect(executeErr).To(MatchError("Unable to authenticate."))
   598  					})
   599  				})
   600  
   601  				When("authenticating succeeds", func() {
   602  					BeforeEach(func() {
   603  						fakeActor.GetCurrentUserReturns(configv3.User{Name: "potatoface"}, nil)
   604  						_, err := input.Write([]byte("faker\nsomeaccount\nsomepassword\ngarbage\n"))
   605  						Expect(err).ToNot(HaveOccurred())
   606  					})
   607  
   608  					It("displays OK and a status summary", func() {
   609  						Expect(executeErr).ToNot(HaveOccurred())
   610  						Expect(testUI.Out).To(Say("OK"))
   611  						Expect(testUI.Out).To(Say(`API endpoint:\s+%s`, cmd.APIEndpoint))
   612  						Expect(testUI.Out).To(Say(`user:\s+potatoface`))
   613  
   614  						Expect(fakeActor.AuthenticateCallCount()).To(Equal(1))
   615  					})
   616  				})
   617  
   618  				When("authenticating fails", func() {
   619  					BeforeEach(func() {
   620  						fakeActor.AuthenticateReturns(errors.New("something died"))
   621  						_, err := input.Write([]byte("faker\nsomeaccount\nsomepassword\ngarbage\nfaker\nsomeaccount\nsomepassword\ngarbage\nfaker\nsomeaccount\nsomepassword\ngarbage\n"))
   622  						Expect(err).ToNot(HaveOccurred())
   623  					})
   624  
   625  					It("prints the error message three times", func() {
   626  						Expect(testUI.Out).To(Say("Your Password:"))
   627  						Expect(testUI.Out).To(Say("MFA Code:"))
   628  						Expect(testUI.Err).To(Say("something died"))
   629  						Expect(testUI.Out).To(Say("Your Password:"))
   630  						Expect(testUI.Out).To(Say("MFA Code:"))
   631  						Expect(testUI.Err).To(Say("something died"))
   632  						Expect(testUI.Out).To(Say("Your Password:"))
   633  						Expect(testUI.Out).To(Say("MFA Code:"))
   634  						Expect(testUI.Err).To(Say("something died"))
   635  
   636  						Expect(executeErr).To(MatchError("Unable to authenticate."))
   637  						Expect(fakeActor.AuthenticateCallCount()).To(Equal(3))
   638  					})
   639  
   640  					It("displays a status summary", func() {
   641  						Expect(testUI.Out).To(Say(`API endpoint:\s+%s`, cmd.APIEndpoint))
   642  						Expect(testUI.Out).To(Say(`Not logged in. Use '%s login' or '%s login --sso' to log in.`, cmd.Config.BinaryName(), cmd.Config.BinaryName()))
   643  					})
   644  				})
   645  
   646  				When("authenticating fails with a bad credentials error", func() {
   647  					BeforeEach(func() {
   648  						fakeActor.AuthenticateReturns(uaa.UnauthorizedError{Message: "Bad credentials"})
   649  						_, err := input.Write([]byte("faker\nsomeaccount\nsomepassword\ngarbage\nfaker\nsomeaccount\nsomepassword\ngarbage\nfaker\nsomeaccount\nsomepassword\ngarbage\n"))
   650  						Expect(err).ToNot(HaveOccurred())
   651  					})
   652  
   653  					It("converts the error before printing it", func() {
   654  						Expect(testUI.Out).To(Say("Your Password:"))
   655  						Expect(testUI.Out).To(Say("MFA Code:"))
   656  						Expect(testUI.Err).To(Say("Credentials were rejected, please try again."))
   657  						Expect(testUI.Out).To(Say("Your Password:"))
   658  						Expect(testUI.Out).To(Say("MFA Code:"))
   659  						Expect(testUI.Err).To(Say("Credentials were rejected, please try again."))
   660  						Expect(testUI.Out).To(Say("Your Password:"))
   661  						Expect(testUI.Out).To(Say("MFA Code:"))
   662  						Expect(testUI.Err).To(Say("Credentials were rejected, please try again."))
   663  					})
   664  				})
   665  			})
   666  		})
   667  
   668  		When("authenticating against Korifi", func() {
   669  			BeforeEach(func() {
   670  				fakeConfig.IsCFOnK8sReturns(true)
   671  				k8sLoginPrompts := map[string]coreconfig.AuthPrompt{
   672  					"username": {
   673  						Type:        coreconfig.AuthPromptTypeMenu,
   674  						Entries:     []string{"myuser", "overly-powerful-admin"},
   675  						DisplayName: "Choose your Kubernetes authentication info",
   676  					},
   677  				}
   678  				fakeActor.GetLoginPromptsReturns(k8sLoginPrompts, nil)
   679  			})
   680  
   681  			When("the user selects a valid username", func() {
   682  				BeforeEach(func() {
   683  					_, err := input.Write([]byte("1\n"))
   684  					Expect(err).ToNot(HaveOccurred())
   685  				})
   686  
   687  				It("prompts the user with available k8s usernames", func() {
   688  					Expect(executeErr).NotTo(HaveOccurred())
   689  
   690  					Expect(testUI.Out).To(Say("myuser"))
   691  					Expect(testUI.Out).To(Say("overly-powerful-admin"))
   692  					Expect(testUI.Out).To(Say("Choose your Kubernetes authentication info"))
   693  				})
   694  
   695  				It("authenticates with the chosen user", func() {
   696  					Expect(executeErr).NotTo(HaveOccurred())
   697  
   698  					Expect(fakeActor.AuthenticateCallCount()).To(Equal(1))
   699  					credentials, _, _ := fakeActor.AuthenticateArgsForCall(0)
   700  					Expect(credentials).To(Equal(map[string]string{
   701  						"username": "myuser",
   702  					}))
   703  				})
   704  			})
   705  
   706  			When("the user selects an invalid username", func() {
   707  				BeforeEach(func() {
   708  					_, err := input.Write([]byte("3\n"))
   709  					Expect(err).ToNot(HaveOccurred())
   710  				})
   711  
   712  				It("errors", func() {
   713  					Expect(executeErr).To(MatchError("Unable to authenticate."))
   714  					Expect(fakeActor.AuthenticateCallCount()).To(Equal(0))
   715  				})
   716  			})
   717  
   718  			When("the username flag is set", func() {
   719  				BeforeEach(func() {
   720  					cmd.Username = "myuser"
   721  				})
   722  
   723  				It("sets that username in the credentials", func() {
   724  					Expect(executeErr).ToNot(HaveOccurred())
   725  					Expect(fakeActor.AuthenticateCallCount()).To(Equal(1))
   726  					credentials, _, _ := fakeActor.AuthenticateArgsForCall(0)
   727  					Expect(credentials).To(Equal(map[string]string{
   728  						"username": "myuser",
   729  					}))
   730  
   731  					Expect(testUI.Out).NotTo(Say("Choose your Kubernetes authentication info"))
   732  				})
   733  
   734  				When("the password flag is also set", func() {
   735  					BeforeEach(func() {
   736  						cmd.Password = "should-be-ignored"
   737  					})
   738  
   739  					It("succeeds and sets only the username in the credentials", func() {
   740  						Expect(executeErr).ToNot(HaveOccurred())
   741  						Expect(fakeActor.AuthenticateCallCount()).To(Equal(1))
   742  						credentials, _, _ := fakeActor.AuthenticateArgsForCall(0)
   743  						Expect(credentials).To(Equal(map[string]string{
   744  							"username": "myuser",
   745  						}))
   746  					})
   747  
   748  					It("displays a warning that password will be ignored", func() {
   749  						Expect(executeErr).ToNot(HaveOccurred())
   750  						Expect(testUI.Err).To(Say("Warning: password is ignored when authenticating against Kubernetes."))
   751  					})
   752  				})
   753  
   754  				When("authentication fails", func() {
   755  					BeforeEach(func() {
   756  						fakeActor.AuthenticateReturns(errors.New("boom"))
   757  					})
   758  
   759  					It("errors", func() {
   760  						Expect(executeErr).To(MatchError("Unable to authenticate."))
   761  					})
   762  				})
   763  			})
   764  		})
   765  	})
   766  
   767  	Describe("SSO Passcode", func() {
   768  		fakeAPI := "whatever.com"
   769  		BeforeEach(func() {
   770  			fakeConfig.TargetReturns(fakeAPI)
   771  
   772  			_, err := input.Write([]byte("some-passcode\n"))
   773  			Expect(err).ToNot(HaveOccurred())
   774  			fakeActor.GetLoginPromptsReturns(map[string]coreconfig.AuthPrompt{
   775  				"passcode": {
   776  					DisplayName: "some-sso-prompt",
   777  					Type:        coreconfig.AuthPromptTypePassword,
   778  				},
   779  			}, nil)
   780  
   781  			fakeActor.GetCurrentUserReturns(configv3.User{Name: "potatoface"}, nil)
   782  		})
   783  
   784  		When("--sso flag is set", func() {
   785  			BeforeEach(func() {
   786  				cmd.SSO = true
   787  			})
   788  
   789  			It("prompts the user for SSO passcode", func() {
   790  				Expect(executeErr).NotTo(HaveOccurred())
   791  				Expect(fakeActor.GetLoginPromptsCallCount()).To(Equal(1))
   792  				Expect(testUI.Out).To(Say("some-sso-prompt:"))
   793  			})
   794  
   795  			It("authenticates with the inputted code", func() {
   796  				Expect(testUI.Out).To(Say("OK"))
   797  				Expect(testUI.Out).To(Say(`API endpoint:\s+%s`, fakeAPI))
   798  				Expect(testUI.Out).To(Say(`user:\s+potatoface`))
   799  
   800  				Expect(fakeActor.AuthenticateCallCount()).To(Equal(1))
   801  				credentials, origin, grantType := fakeActor.AuthenticateArgsForCall(0)
   802  				Expect(credentials["passcode"]).To(Equal("some-passcode"))
   803  				Expect(origin).To(BeEmpty())
   804  				Expect(grantType).To(Equal(constant.GrantTypePassword))
   805  			})
   806  
   807  			When("an error occurs prompting for the code", func() {
   808  				var fakeUI *commandfakes.FakeUI
   809  
   810  				BeforeEach(func() {
   811  					fakeUI = new(commandfakes.FakeUI)
   812  					fakeUI.DisplayPasswordPromptReturns("", errors.New("some-error"))
   813  					cmd = LoginCommand{
   814  						UI:            fakeUI,
   815  						Actor:         fakeActor,
   816  						Config:        fakeConfig,
   817  						ActorReloader: fakeActorReloader,
   818  						SSO:           true,
   819  					}
   820  				})
   821  
   822  				It("errors", func() {
   823  					Expect(fakeUI.DisplayPasswordPromptCallCount()).To(Equal(1))
   824  					Expect(executeErr).To(MatchError("Unable to authenticate."))
   825  				})
   826  			})
   827  		})
   828  
   829  		When("the --sso-passcode flag is set", func() {
   830  			BeforeEach(func() {
   831  				cmd.SSOPasscode = "a-passcode"
   832  			})
   833  
   834  			It("does not prompt the user for SSO passcode", func() {
   835  				Expect(executeErr).NotTo(HaveOccurred())
   836  				Expect(testUI.Out).ToNot(Say("some-sso-prompt:"))
   837  			})
   838  
   839  			It("uses the flag value to authenticate", func() {
   840  				Expect(executeErr).NotTo(HaveOccurred())
   841  				Expect(fakeActor.AuthenticateCallCount()).To(Equal(1))
   842  				credentials, origin, grantType := fakeActor.AuthenticateArgsForCall(0)
   843  				Expect(credentials["passcode"]).To(Equal("a-passcode"))
   844  				Expect(origin).To(BeEmpty())
   845  				Expect(grantType).To(Equal(constant.GrantTypePassword))
   846  			})
   847  
   848  			It("displays a summary with user information", func() {
   849  				Expect(executeErr).NotTo(HaveOccurred())
   850  				Expect(testUI.Out).To(Say("OK"))
   851  				Expect(testUI.Out).To(Say(`API endpoint:\s+%s`, fakeAPI))
   852  				Expect(testUI.Out).To(Say(`user:\s+potatoface`))
   853  			})
   854  
   855  			When("an incorrect passcode is inputted", func() {
   856  				BeforeEach(func() {
   857  					cmd.SSOPasscode = "some-garbage"
   858  					fakeActor.AuthenticateReturns(uaa.UnauthorizedError{
   859  						Message: "Bad credentials",
   860  					})
   861  					fakeActor.GetCurrentUserReturns(configv3.User{}, nil)
   862  					_, err := input.Write([]byte("some-passcode\n"))
   863  					Expect(err).ToNot(HaveOccurred())
   864  				})
   865  
   866  				It("re-prompts two more times", func() {
   867  					Expect(testUI.Out).To(Say("some-sso-prompt:"))
   868  					Expect(testUI.Out).To(Say(`Authenticating\.\.\.`))
   869  					Expect(testUI.Err).To(Say("Credentials were rejected, please try again."))
   870  					Expect(testUI.Out).To(Say("some-sso-prompt:"))
   871  					Expect(testUI.Out).To(Say(`Authenticating\.\.\.`))
   872  					Expect(testUI.Err).To(Say("Credentials were rejected, please try again."))
   873  				})
   874  
   875  				It("returns an error message", func() {
   876  					Expect(executeErr).To(MatchError("Unable to authenticate."))
   877  				})
   878  
   879  				It("does not include user information in the summary", func() {
   880  					Expect(testUI.Out).To(Say(`API endpoint:\s+%s`, fakeAPI))
   881  					Expect(testUI.Out).To(Say(`Not logged in. Use '%s login' or '%s login --sso' to log in.`, cmd.Config.BinaryName(), cmd.Config.BinaryName()))
   882  				})
   883  			})
   884  		})
   885  
   886  		When("both --sso and --sso-passcode flags are set", func() {
   887  			BeforeEach(func() {
   888  				cmd.SSO = true
   889  				cmd.SSOPasscode = "a-passcode"
   890  			})
   891  
   892  			It("returns an error message", func() {
   893  				Expect(fakeActor.AuthenticateCallCount()).To(Equal(0))
   894  				Expect(executeErr).To(MatchError(translatableerror.ArgumentCombinationError{Args: []string{"--sso-passcode", "--sso"}}))
   895  			})
   896  		})
   897  	})
   898  
   899  	Describe("Config", func() {
   900  		When("a user has successfully authenticated", func() {
   901  			BeforeEach(func() {
   902  				cmd.APIEndpoint = "example.com"
   903  				cmd.Username = "some-user"
   904  				cmd.Password = "some-password"
   905  				fakeConfig.APIVersionReturns("3.4.5")
   906  				fakeActor.GetCurrentUserReturns(configv3.User{Name: "some-user"}, nil)
   907  			})
   908  
   909  			It("writes to the config", func() {
   910  				Expect(executeErr).ToNot(HaveOccurred())
   911  				Expect(fakeConfig.WriteConfigCallCount()).To(Equal(1))
   912  			})
   913  
   914  			When("GetOrganizations fails", func() {
   915  				BeforeEach(func() {
   916  					fakeActor.GetOrganizationsReturns(nil, nil, errors.New("Org Failure"))
   917  				})
   918  				It("writes to the config", func() {
   919  					Expect(executeErr).To(HaveOccurred())
   920  					Expect(fakeConfig.WriteConfigCallCount()).To(Equal(1))
   921  				})
   922  			})
   923  
   924  			When("WriteConfig returns an error", func() {
   925  				BeforeEach(func() {
   926  					fakeConfig.WriteConfigReturns(errors.New("Config Failure"))
   927  				})
   928  				It("throws that error", func() {
   929  					Expect(executeErr).To(MatchError("Error writing config: Config Failure"))
   930  				})
   931  			})
   932  		})
   933  	})
   934  
   935  	Describe("Targeting Org", func() {
   936  		BeforeEach(func() {
   937  			cmd.APIEndpoint = "example.com"
   938  			cmd.Username = "some-user"
   939  			cmd.Password = "some-password"
   940  			fakeConfig.APIVersionReturns("3.4.5")
   941  			fakeActor.GetCurrentUserReturns(configv3.User{Name: "some-user"}, nil)
   942  		})
   943  
   944  		When("-o was passed", func() {
   945  			BeforeEach(func() {
   946  				cmd.Organization = "some-org"
   947  			})
   948  
   949  			It("fetches the specified organization", func() {
   950  				Expect(fakeActor.GetOrganizationByNameCallCount()).To(Equal(1))
   951  				Expect(fakeActor.GetOrganizationsCallCount()).To(Equal(0))
   952  				Expect(fakeActor.GetOrganizationByNameArgsForCall(0)).To(Equal("some-org"))
   953  			})
   954  
   955  			When("fetching the organization succeeds", func() {
   956  				BeforeEach(func() {
   957  					fakeActor.GetOrganizationByNameReturns(
   958  						resources.Organization{Name: "some-org", GUID: "some-guid"},
   959  						v7action.Warnings{"some-warning-1", "some-warning-2"},
   960  						nil)
   961  					fakeConfig.TargetedOrganizationNameReturns("some-org")
   962  					fakeConfig.TargetReturns("https://example.com")
   963  				})
   964  
   965  				It("prints all warnings", func() {
   966  					Expect(testUI.Err).To(Say("some-warning-1"))
   967  					Expect(testUI.Err).To(Say("some-warning-2"))
   968  				})
   969  
   970  				It("sets the targeted organization in the config", func() {
   971  					Expect(fakeConfig.SetOrganizationInformationCallCount()).To(Equal(1))
   972  					orgGUID, orgName := fakeConfig.SetOrganizationInformationArgsForCall(0)
   973  					Expect(orgGUID).To(Equal("some-guid"))
   974  					Expect(orgName).To(Equal("some-org"))
   975  				})
   976  
   977  				It("reports to the user that the org is targeted", func() {
   978  					Expect(testUI.Out).To(Say(`API endpoint:\s+https://example.com`))
   979  					Expect(testUI.Out).To(Say(`API version:\s+3.4.5`))
   980  					Expect(testUI.Out).To(Say("user:           some-user"))
   981  					Expect(testUI.Out).To(Say("org:            some-org"))
   982  				})
   983  			})
   984  
   985  			When("fetching the organization fails", func() {
   986  				BeforeEach(func() {
   987  					fakeActor.GetOrganizationByNameReturns(
   988  						resources.Organization{},
   989  						v7action.Warnings{"some-warning-1", "some-warning-2"},
   990  						errors.New("org-not-found"),
   991  					)
   992  				})
   993  
   994  				It("prints all warnings", func() {
   995  					Expect(testUI.Err).To(Say("some-warning-1"))
   996  					Expect(testUI.Err).To(Say("some-warning-2"))
   997  				})
   998  
   999  				It("does not set the targeted org", func() {
  1000  					Expect(fakeConfig.SetOrganizationInformationCallCount()).To(Equal(0))
  1001  				})
  1002  			})
  1003  		})
  1004  
  1005  		When("-o was not passed, -s was passed", func() {
  1006  			BeforeEach(func() {
  1007  				cmd.APIEndpoint = "example.com"
  1008  				cmd.Username = "some-user"
  1009  				cmd.Password = "some-password"
  1010  				cmd.Space = "some-space"
  1011  				fakeActor.GetCurrentUserReturns(configv3.User{Name: "some-user"}, nil)
  1012  				fakeConfig.TargetReturns("https://example.com")
  1013  				fakeActor.GetOrganizationsReturns(
  1014  					[]resources.Organization{},
  1015  					v7action.Warnings{"some-org-warning-1", "some-org-warning-2"},
  1016  					nil,
  1017  				)
  1018  				fakeActor.GetSpaceByNameAndOrganizationCalls(func(spaceName string, orgGUID string) (resources.Space, v7action.Warnings, error) {
  1019  					if orgGUID != "some-org-guid1" {
  1020  						return resources.Space{Name: spaceName}, v7action.Warnings{}, nil
  1021  					}
  1022  					return resources.Space{}, v7action.Warnings{}, actionerror.SpaceNotFoundError{}
  1023  				})
  1024  			})
  1025  
  1026  			When("no org valid org exists", func() {
  1027  				BeforeEach(func() {
  1028  					fakeActor.GetOrganizationsReturns(
  1029  						[]resources.Organization{{
  1030  							GUID: "some-org-guid",
  1031  							Name: "some-org-name",
  1032  						}},
  1033  						v7action.Warnings{"some-org-warning-1", "some-org-warning-2"},
  1034  						nil,
  1035  					)
  1036  				})
  1037  
  1038  				It("does not prompt the user to select an org", func() {
  1039  					Expect(executeErr).ToNot(HaveOccurred())
  1040  					Expect(testUI.Out).ToNot(Say("Select an org:"))
  1041  					Expect(testUI.Out).ToNot(Say(`Org \(enter to skip\):`))
  1042  				})
  1043  
  1044  				It("displays how to target an org and space", func() {
  1045  					Expect(executeErr).ToNot(HaveOccurred())
  1046  
  1047  					Expect(testUI.Out).To(Say(`API endpoint:\s+https://example.com`))
  1048  					Expect(testUI.Out).To(Say(`API version:\s+3.4.5`))
  1049  					Expect(testUI.Out).To(Say(`user:\s+some-user`))
  1050  					Expect(testUI.Out).To(Say("No org or space targeted, use '%s target -o ORG -s SPACE'", binaryName))
  1051  				})
  1052  			})
  1053  
  1054  			When("only one valid org exists", func() {
  1055  				BeforeEach(func() {
  1056  					fakeActor.GetOrganizationsReturns(
  1057  						[]resources.Organization{{
  1058  							GUID: "some-org-guid1",
  1059  							Name: "some-org-name1",
  1060  						}, {
  1061  							GUID: "some-org-guid2",
  1062  							Name: "some-org-name2",
  1063  						}},
  1064  						v7action.Warnings{"some-org-warning-1", "some-org-warning-2"},
  1065  						nil,
  1066  					)
  1067  				})
  1068  
  1069  				It("targets that org", func() {
  1070  					Expect(executeErr).ToNot(HaveOccurred())
  1071  					Expect(fakeConfig.SetOrganizationInformationCallCount()).To(Equal(1))
  1072  					orgGUID, orgName := fakeConfig.SetOrganizationInformationArgsForCall(0)
  1073  					Expect(orgGUID).To(Equal("some-org-guid2"))
  1074  					Expect(orgName).To(Equal("some-org-name2"))
  1075  				})
  1076  			})
  1077  
  1078  			When("more than one valid org exists", func() {
  1079  				BeforeEach(func() {
  1080  					fakeActor.GetOrganizationsReturns(
  1081  						[]resources.Organization{
  1082  							{
  1083  								GUID: "some-org-guid3",
  1084  								Name: "1234",
  1085  							},
  1086  							{
  1087  								GUID: "some-org-guid1",
  1088  								Name: "some-org-name1",
  1089  							},
  1090  							{
  1091  								GUID: "some-org-guid2",
  1092  								Name: "some-org-name2",
  1093  							},
  1094  						},
  1095  						v7action.Warnings{"some-org-warning-1", "some-org-warning-2"},
  1096  						nil,
  1097  					)
  1098  				})
  1099  
  1100  				It("prompts the user to select an org from the filtered selection", func() {
  1101  					Expect(testUI.Out).To(Say("Select an org:"))
  1102  					Expect(testUI.Out).To(Say("1. 1234"))
  1103  					Expect(testUI.Out).To(Say("2. some-org-name2"))
  1104  					Expect(testUI.Out).To(Say("\n\n"))
  1105  					Expect(testUI.Out).To(Say(`Org \(enter to skip\):`))
  1106  					Expect(executeErr).ToNot(HaveOccurred())
  1107  				})
  1108  			})
  1109  
  1110  			When("filtering the orgs errors", func() {
  1111  				BeforeEach(func() {
  1112  					fakeActor.GetOrganizationsReturns(
  1113  						[]resources.Organization{{
  1114  							GUID: "some-org-guid",
  1115  							Name: "some-org-name",
  1116  						}},
  1117  						v7action.Warnings{"some-org-warning-1", "some-org-warning-2"},
  1118  						nil,
  1119  					)
  1120  					fakeActor.GetSpaceByNameAndOrganizationReturns(resources.Space{}, v7action.Warnings{}, errors.New("oh noooooooo"))
  1121  				})
  1122  
  1123  				It("returns the error", func() {
  1124  					Expect(executeErr).To(MatchError(errors.New("oh noooooooo")))
  1125  				})
  1126  			})
  1127  		})
  1128  
  1129  		When("-o and -s were both not passed", func() {
  1130  			BeforeEach(func() {
  1131  				cmd.APIEndpoint = "example.com"
  1132  				cmd.Username = "some-user"
  1133  				cmd.Password = "some-password"
  1134  				fakeActor.GetOrganizationsReturns(
  1135  					[]resources.Organization{},
  1136  					v7action.Warnings{"some-org-warning-1", "some-org-warning-2"},
  1137  					nil,
  1138  				)
  1139  			})
  1140  
  1141  			It("fetches the available organizations", func() {
  1142  				Expect(executeErr).ToNot(HaveOccurred())
  1143  				Expect(fakeActor.GetOrganizationsCallCount()).To(Equal(1))
  1144  			})
  1145  
  1146  			It("prints all warnings", func() {
  1147  				Expect(testUI.Err).To(Say("some-org-warning-1"))
  1148  				Expect(testUI.Err).To(Say("some-org-warning-2"))
  1149  			})
  1150  
  1151  			When("fetching the organizations succeeds", func() {
  1152  				BeforeEach(func() {
  1153  					fakeActor.GetCurrentUserReturns(configv3.User{Name: "some-user"}, nil)
  1154  					fakeConfig.TargetReturns("https://example.com")
  1155  				})
  1156  
  1157  				When("no org exists", func() {
  1158  					It("does not prompt the user to select an org", func() {
  1159  						Expect(executeErr).ToNot(HaveOccurred())
  1160  						Expect(testUI.Out).ToNot(Say("Select an org:"))
  1161  						Expect(testUI.Out).ToNot(Say(`Org \(enter to skip\):`))
  1162  					})
  1163  
  1164  					It("displays how to target an org and space", func() {
  1165  						Expect(executeErr).ToNot(HaveOccurred())
  1166  
  1167  						Expect(testUI.Out).To(Say(`API endpoint:\s+https://example.com`))
  1168  						Expect(testUI.Out).To(Say(`API version:\s+3.4.5`))
  1169  						Expect(testUI.Out).To(Say(`user:\s+some-user`))
  1170  						Expect(testUI.Out).To(Say("No org or space targeted, use '%s target -o ORG -s SPACE'", binaryName))
  1171  					})
  1172  				})
  1173  
  1174  				When("only one org exists", func() {
  1175  					BeforeEach(func() {
  1176  						fakeActor.GetOrganizationsReturns(
  1177  							[]resources.Organization{{
  1178  								GUID: "some-org-guid",
  1179  								Name: "some-org-name",
  1180  							}},
  1181  							v7action.Warnings{"some-org-warning-1", "some-org-warning-2"},
  1182  							nil,
  1183  						)
  1184  					})
  1185  
  1186  					It("targets that org", func() {
  1187  						Expect(executeErr).ToNot(HaveOccurred())
  1188  						Expect(fakeConfig.SetOrganizationInformationCallCount()).To(Equal(1))
  1189  						orgGUID, orgName := fakeConfig.SetOrganizationInformationArgsForCall(0)
  1190  						Expect(orgGUID).To(Equal("some-org-guid"))
  1191  						Expect(orgName).To(Equal("some-org-name"))
  1192  					})
  1193  				})
  1194  
  1195  				When("more than one but fewer than 50 orgs exists", func() {
  1196  					BeforeEach(func() {
  1197  						fakeActor.GetOrganizationsReturns(
  1198  							[]resources.Organization{
  1199  								{
  1200  									GUID: "some-org-guid3",
  1201  									Name: "1234",
  1202  								},
  1203  								{
  1204  									GUID: "some-org-guid1",
  1205  									Name: "some-org-name1",
  1206  								},
  1207  								{
  1208  									GUID: "some-org-guid2",
  1209  									Name: "some-org-name2",
  1210  								},
  1211  							},
  1212  							v7action.Warnings{"some-org-warning-1", "some-org-warning-2"},
  1213  							nil,
  1214  						)
  1215  					})
  1216  
  1217  					When("the user selects an org by list position", func() {
  1218  						When("the position is valid", func() {
  1219  							BeforeEach(func() {
  1220  								fakeConfig.TargetedOrganizationReturns(configv3.Organization{
  1221  									GUID: "targeted-org-guid1",
  1222  								})
  1223  								fakeConfig.TargetedOrganizationNameReturns("targeted-org-name")
  1224  								_, err := input.Write([]byte("2\n"))
  1225  								Expect(err).ToNot(HaveOccurred())
  1226  							})
  1227  
  1228  							It("prompts the user to select an org", func() {
  1229  								Expect(testUI.Out).To(Say("Select an org:"))
  1230  								Expect(testUI.Out).To(Say("1. 1234"))
  1231  								Expect(testUI.Out).To(Say("2. some-org-name1"))
  1232  								Expect(testUI.Out).To(Say("3. some-org-name2"))
  1233  								Expect(testUI.Out).To(Say("\n\n"))
  1234  								Expect(testUI.Out).To(Say(`Org \(enter to skip\):`))
  1235  								Expect(executeErr).ToNot(HaveOccurred())
  1236  							})
  1237  
  1238  							It("targets that org", func() {
  1239  								Expect(fakeConfig.SetOrganizationInformationCallCount()).To(Equal(1))
  1240  								orgGUID, orgName := fakeConfig.SetOrganizationInformationArgsForCall(0)
  1241  								Expect(orgGUID).To(Equal("some-org-guid1"))
  1242  								Expect(orgName).To(Equal("some-org-name1"))
  1243  							})
  1244  
  1245  							It("outputs targeted org", func() {
  1246  								Expect(testUI.Out).To(Say("Targeted org targeted-org-name"))
  1247  							})
  1248  						})
  1249  
  1250  						When("the position is invalid", func() {
  1251  							BeforeEach(func() {
  1252  								_, err := input.Write([]byte("4\n"))
  1253  								Expect(err).ToNot(HaveOccurred())
  1254  							})
  1255  
  1256  							It("reprompts the user", func() {
  1257  								Expect(testUI.Out).To(Say("Select an org:"))
  1258  								Expect(testUI.Out).To(Say("1. 1234"))
  1259  								Expect(testUI.Out).To(Say("2. some-org-name1"))
  1260  								Expect(testUI.Out).To(Say("3. some-org-name2"))
  1261  								Expect(testUI.Out).To(Say(`Org \(enter to skip\):`))
  1262  								Expect(testUI.Out).To(Say("Select an org:"))
  1263  								Expect(testUI.Out).To(Say("1. 1234"))
  1264  								Expect(testUI.Out).To(Say("2. some-org-name1"))
  1265  								Expect(testUI.Out).To(Say("3. some-org-name2"))
  1266  								Expect(testUI.Out).To(Say(`Org \(enter to skip\):`))
  1267  							})
  1268  						})
  1269  					})
  1270  
  1271  					When("the user selects an org by name", func() {
  1272  						When("the list contains that org", func() {
  1273  							BeforeEach(func() {
  1274  								_, err := input.Write([]byte("some-org-name2\n"))
  1275  								Expect(err).NotTo(HaveOccurred())
  1276  							})
  1277  
  1278  							It("prompts the user to select an org", func() {
  1279  								Expect(testUI.Out).To(Say("Select an org:"))
  1280  								Expect(testUI.Out).To(Say("1. 1234"))
  1281  								Expect(testUI.Out).To(Say("2. some-org-name1"))
  1282  								Expect(testUI.Out).To(Say("3. some-org-name2"))
  1283  								Expect(testUI.Out).To(Say(`Org \(enter to skip\):`))
  1284  								Expect(executeErr).ToNot(HaveOccurred())
  1285  							})
  1286  
  1287  							It("targets that org", func() {
  1288  								Expect(fakeConfig.SetOrganizationInformationCallCount()).To(Equal(1))
  1289  								orgGUID, orgName := fakeConfig.SetOrganizationInformationArgsForCall(0)
  1290  								Expect(orgGUID).To(Equal("some-org-guid2"))
  1291  								Expect(orgName).To(Equal("some-org-name2"))
  1292  							})
  1293  						})
  1294  
  1295  						When("the org is not in the list", func() {
  1296  							BeforeEach(func() {
  1297  								_, err := input.Write([]byte("invalid-org\n"))
  1298  								Expect(err).NotTo(HaveOccurred())
  1299  							})
  1300  
  1301  							It("returns an error", func() {
  1302  								Expect(executeErr).To(MatchError(translatableerror.OrganizationNotFoundError{Name: "invalid-org"}))
  1303  							})
  1304  
  1305  							It("does not target the org", func() {
  1306  								Expect(fakeConfig.SetOrganizationInformationCallCount()).To(Equal(0))
  1307  							})
  1308  						})
  1309  					})
  1310  
  1311  					When("the user exits the prompt early", func() {
  1312  						var fakeUI *commandfakes.FakeUI
  1313  
  1314  						BeforeEach(func() {
  1315  							fakeUI = new(commandfakes.FakeUI)
  1316  							cmd.UI = fakeUI
  1317  						})
  1318  
  1319  						When("the prompt returns with an EOF", func() {
  1320  							BeforeEach(func() {
  1321  								fakeUI.DisplayTextMenuReturns("", io.EOF)
  1322  							})
  1323  
  1324  							It("selects no org and returns no error", func() {
  1325  								Expect(executeErr).ToNot(HaveOccurred())
  1326  								Expect(fakeConfig.SetOrganizationInformationCallCount()).To(Equal(0))
  1327  							})
  1328  						})
  1329  					})
  1330  				})
  1331  
  1332  				When("more than 50 orgs exist", func() {
  1333  					BeforeEach(func() {
  1334  						orgs := make([]resources.Organization, 51)
  1335  						for i := range orgs {
  1336  							orgs[i].Name = fmt.Sprintf("org%d", i+1)
  1337  							orgs[i].GUID = fmt.Sprintf("org-guid%d", i+1)
  1338  						}
  1339  
  1340  						fakeActor.GetOrganizationsReturns(
  1341  							orgs,
  1342  							v7action.Warnings{"some-org-warning-1", "some-org-warning-2"},
  1343  							nil,
  1344  						)
  1345  					})
  1346  
  1347  					When("the user selects an org by name", func() {
  1348  						When("the list contains that org", func() {
  1349  							BeforeEach(func() {
  1350  								_, err := input.Write([]byte("org37\n"))
  1351  								Expect(err).NotTo(HaveOccurred())
  1352  							})
  1353  
  1354  							It("prompts the user to select an org", func() {
  1355  								Expect(testUI.Out).To(Say("There are too many options to display; please type in the name."))
  1356  								Expect(testUI.Out).To(Say(`Org \(enter to skip\):`))
  1357  								Expect(executeErr).ToNot(HaveOccurred())
  1358  							})
  1359  
  1360  							It("targets that org", func() {
  1361  								Expect(fakeConfig.SetOrganizationInformationCallCount()).To(Equal(1))
  1362  								orgGUID, orgName := fakeConfig.SetOrganizationInformationArgsForCall(0)
  1363  								Expect(orgGUID).To(Equal("org-guid37"))
  1364  								Expect(orgName).To(Equal("org37"))
  1365  							})
  1366  						})
  1367  
  1368  						When("the org is not in the list", func() {
  1369  							BeforeEach(func() {
  1370  								_, err := input.Write([]byte("invalid-org\n"))
  1371  								Expect(err).NotTo(HaveOccurred())
  1372  							})
  1373  
  1374  							It("returns an error", func() {
  1375  								Expect(executeErr).To(MatchError(translatableerror.OrganizationNotFoundError{Name: "invalid-org"}))
  1376  							})
  1377  
  1378  							It("does not target the org", func() {
  1379  								Expect(fakeConfig.SetOrganizationInformationCallCount()).To(Equal(0))
  1380  							})
  1381  						})
  1382  					})
  1383  				})
  1384  			})
  1385  
  1386  			When("fetching the organizations fails", func() {
  1387  				BeforeEach(func() {
  1388  					fakeActor.GetOrganizationsReturns(
  1389  						[]resources.Organization{},
  1390  						v7action.Warnings{"some-warning-1", "some-warning-2"},
  1391  						errors.New("api call failed"),
  1392  					)
  1393  				})
  1394  
  1395  				It("returns the error", func() {
  1396  					Expect(executeErr).To(MatchError("api call failed"))
  1397  				})
  1398  
  1399  				It("prints all warnings", func() {
  1400  					Expect(testUI.Err).To(Say("some-warning-1"))
  1401  					Expect(testUI.Err).To(Say("some-warning-2"))
  1402  				})
  1403  			})
  1404  		})
  1405  	})
  1406  
  1407  	Describe("Targeting Space", func() {
  1408  		BeforeEach(func() {
  1409  			cmd.APIEndpoint = "example.com"
  1410  			cmd.Username = "some-user"
  1411  			cmd.Password = "some-password"
  1412  			fakeConfig.APIVersionReturns("3.4.5")
  1413  			fakeActor.GetCurrentUserReturns(configv3.User{Name: "some-user"}, nil)
  1414  		})
  1415  
  1416  		When("an org has been successfully targeted", func() {
  1417  			BeforeEach(func() {
  1418  				fakeConfig.TargetedOrganizationReturns(configv3.Organization{
  1419  					GUID: "targeted-org-guid",
  1420  					Name: "targeted-org-name",
  1421  				},
  1422  				)
  1423  				fakeConfig.TargetedOrganizationNameReturns("targeted-org-name")
  1424  			})
  1425  
  1426  			When("-s was passed", func() {
  1427  				BeforeEach(func() {
  1428  					cmd.Space = "some-space"
  1429  				})
  1430  
  1431  				When("the specified space exists", func() {
  1432  					BeforeEach(func() {
  1433  						fakeActor.GetSpaceByNameAndOrganizationReturns(
  1434  							resources.Space{
  1435  								Name: "some-space",
  1436  								GUID: "some-space-guid",
  1437  							},
  1438  							v7action.Warnings{"some-warning-1", "some-warning-2"},
  1439  							nil,
  1440  						)
  1441  					})
  1442  
  1443  					It("targets that space", func() {
  1444  						Expect(fakeConfig.SetSpaceInformationCallCount()).To(Equal(1))
  1445  						spaceGUID, spaceName, allowSSH := fakeConfig.SetSpaceInformationArgsForCall(0)
  1446  						Expect(spaceGUID).To(Equal("some-space-guid"))
  1447  						Expect(spaceName).To(Equal("some-space"))
  1448  						Expect(allowSSH).To(BeTrue())
  1449  					})
  1450  
  1451  					It("prints all warnings", func() {
  1452  						Expect(testUI.Err).To(Say("some-warning-1"))
  1453  						Expect(testUI.Err).To(Say("some-warning-2"))
  1454  					})
  1455  
  1456  					When("the space has been successfully targeted", func() {
  1457  						BeforeEach(func() {
  1458  							fakeConfig.TargetedSpaceReturns(configv3.Space{Name: "some-space"})
  1459  						})
  1460  
  1461  						It("displays that the space has been targeted", func() {
  1462  							Expect(testUI.Out).To(Say(`space:\s+some-space`))
  1463  						})
  1464  					})
  1465  				})
  1466  
  1467  				When("the specified space does not exist or does not belong to the targeted org", func() {
  1468  					BeforeEach(func() {
  1469  						fakeActor.GetSpaceByNameAndOrganizationReturns(
  1470  							resources.Space{},
  1471  							v7action.Warnings{"some-warning-1", "some-warning-2"},
  1472  							actionerror.SpaceNotFoundError{Name: "some-space"},
  1473  						)
  1474  					})
  1475  
  1476  					It("returns an error", func() {
  1477  						Expect(executeErr).To(MatchError(actionerror.SpaceNotFoundError{Name: "some-space"}))
  1478  					})
  1479  
  1480  					It("prints all warnings", func() {
  1481  						Expect(testUI.Err).To(Say("some-warning-1"))
  1482  						Expect(testUI.Err).To(Say("some-warning-2"))
  1483  					})
  1484  
  1485  					It("reports that no space is targeted", func() {
  1486  						Expect(testUI.Out).To(Say(`space:\s+No space targeted, use 'some-executable target -s SPACE'`))
  1487  					})
  1488  				})
  1489  			})
  1490  
  1491  			When("-s was not passed", func() {
  1492  				When("fetching the spaces for an organization succeeds", func() {
  1493  					When("no space exists", func() {
  1494  						BeforeEach(func() {
  1495  							fakeActor.GetOrganizationSpacesReturns(
  1496  								[]resources.Space{},
  1497  								v7action.Warnings{},
  1498  								nil,
  1499  							)
  1500  							fakeConfig.TargetReturns("https://example.com")
  1501  						})
  1502  						It("does not prompt the user to select a space", func() {
  1503  							Expect(executeErr).ToNot(HaveOccurred())
  1504  							Expect(testUI.Out).ToNot(Say("Select a space:"))
  1505  							Expect(testUI.Out).ToNot(Say(`Space \(enter to skip\):`))
  1506  						})
  1507  
  1508  						It("displays how to target a space", func() {
  1509  							Expect(executeErr).ToNot(HaveOccurred())
  1510  							Expect(testUI.Out).To(Say(`API endpoint:\s+https://example.com`))
  1511  							Expect(testUI.Out).To(Say(`API version:\s+3.4.5`))
  1512  							Expect(testUI.Out).To(Say(`user:\s+some-user`))
  1513  							Expect(testUI.Out).To(Say("No space targeted, use '%s target -s SPACE'", binaryName))
  1514  						})
  1515  					})
  1516  
  1517  					When("only one space is available", func() {
  1518  						BeforeEach(func() {
  1519  							spaces := []resources.Space{
  1520  								{
  1521  									GUID: "some-space-guid",
  1522  									Name: "some-space-name",
  1523  								},
  1524  							}
  1525  
  1526  							fakeActor.GetOrganizationSpacesReturns(
  1527  								spaces,
  1528  								v7action.Warnings{},
  1529  								nil,
  1530  							)
  1531  
  1532  							fakeConfig.TargetedSpaceReturns(configv3.Space{
  1533  								GUID: "some-space-guid",
  1534  								Name: "some-space-name",
  1535  							})
  1536  						})
  1537  
  1538  						It("targets this space", func() {
  1539  							Expect(executeErr).NotTo(HaveOccurred())
  1540  
  1541  							Expect(fakeActor.GetOrganizationSpacesCallCount()).To(Equal(1))
  1542  							Expect(fakeActor.GetOrganizationSpacesArgsForCall(0)).To(Equal("targeted-org-guid"))
  1543  
  1544  							Expect(fakeConfig.SetSpaceInformationCallCount()).To(Equal(1))
  1545  
  1546  							firstArg, secondArg, _ := fakeConfig.SetSpaceInformationArgsForCall(0)
  1547  							Expect(firstArg).To(Equal("some-space-guid"))
  1548  							Expect(secondArg).To(Equal("some-space-name"))
  1549  
  1550  							Expect(testUI.Out).To(Say(`Targeted space some-space-name\.`))
  1551  							Expect(testUI.Out).To(Say(`space:\s+some-space-name`))
  1552  							Expect(testUI.Out).NotTo(Say(`space:\s+No space targeted, use 'some-executable target -s SPACE`))
  1553  						})
  1554  					})
  1555  
  1556  					When("more than one space is available", func() {
  1557  						BeforeEach(func() {
  1558  							spaces := []resources.Space{
  1559  								{
  1560  									GUID: "some-space-guid",
  1561  									Name: "some-space-name",
  1562  								},
  1563  								{
  1564  									GUID: "some-space-guid1",
  1565  									Name: "some-space-name1",
  1566  								},
  1567  								{
  1568  									GUID: "some-space-guid2",
  1569  									Name: "some-space-name2",
  1570  								},
  1571  								{
  1572  									GUID: "some-space-guid3",
  1573  									Name: "3",
  1574  								},
  1575  								{
  1576  									GUID: "some-space-guid3",
  1577  									Name: "100",
  1578  								},
  1579  							}
  1580  
  1581  							fakeActor.GetOrganizationSpacesReturns(
  1582  								spaces,
  1583  								v7action.Warnings{},
  1584  								nil,
  1585  							)
  1586  						})
  1587  
  1588  						It("displays a numbered list of spaces", func() {
  1589  							Expect(testUI.Out).To(Say("Select a space:"))
  1590  							Expect(testUI.Out).To(Say("1. some-space-name"))
  1591  							Expect(testUI.Out).To(Say("2. some-space-name1"))
  1592  							Expect(testUI.Out).To(Say("3. some-space-name2"))
  1593  							Expect(testUI.Out).To(Say("4. 3"))
  1594  							Expect(testUI.Out).To(Say("5. 100"))
  1595  							Expect(testUI.Out).To(Say("\n\n"))
  1596  							Expect(testUI.Out).To(Say(`Space \(enter to skip\):`))
  1597  						})
  1598  
  1599  						When("the user selects a space by list position", func() {
  1600  							When("the position is valid", func() {
  1601  								BeforeEach(func() {
  1602  									_, err := input.Write([]byte("2\n"))
  1603  									Expect(err).NotTo(HaveOccurred())
  1604  								})
  1605  
  1606  								It("targets that space", func() {
  1607  									Expect(fakeConfig.SetSpaceInformationCallCount()).To(Equal(1))
  1608  									guid, name, allowSSH := fakeConfig.SetSpaceInformationArgsForCall(0)
  1609  									Expect(guid).To(Equal("some-space-guid1"))
  1610  									Expect(name).To(Equal("some-space-name1"))
  1611  									Expect(allowSSH).To(BeTrue())
  1612  									Expect(executeErr).NotTo(HaveOccurred())
  1613  								})
  1614  							})
  1615  
  1616  							When("the position is invalid", func() {
  1617  								BeforeEach(func() {
  1618  									_, err := input.Write([]byte("-1\n"))
  1619  									Expect(err).NotTo(HaveOccurred())
  1620  								})
  1621  
  1622  								It("reprompts the user", func() {
  1623  									Expect(testUI.Out).To(Say("Select a space:"))
  1624  									Expect(testUI.Out).To(Say("1. some-space-name"))
  1625  									Expect(testUI.Out).To(Say("2. some-space-name1"))
  1626  									Expect(testUI.Out).To(Say("3. some-space-name2"))
  1627  									Expect(testUI.Out).To(Say("4. 3"))
  1628  									Expect(testUI.Out).To(Say("5. 100"))
  1629  									Expect(testUI.Out).To(Say("\n\n"))
  1630  									Expect(testUI.Out).To(Say(`Space \(enter to skip\):`))
  1631  									Expect(testUI.Out).To(Say("Select a space:"))
  1632  									Expect(testUI.Out).To(Say("1. some-space-name"))
  1633  									Expect(testUI.Out).To(Say("2. some-space-name1"))
  1634  									Expect(testUI.Out).To(Say("3. some-space-name2"))
  1635  									Expect(testUI.Out).To(Say("4. 3"))
  1636  									Expect(testUI.Out).To(Say("5. 100"))
  1637  									Expect(testUI.Out).To(Say("\n\n"))
  1638  									Expect(testUI.Out).To(Say(`Space \(enter to skip\):`))
  1639  								})
  1640  							})
  1641  						})
  1642  
  1643  						When("the user selects a space by name", func() {
  1644  							When("the list contains that space", func() {
  1645  								BeforeEach(func() {
  1646  									_, err := input.Write([]byte("some-space-name2\n"))
  1647  									Expect(err).NotTo(HaveOccurred())
  1648  								})
  1649  
  1650  								It("targets that space", func() {
  1651  									Expect(fakeConfig.SetSpaceInformationCallCount()).To(Equal(1))
  1652  									guid, name, allowSSH := fakeConfig.SetSpaceInformationArgsForCall(0)
  1653  									Expect(guid).To(Equal("some-space-guid2"))
  1654  									Expect(name).To(Equal("some-space-name2"))
  1655  									Expect(allowSSH).To(BeTrue())
  1656  									Expect(executeErr).NotTo(HaveOccurred())
  1657  								})
  1658  							})
  1659  
  1660  							When("the space is not in the list", func() {
  1661  								BeforeEach(func() {
  1662  									_, err := input.Write([]byte("invalid-space\n"))
  1663  									Expect(err).NotTo(HaveOccurred())
  1664  								})
  1665  
  1666  								It("returns an error", func() {
  1667  									Expect(executeErr).To(MatchError(translatableerror.SpaceNotFoundError{Name: "invalid-space"}))
  1668  								})
  1669  
  1670  								It("does not target the space", func() {
  1671  									Expect(fakeConfig.SetSpaceInformationCallCount()).To(Equal(0))
  1672  								})
  1673  							})
  1674  
  1675  							When("the user exits the prompt early", func() {
  1676  								var fakeUI *commandfakes.FakeUI
  1677  
  1678  								BeforeEach(func() {
  1679  									fakeUI = new(commandfakes.FakeUI)
  1680  									cmd.UI = fakeUI
  1681  								})
  1682  
  1683  								When("the prompt returns with an EOF", func() {
  1684  									BeforeEach(func() {
  1685  										fakeUI.DisplayTextMenuReturns("", io.EOF)
  1686  									})
  1687  									It("selects no space and returns no error", func() {
  1688  										Expect(executeErr).ToNot(HaveOccurred())
  1689  										Expect(fakeConfig.SetSpaceInformationCallCount()).To(Equal(0))
  1690  									})
  1691  								})
  1692  							})
  1693  						})
  1694  
  1695  						When("the user enters text which is both a space name and a digit", func() {
  1696  							When("the entry is a valid position", func() {
  1697  								BeforeEach(func() {
  1698  									_, err := input.Write([]byte("3\n"))
  1699  									Expect(err).NotTo(HaveOccurred())
  1700  								})
  1701  
  1702  								It("targets the space at the index specified", func() {
  1703  									Expect(fakeConfig.SetSpaceInformationCallCount()).To(Equal(1))
  1704  									guid, name, allowSSH := fakeConfig.SetSpaceInformationArgsForCall(0)
  1705  									Expect(guid).To(Equal("some-space-guid2"))
  1706  									Expect(name).To(Equal("some-space-name2"))
  1707  									Expect(allowSSH).To(BeTrue())
  1708  									Expect(executeErr).NotTo(HaveOccurred())
  1709  								})
  1710  							})
  1711  
  1712  							When("the entry is an invalid position", func() {
  1713  								BeforeEach(func() {
  1714  									_, err := input.Write([]byte("100\n"))
  1715  									Expect(err).NotTo(HaveOccurred())
  1716  								})
  1717  
  1718  								It("reprompts the user", func() {
  1719  									Expect(testUI.Out).To(Say("Select a space:"))
  1720  									Expect(testUI.Out).To(Say("1. some-space-name"))
  1721  									Expect(testUI.Out).To(Say("2. some-space-name1"))
  1722  									Expect(testUI.Out).To(Say("3. some-space-name2"))
  1723  									Expect(testUI.Out).To(Say("4. 3"))
  1724  									Expect(testUI.Out).To(Say("5. 100"))
  1725  									Expect(testUI.Out).To(Say("\n\n"))
  1726  									Expect(testUI.Out).To(Say(`Space \(enter to skip\):`))
  1727  									Expect(testUI.Out).To(Say("1. some-space-name"))
  1728  									Expect(testUI.Out).To(Say("2. some-space-name1"))
  1729  									Expect(testUI.Out).To(Say("3. some-space-name2"))
  1730  									Expect(testUI.Out).To(Say("4. 3"))
  1731  									Expect(testUI.Out).To(Say("5. 100"))
  1732  									Expect(testUI.Out).To(Say("\n\n"))
  1733  									Expect(testUI.Out).To(Say(`Space \(enter to skip\):`))
  1734  								})
  1735  							})
  1736  						})
  1737  					})
  1738  
  1739  					When("more than 50 spaces exist", func() {
  1740  						BeforeEach(func() {
  1741  							spaces := make([]resources.Space, 51)
  1742  							for i := range spaces {
  1743  								spaces[i].Name = fmt.Sprintf("space-%d", i+1)
  1744  								spaces[i].GUID = fmt.Sprintf("space-guid-%d", i+1)
  1745  							}
  1746  
  1747  							fakeActor.GetOrganizationSpacesReturns(
  1748  								spaces,
  1749  								v7action.Warnings{},
  1750  								nil,
  1751  							)
  1752  						})
  1753  
  1754  						It("prompts the user to select an space", func() {
  1755  							Expect(testUI.Out).To(Say("There are too many options to display; please type in the name."))
  1756  							Expect(testUI.Out).To(Say("\n\n"))
  1757  							Expect(testUI.Out).To(Say(`Space \(enter to skip\):`))
  1758  						})
  1759  
  1760  						When("the user selects an space by name", func() {
  1761  							When("the list contains that space", func() {
  1762  								BeforeEach(func() {
  1763  									_, err := input.Write([]byte("space-37\n"))
  1764  									Expect(err).NotTo(HaveOccurred())
  1765  								})
  1766  
  1767  								It("targets that space", func() {
  1768  									Expect(fakeConfig.SetSpaceInformationCallCount()).To(Equal(1))
  1769  									spaceGUID, spaceName, allowSSH := fakeConfig.SetSpaceInformationArgsForCall(0)
  1770  									Expect(spaceGUID).To(Equal("space-guid-37"))
  1771  									Expect(spaceName).To(Equal("space-37"))
  1772  									Expect(allowSSH).To(BeTrue())
  1773  								})
  1774  							})
  1775  
  1776  							When("the name is a valid list position, but it does not match a space name", func() {
  1777  								BeforeEach(func() {
  1778  									_, err := input.Write([]byte("31\n"))
  1779  									Expect(err).NotTo(HaveOccurred())
  1780  								})
  1781  
  1782  								It("returns an error", func() {
  1783  									Expect(executeErr).To(MatchError(translatableerror.SpaceNotFoundError{Name: "31"}))
  1784  								})
  1785  
  1786  								It("does not target the space", func() {
  1787  									Expect(fakeConfig.SetSpaceInformationCallCount()).To(Equal(0))
  1788  								})
  1789  							})
  1790  
  1791  							When("the space is not in the list", func() {
  1792  								BeforeEach(func() {
  1793  									_, err := input.Write([]byte("invalid-space\n"))
  1794  									Expect(err).NotTo(HaveOccurred())
  1795  								})
  1796  
  1797  								It("returns an error", func() {
  1798  									Expect(executeErr).To(MatchError(translatableerror.SpaceNotFoundError{Name: "invalid-space"}))
  1799  								})
  1800  
  1801  								It("does not target the space", func() {
  1802  									Expect(fakeConfig.SetSpaceInformationCallCount()).To(Equal(0))
  1803  								})
  1804  							})
  1805  						})
  1806  					})
  1807  				})
  1808  
  1809  				When("fetching the spaces for an organization fails", func() {
  1810  					BeforeEach(func() {
  1811  						fakeActor.GetOrganizationSpacesReturns(
  1812  							[]resources.Space{},
  1813  							v7action.Warnings{"some-warning-1", "some-warning-2"},
  1814  							errors.New("fetching spaces failed"),
  1815  						)
  1816  					})
  1817  
  1818  					It("returns an error", func() {
  1819  						Expect(executeErr).To(MatchError("fetching spaces failed"))
  1820  					})
  1821  
  1822  					It("returns all warnings", func() {
  1823  						Expect(testUI.Err).To(Say("some-warning-1"))
  1824  						Expect(testUI.Err).To(Say("some-warning-2"))
  1825  					})
  1826  				})
  1827  			})
  1828  		})
  1829  	})
  1830  })