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

[Backport stable/8.0] Realistic example test #278

Merged
merged 5 commits into from
Mar 30, 2022
Merged
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
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