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>
 | 
			
		||||
 | 
			
		||||
  <properties>
 | 
			
		||||
    <dapr.spring.version>0.15.0-rc-7</dapr.spring.version>
 | 
			
		||||
    <dapr.spring.version>0.15.0-rc-8</dapr.spring.version>
 | 
			
		||||
  </properties>
 | 
			
		||||
  <dependencies>
 | 
			
		||||
    <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;
 | 
			
		||||
 | 
			
		||||
@Configuration
 | 
			
		||||
public class ExternalEventsConfiguration {
 | 
			
		||||
public class ShippingAppConfiguration {
 | 
			
		||||
 | 
			
		||||
  @Bean
 | 
			
		||||
  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
 | 
			
		||||
public class ExternalEventsApplication {
 | 
			
		||||
public class ShippingApplication {
 | 
			
		||||
 | 
			
		||||
  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 static io.dapr.springboot.examples.ShippingAppRestController.DAPR_PUBSUB_COMPONENT;
 | 
			
		||||
import static io.dapr.testcontainers.DaprContainerConstants.DAPR_RUNTIME_IMAGE_TAG;
 | 
			
		||||
 | 
			
		||||
@TestConfiguration(proxyBeanMethods = false)
 | 
			
		||||
| 
						 | 
				
			
			@ -31,7 +32,7 @@ public class DaprTestContainersConfig {
 | 
			
		|||
  public DaprContainer daprContainer() {
 | 
			
		||||
    return new DaprContainer(DAPR_RUNTIME_IMAGE_TAG)
 | 
			
		||||
            .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)
 | 
			
		||||
            .withAppHealthCheckPath("/actuator/health")
 | 
			
		||||
            .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
 | 
			
		||||
public class TestExternalEventsApplication {
 | 
			
		||||
public class TestShippingApplication {
 | 
			
		||||
 | 
			
		||||
  public static void main(String[] args) {
 | 
			
		||||
 | 
			
		||||
    SpringApplication.from(ExternalEventsApplication::main)
 | 
			
		||||
    SpringApplication.from(ShippingApplication::main)
 | 
			
		||||
            .with(DaprTestContainersConfig.class)
 | 
			
		||||
            .run(args);
 | 
			
		||||
    org.testcontainers.Testcontainers.exposeHostPorts(8080);
 | 
			
		||||
		Loading…
	
		Reference in New Issue