diff --git a/spring-cloud/pom.xml b/spring-cloud/pom.xml
index c4e606e190..3de527c33b 100644
--- a/spring-cloud/pom.xml
+++ b/spring-cloud/pom.xml
@@ -32,6 +32,7 @@
spring-cloud-zuul-eureka-integration
spring-cloud-contract
spring-cloud-kubernetes
+ spring-cloud-open-service-broker
spring-cloud-archaius
spring-cloud-functions
spring-cloud-vault
diff --git a/spring-cloud/spring-cloud-open-service-broker/README.md b/spring-cloud/spring-cloud-open-service-broker/README.md
new file mode 100644
index 0000000000..f09469076b
--- /dev/null
+++ b/spring-cloud/spring-cloud-open-service-broker/README.md
@@ -0,0 +1 @@
+### Relevant Articles:
diff --git a/spring-cloud/spring-cloud-open-service-broker/pom.xml b/spring-cloud/spring-cloud-open-service-broker/pom.xml
new file mode 100644
index 0000000000..7acd302dc1
--- /dev/null
+++ b/spring-cloud/spring-cloud-open-service-broker/pom.xml
@@ -0,0 +1,41 @@
+
+
+ 4.0.0
+ com.baeldung
+ spring-cloud-open-service-broker
+ jar
+
+
+ com.baeldung.spring.cloud
+ spring-cloud
+ 1.0.0-SNAPSHOT
+
+
+
+ 3.1.1.RELEASE
+ 2.2.7.RELEASE
+ 3.3.5.RELEASE
+
+
+
+
+ org.springframework.cloud
+ spring-cloud-starter-open-service-broker
+ ${spring-cloud-starter-open-service-broker.version}
+
+
+ org.springframework.boot
+ spring-boot-starter-web
+ ${spring-boot-starter-web.version}
+
+
+ io.projectreactor
+ reactor-test
+ ${reactor-test.version}
+ test
+
+
+
+
diff --git a/spring-cloud/spring-cloud-open-service-broker/src/main/java/com/baeldung/spring/cloud/openservicebroker/ServiceBrokerApplication.java b/spring-cloud/spring-cloud-open-service-broker/src/main/java/com/baeldung/spring/cloud/openservicebroker/ServiceBrokerApplication.java
new file mode 100644
index 0000000000..2dbb4bc546
--- /dev/null
+++ b/spring-cloud/spring-cloud-open-service-broker/src/main/java/com/baeldung/spring/cloud/openservicebroker/ServiceBrokerApplication.java
@@ -0,0 +1,13 @@
+package com.baeldung.spring.cloud.openservicebroker;
+
+import org.springframework.boot.SpringApplication;
+import org.springframework.boot.autoconfigure.SpringBootApplication;
+
+@SpringBootApplication
+public class ServiceBrokerApplication {
+
+ public static void main(String[] args) {
+ SpringApplication.run(ServiceBrokerApplication.class, args);
+ }
+
+}
diff --git a/spring-cloud/spring-cloud-open-service-broker/src/main/java/com/baeldung/spring/cloud/openservicebroker/config/CatalogConfiguration.java b/spring-cloud/spring-cloud-open-service-broker/src/main/java/com/baeldung/spring/cloud/openservicebroker/config/CatalogConfiguration.java
new file mode 100644
index 0000000000..e9e9452785
--- /dev/null
+++ b/spring-cloud/spring-cloud-open-service-broker/src/main/java/com/baeldung/spring/cloud/openservicebroker/config/CatalogConfiguration.java
@@ -0,0 +1,34 @@
+package com.baeldung.spring.cloud.openservicebroker.config;
+
+import org.springframework.cloud.servicebroker.model.catalog.Catalog;
+import org.springframework.cloud.servicebroker.model.catalog.Plan;
+import org.springframework.cloud.servicebroker.model.catalog.ServiceDefinition;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+
+@Configuration
+public class CatalogConfiguration {
+
+ @Bean
+ public Catalog catalog() {
+ Plan mailFreePlan = Plan.builder()
+ .id("fd81196c-a414-43e5-bd81-1dbb082a3c55")
+ .name("mail-free-plan")
+ .description("Mail Service Free Plan")
+ .free(true)
+ .build();
+
+ ServiceDefinition serviceDefinition = ServiceDefinition.builder()
+ .id("b92c0ca7-c162-4029-b567-0d92978c0a97")
+ .name("mail-service")
+ .description("Mail Service")
+ .bindable(true)
+ .tags("mail", "service")
+ .plans(mailFreePlan)
+ .build();
+
+ return Catalog.builder()
+ .serviceDefinitions(serviceDefinition)
+ .build();
+ }
+}
diff --git a/spring-cloud/spring-cloud-open-service-broker/src/main/java/com/baeldung/spring/cloud/openservicebroker/mail/MailController.java b/spring-cloud/spring-cloud-open-service-broker/src/main/java/com/baeldung/spring/cloud/openservicebroker/mail/MailController.java
new file mode 100644
index 0000000000..e0c0b36428
--- /dev/null
+++ b/spring-cloud/spring-cloud-open-service-broker/src/main/java/com/baeldung/spring/cloud/openservicebroker/mail/MailController.java
@@ -0,0 +1,19 @@
+package com.baeldung.spring.cloud.openservicebroker.mail;
+
+import org.springframework.web.bind.annotation.GetMapping;
+import org.springframework.web.bind.annotation.PathVariable;
+import org.springframework.web.bind.annotation.RestController;
+
+@RestController
+public class MailController {
+
+ @GetMapping("/mail-dashboard/{mailSystemId}")
+ public String dashboard(@PathVariable("mailSystemId") String mailSystemId) {
+ return "Mail Dashboard - " + mailSystemId;
+ }
+
+ @GetMapping("/mail-system/{mailSystemId}")
+ public String mailSystem(@PathVariable("mailSystemId") String mailSystemId) {
+ return "Mail System - " + mailSystemId;
+ }
+}
diff --git a/spring-cloud/spring-cloud-open-service-broker/src/main/java/com/baeldung/spring/cloud/openservicebroker/mail/MailService.java b/spring-cloud/spring-cloud-open-service-broker/src/main/java/com/baeldung/spring/cloud/openservicebroker/mail/MailService.java
new file mode 100644
index 0000000000..07b7ad9a38
--- /dev/null
+++ b/spring-cloud/spring-cloud-open-service-broker/src/main/java/com/baeldung/spring/cloud/openservicebroker/mail/MailService.java
@@ -0,0 +1,95 @@
+package com.baeldung.spring.cloud.openservicebroker.mail;
+
+import org.springframework.beans.factory.annotation.Value;
+import org.springframework.stereotype.Service;
+import reactor.core.publisher.Mono;
+
+import java.util.HashMap;
+import java.util.Map;
+import java.util.UUID;
+
+@Service
+public class MailService {
+
+ public static final String URI_KEY = "uri";
+ public static final String USERNAME_KEY = "username";
+ public static final String PASSWORD_KEY = "password";
+
+ private final String mailDashboardBaseURL;
+ private final String mailSystemBaseURL;
+
+ private Map mailServices = new HashMap<>();
+
+ private Map mailServiceBindings = new HashMap<>();
+
+ public MailService(@Value("${mail.system.dashboard.base-url}") String mailDashboardBaseURL,
+ @Value("${mail.system.base-url}") String mailSystemBaseURL) {
+ this.mailDashboardBaseURL = mailDashboardBaseURL;
+ this.mailSystemBaseURL = mailSystemBaseURL;
+ }
+
+ public Mono createServiceInstance(String instanceId, String serviceDefinitionId, String planId) {
+ MailServiceInstance mailServiceInstance = new MailServiceInstance(
+ instanceId, serviceDefinitionId, planId, mailDashboardBaseURL + instanceId);
+ mailServices.put(instanceId, mailServiceInstance);
+ return Mono.just(mailServiceInstance);
+ }
+
+ public Mono serviceInstanceExists(String instanceId) {
+ return Mono.just(mailServices.containsKey(instanceId));
+ }
+
+ public Mono getServiceInstance(String instanceId) {
+ if (mailServices.containsKey(instanceId)) {
+ return Mono.just(mailServices.get(instanceId));
+ }
+ return Mono.empty();
+ }
+
+ public Mono deleteServiceInstance(String instanceId) {
+ mailServices.remove(instanceId);
+ mailServiceBindings.remove(instanceId);
+ return Mono.empty();
+ }
+
+ public Mono createServiceBinding(String instanceId, String bindingId) {
+ return this.serviceInstanceExists(instanceId)
+ .flatMap(exists -> {
+ if (exists) {
+ MailServiceBinding mailServiceBinding =
+ new MailServiceBinding(bindingId, buildCredentials(instanceId, bindingId));
+ mailServiceBindings.put(instanceId, mailServiceBinding);
+ return Mono.just(mailServiceBinding);
+ } else {
+ return Mono.empty();
+ }
+ });
+ }
+
+ public Mono serviceBindingExists(String instanceId, String bindingId) {
+ return Mono.just(mailServiceBindings.containsKey(instanceId) &&
+ mailServiceBindings.get(instanceId).getBindingId().equalsIgnoreCase(bindingId));
+ }
+
+ public Mono getServiceBinding(String instanceId, String bindingId) {
+ if (mailServiceBindings.containsKey(instanceId) &&
+ mailServiceBindings.get(instanceId).getBindingId().equalsIgnoreCase(bindingId)) {
+ return Mono.just(mailServiceBindings.get(instanceId));
+ }
+ return Mono.empty();
+ }
+
+ public Mono deleteServiceBinding(String instanceId) {
+ mailServiceBindings.remove(instanceId);
+ return Mono.empty();
+ }
+
+ private Map buildCredentials(String instanceId, String bindingId) {
+ Map credentials = new HashMap<>();
+ credentials.put(URI_KEY, mailSystemBaseURL + instanceId);
+ credentials.put(USERNAME_KEY, bindingId);
+ credentials.put(PASSWORD_KEY, UUID.randomUUID().toString());
+ return credentials;
+ }
+
+}
diff --git a/spring-cloud/spring-cloud-open-service-broker/src/main/java/com/baeldung/spring/cloud/openservicebroker/mail/MailServiceBinding.java b/spring-cloud/spring-cloud-open-service-broker/src/main/java/com/baeldung/spring/cloud/openservicebroker/mail/MailServiceBinding.java
new file mode 100644
index 0000000000..a72d4f7372
--- /dev/null
+++ b/spring-cloud/spring-cloud-open-service-broker/src/main/java/com/baeldung/spring/cloud/openservicebroker/mail/MailServiceBinding.java
@@ -0,0 +1,22 @@
+package com.baeldung.spring.cloud.openservicebroker.mail;
+
+import java.util.Map;
+
+public class MailServiceBinding {
+
+ private String bindingId;
+ private Map credentials;
+
+ public MailServiceBinding(String bindingId, Map credentials) {
+ this.bindingId = bindingId;
+ this.credentials = credentials;
+ }
+
+ public String getBindingId() {
+ return bindingId;
+ }
+
+ public Map getCredentials() {
+ return credentials;
+ }
+}
diff --git a/spring-cloud/spring-cloud-open-service-broker/src/main/java/com/baeldung/spring/cloud/openservicebroker/mail/MailServiceInstance.java b/spring-cloud/spring-cloud-open-service-broker/src/main/java/com/baeldung/spring/cloud/openservicebroker/mail/MailServiceInstance.java
new file mode 100644
index 0000000000..d4dbbe5657
--- /dev/null
+++ b/spring-cloud/spring-cloud-open-service-broker/src/main/java/com/baeldung/spring/cloud/openservicebroker/mail/MailServiceInstance.java
@@ -0,0 +1,32 @@
+package com.baeldung.spring.cloud.openservicebroker.mail;
+
+public class MailServiceInstance {
+
+ private String instanceId;
+ private String serviceDefinitionId;
+ private String planId;
+ private String dashboardUrl;
+
+ public MailServiceInstance(String instanceId, String serviceDefinitionId, String planId, String dashboardUrl) {
+ this.instanceId = instanceId;
+ this.serviceDefinitionId = serviceDefinitionId;
+ this.planId = planId;
+ this.dashboardUrl = dashboardUrl;
+ }
+
+ public String getInstanceId() {
+ return instanceId;
+ }
+
+ public String getServiceDefinitionId() {
+ return serviceDefinitionId;
+ }
+
+ public String getPlanId() {
+ return planId;
+ }
+
+ public String getDashboardUrl() {
+ return dashboardUrl;
+ }
+}
diff --git a/spring-cloud/spring-cloud-open-service-broker/src/main/java/com/baeldung/spring/cloud/openservicebroker/services/MailServiceInstanceBindingService.java b/spring-cloud/spring-cloud-open-service-broker/src/main/java/com/baeldung/spring/cloud/openservicebroker/services/MailServiceInstanceBindingService.java
new file mode 100644
index 0000000000..847b309f2c
--- /dev/null
+++ b/spring-cloud/spring-cloud-open-service-broker/src/main/java/com/baeldung/spring/cloud/openservicebroker/services/MailServiceInstanceBindingService.java
@@ -0,0 +1,77 @@
+package com.baeldung.spring.cloud.openservicebroker.services;
+
+import com.baeldung.spring.cloud.openservicebroker.mail.MailService;
+import org.springframework.cloud.servicebroker.exception.ServiceInstanceBindingDoesNotExistException;
+import org.springframework.cloud.servicebroker.exception.ServiceInstanceDoesNotExistException;
+import org.springframework.cloud.servicebroker.model.binding.CreateServiceInstanceAppBindingResponse;
+import org.springframework.cloud.servicebroker.model.binding.CreateServiceInstanceBindingRequest;
+import org.springframework.cloud.servicebroker.model.binding.CreateServiceInstanceBindingResponse;
+import org.springframework.cloud.servicebroker.model.binding.DeleteServiceInstanceBindingRequest;
+import org.springframework.cloud.servicebroker.model.binding.DeleteServiceInstanceBindingResponse;
+import org.springframework.cloud.servicebroker.model.binding.GetServiceInstanceAppBindingResponse;
+import org.springframework.cloud.servicebroker.model.binding.GetServiceInstanceBindingRequest;
+import org.springframework.cloud.servicebroker.model.binding.GetServiceInstanceBindingResponse;
+import org.springframework.cloud.servicebroker.service.ServiceInstanceBindingService;
+import org.springframework.stereotype.Service;
+import reactor.core.publisher.Mono;
+
+@Service
+public class MailServiceInstanceBindingService implements ServiceInstanceBindingService {
+
+ private final MailService mailService;
+
+ public MailServiceInstanceBindingService(MailService mailService) {
+ this.mailService = mailService;
+ }
+
+ @Override
+ public Mono createServiceInstanceBinding(
+ CreateServiceInstanceBindingRequest request) {
+ return Mono.just(CreateServiceInstanceAppBindingResponse.builder())
+ .flatMap(responseBuilder -> mailService.serviceBindingExists(
+ request.getServiceInstanceId(), request.getBindingId())
+ .flatMap(exists -> {
+ if (exists) {
+ return mailService.getServiceBinding(
+ request.getServiceInstanceId(), request.getBindingId())
+ .flatMap(serviceBinding -> Mono.just(responseBuilder
+ .bindingExisted(true)
+ .credentials(serviceBinding.getCredentials())
+ .build()));
+ } else {
+ return mailService.createServiceBinding(
+ request.getServiceInstanceId(), request.getBindingId())
+ .switchIfEmpty(Mono.error(
+ new ServiceInstanceDoesNotExistException(
+ request.getServiceInstanceId())))
+ .flatMap(mailServiceBinding -> Mono.just(responseBuilder
+ .bindingExisted(false)
+ .credentials(mailServiceBinding.getCredentials())
+ .build()));
+ }
+ }));
+ }
+
+ @Override
+ public Mono getServiceInstanceBinding(GetServiceInstanceBindingRequest request) {
+ return mailService.getServiceBinding(request.getServiceInstanceId(), request.getBindingId())
+ .switchIfEmpty(Mono.error(new ServiceInstanceBindingDoesNotExistException(request.getBindingId())))
+ .flatMap(mailServiceBinding -> Mono.just(GetServiceInstanceAppBindingResponse.builder()
+ .credentials(mailServiceBinding.getCredentials())
+ .build()));
+ }
+
+ @Override
+ public Mono deleteServiceInstanceBinding(
+ DeleteServiceInstanceBindingRequest request) {
+ return mailService.serviceBindingExists(request.getServiceInstanceId(), request.getBindingId())
+ .flatMap(exists -> {
+ if (exists) {
+ return mailService.deleteServiceBinding(request.getServiceInstanceId())
+ .thenReturn(DeleteServiceInstanceBindingResponse.builder().build());
+ } else {
+ return Mono.error(new ServiceInstanceBindingDoesNotExistException(request.getBindingId()));
+ }
+ });
+ }
+}
diff --git a/spring-cloud/spring-cloud-open-service-broker/src/main/java/com/baeldung/spring/cloud/openservicebroker/services/MailServiceInstanceService.java b/spring-cloud/spring-cloud-open-service-broker/src/main/java/com/baeldung/spring/cloud/openservicebroker/services/MailServiceInstanceService.java
new file mode 100644
index 0000000000..8c757c3f25
--- /dev/null
+++ b/spring-cloud/spring-cloud-open-service-broker/src/main/java/com/baeldung/spring/cloud/openservicebroker/services/MailServiceInstanceService.java
@@ -0,0 +1,72 @@
+package com.baeldung.spring.cloud.openservicebroker.services;
+
+import com.baeldung.spring.cloud.openservicebroker.mail.MailService;
+import org.springframework.cloud.servicebroker.exception.ServiceInstanceDoesNotExistException;
+import org.springframework.cloud.servicebroker.model.instance.CreateServiceInstanceRequest;
+import org.springframework.cloud.servicebroker.model.instance.CreateServiceInstanceResponse;
+import org.springframework.cloud.servicebroker.model.instance.DeleteServiceInstanceRequest;
+import org.springframework.cloud.servicebroker.model.instance.DeleteServiceInstanceResponse;
+import org.springframework.cloud.servicebroker.model.instance.GetServiceInstanceRequest;
+import org.springframework.cloud.servicebroker.model.instance.GetServiceInstanceResponse;
+import org.springframework.cloud.servicebroker.service.ServiceInstanceService;
+import org.springframework.stereotype.Service;
+import reactor.core.publisher.Mono;
+
+@Service
+public class MailServiceInstanceService implements ServiceInstanceService {
+
+ private final MailService mailService;
+
+ public MailServiceInstanceService(MailService mailService) {
+ this.mailService = mailService;
+ }
+
+ @Override
+ public Mono createServiceInstance(CreateServiceInstanceRequest request) {
+ return Mono.just(request.getServiceInstanceId())
+ .flatMap(instanceId -> Mono.just(CreateServiceInstanceResponse.builder())
+ .flatMap(responseBuilder -> mailService.serviceInstanceExists(instanceId)
+ .flatMap(exists -> {
+ if (exists) {
+ return mailService.getServiceInstance(instanceId)
+ .flatMap(mailServiceInstance -> Mono.just(responseBuilder
+ .instanceExisted(true)
+ .dashboardUrl(mailServiceInstance.getDashboardUrl())
+ .build()));
+ } else {
+ return mailService.createServiceInstance(
+ instanceId, request.getServiceDefinitionId(), request.getPlanId())
+ .flatMap(mailServiceInstance -> Mono.just(responseBuilder
+ .instanceExisted(false)
+ .dashboardUrl(mailServiceInstance.getDashboardUrl())
+ .build()));
+ }
+ })));
+ }
+
+ @Override
+ public Mono deleteServiceInstance(DeleteServiceInstanceRequest request) {
+ return Mono.just(request.getServiceInstanceId())
+ .flatMap(instanceId -> mailService.serviceInstanceExists(instanceId)
+ .flatMap(exists -> {
+ if (exists) {
+ return mailService.deleteServiceInstance(instanceId)
+ .thenReturn(DeleteServiceInstanceResponse.builder().build());
+ } else {
+ return Mono.error(new ServiceInstanceDoesNotExistException(instanceId));
+ }
+ }));
+ }
+
+ @Override
+ public Mono getServiceInstance(GetServiceInstanceRequest request) {
+ return Mono.just(request.getServiceInstanceId())
+ .flatMap(instanceId -> mailService.getServiceInstance(instanceId)
+ .switchIfEmpty(Mono.error(new ServiceInstanceDoesNotExistException(instanceId)))
+ .flatMap(serviceInstance -> Mono.just(GetServiceInstanceResponse.builder()
+ .serviceDefinitionId(serviceInstance.getServiceDefinitionId())
+ .planId(serviceInstance.getPlanId())
+ .dashboardUrl(serviceInstance.getDashboardUrl())
+ .build())));
+ }
+}
diff --git a/spring-cloud/spring-cloud-open-service-broker/src/main/resources/application.yml b/spring-cloud/spring-cloud-open-service-broker/src/main/resources/application.yml
new file mode 100644
index 0000000000..d863b513b0
--- /dev/null
+++ b/spring-cloud/spring-cloud-open-service-broker/src/main/resources/application.yml
@@ -0,0 +1,10 @@
+spring:
+ cloud:
+ openservicebroker:
+ base-path: /broker
+
+mail:
+ system:
+ base-url: http://localhost:8080/mail-system/
+ dashboard:
+ base-url: http://localhost:8080/mail-dashboard/
\ No newline at end of file
diff --git a/spring-cloud/spring-cloud-open-service-broker/src/test/java/com/baeldung/spring/cloud/openservicebroker/services/MailServiceInstanceBindingServiceUnitTest.java b/spring-cloud/spring-cloud-open-service-broker/src/test/java/com/baeldung/spring/cloud/openservicebroker/services/MailServiceInstanceBindingServiceUnitTest.java
new file mode 100644
index 0000000000..5b50d44600
--- /dev/null
+++ b/spring-cloud/spring-cloud-open-service-broker/src/test/java/com/baeldung/spring/cloud/openservicebroker/services/MailServiceInstanceBindingServiceUnitTest.java
@@ -0,0 +1,201 @@
+package com.baeldung.spring.cloud.openservicebroker.services;
+
+import com.baeldung.spring.cloud.openservicebroker.mail.MailService;
+import com.baeldung.spring.cloud.openservicebroker.mail.MailServiceBinding;
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
+import org.mockito.Mock;
+import org.springframework.cloud.servicebroker.exception.ServiceInstanceBindingDoesNotExistException;
+import org.springframework.cloud.servicebroker.model.binding.CreateServiceInstanceAppBindingResponse;
+import org.springframework.cloud.servicebroker.model.binding.CreateServiceInstanceBindingRequest;
+import org.springframework.cloud.servicebroker.model.binding.DeleteServiceInstanceBindingRequest;
+import org.springframework.cloud.servicebroker.model.binding.GetServiceInstanceAppBindingResponse;
+import org.springframework.cloud.servicebroker.model.binding.GetServiceInstanceBindingRequest;
+import reactor.core.publisher.Mono;
+import reactor.test.StepVerifier;
+
+import java.util.HashMap;
+import java.util.Map;
+
+import static com.baeldung.spring.cloud.openservicebroker.mail.MailService.PASSWORD_KEY;
+import static com.baeldung.spring.cloud.openservicebroker.mail.MailService.URI_KEY;
+import static com.baeldung.spring.cloud.openservicebroker.mail.MailService.USERNAME_KEY;
+import static java.util.UUID.randomUUID;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertTrue;
+import static org.mockito.Mockito.when;
+import static org.mockito.MockitoAnnotations.initMocks;
+
+public class MailServiceInstanceBindingServiceUnitTest {
+
+ private static final String MAIL_SERVICE_INSTANCE_ID = "test@baeldung.com";
+ private static final String MAIL_SERVICE_BINDING_ID = "test";
+ private static final String MAIL_SYSTEM_URL = "http://localhost:8080/mail-system/test@baeldung.com";
+
+ @Mock
+ private MailService mailService;
+
+ private MailServiceInstanceBindingService mailServiceInstanceBindingService;
+
+ @BeforeEach
+ public void setUp() {
+ initMocks(this);
+
+ this.mailServiceInstanceBindingService = new MailServiceInstanceBindingService(mailService);
+ }
+
+ @Test
+ public void givenServiceBindingDoesNotExist_whenCreateServiceBinding_thenNewBindingIsCreated() {
+ // given service binding does not exist
+ when(mailService.serviceBindingExists(MAIL_SERVICE_INSTANCE_ID, MAIL_SERVICE_BINDING_ID)).thenReturn(Mono.just(false));
+
+ Map credentials = generateCredentials();
+ MailServiceBinding serviceBinding = new MailServiceBinding(MAIL_SERVICE_BINDING_ID, credentials);
+ when(mailService.createServiceBinding(MAIL_SERVICE_INSTANCE_ID, MAIL_SERVICE_BINDING_ID))
+ .thenReturn(Mono.just(serviceBinding));
+
+ // when create service binding
+ CreateServiceInstanceBindingRequest request = CreateServiceInstanceBindingRequest.builder()
+ .serviceInstanceId(MAIL_SERVICE_INSTANCE_ID)
+ .bindingId(MAIL_SERVICE_BINDING_ID)
+ .build();
+
+ // then a new service binding is provisioned
+ StepVerifier.create(mailServiceInstanceBindingService.createServiceInstanceBinding(request))
+ .consumeNextWith(response -> {
+ assertTrue(response instanceof CreateServiceInstanceAppBindingResponse);
+ CreateServiceInstanceAppBindingResponse bindingResponse = (CreateServiceInstanceAppBindingResponse) response;
+ assertFalse(bindingResponse.isBindingExisted());
+ validateBindingCredentials(bindingResponse.getCredentials());
+ })
+ .verifyComplete();
+ }
+
+ @Test
+ public void givenServiceBindingExists_whenCreateServiceBinding_thenExistingBindingIsRetrieved() {
+ // given service binding exists
+ when(mailService.serviceBindingExists(MAIL_SERVICE_INSTANCE_ID, MAIL_SERVICE_BINDING_ID)).thenReturn(Mono.just(true));
+
+ Map credentials = generateCredentials();
+ MailServiceBinding serviceBinding = new MailServiceBinding(MAIL_SERVICE_BINDING_ID, credentials);
+ when(mailService.getServiceBinding(MAIL_SERVICE_INSTANCE_ID, MAIL_SERVICE_BINDING_ID))
+ .thenReturn(Mono.just(serviceBinding));
+
+ // when create service binding
+ CreateServiceInstanceBindingRequest request = CreateServiceInstanceBindingRequest.builder()
+ .serviceInstanceId(MAIL_SERVICE_INSTANCE_ID)
+ .bindingId(MAIL_SERVICE_BINDING_ID)
+ .build();
+
+ // then a new service binding is provisioned
+ StepVerifier.create(mailServiceInstanceBindingService.createServiceInstanceBinding(request))
+ .consumeNextWith(response -> {
+ assertTrue(response instanceof CreateServiceInstanceAppBindingResponse);
+ CreateServiceInstanceAppBindingResponse bindingResponse = (CreateServiceInstanceAppBindingResponse) response;
+ assertTrue(bindingResponse.isBindingExisted());
+ validateBindingCredentials(bindingResponse.getCredentials());
+ })
+ .verifyComplete();
+ }
+
+ @Test
+ public void givenServiceBindingDoesNotExist_whenGetServiceBinding_thenException() {
+ // given service binding does not exist
+ when(mailService.getServiceBinding(MAIL_SERVICE_INSTANCE_ID, MAIL_SERVICE_BINDING_ID)).thenReturn(Mono.empty());
+
+ // when get service binding
+ GetServiceInstanceBindingRequest request = GetServiceInstanceBindingRequest.builder()
+ .serviceInstanceId(MAIL_SERVICE_INSTANCE_ID)
+ .bindingId(MAIL_SERVICE_BINDING_ID)
+ .build();
+
+ // then ServiceInstanceBindingDoesNotExistException is thrown
+ StepVerifier.create(mailServiceInstanceBindingService.getServiceInstanceBinding(request))
+ .expectErrorMatches(ex -> ex instanceof ServiceInstanceBindingDoesNotExistException)
+ .verify();
+ }
+
+ @Test
+ public void givenServiceBindingExists_whenGetServiceBinding_thenExistingBindingIsRetrieved() {
+ // given service binding exists
+ Map credentials = generateCredentials();
+ MailServiceBinding serviceBinding = new MailServiceBinding(MAIL_SERVICE_BINDING_ID, credentials);
+ when(mailService.getServiceBinding(MAIL_SERVICE_INSTANCE_ID, MAIL_SERVICE_BINDING_ID))
+ .thenReturn(Mono.just(serviceBinding));
+
+ // when get service binding
+ GetServiceInstanceBindingRequest request = GetServiceInstanceBindingRequest.builder()
+ .serviceInstanceId(MAIL_SERVICE_INSTANCE_ID)
+ .bindingId(MAIL_SERVICE_BINDING_ID)
+ .build();
+
+ // then the existing service binding is retrieved
+ StepVerifier.create(mailServiceInstanceBindingService.getServiceInstanceBinding(request))
+ .consumeNextWith(response -> {
+ assertTrue(response instanceof GetServiceInstanceAppBindingResponse);
+ GetServiceInstanceAppBindingResponse bindingResponse = (GetServiceInstanceAppBindingResponse) response;
+ validateBindingCredentials(bindingResponse.getCredentials());
+ })
+ .verifyComplete();
+ }
+
+ @Test
+ public void givenServiceBindingDoesNotExist_whenDeleteServiceBinding_thenException() {
+ // given service binding does not exist
+ when(mailService.serviceBindingExists(MAIL_SERVICE_INSTANCE_ID, MAIL_SERVICE_BINDING_ID)).thenReturn(Mono.just(false));
+
+ // when delete service binding
+ DeleteServiceInstanceBindingRequest request = DeleteServiceInstanceBindingRequest.builder()
+ .serviceInstanceId(MAIL_SERVICE_INSTANCE_ID)
+ .bindingId(MAIL_SERVICE_BINDING_ID)
+ .build();
+
+ // then ServiceInstanceBindingDoesNotExistException is thrown
+ StepVerifier.create(mailServiceInstanceBindingService.deleteServiceInstanceBinding(request))
+ .expectErrorMatches(ex -> ex instanceof ServiceInstanceBindingDoesNotExistException)
+ .verify();
+ }
+
+ @Test
+ public void givenServiceBindingExists_whenDeleteServiceBinding_thenExistingBindingIsDeleted() {
+ // given service binding exists
+ when(mailService.serviceBindingExists(MAIL_SERVICE_INSTANCE_ID, MAIL_SERVICE_BINDING_ID)).thenReturn(Mono.just(true));
+ when(mailService.deleteServiceBinding(MAIL_SERVICE_INSTANCE_ID)).thenReturn(Mono.empty());
+
+ // when delete service binding
+ DeleteServiceInstanceBindingRequest request = DeleteServiceInstanceBindingRequest.builder()
+ .serviceInstanceId(MAIL_SERVICE_INSTANCE_ID)
+ .bindingId(MAIL_SERVICE_BINDING_ID)
+ .build();
+
+ // then the existing service binding is retrieved
+ StepVerifier.create(mailServiceInstanceBindingService.deleteServiceInstanceBinding(request))
+ .consumeNextWith(response -> {
+ assertFalse(response.isAsync());
+ assertNull(response.getOperation());
+ })
+ .verifyComplete();
+ }
+
+ private void validateBindingCredentials(Map bindingCredentials) {
+ assertNotNull(bindingCredentials);
+ assertEquals(3, bindingCredentials.size());
+ assertTrue(bindingCredentials.containsKey(URI_KEY));
+ assertTrue(bindingCredentials.containsKey(USERNAME_KEY));
+ assertTrue(bindingCredentials.containsKey(PASSWORD_KEY));
+ assertEquals(MAIL_SYSTEM_URL, bindingCredentials.get(URI_KEY));
+ assertEquals(MAIL_SERVICE_BINDING_ID, bindingCredentials.get(USERNAME_KEY));
+ assertNotNull(bindingCredentials.get(PASSWORD_KEY));
+ }
+
+ private Map generateCredentials() {
+ Map credentials = new HashMap<>();
+ credentials.put(URI_KEY, MAIL_SYSTEM_URL);
+ credentials.put(USERNAME_KEY, MAIL_SERVICE_BINDING_ID);
+ credentials.put(PASSWORD_KEY, randomUUID().toString());
+ return credentials;
+ }
+}
diff --git a/spring-cloud/spring-cloud-open-service-broker/src/test/java/com/baeldung/spring/cloud/openservicebroker/services/MailServiceInstanceServiceUnitTest.java b/spring-cloud/spring-cloud-open-service-broker/src/test/java/com/baeldung/spring/cloud/openservicebroker/services/MailServiceInstanceServiceUnitTest.java
new file mode 100644
index 0000000000..1302cad42e
--- /dev/null
+++ b/spring-cloud/spring-cloud-open-service-broker/src/test/java/com/baeldung/spring/cloud/openservicebroker/services/MailServiceInstanceServiceUnitTest.java
@@ -0,0 +1,166 @@
+package com.baeldung.spring.cloud.openservicebroker.services;
+
+import com.baeldung.spring.cloud.openservicebroker.mail.MailService;
+import com.baeldung.spring.cloud.openservicebroker.mail.MailServiceInstance;
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
+import org.mockito.Mock;
+import org.springframework.cloud.servicebroker.exception.ServiceInstanceDoesNotExistException;
+import org.springframework.cloud.servicebroker.model.instance.CreateServiceInstanceRequest;
+import org.springframework.cloud.servicebroker.model.instance.DeleteServiceInstanceRequest;
+import org.springframework.cloud.servicebroker.model.instance.GetServiceInstanceRequest;
+import reactor.core.publisher.Mono;
+import reactor.test.StepVerifier;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertTrue;
+import static org.mockito.Mockito.when;
+import static org.mockito.MockitoAnnotations.initMocks;
+
+public class MailServiceInstanceServiceUnitTest {
+
+ private static final String MAIL_SERVICE_INSTANCE_ID = "test@baeldung.com";
+ private static final String MAIL_SERVICE_DEFINITION_ID = "mock-service-definition-id";
+ private static final String MAIL_SERVICE_PLAN_ID = "mock-service-plan-id";
+ private static final String MAIL_DASHBOARD_URL = "http://localhost:8080/mail-dashboard/test@baeldung.com";
+
+ @Mock
+ private MailService mailService;
+
+ private MailServiceInstanceService mailServiceInstanceService;
+
+ @BeforeEach
+ public void setUp() {
+ initMocks(this);
+
+ this.mailServiceInstanceService = new MailServiceInstanceService(mailService);
+ }
+
+ @Test
+ public void givenServiceInstanceDoesNotExist_whenCreateServiceInstance_thenProvisionNewService() {
+ // given service instance does not exist
+ when(mailService.serviceInstanceExists(MAIL_SERVICE_INSTANCE_ID)).thenReturn(Mono.just(false));
+
+ MailServiceInstance serviceInstance = new MailServiceInstance(MAIL_SERVICE_INSTANCE_ID, MAIL_SERVICE_DEFINITION_ID,
+ MAIL_SERVICE_PLAN_ID, MAIL_DASHBOARD_URL);
+ when(mailService.createServiceInstance(MAIL_SERVICE_INSTANCE_ID, MAIL_SERVICE_DEFINITION_ID, MAIL_SERVICE_PLAN_ID))
+ .thenReturn(Mono.just(serviceInstance));
+
+ // when create service instance
+ CreateServiceInstanceRequest request = CreateServiceInstanceRequest.builder()
+ .serviceInstanceId(MAIL_SERVICE_INSTANCE_ID)
+ .serviceDefinitionId(MAIL_SERVICE_DEFINITION_ID)
+ .planId(MAIL_SERVICE_PLAN_ID)
+ .build();
+
+ // then a new service instance is provisioned
+ StepVerifier.create(mailServiceInstanceService.createServiceInstance(request))
+ .consumeNextWith(response -> {
+ assertFalse(response.isInstanceExisted());
+ assertEquals(MAIL_DASHBOARD_URL, response.getDashboardUrl());
+ })
+ .verifyComplete();
+ }
+
+ @Test
+ public void givenServiceInstanceExists_whenCreateServiceInstance_thenExistingServiceInstanceIsRetrieved() {
+ // given service instance exists
+ when(mailService.serviceInstanceExists(MAIL_SERVICE_INSTANCE_ID)).thenReturn(Mono.just(true));
+
+ MailServiceInstance serviceInstance = new MailServiceInstance(MAIL_SERVICE_INSTANCE_ID, MAIL_SERVICE_DEFINITION_ID,
+ MAIL_SERVICE_PLAN_ID, MAIL_DASHBOARD_URL);
+ when(mailService.getServiceInstance(MAIL_SERVICE_INSTANCE_ID)).thenReturn(Mono.just(serviceInstance));
+
+ // when create service instance
+ CreateServiceInstanceRequest request = CreateServiceInstanceRequest.builder()
+ .serviceInstanceId(MAIL_SERVICE_INSTANCE_ID)
+ .serviceDefinitionId(MAIL_SERVICE_DEFINITION_ID)
+ .planId(MAIL_SERVICE_PLAN_ID)
+ .build();
+
+ // then the existing one is retrieved
+ StepVerifier.create(mailServiceInstanceService.createServiceInstance(request))
+ .consumeNextWith(response -> {
+ assertTrue(response.isInstanceExisted());
+ assertEquals(MAIL_DASHBOARD_URL, response.getDashboardUrl());
+ })
+ .verifyComplete();
+ }
+
+ @Test
+ public void givenServiceInstanceDoesNotExist_whenDeleteServiceInstance_thenException() {
+ // given service instance does not exist
+ when(mailService.serviceInstanceExists(MAIL_SERVICE_INSTANCE_ID)).thenReturn(Mono.just(false));
+
+ // when delete service instance
+ DeleteServiceInstanceRequest request = DeleteServiceInstanceRequest.builder()
+ .serviceInstanceId(MAIL_SERVICE_INSTANCE_ID)
+ .build();
+
+ // then ServiceInstanceDoesNotExistException is thrown
+ StepVerifier.create(mailServiceInstanceService.deleteServiceInstance(request))
+ .expectErrorMatches(ex -> ex instanceof ServiceInstanceDoesNotExistException)
+ .verify();
+ }
+
+ @Test
+ public void givenServiceInstanceExists_whenDeleteServiceInstance_thenSuccess() {
+ // given service instance exists
+ when(mailService.serviceInstanceExists(MAIL_SERVICE_INSTANCE_ID)).thenReturn(Mono.just(true));
+
+ // when delete service instance
+ when(mailService.deleteServiceInstance(MAIL_SERVICE_INSTANCE_ID)).thenReturn(Mono.empty());
+
+ DeleteServiceInstanceRequest request = DeleteServiceInstanceRequest.builder()
+ .serviceInstanceId(MAIL_SERVICE_INSTANCE_ID)
+ .build();
+
+ // then success
+ StepVerifier.create(mailServiceInstanceService.deleteServiceInstance(request))
+ .consumeNextWith(response -> {
+ assertFalse(response.isAsync());
+ assertNull(response.getOperation());
+ })
+ .verifyComplete();
+ }
+
+ @Test
+ public void givenServiceInstanceDoesNotExist_whenGetServiceInstance_thenException() {
+ // given service instance does not exist
+ when(mailService.getServiceInstance(MAIL_SERVICE_INSTANCE_ID)).thenReturn(Mono.empty());
+
+ // when get service instance
+ GetServiceInstanceRequest request = GetServiceInstanceRequest.builder()
+ .serviceInstanceId(MAIL_SERVICE_INSTANCE_ID)
+ .build();
+
+ // then ServiceInstanceDoesNotExistException is thrown
+ StepVerifier.create(mailServiceInstanceService.getServiceInstance(request))
+ .expectErrorMatches(ex -> ex instanceof ServiceInstanceDoesNotExistException)
+ .verify();
+ }
+
+ @Test
+ public void givenServiceInstanceExists_whenGetServiceInstance_thenExistingServiceInstanceIsRetrieved() {
+ // given service instance exists
+ MailServiceInstance serviceInstance = new MailServiceInstance(MAIL_SERVICE_INSTANCE_ID, MAIL_SERVICE_DEFINITION_ID,
+ MAIL_SERVICE_PLAN_ID, MAIL_DASHBOARD_URL);
+ when(mailService.getServiceInstance(MAIL_SERVICE_INSTANCE_ID)).thenReturn(Mono.just(serviceInstance));
+
+ // when get service instance
+ GetServiceInstanceRequest request = GetServiceInstanceRequest.builder()
+ .serviceInstanceId(MAIL_SERVICE_INSTANCE_ID)
+ .build();
+
+ // then the existing service instance is retrieved
+ StepVerifier.create(mailServiceInstanceService.getServiceInstance(request))
+ .consumeNextWith(response -> {
+ assertEquals(MAIL_SERVICE_DEFINITION_ID, response.getServiceDefinitionId());
+ assertEquals(MAIL_SERVICE_PLAN_ID, response.getPlanId());
+ assertEquals(MAIL_DASHBOARD_URL, response.getDashboardUrl());
+ })
+ .verifyComplete();
+ }
+}