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