mirror of https://github.com/dapr/quickstarts.git
adding shipping app
Signed-off-by: salaboy <Salaboy@gmail.com>
This commit is contained in:
parent
aaa8a46dad
commit
1ea44f871f
|
|
@ -15,7 +15,7 @@
|
||||||
<description>Shipping App Example</description>
|
<description>Shipping App Example</description>
|
||||||
|
|
||||||
<properties>
|
<properties>
|
||||||
<dapr.spring.version>0.15.0-rc-7</dapr.spring.version>
|
<dapr.spring.version>0.15.0-rc-8</dapr.spring.version>
|
||||||
</properties>
|
</properties>
|
||||||
<dependencies>
|
<dependencies>
|
||||||
<dependency>
|
<dependency>
|
||||||
|
|
|
||||||
|
|
@ -1,94 +0,0 @@
|
||||||
/*
|
|
||||||
* Copyright 2025 The Dapr Authors
|
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
* you may not use this file except in compliance with the License.
|
|
||||||
* You may obtain a copy of the License at
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
* See the License for the specific language governing permissions and
|
|
||||||
limitations under the License.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package io.dapr.springboot.examples;
|
|
||||||
|
|
||||||
|
|
||||||
import io.dapr.spring.workflows.config.EnableDaprWorkflows;
|
|
||||||
import io.dapr.springboot.examples.external.ApprovalStatus;
|
|
||||||
import io.dapr.springboot.examples.external.ExternalEventsWorkflow;
|
|
||||||
import io.dapr.springboot.examples.external.Order;
|
|
||||||
import io.dapr.workflows.client.DaprWorkflowClient;
|
|
||||||
import io.dapr.workflows.client.WorkflowInstanceStatus;
|
|
||||||
import io.dapr.workflows.client.WorkflowRuntimeStatus;
|
|
||||||
import org.slf4j.Logger;
|
|
||||||
import org.slf4j.LoggerFactory;
|
|
||||||
import org.springframework.beans.factory.annotation.Autowired;
|
|
||||||
import org.springframework.web.bind.annotation.*;
|
|
||||||
|
|
||||||
import java.util.concurrent.TimeoutException;
|
|
||||||
|
|
||||||
@RestController
|
|
||||||
/*
|
|
||||||
* Dapr Workflows and Activities need to be registered in the DI container otherwise
|
|
||||||
* the Dapr runtime does not know this application contains workflows and activities.
|
|
||||||
* In Spring Boot Applications, the `@EnableDaprWorkflow` annotation takes care of registering
|
|
||||||
* all workflows and activities components found in the classpath.
|
|
||||||
*/
|
|
||||||
@EnableDaprWorkflows
|
|
||||||
public class ExternalEventsRestController {
|
|
||||||
|
|
||||||
private final Logger logger = LoggerFactory.getLogger(ExternalEventsRestController.class);
|
|
||||||
|
|
||||||
@Autowired
|
|
||||||
private DaprWorkflowClient daprWorkflowClient;
|
|
||||||
|
|
||||||
private String instanceId;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The DaprWorkflowClient is the API to manage workflows.
|
|
||||||
* Here it is used to schedule a new workflow instance.
|
|
||||||
*
|
|
||||||
* @return the instanceId of the ExternalEventsWorkflow execution
|
|
||||||
*/
|
|
||||||
@PostMapping("start")
|
|
||||||
public String basic(@RequestBody Order order) throws TimeoutException {
|
|
||||||
logger.info("Received order: {}", order);
|
|
||||||
instanceId = daprWorkflowClient.scheduleNewWorkflow(ExternalEventsWorkflow.class, order);
|
|
||||||
return instanceId;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Obtain the status of the workflow
|
|
||||||
*
|
|
||||||
* @return the status of the ExternalEventsWorkflow instance
|
|
||||||
*/
|
|
||||||
@GetMapping("status")
|
|
||||||
public String status() throws TimeoutException {
|
|
||||||
if(instanceId != null && !instanceId.isEmpty()) {
|
|
||||||
WorkflowInstanceStatus instanceState = daprWorkflowClient.getInstanceState(instanceId, true);
|
|
||||||
if (instanceState != null) {
|
|
||||||
if (instanceState.getRuntimeStatus().equals(WorkflowRuntimeStatus.COMPLETED)) {
|
|
||||||
var output = instanceState.readOutputAs(String.class);
|
|
||||||
if (output != null && !output.isEmpty()) {
|
|
||||||
return "Workflow Instance (" + instanceId + ") Status: " + instanceState.getRuntimeStatus().name() + "\n"
|
|
||||||
+ "Output: " + output;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return "Workflow Instance (" + instanceId + ") Status: " + instanceState.getRuntimeStatus().name();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return "N/A";
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Raise a workflow event
|
|
||||||
*/
|
|
||||||
@PostMapping("event")
|
|
||||||
public void raiseEvent(@RequestBody ApprovalStatus approvalStatus) {
|
|
||||||
daprWorkflowClient.raiseEvent(instanceId, "approval-event", approvalStatus);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
@ -20,7 +20,7 @@ import org.springframework.context.annotation.Configuration;
|
||||||
import org.springframework.web.client.RestTemplate;
|
import org.springframework.web.client.RestTemplate;
|
||||||
|
|
||||||
@Configuration
|
@Configuration
|
||||||
public class ExternalEventsConfiguration {
|
public class ShippingAppConfiguration {
|
||||||
|
|
||||||
@Bean
|
@Bean
|
||||||
public RestTemplate restTemplate() {
|
public RestTemplate restTemplate() {
|
||||||
|
|
@ -0,0 +1,67 @@
|
||||||
|
/*
|
||||||
|
* Copyright 2025 The Dapr Authors
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package io.dapr.springboot.examples;
|
||||||
|
|
||||||
|
|
||||||
|
import io.dapr.client.DaprClient;
|
||||||
|
import org.slf4j.Logger;
|
||||||
|
import org.slf4j.LoggerFactory;
|
||||||
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
|
import org.springframework.web.bind.annotation.*;
|
||||||
|
|
||||||
|
import java.math.BigDecimal;
|
||||||
|
|
||||||
|
@RestController
|
||||||
|
public class ShippingAppRestController {
|
||||||
|
|
||||||
|
public final static String DAPR_PUBSUB_COMPONENT = "shippingpubsub";
|
||||||
|
public final static String DAPR_PUBSUB_REGISTRATION_TOPIC = "shipment-registration-events";
|
||||||
|
public final static String DAPR_PUBSUB_CONFIRMED_TOPIC = "shipment-registration-confirmed-events";
|
||||||
|
|
||||||
|
private final Logger logger = LoggerFactory.getLogger(ShippingAppRestController.class);
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private DaprClient daprClient;
|
||||||
|
|
||||||
|
/// This endpoint is called by the CheckShippingDestination activity in the WorkflowApp.
|
||||||
|
@PostMapping("checkDestination")
|
||||||
|
public ShippingDestinationResult checkDestination(@RequestBody Order order) {
|
||||||
|
logger.info("checkDestination: Received input: {}", order);
|
||||||
|
return new ShippingDestinationResult( true, "");
|
||||||
|
}
|
||||||
|
// This endpoint handles messages that are published to the shipment-registration-events topic.
|
||||||
|
// The RegisterShipment activity in the WorkflowApp is publishing to this topic.
|
||||||
|
// This method is publishing a message to the shipment-registration-confirmed-events topic.
|
||||||
|
@PostMapping("registerShipment")
|
||||||
|
public ShipmentRegistrationStatus registerShipment(@RequestBody Order order){
|
||||||
|
logger.info("registerShipment: Received input: {}", order);
|
||||||
|
var status = new ShipmentRegistrationStatus(order.id(), true, "");
|
||||||
|
if( order.id().isEmpty()){
|
||||||
|
logger.info("Order Id is empty!");
|
||||||
|
}else{
|
||||||
|
daprClient.publishEvent(DAPR_PUBSUB_COMPONENT,
|
||||||
|
DAPR_PUBSUB_CONFIRMED_TOPIC, status).block();
|
||||||
|
}
|
||||||
|
return status;
|
||||||
|
}
|
||||||
|
|
||||||
|
public record Order(String id, OrderItem orderItem, CustomerInfo customerInfo){}
|
||||||
|
public record OrderItem(String productId, String productName, int quantity, BigDecimal totalPrice){}
|
||||||
|
public record CustomerInfo(String id, String country){}
|
||||||
|
public record ShipmentRegistrationStatus(String orderId, boolean isSuccess, String message){}
|
||||||
|
public record ShippingDestinationResult(boolean isSuccess, String message ){}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
@ -18,10 +18,10 @@ import org.springframework.boot.autoconfigure.SpringBootApplication;
|
||||||
|
|
||||||
|
|
||||||
@SpringBootApplication
|
@SpringBootApplication
|
||||||
public class ExternalEventsApplication {
|
public class ShippingApplication {
|
||||||
|
|
||||||
public static void main(String[] args) {
|
public static void main(String[] args) {
|
||||||
SpringApplication.run(ExternalEventsApplication.class, args);
|
SpringApplication.run(ShippingApplication.class, args);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
@ -1,3 +0,0 @@
|
||||||
package io.dapr.springboot.examples.external;
|
|
||||||
|
|
||||||
public record ApprovalStatus(String orderId, boolean isApproved){}
|
|
||||||
|
|
@ -1,59 +0,0 @@
|
||||||
/*
|
|
||||||
* Copyright 2023 The Dapr Authors
|
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
* you may not use this file except in compliance with the License.
|
|
||||||
* You may obtain a copy of the License at
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
* See the License for the specific language governing permissions and
|
|
||||||
limitations under the License.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package io.dapr.springboot.examples.external;
|
|
||||||
|
|
||||||
import io.dapr.durabletask.TaskCanceledException;
|
|
||||||
import io.dapr.springboot.examples.external.activities.ProcessOrderActivity;
|
|
||||||
import io.dapr.springboot.examples.external.activities.SendNotificationActivity;
|
|
||||||
import io.dapr.workflows.Workflow;
|
|
||||||
import io.dapr.workflows.WorkflowStub;
|
|
||||||
import org.springframework.stereotype.Component;
|
|
||||||
|
|
||||||
import java.time.Duration;
|
|
||||||
|
|
||||||
@Component
|
|
||||||
public class ExternalEventsWorkflow implements Workflow {
|
|
||||||
@Override
|
|
||||||
public WorkflowStub create() {
|
|
||||||
return ctx -> {
|
|
||||||
ctx.getLogger().info("Starting Workflow: {}", ctx.getName());
|
|
||||||
|
|
||||||
var order = ctx.getInput(Order.class);
|
|
||||||
var approvalStatus = new ApprovalStatus(order.id(), true);
|
|
||||||
|
|
||||||
if(order.totalPrice() > 250){
|
|
||||||
try{
|
|
||||||
approvalStatus = ctx.waitForExternalEvent("approval-event", Duration.ofSeconds(12), ApprovalStatus.class).await();
|
|
||||||
} catch (TaskCanceledException tce){
|
|
||||||
var notification = "Approval request for order " + order.id() + " timed out.";
|
|
||||||
ctx.callActivity(SendNotificationActivity.class.getName(), notification).await();
|
|
||||||
ctx.complete(notification);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
if (approvalStatus.isApproved()){
|
|
||||||
ctx.callActivity(ProcessOrderActivity.class.getName(), order).await();
|
|
||||||
}
|
|
||||||
var notification = approvalStatus.isApproved() ?
|
|
||||||
"Order " + order.id() + " has been approved." :
|
|
||||||
"Order " + order.id() +" has been rejected.";
|
|
||||||
|
|
||||||
ctx.callActivity(SendNotificationActivity.class.getName(), notification).await();
|
|
||||||
|
|
||||||
ctx.complete(notification);
|
|
||||||
};
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
@ -1,3 +0,0 @@
|
||||||
package io.dapr.springboot.examples.external;
|
|
||||||
|
|
||||||
public record Order(String id, String description, int quantity, double totalPrice){}
|
|
||||||
|
|
@ -1,41 +0,0 @@
|
||||||
/*
|
|
||||||
* Copyright 2023 The Dapr Authors
|
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
* you may not use this file except in compliance with the License.
|
|
||||||
* You may obtain a copy of the License at
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
* See the License for the specific language governing permissions and
|
|
||||||
limitations under the License.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package io.dapr.springboot.examples.external.activities;
|
|
||||||
|
|
||||||
import io.dapr.springboot.examples.external.Order;
|
|
||||||
import io.dapr.workflows.WorkflowActivity;
|
|
||||||
import io.dapr.workflows.WorkflowActivityContext;
|
|
||||||
import org.slf4j.Logger;
|
|
||||||
import org.slf4j.LoggerFactory;
|
|
||||||
import org.springframework.stereotype.Component;
|
|
||||||
|
|
||||||
/*
|
|
||||||
|
|
||||||
*/
|
|
||||||
@Component
|
|
||||||
public class ProcessOrderActivity implements WorkflowActivity {
|
|
||||||
|
|
||||||
/*
|
|
||||||
|
|
||||||
*/
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public Object run(WorkflowActivityContext ctx) {
|
|
||||||
Logger logger = LoggerFactory.getLogger(ProcessOrderActivity.class);
|
|
||||||
var order = ctx.getInput(Order.class);
|
|
||||||
// Imagine the order being processed by another system
|
|
||||||
logger.info("{} : Processed Order: {}", ctx.getName(), order.id());
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,33 +0,0 @@
|
||||||
/*
|
|
||||||
* Copyright 2023 The Dapr Authors
|
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
* you may not use this file except in compliance with the License.
|
|
||||||
* You may obtain a copy of the License at
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
* See the License for the specific language governing permissions and
|
|
||||||
limitations under the License.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package io.dapr.springboot.examples.external.activities;
|
|
||||||
|
|
||||||
import io.dapr.springboot.examples.external.Order;
|
|
||||||
import io.dapr.workflows.WorkflowActivity;
|
|
||||||
import io.dapr.workflows.WorkflowActivityContext;
|
|
||||||
import org.slf4j.Logger;
|
|
||||||
import org.slf4j.LoggerFactory;
|
|
||||||
import org.springframework.stereotype.Component;
|
|
||||||
|
|
||||||
@Component
|
|
||||||
public class RequestApprovalActivity implements WorkflowActivity {
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public Object run(WorkflowActivityContext ctx) {
|
|
||||||
Logger logger = LoggerFactory.getLogger(RequestApprovalActivity.class);
|
|
||||||
var order = ctx.getInput(Order.class);
|
|
||||||
logger.info("{} : Request Approval for Order: {}", ctx.getName(), order.id());
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,40 +0,0 @@
|
||||||
/*
|
|
||||||
* Copyright 2023 The Dapr Authors
|
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
* you may not use this file except in compliance with the License.
|
|
||||||
* You may obtain a copy of the License at
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
* See the License for the specific language governing permissions and
|
|
||||||
limitations under the License.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package io.dapr.springboot.examples.external.activities;
|
|
||||||
|
|
||||||
import io.dapr.workflows.WorkflowActivity;
|
|
||||||
import io.dapr.workflows.WorkflowActivityContext;
|
|
||||||
import org.slf4j.Logger;
|
|
||||||
import org.slf4j.LoggerFactory;
|
|
||||||
import org.springframework.stereotype.Component;
|
|
||||||
|
|
||||||
/*
|
|
||||||
*/
|
|
||||||
@Component
|
|
||||||
public class SendNotificationActivity implements WorkflowActivity {
|
|
||||||
|
|
||||||
/*
|
|
||||||
|
|
||||||
*/
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public Object run(WorkflowActivityContext ctx) {
|
|
||||||
Logger logger = LoggerFactory.getLogger(SendNotificationActivity.class);
|
|
||||||
var message = ctx.getInput(String.class);
|
|
||||||
|
|
||||||
// Imagine a notification being sent to the user
|
|
||||||
logger.info("{} : Sending Notification: {}", ctx.getName(), message);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1 +1 @@
|
||||||
spring.application.name=external-system-interactions
|
spring.application.name=shipping-app
|
||||||
|
|
|
||||||
|
|
@ -21,6 +21,7 @@ import org.springframework.context.annotation.Bean;
|
||||||
|
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
|
|
||||||
|
import static io.dapr.springboot.examples.ShippingAppRestController.DAPR_PUBSUB_COMPONENT;
|
||||||
import static io.dapr.testcontainers.DaprContainerConstants.DAPR_RUNTIME_IMAGE_TAG;
|
import static io.dapr.testcontainers.DaprContainerConstants.DAPR_RUNTIME_IMAGE_TAG;
|
||||||
|
|
||||||
@TestConfiguration(proxyBeanMethods = false)
|
@TestConfiguration(proxyBeanMethods = false)
|
||||||
|
|
@ -31,7 +32,7 @@ public class DaprTestContainersConfig {
|
||||||
public DaprContainer daprContainer() {
|
public DaprContainer daprContainer() {
|
||||||
return new DaprContainer(DAPR_RUNTIME_IMAGE_TAG)
|
return new DaprContainer(DAPR_RUNTIME_IMAGE_TAG)
|
||||||
.withAppName("external-system-interactions")
|
.withAppName("external-system-interactions")
|
||||||
.withComponent(new Component("kvstore", "state.in-memory", "v1", Collections.singletonMap("actorStateStore", String.valueOf(true))))
|
.withComponent(new Component(DAPR_PUBSUB_COMPONENT, "pubsub.in-memory", "v1", Collections.emptyList()))
|
||||||
.withAppPort(8080)
|
.withAppPort(8080)
|
||||||
.withAppHealthCheckPath("/actuator/health")
|
.withAppHealthCheckPath("/actuator/health")
|
||||||
.withAppChannelAddress("host.testcontainers.internal");
|
.withAppChannelAddress("host.testcontainers.internal");
|
||||||
|
|
|
||||||
|
|
@ -1,120 +0,0 @@
|
||||||
/*
|
|
||||||
* Copyright 2025 The Dapr Authors
|
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
* you may not use this file except in compliance with the License.
|
|
||||||
* You may obtain a copy of the License at
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
* See the License for the specific language governing permissions and
|
|
||||||
limitations under the License.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package io.dapr.springboot.examples;
|
|
||||||
|
|
||||||
import io.dapr.client.DaprClient;
|
|
||||||
import io.dapr.springboot.DaprAutoConfiguration;
|
|
||||||
import io.dapr.springboot.examples.external.ApprovalStatus;
|
|
||||||
import io.dapr.springboot.examples.external.Order;
|
|
||||||
import io.restassured.RestAssured;
|
|
||||||
import io.restassured.http.ContentType;
|
|
||||||
import org.junit.jupiter.api.BeforeEach;
|
|
||||||
import org.junit.jupiter.api.Test;
|
|
||||||
import org.springframework.beans.factory.annotation.Autowired;
|
|
||||||
import org.springframework.boot.test.context.SpringBootTest;
|
|
||||||
import org.hamcrest.Description;
|
|
||||||
import org.hamcrest.Matcher;
|
|
||||||
import org.hamcrest.TypeSafeMatcher;
|
|
||||||
|
|
||||||
import java.time.Duration;
|
|
||||||
import java.util.concurrent.TimeUnit;
|
|
||||||
|
|
||||||
import static io.dapr.springboot.examples.StringMatchesUUIDPattern.matchesThePatternOfAUUID;
|
|
||||||
import static io.restassured.RestAssured.given;
|
|
||||||
import static org.awaitility.Awaitility.await;
|
|
||||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
|
||||||
import static org.junit.jupiter.api.Assertions.assertTrue;
|
|
||||||
|
|
||||||
@SpringBootTest(classes = {TestExternalEventsApplication.class, DaprTestContainersConfig.class,
|
|
||||||
DaprAutoConfiguration.class, },
|
|
||||||
webEnvironment = SpringBootTest.WebEnvironment.DEFINED_PORT)
|
|
||||||
class ExternalEventsAppTests {
|
|
||||||
|
|
||||||
@Autowired
|
|
||||||
private DaprClient daprClient;
|
|
||||||
|
|
||||||
@BeforeEach
|
|
||||||
void setUp() {
|
|
||||||
RestAssured.baseURI = "http://localhost:" + 8080;
|
|
||||||
org.testcontainers.Testcontainers.exposeHostPorts(8080);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
@Test
|
|
||||||
void testExternalEventsWorkflow() throws InterruptedException {
|
|
||||||
|
|
||||||
var order = new Order("123", "Rubber ducks", 100, 500);
|
|
||||||
given().contentType(ContentType.JSON)
|
|
||||||
.body(order)
|
|
||||||
.when()
|
|
||||||
.post("/start")
|
|
||||||
.then()
|
|
||||||
.statusCode(200).body(matchesThePatternOfAUUID());
|
|
||||||
|
|
||||||
|
|
||||||
String status = given().contentType(ContentType.JSON)
|
|
||||||
.when()
|
|
||||||
.get("/status")
|
|
||||||
.then()
|
|
||||||
.statusCode(200).extract().asString();
|
|
||||||
|
|
||||||
assertTrue(status.contains("RUNNING"));
|
|
||||||
|
|
||||||
ApprovalStatus approvalStatus = new ApprovalStatus("123", true);
|
|
||||||
given().contentType(ContentType.JSON)
|
|
||||||
.body(approvalStatus)
|
|
||||||
.when()
|
|
||||||
.post("/event")
|
|
||||||
.then()
|
|
||||||
.statusCode(200);
|
|
||||||
|
|
||||||
// Wait for the workflow instance to complete
|
|
||||||
|
|
||||||
await().atMost(Duration.ofSeconds(2))
|
|
||||||
.pollDelay(500, TimeUnit.MILLISECONDS)
|
|
||||||
.pollInterval(500, TimeUnit.MILLISECONDS)
|
|
||||||
.until(() -> {
|
|
||||||
var completedStatus = given().contentType(ContentType.JSON)
|
|
||||||
.when()
|
|
||||||
.get("/status")
|
|
||||||
.then()
|
|
||||||
.statusCode(200).extract().asString();
|
|
||||||
assertTrue(completedStatus.contains("COMPLETED"));
|
|
||||||
assertTrue(completedStatus.contains("has been approved"));
|
|
||||||
return true;
|
|
||||||
});
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
class StringMatchesUUIDPattern extends TypeSafeMatcher<String> {
|
|
||||||
private static final String UUID_REGEX = "[0-9a-fA-F]{8}(?:-[0-9a-fA-F]{4}){3}-[0-9a-fA-F]{12}";
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected boolean matchesSafely(String s) {
|
|
||||||
return s.matches(UUID_REGEX);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void describeTo(Description description) {
|
|
||||||
description.appendText("a string matching the pattern of a UUID");
|
|
||||||
}
|
|
||||||
|
|
||||||
public static Matcher<String> matchesThePatternOfAUUID() {
|
|
||||||
return new StringMatchesUUIDPattern();
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
@ -0,0 +1,86 @@
|
||||||
|
/*
|
||||||
|
* Copyright 2025 The Dapr Authors
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package io.dapr.springboot.examples;
|
||||||
|
|
||||||
|
import io.dapr.client.DaprClient;
|
||||||
|
import io.dapr.springboot.DaprAutoConfiguration;
|
||||||
|
|
||||||
|
import io.restassured.RestAssured;
|
||||||
|
import io.restassured.http.ContentType;
|
||||||
|
import org.junit.jupiter.api.BeforeEach;
|
||||||
|
import org.junit.jupiter.api.Test;
|
||||||
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
|
import org.springframework.boot.test.context.SpringBootTest;
|
||||||
|
|
||||||
|
import java.math.BigDecimal;
|
||||||
|
|
||||||
|
import static io.restassured.RestAssured.given;
|
||||||
|
|
||||||
|
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||||
|
import static org.junit.jupiter.api.Assertions.assertTrue;
|
||||||
|
|
||||||
|
@SpringBootTest(classes = {TestShippingApplication.class, DaprTestContainersConfig.class,
|
||||||
|
DaprAutoConfiguration.class, },
|
||||||
|
webEnvironment = SpringBootTest.WebEnvironment.DEFINED_PORT)
|
||||||
|
class ShippingAppTests {
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private DaprClient daprClient;
|
||||||
|
|
||||||
|
@BeforeEach
|
||||||
|
void setUp() {
|
||||||
|
RestAssured.baseURI = "http://localhost:" + 8080;
|
||||||
|
org.testcontainers.Testcontainers.exposeHostPorts(8080);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void testCheckDestinationEndpoint() throws InterruptedException {
|
||||||
|
ShippingAppRestController.OrderItem orderItem = new ShippingAppRestController.OrderItem("ABC-123", "The Mars Volta EP", 1, BigDecimal.valueOf(100));
|
||||||
|
ShippingAppRestController.CustomerInfo customerInfo = new ShippingAppRestController.CustomerInfo("CUST-456", "UK");
|
||||||
|
var order = new ShippingAppRestController.Order("123", orderItem, customerInfo);
|
||||||
|
ShippingAppRestController.ShippingDestinationResult result = given().contentType(ContentType.JSON)
|
||||||
|
.body(order)
|
||||||
|
.when()
|
||||||
|
.post("/checkDestination")
|
||||||
|
.then()
|
||||||
|
.statusCode(200).extract()
|
||||||
|
.as(ShippingAppRestController.ShippingDestinationResult.class);
|
||||||
|
|
||||||
|
assertTrue(result.isSuccess());
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void testCheckRegisterShipmentEndpoint() throws InterruptedException {
|
||||||
|
ShippingAppRestController.OrderItem orderItem = new ShippingAppRestController.OrderItem("ABC-123", "The Mars Volta EP", 1, BigDecimal.valueOf(100));
|
||||||
|
ShippingAppRestController.CustomerInfo customerInfo = new ShippingAppRestController.CustomerInfo("CUST-456", "UK");
|
||||||
|
var order = new ShippingAppRestController.Order("123", orderItem, customerInfo);
|
||||||
|
ShippingAppRestController.ShipmentRegistrationStatus status = given().contentType(ContentType.JSON)
|
||||||
|
.body(order)
|
||||||
|
.when()
|
||||||
|
.post("/registerShipment")
|
||||||
|
.then()
|
||||||
|
.statusCode(200).extract()
|
||||||
|
.as(ShippingAppRestController.ShipmentRegistrationStatus.class);
|
||||||
|
|
||||||
|
assertTrue(status.isSuccess());
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -18,11 +18,11 @@ import org.springframework.boot.autoconfigure.SpringBootApplication;
|
||||||
|
|
||||||
|
|
||||||
@SpringBootApplication
|
@SpringBootApplication
|
||||||
public class TestExternalEventsApplication {
|
public class TestShippingApplication {
|
||||||
|
|
||||||
public static void main(String[] args) {
|
public static void main(String[] args) {
|
||||||
|
|
||||||
SpringApplication.from(ExternalEventsApplication::main)
|
SpringApplication.from(ShippingApplication::main)
|
||||||
.with(DaprTestContainersConfig.class)
|
.with(DaprTestContainersConfig.class)
|
||||||
.run(args);
|
.run(args);
|
||||||
org.testcontainers.Testcontainers.exposeHostPorts(8080);
|
org.testcontainers.Testcontainers.exposeHostPorts(8080);
|
||||||
Loading…
Reference in New Issue