diff --git a/README.md b/README.md index c8d94d2..2997036 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,8 @@ # Cook Veg Masala Noodles using Camunda Workflow +*** -This standalone process application is an example using [Camunda Workflow](https://camunda.com/) & [Springboot](https://spring.io/projects/spring-boot). As for the use case, we will try to _cook veg masala instant noodles_ else order from our favorite restaurant if we fail. +## Introduction: +This standalone process application is an example using [Camunda Workflow](https://camunda.com/) & [Springboot](https://spring.io/projects/spring-boot) with JUnit5 Test cases. As for the use case, we will try to _cook veg masala instant noodles_ else order from our favorite restaurant if we fail. _**Note:** You may see that some cooking steps may not be intuitive, but they are added to make use of features of camunda._ @@ -14,7 +16,7 @@ Out of the [BMPN 2.0 Implementations](https://docs.camunda.org/manual/7.15/refer - `Timer Intermediate Catch Event`: Timer events are events which are triggered by a defined timer. They can be used as start event, intermediate event or boundary event. -### Veg Masala Noodles Cooking Flow: +### Use Case: Veg Masala Noodles Cooking Flow: ![Noodles Cooking Workflow Process](./src/main/resources/cook_noodles_process.png) - We start by checking that we have minimum ingredients, where instant noodles, water, pan and spatula are mandatory. Vegetables, Cheese etc are optional to make instant noodles. @@ -25,6 +27,7 @@ Out of the [BMPN 2.0 Implementations](https://docs.camunda.org/manual/7.15/refer With that we reach end of our non-intuitive flow to cook my instant noodles. By the way, that's how I cook instant noodles, and they turn out good most of the times. + ## Code Configuration ### Camunda Springboot Initializer @@ -41,6 +44,8 @@ On systems running the `API`, it is recommended to use the below port for starti > `10101` – default api listening port +http://localhost:10101/camunda-masala-noodles/swagger-ui.html + ### API Build & deploy from GIT repo Below section would cover high level tasks required to configure and deploy api jar using Apache Maven @@ -52,6 +57,129 @@ Below section would cover high level tasks required to configure and deploy api 6. Start execution with `java -jar camunda-masala-noodles-.jar` 7. Logs are generated in deployment-directory/logs folder with file name 'camunda-masala-noodles-logger.log' or as mentioned in logback-spring.xml +## Testing it out + +### Run the Springboot application with maven + +- You can follow above steps in order to compile, build, package and install jar using maven. + +- Use command `mvnw clean install` to build and install the jar + +- Use command `mvnw spring-boot:run` to run the springboot application. + +- Alternatively you can navigate to file [MasalaNoodlesApplication](./src/main/java/com/noodles/MasalaNoodlesApplication.java) and start the application. + +- If every thing works then you should see below log in your console +``` +2021-06-25 00:27:50,315 INFO [main] org.springframework.boot.web.embedded.tomcat.TomcatWebServer: Tomcat started on port(s): 10101 (http) with context path '/camunda-masala-noodles' +2021-06-25 00:27:50,335 INFO [main] com.noodles.MasalaNoodlesApplication: Started MasalaNoodlesApplication in 22.716 seconds (JVM running for 25.565) +2021-06-25 00:27:50,340 INFO [main] org.camunda.bpm.engine.jobexecutor: ENGINE-14014 Starting up the JobExecutor[org.camunda.bpm.engine.spring.components.jobexecutor.SpringJobExecutor]. +2021-06-25 00:27:50,344 INFO [JobExecutor[org.camunda.bpm.engine.spring.components.jobexecutor.SpringJobExecutor]] org.camunda.bpm.engine.jobexecutor: ENGINE-14018 JobExecutor[org.camunda.bpm.engine.spring.components.jobexecutor.SpringJobExecutor] starting to acquire jobs +``` +- Refer to [running-your-application](https://docs.spring.io/spring-boot/docs/1.5.16.RELEASE/reference/html/using-boot-running-your-application.html) for more help with running boot application. + +### Instantiate new process to make veg masala noodles + +#### 1. Open & Login Camunda in Browser + +- On your local machine, you can access Camunda using [Camunda Home Page](http://localhost:10101/camunda-masala-noodles) url +- Credentials are configured in [application.yaml](./src/main/resources/application.yaml) file in key `camunda.bpm.admin-user`. Default credentials are + > `username:` noodles + `password:` noodles + +![camunda homepage](./documentation/images/camunda-homepage.png) + +#### 2. Start 'Cook Masala Veggies Noodles' process + +- Click on `TaskList` in welcome page + +![camunda-welcome-screen.png](./documentation/images/camunda-welcome-screen.png) + +- In top right corner, we have the menu. Click `Start process` to select the process to be started. + +![camunda-tasklist-Start process.png](./documentation/images/camunda-tasklist-Start%20process.png) + +- Click on `Cook Masala Veggies Noodles` which is the process we are about to test + +#### 3. Input the details to start process instance + +- We will now be presented with a `form` to select the ingredients we have. Based on our input, workflow will decide the course of action. _You can check console logs to see what happened with your process._ + +![camunda-start-process-instance.png](./documentation/images/camunda-start-process-instance.png) + +#### 4. Navigate to Camunda Cockpit + +- `Cockpit` helps us to visualise which step our process is. It would also give us the process instance id. + +![camunda-cockpit.png](./documentation/images/camunda-cockpit.png) + +- You can now click on `Cook Masala Veggies Noodles` Process Definition to view the process. Copy the process instance id. + +![camunda-activity-instance.png](./documentation/images/camunda-activity-instance.png) + +> Checking of ingredients process will end and cooking process will begin. In case you do not see your process in cockpit then, check logs on console. It would be mainly due to the fact that you do not have enough ingredients to cook instant noodles. In that case, you have to order online. + +### Once cooked call the process using the instance id + +#### 1. Open Swagger API Browser + +- While you were busy with your mobile, suddenly you remember you have kept instant noodles to cook. If your process has not ended yet i:e noodles are not burnt and they are ready to eat then you can trigger an api to indicate to process that you cooked noodles. + +- URL to access [Swagger API](http://localhost:10101/camunda-masala-noodles/swagger-ui.html) + +#### 2. Indicate Noodles are cooked by passing the process instance id + +- Click on `Try it out` to enable the API. The process instance id that was copied from cockpit, goes into the path parameter. + +- Click `Execute` to send the request. You can check the response which will say ` is ready to eat. ` + +![swagger-event.png](./documentation/images/swagger-event.png) + +- If you want to read more about swagger, then you can go through [tutorial](https://sourabhparsekar.medium.com/open-api-specification-swagger3-fc9ad3bbacdd) + +### Check Logs + +- In the end, all the steps we did will be tracked via the logs in the console. If you filter the logs using keyword `workflow-service-info` then you would see below + + +Logs for **Process instantiation** +``` +Timestamp:1624563683397:workflow-service-info:Check Ingredients:Check ingredients to make veg masala noodles +Timestamp:1624563683397:workflow-service-info:Check Ingredients:we can make veg masala noodles +Timestamp:1624563683400:workflow-service-info:Prepare Noodles:Follow below to make veg masala noodles +Timestamp:1624563683400:workflow-service-info:STEP 1:Take a deep-bottomed pan over medium flame and add water in it and bring it to a boil. +Timestamp:1624563683400:workflow-service-info:STEP 2:While the water starts to boil, check if you received IMs on your mobile. +Timestamp:1624563683400:workflow-service-info:STEP 3:Once the water boils, add chopped vegetables, add 1 packet of instant noodles and stir it. +Timestamp:1624563683401:workflow-service-info:STEP 4:Add the taste-maker to it and give it another stir +Timestamp:1624563683401:workflow-service-info:STEP 5:Close the lid +Timestamp:1624563683401:workflow-service-info:Cooking in Process:You can play with your mobile as it cooks for sometime... +``` + +Logs for **Process continuation success** +``` +Timestamp:1624563718006:workflow-service-info:Noodles Cooked:Cooking done for process instance id: 28242b5c-d524-11eb-878f-dc7196c5d636 +Timestamp:1624563718030:workflow-service-info:Eat Noodles:Veg masala noodles is ready. Let's eat... But first serve it.. +Timestamp:1624563718030:workflow-service-info:Eat Noodles:Transfer to a serving bowl and sprinkle a pinch of chaat masala or oregano over the noodles to make it even more flavorful. +Timestamp:1624563718030:workflow-service-info:Eat Noodles:Serve it hot to enjoy!! +``` + +Logs for **Process continuation failure** +``` +Timestamp:1624563560428:workflow-service-info:Order Online:Veg masala noodles was no success.. Let's order online... +Timestamp:1624563560429:workflow-service-info:Order Online:Ordering is not part of this flow yet... Try your local apps... +``` + +Logs for **insufficient ingredients** +``` +Timestamp:1624562624142:workflow-service-info:Check Ingredients:Check ingredients to make veg masala noodles +Timestamp:1624562624142:workflow-service-error:Check Ingredients:we cannot make veg masala noodles as required ingredient is missing. Instant Noodles, Water, Pan and Spatula are required. +Timestamp:1624562624144:workflow-service-info:Order Online:Veg masala noodles was no success.. Let's order online... +Timestamp:1624562624145:workflow-service-info:Order Online:Ordering is not part of this flow yet... Try your local apps... +``` + +_Hope you enjoy the wonderful journey of cooking veg masala instant noodles using camunda workflow. Until next time, happy cooking !!_ + + ## Appendix - Deployment as Docker container To deploy API as Docker Container refer [Docker-Image-Deployment](./documentation/deployment/Readme.md) diff --git a/camunda-masala-noodles.iml b/camunda-masala-noodles.iml index b40b41f..61d7cff 100644 --- a/camunda-masala-noodles.iml +++ b/camunda-masala-noodles.iml @@ -33,8 +33,6 @@ - - @@ -72,13 +70,10 @@ - - - @@ -91,7 +86,6 @@ - @@ -110,7 +104,6 @@ - @@ -134,7 +127,6 @@ - @@ -150,7 +142,44 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/documentation/images/camunda-activity-instance.png b/documentation/images/camunda-activity-instance.png new file mode 100644 index 0000000..9d9293b Binary files /dev/null and b/documentation/images/camunda-activity-instance.png differ diff --git a/documentation/images/camunda-cockpit.png b/documentation/images/camunda-cockpit.png new file mode 100644 index 0000000..5973ed1 Binary files /dev/null and b/documentation/images/camunda-cockpit.png differ diff --git a/documentation/images/camunda-homepage.png b/documentation/images/camunda-homepage.png new file mode 100644 index 0000000..4c97572 Binary files /dev/null and b/documentation/images/camunda-homepage.png differ diff --git a/documentation/images/camunda-start-process-instance.png b/documentation/images/camunda-start-process-instance.png new file mode 100644 index 0000000..7bd7ee1 Binary files /dev/null and b/documentation/images/camunda-start-process-instance.png differ diff --git a/documentation/images/camunda-tasklist-Start process.png b/documentation/images/camunda-tasklist-Start process.png new file mode 100644 index 0000000..56d4423 Binary files /dev/null and b/documentation/images/camunda-tasklist-Start process.png differ diff --git a/documentation/images/camunda-welcome-screen.png b/documentation/images/camunda-welcome-screen.png new file mode 100644 index 0000000..7f98737 Binary files /dev/null and b/documentation/images/camunda-welcome-screen.png differ diff --git a/documentation/images/swagger-event.png b/documentation/images/swagger-event.png new file mode 100644 index 0000000..736738b Binary files /dev/null and b/documentation/images/swagger-event.png differ diff --git a/pom.xml b/pom.xml index 421736e..f6337cc 100644 --- a/pom.xml +++ b/pom.xml @@ -32,7 +32,6 @@ import pom - @@ -65,12 +64,24 @@ 7.15.0 + + org.springframework.boot + spring-boot-starter-data-jpa + + com.h2database h2 + + + org.springdoc + springdoc-openapi-ui + 1.4.8 + + org.camunda.bpm.extension.mockito camunda-bpm-mockito diff --git a/src/main/java/com/noodles/MasalaNoodlesApplication.java b/src/main/java/com/noodles/MasalaNoodlesApplication.java index df1eac9..4211ffe 100644 --- a/src/main/java/com/noodles/MasalaNoodlesApplication.java +++ b/src/main/java/com/noodles/MasalaNoodlesApplication.java @@ -6,8 +6,8 @@ @SpringBootApplication public class MasalaNoodlesApplication { - public static void main(String... args) { - SpringApplication.run(MasalaNoodlesApplication.class, args); - } + public static void main(String... args) { + SpringApplication.run(MasalaNoodlesApplication.class, args); + } } \ No newline at end of file diff --git a/src/main/java/com/noodles/configuration/SwaggerConfig.java b/src/main/java/com/noodles/configuration/SwaggerConfig.java new file mode 100644 index 0000000..6b6f2e9 --- /dev/null +++ b/src/main/java/com/noodles/configuration/SwaggerConfig.java @@ -0,0 +1,44 @@ +package com.noodles.configuration; + +import io.swagger.v3.oas.models.OpenAPI; +import io.swagger.v3.oas.models.info.Contact; +import io.swagger.v3.oas.models.info.Info; +import io.swagger.v3.oas.models.info.License; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; + +import java.util.Collections; + +/** + * @implNote Swagger Configuration + */ +@Configuration +public class SwaggerConfig { + + @Bean + public OpenAPI customOpenAPI() { + return new OpenAPI() + .info(new Info().title("Camunda Noodles Service").version("v1.0.0") + .description("We will try to cook veg masala instant noodles using Springboot Camunda Workflow.") + .termsOfService("Terms of Service").license(getLicense()).contact(getContact())); + + } + + private Contact getContact() { + Contact contact = new Contact(); + contact.setEmail("sourabhanant@gmail.com"); + contact.setName("Sourabh Parsekar"); + contact.setUrl("https://sourabhparsekar.medium.com/"); + contact.setExtensions(Collections.emptyMap()); + return contact; + } + + private License getLicense() { + License license = new License(); + license.setName("Apache License, Version 2.0"); + license.setUrl("https://opensource.org/licenses/Apache-2.0"); + license.setExtensions(Collections.emptyMap()); + return license; + } + +} \ No newline at end of file diff --git a/src/main/java/com/noodles/controller/NoodlesController.java b/src/main/java/com/noodles/controller/NoodlesController.java new file mode 100644 index 0000000..49ab926 --- /dev/null +++ b/src/main/java/com/noodles/controller/NoodlesController.java @@ -0,0 +1,63 @@ +package com.noodles.controller; + + +import com.noodles.util.Constants; +import com.noodles.util.WorkflowLogger; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.media.Content; +import io.swagger.v3.oas.annotations.media.Schema; +import io.swagger.v3.oas.annotations.responses.ApiResponses; +import org.apache.commons.lang.StringUtils; +import org.camunda.bpm.engine.RuntimeService; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.http.HttpStatus; +import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.annotation.PathVariable; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.RestController; + +/** + * @implSpec : Controller to start/resume cooking of veg masala noodles + */ +@RestController +public class NoodlesController { + + private final Logger logger = LoggerFactory.getLogger(this.getClass()); + + @Autowired + private RuntimeService runtimeService; + + @PostMapping("/noodles/ready/{process-instance-id}") + @Operation(summary = "cooked instant noodles", tags = {"noodles"}) + @ApiResponses(value = { + @io.swagger.v3.oas.annotations.responses.ApiResponse(responseCode = "204", description = "Cooking done", content = {@Content(schema = @Schema(hidden = true))}), + @io.swagger.v3.oas.annotations.responses.ApiResponse(responseCode = "400", description = "Bad Request", content = {@Content(schema = @Schema(hidden = true))}), + @io.swagger.v3.oas.annotations.responses.ApiResponse(responseCode = "500", description = "Unexpected Error", content = {@Content(schema = @Schema(hidden = true))})}) + public ResponseEntity cookedNoodles( + @PathVariable(name = "process-instance-id") String processInstanceId + ) { + + WorkflowLogger.info(logger, "Noodles Cooked", "Cooking done for process instance id: " + processInstanceId); + + try { + if (StringUtils.isEmpty(processInstanceId)) { + WorkflowLogger.error(logger, "Noodles Ready", "Process Instance Id cannot be null or empty"); + return ResponseEntity.badRequest().body("Process Instance Id cannot be null or empty"); + } + + runtimeService + .createMessageCorrelation(Constants.NOODLES_COOKED) + .processInstanceId(processInstanceId) + .correlate(); + + return ResponseEntity.ok().body(processInstanceId + " is ready to eat."); + } catch (Exception e) { + WorkflowLogger.error(logger, "Noodles Ready", "Unknown Exception", e); + return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).body("Unknown Exception. Message: " + e.getMessage()); + } + + } + +} diff --git a/src/main/java/com/noodles/util/Constants.java b/src/main/java/com/noodles/util/Constants.java index 6a3c524..7ef408c 100644 --- a/src/main/java/com/noodles/util/Constants.java +++ b/src/main/java/com/noodles/util/Constants.java @@ -8,8 +8,7 @@ public class Constants { public static final String INGREDIENTS_AVAILABLE = "IngredientsAvailable"; public static final String IS_IT_COOKING = "IsItCooking"; public static final String DID_WE_EAT_NOODLES = "DidWeEat"; - public static String ORDER_ONLINE = "OrderOnline"; - + public static final String NOODLES_COOKED = "noodles cooked"; public static final String NOODLES = "noodles"; public static final String WATER = "water"; public static final String PAN_SPATULA = "pan_and_spatula"; @@ -18,6 +17,7 @@ public class Constants { public static final String CHEESE = "cheese"; public static final String CARROT = "carrot"; public static final String CAPSICUM = "capsicum"; + public static String ORDER_ONLINE = "OrderOnline"; private Constants() { throw new IllegalStateException("Constants Utility Class. Cannot be instantiated."); diff --git a/src/main/java/com/noodles/util/WorkflowLogger.java b/src/main/java/com/noodles/util/WorkflowLogger.java index e546654..79738ad 100644 --- a/src/main/java/com/noodles/util/WorkflowLogger.java +++ b/src/main/java/com/noodles/util/WorkflowLogger.java @@ -16,8 +16,9 @@ private WorkflowLogger() { /** * INFO log statement - * @param logger : logger used in the calling class - * @param method : method description + * + * @param logger : logger used in the calling class + * @param method : method description * @param message : processing details */ public static void info(Logger logger, String method, String message) { @@ -27,9 +28,10 @@ public static void info(Logger logger, String method, String message) { /** * ERROR log statement with exception trace - * @param logger : logger used in the calling class - * @param method : method description - * @param message : processing details + * + * @param logger : logger used in the calling class + * @param method : method description + * @param message : processing details * @param exception : exception trace details */ public static void error(Logger logger, String method, String message, Exception exception) { @@ -39,8 +41,9 @@ public static void error(Logger logger, String method, String message, Exception /** * ERROR log statement - * @param logger : logger used in the calling class - * @param method : method description + * + * @param logger : logger used in the calling class + * @param method : method description * @param message : processing details */ public static void error(Logger logger, String method, String message) { diff --git a/src/main/java/com/noodles/workflow/delegates/LetUsCook.java b/src/main/java/com/noodles/workflow/delegates/LetUsCook.java index 22990d6..a3c37db 100644 --- a/src/main/java/com/noodles/workflow/delegates/LetUsCook.java +++ b/src/main/java/com/noodles/workflow/delegates/LetUsCook.java @@ -29,10 +29,14 @@ public void execute(DelegateExecution execution) { WorkflowLogger.info(logger, STEP + 1, "Take a deep-bottomed pan over medium flame and add water in it and bring it to a boil."); StringJoiner vegetables = new StringJoiner(", "); - if (execution.hasVariable(Constants.ONION) && (boolean) execution.getVariable(Constants.ONION)) vegetables.add(Constants.ONION); - if (execution.hasVariable(Constants.TOMATO) && (boolean) execution.getVariable(Constants.TOMATO)) vegetables.add(Constants.TOMATO); - if (execution.hasVariable(Constants.CARROT) && (boolean) execution.getVariable(Constants.CARROT)) vegetables.add(Constants.CARROT); - if (execution.hasVariable(Constants.CAPSICUM) && (boolean) execution.getVariable(Constants.CAPSICUM)) vegetables.add(Constants.CAPSICUM); + if (execution.hasVariable(Constants.ONION) && (boolean) execution.getVariable(Constants.ONION)) + vegetables.add(Constants.ONION); + if (execution.hasVariable(Constants.TOMATO) && (boolean) execution.getVariable(Constants.TOMATO)) + vegetables.add(Constants.TOMATO); + if (execution.hasVariable(Constants.CARROT) && (boolean) execution.getVariable(Constants.CARROT)) + vegetables.add(Constants.CARROT); + if (execution.hasVariable(Constants.CAPSICUM) && (boolean) execution.getVariable(Constants.CAPSICUM)) + vegetables.add(Constants.CAPSICUM); if (vegetables.length() < 4) WorkflowLogger.info(logger, STEP + 2, "While the water boils, take a chopping board and chop " + vegetables); diff --git a/src/main/java/com/noodles/workflow/delegates/LetUsEat.java b/src/main/java/com/noodles/workflow/delegates/LetUsEat.java index de3c3ba..e670513 100644 --- a/src/main/java/com/noodles/workflow/delegates/LetUsEat.java +++ b/src/main/java/com/noodles/workflow/delegates/LetUsEat.java @@ -9,13 +9,14 @@ import org.springframework.stereotype.Service; @Service("LetUsEat") -public class LetUsEat implements JavaDelegate { +public class LetUsEat implements JavaDelegate { public static final String EAT_NOODLES = "Eat Noodles"; private final Logger logger = LoggerFactory.getLogger(this.getClass()); /** * We will eat what we cooked if it was not burnt + * * @param execution : Process Variables will be retrieved from DelegateExecution */ @Override diff --git a/src/main/java/com/noodles/workflow/delegates/OrderOnline.java b/src/main/java/com/noodles/workflow/delegates/OrderOnline.java index 4d7f11d..38cf47a 100644 --- a/src/main/java/com/noodles/workflow/delegates/OrderOnline.java +++ b/src/main/java/com/noodles/workflow/delegates/OrderOnline.java @@ -9,12 +9,13 @@ import org.springframework.stereotype.Service; @Service("OrderOnline") -public class OrderOnline implements JavaDelegate { +public class OrderOnline implements JavaDelegate { private final Logger logger = LoggerFactory.getLogger(this.getClass()); /** * Cooking is no child's play. Let's order online + * * @param execution : Process Variables will be retrieved from DelegateExecution */ @Override diff --git a/src/main/resources/cook_noodles_process.bpmn b/src/main/resources/cook_noodles_process.bpmn index f239b13..08aebbc 100644 --- a/src/main/resources/cook_noodles_process.bpmn +++ b/src/main/resources/cook_noodles_process.bpmn @@ -10,7 +10,7 @@ - + @@ -73,7 +73,7 @@ - + diff --git a/src/test/java/com/noodles/WorkflowTest.java b/src/test/java/com/noodles/WorkflowTest.java deleted file mode 100644 index 64cd6e2..0000000 --- a/src/test/java/com/noodles/WorkflowTest.java +++ /dev/null @@ -1,37 +0,0 @@ -package com.noodles; - -import org.camunda.bpm.engine.RuntimeService; -import org.camunda.bpm.engine.runtime.ProcessInstance; -import org.camunda.bpm.spring.boot.starter.test.helper.AbstractProcessEngineRuleTest; -import org.junit.Test; -import org.junit.runner.RunWith; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.boot.test.context.SpringBootTest; -import org.springframework.test.context.junit4.SpringRunner; - -import static org.camunda.bpm.engine.test.assertions.bpmn.BpmnAwareTests.assertThat; - -@SpringBootTest -@RunWith(SpringRunner.class) -public class WorkflowTest extends AbstractProcessEngineRuleTest { - - @Autowired - public RuntimeService runtimeService; - - @Test - public void shouldExecuteHappyPath() { - // given - String processDefinitionKey = "masala-noodles-process"; - - // when - ProcessInstance processInstance = runtimeService.startProcessInstanceByKey(processDefinitionKey); - - // then - assertThat(processInstance).isStarted() - .task() - .hasDefinitionKey("say-hello") - .hasCandidateUser("noodles") - .isNotAssigned(); - } - -} diff --git a/src/test/java/com/noodles/controller/NoodlesControllerTest.java b/src/test/java/com/noodles/controller/NoodlesControllerTest.java new file mode 100644 index 0000000..390d0db --- /dev/null +++ b/src/test/java/com/noodles/controller/NoodlesControllerTest.java @@ -0,0 +1,71 @@ +package com.noodles.controller; + +import org.camunda.bpm.engine.RuntimeService; +import org.camunda.bpm.engine.runtime.MessageCorrelationBuilder; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.mockito.*; +import org.springframework.http.HttpStatus; +import org.springframework.http.ResponseEntity; +import org.springframework.test.util.ReflectionTestUtils; + +import static org.mockito.ArgumentMatchers.anyMap; +import static org.mockito.ArgumentMatchers.anyString; +import static org.mockito.Mockito.*; + +class NoodlesControllerTest { + + @InjectMocks + private NoodlesController noodlesController; + + @Mock(answer = Answers.RETURNS_DEEP_STUBS) + private RuntimeService runtimeService; + + @BeforeEach + void setUp() { + + MockitoAnnotations.openMocks(this); + + MessageCorrelationBuilder messageCorrelationBuilder = Mockito.mock(MessageCorrelationBuilder.class, RETURNS_DEEP_STUBS); + doNothing().when(messageCorrelationBuilder).correlate(); + + when(runtimeService.createMessageCorrelation(anyString()).setVariables(anyMap()).processInstanceId(anyString())).thenReturn(messageCorrelationBuilder); + + ReflectionTestUtils.setField(noodlesController, "runtimeService", runtimeService); + + + } + + @Test + void test_noodles_are_cooked() { + + ResponseEntity responseEntity = noodlesController.cookedNoodles("28242b5c-d524-11eb-878f-dc7196c5d636"); + + Assertions.assertEquals(HttpStatus.OK, responseEntity.getStatusCode()); + Assertions.assertEquals("28242b5c-d524-11eb-878f-dc7196c5d636 is ready to eat.", responseEntity.getBody()); + + } + + @Test + void test_noodles_are_cooked_but_no_process_id() { + + ResponseEntity responseEntity = noodlesController.cookedNoodles(""); + + Assertions.assertEquals(HttpStatus.BAD_REQUEST, responseEntity.getStatusCode()); + + } + + + @Test + void test_noodles_are_cooked_but_some_exception() { + + doThrow(NullPointerException.class).when(runtimeService).createMessageCorrelation(anyString()); + + ResponseEntity responseEntity = noodlesController.cookedNoodles("28242b5c-d524-11eb-878f-dc7196c5d636"); + + Assertions.assertEquals(HttpStatus.INTERNAL_SERVER_ERROR, responseEntity.getStatusCode()); + + } + +} \ No newline at end of file diff --git a/src/test/java/com/noodles/util/ConstantsTest.java b/src/test/java/com/noodles/util/ConstantsTest.java index f6f428d..894f7da 100644 --- a/src/test/java/com/noodles/util/ConstantsTest.java +++ b/src/test/java/com/noodles/util/ConstantsTest.java @@ -7,7 +7,7 @@ import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Modifier; -import static org.junit.jupiter.api.Assertions.*; +import static org.junit.jupiter.api.Assertions.assertTrue; class ConstantsTest { diff --git a/src/test/java/com/noodles/util/WorkflowLoggerTest.java b/src/test/java/com/noodles/util/WorkflowLoggerTest.java index 42274fc..eaae487 100644 --- a/src/test/java/com/noodles/util/WorkflowLoggerTest.java +++ b/src/test/java/com/noodles/util/WorkflowLoggerTest.java @@ -7,7 +7,7 @@ import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Modifier; -import static org.junit.jupiter.api.Assertions.*; +import static org.junit.jupiter.api.Assertions.assertTrue; class WorkflowLoggerTest { diff --git a/src/test/java/com/noodles/workflow/delegates/CheckIngredientsTest.java b/src/test/java/com/noodles/workflow/delegates/CheckIngredientsTest.java index 7b7a7c7..568800d 100644 --- a/src/test/java/com/noodles/workflow/delegates/CheckIngredientsTest.java +++ b/src/test/java/com/noodles/workflow/delegates/CheckIngredientsTest.java @@ -43,7 +43,7 @@ void test_I_have_noodles_water_pan_spatula() { checkIngredients.execute(execution); //one additional variable added to execution - Assertions.assertEquals((variables.size()+1), execution.getVariables().size()); + Assertions.assertEquals((variables.size() + 1), execution.getVariables().size()); //check all mandatory ingredients are avaialble Assertions.assertEquals(true, execution.getVariable(Constants.INGREDIENTS_AVAILABLE)); @@ -67,7 +67,7 @@ void test_I_have_noodles_water_pan_spatula_vegetables_cheese() { checkIngredients.execute(execution); //one additional variable added to execution - Assertions.assertEquals((variables.size()+1), execution.getVariables().size()); + Assertions.assertEquals((variables.size() + 1), execution.getVariables().size()); //check all mandatory ingredients are avaialble Assertions.assertEquals(true, execution.getVariable(Constants.INGREDIENTS_AVAILABLE)); @@ -85,7 +85,7 @@ void test_I_do_not_have_noodles() { checkIngredients.execute(execution); //one additional variable added to execution - Assertions.assertEquals((variables.size()+1), execution.getVariables().size()); + Assertions.assertEquals((variables.size() + 1), execution.getVariables().size()); //check all mandatory ingredients are avaialble Assertions.assertEquals(false, execution.getVariable(Constants.INGREDIENTS_AVAILABLE)); @@ -103,7 +103,7 @@ void test_I_do_not_have_water() { checkIngredients.execute(execution); //one additional variable added to execution - Assertions.assertEquals((variables.size()+1), execution.getVariables().size()); + Assertions.assertEquals((variables.size() + 1), execution.getVariables().size()); //check all mandatory ingredients are avaialble Assertions.assertEquals(false, execution.getVariable(Constants.INGREDIENTS_AVAILABLE)); @@ -121,7 +121,7 @@ void test_I_do_not_have_pan_and_spatula() { checkIngredients.execute(execution); //one additional variable added to execution - Assertions.assertEquals((variables.size()+1), execution.getVariables().size()); + Assertions.assertEquals((variables.size() + 1), execution.getVariables().size()); //check all mandatory ingredients are avaialble Assertions.assertEquals(false, execution.getVariable(Constants.INGREDIENTS_AVAILABLE)); @@ -129,5 +129,4 @@ void test_I_do_not_have_pan_and_spatula() { } - } \ No newline at end of file diff --git a/src/test/java/com/noodles/workflow/delegates/LetUsEatTest.java b/src/test/java/com/noodles/workflow/delegates/LetUsEatTest.java index 0fe5644..573b9fd 100644 --- a/src/test/java/com/noodles/workflow/delegates/LetUsEatTest.java +++ b/src/test/java/com/noodles/workflow/delegates/LetUsEatTest.java @@ -12,8 +12,6 @@ import java.util.HashMap; import java.util.Map; -import static org.junit.jupiter.api.Assertions.*; - class LetUsEatTest { DelegateExecution execution; diff --git a/src/test/java/com/noodles/workflow/delegates/OrderOnlineTest.java b/src/test/java/com/noodles/workflow/delegates/OrderOnlineTest.java index b85ed79..08ad541 100644 --- a/src/test/java/com/noodles/workflow/delegates/OrderOnlineTest.java +++ b/src/test/java/com/noodles/workflow/delegates/OrderOnlineTest.java @@ -9,8 +9,6 @@ import org.mockito.InjectMocks; import org.mockito.MockitoAnnotations; -import static org.junit.jupiter.api.Assertions.*; - class OrderOnlineTest { DelegateExecution execution;