func (b ServiceBroker) Destroy() { cf.AsUser(b.context.AdminUserContext(), DEFAULT_TIMEOUT, func() { Expect(cf.Cf("purge-service-offering", b.Service.Name, "-f").Wait(DEFAULT_TIMEOUT)).To(Exit(0)) }) b.Delete() Expect(cf.Cf("delete", b.Name, "-f", "-r").Wait(DEFAULT_TIMEOUT)).To(Exit(0)) }
func (context *ConfiguredContext) Setup() { cf.AsUser(context.AdminUserContext(), func() { definition := quotaDefinition{ Name: context.quotaDefinitionName, TotalServices: "100", TotalRoutes: "1000", MemoryLimit: "10G", NonBasicServicesAllowed: true, } args := []string{ "create-quota", context.quotaDefinitionName, "-m", definition.MemoryLimit, "-r", definition.TotalRoutes, "-s", definition.TotalServices, } if definition.NonBasicServicesAllowed { args = append(args, "--allow-paid-service-plans") } Expect(cf.Cf(args...).Wait(CF_API_TIMEOUT)).To(Exit(0)) createUserSession := cf.Cf("create-user", context.regularUserUsername, context.regularUserPassword) createUserSession.Wait(CF_API_TIMEOUT) if createUserSession.ExitCode() != 0 { Expect(createUserSession.Out).To(Say("scim_resource_already_exists")) } Expect(cf.Cf("create-org", context.organizationName).Wait(CF_API_TIMEOUT)).To(Exit(0)) Expect(cf.Cf("set-quota", context.organizationName, definition.Name).Wait(CF_API_TIMEOUT)).To(Exit(0)) }) }
func (context *ConfiguredContext) Setup() { cf.AsUser(context.AdminUserContext(), func() { channel := cf.Cf("create-user", context.regularUserUsername, context.regularUserPassword) select { case <-channel.Out.Detect("OK"): case <-channel.Out.Detect("scim_resource_already_exists"): case <-time.After(ScaledTimeout(10 * time.Second)): Fail("failed to create user") } definition := quotaDefinition{ Name: context.quotaDefinitionName, TotalServices: 100, TotalRoutes: 1000, MemoryLimit: 10240, NonBasicServicesAllowed: true, } definitionPayload, err := json.Marshal(definition) Expect(err).ToNot(HaveOccurred()) var response cf.GenericResource cf.ApiRequest("POST", "/v2/quota_definitions", &response, string(definitionPayload)) context.quotaDefinitionGUID = response.Metadata.Guid Eventually(cf.Cf("create-org", context.organizationName), ScaledTimeout(60*time.Second)).Should(Exit(0)) Eventually(cf.Cf("set-quota", context.organizationName, definition.Name), ScaledTimeout(60*time.Second)).Should(Exit(0)) }) }
func (c *context) Teardown() { userOrg := c.RegularUserContext().Org cf.RestoreUserContext(c.RegularUserContext(), c.shortTimeout, c.originalCfHomeDir, c.currentCfHomeDir) cf.AsUser(c.AdminUserContext(), c.shortTimeout, func() { runner.NewCmdRunner(cf.Cf("delete-user", "-f", c.regularUserUsername), c.longTimeout).Run() // delete-space does not provide an org flag, so we must target the Org first runner.NewCmdRunner(cf.Cf("target", "-o", userOrg), c.longTimeout).Run() runner.NewCmdRunner(cf.Cf("delete-space", "-f", c.spaceName), c.longTimeout).Run() if !c.useExistingOrg { runner.NewCmdRunner(cf.Cf("delete-org", "-f", c.organizationName), c.longTimeout).Run() cf.ApiRequest( "DELETE", "/v2/quota_definitions/"+c.quotaDefinitionGUID+"?recursive=true", nil, c.ShortTimeout(), ) } if c.config.CreatePermissiveSecurityGroup { runner.NewCmdRunner(cf.Cf("delete-security-group", "-f", c.securityGroupName), c.shortTimeout).Run() } }) }
func (b ServiceBroker) PublicizePlan(url string) { jsonMap := make(map[string]bool) jsonMap["public"] = true planJson, _ := json.Marshal(jsonMap) cf.AsUser(b.context.AdminUserContext(), DEFAULT_TIMEOUT, func() { Expect(cf.Cf("curl", url, "-X", "PUT", "-d", string(planJson)).Wait(DEFAULT_TIMEOUT)).To(Exit(0)) }) }
func deleteServiceBroker(brokerName string) { config = helpers.LoadConfig() context := helpers.NewContext(config) cf.AsUser(context.AdminUserContext(), context.ShortTimeout(), func() { responseBuffer := cf.Cf("delete-service-broker", brokerName, "-f") Expect(responseBuffer.Wait(DEFAULT_TIMEOUT)).To(Exit(0)) }) }
func (b ServiceBroker) Delete() { cf.AsUser(b.context.AdminUserContext(), DEFAULT_TIMEOUT, func() { Expect(cf.Cf("delete-service-broker", b.Name, "-f").Wait(DEFAULT_TIMEOUT)).To(Exit(0)) brokers := cf.Cf("service-brokers").Wait(DEFAULT_TIMEOUT) Expect(brokers).To(Exit(0)) Expect(brokers.Out.Contents()).ToNot(ContainSubstring(b.Name)) }) }
func lastPageUsageEvents(appName string) []AppUsageEvent { var response AppUsageEvents cf.AsUser(context.AdminUserContext(), DEFAULT_TIMEOUT, func() { cf.ApiRequest("GET", "/v2/app_usage_events?order-direction=desc&page=1", &response, DEFAULT_TIMEOUT) }) return response.Resources }
func (e *Environment) Setup() { e.context.Setup() cf.AsUser(e.context.AdminUserContext(), func() { setUpSpaceWithUserAccess(e.context.RegularUserContext()) }) e.originalCfHomeDir, e.currentCfHomeDir = cf.InitiateUserContext(e.context.RegularUserContext()) cf.TargetSpace(e.context.RegularUserContext()) }
func (context *ConfiguredContext) Teardown() { cf.AsUser(context.AdminUserContext(), func() { Expect(cf.Cf("delete-user", "-f", context.regularUserUsername).Wait(CF_API_TIMEOUT)).To(Exit(0)) if !context.isPersistent { Expect(cf.Cf("delete-org", "-f", context.organizationName).Wait(CF_API_TIMEOUT)).To(Exit(0)) Expect(cf.Cf("delete-quota", "-f", context.quotaDefinitionName).Wait(CF_API_TIMEOUT)).To(Exit(0)) } }) }
func (context *ConfiguredContext) Teardown() { cf.AsUser(context.AdminUserContext(), context.shortTimeout, func() { if !context.config.ShouldKeepUser { runner.NewCmdRunner(cf.Cf("delete-user", "-f", context.regularUserUsername), context.shortTimeout).Run() } if !context.isPersistent { runner.NewCmdRunner(cf.Cf("delete-org", "-f", context.organizationName), context.shortTimeout).Run() runner.NewCmdRunner(cf.Cf("delete-quota", "-f", context.quotaDefinitionName), context.shortTimeout).Run() } }) }
func lastAppUsageEvent(appName string, state string) (bool, AppUsageEvent) { var response AppUsageEvents cf.AsUser(context.AdminUserContext(), DEFAULT_TIMEOUT, func() { cf.ApiRequest("GET", "/v2/app_usage_events?order-direction=desc&page=1&results-per-page=150", &response, DEFAULT_TIMEOUT) }) for _, event := range response.Resources { if event.Entity.AppName == appName && event.Entity.State == state { return true, event } } return false, AppUsageEvent{} }
func (context *ConfiguredContext) Teardown() { cf.AsUser(context.AdminUserContext(), func() { Eventually(cf.Cf("delete-user", "-f", context.regularUserUsername), ScaledTimeout(60*time.Second)).Should(Exit(0)) if !context.isPersistent { Eventually(cf.Cf("delete-org", "-f", context.organizationName), ScaledTimeout(60*time.Second)).Should(Exit(0)) cf.ApiRequest( "DELETE", "/v2/quota_definitions/"+context.quotaDefinitionGUID+"?recursive=true", nil, ) } }) }
func (b ServiceBroker) PublicizePlans() { url := fmt.Sprintf("/v2/services?inline-relations-depth=1&q=label:%s", b.Service.Name) var session *Session cf.AsUser(b.context.AdminUserContext(), DEFAULT_TIMEOUT, func() { session = cf.Cf("curl", url).Wait(DEFAULT_TIMEOUT) Expect(session).To(Exit(0)) }) structure := ServicesResponse{} json.Unmarshal(session.Out.Contents(), &structure) for _, service := range structure.Resources { if service.Entity.Label == b.Service.Name { for _, plan := range service.Entity.ServicePlans { if b.HasPlan(plan.Entity.Name) { b.PublicizePlan(plan.Metadata.Url) } } } } }
func getCfHomeConfig() *cfHomeConfig { myCfHomeConfig := &cfHomeConfig{} cf.AsUser(context.AdminUserContext(), DEFAULT_TIMEOUT, func() { path := filepath.Join(os.Getenv("CF_HOME"), ".cf", "config.json") configFile, err := os.Open(path) if err != nil { panic(err) } decoder := json.NewDecoder(configFile) err = decoder.Decode(myCfHomeConfig) if err != nil { panic(err) } }) return myCfHomeConfig }
func (c *context) Setup() { cf.AsUser(c.AdminUserContext(), c.shortTimeout, func() { runner.NewCmdRunner(cf.Cf("create-user", c.regularUserUsername, c.regularUserPassword), c.shortTimeout).Run() if c.useExistingOrg == false { definition := QuotaDefinition{ Name: c.quotaDefinitionName, TotalServices: 100, TotalRoutes: 1000, MemoryLimit: 10240, NonBasicServicesAllowed: true, } definitionPayload, err := json.Marshal(definition) gomega.Expect(err).ToNot(gomega.HaveOccurred()) var response cf.GenericResource cf.ApiRequest("POST", "/v2/quota_definitions", &response, c.shortTimeout, string(definitionPayload)) c.quotaDefinitionGUID = response.Metadata.Guid runner.NewCmdRunner(cf.Cf("create-org", c.organizationName), c.shortTimeout).Run() runner.NewCmdRunner(cf.Cf("set-quota", c.organizationName, c.quotaDefinitionName), c.shortTimeout).Run() } c.setUpSpaceWithUserAccess(c.RegularUserContext()) if c.config.CreatePermissiveSecurityGroup { c.createPermissiveSecurityGroup() } }) c.originalCfHomeDir, c.currentCfHomeDir = cf.InitiateUserContext(c.RegularUserContext(), c.shortTimeout) cf.TargetSpace(c.RegularUserContext(), c.shortTimeout) }
func createServiceBroker() (string, string, string) { serviceBrokerAsset := assets.NewAssets().ServiceBroker serviceBrokerAppName := PushApp(serviceBrokerAsset, config.RubyBuildpackName) serviceName := initiateBrokerConfig(serviceBrokerAppName) brokerName := generator.PrefixedRandomName("RATS-BROKER-") brokerUrl := helpers.AppUri(serviceBrokerAppName, "") config = helpers.LoadConfig() context := helpers.NewContext(config) cf.AsUser(context.AdminUserContext(), context.ShortTimeout(), func() { session := cf.Cf("create-service-broker", brokerName, "user", "password", brokerUrl) Expect(session.Wait(DEFAULT_TIMEOUT)).To(Exit(0)) session = cf.Cf("enable-service-access", serviceName) Expect(session.Wait(DEFAULT_TIMEOUT)).To(Exit(0)) }) return brokerName, serviceBrokerAppName, serviceName }
func (c *context) Teardown() { cf.RestoreUserContext(c.RegularUserContext(), c.shortTimeout, c.originalCfHomeDir, c.currentCfHomeDir) cf.AsUser(c.AdminUserContext(), c.shortTimeout, func() { runner.NewCmdRunner(cf.Cf("delete-user", "-f", c.regularUserUsername), c.longTimeout).Run() if !c.isPersistent { runner.NewCmdRunner(cf.Cf("delete-org", "-f", c.organizationName), c.longTimeout).Run() cf.ApiRequest( "DELETE", "/v2/quota_definitions/"+c.quotaDefinitionGUID+"?recursive=true", nil, c.ShortTimeout(), ) } if c.config.CreatePermissiveSecurityGroup { runner.NewCmdRunner(cf.Cf("delete-security-group", "-f", c.securityGroupName), c.shortTimeout).Run() } }) }
func (context *ConfiguredContext) Setup() { cf.AsUser(context.AdminUserContext(), context.shortTimeout, func() { definition := quotaDefinition{ Name: context.quotaDefinitionName, TotalServices: "100", TotalRoutes: "1000", MemoryLimit: "10G", NonBasicServicesAllowed: true, } args := []string{ "create-quota", context.quotaDefinitionName, "-m", definition.MemoryLimit, "-r", definition.TotalRoutes, "-s", definition.TotalServices, } if definition.NonBasicServicesAllowed { args = append(args, "--allow-paid-service-plans") } runner.NewCmdRunner(cf.Cf(args...), context.shortTimeout).Run() if !context.config.UseExistingUser { createUserCmd := cf.Cf("create-user", context.regularUserUsername, context.regularUserPassword) runner.NewCmdRunner(createUserCmd, context.shortTimeout).Run() if createUserCmd.ExitCode() != 0 { Expect(createUserCmd.Out).To(Say("scim_resource_already_exists")) } } runner.NewCmdRunner(cf.Cf("create-org", context.organizationName), context.shortTimeout).Run() runner.NewCmdRunner(cf.Cf("set-quota", context.organizationName, definition.Name), context.shortTimeout).Run() }) }
func SetupEnvironment(context SuiteContext) { var originalCfHomeDir, currentCfHomeDir string BeforeEach(func() { AdminUserContext = context.AdminUserContext() RegularUserContext = context.RegularUserContext() context.Setup() cf.AsUser(AdminUserContext, func() { setUpSpaceWithUserAccess(RegularUserContext) }) originalCfHomeDir, currentCfHomeDir = cf.InitiateUserContext(RegularUserContext) cf.TargetSpace(RegularUserContext) }) AfterEach(func() { cf.RestoreUserContext(RegularUserContext, originalCfHomeDir, currentCfHomeDir) context.Teardown() }) }
var output []byte var oldServiceName string var oldPlanName string BeforeEach(func() { broker = NewServiceBroker( generator.PrefixedRandomName("pblc-brkr-"), assets.NewAssets().ServiceBroker, context, ) cf.TargetSpace(context.RegularUserContext(), context.ShortTimeout()) broker.Push() broker.Configure() cf.AsUser(context.AdminUserContext(), context.ShortTimeout(), func() { broker.Create() }) }) Describe("Updating the catalog", func() { BeforeEach(func() { broker.PublicizePlans() }) It("updates the broker and sees catalog changes", func() { // Confirming plans show up in the marketplace for regular user plans := cf.Cf("marketplace").Wait(DEFAULT_TIMEOUT) Expect(plans).To(Exit(0)) Expect(plans).To(Say(broker.Service.Name))
rules := fmt.Sprintf( `[{"destination":"%s","ports":"%d","protocol":"tcp"}, {"destination":"%s","ports":"%d","protocol":"tcp"}]`, privateHost, privatePort, containerIp, privatePort) file, _ := ioutil.TempFile(os.TempDir(), "CATS-sg-rules") defer os.Remove(file.Name()) file.WriteString(rules) rulesPath := file.Name() securityGroupName = fmt.Sprintf("CATS-SG-%s", generator.RandomName()) cf.AsUser(context.AdminUserContext(), DEFAULT_TIMEOUT, func() { Expect(cf.Cf("create-security-group", securityGroupName, rulesPath).Wait(DEFAULT_TIMEOUT)).To(Exit(0)) Expect( cf.Cf("bind-security-group", securityGroupName, context.RegularUserContext().Org, context.RegularUserContext().Space).Wait(DEFAULT_TIMEOUT)).To(Exit(0)) }) defer func() { cf.AsUser(context.AdminUserContext(), DEFAULT_TIMEOUT, func() { Expect(cf.Cf("delete-security-group", securityGroupName, "-f").Wait(DEFAULT_TIMEOUT)).To(Exit(0)) }) }() Expect(cf.Cf("restart", clientAppName).Wait(CF_PUSH_TIMEOUT)).To(Exit(0)) By("Testing app egress rules") curlResponse = helpers.CurlApp(clientAppName, fmt.Sprintf("/curl/%s/%d", privateHost, privatePort)) json.Unmarshal([]byte(curlResponse), &doraCurlResponse) Expect(doraCurlResponse.ReturnCode).To(Equal(0))
BeforeEach(func() { appName = generator.PrefixedRandomName("CATS-APP-") spaceGuid = GetSpaceGuidFromName(context.RegularUserContext().Space) appGuid = CreateApp(appName, spaceGuid, "{}") packageGuid = CreatePackage(appGuid) token = GetAuthToken() uploadUrl := fmt.Sprintf("%s/v3/packages/%s/upload", config.ApiEndpoint, packageGuid) UploadPackage(uploadUrl, assets.NewAssets().DoraZip, token) WaitForPackageToBeReady(packageGuid) buildpackName = generator.PrefixedRandomName("CATS-BP-") buildpackZip := createBuildpack() cf.AsUser(context.AdminUserContext(), DEFAULT_TIMEOUT, func() { Expect(cf.Cf("create-buildpack", buildpackName, buildpackZip, "999").Wait(DEFAULT_TIMEOUT)).To(Exit(0)) }) }) AfterEach(func() { app_helpers.AppReport(appName, DEFAULT_TIMEOUT) cf.AsUser(context.AdminUserContext(), DEFAULT_TIMEOUT, func() { Expect(cf.Cf("delete-buildpack", buildpackName, "-f").Wait(DEFAULT_TIMEOUT)).To(Exit(0)) }) DeleteApp(appGuid) }) It("Stages with a user specified admin buildpack", func() { StagePackage(packageGuid, fmt.Sprintf(`{"lifecycle":{ "type": "buildpack", "data": { "buildpack": "%s" } }}`, buildpackName))
func (b ServiceBroker) Update() { cf.AsUser(b.context.AdminUserContext(), DEFAULT_TIMEOUT, func() { Expect(cf.Cf("update-service-broker", b.Name, "username", "password", helpers.AppUri(b.Name, "")).Wait(DEFAULT_TIMEOUT)).To(Exit(0)) }) }
func (b ServiceBroker) EnableServiceAccess() { cf.AsUser(b.context.AdminUserContext(), b.context.ShortTimeout(), func() { session := cf.Cf("enable-service-access", b.Service.Name).Wait(DEFAULT_TIMEOUT) Expect(session).To(Exit(0)) }) }
return buildpackArchivePath } var originalRunningEnv string var originalStagingEnv string var appName string var buildpackName string BeforeEach(func() { appName = generator.PrefixedRandomName("CATS-APP-") cf.AsUser(context.AdminUserContext(), DEFAULT_TIMEOUT, func() { session := cf.Cf("curl", "/v2/config/environment_variable_groups/running").Wait(DEFAULT_TIMEOUT) Expect(session).To(Exit(0)) originalRunningEnv = string(session.Out.Contents()) session = cf.Cf("curl", "/v2/config/environment_variable_groups/staging").Wait(DEFAULT_TIMEOUT) Expect(session).To(Exit(0)) originalStagingEnv = string(session.Out.Contents()) }) }) AfterEach(func() { cf.AsUser(context.AdminUserContext(), DEFAULT_TIMEOUT, func() { Expect(cf.Cf("curl", "/v2/config/environment_variable_groups/staging", "-X", "PUT", "-d", originalStagingEnv).Wait(DEFAULT_TIMEOUT)).To(Exit(0)) Expect(cf.Cf("curl", "/v2/config/environment_variable_groups/running", "-X", "PUT", "-d", originalRunningEnv).Wait(DEFAULT_TIMEOUT)).To(Exit(0)) if buildpackName != "" { Expect(cf.Cf("delete-buildpack", buildpackName, "-f").Wait(DEFAULT_TIMEOUT)).To(Exit(0)) } })
. "github.com/cloudfoundry/cf-acceptance-tests/helpers/services" ) var _ = Describe("Purging service offerings", func() { var broker ServiceBroker BeforeEach(func() { broker = NewServiceBroker( generator.PrefixedRandomName("ps-"), assets.NewAssets().ServiceBroker, context, ) broker.Push() broker.Configure() cf.AsUser(context.AdminUserContext(), DEFAULT_TIMEOUT, func() { broker.Create() broker.PublicizePlans() }) }) AfterEach(func() { app_helpers.AppReport(broker.Name, DEFAULT_TIMEOUT) broker.Destroy() }) Context("when there are several existing service entities", func() { var appName, instanceName, asyncInstanceName string BeforeEach(func() { appName = generator.PrefixedRandomName("CATS-APP-ps-") instanceName = generator.PrefixedRandomName("CATS-APP-ps-")
curlRoute := func(hostName string, path string) string { uri := config.Protocol() + hostName + "." + domainName + path curlCmd := runner.Curl(uri) runner.NewCmdRunner(curlCmd, DEFAULT_TIMEOUT).Run() Expect(string(curlCmd.Err.Contents())).To(HaveLen(0)) return string(curlCmd.Out.Contents()) } BeforeEach(func() { orgName = context.RegularUserContext().Org spaceName = context.RegularUserContext().Space domainName = generator.RandomName() + "." + helpers.LoadConfig().AppsDomain cf.AsUser(context.AdminUserContext(), DEFAULT_TIMEOUT, func() { Expect(cf.Cf("create-shared-domain", domainName).Wait(CF_PUSH_TIMEOUT)).To(Exit(0)) }) appNameDora = generator.PrefixedRandomName("CATS-APP-") Expect(cf.Cf("push", appNameDora, "-m", "128M", "-p", assets.NewAssets().Dora, "-d", config.AppsDomain).Wait(CF_PUSH_TIMEOUT)).To(Exit(0)) appNameSimple = generator.PrefixedRandomName("CATS-APP-") Expect(cf.Cf("push", appNameSimple, "-m", "128M", "-p", assets.NewAssets().HelloWorld, "-d", config.AppsDomain).Wait(CF_PUSH_TIMEOUT)).To(Exit(0)) }) AfterEach(func() { cf.AsUser(context.AdminUserContext(), DEFAULT_TIMEOUT, func() { Expect(cf.Cf("target", "-o", orgName).Wait(DEFAULT_TIMEOUT)).To(Exit(0)) Expect(cf.Cf("delete-shared-domain", domainName, "-f").Wait(DEFAULT_TIMEOUT)).To(Exit(0)) })
var FakeCf = func(args ...string) *gexec.Session { FakeCfCalls = append(FakeCfCalls, args) var session, _ = gexec.Start(exec.Command("echo", "nothing"), nil, nil) return session } var user cf.UserContext BeforeEach(func() { FakeCfCalls = [][]string{} cf.Cf = FakeCf user = cf.NewUserContext("http://FAKE_API.example.com", "FAKE_USERNAME", "FAKE_PASSWORD", "FAKE_ORG", "FAKE_SPACE", true) }) It("calls cf api", func() { cf.AsUser(user, FakeThingsToRunAsUser) Expect(FakeCfCalls[0]).To(Equal([]string{"api", "http://FAKE_API.example.com", "--skip-ssl-validation"})) }) It("calls cf auth", func() { cf.AsUser(user, FakeThingsToRunAsUser) Expect(FakeCfCalls[1]).To(Equal([]string{"auth", "FAKE_USERNAME", "FAKE_PASSWORD"})) }) Describe("calling cf target", func() { Context("when org is set and space is set", func() { It("includes flags to set org and space", func() { cf.AsUser(user, FakeThingsToRunAsUser)
}) It("removes all instances and plans of the service, then removes the service offering", func() { instanceName := "purge-offering-instance" marketplace := cf.Cf("marketplace").Wait(DEFAULT_TIMEOUT) Expect(marketplace).To(Exit(0)) Expect(marketplace).To(Say(broker.Plan.Name)) broker.CreateServiceInstance(instanceName) services := cf.Cf("services").Wait(DEFAULT_TIMEOUT) Expect(marketplace).To(Exit(0)) Expect(services).To(Say(instanceName)) Expect(cf.Cf("delete", broker.Name, "-f").Wait(DEFAULT_TIMEOUT)).To(Exit(0)) cf.AsUser(context.AdminUserContext(), func() { Expect(cf.Cf("purge-service-offering", broker.Service.Name, "-f").Wait(DEFAULT_TIMEOUT)).To(Exit(0)) }) services = cf.Cf("services").Wait(DEFAULT_TIMEOUT) Expect(services).To(Exit(0)) Expect(services.Out.Contents()).NotTo(ContainSubstring(instanceName)) //TODO: Say? marketplace = cf.Cf("marketplace").Wait(DEFAULT_TIMEOUT) Expect(marketplace).To(Exit(0)) Expect(marketplace.Out.Contents()).NotTo(ContainSubstring(broker.Service.Name)) //TODO: Say? }) })