github.com/LukasHeimann/cloudfoundrycli/v8@v8.4.4/command/v7/login_command_test.go (about)

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