Skip to content

Commit

Permalink
Merge pull request #278 from camunda/backport-276-to-stable/8.0
Browse files Browse the repository at this point in the history
[Backport stable/8.0] Realistic example test
  • Loading branch information
remcowesterhoud authored Mar 30, 2022
2 parents 5b45a7d + 7980363 commit cf2af78
Show file tree
Hide file tree
Showing 9 changed files with 697 additions and 7 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@

import io.camunda.zeebe.client.impl.ZeebeObjectMapper;
import io.camunda.zeebe.process.test.filters.IncidentRecordStreamFilter;
import io.camunda.zeebe.process.test.filters.ProcessInstanceRecordStreamFilter;
import io.camunda.zeebe.process.test.filters.RecordStream;
import io.camunda.zeebe.process.test.filters.StreamFilter;
import io.camunda.zeebe.protocol.record.Record;
Expand All @@ -35,6 +36,7 @@
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.NoSuchElementException;
import java.util.Set;
import java.util.stream.Collectors;
import org.assertj.core.api.AbstractAssert;
Expand Down Expand Up @@ -597,4 +599,40 @@ private IncidentRecordStreamFilter getIncidentCreatedRecords() {
.withIntent(IncidentIntent.CREATED)
.withProcessInstanceKey(actual);
}

/**
* Extracts the latest called process. This will result in a failed assertion when no process has
* been called.
*
* @return {@link ProcessInstanceAssert} for the called process
*/
public ProcessInstanceAssert extractingLatestCalledProcess(final String processId) {
hasCalledProcess(processId);

final Record<ProcessInstanceRecordValue> latestCalledProcessRecord =
getCalledProcessRecords().stream()
.reduce((first, second) -> second)
.orElseThrow(NoSuchElementException::new);

return new ProcessInstanceAssert(latestCalledProcessRecord.getKey(), recordStream);
}

/**
* Asserts whether this process has called another process
*
* @param processId The id of the process that should be called
* @return this {@link ProcessInstanceAssert}
*/
public ProcessInstanceAssert hasCalledProcess(final String processId) {
final boolean hasCalledProcess = getCalledProcessRecords().stream().findAny().isPresent();

assertThat(hasCalledProcess)
.withFailMessage("No process with id `%s` was called from this process", processId)
.isTrue();
return this;
}

private ProcessInstanceRecordStreamFilter getCalledProcessRecords() {
return StreamFilter.processInstance(recordStream).withParentProcessInstanceKey(actual);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -36,8 +36,8 @@
*/
final class EngineStateMonitor implements LogStorage.CommitListener, StreamProcessorListener {

public static final int GRACE_PERIOD_MS = 50;
private static final Timer TIMER = new Timer();
public static final int GRACE_PERIOD = 30;
private final List<Runnable> idleCallbacks = new ArrayList<>();
private final List<Runnable> processingCallbacks = new ArrayList<>();
private final LogStreamReader reader;
Expand Down Expand Up @@ -88,8 +88,8 @@ private void notifyProcessingCallbacks() {
private void scheduleIdleStateNotification() {
idleStateNotifier = createIdleStateNotifier();
try {
TIMER.schedule(idleStateNotifier, GRACE_PERIOD);
} catch (IllegalStateException e) {
TIMER.schedule(idleStateNotifier, GRACE_PERIOD_MS);
} catch (final IllegalStateException e) {
// thrown - among others - if task was cancelled before it could be scheduled
// do nothing in this case
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -116,7 +116,12 @@ void testHasExpired() throws InterruptedException, TimeoutException {
// when
final PublishMessageResponse response =
Utilities.sendMessage(
engine, client, ProcessPackMessageEvent.MESSAGE_NAME, CORRELATION_KEY, timeToLive);
engine,
client,
ProcessPackMessageEvent.MESSAGE_NAME,
CORRELATION_KEY,
timeToLive,
Collections.emptyMap());
Utilities.increaseTime(engine, timeToLive.plusMinutes(1));

// then
Expand Down Expand Up @@ -285,7 +290,12 @@ void testHasNotExpiredFailure() throws InterruptedException, TimeoutException {
// when
final PublishMessageResponse response =
Utilities.sendMessage(
engine, client, ProcessPackMessageEvent.MESSAGE_NAME, CORRELATION_KEY, timeToLive);
engine,
client,
ProcessPackMessageEvent.MESSAGE_NAME,
CORRELATION_KEY,
timeToLive,
Collections.emptyMap());
Utilities.increaseTime(engine, timeToLive.plusMinutes(1));

// then
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,167 @@
/*
* Copyright © 2021 camunda services GmbH (info@camunda.com)
*
* 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.camunda.zeebe.process.test.qa.abstracts.examples;

import static io.camunda.zeebe.process.test.assertions.BpmnAssert.assertThat;
import static io.camunda.zeebe.process.test.qa.util.Utilities.ProcessPackPRCreated.AUTOMATED_TESTS_PROCESS_ID;
import static io.camunda.zeebe.process.test.qa.util.Utilities.ProcessPackPRCreated.AUTOMATED_TESTS_RESOURCE_NAME;
import static io.camunda.zeebe.process.test.qa.util.Utilities.ProcessPackPRCreated.AUTOMATED_TESTS_RUN_TESTS;
import static io.camunda.zeebe.process.test.qa.util.Utilities.ProcessPackPRCreated.DEPLOY_SNAPSHOT;
import static io.camunda.zeebe.process.test.qa.util.Utilities.ProcessPackPRCreated.MAKE_CHANGES;
import static io.camunda.zeebe.process.test.qa.util.Utilities.ProcessPackPRCreated.MERGE_CODE;
import static io.camunda.zeebe.process.test.qa.util.Utilities.ProcessPackPRCreated.PR_CREATED_MSG;
import static io.camunda.zeebe.process.test.qa.util.Utilities.ProcessPackPRCreated.PR_ID_VAR;
import static io.camunda.zeebe.process.test.qa.util.Utilities.ProcessPackPRCreated.REMIND_REVIEWER;
import static io.camunda.zeebe.process.test.qa.util.Utilities.ProcessPackPRCreated.REQUEST_REVIEW;
import static io.camunda.zeebe.process.test.qa.util.Utilities.ProcessPackPRCreated.RESOURCE_NAME;
import static io.camunda.zeebe.process.test.qa.util.Utilities.ProcessPackPRCreated.REVIEW_RECEIVED_MSG;
import static io.camunda.zeebe.process.test.qa.util.Utilities.ProcessPackPRCreated.REVIEW_RESULT_VAR;

import io.camunda.zeebe.client.ZeebeClient;
import io.camunda.zeebe.client.api.response.DeploymentEvent;
import io.camunda.zeebe.client.api.response.PublishMessageResponse;
import io.camunda.zeebe.process.test.api.ZeebeTestEngine;
import io.camunda.zeebe.process.test.qa.util.Utilities;
import java.time.Duration;
import java.util.Map;
import java.util.concurrent.TimeoutException;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;

/**
* This is an abstract test class so we can test these tests with both our extensions (embedded and
* testcontainer) without the need to duplicate our test code.
*
* <p>Users would not do this. They would create a regular test class and annotate this with the
* preferred annotation to include the extension they need.
*/
public abstract class AbstractPrCreatedTest {

private ZeebeTestEngine engine;
private ZeebeClient client;

@BeforeEach
void deployProcesses() {
// Normally these fields get injected by our annotation. Since we want to reuse these tests we
// need to use these abstract methods to obtain them, as they get injected in the extending test
// classes. Users would not need to do this.
engine = getEngine();
client = getClient();

final DeploymentEvent deploymentEvent =
Utilities.deployProcesses(client, RESOURCE_NAME, AUTOMATED_TESTS_RESOURCE_NAME);
assertThat(deploymentEvent)
.containsProcessesByResourceName(RESOURCE_NAME, AUTOMATED_TESTS_RESOURCE_NAME);
}

@Test
void testPRCreateddHappyPath() throws InterruptedException, TimeoutException {
// Given
final String prId = "123";
final PublishMessageResponse prCreatedResponse =
Utilities.sendMessage(engine, client, PR_CREATED_MSG, "", Map.of(PR_ID_VAR, prId));

// When
completeTask(REQUEST_REVIEW);
Utilities.sendMessage(
engine, client, REVIEW_RECEIVED_MSG, prId, Map.of(REVIEW_RESULT_VAR, "approved"));
completeTask(AUTOMATED_TESTS_RUN_TESTS);
completeTask(AUTOMATED_TESTS_RUN_TESTS);
completeTask(AUTOMATED_TESTS_RUN_TESTS);
completeTask(MERGE_CODE);
completeTask(DEPLOY_SNAPSHOT);

// Then
assertThat(prCreatedResponse)
.hasCreatedProcessInstance()
.extractingProcessInstance()
.hasPassedElementsInOrder(REQUEST_REVIEW, MERGE_CODE, DEPLOY_SNAPSHOT)
.hasNotPassedElement(REMIND_REVIEWER)
.hasNotPassedElement(MAKE_CHANGES)
.hasVariableWithValue(REVIEW_RESULT_VAR, "approved")
.extractingLatestCalledProcess(AUTOMATED_TESTS_PROCESS_ID)
.hasPassedElement(AUTOMATED_TESTS_RUN_TESTS, 3)
.isCompleted();
}

@Test
void testRemindReviewer() throws InterruptedException, TimeoutException {
// Given
final String prId = "123";
final PublishMessageResponse prCreatedResponse =
Utilities.sendMessage(engine, client, PR_CREATED_MSG, "", Map.of(PR_ID_VAR, prId));

// When
completeTask(REQUEST_REVIEW);
completeTask(AUTOMATED_TESTS_RUN_TESTS);
completeTask(AUTOMATED_TESTS_RUN_TESTS);
completeTask(AUTOMATED_TESTS_RUN_TESTS);
Utilities.increaseTime(engine, Duration.ofDays(1));
completeTask(REMIND_REVIEWER);
Utilities.sendMessage(
engine, client, REVIEW_RECEIVED_MSG, prId, Map.of(REVIEW_RESULT_VAR, "approved"));
completeTask(MERGE_CODE);
completeTask(DEPLOY_SNAPSHOT);

// Then
assertThat(prCreatedResponse)
.hasCreatedProcessInstance()
.extractingProcessInstance()
.hasPassedElementsInOrder(REQUEST_REVIEW, REMIND_REVIEWER, MERGE_CODE, DEPLOY_SNAPSHOT)
.hasNotPassedElement(MAKE_CHANGES)
.isCompleted();
}

@Test
void testRejectReview() throws InterruptedException, TimeoutException {
// Given
final String prId = "123";
final PublishMessageResponse prCreatedResponse =
Utilities.sendMessage(engine, client, PR_CREATED_MSG, "", Map.of(PR_ID_VAR, prId));

// When
completeTask(REQUEST_REVIEW);
completeTask(AUTOMATED_TESTS_RUN_TESTS);
completeTask(AUTOMATED_TESTS_RUN_TESTS);
completeTask(AUTOMATED_TESTS_RUN_TESTS);
Utilities.sendMessage(
engine, client, REVIEW_RECEIVED_MSG, prId, Map.of(REVIEW_RESULT_VAR, "rejected"));
completeTask(MAKE_CHANGES);
completeTask(REQUEST_REVIEW);
Utilities.sendMessage(
engine, client, REVIEW_RECEIVED_MSG, prId, Map.of(REVIEW_RESULT_VAR, "approved"));
completeTask(MERGE_CODE);
completeTask(DEPLOY_SNAPSHOT);

// Then
assertThat(prCreatedResponse)
.hasCreatedProcessInstance()
.extractingProcessInstance()
.hasPassedElementsInOrder(
REQUEST_REVIEW, MAKE_CHANGES, REQUEST_REVIEW, MERGE_CODE, DEPLOY_SNAPSHOT)
.hasNotPassedElement(REMIND_REVIEWER)
.isCompleted();
}

private void completeTask(final String taskId) throws InterruptedException, TimeoutException {
Utilities.completeTask(engine, client, taskId);
}

public abstract ZeebeClient getClient();

public abstract ZeebeTestEngine getEngine();
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
/*
* Copyright © 2021 camunda services GmbH (info@camunda.com)
*
* 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.camunda.zeebe.process.test.qa.embedded.examples;

import io.camunda.zeebe.client.ZeebeClient;
import io.camunda.zeebe.process.test.api.ZeebeTestEngine;
import io.camunda.zeebe.process.test.extension.ZeebeProcessTest;
import io.camunda.zeebe.process.test.qa.abstracts.examples.AbstractPrCreatedTest;

@ZeebeProcessTest
class PrCreatedTest extends AbstractPrCreatedTest {

private ZeebeTestEngine engine;
private ZeebeClient client;

@Override
public ZeebeClient getClient() {
return client;
}

@Override
public ZeebeTestEngine getEngine() {
return engine;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
/*
* Copyright © 2021 camunda services GmbH (info@camunda.com)
*
* 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.camunda.zeebe.process.test.qa.testcontainer.examples;

import io.camunda.zeebe.client.ZeebeClient;
import io.camunda.zeebe.process.test.api.ZeebeTestEngine;
import io.camunda.zeebe.process.test.extension.testcontainer.ZeebeProcessTest;
import io.camunda.zeebe.process.test.qa.abstracts.examples.AbstractPrCreatedTest;

@ZeebeProcessTest
public class PrCreatedTest extends AbstractPrCreatedTest {
private ZeebeTestEngine engine;
private ZeebeClient client;

@Override
public ZeebeClient getClient() {
return client;
}

@Override
public ZeebeTestEngine getEngine() {
return engine;
}
}
Loading

0 comments on commit cf2af78

Please sign in to comment.