Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Payment example process application: migrated to sdk #531

Open
wants to merge 3 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
18 changes: 10 additions & 8 deletions payment-example-process-application/kube/manifests/deployment.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -20,17 +20,19 @@ spec:
- containerPort: 8080
name: http
env:
- name: ZEEBE_CLIENT_BROKER_GATEWAY_ADDRESS
value: "camunda-platform-zeebe-gateway.camunda-platform.svc.cluster.local:26500"
- name: ZEEBE_CLIENT_SECURITY_PLAINTEXT
value: "true"
- name: ZEEBE_CLIENT_ID
- name: CAMUNDA_CLIENT_MODE
value: "self-managed"
- name: CAMUNDA_CLIENT_ZEEBE_GRPCADDRESS
value: "http://camunda-platform-zeebe-gateway.camunda-platform.svc.cluster.local:26500"
- name: CAMUNDA_CLIENT_ZEEBE_RESTADDRESS
value: "http://camunda-platform-zeebe-gateway.camunda-platform.svc.cluster.local:8080"
- name: CAMUNDA_CLIENT_AUTH_CLIENTID
value: "payment-app"
- name: ZEEBE_AUTHORIZATION_SERVER_URL
- name: CAMUNDA_CLIENT_AUTH_ISSUER
value: http://camunda-platform-keycloak.camunda-platform.svc.cluster.local/auth/realms/camunda-platform/protocol/openid-connect/token
- name: ZEEBE_TOKEN_AUDIENCE
- name: CAMUNDA_CLIENT_AUTH_AUDIENCE
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

❌ The property name is wrong (ref).

Suggested change
- name: CAMUNDA_CLIENT_AUTH_AUDIENCE
- name: CAMUNDA_CLIENT_ZEEBE_AUDIENCE

value: zeebe-api
- name: ZEEBE_CLIENT_CLOUD_CLIENTSECRET
- name: CAMUNDA_CLIENT_AUTH_CLIENTSECRET
valueFrom:
secretKeyRef:
name: payment-example-process-application-secrets
Expand Down
37 changes: 25 additions & 12 deletions payment-example-process-application/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -10,9 +10,8 @@
<maven.compiler.target>21</maven.compiler.target>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>

<zeebe.version>8.5.8</zeebe.version>
<spring-zeebe.version>8.5.7</spring-zeebe.version>
<spring-boot.version>3.3.0</spring-boot.version>
<zeebe.version>8.6.4</zeebe.version>
<spring-boot.version>3.3.5</spring-boot.version>
</properties>

<dependencyManagement>
Expand All @@ -30,9 +29,19 @@
<version>${zeebe.version}</version>
</dependency>
<dependency>
<groupId>io.camunda.spring</groupId>
<artifactId>spring-boot-starter-camunda</artifactId>
<version>${spring-zeebe.version}</version>
<groupId>io.camunda</groupId>
<artifactId>spring-boot-starter-camunda-sdk</artifactId>
<version>${zeebe.version}</version>
</dependency>
<dependency>
<groupId>io.camunda</groupId>
<artifactId>zeebe-process-test-extension-testcontainer</artifactId>
<version>${zeebe.version}</version>
</dependency>
Comment on lines +36 to +40
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🔧 We could use the new Camunda Process Test instead of ZPT. It works natively with the Spring SDK. It is in an early stage but should support most of the assertions used in the test.

<dependency>
<groupId>org.camunda.community.process_test_coverage</groupId>
<artifactId>camunda-process-test-coverage-junit5-platform-8</artifactId>
<version>2.7.0</version>
</dependency>
</dependencies>
</dependencyManagement>
Expand All @@ -44,8 +53,8 @@
</dependency>

<dependency>
<groupId>io.camunda.spring</groupId>
<artifactId>spring-boot-starter-camunda</artifactId>
<groupId>io.camunda</groupId>
<artifactId>spring-boot-starter-camunda-sdk</artifactId>
</dependency>

<dependency>
Expand All @@ -54,16 +63,20 @@
</dependency>

<dependency>
<groupId>io.camunda.spring</groupId>
<artifactId>spring-boot-starter-camunda-test</artifactId>
<version>${spring-zeebe.version}</version>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>

<dependency>
<groupId>io.camunda</groupId>
<artifactId>zeebe-process-test-extension-testcontainer</artifactId>
<scope>test</scope>
</dependency>

<dependency>
<groupId>org.camunda.community.process_test_coverage</groupId>
<artifactId>camunda-process-test-coverage-junit5-platform-8</artifactId>
<version>2.7.0</version>
<scope>test</scope>
</dependency>
</dependencies>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ public class CreditCardHandler {

private static final Logger LOG = LoggerFactory.getLogger(CreditCardHandler.class);

private CreditCardService creditCardService;
private final CreditCardService creditCardService;

public CreditCardHandler(CreditCardService creditCardService) {
this.creditCardService = creditCardService;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,10 +13,9 @@ public class CustomerCreditHandler {

private static final Logger LOG = LoggerFactory.getLogger(CustomerCreditHandler.class);

CustomerService customerService;
private final CustomerService customerService;

public CustomerCreditHandler(CustomerService customerService) {
super();
this.customerService = customerService;
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,41 +2,65 @@

import static io.camunda.zeebe.process.test.assertions.BpmnAssert.*;
import static io.camunda.zeebe.protocol.Protocol.USER_TASK_JOB_TYPE;
import static io.camunda.zeebe.spring.test.ZeebeTestThreadSupport.*;
import static org.assertj.core.api.Assertions.*;
import static org.mockito.BDDMockito.*;

import com.camunda.consulting.web_shop_process_app.service.CreditCardExpiredException;
import com.camunda.consulting.web_shop_process_app.service.CreditCardService;
import com.camunda.consulting.web_shop_process_app.service.CustomerService;
import com.camunda.consulting.web_shop_process_app.worker.CreditCardHandler;
import com.camunda.consulting.web_shop_process_app.worker.CustomerCreditHandler;
import io.camunda.zeebe.client.ZeebeClient;
import io.camunda.zeebe.client.api.response.ActivateJobsResponse;
import io.camunda.zeebe.client.api.response.ActivatedJob;
import io.camunda.zeebe.client.api.response.ProcessInstanceEvent;
import io.camunda.zeebe.process.test.api.ZeebeTestEngine;
import io.camunda.zeebe.spring.test.ZeebeSpringTest;
import io.camunda.zeebe.process.test.extension.testcontainer.ZeebeProcessTest;
import java.time.Duration;
import java.util.List;
import java.util.Map;
import java.util.concurrent.TimeoutException;
import java.util.function.Consumer;
import org.camunda.community.process_test_coverage.junit5.platform8.ProcessEngineCoverageExtension;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.boot.test.mock.mockito.MockBean;
import org.mockito.Mock;
import org.mockito.junit.jupiter.MockitoExtension;

@SpringBootTest
@ZeebeSpringTest
@ExtendWith(ProcessEngineCoverageExtension.class)
public class ProcessIntegrationTest {
@ZeebeProcessTest
@ExtendWith({ProcessEngineCoverageExtension.class, MockitoExtension.class})
public class ProcessUnitTest {

@Autowired ZeebeClient zeebeClient;
ZeebeClient zeebeClient;
ZeebeTestEngine engine;

@Autowired ZeebeTestEngine engine;
@Mock CustomerService mockedCustomerService;

@MockBean CustomerService mockedCustomerService;
@Mock CreditCardService mockedCreditCardService;

@MockBean CreditCardService mockedCreditCardService;
private void assertProcessInstanceCompleted(ProcessInstanceEvent processInstance)
throws InterruptedException, TimeoutException {
engine.waitForIdleState(Duration.ofSeconds(10));
assertThat(processInstance).isCompleted();
}

private void assertProcessInstanceHasPassedElement(
ProcessInstanceEvent processInstance, String elementId)
throws InterruptedException, TimeoutException {
engine.waitForIdleState(Duration.ofSeconds(10));
assertThat(processInstance).hasPassedElement(elementId, 1);
}

@BeforeEach
void init() {
zeebeClient
.newDeployResourceCommand()
.addResourceFromClasspath("check-payment.form")
.addResourceFromClasspath("payment_process.bpmn")
.send()
.join();
}

@Test
public void testPappyPath() throws InterruptedException, TimeoutException {
Expand All @@ -51,15 +75,51 @@ public void testPappyPath() throws InterruptedException, TimeoutException {
Map.of("customerId", "testCustomer", "orderTotal", 190.0, "expiryDate", "10/24"))
.send()
.join();

waitForProcessInstanceCompleted(processInstance);
completeCustomerCreditHandling();
completeCreditCardCharging();
assertProcessInstanceCompleted(processInstance);

assertThat(processInstance)
.hasPassedElement("Activity_0nppgjk")
.hasVariableWithValue("remainingAmount", 90.0);
verify(mockedCustomerService).getCustomerCredit("testCustomer");
}

private void completeCreditCardCharging() throws InterruptedException, TimeoutException {
completeJob(
"creditCardCharging",
(activatedJob) ->
new CreditCardHandler(mockedCreditCardService).handle(zeebeClient, activatedJob));
}

private void completeCustomerCreditHandling() throws InterruptedException, TimeoutException {
completeJob(
"customerCreditHandling",
(activatedJob) -> {
try {
Map<String, Object> result =
new CustomerCreditHandler(mockedCustomerService).handle(activatedJob);
zeebeClient.newCompleteCommand(activatedJob).variables(result).send().join();
} catch (Exception e) {
zeebeClient.newFailCommand(activatedJob).retries(0).send().join();
}
});
}

private void completeJob(String jobType, Consumer<ActivatedJob> handler)
throws InterruptedException, TimeoutException {
// wait for idle state
engine.waitForIdleState(Duration.ofSeconds(10));
// find a job
ActivateJobsResponse jobsResponse =
zeebeClient.newActivateJobsCommand().jobType(jobType).maxJobsToActivate(1).send().join();
// expect exactly one
assertThat(jobsResponse).isNotNull();
assertThat(jobsResponse.getJobs()).hasSize(1);
// use the handler
handler.accept(jobsResponse.getJobs().get(0));
}

@Test
public void testNoCreditCardRequired() throws InterruptedException, TimeoutException {
given(mockedCustomerService.deductCredit(anyString(), anyDouble(), anyDouble()))
Expand All @@ -73,7 +133,8 @@ public void testNoCreditCardRequired() throws InterruptedException, TimeoutExcep
.variables(Map.of("customerId", "testCustomer", "orderTotal", 50.0))
.send()
.join();
waitForProcessInstanceCompleted(processInstance);
completeCustomerCreditHandling();
assertProcessInstanceCompleted(processInstance);

assertThat(processInstance).hasNotPassedElement("Activity_0nppgjk");
}
Expand All @@ -91,13 +152,13 @@ public void testIncident() throws InterruptedException, TimeoutException {
.send()
.join();

engine.waitForIdleState(Duration.ofSeconds(20));
completeCustomerCreditHandling();

assertThat(processInstance).isActive().hasAnyIncidents();
}

@Test
public void testInvalidExpiryDate() throws InterruptedException {
public void testInvalidExpiryDate() throws InterruptedException, TimeoutException {
doThrow(new CreditCardExpiredException("expired"))
.when(mockedCreditCardService)
.chargeAmount("1234 5678", "123", "05/23", 100.0);
Expand All @@ -120,8 +181,8 @@ public void testInvalidExpiryDate() throws InterruptedException {
.startBeforeElement("Activity_0nppgjk")
.send()
.join();

waitForProcessInstanceHasPassedElement(processInstance, "Event_0u18e53");
completeCreditCardCharging();
assertProcessInstanceHasPassedElement(processInstance, "Event_0u18e53");

assertThat(processInstance)
.isActive()
Expand All @@ -142,7 +203,7 @@ public void testCheckPayment() throws InterruptedException, TimeoutException {

completeUserTask(Map.of("errorResolved", false));

waitForProcessInstanceCompleted(processInstance);
assertProcessInstanceCompleted(processInstance);

assertThat(processInstance).isCompleted().hasPassedElement("Event_1854135");
}
Expand All @@ -158,10 +219,10 @@ public void testRetryPayment() throws InterruptedException, TimeoutException {
.variables(Map.of("remainingAmount", 10.0))
.send()
.join();

completeUserTask(Map.of("errorResolved", true));
completeCreditCardCharging();

waitForProcessInstanceHasPassedElement(processInstance, "Gateway_1ymklbs");
assertProcessInstanceHasPassedElement(processInstance, "Gateway_1ymklbs");

assertThat(processInstance).hasPassedElement("Activity_0nppgjk");
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,21 +7,17 @@
import com.camunda.consulting.web_shop_process_app.worker.CustomerCreditHandler;
import io.camunda.zeebe.client.api.response.ActivatedJob;
import java.util.Map;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
import org.mockito.junit.jupiter.MockitoExtension;

@ExtendWith(MockitoExtension.class)
public class WorkerTest {

@Mock(stubOnly = true)
ActivatedJob mockedJob;

@BeforeEach
public void init() {
MockitoAnnotations.openMocks(this);
}

@Test
public void testCustomerCreditWorker() {
given(mockedJob.getVariablesAsMap())
Expand Down