content: /*
   * Copyright 2017-2025 Hyland Software, Inc. and its affiliates.
   *
   * 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 org.activiti.cloud.starter.audit.tests.it;
  
  import static org.assertj.core.api.Assertions.assertThat;
  import static org.assertj.core.api.Assertions.tuple;
  import static org.awaitility.Awaitility.await;
  
  import java.math.BigDecimal;
  import java.util.ArrayList;
  import java.util.Arrays;
  import java.util.Collection;
  import java.util.Collections;
  import java.util.HashMap;
  import java.util.List;
  import java.util.Map;
  import java.util.UUID;
  import org.activiti.api.model.shared.event.VariableEvent;
  import org.activiti.api.process.model.builders.ProcessPayloadBuilder;
  import org.activiti.api.process.model.events.ApplicationEvent;
  import org.activiti.api.process.model.events.ApplicationEvent.ApplicationEvents;
  import org.activiti.api.process.model.events.BPMNActivityEvent;
  import org.activiti.api.process.model.events.BPMNErrorReceivedEvent;
  import org.activiti.api.process.model.events.BPMNTimerEvent;
  import org.activiti.api.process.model.events.MessageSubscriptionCancelledEvent;
  import org.activiti.api.process.model.payloads.SignalPayload;
  import org.activiti.api.process.model.payloads.TimerPayload;
  import org.activiti.api.runtime.model.impl.BPMNActivityImpl;
  import org.activiti.api.runtime.model.impl.BPMNErrorImpl;
  import org.activiti.api.runtime.model.impl.BPMNSignalImpl;
  import org.activiti.api.runtime.model.impl.BPMNTimerImpl;
  import org.activiti.api.runtime.model.impl.DeploymentImpl;
  import org.activiti.api.runtime.model.impl.IntegrationContextImpl;
  import org.activiti.api.runtime.model.impl.MessageSubscriptionImpl;
  import org.activiti.api.runtime.model.impl.ProcessCandidateStarterGroupImpl;
  import org.activiti.api.runtime.model.impl.ProcessCandidateStarterUserImpl;
  import org.activiti.api.runtime.model.impl.ProcessDefinitionImpl;
  import org.activiti.api.runtime.model.impl.ProcessInstanceImpl;
  import org.activiti.api.runtime.model.impl.VariableInstanceImpl;
  import org.activiti.api.task.model.Task;
  import org.activiti.api.task.model.events.TaskCandidateUserEvent;
  import org.activiti.api.task.model.events.TaskRuntimeEvent;
  import org.activiti.api.task.model.impl.TaskCandidateUserImpl;
  import org.activiti.api.task.model.impl.TaskImpl;
  import org.activiti.cloud.api.model.shared.events.CloudRuntimeEvent;
  import org.activiti.cloud.api.model.shared.events.CloudVariableCreatedEvent;
  import org.activiti.cloud.api.model.shared.events.CloudVariableEvent;
  import org.activiti.cloud.api.model.shared.impl.conf.IgnoredRuntimeEvent;
  import org.activiti.cloud.api.model.shared.impl.events.CloudRuntimeEventImpl;
  import org.activiti.cloud.api.model.shared.impl.events.CloudVariableCreatedEventImpl;
  import org.activiti.cloud.api.model.shared.impl.events.CloudVariableDeletedEventImpl;
  import org.activiti.cloud.api.model.shared.impl.events.CloudVariableUpdatedEventImpl;
  import org.activiti.cloud.api.process.model.CloudBpmnError;
  import org.activiti.cloud.api.process.model.events.CloudApplicationDeployedEvent;
  import org.activiti.cloud.api.process.model.events.CloudBPMNActivityEvent;
  import org.activiti.cloud.api.process.model.events.CloudBPMNActivityStartedEvent;
  import org.activiti.cloud.api.process.model.events.CloudBPMNErrorReceivedEvent;
  import org.activiti.cloud.api.process.model.events.CloudBPMNSignalReceivedEvent;
  import org.activiti.cloud.api.process.model.events.CloudBPMNTimerScheduledEvent;
  import org.activiti.cloud.api.process.model.events.CloudMessageSubscriptionCancelledEvent;
  import org.activiti.cloud.api.process.model.impl.events.CloudApplicationDeployedEventImpl;
  import org.activiti.cloud.api.process.model.impl.events.CloudBPMNActivityCancelledEventImpl;
  import org.activiti.cloud.api.process.model.impl.events.CloudBPMNActivityCompletedEventImpl;
  import org.activiti.cloud.api.process.model.impl.events.CloudBPMNActivityStartedEventImpl;
  import org.activiti.cloud.api.process.model.impl.events.CloudBPMNErrorReceivedEventImpl;
  import org.activiti.cloud.api.process.model.impl.events.CloudBPMNSignalReceivedEventImpl;
  import org.activiti.cloud.api.process.model.impl.events.CloudBPMNTimerFiredEventImpl;
  import org.activiti.cloud.api.process.model.impl.events.CloudBPMNTimerScheduledEventImpl;
  import org.activiti.cloud.api.process.model.impl.events.CloudIntegrationErrorReceivedEventImpl;
  import org.activiti.cloud.api.process.model.impl.events.CloudIntegrationRequestedEventImpl;
  import org.activiti.cloud.api.process.model.impl.events.CloudIntegrationResultReceivedEventImpl;
  import org.activiti.cloud.api.process.model.impl.events.CloudMessageSubscriptionCancelledEventImpl;
  import org.activiti.cloud.api.process.model.impl.events.CloudProcessCancelledEventImpl;
  import org.activiti.cloud.api.process.model.impl.events.CloudProcessCandidateStarterGroupAddedEventImpl;
  import org.activiti.cloud.api.process.model.impl.events.CloudProcessCandidateStarterGroupRemovedEventImpl;
  import org.activiti.cloud.api.process.model.impl.events.CloudProcessCandidateStarterUserAddedEventImpl;
  import org.activiti.cloud.api.process.model.impl.events.CloudProcessCandidateStarterUserRemovedEventImpl;
  import org.activiti.cloud.api.process.model.impl.events.CloudProcessCompletedEventImpl;
  import org.activiti.cloud.api.process.model.impl.events.CloudProcessDeletedEventImpl;
  import org.activiti.cloud.api.process.model.impl.events.CloudProcessDeployedEventImpl;
  import org.activiti.cloud.api.process.model.impl.events.CloudProcessStartedEventImpl;
  import org.activiti.cloud.api.process.model.impl.events.CloudProcessSuspendedEventImpl;
  import org.activiti.cloud.api.process.model.impl.events.CloudProcessUpdatedEventImpl;
  import org.activiti.cloud.api.task.model.events.CloudTaskAssignedEvent;
  import org.activiti.cloud.api.task.model.events.CloudTaskCancelledEvent;
  import org.activiti.cloud.api.task.model.events.CloudTaskCreatedEvent;
  import org.activiti.cloud.api.task.model.impl.events.CloudTaskAssignedEventImpl;
  import org.activiti.cloud.api.task.model.impl.events.CloudTaskCancelledEventImpl;
  import org.activiti.cloud.api.task.model.impl.events.CloudTaskCandidateUserAddedEventImpl;
  import org.activiti.cloud.api.task.model.impl.events.CloudTaskCandidateUserRemovedEventImpl;
  import org.activiti.cloud.api.task.model.impl.events.CloudTaskCompletedEventImpl;
  import org.activiti.cloud.api.task.model.impl.events.CloudTaskCreatedEventImpl;
  import org.activiti.cloud.api.task.model.impl.events.CloudTaskUpdatedEventImpl;
  import org.activiti.cloud.services.audit.jpa.repository.EventsRepository;
  import org.activiti.cloud.services.test.containers.KeycloakContainerApplicationInitializer;
  import org.activiti.cloud.starters.test.MyProducer;
  import org.junit.jupiter.api.AfterEach;
  import org.junit.jupiter.api.Test;
  import org.springframework.beans.factory.annotation.Autowired;
  import org.springframework.boot.test.context.SpringBootTest;
  import org.springframework.cloud.stream.binder.test.TestChannelBinderConfiguration;
  import org.springframework.context.annotation.Import;
  import org.springframework.hateoas.PagedModel;
  import org.springframework.http.ResponseEntity;
  import org.springframework.test.annotation.DirtiesContext;
  import org.springframework.test.context.ContextConfiguration;
  import org.springframework.test.context.TestPropertySource;
  
  @SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
  @DirtiesContext
  @TestPropertySource("classpath:application.properties")
  @Import({ EventsRestTemplate.class, TestChannelBinderConfiguration.class })
  @ContextConfiguration(initializers = { KeycloakContainerApplicationInitializer.class })
  public class AuditServiceIT {
  
      private static final String ERROR_MESSAGE =
          "An error occurred consuming ACS API with inputs {targetFolder={}, action=CREATE_FILE}. Cause: [405] during [GET] to [https://aae-3734-env.envalfresco.com/alfresco/api/-default-/public/alfresco/versions/1/nodes/] [NodesApiClient#getNode(String,List,String,List)]: [{\"error\":{\"errorKey\":\"framework.exception.UnsupportedResourceOperation\",\"statusCode\":405,\"briefSummary\":\"09070282 The operation is unsupported\",\"stackTrace\":\"For security reasons the stack trace is no longer displayed, but the property is kept for previous versions\",\"descriptionURL\":\"https://api-explorer.alfresco.com\"}}]";
  
      @Autowired
      private EventsRestTemplate eventsRestTemplate;
  
      @Autowired
      private EventsRepository repository;
  
      @Autowired
      private MyProducer producer;
  
      @AfterEach
      public void cleanUp() {
          repository.deleteAll();
      }
  
      @Test
      public void findAllShouldReturnAllAvailableEvents() {
          //given
          List<CloudRuntimeEvent> coveredEvents = getTestEvents();
  
          producer.send(coveredEvents.toArray(new CloudRuntimeEvent[coveredEvents.size()]));
  
          await()
              .untilAsserted(() -> {
                  //when
                  ResponseEntity<PagedModel<CloudRuntimeEvent>> eventsPagedModel = eventsRestTemplate.executeFindAll();
  
                  //then
                  Collection<CloudRuntimeEvent> retrievedEvents = eventsPagedModel.getBody().getContent();
                  assertThat(retrievedEvents).hasSameSizeAs(coveredEvents);
                  for (CloudRuntimeEvent coveredEvent : coveredEvents) {
                      assertThat(retrievedEvents)
                          .extracting(
                              CloudRuntimeEvent::getEventType,
                              CloudRuntimeEvent::getServiceName,
                              CloudRuntimeEvent::getServiceVersion
                          )
                          .contains(
                              tuple(
                                  coveredEvent.getEventType(),
                                  coveredEvent.getServiceName(),
                                  coveredEvent.getServiceVersion()
                              )
                          );
                  }
                  assertThatEntityIsSet(retrievedEvents);
              });
      }
  
      @Test
      public void should_supportEventsContainingBigDecimalValues() {
          //given
          CloudVariableCreatedEventImpl variableCreatedEvent = new CloudVariableCreatedEventImpl(
              new VariableInstanceImpl<>(
                  "bigDecimalVar",
                  "bigdecimal",
                  BigDecimal.valueOf(100, 2),
                  UUID.randomUUID().toString(),
                  null
              )
          );
          producer.send(variableCreatedEvent);
  
          await()
              .untilAsserted(() -> {
                  //when
                  ResponseEntity<PagedModel<CloudRuntimeEvent>> eventsPagedModel = eventsRestTemplate.executeFindAll();
  
                  //then
                  Collection<CloudRuntimeEvent> retrievedEvents = eventsPagedModel.getBody().getContent();
                  assertThat(retrievedEvents).hasSize(1).hasOnlyElementsOfTypes(CloudVariableCreatedEvent.class);
                  CloudVariableCreatedEvent retrievedEvent = (CloudVariableCreatedEvent) retrievedEvents
                      .iterator()
                      .next();
                  assertThat(retrievedEvent)
                      .extracting(
                          event -> event.getEntity().getName(),
                          event -> event.getEntity().getType(),
                          event -> event.getEntity().getValue()
                      )
                      .containsExactly("bigDecimalVar", "bigdecimal", "1.00");
              });
      }
  
      @Test
      public void should_handleEphemeralVariables() {
          //given
          VariableInstanceImpl<String> variableInstance = new VariableInstanceImpl<>(
              "ephemeralVar",
              "string",
              null,
              UUID.randomUUID().toString(),
              null
          );
          List<CloudVariableEvent> variableEvents = new ArrayList<>();
          variableEvents.add(new CloudVariableCreatedEventImpl(variableInstance, true));
          variableEvents.add(new CloudVariableUpdatedEventImpl<>(variableInstance, null, true));
          variableEvents.add(new CloudVariableDeletedEventImpl(variableInstance, true));
          producer.send(variableEvents.toArray(new CloudVariableEvent[0]));
  
          await()
              .untilAsserted(() -> {
                  //when
                  ResponseEntity<PagedModel<CloudRuntimeEvent>> eventsPagedModel = eventsRestTemplate.executeFindAll();
  
                  //then
                  Collection<CloudRuntimeEvent> retrievedEvents = eventsPagedModel.getBody().getContent();
                  assertThat(retrievedEvents)
                      .filteredOn(CloudVariableEvent.class::isInstance)
                      .extracting(CloudVariableEvent.class::cast)
                      .extracting(
                          CloudVariableEvent::getEventType,
                          event -> event.getEntity().getName(),
                          event -> event.getEntity().getType(),
                          event -> event.getEntity().getValue(),
                          CloudVariableEvent::isEphemeralVariable
                      )
                      .containsExactlyInAnyOrder(
                          tuple(VariableEvent.VariableEvents.VARIABLE_CREATED, "ephemeralVar", "string", null, true),
                          tuple(VariableEvent.VariableEvents.VARIABLE_UPDATED, "ephemeralVar", "string", null, true),
                          tuple(VariableEvent.VariableEvents.VARIABLE_DELETED, "ephemeralVar", "string", null, true)
                      );
              });
      }
  
      @Test
      public void shouldBeAbleToFilterOnProcessInstanceId() {
          //given
          List<CloudRuntimeEvent> coveredEvents = getTestEvents();
          producer.send(coveredEvents.toArray(new CloudRuntimeEvent[coveredEvents.size()]));
  
          await()
              .untilAsserted(() -> {
                  //when
                  ResponseEntity<PagedModel<CloudRuntimeEvent>> eventsPagedModel = eventsRestTemplate.executeFind(
                      Collections.singletonMap("processInstanceId", "4")
                  );
  
                  //then
                  Collection<CloudRuntimeEvent> retrievedEvents = eventsPagedModel.getBody().getContent();
                  assertThat(retrievedEvents).hasSize(2);
                  for (CloudRuntimeEvent event : retrievedEvents) {
                      CloudBPMNActivityEvent cloudBPMNActivityEvent = (CloudBPMNActivityEvent) event;
                      assertThat(cloudBPMNActivityEvent.getProcessInstanceId()).isEqualTo("4");
                  }
              });
      }
  
      @Test
      public void shouldBeAbleToFilterOnProcessInstanceIdAndEventType() {
          //given
          List<CloudRuntimeEvent> coveredEvents = getTestEvents();
          producer.send(coveredEvents.toArray(new CloudRuntimeEvent[coveredEvents.size()]));
  
          await()
              .untilAsserted(() -> {
                  //when
                  Map<String, Object> filters = new HashMap<>();
                  filters.put("processInstanceId", "4");
                  filters.put("eventType", BPMNActivityEvent.ActivityEvents.ACTIVITY_STARTED.name());
                  ResponseEntity<PagedModel<CloudRuntimeEvent>> eventsPagedModel = eventsRestTemplate.executeFind(
                      filters
                  );
  
                  //then
                  Collection<CloudRuntimeEvent> retrievedEvents = eventsPagedModel.getBody().getContent();
                  assertThat(retrievedEvents).hasSize(2);
                  for (CloudRuntimeEvent event : retrievedEvents) {
                      CloudBPMNActivityEvent cloudBPMNActivityEvent = (CloudBPMNActivityStartedEvent) event;
                      assertThat(cloudBPMNActivityEvent.getEventType())
                          .isEqualTo(BPMNActivityEvent.ActivityEvents.ACTIVITY_STARTED);
                  }
              });
      }
  
      @Test
      public void should_getTaskCreatedEvent_when_filteredOnProcessInstanceIdEventType() {
          //given
          List<CloudRuntimeEvent> coveredEvents = getTestEvents();
          producer.send(coveredEvents.toArray(new CloudRuntimeEvent[coveredEvents.size()]));
  
          await()
              .untilAsserted(() -> {
                  //when
                  Map<String, Object> filters = new HashMap<>();
                  filters.put("processInstanceId", "47");
                  filters.put("eventType", TaskRuntimeEvent.TaskEvents.TASK_CREATED.name());
  
                  ResponseEntity<PagedModel<CloudRuntimeEvent>> eventsPagedModel = eventsRestTemplate.executeFind(
                      filters
                  );
  
                  //then
                  assertThat(eventsPagedModel).isNotNull();
                  assertThat(eventsPagedModel.getBody())
                      .isNotEmpty()
                      .filteredOn(event ->
                          ((CloudTaskCreatedEvent) event).getEntity().getTaskDefinitionKey().equals("taskDefinitionKey")
                      )
                      .extracting(
                          event -> event.getEventType(),
                          event -> ((CloudTaskCreatedEvent) event).getEntity().getName(),
                          event -> ((CloudTaskCreatedEvent) event).getEntity().getTaskDefinitionKey()
                      )
                      .contains(tuple(TaskRuntimeEvent.TaskEvents.TASK_CREATED, "task created", "taskDefinitionKey"));
              });
      }
  
      @Test
      public void shouldGetProcessStartedUpdatedCompletedEvents() {
          //given
          List<CloudRuntimeEvent> coveredEvents = getTestProcessStartedUpdatedCompletedEvents();
          producer.send(coveredEvents.toArray(new CloudRuntimeEvent[0]));
  
          await()
              .untilAsserted(() -> {
                  //when
                  Map<String, Object> filters = new HashMap<>();
                  filters.put("processInstanceId", "25");
  
                  ResponseEntity<PagedModel<CloudRuntimeEvent>> eventsPagedModel = eventsRestTemplate.executeFind(
                      filters
                  );
  
                  //then
                  Collection<CloudRuntimeEvent> retrievedEvents = eventsPagedModel.getBody().getContent();
                  assertThat(retrievedEvents).hasSameSizeAs(coveredEvents);
                  for (CloudRuntimeEvent coveredEvent : coveredEvents) {
                      assertThat(retrievedEvents)
                          .extracting(
                              CloudRuntimeEvent::getEventType,
                              CloudRuntimeEvent::getServiceName,
                              CloudRuntimeEvent::getServiceVersion
                          )
                          .contains(
                              tuple(
                                  coveredEvent.getEventType(),
                                  coveredEvent.getServiceName(),
                                  coveredEvent.getServiceVersion()
                              )
                          );
                  }
  
                  assertThatEntityIsSet(retrievedEvents);
                  retrievedEvents.forEach(event -> {
                      assertThat(event.getProcessDefinitionId())
                          .describedAs("Process definition for event " + event.getEventType() + " should not be null!")
                          .isNotNull();
                      assertThat(event.getProcessInstanceId())
                          .describedAs("Process instance for event " + event.getEventType() + " should not be null!")
                          .isNotNull();
                  });
              });
      }
  
      private void assertThatEntityIsSet(Collection<CloudRuntimeEvent> retrievedEvents) {
          retrievedEvents.forEach(event ->
              assertThat(event.getEntity())
                  .describedAs("Entity for " + event.getEventType() + " should not be null")
                  .isNotNull()
          );
          retrievedEvents.forEach(event ->
              assertThat(event.getEntityId())
                  .describedAs("EntityId for " + event.getEventType() + " should not be null")
                  .isNotNull()
          );
      }
  
      @Test
      public void shouldGetEventsForACancelledTask() {
          //given
          List<CloudRuntimeEvent> coveredEvents = getTaskCancelledEvents();
          producer.send(coveredEvents.toArray(new CloudRuntimeEvent[coveredEvents.size()]));
  
          await()
              .untilAsserted(() -> {
                  //when
                  Map<String, Object> filters = new HashMap<>();
                  filters.put("entityId", "1234-abc-5678-def");
  
                  ResponseEntity<PagedModel<CloudRuntimeEvent>> eventsPagedModel = eventsRestTemplate.executeFind(
                      filters
                  );
  
                  //then
                  Collection<CloudRuntimeEvent> retrievedEvents = eventsPagedModel.getBody().getContent();
                  assertThat(retrievedEvents).hasSize(3);
                  for (CloudRuntimeEvent e : retrievedEvents) {
                      assertThat(e.getEntityId()).isEqualTo("1234-abc-5678-def");
                  }
              });
      }
  
      @Test
      public void shouldBeAbleToFilterOnEventType() {
          //given
          List<CloudRuntimeEvent> coveredEvents = getTestEvents();
          producer.send(coveredEvents.toArray(new CloudRuntimeEvent[coveredEvents.size()]));
  
          await()
              .untilAsserted(() -> {
                  //when
                  ResponseEntity<PagedModel<CloudRuntimeEvent>> eventsPagedModel = eventsRestTemplate.executeFind(
                      Collections.singletonMap("eventType", TaskRuntimeEvent.TaskEvents.TASK_ASSIGNED.name())
                  );
  
                  //then
                  Collection<CloudRuntimeEvent> retrievedEvents = eventsPagedModel.getBody().getContent();
                  assertThat(retrievedEvents).hasSize(1);
                  CloudTaskAssignedEvent cloudTaskAssignedEvent = (CloudTaskAssignedEvent) retrievedEvents
                      .iterator()
                      .next();
                  assertThat(cloudTaskAssignedEvent.getEventType()).isEqualTo(TaskRuntimeEvent.TaskEvents.TASK_ASSIGNED);
                  assertThat(cloudTaskAssignedEvent.getEntity().getProcessDefinitionId()).isEqualTo("27");
                  assertThat(cloudTaskAssignedEvent.getEntity().getProcessInstanceId()).isEqualTo("46");
              });
      }
  
      @Test
      public void shouldBeAbleToFilterOnEventTypeActivitiStarted() {
          //given
          List<CloudRuntimeEvent> coveredEvents = getTestEvents();
          producer.send(coveredEvents.toArray(new CloudRuntimeEvent[coveredEvents.size()]));
  
          await()
              .untilAsserted(() -> {
                  //when
                  ResponseEntity<PagedModel<CloudRuntimeEvent>> eventsPagedModel = eventsRestTemplate.executeFind(
                      Collections.singletonMap("eventType", BPMNActivityEvent.ActivityEvents.ACTIVITY_STARTED.name())
                  );
  
                  //then
                  Collection<CloudRuntimeEvent> retrievedEvents = eventsPagedModel.getBody().getContent();
                  assertThat(retrievedEvents).hasSize(3);
                  for (CloudRuntimeEvent event : retrievedEvents) {
                      CloudBPMNActivityEvent cloudBPMNActivityEvent = (CloudBPMNActivityStartedEvent) event;
                      assertThat(cloudBPMNActivityEvent.getEventType())
                          .isEqualTo(BPMNActivityEvent.ActivityEvents.ACTIVITY_STARTED);
                  }
              });
      }
  
      @Test
      public void shouldBeAbleToFilterOnEventEntityId() {
          //given
          List<CloudRuntimeEvent> coveredEvents = getTestEvents();
          producer.send(coveredEvents.toArray(new CloudRuntimeEvent[coveredEvents.size()]));
  
          await()
              .untilAsserted(() -> {
                  //when
  
                  ResponseEntity<PagedModel<CloudRuntimeEvent>> eventsPagedModel = eventsRestTemplate.executeFind(
                      Collections.singletonMap("entityId", "1234-abc-5678-def")
                  );
                  //then
                  assertThat(eventsPagedModel.getBody()).isNotNull();
  
                  assertThat(eventsPagedModel.getBody().getContent())
                      .extracting(CloudRuntimeEvent::getEntityId)
                      .containsOnly("1234-abc-5678-def");
              });
      }
  
      @Test
      public void shouldBeAbleToFilterOnEventTypeTaskCancelled() {
          //given
          List<CloudRuntimeEvent> coveredEvents = getTestEvents();
          producer.send(coveredEvents.toArray(new CloudRuntimeEvent[coveredEvents.size()]));
  
          await()
              .untilAsserted(() -> {
                  //when
                  ResponseEntity<PagedModel<CloudRuntimeEvent>> eventsPagedModel = eventsRestTemplate.executeFind(
                      Collections.singletonMap("eventType", TaskRuntimeEvent.TaskEvents.TASK_CANCELLED.name())
                  );
  
                  //then
                  Collection<CloudRuntimeEvent> retrievedEvents = eventsPagedModel.getBody().getContent();
                  assertThat(retrievedEvents).hasSize(1);
                  CloudTaskCancelledEvent cloudBPMNTaskCancelled = (CloudTaskCancelledEvent) retrievedEvents
                      .iterator()
                      .next();
                  assertThat(cloudBPMNTaskCancelled.getEventType()).isEqualTo(TaskRuntimeEvent.TaskEvents.TASK_CANCELLED);
                  assertThat(cloudBPMNTaskCancelled.getEntityId()).isEqualTo("1234-abc-5678-def");
                  assertThat(cloudBPMNTaskCancelled.getEntity()).isInstanceOf(Task.class);
                  assertThat(cloudBPMNTaskCancelled.getEntity().getId()).isEqualTo("1234-abc-5678-def");
              });
      }
  
      @Test
      public void findByIdShouldReturnTheEventIdentifiedByTheGivenId() {
          //given
          CloudRuntimeEvent[] events = new CloudRuntimeEvent[1];
  
          BPMNActivityImpl bpmnActivityStarted = new BPMNActivityImpl();
          bpmnActivityStarted.setActivityName("first step");
          String eventId = "ActivityStartedEventId" + UUID.randomUUID().toString();
          CloudBPMNActivityStartedEventImpl cloudBPMNActivityStartedEvent = new CloudBPMNActivityStartedEventImpl(
              eventId,
              System.currentTimeMillis(),
              bpmnActivityStarted,
              "3",
              "4"
          );
  
          events[0] = cloudBPMNActivityStartedEvent;
  
          producer.send(events);
  
          await()
              .untilAsserted(() -> {
                  //when
                  ResponseEntity<CloudRuntimeEvent> responseEntity = eventsRestTemplate.executeFindById(eventId);
  
                  //then
                  CloudRuntimeEvent event = responseEntity.getBody();
  
                  assertThat(event).isInstanceOf(CloudBPMNActivityStartedEvent.class);
  
                  CloudBPMNActivityStartedEvent cloudProcessStartedEvent = (CloudBPMNActivityStartedEvent) event;
                  assertThat(cloudProcessStartedEvent.getEventType())
                      .isEqualTo(BPMNActivityEvent.ActivityEvents.ACTIVITY_STARTED);
                  assertThat(cloudProcessStartedEvent.getProcessDefinitionId()).isEqualTo("3");
                  assertThat(cloudProcessStartedEvent.getProcessInstanceId()).isEqualTo("4");
                  assertThat(cloudProcessStartedEvent.getEntity().getActivityName()).isEqualTo("first step");
              });
      }
  
      @Test
      public void unknownEventShouldNotPreventHandlingOfKnownEvents() {
          //given
          CloudRuntimeEvent[] events = new CloudRuntimeEvent[2];
  
          BPMNActivityImpl bpmnActivityStarted = new BPMNActivityImpl();
          bpmnActivityStarted.setActivityName("first step");
          String eventId = "ActivityStartedEventId" + UUID.randomUUID().toString();
          CloudBPMNActivityStartedEventImpl cloudBPMNActivityStartedEvent = new CloudBPMNActivityStartedEventImpl(
              eventId,
              System.currentTimeMillis(),
              bpmnActivityStarted,
              "3",
              "4"
          );
  
          events[0] = cloudBPMNActivityStartedEvent;
          events[1] =
              new CloudRuntimeEventImpl() {
                  @Override
                  public Enum<?> getEventType() {
                      return IgnoredRuntimeEvent.IgnoredRuntimeEvents.IGNORED;
                  }
              };
  
          producer.send(events);
  
          await()
              .untilAsserted(() -> {
                  //then
                  ResponseEntity<PagedModel<CloudRuntimeEvent>> eventsPagedModel = eventsRestTemplate.executeFindAll();
                  assertThat(eventsPagedModel.getBody()).isNotEmpty();
  
                  Collection<CloudRuntimeEvent> retrievedEvents = eventsPagedModel.getBody().getContent();
                  assertThat(retrievedEvents).hasSize(1);
                  CloudRuntimeEvent event = retrievedEvents.iterator().next();
                  //when
                  assertThat(event).isInstanceOf(CloudBPMNActivityStartedEvent.class);
  
                  CloudBPMNActivityStartedEvent cloudProcessStartedEvent = (CloudBPMNActivityStartedEvent) event;
                  assertThat(cloudProcessStartedEvent.getEventType())
                      .isEqualTo(BPMNActivityEvent.ActivityEvents.ACTIVITY_STARTED);
                  assertThat(cloudProcessStartedEvent.getProcessDefinitionId()).isEqualTo("3");
                  assertThat(cloudProcessStartedEvent.getProcessInstanceId()).isEqualTo("4");
                  assertThat(cloudProcessStartedEvent.getEntity().getActivityName()).isEqualTo("first step");
              });
      }
  
      @Test
      public void shouldGetUserCandidateEvents() {
          //given
          List<CloudRuntimeEvent> coveredEvents = getTestUserCandidatesEvents();
          producer.send(coveredEvents.toArray(new CloudRuntimeEvent[coveredEvents.size()]));
  
          await()
              .untilAsserted(() -> {
                  //when
                  ResponseEntity<PagedModel<CloudRuntimeEvent>> eventsPagedModel = eventsRestTemplate.executeFindAll();
  
                  //then
                  Collection<CloudRuntimeEvent> retrievedEvents = eventsPagedModel.getBody().getContent();
                  assertThat(retrievedEvents).hasSize(2);
  
                  CloudRuntimeEvent e = retrievedEvents.iterator().next();
                  assertThat(e.getEventType())
                      .isIn(
                          TaskCandidateUserEvent.TaskCandidateUserEvents.TASK_CANDIDATE_USER_ADDED,
                          TaskCandidateUserEvent.TaskCandidateUserEvents.TASK_CANDIDATE_USER_REMOVED
                      );
                  assertThat(e.getEntityId()).isEqualTo("userId");
  
                  e = retrievedEvents.iterator().next();
                  assertThat(e.getEventType())
                      .isIn(
                          TaskCandidateUserEvent.TaskCandidateUserEvents.TASK_CANDIDATE_USER_ADDED,
                          TaskCandidateUserEvent.TaskCandidateUserEvents.TASK_CANDIDATE_USER_REMOVED
                      );
                  assertThat(e.getEntityId()).isEqualTo("userId");
              });
      }
  
      @Test
      public void eventsShouldHaveSequenceNumberSet() {
          //given
          List<CloudRuntimeEvent> testEvents = getTaskCancelledEvents();
  
          producer.send(testEvents.toArray(new CloudRuntimeEvent[testEvents.size()]));
  
          await()
              .untilAsserted(() -> {
                  //when
                  ResponseEntity<PagedModel<CloudRuntimeEvent>> eventsPagedModel = eventsRestTemplate.executeFindAll();
  
                  //then
                  Collection<CloudRuntimeEvent> retrievedEvents = eventsPagedModel.getBody().getContent();
                  List<CloudRuntimeEvent> retrievedEventsList = new ArrayList<>(retrievedEvents);
  
                  assertThat(retrievedEvents).hasSameSizeAs(testEvents);
  
                  for (int i = 0; i < testEvents.size(); i++) {
                      assertThat(retrievedEventsList.get(i).getSequenceNumber()).isEqualTo(i);
                  }
              });
      }
  
      @Test
      public void eventsShouldHaveMessageIdSet() {
          //given
          List<CloudRuntimeEvent> testEvents = getTaskCancelledEvents();
  
          producer.send(testEvents.toArray(new CloudRuntimeEvent[testEvents.size()]));
  
          await()
              .untilAsserted(() -> {
                  //when
                  ResponseEntity<PagedModel<CloudRuntimeEvent>> eventsPagedModel = eventsRestTemplate.executeFindAll();
  
                  //then
                  Collection<CloudRuntimeEvent> retrievedEvents = eventsPagedModel.getBody().getContent();
                  List<CloudRuntimeEvent> retrievedEventsList = new ArrayList<>(retrievedEvents);
  
                  assertThat(retrievedEvents).hasSameSizeAs(testEvents);
                  String commonMessageId = retrievedEventsList.get(0).getMessageId();
  
                  for (int i = 0; i < testEvents.size(); i++) {
                      assertThat(retrievedEventsList.get(i).getMessageId()).isNotNull().isEqualTo(commonMessageId);
                  }
              });
      }
  
      @Test
      public void shouldGetSignalReceivedEvent() {
          //given
          List<CloudRuntimeEvent> coveredEvents = new ArrayList<>();
  
          BPMNSignalImpl signal = new BPMNSignalImpl("signalId");
          signal.setProcessDefinitionId("processDefinitionId");
          signal.setProcessInstanceId("processInstanceId");
  
          SignalPayload signalPayload = ProcessPayloadBuilder
              .signal()
              .withName("SignalName")
              .withVariable("signal-variable", "test")
              .build();
          signal.setSignalPayload(signalPayload);
  
          CloudBPMNSignalReceivedEventImpl cloudSignalReceivedEvent = new CloudBPMNSignalReceivedEventImpl(
              "eventId",
              System.currentTimeMillis(),
              signal,
              signal.getProcessDefinitionId(),
              signal.getProcessInstanceId()
          );
          coveredEvents.add(cloudSignalReceivedEvent);
  
          producer.send(coveredEvents.toArray(new CloudRuntimeEvent[coveredEvents.size()]));
  
          await()
              .untilAsserted(() -> {
                  //when
                  Map<String, Object> filters = new HashMap<>();
                  filters.put("entityId", "signalId");
  
                  ResponseEntity<PagedModel<CloudRuntimeEvent>> eventsPagedModel = eventsRestTemplate.executeFind(
                      filters
                  );
  
                  //then
                  Collection<CloudRuntimeEvent> retrievedEvents = eventsPagedModel.getBody().getContent();
                  assertThat(retrievedEvents).hasSize(1);
  
                  assertThat(retrievedEvents)
                      .extracting(
                          CloudRuntimeEvent::getEventType,
                          CloudRuntimeEvent::getServiceName,
                          CloudRuntimeEvent::getServiceVersion,
                          CloudRuntimeEvent::getProcessInstanceId,
                          CloudRuntimeEvent::getProcessDefinitionId,
                          CloudRuntimeEvent::getEntityId,
                          event -> ((CloudBPMNSignalReceivedEvent) event).getEntity().getElementId(),
                          event -> ((CloudBPMNSignalReceivedEvent) event).getEntity().getSignalPayload().getId(),
                          event -> ((CloudBPMNSignalReceivedEvent) event).getEntity().getSignalPayload().getName(),
                          event -> ((CloudBPMNSignalReceivedEvent) event).getEntity().getSignalPayload().getVariables()
                      )
                      .contains(
                          tuple(
                              cloudSignalReceivedEvent.getEventType(),
                              cloudSignalReceivedEvent.getServiceName(),
                              cloudSignalReceivedEvent.getServiceVersion(),
                              cloudSignalReceivedEvent.getProcessInstanceId(),
                              cloudSignalReceivedEvent.getProcessDefinitionId(),
                              cloudSignalReceivedEvent.getEntityId(),
                              cloudSignalReceivedEvent.getEntity().getElementId(),
                              cloudSignalReceivedEvent.getEntity().getSignalPayload().getId(),
                              cloudSignalReceivedEvent.getEntity().getSignalPayload().getName(),
                              cloudSignalReceivedEvent.getEntity().getSignalPayload().getVariables()
                          )
                      );
              });
      }
  
      @Test
      public void shouldGetTimerScheduledEvent() {
          //given
          List<CloudRuntimeEvent> coveredEvents = new ArrayList<>();
  
          BPMNTimerImpl timer1 = new BPMNTimerImpl("timerId1");
          timer1.setProcessDefinitionId("processDefinitionId");
          timer1.setProcessInstanceId("processInstanceId");
          timer1.setTimerPayload(createTimerPayload());
  
          CloudBPMNTimerFiredEventImpl cloudTimerFiredEvent = new CloudBPMNTimerFiredEventImpl(
              "eventId1",
              System.currentTimeMillis(),
              timer1,
              timer1.getProcessDefinitionId(),
              timer1.getProcessInstanceId()
          );
          coveredEvents.add(cloudTimerFiredEvent);
  
          BPMNTimerImpl timer2 = new BPMNTimerImpl("timerId2");
          timer2.setProcessDefinitionId("processDefinitionId");
          timer2.setProcessInstanceId("processInstanceId");
          timer2.setTimerPayload(createTimerPayload());
  
          CloudBPMNTimerScheduledEventImpl cloudTimerScheduledEvent = new CloudBPMNTimerScheduledEventImpl(
              "eventId2",
              System.currentTimeMillis(),
              timer2,
              timer2.getProcessDefinitionId(),
              timer2.getProcessInstanceId()
          );
  
          coveredEvents.add(cloudTimerScheduledEvent);
  
          producer.send(coveredEvents.toArray(new CloudRuntimeEvent[coveredEvents.size()]));
  
          await()
              .untilAsserted(() -> {
                  //when
                  Map<String, Object> filters = new HashMap<>();
                  filters.put("eventType", BPMNTimerEvent.TimerEvents.TIMER_SCHEDULED.name());
  
                  ResponseEntity<PagedModel<CloudRuntimeEvent>> eventsPagedModel = eventsRestTemplate.executeFind(
                      filters
                  );
  
                  //then
                  Collection<CloudRuntimeEvent> retrievedEvents = eventsPagedModel.getBody().getContent();
                  assertThat(retrievedEvents).hasSize(1);
  
                  assertThat(retrievedEvents)
                      .extracting(
                          CloudRuntimeEvent::getEventType,
                          CloudRuntimeEvent::getServiceName,
                          CloudRuntimeEvent::getServiceVersion,
                          CloudRuntimeEvent::getProcessInstanceId,
                          CloudRuntimeEvent::getProcessDefinitionId,
                          CloudRuntimeEvent::getEntityId,
                          event -> ((CloudBPMNTimerScheduledEvent) event).getEntity().getElementId(),
                          event -> ((CloudBPMNTimerScheduledEvent) event).getEntity().getProcessInstanceId(),
                          event -> ((CloudBPMNTimerScheduledEvent) event).getEntity().getProcessDefinitionId(),
                          event -> ((CloudBPMNTimerScheduledEvent) event).getEntity().getTimerPayload().getId(),
                          event ->
                              ((CloudBPMNTimerScheduledEvent) event).getEntity().getTimerPayload().getMaxIterations(),
                          event -> ((CloudBPMNTimerScheduledEvent) event).getEntity().getTimerPayload().getRepeat(),
                          event -> ((CloudBPMNTimerScheduledEvent) event).getEntity().getTimerPayload().getRetries()
                      )
                      .contains(
                          tuple(
                              cloudTimerScheduledEvent.getEventType(),
                              cloudTimerScheduledEvent.getServiceName(),
                              cloudTimerScheduledEvent.getServiceVersion(),
                              cloudTimerScheduledEvent.getProcessInstanceId(),
                              cloudTimerScheduledEvent.getProcessDefinitionId(),
                              cloudTimerScheduledEvent.getEntityId(),
                              cloudTimerScheduledEvent.getEntity().getElementId(),
                              cloudTimerScheduledEvent.getEntity().getProcessInstanceId(),
                              cloudTimerScheduledEvent.getEntity().getProcessDefinitionId(),
                              cloudTimerScheduledEvent.getEntity().getTimerPayload().getId(),
                              cloudTimerScheduledEvent.getEntity().getTimerPayload().getMaxIterations(),
                              cloudTimerScheduledEvent.getEntity().getTimerPayload().getRepeat(),
                              cloudTimerScheduledEvent.getEntity().getTimerPayload().getRetries()
                          )
                      );
              });
      }
  
      @Test
      public void shouldGetErrorReceivedEvent() {
          //given
          List<CloudRuntimeEvent> coveredEvents = new ArrayList<>();
  
          BPMNErrorImpl error = new BPMNErrorImpl("elementId");
          error.setProcessDefinitionId("processDefinitionId");
          error.setProcessInstanceId("processInstanceId");
          error.setErrorCode("errorCode");
          error.setErrorId("errorId");
  
          CloudBPMNErrorReceivedEventImpl cloudErrorReceivedEvent = new CloudBPMNErrorReceivedEventImpl(
              "eventId",
              System.currentTimeMillis(),
              error,
              error.getProcessDefinitionId(),
              error.getProcessInstanceId()
          );
          coveredEvents.add(cloudErrorReceivedEvent);
  
          producer.send(coveredEvents.toArray(new CloudRuntimeEvent[coveredEvents.size()]));
  
          await()
              .untilAsserted(() -> {
                  //when
                  Map<String, Object> filters = new HashMap<>();
                  filters.put("eventType", BPMNErrorReceivedEvent.ErrorEvents.ERROR_RECEIVED.name());
  
                  ResponseEntity<PagedModel<CloudRuntimeEvent>> eventsPagedModel = eventsRestTemplate.executeFind(
                      filters
                  );
  
                  //then
                  Collection<CloudRuntimeEvent> retrievedEvents = eventsPagedModel.getBody().getContent();
                  assertThat(retrievedEvents).hasSize(1);
  
                  assertThat(retrievedEvents)
                      .extracting(
                          CloudRuntimeEvent::getEventType,
                          CloudRuntimeEvent::getServiceName,
                          CloudRuntimeEvent::getServiceVersion,
                          CloudRuntimeEvent::getProcessInstanceId,
                          CloudRuntimeEvent::getProcessDefinitionId,
                          CloudRuntimeEvent::getEntityId,
                          event -> ((CloudBPMNErrorReceivedEvent) event).getEntity().getElementId(),
                          event -> ((CloudBPMNErrorReceivedEvent) event).getEntity().getProcessInstanceId(),
                          event -> ((CloudBPMNErrorReceivedEvent) event).getEntity().getProcessDefinitionId(),
                          event -> ((CloudBPMNErrorReceivedEvent) event).getEntity().getErrorCode(),
                          event -> ((CloudBPMNErrorReceivedEvent) event).getEntity().getErrorId()
                      )
                      .contains(
                          tuple(
                              cloudErrorReceivedEvent.getEventType(),
                              cloudErrorReceivedEvent.getServiceName(),
                              cloudErrorReceivedEvent.getServiceVersion(),
                              cloudErrorReceivedEvent.getProcessInstanceId(),
                              cloudErrorReceivedEvent.getProcessDefinitionId(),
                              cloudErrorReceivedEvent.getEntityId(),
                              cloudErrorReceivedEvent.getEntity().getElementId(),
                              cloudErrorReceivedEvent.getEntity().getProcessInstanceId(),
                              cloudErrorReceivedEvent.getEntity().getProcessDefinitionId(),
                              cloudErrorReceivedEvent.getEntity().getErrorCode(),
                              cloudErrorReceivedEvent.getEntity().getErrorId()
                          )
                      );
              });
      }
  
      @Test
      public void shouldGetMessageSubscriptionCancelledEvent() {
          //given
          List<CloudRuntimeEvent> coveredEvents = new ArrayList<>();
  
          MessageSubscriptionImpl messageSubscription = MessageSubscriptionImpl
              .builder()
              .withId("entityId")
              .withEventName("messageName")
              .withConfiguration("correlationKey")
              .withProcessDefinitionId("processDefinitionId")
              .withProcessInstanceId("processInstanceId")
              .withBusinessKey("businessKey")
              .build();
  
          CloudMessageSubscriptionCancelledEventImpl cloudEvent = CloudMessageSubscriptionCancelledEventImpl
              .builder()
              .withEntity(messageSubscription)
              .build();
          coveredEvents.add(cloudEvent);
  
          producer.send(coveredEvents.toArray(new CloudRuntimeEvent[coveredEvents.size()]));
  
          await()
              .untilAsserted(() -> {
                  //when
                  Map<String, Object> filters = new HashMap<>();
                  filters.put(
                      "eventType",
                      MessageSubscriptionCancelledEvent.MessageSubscriptionEvents.MESSAGE_SUBSCRIPTION_CANCELLED.name()
                  );
  
                  ResponseEntity<PagedModel<CloudRuntimeEvent>> eventsPagedModel = eventsRestTemplate.executeFind(
                      filters
                  );
  
                  //then
                  Collection<CloudRuntimeEvent> retrievedEvents = eventsPagedModel.getBody().getContent();
                  assertThat(retrievedEvents).hasSize(1);
  
                  assertThat(retrievedEvents)
                      .extracting(
                          CloudRuntimeEvent::getEventType,
                          CloudRuntimeEvent::getServiceName,
                          CloudRuntimeEvent::getServiceVersion,
                          CloudRuntimeEvent::getProcessInstanceId,
                          CloudRuntimeEvent::getProcessDefinitionId,
                          CloudRuntimeEvent::getEntityId,
                          event -> ((CloudMessageSubscriptionCancelledEvent) event).getEntity().getId(),
                          event -> ((CloudMessageSubscriptionCancelledEvent) event).getEntity().getProcessInstanceId(),
                          event -> ((CloudMessageSubscriptionCancelledEvent) event).getEntity().getProcessDefinitionId(),
                          event -> ((CloudMessageSubscriptionCancelledEvent) event).getEntity().getEventName(),
                          event -> ((CloudMessageSubscriptionCancelledEvent) event).getEntity().getConfiguration(),
                          event -> ((CloudMessageSubscriptionCancelledEvent) event).getEntity().getBusinessKey()
                      )
                      .contains(
                          tuple(
                              cloudEvent.getEventType(),
                              cloudEvent.getServiceName(),
                              cloudEvent.getServiceVersion(),
                              cloudEvent.getProcessInstanceId(),
                              cloudEvent.getProcessDefinitionId(),
                              cloudEvent.getEntityId(),
                              cloudEvent.getEntity().getId(),
                              cloudEvent.getEntity().getProcessInstanceId(),
                              cloudEvent.getEntity().getProcessDefinitionId(),
                              cloudEvent.getEntity().getEventName(),
                              cloudEvent.getEntity().getConfiguration(),
                              cloudEvent.getEntity().getBusinessKey()
                          )
                      );
              });
      }
  
      private List<CloudRuntimeEvent> getTaskCancelledEvents() {
          List<CloudRuntimeEvent> testEvents = new ArrayList<>();
          TaskImpl taskCreated = new TaskImpl("1234-abc-5678-def", "my task", Task.TaskStatus.CREATED);
          taskCreated.setProcessDefinitionId("proc-def");
          taskCreated.setProcessInstanceId("100");
          CloudTaskCreatedEventImpl cloudTaskCreatedEvent = new CloudTaskCreatedEventImpl(
              "TaskCreatedEventId",
              System.currentTimeMillis(),
              taskCreated
          );
          testEvents.add(cloudTaskCreatedEvent);
  
          TaskImpl taskAssigned = new TaskImpl("1234-abc-5678-def", "my task", Task.TaskStatus.ASSIGNED);
          taskAssigned.setProcessDefinitionId("proc-def");
          taskAssigned.setProcessInstanceId("100");
          CloudTaskAssignedEventImpl cloudTaskAssignedEvent = new CloudTaskAssignedEventImpl(
              "TaskAssignedEventId",
              System.currentTimeMillis(),
              taskAssigned
          );
          testEvents.add(cloudTaskAssignedEvent);
  
          TaskImpl taskCancelled = new TaskImpl("1234-abc-5678-def", "my task", Task.TaskStatus.CANCELLED);
          taskCancelled.setProcessDefinitionId("proc-def");
          taskCancelled.setProcessInstanceId("100");
          CloudTaskCancelledEventImpl cloudTaskCancelledEvent = new CloudTaskCancelledEventImpl(
              "TaskCancelledEventId",
              System.currentTimeMillis(),
              taskCancelled
          );
          testEvents.add(cloudTaskCancelledEvent);
          return testEvents;
      }
  
      private List<CloudRuntimeEvent> getTestEvents() {
          List<CloudRuntimeEvent> testEvents = new ArrayList<>();
  
          testEvents.add(new CloudProcessDeployedEventImpl(buildDefaultProcessDefinition()));
  
          testEvents.add(
              new CloudProcessCandidateStarterUserAddedEventImpl(
                  "CloudProcessCandidateStarterUserAddedEventImpl",
                  System.currentTimeMillis(),
                  new ProcessCandidateStarterUserImpl("pid", "uid")
              )
          );
  
          testEvents.add(
              new CloudProcessCandidateStarterUserRemovedEventImpl(
                  "CloudProcessCandidateStarterUserRemovedEventImpl",
                  System.currentTimeMillis(),
                  new ProcessCandidateStarterUserImpl("pid", "uid")
              )
          );
  
          testEvents.add(
              new CloudProcessCandidateStarterGroupAddedEventImpl(
                  "CloudProcessCandidateStarterGroupAddedEventId",
                  System.currentTimeMillis(),
                  new ProcessCandidateStarterGroupImpl("pid", "gid")
              )
          );
  
          testEvents.add(
              new CloudProcessCandidateStarterGroupRemovedEventImpl(
                  "CloudProcessCandidateStarterGroupRemovedEventImpl",
                  System.currentTimeMillis(),
                  new ProcessCandidateStarterGroupImpl("pid", "gid")
              )
          );
  
          BPMNActivityImpl bpmnActivityCancelled = new BPMNActivityImpl();
          bpmnActivityCancelled.setElementId("elementId");
  
          testEvents.add(
              new CloudBPMNActivityCancelledEventImpl(
                  "ActivityCancelledEventId",
                  System.currentTimeMillis(),
                  bpmnActivityCancelled,
                  "103",
                  "104",
                  "manually cancelled"
              )
          );
  
          BPMNActivityImpl bpmnActivityStarted = new BPMNActivityImpl(
              "bpmnActivityStarted1",
              "My Service Task",
              "Service Task"
          );
  
          CloudBPMNActivityStartedEventImpl cloudBPMNActivityStartedEvent = new CloudBPMNActivityStartedEventImpl(
              "ActivityStartedEventId",
              System.currentTimeMillis(),
              bpmnActivityStarted,
              "3",
              "4"
          );
  
          testEvents.add(cloudBPMNActivityStartedEvent);
  
          BPMNActivityImpl bpmnActivityStarted2 = new BPMNActivityImpl(
              "bpmnActivityStarted2",
              "My User Task",
              "User Task"
          );
  
          CloudBPMNActivityStartedEventImpl cloudBPMNActivityStartedEvent2 = new CloudBPMNActivityStartedEventImpl(
              "ActivityStartedEventId2",
              System.currentTimeMillis(),
              bpmnActivityStarted2,
              "3",
              "4"
          );
  
          testEvents.add(cloudBPMNActivityStartedEvent2);
  
          BPMNActivityImpl bpmnActivityStarted3 = new BPMNActivityImpl(
              "bpmnActivityStarted3",
              "My User Task",
              "User Task"
          );
  
          CloudBPMNActivityStartedEventImpl cloudBPMNActivityStartedEvent3 = new CloudBPMNActivityStartedEventImpl(
              "ActivityStartedEventId3",
              System.currentTimeMillis(),
              bpmnActivityStarted3,
              "3",
              "5"
          );
  
          testEvents.add(cloudBPMNActivityStartedEvent3);
  
          BPMNActivityImpl bpmnActivityCompleted = new BPMNActivityImpl();
          bpmnActivityCompleted.setElementId("elementId");
  
          testEvents.add(
              new CloudBPMNActivityCompletedEventImpl(
                  "ActivityCompletedEventId",
                  System.currentTimeMillis(),
                  bpmnActivityCompleted,
                  "23",
                  "42"
              )
          );
  
          ProcessInstanceImpl processInstanceCompleted = new ProcessInstanceImpl();
          processInstanceCompleted.setId("24");
          processInstanceCompleted.setProcessDefinitionId("43");
  
          CloudProcessCompletedEventImpl cloudProcessCompletedEvent = new CloudProcessCompletedEventImpl(
              "ProcessCompletedEventId",
              System.currentTimeMillis(),
              processInstanceCompleted
          );
  
          testEvents.add(cloudProcessCompletedEvent);
  
          ProcessInstanceImpl processInstanceCancelled = new ProcessInstanceImpl();
          processInstanceCancelled.setId("124");
          processInstanceCancelled.setProcessDefinitionId("143");
  
          CloudProcessCancelledEventImpl cloudProcessCancelledEvent = new CloudProcessCancelledEventImpl(
              "ProcessCancelledEventId",
              System.currentTimeMillis(),
              processInstanceCancelled
          );
  
          testEvents.add(cloudProcessCancelledEvent);
  
          ProcessInstanceImpl processInstanceStarted = new ProcessInstanceImpl();
          processInstanceStarted.setId("25");
          processInstanceStarted.setProcessDefinitionId("44");
  
          CloudProcessStartedEventImpl cloudProcessStartedEvent = new CloudProcessStartedEventImpl(
              "ProcessStartedEventId",
              System.currentTimeMillis(),
              processInstanceStarted
          );
  
          testEvents.add(cloudProcessStartedEvent);
  
          testEvents.add(
              new CloudProcessSuspendedEventImpl(
                  "ProcessSuspendedEventId",
                  System.currentTimeMillis(),
                  processInstanceStarted
              )
          );
  
          testEvents.add(
              new CloudProcessDeletedEventImpl(
                  "ProcessDeletedEventId",
                  System.currentTimeMillis(),
                  processInstanceStarted
              )
          );
  
          TaskImpl taskAssigned = new TaskImpl("1234-abc-5678-def", "task assigned", Task.TaskStatus.ASSIGNED);
          taskAssigned.setProcessDefinitionId("27");
          taskAssigned.setProcessInstanceId("46");
          CloudTaskAssignedEventImpl cloudTaskAssignedEvent = new CloudTaskAssignedEventImpl(
              "TaskAssignedEventId",
              System.currentTimeMillis(),
              taskAssigned
          );
          testEvents.add(cloudTaskAssignedEvent);
  
          taskAssigned.setPriority(10);
          testEvents.add(new CloudTaskUpdatedEventImpl("TaskUpdatedEventId", System.currentTimeMillis(), taskAssigned));
  
          TaskImpl taskCompleted = new TaskImpl("1234-abc-5678-def", "task completed", Task.TaskStatus.COMPLETED);
          taskCompleted.setProcessDefinitionId("28");
          taskCompleted.setProcessInstanceId("47");
          CloudTaskCompletedEventImpl cloudTaskCompletedEvent = new CloudTaskCompletedEventImpl(
              "TaskCompletedEventId",
              System.currentTimeMillis(),
              taskCompleted
          );
          testEvents.add(cloudTaskCompletedEvent);
  
          TaskImpl taskCreated = new TaskImpl("1234-abc-5678-def", "task created", Task.TaskStatus.CREATED);
          taskCreated.setProcessDefinitionId("28");
          taskCreated.setProcessInstanceId("47");
          taskCreated.setTaskDefinitionKey("taskDefinitionKey");
          CloudTaskCreatedEventImpl cloudTaskCreatedEvent = new CloudTaskCreatedEventImpl(
              "TaskCreatedEventId",
              System.currentTimeMillis(),
              taskCreated
          );
          testEvents.add(cloudTaskCreatedEvent);
  
          TaskImpl taskCancelled = new TaskImpl("1234-abc-5678-def", "task cancelled", Task.TaskStatus.CANCELLED);
          taskCancelled.setProcessDefinitionId("28");
          taskCancelled.setProcessInstanceId("47");
          CloudTaskCancelledEventImpl cloudTaskCancelledEvent = new CloudTaskCancelledEventImpl(
              "TaskCancelledEventId",
              System.currentTimeMillis(),
              taskCancelled
          );
          testEvents.add(cloudTaskCancelledEvent);
  
          IntegrationContextImpl integrationContext = new IntegrationContextImpl();
          integrationContext.setProcessDefinitionId("28");
          integrationContext.setProcessInstanceId("47");
          integrationContext.setClientId("elementId");
          integrationContext.setClientName("Connector Task");
          integrationContext.setClientType("serviceTask");
  
          CloudIntegrationRequestedEventImpl cloudIntegrationRequestedEvent = new CloudIntegrationRequestedEventImpl(
              integrationContext
          );
  
          testEvents.add(cloudIntegrationRequestedEvent);
  
          CloudIntegrationResultReceivedEventImpl cloudIntegrationResultReceivedEvent = new CloudIntegrationResultReceivedEventImpl(
              integrationContext
          );
  
          testEvents.add(cloudIntegrationResultReceivedEvent);
  
          Error cause = new Error(ERROR_MESSAGE);
          CloudBpmnError error = new CloudBpmnError("ERROR_CODE", cause);
  
          CloudIntegrationErrorReceivedEventImpl cloudIntegrationErrorReceivedEvent = new CloudIntegrationErrorReceivedEventImpl(
              integrationContext,
              error.getErrorCode(),
              error.getMessage(),
              error.getClass().getName(),
              Arrays.asList(error.getCause().getStackTrace())
          );
          testEvents.add(cloudIntegrationErrorReceivedEvent);
  
          DeploymentImpl deployment = new DeploymentImpl();
          deployment.setId("deploymentId");
          deployment.setVersion(1);
          deployment.setName("SpringAutoDeployment");
  
          CloudApplicationDeployedEventImpl cloudApplicationDeployedEvent = new CloudApplicationDeployedEventImpl(
              UUID.randomUUID().toString(),
              System.currentTimeMillis(),
              deployment,
              ApplicationEvents.APPLICATION_DEPLOYED
          );
          testEvents.add(cloudApplicationDeployedEvent);
  
          return testEvents;
      }
  
      private ProcessDefinitionImpl buildDefaultProcessDefinition() {
          ProcessDefinitionImpl processDefinition = new ProcessDefinitionImpl();
          processDefinition.setName("My process");
          processDefinition.setKey("my proc");
          processDefinition.setId("processId");
          return processDefinition;
      }
  
      private List<CloudRuntimeEvent> getTestProcessStartedUpdatedCompletedEvents() {
          List<CloudRuntimeEvent> testEvents = new ArrayList<>();
  
          ProcessInstanceImpl processInstanceStarted = new ProcessInstanceImpl();
          processInstanceStarted.setId("25");
          processInstanceStarted.setProcessDefinitionId("44");
  
          CloudProcessStartedEventImpl cloudProcessStartedEvent = new CloudProcessStartedEventImpl(
              "ProcessStartedEventId",
              System.currentTimeMillis(),
              processInstanceStarted
          );
  
          testEvents.add(cloudProcessStartedEvent);
  
          ProcessInstanceImpl processInstanceUpdated = new ProcessInstanceImpl();
          processInstanceUpdated.setId("25");
          processInstanceUpdated.setProcessDefinitionId("44");
          processInstanceUpdated.setBusinessKey("businessKey");
          processInstanceUpdated.setName("name");
  
          CloudProcessUpdatedEventImpl cloudProcessUpdatedEvent = new CloudProcessUpdatedEventImpl(
              "ProcessUpdatedEventId",
              System.currentTimeMillis(),
              processInstanceUpdated
          );
          testEvents.add(cloudProcessUpdatedEvent);
  
          ProcessInstanceImpl processInstanceCompleted = new ProcessInstanceImpl();
          processInstanceCompleted.setId("25");
          processInstanceCompleted.setProcessDefinitionId("44");
  
          CloudProcessCompletedEventImpl cloudProcessCompletedEvent = new CloudProcessCompletedEventImpl(
              "ProcessCompletedEventId",
              System.currentTimeMillis(),
              processInstanceCompleted
          );
  
          testEvents.add(cloudProcessCompletedEvent);
  
          return testEvents;
      }
  
      private List<CloudRuntimeEvent> getTestUserCandidatesEvents() {
          List<CloudRuntimeEvent> testEvents = new ArrayList<>();
  
          TaskCandidateUserImpl taskCandidateUser = new TaskCandidateUserImpl("userId", "1234-abc-5678-def");
  
          CloudTaskCandidateUserAddedEventImpl candidateUserAddedEvent = new CloudTaskCandidateUserAddedEventImpl(
              "TaskCandidateUserAddedEventId",
              System.currentTimeMillis(),
              taskCandidateUser
          );
  
          testEvents.add(candidateUserAddedEvent);
  
          taskCandidateUser = new TaskCandidateUserImpl("userId", "1234-abc-5678-def");
          CloudTaskCandidateUserRemovedEventImpl candidateUserRemovedEvent = new CloudTaskCandidateUserRemovedEventImpl(
              "TaskCandidateUserRemovedEventId",
              System.currentTimeMillis(),
              taskCandidateUser
          );
          testEvents.add(candidateUserRemovedEvent);
  
          return testEvents;
      }
  
      private TimerPayload createTimerPayload() {
          TimerPayload timerPayload = new TimerPayload();
          timerPayload.setRetries(5);
          timerPayload.setMaxIterations(2);
          timerPayload.setRepeat("repeat");
          timerPayload.setExceptionMessage("Any message");
  
          return timerPayload;
      }
  
      @Test
      public void shouldGetApplicationDeployedEvent() {
          //given
          List<CloudRuntimeEvent> coveredEvents = new ArrayList<>();
  
          DeploymentImpl deployment = new DeploymentImpl();
          deployment.setId("deploymentId");
          deployment.setVersion(1);
          deployment.setName("SpringAutoDeployment");
  
          CloudApplicationDeployedEventImpl cloudApplicationDeployedEvent = new CloudApplicationDeployedEventImpl(
              UUID.randomUUID().toString(),
              System.currentTimeMillis(),
              deployment,
              ApplicationEvents.APPLICATION_DEPLOYED
          );
          cloudApplicationDeployedEvent.setAppName("EventApplicationName");
          coveredEvents.add(cloudApplicationDeployedEvent);
  
          producer.send(coveredEvents.toArray(new CloudRuntimeEvent[coveredEvents.size()]));
  
          await()
              .untilAsserted(() -> {
                  //when
                  Map<String, Object> filters = new HashMap<>();
                  filters.put("eventType", ApplicationEvent.ApplicationEvents.APPLICATION_DEPLOYED.name());
  
                  ResponseEntity<PagedModel<CloudRuntimeEvent>> eventsPagedModel = eventsRestTemplate.executeFind(
                      filters
                  );
  
                  //then
                  Collection<CloudRuntimeEvent> retrievedEvents = eventsPagedModel.getBody().getContent();
                  assertThat(retrievedEvents).hasSize(1);
  
                  assertThat(retrievedEvents)
                      .extracting(
                          CloudRuntimeEvent::getEventType,
                          event -> ((CloudApplicationDeployedEvent) event).getEntity().getId(),
                          event -> ((CloudApplicationDeployedEvent) event).getEntity().getName(),
                          event -> ((CloudApplicationDeployedEvent) event).getEntity().getVersion()
                      )
                      .contains(
                          tuple(
                              cloudApplicationDeployedEvent.getEventType(),
                              cloudApplicationDeployedEvent.getEntity().getId(),
                              cloudApplicationDeployedEvent.getEntity().getName(),
                              cloudApplicationDeployedEvent.getEntity().getVersion()
                          )
                      );
              });
      }
  }
  