github.com/nimakaviani/cli@v6.37.1-0.20180619223813-e734901a73fa+incompatible/actor/pushaction/route_test.go (about)

     1  package pushaction_test
     2  
     3  import (
     4  	"errors"
     5  	"strings"
     6  
     7  	"code.cloudfoundry.org/cli/actor/actionerror"
     8  	. "code.cloudfoundry.org/cli/actor/pushaction"
     9  	"code.cloudfoundry.org/cli/actor/pushaction/pushactionfakes"
    10  	"code.cloudfoundry.org/cli/actor/v2action"
    11  	"code.cloudfoundry.org/cli/api/cloudcontroller/ccv2/constant"
    12  	"code.cloudfoundry.org/cli/util/manifest"
    13  
    14  	. "github.com/onsi/ginkgo"
    15  	. "github.com/onsi/gomega"
    16  )
    17  
    18  var _ = Describe("Routes", func() {
    19  	var (
    20  		actor                   *Actor
    21  		fakeV2Actor             *pushactionfakes.FakeV2Actor
    22  		fakeRandomWordGenerator *pushactionfakes.FakeRandomWordGenerator
    23  	)
    24  
    25  	BeforeEach(func() {
    26  		fakeV2Actor = new(pushactionfakes.FakeV2Actor)
    27  		actor = NewActor(fakeV2Actor, nil, nil)
    28  
    29  		fakeRandomWordGenerator = new(pushactionfakes.FakeRandomWordGenerator)
    30  		actor.WordGenerator = fakeRandomWordGenerator
    31  	})
    32  
    33  	Describe("UnmapRoutes", func() {
    34  		var (
    35  			config ApplicationConfig
    36  
    37  			returnedConfig ApplicationConfig
    38  			warnings       Warnings
    39  			executeErr     error
    40  		)
    41  
    42  		BeforeEach(func() {
    43  			config = ApplicationConfig{
    44  				DesiredApplication: Application{
    45  					Application: v2action.Application{
    46  						GUID: "some-app-guid",
    47  					}},
    48  			}
    49  		})
    50  
    51  		JustBeforeEach(func() {
    52  			returnedConfig, warnings, executeErr = actor.UnmapRoutes(config)
    53  		})
    54  
    55  		Context("when there are routes on the application", func() {
    56  			BeforeEach(func() {
    57  				config.CurrentRoutes = []v2action.Route{
    58  					{GUID: "some-route-guid-1", Host: "some-route-1", Domain: v2action.Domain{Name: "some-domain.com"}},
    59  					{GUID: "some-route-guid-2", Host: "some-route-2"},
    60  				}
    61  			})
    62  
    63  			Context("when the unmapping is successful", func() {
    64  				BeforeEach(func() {
    65  					fakeV2Actor.UnmapRouteFromApplicationReturns(v2action.Warnings{"unmap-route-warning"}, nil)
    66  				})
    67  
    68  				It("only creates the routes that do not exist", func() {
    69  					Expect(executeErr).ToNot(HaveOccurred())
    70  					Expect(warnings).To(ConsistOf("unmap-route-warning", "unmap-route-warning"))
    71  
    72  					Expect(returnedConfig.CurrentRoutes).To(BeEmpty())
    73  
    74  					Expect(fakeV2Actor.UnmapRouteFromApplicationCallCount()).To(Equal(2))
    75  
    76  					routeGUID, appGUID := fakeV2Actor.UnmapRouteFromApplicationArgsForCall(0)
    77  					Expect(routeGUID).To(Equal("some-route-guid-1"))
    78  					Expect(appGUID).To(Equal("some-app-guid"))
    79  
    80  					routeGUID, appGUID = fakeV2Actor.UnmapRouteFromApplicationArgsForCall(1)
    81  					Expect(routeGUID).To(Equal("some-route-guid-2"))
    82  					Expect(appGUID).To(Equal("some-app-guid"))
    83  				})
    84  			})
    85  
    86  			Context("when the mapping errors", func() {
    87  				var expectedErr error
    88  				BeforeEach(func() {
    89  					expectedErr = errors.New("oh my")
    90  					fakeV2Actor.UnmapRouteFromApplicationReturns(v2action.Warnings{"unmap-route-warning"}, expectedErr)
    91  				})
    92  
    93  				It("sends the warnings and errors and returns true", func() {
    94  					Expect(executeErr).To(MatchError(expectedErr))
    95  					Expect(warnings).To(ConsistOf("unmap-route-warning"))
    96  				})
    97  			})
    98  		})
    99  	})
   100  
   101  	Describe("MapRoutes", func() {
   102  		var (
   103  			config ApplicationConfig
   104  
   105  			returnedConfig ApplicationConfig
   106  			boundRoutes    bool
   107  			warnings       Warnings
   108  			executeErr     error
   109  		)
   110  
   111  		BeforeEach(func() {
   112  			config = ApplicationConfig{
   113  				DesiredApplication: Application{
   114  					Application: v2action.Application{
   115  						GUID: "some-app-guid",
   116  					}},
   117  			}
   118  		})
   119  
   120  		JustBeforeEach(func() {
   121  			returnedConfig, boundRoutes, warnings, executeErr = actor.MapRoutes(config)
   122  		})
   123  
   124  		Context("when routes need to be bound to the application", func() {
   125  			BeforeEach(func() {
   126  				config.CurrentRoutes = []v2action.Route{
   127  					{GUID: "some-route-guid-2", Host: "some-route-2"},
   128  				}
   129  				config.DesiredRoutes = []v2action.Route{
   130  					{GUID: "some-route-guid-1", Host: "some-route-1", Domain: v2action.Domain{Name: "some-domain.com"}},
   131  					{GUID: "some-route-guid-2", Host: "some-route-2"},
   132  					{GUID: "some-route-guid-3", Host: "some-route-3"},
   133  				}
   134  			})
   135  
   136  			Context("when the mapping is successful", func() {
   137  				BeforeEach(func() {
   138  					fakeV2Actor.MapRouteToApplicationReturns(v2action.Warnings{"map-route-warning"}, nil)
   139  				})
   140  
   141  				It("only creates the routes that do not exist", func() {
   142  					Expect(executeErr).ToNot(HaveOccurred())
   143  					Expect(warnings).To(ConsistOf("map-route-warning", "map-route-warning"))
   144  					Expect(boundRoutes).To(BeTrue())
   145  
   146  					Expect(returnedConfig.CurrentRoutes).To(Equal(config.DesiredRoutes))
   147  
   148  					Expect(fakeV2Actor.MapRouteToApplicationCallCount()).To(Equal(2))
   149  
   150  					routeGUID, appGUID := fakeV2Actor.MapRouteToApplicationArgsForCall(0)
   151  					Expect(routeGUID).To(Equal("some-route-guid-1"))
   152  					Expect(appGUID).To(Equal("some-app-guid"))
   153  
   154  					routeGUID, appGUID = fakeV2Actor.MapRouteToApplicationArgsForCall(1)
   155  					Expect(routeGUID).To(Equal("some-route-guid-3"))
   156  					Expect(appGUID).To(Equal("some-app-guid"))
   157  				})
   158  			})
   159  
   160  			Context("when the mapping errors", func() {
   161  				Context("when the route is bound in another space", func() {
   162  					BeforeEach(func() {
   163  						fakeV2Actor.MapRouteToApplicationReturns(v2action.Warnings{"map-route-warning"}, actionerror.RouteInDifferentSpaceError{})
   164  					})
   165  
   166  					It("sends the RouteInDifferentSpaceError (with a guid set) and warnings and returns true", func() {
   167  						Expect(executeErr).To(MatchError(actionerror.RouteInDifferentSpaceError{Route: "some-route-1.some-domain.com"}))
   168  						Expect(warnings).To(ConsistOf("map-route-warning"))
   169  					})
   170  				})
   171  
   172  				Context("generic error", func() {
   173  					var expectedErr error
   174  					BeforeEach(func() {
   175  						expectedErr = errors.New("oh my")
   176  						fakeV2Actor.MapRouteToApplicationReturns(v2action.Warnings{"map-route-warning"}, expectedErr)
   177  					})
   178  
   179  					It("sends the warnings and errors and returns true", func() {
   180  						Expect(executeErr).To(MatchError(expectedErr))
   181  						Expect(warnings).To(ConsistOf("map-route-warning"))
   182  					})
   183  				})
   184  			})
   185  		})
   186  
   187  		Context("when no routes need to be bound", func() {
   188  			It("returns false", func() {
   189  				Expect(executeErr).ToNot(HaveOccurred())
   190  			})
   191  		})
   192  	})
   193  
   194  	Describe("CalculateRoutes", func() {
   195  		var (
   196  			routes         []string
   197  			orgGUID        string
   198  			spaceGUID      string
   199  			existingRoutes []v2action.Route
   200  
   201  			calculatedRoutes []v2action.Route
   202  			warnings         Warnings
   203  			executeErr       error
   204  		)
   205  
   206  		BeforeEach(func() {
   207  			routes = []string{
   208  				"a.com",
   209  				"b.a.com",
   210  				"c.b.a.com",
   211  				"d.c.b.a.com",
   212  				"a.com/some-path",
   213  				"*.f.e.com",
   214  				"*.e.com",
   215  			}
   216  			orgGUID = "some-org-guid"
   217  			spaceGUID = "some-space-guid"
   218  		})
   219  
   220  		JustBeforeEach(func() {
   221  			calculatedRoutes, warnings, executeErr = actor.CalculateRoutes(routes, orgGUID, spaceGUID, existingRoutes)
   222  		})
   223  
   224  		Context("when there are no known routes", func() {
   225  			BeforeEach(func() {
   226  				existingRoutes = []v2action.Route{{
   227  					GUID: "some-route-5",
   228  					Host: "banana",
   229  					Domain: v2action.Domain{
   230  						GUID: "domain-guid-1",
   231  						Name: "a.com",
   232  					},
   233  					SpaceGUID: spaceGUID,
   234  				}}
   235  			})
   236  
   237  			Context("when a route looking up the domains is succuessful", func() {
   238  				BeforeEach(func() {
   239  					fakeV2Actor.GetDomainsByNameAndOrganizationReturns([]v2action.Domain{
   240  						{GUID: "domain-guid-1", Name: "a.com"},
   241  						{GUID: "domain-guid-2", Name: "b.a.com"},
   242  						{GUID: "domain-guid-3", Name: "f.e.com"},
   243  						{GUID: "domain-guid-4", Name: "e.com"},
   244  					}, v2action.Warnings{"domain-warnings-1", "domains-warnings-2"}, nil)
   245  				})
   246  
   247  				Context("when the route is invalid", func() {
   248  					BeforeEach(func() {
   249  						routes = []string{"a.com", "b.a.com", "c.b.a.com:1234"}
   250  					})
   251  
   252  					It("returns back warnings and error", func() {
   253  						Expect(executeErr).To(MatchError(actionerror.InvalidHTTPRouteSettings{Domain: "b.a.com"}))
   254  						Expect(warnings).To(ConsistOf("domain-warnings-1", "domains-warnings-2"))
   255  					})
   256  				})
   257  
   258  				Context("when the route existance check is successful", func() {
   259  					BeforeEach(func() {
   260  						fakeV2Actor.FindRouteBoundToSpaceWithSettingsReturns(v2action.Route{}, v2action.Warnings{"find-route-warning"}, actionerror.RouteNotFoundError{})
   261  						fakeV2Actor.FindRouteBoundToSpaceWithSettingsReturnsOnCall(3, v2action.Route{
   262  							GUID: "route-guid-4",
   263  							Host: "d.c",
   264  							Domain: v2action.Domain{
   265  								GUID: "domain-guid-2",
   266  								Name: "b.a.com",
   267  							},
   268  							SpaceGUID: spaceGUID,
   269  						}, v2action.Warnings{"find-route-warning"}, nil)
   270  					})
   271  
   272  					It("returns new and existing routes", func() {
   273  						Expect(executeErr).NotTo(HaveOccurred())
   274  						Expect(warnings).To(ConsistOf("domain-warnings-1", "domains-warnings-2", "find-route-warning", "find-route-warning", "find-route-warning", "find-route-warning", "find-route-warning", "find-route-warning", "find-route-warning"))
   275  						Expect(calculatedRoutes).To(ConsistOf(
   276  							v2action.Route{
   277  								Domain: v2action.Domain{
   278  									GUID: "domain-guid-1",
   279  									Name: "a.com",
   280  								},
   281  								SpaceGUID: spaceGUID,
   282  							},
   283  							v2action.Route{
   284  								Domain: v2action.Domain{
   285  									GUID: "domain-guid-2",
   286  									Name: "b.a.com",
   287  								},
   288  								SpaceGUID: spaceGUID,
   289  							},
   290  							v2action.Route{
   291  								Host: "c",
   292  								Domain: v2action.Domain{
   293  									GUID: "domain-guid-2",
   294  									Name: "b.a.com",
   295  								},
   296  								SpaceGUID: spaceGUID,
   297  							},
   298  							v2action.Route{
   299  								GUID: "route-guid-4",
   300  								Host: "d.c",
   301  								Domain: v2action.Domain{
   302  									GUID: "domain-guid-2",
   303  									Name: "b.a.com",
   304  								},
   305  								SpaceGUID: spaceGUID,
   306  							},
   307  							v2action.Route{
   308  								GUID: "some-route-5",
   309  								Host: "banana",
   310  								Domain: v2action.Domain{
   311  									GUID: "domain-guid-1",
   312  									Name: "a.com",
   313  								},
   314  								SpaceGUID: spaceGUID,
   315  							},
   316  							v2action.Route{
   317  								Host: "",
   318  								Domain: v2action.Domain{
   319  									GUID: "domain-guid-1",
   320  									Name: "a.com",
   321  								},
   322  								Path:      "/some-path",
   323  								SpaceGUID: spaceGUID,
   324  							},
   325  							v2action.Route{
   326  								Host: "*",
   327  								Domain: v2action.Domain{
   328  									GUID: "domain-guid-3",
   329  									Name: "f.e.com",
   330  								},
   331  								SpaceGUID: spaceGUID,
   332  							},
   333  							v2action.Route{
   334  								Host: "*",
   335  								Domain: v2action.Domain{
   336  									GUID: "domain-guid-4",
   337  									Name: "e.com",
   338  								},
   339  								SpaceGUID: spaceGUID,
   340  							}))
   341  
   342  						Expect(fakeV2Actor.GetDomainsByNameAndOrganizationCallCount()).To(Equal(1))
   343  						domains, passedOrgGUID := fakeV2Actor.GetDomainsByNameAndOrganizationArgsForCall(0)
   344  						Expect(domains).To(ConsistOf("a.com", "b.a.com", "c.b.a.com", "d.c.b.a.com", "*.f.e.com", "f.e.com", "*.e.com", "e.com"))
   345  						Expect(passedOrgGUID).To(Equal(orgGUID))
   346  
   347  						Expect(fakeV2Actor.FindRouteBoundToSpaceWithSettingsCallCount()).To(Equal(7))
   348  						// One check is enough here - checking 4th call since it's the only
   349  						// existing one.
   350  						Expect(fakeV2Actor.FindRouteBoundToSpaceWithSettingsArgsForCall(3)).To(Equal(v2action.Route{
   351  							Host: "d.c",
   352  							Domain: v2action.Domain{
   353  								GUID: "domain-guid-2",
   354  								Name: "b.a.com",
   355  							},
   356  							SpaceGUID: spaceGUID,
   357  						}))
   358  					})
   359  				})
   360  
   361  				Context("when the route existance check fails", func() {
   362  					var expectedErr error
   363  
   364  					BeforeEach(func() {
   365  						expectedErr = errors.New("oh noes")
   366  						fakeV2Actor.FindRouteBoundToSpaceWithSettingsReturns(v2action.Route{}, v2action.Warnings{"find-route-warning"}, expectedErr)
   367  					})
   368  
   369  					It("returns back warnings and error", func() {
   370  						Expect(executeErr).To(MatchError(expectedErr))
   371  						Expect(warnings).To(ConsistOf("domain-warnings-1", "domains-warnings-2", "find-route-warning"))
   372  					})
   373  				})
   374  
   375  				Context("when one of the domains does not exist", func() {
   376  					BeforeEach(func() {
   377  						fakeV2Actor.GetDomainsByNameAndOrganizationReturns(nil, v2action.Warnings{"domain-warnings-1", "domains-warnings-2"}, nil)
   378  					})
   379  
   380  					It("returns back warnings and error", func() {
   381  						Expect(executeErr).To(MatchError(actionerror.NoMatchingDomainError{Route: "a.com"}))
   382  						Expect(warnings).To(ConsistOf("domain-warnings-1", "domains-warnings-2"))
   383  					})
   384  				})
   385  			})
   386  
   387  			Context("when looking up a domain returns an error", func() {
   388  				var expectedErr error
   389  
   390  				BeforeEach(func() {
   391  					expectedErr = errors.New("po-tate-toe")
   392  					fakeV2Actor.GetDomainsByNameAndOrganizationReturns(nil, v2action.Warnings{"domain-warnings-1", "domains-warnings-2"}, expectedErr)
   393  				})
   394  
   395  				It("returns back warnings and error", func() {
   396  					Expect(executeErr).To(MatchError(expectedErr))
   397  					Expect(warnings).To(ConsistOf("domain-warnings-1", "domains-warnings-2"))
   398  				})
   399  			})
   400  		})
   401  
   402  		Context("when there are known routes", func() {
   403  			BeforeEach(func() {
   404  				existingRoutes = []v2action.Route{{
   405  					GUID: "route-guid-4",
   406  					Host: "d.c",
   407  					Domain: v2action.Domain{
   408  						GUID: "domain-guid-2",
   409  						Name: "b.a.com",
   410  					},
   411  					SpaceGUID: spaceGUID,
   412  				}}
   413  
   414  				fakeV2Actor.GetDomainsByNameAndOrganizationReturns([]v2action.Domain{
   415  					{GUID: "domain-guid-1", Name: "a.com"},
   416  					{GUID: "domain-guid-2", Name: "b.a.com"},
   417  					{GUID: "domain-guid-3", Name: "f.e.com"},
   418  					{GUID: "domain-guid-4", Name: "e.com"},
   419  				}, v2action.Warnings{"domain-warnings-1", "domains-warnings-2"}, nil)
   420  				fakeV2Actor.FindRouteBoundToSpaceWithSettingsReturns(v2action.Route{}, v2action.Warnings{"find-route-warning"}, actionerror.RouteNotFoundError{})
   421  			})
   422  
   423  			It("does not lookup known routes", func() {
   424  				Expect(executeErr).NotTo(HaveOccurred())
   425  				Expect(warnings).To(ConsistOf("domain-warnings-1", "domains-warnings-2", "find-route-warning", "find-route-warning", "find-route-warning", "find-route-warning", "find-route-warning", "find-route-warning"))
   426  				Expect(calculatedRoutes).To(ConsistOf(
   427  					v2action.Route{
   428  						Domain: v2action.Domain{
   429  							GUID: "domain-guid-1",
   430  							Name: "a.com",
   431  						},
   432  						SpaceGUID: spaceGUID,
   433  					},
   434  					v2action.Route{
   435  						Domain: v2action.Domain{
   436  							GUID: "domain-guid-2",
   437  							Name: "b.a.com",
   438  						},
   439  						SpaceGUID: spaceGUID,
   440  					},
   441  					v2action.Route{
   442  						Host: "c",
   443  						Domain: v2action.Domain{
   444  							GUID: "domain-guid-2",
   445  							Name: "b.a.com",
   446  						},
   447  						SpaceGUID: spaceGUID,
   448  					},
   449  					v2action.Route{
   450  						GUID: "route-guid-4",
   451  						Host: "d.c",
   452  						Domain: v2action.Domain{
   453  							GUID: "domain-guid-2",
   454  							Name: "b.a.com",
   455  						},
   456  						SpaceGUID: spaceGUID,
   457  					},
   458  					v2action.Route{
   459  						Host: "",
   460  						Domain: v2action.Domain{
   461  							GUID: "domain-guid-1",
   462  							Name: "a.com",
   463  						},
   464  						Path:      "/some-path",
   465  						SpaceGUID: spaceGUID,
   466  					},
   467  					v2action.Route{
   468  						Host: "*",
   469  						Domain: v2action.Domain{
   470  							GUID: "domain-guid-3",
   471  							Name: "f.e.com",
   472  						},
   473  						SpaceGUID: spaceGUID,
   474  					},
   475  					v2action.Route{
   476  						Host: "*",
   477  						Domain: v2action.Domain{
   478  							GUID: "domain-guid-4",
   479  							Name: "e.com",
   480  						},
   481  						SpaceGUID: spaceGUID,
   482  					}))
   483  
   484  				Expect(fakeV2Actor.GetDomainsByNameAndOrganizationCallCount()).To(Equal(1))
   485  				domains, passedOrgGUID := fakeV2Actor.GetDomainsByNameAndOrganizationArgsForCall(0)
   486  				Expect(domains).To(ConsistOf("a.com", "b.a.com", "c.b.a.com", "*.f.e.com", "f.e.com", "*.e.com", "e.com"))
   487  				Expect(passedOrgGUID).To(Equal(orgGUID))
   488  			})
   489  		})
   490  	})
   491  
   492  	Describe("CreateAndMapDefaultApplicationRoute", func() {
   493  		var (
   494  			warnings   Warnings
   495  			executeErr error
   496  		)
   497  
   498  		JustBeforeEach(func() {
   499  			warnings, executeErr = actor.CreateAndMapDefaultApplicationRoute("some-org-guid", "some-space-guid",
   500  				v2action.Application{Name: "some-app", GUID: "some-app-guid"})
   501  		})
   502  
   503  		Context("when getting organization domains errors", func() {
   504  			BeforeEach(func() {
   505  				fakeV2Actor.GetOrganizationDomainsReturns(
   506  					[]v2action.Domain{},
   507  					v2action.Warnings{"domain-warning"},
   508  					errors.New("some-error"))
   509  			})
   510  
   511  			It("returns the error", func() {
   512  				Expect(executeErr).To(MatchError("some-error"))
   513  				Expect(warnings).To(ConsistOf("domain-warning"))
   514  			})
   515  		})
   516  
   517  		Context("when getting organization domains succeeds", func() {
   518  			BeforeEach(func() {
   519  				fakeV2Actor.GetOrganizationDomainsReturns(
   520  					[]v2action.Domain{
   521  						{
   522  							GUID: "some-domain-guid",
   523  							Name: "some-domain",
   524  						},
   525  					},
   526  					v2action.Warnings{"domain-warning"},
   527  					nil,
   528  				)
   529  			})
   530  
   531  			Context("when getting the application routes errors", func() {
   532  				BeforeEach(func() {
   533  					fakeV2Actor.GetApplicationRoutesReturns(
   534  						[]v2action.Route{},
   535  						v2action.Warnings{"route-warning"},
   536  						errors.New("some-error"),
   537  					)
   538  				})
   539  
   540  				It("returns the error", func() {
   541  					Expect(executeErr).To(MatchError("some-error"))
   542  					Expect(warnings).To(ConsistOf("domain-warning", "route-warning"))
   543  				})
   544  			})
   545  
   546  			Context("when getting the application routes succeeds", func() {
   547  				// TODO: do we need this context
   548  				Context("when the route is already bound to the app", func() {
   549  					BeforeEach(func() {
   550  						fakeV2Actor.GetApplicationRoutesReturns(
   551  							[]v2action.Route{
   552  								{
   553  									Host: "some-app",
   554  									Domain: v2action.Domain{
   555  										GUID: "some-domain-guid",
   556  										Name: "some-domain",
   557  									},
   558  									GUID:      "some-route-guid",
   559  									SpaceGUID: "some-space-guid",
   560  								},
   561  							},
   562  							v2action.Warnings{"route-warning"},
   563  							nil,
   564  						)
   565  					})
   566  
   567  					It("returns any warnings", func() {
   568  						Expect(executeErr).ToNot(HaveOccurred())
   569  						Expect(warnings).To(ConsistOf("domain-warning", "route-warning"))
   570  
   571  						Expect(fakeV2Actor.GetOrganizationDomainsCallCount()).To(Equal(1), "Expected GetOrganizationDomains to be called once, but it was not")
   572  						orgGUID := fakeV2Actor.GetOrganizationDomainsArgsForCall(0)
   573  						Expect(orgGUID).To(Equal("some-org-guid"))
   574  
   575  						Expect(fakeV2Actor.GetApplicationRoutesCallCount()).To(Equal(1), "Expected GetApplicationRoutes to be called once, but it was not")
   576  						appGUID := fakeV2Actor.GetApplicationRoutesArgsForCall(0)
   577  						Expect(appGUID).To(Equal("some-app-guid"))
   578  
   579  						Expect(fakeV2Actor.CreateRouteCallCount()).To(Equal(0), "Expected CreateRoute to not be called but it was")
   580  						Expect(fakeV2Actor.MapRouteToApplicationCallCount()).To(Equal(0), "Expected MapRouteToApplication to not be called but it was")
   581  					})
   582  				})
   583  
   584  				Context("when the route isn't bound to the app", func() {
   585  					Context("when finding route in space errors", func() {
   586  						BeforeEach(func() {
   587  							fakeV2Actor.FindRouteBoundToSpaceWithSettingsReturns(
   588  								v2action.Route{},
   589  								v2action.Warnings{"route-warning"},
   590  								errors.New("some-error"),
   591  							)
   592  						})
   593  
   594  						It("returns the error", func() {
   595  							Expect(executeErr).To(MatchError("some-error"))
   596  							Expect(warnings).To(ConsistOf("domain-warning", "route-warning"))
   597  						})
   598  					})
   599  
   600  					Context("when the route exists", func() {
   601  						BeforeEach(func() {
   602  							fakeV2Actor.FindRouteBoundToSpaceWithSettingsReturns(
   603  								v2action.Route{
   604  									GUID: "some-route-guid",
   605  									Host: "some-app",
   606  									Domain: v2action.Domain{
   607  										Name: "some-domain",
   608  										GUID: "some-domain-guid",
   609  									},
   610  									SpaceGUID: "some-space-guid",
   611  								},
   612  								v2action.Warnings{"route-warning"},
   613  								nil,
   614  							)
   615  						})
   616  
   617  						Context("when the map command returns an error", func() {
   618  							BeforeEach(func() {
   619  								fakeV2Actor.MapRouteToApplicationReturns(
   620  									v2action.Warnings{"map-warning"},
   621  									errors.New("some-error"),
   622  								)
   623  							})
   624  
   625  							It("returns the error", func() {
   626  								Expect(executeErr).To(MatchError("some-error"))
   627  								Expect(warnings).To(ConsistOf("domain-warning", "route-warning", "map-warning"))
   628  							})
   629  						})
   630  
   631  						Context("when the map command succeeds", func() {
   632  							BeforeEach(func() {
   633  								fakeV2Actor.MapRouteToApplicationReturns(
   634  									v2action.Warnings{"map-warning"},
   635  									nil,
   636  								)
   637  							})
   638  
   639  							It("maps the route to the app and returns any warnings", func() {
   640  								Expect(executeErr).ToNot(HaveOccurred())
   641  								Expect(warnings).To(ConsistOf("domain-warning", "route-warning", "map-warning"))
   642  
   643  								Expect(fakeV2Actor.FindRouteBoundToSpaceWithSettingsCallCount()).To(Equal(1), "Expected FindRouteBoundToSpaceWithSettings to be called once, but it was not")
   644  								spaceRoute := fakeV2Actor.FindRouteBoundToSpaceWithSettingsArgsForCall(0)
   645  								Expect(spaceRoute).To(Equal(v2action.Route{
   646  									Host: "some-app",
   647  									Domain: v2action.Domain{
   648  										Name: "some-domain",
   649  										GUID: "some-domain-guid",
   650  									},
   651  									SpaceGUID: "some-space-guid",
   652  								}))
   653  
   654  								Expect(fakeV2Actor.MapRouteToApplicationCallCount()).To(Equal(1), "Expected MapRouteToApplication to be called once, but it was not")
   655  								routeGUID, appGUID := fakeV2Actor.MapRouteToApplicationArgsForCall(0)
   656  								Expect(routeGUID).To(Equal("some-route-guid"))
   657  								Expect(appGUID).To(Equal("some-app-guid"))
   658  							})
   659  						})
   660  					})
   661  
   662  					Context("when the route does not exist", func() {
   663  						BeforeEach(func() {
   664  							fakeV2Actor.FindRouteBoundToSpaceWithSettingsReturns(
   665  								v2action.Route{},
   666  								v2action.Warnings{"route-warning"},
   667  								actionerror.RouteNotFoundError{},
   668  							)
   669  						})
   670  
   671  						Context("when the create route command errors", func() {
   672  							BeforeEach(func() {
   673  								fakeV2Actor.CreateRouteReturns(
   674  									v2action.Route{},
   675  									v2action.Warnings{"route-create-warning"},
   676  									errors.New("some-error"),
   677  								)
   678  							})
   679  
   680  							It("returns the error", func() {
   681  								Expect(executeErr).To(MatchError("some-error"))
   682  								Expect(warnings).To(ConsistOf("domain-warning", "route-warning", "route-create-warning"))
   683  							})
   684  						})
   685  
   686  						Context("when the create route command succeeds", func() {
   687  							BeforeEach(func() {
   688  								fakeV2Actor.CreateRouteReturns(
   689  									v2action.Route{
   690  										GUID: "some-route-guid",
   691  										Host: "some-app",
   692  										Domain: v2action.Domain{
   693  											Name: "some-domain",
   694  											GUID: "some-domain-guid",
   695  										},
   696  										SpaceGUID: "some-space-guid",
   697  									},
   698  									v2action.Warnings{"route-create-warning"},
   699  									nil,
   700  								)
   701  							})
   702  
   703  							Context("when the map command errors", func() {
   704  								BeforeEach(func() {
   705  									fakeV2Actor.MapRouteToApplicationReturns(
   706  										v2action.Warnings{"map-warning"},
   707  										errors.New("some-error"),
   708  									)
   709  								})
   710  
   711  								It("returns the error", func() {
   712  									Expect(executeErr).To(MatchError("some-error"))
   713  									Expect(warnings).To(ConsistOf("domain-warning", "route-warning", "route-create-warning", "map-warning"))
   714  								})
   715  							})
   716  							Context("when the map command succeeds", func() {
   717  
   718  								BeforeEach(func() {
   719  									fakeV2Actor.MapRouteToApplicationReturns(
   720  										v2action.Warnings{"map-warning"},
   721  										nil,
   722  									)
   723  								})
   724  
   725  								It("creates the route, maps it to the app, and returns any warnings", func() {
   726  									Expect(executeErr).ToNot(HaveOccurred())
   727  									Expect(warnings).To(ConsistOf("domain-warning", "route-warning", "route-create-warning", "map-warning"))
   728  
   729  									Expect(fakeV2Actor.CreateRouteCallCount()).To(Equal(1), "Expected CreateRoute to be called once, but it was not")
   730  									defaultRoute, shouldGeneratePort := fakeV2Actor.CreateRouteArgsForCall(0)
   731  									Expect(defaultRoute).To(Equal(v2action.Route{
   732  										Host: "some-app",
   733  										Domain: v2action.Domain{
   734  											Name: "some-domain",
   735  											GUID: "some-domain-guid",
   736  										},
   737  										SpaceGUID: "some-space-guid",
   738  									}))
   739  									Expect(shouldGeneratePort).To(BeFalse())
   740  
   741  									Expect(fakeV2Actor.FindRouteBoundToSpaceWithSettingsCallCount()).To(Equal(1), "Expected FindRouteBoundToSpaceWithSettings to be called once, but it was not")
   742  									spaceRoute := fakeV2Actor.FindRouteBoundToSpaceWithSettingsArgsForCall(0)
   743  									Expect(spaceRoute).To(Equal(v2action.Route{
   744  										Host: "some-app",
   745  										Domain: v2action.Domain{
   746  											Name: "some-domain",
   747  											GUID: "some-domain-guid",
   748  										},
   749  										SpaceGUID: "some-space-guid",
   750  									}))
   751  
   752  									Expect(fakeV2Actor.MapRouteToApplicationCallCount()).To(Equal(1), "Expected MapRouteToApplication to be called once, but it was not")
   753  									routeGUID, appGUID := fakeV2Actor.MapRouteToApplicationArgsForCall(0)
   754  									Expect(routeGUID).To(Equal("some-route-guid"))
   755  									Expect(appGUID).To(Equal("some-app-guid"))
   756  								})
   757  							})
   758  						})
   759  					})
   760  				})
   761  			})
   762  		})
   763  	})
   764  
   765  	Describe("CreateRoutes", func() {
   766  		var (
   767  			config ApplicationConfig
   768  
   769  			returnedConfig ApplicationConfig
   770  			createdRoutes  bool
   771  			warnings       Warnings
   772  			executeErr     error
   773  		)
   774  
   775  		BeforeEach(func() {
   776  			config = ApplicationConfig{}
   777  		})
   778  
   779  		JustBeforeEach(func() {
   780  			returnedConfig, createdRoutes, warnings, executeErr = actor.CreateRoutes(config)
   781  		})
   782  
   783  		Describe("when routes need to be created", func() {
   784  			BeforeEach(func() {
   785  				config.DesiredRoutes = []v2action.Route{
   786  					{GUID: "", Host: "some-route-1"},
   787  					{GUID: "some-route-guid-2", Host: "some-route-2"},
   788  					{GUID: "", Host: "some-route-3"},
   789  					{GUID: "", Host: "", Domain: v2action.Domain{RouterGroupType: constant.TCPRouterGroup}},
   790  				}
   791  			})
   792  
   793  			Context("when the creation is successful", func() {
   794  				BeforeEach(func() {
   795  					fakeV2Actor.CreateRouteReturnsOnCall(0, v2action.Route{GUID: "some-route-guid-1", Host: "some-route-1"}, v2action.Warnings{"create-route-warning"}, nil)
   796  					fakeV2Actor.CreateRouteReturnsOnCall(1, v2action.Route{GUID: "some-route-guid-3", Host: "some-route-3"}, v2action.Warnings{"create-route-warning"}, nil)
   797  					fakeV2Actor.CreateRouteReturnsOnCall(2, v2action.Route{GUID: "some-route-guid-4", Domain: v2action.Domain{RouterGroupType: constant.TCPRouterGroup}}, v2action.Warnings{"create-route-warning"}, nil)
   798  				})
   799  
   800  				It("only creates the routes that do not exist", func() {
   801  					Expect(executeErr).ToNot(HaveOccurred())
   802  					Expect(warnings).To(ConsistOf("create-route-warning", "create-route-warning", "create-route-warning"))
   803  					Expect(createdRoutes).To(BeTrue())
   804  					Expect(returnedConfig.DesiredRoutes).To(Equal([]v2action.Route{
   805  						{GUID: "some-route-guid-1", Host: "some-route-1"},
   806  						{GUID: "some-route-guid-2", Host: "some-route-2"},
   807  						{GUID: "some-route-guid-3", Host: "some-route-3"},
   808  						{GUID: "some-route-guid-4", Domain: v2action.Domain{RouterGroupType: constant.TCPRouterGroup}},
   809  					}))
   810  
   811  					Expect(fakeV2Actor.CreateRouteCallCount()).To(Equal(3))
   812  
   813  					passedRoute, randomRoute := fakeV2Actor.CreateRouteArgsForCall(0)
   814  					Expect(passedRoute).To(Equal(v2action.Route{Host: "some-route-1"}))
   815  					Expect(randomRoute).To(BeFalse())
   816  
   817  					passedRoute, randomRoute = fakeV2Actor.CreateRouteArgsForCall(1)
   818  					Expect(passedRoute).To(Equal(v2action.Route{Host: "some-route-3"}))
   819  					Expect(randomRoute).To(BeFalse())
   820  
   821  					passedRoute, randomRoute = fakeV2Actor.CreateRouteArgsForCall(2)
   822  					Expect(passedRoute).To(Equal(v2action.Route{GUID: "", Host: "", Domain: v2action.Domain{RouterGroupType: constant.TCPRouterGroup}}))
   823  					Expect(randomRoute).To(BeTrue())
   824  				})
   825  			})
   826  
   827  			Context("when the creation errors", func() {
   828  				var expectedErr error
   829  
   830  				BeforeEach(func() {
   831  					expectedErr = errors.New("oh my")
   832  					fakeV2Actor.CreateRouteReturns(
   833  						v2action.Route{},
   834  						v2action.Warnings{"create-route-warning"},
   835  						expectedErr)
   836  				})
   837  
   838  				It("sends the warnings and errors and returns true", func() {
   839  					Expect(executeErr).To(MatchError(expectedErr))
   840  					Expect(warnings).To(ConsistOf("create-route-warning"))
   841  				})
   842  			})
   843  		})
   844  
   845  		Context("when no routes are created", func() {
   846  			BeforeEach(func() {
   847  				config.DesiredRoutes = []v2action.Route{
   848  					{GUID: "some-route-guid-1", Host: "some-route-1"},
   849  					{GUID: "some-route-guid-2", Host: "some-route-2"},
   850  					{GUID: "some-route-guid-3", Host: "some-route-3"},
   851  				}
   852  			})
   853  
   854  			It("returns false", func() {
   855  				Expect(createdRoutes).To(BeFalse())
   856  			})
   857  		})
   858  	})
   859  
   860  	Describe("GenerateRandomRoute", func() {
   861  		var (
   862  			spaceGUID string
   863  			orgGUID   string
   864  
   865  			randomRoute v2action.Route
   866  			warnings    Warnings
   867  			executeErr  error
   868  
   869  			domain      v2action.Domain
   870  			manifestApp manifest.Application
   871  		)
   872  
   873  		BeforeEach(func() {
   874  			manifestApp = manifest.Application{
   875  				Name: "some a$pp nAme",
   876  			}
   877  			spaceGUID = "some-space-guid"
   878  			orgGUID = "some-org-guid"
   879  			domain = v2action.Domain{}
   880  		})
   881  
   882  		JustBeforeEach(func() {
   883  			randomRoute, warnings, executeErr = actor.GenerateRandomRoute(manifestApp, spaceGUID, orgGUID)
   884  		})
   885  
   886  		Context("when a domain is specified", func() {
   887  			BeforeEach(func() {
   888  				manifestApp.Domain = "some-domain"
   889  				domain.Name = "some-domain"
   890  				fakeRandomWordGenerator.RandomAdjectiveReturns("striped")
   891  				fakeRandomWordGenerator.RandomNounReturns("apple")
   892  
   893  				fakeV2Actor.GetDomainsByNameAndOrganizationReturns(
   894  					[]v2action.Domain{domain},
   895  					v2action.Warnings{"some-organization-domain-warning"},
   896  					nil,
   897  				)
   898  			})
   899  
   900  			It("uses the specified domain to generate a route", func() {
   901  				Expect(executeErr).ToNot(HaveOccurred())
   902  				Expect(randomRoute).To(Equal(v2action.Route{
   903  					Domain:    domain,
   904  					Host:      "some-app-name-striped-apple",
   905  					SpaceGUID: spaceGUID,
   906  				}))
   907  				Expect(warnings).To(ConsistOf("some-organization-domain-warning"))
   908  
   909  				Expect(fakeV2Actor.GetDomainsByNameAndOrganizationCallCount()).To(Equal(1))
   910  				domainsArg, orgGUIDArg := fakeV2Actor.GetDomainsByNameAndOrganizationArgsForCall(0)
   911  				Expect(domainsArg).To(ConsistOf("some-domain"))
   912  				Expect(orgGUIDArg).To(Equal("some-org-guid"))
   913  			})
   914  		})
   915  
   916  		Context("when no domain is specified", func() {
   917  			Context("when the default domain is a tcp domain", func() {
   918  				BeforeEach(func() {
   919  					domain.RouterGroupType = constant.TCPRouterGroup
   920  					fakeV2Actor.GetOrganizationDomainsReturns(
   921  						[]v2action.Domain{domain},
   922  						v2action.Warnings{"some-organization-domain-warning"},
   923  						nil,
   924  					)
   925  				})
   926  
   927  				It("generates a route with a randomly generated server side port number", func() {
   928  					Expect(executeErr).ToNot(HaveOccurred())
   929  					Expect(randomRoute).To(Equal(v2action.Route{
   930  						Domain:    domain,
   931  						SpaceGUID: spaceGUID,
   932  					}))
   933  					Expect(warnings).To(ConsistOf("some-organization-domain-warning"))
   934  
   935  					Expect(fakeV2Actor.GetOrganizationDomainsCallCount()).To(Equal(1))
   936  					Expect(fakeV2Actor.GetOrganizationDomainsArgsForCall(0)).To(Equal(orgGUID))
   937  				})
   938  			})
   939  
   940  			Context("when the default domain is an http domain", func() {
   941  				BeforeEach(func() {
   942  					domain.RouterGroupType = constant.HTTPRouterGroup
   943  					fakeV2Actor.GetOrganizationDomainsReturns(
   944  						[]v2action.Domain{domain},
   945  						v2action.Warnings{"some-organization-domain-warning"},
   946  						nil,
   947  					)
   948  					fakeRandomWordGenerator.RandomAdjectiveReturns("striped")
   949  					fakeRandomWordGenerator.RandomNounReturns("apple")
   950  				})
   951  
   952  				Context("when the app name is partially sanitized", func() {
   953  					BeforeEach(func() {
   954  						manifestApp.Name = "a--b"
   955  					})
   956  
   957  					It("generates a route whose hostname is a sanitized app name and two randomly generated words", func() {
   958  						Expect(executeErr).ToNot(HaveOccurred())
   959  						Expect(randomRoute).To(Equal(v2action.Route{
   960  							Domain:    domain,
   961  							SpaceGUID: spaceGUID,
   962  							Host:      "a--b-striped-apple",
   963  						}))
   964  						Expect(warnings).To(ConsistOf("some-organization-domain-warning"))
   965  					})
   966  				})
   967  
   968  				Context("when the app name is fully sanitized", func() {
   969  					BeforeEach(func() {
   970  						manifestApp.Name = "@@@"
   971  					})
   972  
   973  					It("generates a route whose hostname is a sanitized app name and two randomly generated words", func() {
   974  						Expect(executeErr).ToNot(HaveOccurred())
   975  						Expect(randomRoute).To(Equal(v2action.Route{
   976  							Domain:    domain,
   977  							SpaceGUID: spaceGUID,
   978  							Host:      "striped-apple",
   979  						}))
   980  						Expect(warnings).To(ConsistOf("some-organization-domain-warning"))
   981  					})
   982  				})
   983  			})
   984  
   985  			Context("when the default domain lookup fails", func() {
   986  				BeforeEach(func() {
   987  					fakeV2Actor.GetOrganizationDomainsReturns(
   988  						[]v2action.Domain{domain},
   989  						v2action.Warnings{"some-organization-domain-warning"},
   990  						errors.New("some-error"),
   991  					)
   992  				})
   993  				It("returns an error and a warning", func() {
   994  					Expect(executeErr).To(MatchError("some-error"))
   995  					Expect(warnings).To(ConsistOf("some-organization-domain-warning"))
   996  				})
   997  			})
   998  		})
   999  	})
  1000  
  1001  	Describe("GetGeneratedRoute", func() {
  1002  		var (
  1003  			providedManifest manifest.Application
  1004  			orgGUID          string
  1005  			spaceGUID        string
  1006  			knownRoutes      []v2action.Route
  1007  
  1008  			defaultRoute v2action.Route
  1009  			warnings     Warnings
  1010  			executeErr   error
  1011  
  1012  			domain v2action.Domain
  1013  		)
  1014  
  1015  		BeforeEach(func() {
  1016  			providedManifest = manifest.Application{
  1017  				Name: "Some-App",
  1018  			}
  1019  			orgGUID = "some-org-guid"
  1020  			spaceGUID = "some-space-guid"
  1021  			knownRoutes = nil
  1022  
  1023  			domain = v2action.Domain{
  1024  				Name: "shared-domain.com",
  1025  				GUID: "some-shared-domain-guid",
  1026  			}
  1027  		})
  1028  
  1029  		JustBeforeEach(func() {
  1030  			defaultRoute, warnings, executeErr = actor.GetGeneratedRoute(providedManifest, orgGUID, spaceGUID, knownRoutes)
  1031  		})
  1032  
  1033  		Context("the domain is provided", func() {
  1034  			BeforeEach(func() {
  1035  				providedManifest.Domain = "shared-domain.com"
  1036  			})
  1037  
  1038  			Context("when the provided domain exists", func() {
  1039  				BeforeEach(func() {
  1040  					domain.Type = constant.SharedDomain
  1041  
  1042  					// Assumes new route
  1043  					fakeV2Actor.FindRouteBoundToSpaceWithSettingsReturns(v2action.Route{}, v2action.Warnings{"get-route-warnings"}, actionerror.RouteNotFoundError{})
  1044  				})
  1045  
  1046  				Context("when the provided domain is an HTTP domain", func() {
  1047  					BeforeEach(func() {
  1048  						fakeV2Actor.GetDomainsByNameAndOrganizationReturns(
  1049  							[]v2action.Domain{domain},
  1050  							v2action.Warnings{"some-organization-domain-warning"},
  1051  							nil,
  1052  						)
  1053  					})
  1054  
  1055  					It("it uses the provided domain instead of the first shared domain", func() {
  1056  						Expect(executeErr).ToNot(HaveOccurred())
  1057  						Expect(warnings).To(ConsistOf("some-organization-domain-warning", "get-route-warnings"))
  1058  						Expect(defaultRoute).To(Equal(v2action.Route{
  1059  							Domain:    domain,
  1060  							Host:      strings.ToLower(providedManifest.Name),
  1061  							SpaceGUID: spaceGUID,
  1062  						}))
  1063  
  1064  						Expect(fakeV2Actor.GetDomainsByNameAndOrganizationCallCount()).To(Equal(1))
  1065  						domainNamesArg, orgGUIDArg := fakeV2Actor.GetDomainsByNameAndOrganizationArgsForCall(0)
  1066  						Expect(domainNamesArg).To(Equal([]string{"shared-domain.com"}))
  1067  						Expect(orgGUIDArg).To(Equal(orgGUID))
  1068  
  1069  						Expect(fakeV2Actor.FindRouteBoundToSpaceWithSettingsCallCount()).To(Equal(1))
  1070  						Expect(fakeV2Actor.FindRouteBoundToSpaceWithSettingsArgsForCall(0)).To(Equal(v2action.Route{
  1071  							Domain:    domain,
  1072  							Host:      strings.ToLower(providedManifest.Name),
  1073  							SpaceGUID: spaceGUID,
  1074  						}))
  1075  					})
  1076  				})
  1077  
  1078  				Context("when the provided domain is an TCP domain", func() {
  1079  					BeforeEach(func() {
  1080  						domain.RouterGroupType = constant.TCPRouterGroup
  1081  
  1082  						fakeV2Actor.GetDomainsByNameAndOrganizationReturns(
  1083  							[]v2action.Domain{domain},
  1084  							v2action.Warnings{"some-organization-domain-warning"},
  1085  							nil,
  1086  						)
  1087  					})
  1088  
  1089  					It("it uses the provided domain instead of the first shared domain and has no host", func() {
  1090  						Expect(executeErr).ToNot(HaveOccurred())
  1091  						Expect(warnings).To(ConsistOf("some-organization-domain-warning"))
  1092  						Expect(defaultRoute).To(Equal(v2action.Route{
  1093  							Domain:    domain,
  1094  							SpaceGUID: spaceGUID,
  1095  						}))
  1096  
  1097  						Expect(fakeV2Actor.GetDomainsByNameAndOrganizationCallCount()).To(Equal(1))
  1098  						domainNamesArg, orgGUIDArg := fakeV2Actor.GetDomainsByNameAndOrganizationArgsForCall(0)
  1099  						Expect(domainNamesArg).To(Equal([]string{"shared-domain.com"}))
  1100  						Expect(orgGUIDArg).To(Equal(orgGUID))
  1101  
  1102  						Expect(fakeV2Actor.FindRouteBoundToSpaceWithSettingsCallCount()).To(Equal(0))
  1103  					})
  1104  				})
  1105  			})
  1106  
  1107  			Context("when the provided domain does not exist", func() {
  1108  				BeforeEach(func() {
  1109  					fakeV2Actor.GetDomainsByNameAndOrganizationReturns(
  1110  						[]v2action.Domain{},
  1111  						v2action.Warnings{"some-organization-domain-warning"},
  1112  						nil,
  1113  					)
  1114  				})
  1115  
  1116  				It("returns an DomainNotFoundError", func() {
  1117  					Expect(executeErr).To(MatchError(actionerror.DomainNotFoundError{Name: "shared-domain.com"}))
  1118  					Expect(warnings).To(ConsistOf("some-organization-domain-warning"))
  1119  				})
  1120  			})
  1121  		})
  1122  
  1123  		Context("the hostname is provided", func() {
  1124  			BeforeEach(func() {
  1125  				providedManifest.Hostname = "some HO_ST"
  1126  			})
  1127  
  1128  			Context("when the domain is an HTTP domain", func() {
  1129  				BeforeEach(func() {
  1130  					domain.Type = constant.SharedDomain
  1131  					fakeV2Actor.GetOrganizationDomainsReturns(
  1132  						[]v2action.Domain{domain},
  1133  						v2action.Warnings{"some-organization-domain-warning"},
  1134  						nil,
  1135  					)
  1136  
  1137  					// Assumes new route
  1138  					fakeV2Actor.FindRouteBoundToSpaceWithSettingsReturns(v2action.Route{}, v2action.Warnings{"get-route-warnings"}, actionerror.RouteNotFoundError{})
  1139  				})
  1140  
  1141  				It("it uses the provided hostname instead of the app name", func() {
  1142  					Expect(executeErr).ToNot(HaveOccurred())
  1143  					Expect(warnings).To(ConsistOf("some-organization-domain-warning", "get-route-warnings"))
  1144  					Expect(defaultRoute).To(Equal(v2action.Route{
  1145  						Domain:    domain,
  1146  						Host:      "some-host",
  1147  						SpaceGUID: spaceGUID,
  1148  					}))
  1149  
  1150  					Expect(fakeV2Actor.FindRouteBoundToSpaceWithSettingsCallCount()).To(Equal(1))
  1151  					Expect(fakeV2Actor.FindRouteBoundToSpaceWithSettingsArgsForCall(0)).To(Equal(v2action.Route{
  1152  						Domain:    domain,
  1153  						Host:      "some-host",
  1154  						SpaceGUID: spaceGUID,
  1155  					}))
  1156  				})
  1157  			})
  1158  
  1159  			Context("when the provided domain is an TCP domain", func() {
  1160  				BeforeEach(func() {
  1161  					domain.RouterGroupType = constant.TCPRouterGroup
  1162  					fakeV2Actor.GetOrganizationDomainsReturns(
  1163  						[]v2action.Domain{domain},
  1164  						v2action.Warnings{"some-organization-domain-warning"},
  1165  						nil,
  1166  					)
  1167  				})
  1168  
  1169  				It("returns an error", func() {
  1170  					Expect(executeErr).To(MatchError(actionerror.HostnameWithTCPDomainError{}))
  1171  					Expect(warnings).To(ConsistOf("some-organization-domain-warning"))
  1172  				})
  1173  			})
  1174  		})
  1175  
  1176  		Context("when no hostname is requested", func() {
  1177  			BeforeEach(func() {
  1178  				providedManifest.NoHostname = true
  1179  
  1180  				// Assumes new route
  1181  				fakeV2Actor.FindRouteBoundToSpaceWithSettingsReturns(v2action.Route{}, v2action.Warnings{"get-route-warnings"}, actionerror.RouteNotFoundError{})
  1182  			})
  1183  
  1184  			Context("the domain is a private domain", func() {
  1185  				BeforeEach(func() {
  1186  					domain.Type = constant.PrivateDomain
  1187  					fakeV2Actor.GetOrganizationDomainsReturns([]v2action.Domain{domain}, nil, nil)
  1188  				})
  1189  
  1190  				It("does not set the hostname for the route", func() {
  1191  					Expect(executeErr).ToNot(HaveOccurred())
  1192  					Expect(defaultRoute).To(Equal(v2action.Route{
  1193  						Domain:    domain,
  1194  						SpaceGUID: spaceGUID,
  1195  					}))
  1196  
  1197  					Expect(fakeV2Actor.FindRouteBoundToSpaceWithSettingsCallCount()).To(Equal(1))
  1198  					Expect(fakeV2Actor.FindRouteBoundToSpaceWithSettingsArgsForCall(0)).To(Equal(v2action.Route{
  1199  						Domain:    domain,
  1200  						SpaceGUID: spaceGUID,
  1201  					}))
  1202  				})
  1203  			})
  1204  
  1205  			Context("the domain is a shared domain", func() {
  1206  				Context("when the domain is a TCP Domain", func() {
  1207  					BeforeEach(func() {
  1208  						domain.Type = constant.SharedDomain
  1209  						domain.RouterGroupType = constant.TCPRouterGroup
  1210  						fakeV2Actor.GetOrganizationDomainsReturns([]v2action.Domain{domain}, v2action.Warnings{"private-domain-warnings", "shared-domain-warnings"}, nil)
  1211  					})
  1212  
  1213  					It("returns a TCP route", func() {
  1214  						Expect(executeErr).ToNot(HaveOccurred())
  1215  						Expect(warnings).To(ConsistOf("private-domain-warnings", "shared-domain-warnings"))
  1216  						Expect(defaultRoute).To(Equal(v2action.Route{
  1217  							Domain:    domain,
  1218  							SpaceGUID: spaceGUID,
  1219  						}))
  1220  					})
  1221  				})
  1222  
  1223  				Context("when the domain is an HTTP Domain", func() {
  1224  					BeforeEach(func() {
  1225  						domain.Type = constant.SharedDomain
  1226  						fakeV2Actor.GetOrganizationDomainsReturns([]v2action.Domain{domain}, v2action.Warnings{"private-domain-warnings", "shared-domain-warnings"}, nil)
  1227  					})
  1228  
  1229  					It("returns an error and warnings", func() {
  1230  						Expect(executeErr).To(MatchError(actionerror.NoHostnameAndSharedDomainError{}))
  1231  						Expect(warnings).To(ConsistOf("private-domain-warnings", "shared-domain-warnings"))
  1232  					})
  1233  				})
  1234  			})
  1235  		})
  1236  
  1237  		Context("the route path is provided", func() {
  1238  			BeforeEach(func() {
  1239  				providedManifest.RoutePath = "/some-route-path"
  1240  			})
  1241  
  1242  			Context("when the domain is an HTTP domain", func() {
  1243  				BeforeEach(func() {
  1244  					domain.Type = constant.SharedDomain
  1245  					fakeV2Actor.GetOrganizationDomainsReturns(
  1246  						[]v2action.Domain{domain},
  1247  						v2action.Warnings{"some-organization-domain-warning"},
  1248  						nil,
  1249  					)
  1250  
  1251  					// Assumes new route
  1252  					fakeV2Actor.FindRouteBoundToSpaceWithSettingsReturns(v2action.Route{}, v2action.Warnings{"get-route-warnings"}, actionerror.RouteNotFoundError{})
  1253  				})
  1254  
  1255  				It("it uses the provided route-path for the route", func() {
  1256  					Expect(executeErr).ToNot(HaveOccurred())
  1257  					Expect(warnings).To(ConsistOf("some-organization-domain-warning", "get-route-warnings"))
  1258  					Expect(defaultRoute).To(Equal(v2action.Route{
  1259  						Domain:    domain,
  1260  						Host:      "some-app",
  1261  						SpaceGUID: spaceGUID,
  1262  						Path:      "/some-route-path",
  1263  					}))
  1264  
  1265  					Expect(fakeV2Actor.FindRouteBoundToSpaceWithSettingsCallCount()).To(Equal(1))
  1266  					Expect(fakeV2Actor.FindRouteBoundToSpaceWithSettingsArgsForCall(0)).To(Equal(v2action.Route{
  1267  						Domain:    domain,
  1268  						Host:      "some-app",
  1269  						SpaceGUID: spaceGUID,
  1270  						Path:      "/some-route-path",
  1271  					}))
  1272  				})
  1273  			})
  1274  
  1275  			Context("when the provided domain is a TCP domain", func() {
  1276  				BeforeEach(func() {
  1277  					domain.RouterGroupType = constant.TCPRouterGroup
  1278  					fakeV2Actor.GetOrganizationDomainsReturns(
  1279  						[]v2action.Domain{domain},
  1280  						v2action.Warnings{"some-organization-domain-warning"},
  1281  						nil,
  1282  					)
  1283  				})
  1284  
  1285  				It("returns an error", func() {
  1286  					Expect(executeErr).To(MatchError(actionerror.RoutePathWithTCPDomainError{}))
  1287  					Expect(warnings).To(ConsistOf("some-organization-domain-warning"))
  1288  				})
  1289  
  1290  			})
  1291  		})
  1292  
  1293  		Context("when no route settings are provided (default route)", func() {
  1294  			Context("when retrieving the domains is successful", func() {
  1295  				BeforeEach(func() {
  1296  					fakeV2Actor.GetOrganizationDomainsReturns(
  1297  						[]v2action.Domain{domain},
  1298  						v2action.Warnings{"private-domain-warnings", "shared-domain-warnings"},
  1299  						nil,
  1300  					)
  1301  				})
  1302  
  1303  				Context("when the app name is simple", func() {
  1304  					Context("when the route exists", func() {
  1305  						BeforeEach(func() {
  1306  							fakeV2Actor.FindRouteBoundToSpaceWithSettingsReturns(v2action.Route{
  1307  								Domain:    domain,
  1308  								GUID:      "some-route-guid",
  1309  								Host:      "some-app",
  1310  								SpaceGUID: spaceGUID,
  1311  							}, v2action.Warnings{"get-route-warnings"}, nil)
  1312  						})
  1313  
  1314  						It("returns the route and warnings", func() {
  1315  							Expect(executeErr).ToNot(HaveOccurred())
  1316  							Expect(warnings).To(ConsistOf("private-domain-warnings", "shared-domain-warnings", "get-route-warnings"))
  1317  
  1318  							Expect(defaultRoute).To(Equal(v2action.Route{
  1319  								Domain:    domain,
  1320  								GUID:      "some-route-guid",
  1321  								Host:      "some-app",
  1322  								SpaceGUID: spaceGUID,
  1323  							}))
  1324  
  1325  							Expect(fakeV2Actor.GetOrganizationDomainsCallCount()).To(Equal(1))
  1326  							Expect(fakeV2Actor.GetOrganizationDomainsArgsForCall(0)).To(Equal(orgGUID))
  1327  
  1328  							Expect(fakeV2Actor.FindRouteBoundToSpaceWithSettingsCallCount()).To(Equal(1))
  1329  							Expect(fakeV2Actor.FindRouteBoundToSpaceWithSettingsArgsForCall(0)).To(Equal(v2action.Route{
  1330  								Domain:    domain,
  1331  								Host:      strings.ToLower(providedManifest.Name),
  1332  								SpaceGUID: spaceGUID,
  1333  							}))
  1334  						})
  1335  
  1336  						Context("when the route is in known routes", func() {
  1337  							BeforeEach(func() {
  1338  								knownRoutes = []v2action.Route{{
  1339  									Domain:    domain,
  1340  									GUID:      "some-route-guid",
  1341  									Host:      strings.ToLower(providedManifest.Name),
  1342  									SpaceGUID: spaceGUID,
  1343  								}}
  1344  							})
  1345  
  1346  							It("should return the known route and warnings", func() {
  1347  								Expect(executeErr).ToNot(HaveOccurred())
  1348  								Expect(warnings).To(ConsistOf("private-domain-warnings", "shared-domain-warnings"))
  1349  
  1350  								Expect(defaultRoute).To(Equal(v2action.Route{
  1351  									Domain:    domain,
  1352  									GUID:      "some-route-guid",
  1353  									Host:      strings.ToLower(providedManifest.Name),
  1354  									SpaceGUID: spaceGUID,
  1355  								}))
  1356  
  1357  								Expect(fakeV2Actor.FindRouteBoundToSpaceWithSettingsCallCount()).To(Equal(0))
  1358  							})
  1359  						})
  1360  
  1361  						Context("when the route does not exist", func() {
  1362  							BeforeEach(func() {
  1363  								fakeV2Actor.FindRouteBoundToSpaceWithSettingsReturns(v2action.Route{}, v2action.Warnings{"get-route-warnings"}, actionerror.RouteNotFoundError{})
  1364  							})
  1365  
  1366  							It("returns a partial route", func() {
  1367  								Expect(executeErr).ToNot(HaveOccurred())
  1368  								Expect(warnings).To(ConsistOf("private-domain-warnings", "shared-domain-warnings", "get-route-warnings"))
  1369  
  1370  								Expect(defaultRoute).To(Equal(v2action.Route{Domain: domain, Host: strings.ToLower(providedManifest.Name), SpaceGUID: spaceGUID}))
  1371  							})
  1372  						})
  1373  
  1374  						Context("when retrieving the routes errors", func() {
  1375  							var expectedErr error
  1376  
  1377  							BeforeEach(func() {
  1378  								expectedErr = errors.New("whoops")
  1379  								fakeV2Actor.FindRouteBoundToSpaceWithSettingsReturns(v2action.Route{}, v2action.Warnings{"get-route-warnings"}, expectedErr)
  1380  							})
  1381  
  1382  							It("returns errors and warnings", func() {
  1383  								Expect(executeErr).To(MatchError(expectedErr))
  1384  								Expect(warnings).To(ConsistOf("private-domain-warnings", "shared-domain-warnings", "get-route-warnings"))
  1385  							})
  1386  						})
  1387  					})
  1388  				})
  1389  
  1390  				Context("when the app name is complex", func() {
  1391  					BeforeEach(func() {
  1392  						providedManifest.Name = "$Some App 1234567890"
  1393  					})
  1394  
  1395  					It("provides the sanitized application name to FindRouteBoundToSpaceWithSettings", func() {
  1396  						Expect(fakeV2Actor.FindRouteBoundToSpaceWithSettingsCallCount()).To(Equal(1))
  1397  						Expect(fakeV2Actor.FindRouteBoundToSpaceWithSettingsArgsForCall(0)).To(Equal(v2action.Route{
  1398  							Domain:    domain,
  1399  							Host:      "some-app-1234567890",
  1400  							SpaceGUID: spaceGUID,
  1401  						}))
  1402  					})
  1403  				})
  1404  
  1405  				Context("when the app name is not a usable hostname", func() {
  1406  					BeforeEach(func() {
  1407  						providedManifest.Name = " %^ @# **(& "
  1408  					})
  1409  
  1410  					It("provides the sanitized application name to FindRouteBoundToSpaceWithSettings", func() {
  1411  						Expect(fakeV2Actor.FindRouteBoundToSpaceWithSettingsCallCount()).To(Equal(1))
  1412  						Expect(fakeV2Actor.FindRouteBoundToSpaceWithSettingsArgsForCall(0)).To(Equal(v2action.Route{
  1413  							Domain:    domain,
  1414  							SpaceGUID: spaceGUID,
  1415  						}))
  1416  					})
  1417  				})
  1418  			})
  1419  
  1420  			Context("when retrieving the domains errors", func() {
  1421  				var expectedErr error
  1422  
  1423  				BeforeEach(func() {
  1424  					expectedErr = errors.New("whoops")
  1425  					fakeV2Actor.GetOrganizationDomainsReturns([]v2action.Domain{}, v2action.Warnings{"private-domain-warnings", "shared-domain-warnings"}, expectedErr)
  1426  				})
  1427  
  1428  				It("returns errors and warnings", func() {
  1429  					Expect(executeErr).To(MatchError(expectedErr))
  1430  					Expect(warnings).To(ConsistOf("private-domain-warnings", "shared-domain-warnings"))
  1431  				})
  1432  			})
  1433  		})
  1434  	})
  1435  })